Files
CLIProxyAPI/docs/sdk-advanced.md
Luis Pater a4767fdd8e feat(auth, docs): add SDK guides and local password support for management
- Added extensive SDK usage guides for `cliproxy`, `sdk/access`, and watcher integration.
- Introduced `--password` flag for specifying local management access passwords.
- Enhanced management API with local password checks to secure localhost requests.
- Updated documentation to reflect the new password functionality.
2025-09-25 11:32:14 +08:00

139 lines
5.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SDK Advanced: Executors & Translators
This guide explains how to extend the embedded proxy with custom providers and schemas using the SDK. You will:
- Implement a provider executor that talks to your upstream API
- Register request/response translators for schema conversion
- Register models so they appear in `/v1/models`
The examples use Go 1.24+ and the v6 module path.
## Concepts
- Provider executor: a runtime component implementing `auth.ProviderExecutor` that performs outbound calls for a given provider key (e.g., `gemini`, `claude`, `codex`). Executors can also implement `RequestPreparer` to inject credentials on raw HTTP requests.
- Translator registry: schema conversion functions routed by `sdk/translator`. The builtin handlers translate between OpenAI/Gemini/Claude/Codex formats; you can register new ones.
- Model registry: publishes the list of available models per client/provider to power `/v1/models` and routing hints.
## 1) Implement a Provider Executor
Create a type that satisfies `auth.ProviderExecutor`.
```go
package myprov
import (
"context"
"net/http"
coreauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth"
clipexec "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/executor"
)
type Executor struct{}
func (Executor) Identifier() string { return "myprov" }
// Optional: mutate outbound HTTP requests with credentials
func (Executor) PrepareRequest(req *http.Request, a *coreauth.Auth) error {
// Example: req.Header.Set("Authorization", "Bearer "+a.APIKey)
return nil
}
func (Executor) Execute(ctx context.Context, a *coreauth.Auth, req clipexec.Request, opts clipexec.Options) (clipexec.Response, error) {
// Build HTTP request based on req.Payload (already translated into provider format)
// Use perauth transport if provided: transport := a.RoundTripper // via RoundTripperProvider
// Perform call and return provider JSON payload
return clipexec.Response{Payload: []byte(`{"ok":true}`)}, nil
}
func (Executor) ExecuteStream(ctx context.Context, a *coreauth.Auth, req clipexec.Request, opts clipexec.Options) (<-chan clipexec.StreamChunk, error) {
ch := make(chan clipexec.StreamChunk, 1)
go func() { defer close(ch); ch <- clipexec.StreamChunk{Payload: []byte("data: {\"done\":true}\n\n")} }()
return ch, nil
}
func (Executor) Refresh(ctx context.Context, a *coreauth.Auth) (*coreauth.Auth, error) {
// Optionally refresh tokens and return updated auth
return a, nil
}
```
Register the executor with the core manager before starting the service:
```go
core := coreauth.NewManager(coreauth.NewFileStore(cfg.AuthDir), nil, nil)
core.RegisterExecutor(myprov.Executor{})
svc, _ := cliproxy.NewBuilder().WithConfig(cfg).WithConfigPath(cfgPath).WithCoreAuthManager(core).Build()
```
If your auth entries use provider `"myprov"`, the manager routes requests to your executor.
## 2) Register Translators
The handlers accept OpenAI/Gemini/Claude/Codex inputs. To support a new provider format, register translation functions in `sdk/translator`s default registry.
Direction matters:
- Request: register from inbound schema to provider schema
- Response: register from provider schema back to inbound schema
Example: Convert OpenAI Chat → MyProv Chat and back.
```go
package myprov
import (
"context"
sdktr "github.com/router-for-me/CLIProxyAPI/v6/sdk/translator"
)
const (
FOpenAI = sdktr.Format("openai.chat")
FMyProv = sdktr.Format("myprov.chat")
)
func init() {
sdktr.Register(FOpenAI, FMyProv,
// Request transform (model, rawJSON, stream)
func(model string, raw []byte, stream bool) []byte { return convertOpenAIToMyProv(model, raw, stream) },
// Response transform (stream & nonstream)
sdktr.ResponseTransform{
Stream: func(ctx context.Context, model string, originalReq, translatedReq, raw []byte, param *any) []string {
return convertStreamMyProvToOpenAI(model, originalReq, translatedReq, raw)
},
NonStream: func(ctx context.Context, model string, originalReq, translatedReq, raw []byte, param *any) string {
return convertMyProvToOpenAI(model, originalReq, translatedReq, raw)
},
},
)
}
```
When the OpenAI handler receives a request that should route to `myprov`, the pipeline uses the registered transforms automatically.
## 3) Register Models
Expose models under `/v1/models` by registering them in the global model registry using the auth ID (client ID) and provider name.
```go
models := []*cliproxy.ModelInfo{
{ ID: "myprov-pro-1", Object: "model", Type: "myprov", DisplayName: "MyProv Pro 1" },
}
cliproxy.GlobalModelRegistry().RegisterClient(authID, "myprov", models)
```
The embedded server calls this automatically for builtin providers; for custom providers, register during startup (e.g., after loading auths) or upon auth registration hooks.
## Credentials & Transports
- Use `Manager.SetRoundTripperProvider` to inject perauth `*http.Transport` (e.g., proxy):
```go
core.SetRoundTripperProvider(myProvider) // returns transport per auth
```
- For raw HTTP flows, implement `PrepareRequest` and/or call `Manager.InjectCredentials(req, authID)` to set headers.
## Testing Tips
- Enable request logging: Management API GET/PUT `/v0/management/request-log`
- Toggle debug logs: Management API GET/PUT `/v0/management/debug`
- Hot reload changes in `config.yaml` and `auths/` are picked up automatically by the watcher