From 2f477df97e331f33c3f9ad6332e0020bff3781d6 Mon Sep 17 00:00:00 2001 From: Luis Pater Date: Thu, 30 Oct 2025 12:20:46 +0800 Subject: [PATCH] feat(translator): add built-in translator registry and helpers - Introduced `builtin` package exposing a default registry and pipeline for built-in translators. - Added format constants for common schemas (e.g., OpenAI, Gemini, Codex). - Implemented helper functions for schema translation using format name strings. - Provided example usage for integration with translator helpers. --- examples/translator/main.go | 42 +++++++++++++++++++++++++++++++ sdk/translator/builtin/builtin.go | 18 +++++++++++++ sdk/translator/formats.go | 11 ++++++++ sdk/translator/helpers.go | 28 +++++++++++++++++++++ 4 files changed, 99 insertions(+) create mode 100644 examples/translator/main.go create mode 100644 sdk/translator/builtin/builtin.go create mode 100644 sdk/translator/formats.go create mode 100644 sdk/translator/helpers.go diff --git a/examples/translator/main.go b/examples/translator/main.go new file mode 100644 index 00000000..88f142a3 --- /dev/null +++ b/examples/translator/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "context" + "fmt" + + "github.com/router-for-me/CLIProxyAPI/v6/sdk/translator" + _ "github.com/router-for-me/CLIProxyAPI/v6/sdk/translator/builtin" +) + +func main() { + rawRequest := []byte(`{"messages":[{"content":[{"text":"Hello! Gemini","type":"text"}],"role":"user"}],"model":"gemini-2.5-pro","stream":false}`) + fmt.Println("Has gemini->openai response translator:", translator.HasResponseTransformerByFormatName( + translator.FormatGemini, + translator.FormatOpenAI, + )) + + translatedRequest := translator.TranslateRequestByFormatName( + translator.FormatOpenAI, + translator.FormatGemini, + "gemini-2.5-pro", + rawRequest, + false, + ) + + fmt.Printf("Translated request to Gemini format:\n%s\n\n", translatedRequest) + + claudeResponse := []byte(`{"candidates":[{"content":{"role":"model","parts":[{"thought":true,"text":"Okay, here's what's going through my mind. I need to schedule a meeting"},{"thoughtSignature":"","functionCall":{"name":"schedule_meeting","args":{"topic":"Q3 planning","attendees":["Bob","Alice"],"time":"10:00","date":"2025-03-27"}}}]},"finishReason":"STOP","avgLogprobs":-0.50018133435930523}],"usageMetadata":{"promptTokenCount":117,"candidatesTokenCount":28,"totalTokenCount":474,"trafficType":"PROVISIONED_THROUGHPUT","promptTokensDetails":[{"modality":"TEXT","tokenCount":117}],"candidatesTokensDetails":[{"modality":"TEXT","tokenCount":28}],"thoughtsTokenCount":329},"modelVersion":"gemini-2.5-pro","createTime":"2025-08-15T04:12:55.249090Z","responseId":"x7OeaIKaD6CU48APvNXDyA4"}`) + + convertedResponse := translator.TranslateNonStreamByFormatName( + context.Background(), + translator.FormatGemini, + translator.FormatOpenAI, + "gemini-2.5-pro", + rawRequest, + translatedRequest, + claudeResponse, + nil, + ) + + fmt.Printf("Converted response for OpenAI clients:\n%s\n", convertedResponse) +} diff --git a/sdk/translator/builtin/builtin.go b/sdk/translator/builtin/builtin.go new file mode 100644 index 00000000..798e43f1 --- /dev/null +++ b/sdk/translator/builtin/builtin.go @@ -0,0 +1,18 @@ +// Package builtin exposes the built-in translator registrations for SDK users. +package builtin + +import ( + sdktranslator "github.com/router-for-me/CLIProxyAPI/v6/sdk/translator" + + _ "github.com/router-for-me/CLIProxyAPI/v6/internal/translator" +) + +// Registry exposes the default registry populated with all built-in translators. +func Registry() *sdktranslator.Registry { + return sdktranslator.Default() +} + +// Pipeline returns a pipeline that already contains the built-in translators. +func Pipeline() *sdktranslator.Pipeline { + return sdktranslator.NewPipeline(sdktranslator.Default()) +} diff --git a/sdk/translator/formats.go b/sdk/translator/formats.go new file mode 100644 index 00000000..658eafae --- /dev/null +++ b/sdk/translator/formats.go @@ -0,0 +1,11 @@ +package translator + +// Common format identifiers exposed for SDK users. +const ( + FormatOpenAI Format = "openai" + FormatOpenAIResponse Format = "openai-response" + FormatClaude Format = "claude" + FormatGemini Format = "gemini" + FormatGeminiCLI Format = "gemini-cli" + FormatCodex Format = "codex" +) diff --git a/sdk/translator/helpers.go b/sdk/translator/helpers.go new file mode 100644 index 00000000..bf8cfbf7 --- /dev/null +++ b/sdk/translator/helpers.go @@ -0,0 +1,28 @@ +package translator + +import "context" + +// TranslateRequestByFormatName converts a request payload between schemas by their string identifiers. +func TranslateRequestByFormatName(from, to Format, model string, rawJSON []byte, stream bool) []byte { + return TranslateRequest(from, to, model, rawJSON, stream) +} + +// HasResponseTransformerByFormatName reports whether a response translator exists between two schemas. +func HasResponseTransformerByFormatName(from, to Format) bool { + return HasResponseTransformer(from, to) +} + +// TranslateStreamByFormatName converts streaming responses between schemas by their string identifiers. +func TranslateStreamByFormatName(ctx context.Context, from, to Format, model string, originalRequestRawJSON, requestRawJSON, rawJSON []byte, param *any) []string { + return TranslateStream(ctx, from, to, model, originalRequestRawJSON, requestRawJSON, rawJSON, param) +} + +// TranslateNonStreamByFormatName converts non-streaming responses between schemas by their string identifiers. +func TranslateNonStreamByFormatName(ctx context.Context, from, to Format, model string, originalRequestRawJSON, requestRawJSON, rawJSON []byte, param *any) string { + return TranslateNonStream(ctx, from, to, model, originalRequestRawJSON, requestRawJSON, rawJSON, param) +} + +// TranslateTokenCountByFormatName converts token counts between schemas by their string identifiers. +func TranslateTokenCountByFormatName(ctx context.Context, from, to Format, count int64, rawJSON []byte) string { + return TranslateTokenCount(ctx, from, to, count, rawJSON) +}