Files
egutierrez 4634ad104b feat: añadir claude-code como proveedor LLM via claude -p
Implementa un nuevo proveedor LLM que ejecuta 'claude -p' como subproceso,
permitiendo usar Claude Code como backend de cualquier agente Matrix.

Cambios:
- pkg/llm/types.go: nueva constante ProviderClaudeCode
- pkg/llm/router.go: routing de 'claude-code' antes de 'claude*' (Anthropic API)
- internal/config/schema.go: nuevo tipo ClaudeCodeCfg con campos para binary,
  timeout, disable_tools, allowed/disallowed tools, permission_mode, model,
  fallback_model, session_id y add_dirs
- shell/llm/claudecode.go: provider completo — buildClaudeArgs(), flattenMessages(),
  parseClaudeOutput() y filterEnv() para limpiar ANTHROPIC_API_KEY del entorno
  y que claude use su propia auth OAuth
- shell/llm/factory.go: case 'claude-code' en FromConfig(), WithFallback() ahora
  recibe fallbackCfg para sobreescribir model/max_tokens al hacer fallback
- agents/runtime.go: actualizado para pasar fallbackCfg a WithFallback()

No se tocó: los proveedores existentes (anthropic.go, openai.go), el core puro
de decision ni el listener de Matrix.
2026-03-06 22:14:28 +00:00

52 lines
1.6 KiB
Go

package llm
import (
"context"
"fmt"
"log/slog"
"github.com/enmanuel/agents/internal/config"
coretypes "github.com/enmanuel/agents/pkg/llm"
)
// FromConfig builds a CompleteFunc from an LLMProviderCfg.
func FromConfig(cfg config.LLMProviderCfg, log *slog.Logger) (coretypes.CompleteFunc, error) {
log.Info("llm_provider_init", "provider", cfg.Provider, "model", cfg.Model)
switch cfg.Provider {
case "anthropic":
return NewAnthropicComplete(cfg.APIKeyEnv, cfg.BaseURL, log), nil
case "openai":
return NewOpenAIComplete(cfg.APIKeyEnv, cfg.BaseURL, log), nil
case "ollama":
base := cfg.BaseURL
if base == "" {
base = "http://localhost:11434/v1"
}
return NewOpenAIComplete("OLLAMA_API_KEY", base, log), nil
case "claude-code":
return NewClaudeCodeComplete(cfg.ClaudeCode, log), nil
default:
return nil, fmt.Errorf("unknown LLM provider: %s", cfg.Provider)
}
}
// WithFallback wraps primary with a fallback CompleteFunc.
// If primary returns an error, fallback is tried with the fallback config's model.
func WithFallback(primary, fallback coretypes.CompleteFunc, fallbackCfg config.LLMProviderCfg, log *slog.Logger) coretypes.CompleteFunc {
return func(ctx context.Context, req coretypes.CompletionRequest) (coretypes.CompletionResponse, error) {
resp, err := primary(ctx, req)
if err != nil {
log.Warn("llm_fallback_triggered", "primary_err", err)
// Override request fields with fallback config values
if fallbackCfg.Model != "" {
req.Model = fallbackCfg.Model
}
if fallbackCfg.MaxTokens > 0 {
req.MaxTokens = fallbackCfg.MaxTokens
}
return fallback(ctx, req)
}
return resp, nil
}
}