switchAILocal isn’t just a standalone server. It’s also a Go SDK you can embed directly into your own applications. Instead of running a separate proxy process, you bake the gateway into your binary—and your users get unified AI access without any extra setup.
This guide walks you through the integration, from a minimal embed to advanced customizations.
Why Embed Instead of Proxy?
Running switchAILocal as a standalone server works great for personal use. But if you’re building a product—a coding tool, a documentation generator, or an internal platform—embedding the SDK directly has clear advantages:
- No external dependency. Your users don’t need to install or run a separate gateway.
- Shared infrastructure. Use your existing logging, authentication middleware, and configuration management.
- Programmatic control. Execute requests, manage providers, and handle lifecycle events in code.
The Minimal Embed: 10 Lines of Go
The simplest integration gives you a fully functional gateway with hot-reloading configuration, automatic provider discovery, and graceful shutdown—all for free.
package main
import (
"context"
"os/signal"
"syscall"
"github.com/traylinx/switchAILocal/sdk/switchailocal"
)
func main() {
ctx, stop := signal.NotifyContext(
context.Background(), syscall.SIGINT, syscall.SIGTERM,
)
defer stop()
svc, err := switchailocal.NewService(ctx)
if err != nil {
panic(err)
}
if err := svc.Run(ctx); err != nil {
panic(err)
}
}
That’s it. The service reads config.yaml, discovers local providers like Ollama, watches for configuration changes via fsnotify, and shuts down cleanly when the context is cancelled.
Customizing the HTTP Server
If you already have a Go web application (using Gin, Chi, or stdlib), you probably want switchAILocal to live alongside your existing routes. The SDK supports this through WithServerOptions:
import (
"github.com/traylinx/switchAILocal/internal/api/server"
"github.com/traylinx/switchAILocal/sdk/switchailocal"
)
srv, err := server.New(
server.WithLogger(myLogger),
server.WithMiddleware(myAuthMiddleware),
server.WithRoute("GET", "/health", myHealthHandler),
)
svc, err := switchailocal.NewService(ctx,
switchailocal.WithServerOptions(srv),
)
This lets you inject your own logging, authentication, rate limiting, or custom health checks while keeping the AI gateway functionality intact.
Building a Custom Provider
The real power of the SDK is extensibility. If you have a proprietary model or an internal inference service, you can register it as a first-class provider.
The process has three parts:
1. Implement the Executor interface
type MyProvExecutor struct{}
func (e *MyProvExecutor) Execute(
ctx context.Context,
req *auth.ExecutionRequest,
) (*schema.OpenAIResponse, error) {
// Build your provider-specific request
// Make the call to your internal API
// Return a standard OpenAI-format response
return &schema.OpenAIResponse{/* ... */}, nil
}
2. Register a schema translator
The sdk/translator package handles format conversion. You register functions that translate between OpenAI’s format and your provider’s format:
func init() {
translator.RegisterRequestHandler(
translator.HandlerKey{From: "openai", To: "myprov", Type: "chat"},
func(body []byte) ([]byte, error) {
// Convert OpenAI JSON → your format
return convertedBody, nil
},
)
}
3. Register the executor
manager.RegisterExecutor("myprov", &MyProvExecutor{})
Once registered, users can access your provider with the myprov: prefix, just like any built-in provider. The translation pipeline handles the rest.
Lifecycle Hooks
For observability, the SDK provides hooks that fire on internal events:
svc, err := switchailocal.NewService(ctx,
switchailocal.WithHooks(switchailocal.Hooks{
OnAuthRegistered: func(ctx context.Context, id string, auth *config.Auth) {
log.Printf("Provider registered: %s", id)
},
OnConfigReload: func(ctx context.Context) {
log.Println("Configuration reloaded")
},
}),
)
Available hooks include OnAuthRegistered, OnAuthUnregistered, OnConfigReload, OnRequestStart, and OnRequestEnd. These are useful for metrics, audit logging, or triggering custom behavior when the configuration changes.
Custom Credential Sources
In production, you probably don’t want credentials in a YAML file on disk. The SDK lets you replace the default file-based loader with your own implementation:
svc, err := switchailocal.NewService(ctx,
switchailocal.WithClientSources(&myVaultLoader{}),
)
Your myVaultLoader can fetch secrets from HashiCorp Vault, AWS Secrets Manager, or any other backend. The SDK calls it during startup and whenever configuration is reloaded.
Graceful Shutdown
Shutdown is automatic when you cancel the parent context (as shown in the minimal example). For manual control:
svc.Shutdown(context.Background())
Active connections are drained before the service exits.
Next Steps
The SDK source lives under sdk/ in the repository. The key packages are:
sdk/switchailocal— Service builder and lifecyclesdk/access— Inbound authenticationsdk/auth— Provider executor managementsdk/translator— Schema translation registrysdk/config— Configuration types and client sources
Explore the SDK on GitHub →
Open Source. MIT Licensed. Contributions welcome.
Sebastian Schkudlara
Cortex Phase 2: 20ms to Understand Your Soul