summaryrefslogtreecommitdiff
path: root/internal/cli/cloudrunners.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/cli/cloudrunners.go')
-rw-r--r--internal/cli/cloudrunners.go91
1 files changed, 91 insertions, 0 deletions
diff --git a/internal/cli/cloudrunners.go b/internal/cli/cloudrunners.go
new file mode 100644
index 0000000..55b3efb
--- /dev/null
+++ b/internal/cli/cloudrunners.go
@@ -0,0 +1,91 @@
+package cli
+
+import (
+ "log/slog"
+ "net/http"
+ "time"
+
+ "github.com/thepeterstone/claudomator/internal/config"
+ "github.com/thepeterstone/claudomator/internal/executor"
+ "github.com/thepeterstone/claudomator/internal/llm"
+ "github.com/thepeterstone/claudomator/internal/provider"
+ "github.com/thepeterstone/claudomator/internal/provider/anthropic"
+ "github.com/thepeterstone/claudomator/internal/provider/google"
+ "github.com/thepeterstone/claudomator/internal/provider/openaicompat"
+)
+
+// cloudProviderSpec describes how to construct a provider.Provider for one
+// cloud provider entry in cfg.Providers, and which RunnersConfig field gates
+// it. anthropic/google use their native wire-format adapters; groq/
+// openrouter/openai are OpenAI-wire-compatible and reuse the Phase 1
+// openaicompat adapter — no dedicated adapter package needed for those three
+// (see docs/api-keys-setup.md).
+type cloudProviderSpec struct {
+ name string
+ enabled func(config.RunnersConfig) bool
+ build func(pc config.ProviderConfig, timeout time.Duration) provider.Provider
+}
+
+func openaiCompatBuild(pc config.ProviderConfig, timeout time.Duration) provider.Provider {
+ return openaicompat.New(&llm.Client{
+ Endpoint: pc.Endpoint,
+ Model: pc.DefaultModel,
+ APIKey: pc.APIKey,
+ HTTPClient: &http.Client{Timeout: timeout},
+ })
+}
+
+var cloudProviderSpecs = []cloudProviderSpec{
+ {
+ name: "anthropic",
+ enabled: config.RunnersConfig.AnthropicEnabled,
+ build: func(pc config.ProviderConfig, timeout time.Duration) provider.Provider {
+ return anthropic.New(pc.APIKey, pc.Endpoint, timeout)
+ },
+ },
+ {
+ name: "google",
+ enabled: config.RunnersConfig.GoogleEnabled,
+ build: func(pc config.ProviderConfig, timeout time.Duration) provider.Provider {
+ return google.New(pc.APIKey, pc.Endpoint, timeout)
+ },
+ },
+ {name: "groq", enabled: config.RunnersConfig.GroqEnabled, build: openaiCompatBuild},
+ {name: "openrouter", enabled: config.RunnersConfig.OpenRouterEnabled, build: openaiCompatBuild},
+ {name: "openai", enabled: config.RunnersConfig.OpenAIEnabled, build: openaiCompatBuild},
+}
+
+// registerCloudRunners constructs and adds a NativeRunner (SandboxKind:
+// "docker", matching the original anthropic/google-only wiring — cloud
+// providers get real container isolation, not the weaker HostSandbox local
+// runners use) into runners for every cloud provider in cloudProviderSpecs
+// that has a non-empty cfg.Providers[name].APIKey and is enabled via its
+// RunnersConfig.<Name>Enabled() gate. Called identically from both `serve`
+// and `run` — the only difference between them (logDir) is a parameter, and
+// neither command does anything provider-specific beyond this.
+func registerCloudRunners(runners map[string]executor.Runner, cfg *config.Config, logger *slog.Logger, logDir string) {
+ for _, spec := range cloudProviderSpecs {
+ pc, ok := cfg.Providers[spec.name]
+ if !ok || pc.APIKey == "" || !spec.enabled(cfg.Runners) {
+ continue
+ }
+ timeout := time.Duration(0)
+ if pc.TimeoutSeconds > 0 {
+ timeout = time.Duration(pc.TimeoutSeconds) * time.Second
+ }
+ runners[spec.name] = &executor.NativeRunner{
+ Provider: spec.build(pc, timeout),
+ Logger: logger,
+ LogDir: logDir,
+ DefaultModel: pc.DefaultModel,
+ // Native cloud providers get real container isolation
+ // (sandbox.DockerSandbox) rather than HostSandbox's host-side
+ // path-prefix confinement — see NativeRunner.SandboxKind doc.
+ SandboxKind: "docker",
+ SandboxImage: cfg.SandboxImage,
+ }
+ if logger != nil {
+ logger.Info(spec.name+" runner registered", "default_model", pc.DefaultModel, "sandbox", "docker")
+ }
+ }
+}