fix(providers): use DB name for ClaudeCLI, ACP, and Anthropic registration

Provider Name() methods returned hardcoded strings, so DB-registered
providers with custom names got wrong registry key — causing "provider
not found" fallback. Add WithClaudeCLIName/WithACPName/WithAnthropicName
options, pass p.Name from DB registration paths. Config-based paths
keep hardcoded defaults.

Closes #742
This commit is contained in:
viettranx committed 2026-04-08 15:37:54 +07:00
1 parent acd9f917d5
commit 7fcf03273e
4 files changed
+39 -3

No files matched your search

+3
View File
@@ -294,6 +294,7 @@ func registerProvidersFromDB(registry *providers.Registry, provStore store.Provi
continue continue
} }
var cliOpts []providers.ClaudeCLIOption var cliOpts []providers.ClaudeCLIOption
cliOpts = append(cliOpts, providers.WithClaudeCLIName(p.Name))
cliOpts = append(cliOpts, providers.WithClaudeCLISecurityHooks("", true)) cliOpts = append(cliOpts, providers.WithClaudeCLISecurityHooks("", true))
if gatewayAddr != "" { if gatewayAddr != "" {
mcpData := providers.BuildCLIMCPConfigData(nil, gatewayAddr, gatewayToken) mcpData := providers.BuildCLIMCPConfigData(nil, gatewayAddr, gatewayToken)
@@ -341,6 +342,7 @@ func registerProvidersFromDB(registry *providers.Registry, provStore store.Provi
registry.RegisterForTenant(p.TenantID, codex) registry.RegisterForTenant(p.TenantID, codex)
case store.ProviderAnthropicNative: case store.ProviderAnthropicNative:
registry.RegisterForTenant(p.TenantID, providers.NewAnthropicProvider(p.APIKey, registry.RegisterForTenant(p.TenantID, providers.NewAnthropicProvider(p.APIKey,
providers.WithAnthropicName(p.Name),
providers.WithAnthropicBaseURL(p.APIBase))) providers.WithAnthropicBaseURL(p.APIBase)))
case store.ProviderDashScope: case store.ProviderDashScope:
registry.RegisterForTenant(p.TenantID, providers.NewDashScopeProvider(p.Name, p.APIKey, p.APIBase, "")) registry.RegisterForTenant(p.TenantID, providers.NewDashScopeProvider(p.Name, p.APIKey, p.APIBase, ""))
@@ -483,6 +485,7 @@ func registerACPFromDB(registry *providers.Registry, p store.LLMProviderData) {
} }
registry.RegisterForTenant(p.TenantID, providers.NewACPProvider( registry.RegisterForTenant(p.TenantID, providers.NewACPProvider(
binary, settings.Args, workDir, idleTTL, tools.DefaultDenyPatterns(), binary, settings.Args, workDir, idleTTL, tools.DefaultDenyPatterns(),
providers.WithACPName(p.Name),
providers.WithACPModel(p.Name), providers.WithACPModel(p.Name),
)) ))
slog.Info("registered provider from DB", "name", p.Name, "type", "acp") slog.Info("registered provider from DB", "name", p.Name, "type", "acp")
+12 -1
View File
@@ -16,6 +16,7 @@ import (
// ACPProvider implements Provider by orchestrating ACP-compatible agent subprocesses. // ACPProvider implements Provider by orchestrating ACP-compatible agent subprocesses.
// It delegates to a ProcessPool that manages agent lifecycle over JSON-RPC 2.0 stdio. // It delegates to a ProcessPool that manages agent lifecycle over JSON-RPC 2.0 stdio.
type ACPProvider struct { type ACPProvider struct {
name string // provider name (default: "acp")
pool *acp.ProcessPool pool *acp.ProcessPool
bridge *acp.ToolBridge bridge *acp.ToolBridge
defaultModel string defaultModel string
@@ -26,6 +27,15 @@ type ACPProvider struct {
// ACPOption configures an ACPProvider. // ACPOption configures an ACPProvider.
type ACPOption func(*ACPProvider) type ACPOption func(*ACPProvider)
// WithACPName overrides the provider name (default: "acp").
func WithACPName(name string) ACPOption {
return func(p *ACPProvider) {
if name != "" {
p.name = name
}
}
}
// WithACPModel sets the default model/agent name. // WithACPModel sets the default model/agent name.
func WithACPModel(model string) ACPOption { func WithACPModel(model string) ACPOption {
return func(p *ACPProvider) { return func(p *ACPProvider) {
@@ -47,6 +57,7 @@ func WithACPPermMode(mode string) ACPOption {
// NewACPProvider creates a provider that orchestrates ACP agents as subprocesses. // NewACPProvider creates a provider that orchestrates ACP agents as subprocesses.
func NewACPProvider(binary string, args []string, workDir string, idleTTL time.Duration, denyPatterns []*regexp.Regexp, opts ...ACPOption) *ACPProvider { func NewACPProvider(binary string, args []string, workDir string, idleTTL time.Duration, denyPatterns []*regexp.Regexp, opts ...ACPOption) *ACPProvider {
p := &ACPProvider{ p := &ACPProvider{
name: "acp",
defaultModel: "claude", defaultModel: "claude",
} }
for _, opt := range opts { for _, opt := range opts {
@@ -70,7 +81,7 @@ func NewACPProvider(binary string, args []string, workDir string, idleTTL time.D
return p return p
} }
func (p *ACPProvider) Name() string { return "acp" } func (p *ACPProvider) Name() string { return p.name }
func (p *ACPProvider) DefaultModel() string { return p.defaultModel } func (p *ACPProvider) DefaultModel() string { return p.defaultModel }
// Chat sends a prompt and returns the complete response (non-streaming). // Chat sends a prompt and returns the complete response (non-streaming).
+12 -1
View File
@@ -38,6 +38,7 @@ func resolveAnthropicModel(model, defaultModel string) string {
// AnthropicProvider implements Provider using the Anthropic Claude API via net/http. // AnthropicProvider implements Provider using the Anthropic Claude API via net/http.
type AnthropicProvider struct { type AnthropicProvider struct {
name string // provider name (default: "anthropic")
apiKey string apiKey string
baseURL string baseURL string
defaultModel string defaultModel string
@@ -48,6 +49,7 @@ type AnthropicProvider struct {
// NewAnthropicProvider creates a new Anthropic provider. // NewAnthropicProvider creates a new Anthropic provider.
func NewAnthropicProvider(apiKey string, opts ...AnthropicOption) *AnthropicProvider { func NewAnthropicProvider(apiKey string, opts ...AnthropicOption) *AnthropicProvider {
p := &AnthropicProvider{ p := &AnthropicProvider{
name: "anthropic",
apiKey: apiKey, apiKey: apiKey,
baseURL: anthropicAPIBase, baseURL: anthropicAPIBase,
defaultModel: defaultClaudeModel, defaultModel: defaultClaudeModel,
@@ -62,6 +64,15 @@ func NewAnthropicProvider(apiKey string, opts ...AnthropicOption) *AnthropicProv
type AnthropicOption func(*AnthropicProvider) type AnthropicOption func(*AnthropicProvider)
// WithAnthropicName overrides the provider name (default: "anthropic").
func WithAnthropicName(name string) AnthropicOption {
return func(p *AnthropicProvider) {
if name != "" {
p.name = name
}
}
}
func WithAnthropicModel(model string) AnthropicOption { func WithAnthropicModel(model string) AnthropicOption {
return func(p *AnthropicProvider) { p.defaultModel = model } return func(p *AnthropicProvider) { p.defaultModel = model }
} }
@@ -74,7 +85,7 @@ func WithAnthropicBaseURL(baseURL string) AnthropicOption {
} }
} }
func (p *AnthropicProvider) Name() string { return "anthropic" } func (p *AnthropicProvider) Name() string { return p.name }
func (p *AnthropicProvider) DefaultModel() string { return p.defaultModel } func (p *AnthropicProvider) DefaultModel() string { return p.defaultModel }
func (p *AnthropicProvider) SupportsThinking() bool { return true } func (p *AnthropicProvider) SupportsThinking() bool { return true }
+12 -1
View File
@@ -39,6 +39,7 @@ const OptTenantID = "tenant_id"
// It acts as a thin proxy: CLI manages session history, tool execution, and context. // It acts as a thin proxy: CLI manages session history, tool execution, and context.
// GoClaw only forwards the latest user message and streams back the response. // GoClaw only forwards the latest user message and streams back the response.
type ClaudeCLIProvider struct { type ClaudeCLIProvider struct {
name string // provider name (default: "claude-cli")
cliPath string // path to claude binary (default: "claude") cliPath string // path to claude binary (default: "claude")
defaultModel string // default: "sonnet" defaultModel string // default: "sonnet"
baseWorkDir string // base dir for agent workspaces baseWorkDir string // base dir for agent workspaces
@@ -54,6 +55,15 @@ type ClaudeCLIProvider struct {
// ClaudeCLIOption configures the provider. // ClaudeCLIOption configures the provider.
type ClaudeCLIOption func(*ClaudeCLIProvider) type ClaudeCLIOption func(*ClaudeCLIProvider)
// WithClaudeCLIName overrides the provider name (default: "claude-cli").
func WithClaudeCLIName(name string) ClaudeCLIOption {
return func(p *ClaudeCLIProvider) {
if name != "" {
p.name = name
}
}
}
// WithClaudeCLIModel sets the default model alias. // WithClaudeCLIModel sets the default model alias.
func WithClaudeCLIModel(model string) ClaudeCLIOption { func WithClaudeCLIModel(model string) ClaudeCLIOption {
return func(p *ClaudeCLIProvider) { return func(p *ClaudeCLIProvider) {
@@ -110,6 +120,7 @@ func NewClaudeCLIProvider(cliPath string, opts ...ClaudeCLIOption) *ClaudeCLIPro
cliPath = "claude" cliPath = "claude"
} }
p := &ClaudeCLIProvider{ p := &ClaudeCLIProvider{
name: "claude-cli",
cliPath: cliPath, cliPath: cliPath,
defaultModel: "sonnet", defaultModel: "sonnet",
baseWorkDir: defaultCLIWorkDir(), baseWorkDir: defaultCLIWorkDir(),
@@ -122,7 +133,7 @@ func NewClaudeCLIProvider(cliPath string, opts ...ClaudeCLIOption) *ClaudeCLIPro
return p return p
} }
func (p *ClaudeCLIProvider) Name() string { return "claude-cli" } func (p *ClaudeCLIProvider) Name() string { return p.name }
func (p *ClaudeCLIProvider) DefaultModel() string { return p.defaultModel } func (p *ClaudeCLIProvider) DefaultModel() string { return p.defaultModel }
// Close cleans up temp files (per-session MCP configs, hooks settings). Implements io.Closer. // Close cleans up temp files (per-session MCP configs, hooks settings). Implements io.Closer.