File size: 5,115 Bytes
bf9e111 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | # CLI Proxy SDK Guide
The `sdk/cliproxy` module exposes the proxy as a reusable Go library so external programs can embed the routing, authentication, hot‑reload, and translation layers without depending on the CLI binary.
## Install & Import
```bash
go get github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy
```
```go
import (
"context"
"errors"
"time"
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
"github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy"
)
```
Note the `/v6` module path.
## Minimal Embed
```go
cfg, err := config.LoadConfig("config.yaml")
if err != nil { panic(err) }
svc, err := cliproxy.NewBuilder().
WithConfig(cfg).
WithConfigPath("config.yaml"). // absolute or working-dir relative
Build()
if err != nil { panic(err) }
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if err := svc.Run(ctx); err != nil && !errors.Is(err, context.Canceled) {
panic(err)
}
```
The service manages config/auth watching, background token refresh, and graceful shutdown. Cancel the context to stop it.
## Server Options (middleware, routes, logs)
The server accepts options via `WithServerOptions`:
```go
svc, _ := cliproxy.NewBuilder().
WithConfig(cfg).
WithConfigPath("config.yaml").
WithServerOptions(
// Add global middleware
cliproxy.WithMiddleware(func(c *gin.Context) { c.Header("X-Embed", "1"); c.Next() }),
// Tweak gin engine early (CORS, trusted proxies, etc.)
cliproxy.WithEngineConfigurator(func(e *gin.Engine) { e.ForwardedByClientIP = true }),
// Add your own routes after defaults
cliproxy.WithRouterConfigurator(func(e *gin.Engine, _ *handlers.BaseAPIHandler, _ *config.Config) {
e.GET("/healthz", func(c *gin.Context) { c.String(200, "ok") })
}),
// Override request log writer/dir
cliproxy.WithRequestLoggerFactory(func(cfg *config.Config, cfgPath string) logging.RequestLogger {
return logging.NewFileRequestLogger(true, "logs", filepath.Dir(cfgPath))
}),
).
Build()
```
These options mirror the internals used by the CLI server.
## Management API (when embedded)
- Management endpoints are mounted only when `remote-management.secret-key` is set in `config.yaml`.
- Remote access additionally requires `remote-management.allow-remote: true`.
- See MANAGEMENT_API.md for endpoints. Your embedded server exposes them under `/v0/management` on the configured port.
## Using the Core Auth Manager
The service uses a core `auth.Manager` for selection, execution, and auto‑refresh. When embedding, you can provide your own manager to customize transports or hooks:
```go
core := coreauth.NewManager(coreauth.NewFileStore(cfg.AuthDir), nil, nil)
core.SetRoundTripperProvider(myRTProvider) // per‑auth *http.Transport
svc, _ := cliproxy.NewBuilder().
WithConfig(cfg).
WithConfigPath("config.yaml").
WithCoreAuthManager(core).
Build()
```
Implement a custom per‑auth transport:
```go
type myRTProvider struct{}
func (myRTProvider) RoundTripperFor(a *coreauth.Auth) http.RoundTripper {
if a == nil || a.ProxyURL == "" { return nil }
u, _ := url.Parse(a.ProxyURL)
return &http.Transport{ Proxy: http.ProxyURL(u) }
}
```
Programmatic execution is available on the manager:
```go
// Non‑streaming
resp, err := core.Execute(ctx, []string{"gemini"}, req, opts)
// Streaming
chunks, err := core.ExecuteStream(ctx, []string{"gemini"}, req, opts)
for ch := range chunks { /* ... */ }
```
Note: Built‑in provider executors are wired automatically when you run the `Service`. If you want to use `Manager` stand‑alone without the HTTP server, you must register your own executors that implement `auth.ProviderExecutor`.
## Custom Client Sources
Replace the default loaders if your creds live outside the local filesystem:
```go
type memoryTokenProvider struct{}
func (p *memoryTokenProvider) Load(ctx context.Context, cfg *config.Config) (*cliproxy.TokenClientResult, error) {
// Populate from memory/remote store and return counts
return &cliproxy.TokenClientResult{}, nil
}
svc, _ := cliproxy.NewBuilder().
WithConfig(cfg).
WithConfigPath("config.yaml").
WithTokenClientProvider(&memoryTokenProvider{}).
WithAPIKeyClientProvider(cliproxy.NewAPIKeyClientProvider()).
Build()
```
## Hooks
Observe lifecycle without patching internals:
```go
hooks := cliproxy.Hooks{
OnBeforeStart: func(cfg *config.Config) { log.Infof("starting on :%d", cfg.Port) },
OnAfterStart: func(s *cliproxy.Service) { log.Info("ready") },
}
svc, _ := cliproxy.NewBuilder().WithConfig(cfg).WithConfigPath("config.yaml").WithHooks(hooks).Build()
```
## Shutdown
`Run` defers `Shutdown`, so cancelling the parent context is enough. To stop manually:
```go
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
_ = svc.Shutdown(ctx)
```
## Notes
- Hot reload: changes to `config.yaml` and `auths/` are picked up automatically.
- Request logging can be toggled at runtime via the Management API.
- Gemini Web features (`gemini-web.*`) are honored in the embedded server.
|