fix(openai_compat): gate prompt_cache_key to OpenAI endpoints
This commit is contained in:
parent
8581d46eaa
commit
3d80078db7
2 changed files with 100 additions and 2 deletions
|
|
@ -155,9 +155,9 @@ func (p *Provider) Chat(
|
|||
// The key is typically the agent ID — stable per agent, shared across requests.
|
||||
// See: https://platform.openai.com/docs/guides/prompt-caching
|
||||
// Prompt caching is only supported by OpenAI-native endpoints.
|
||||
// Gemini and other providers reject unknown fields, so skip for non-OpenAI APIs.
|
||||
// Other OpenAI-compatible providers may reject unknown fields.
|
||||
if cacheKey, ok := options["prompt_cache_key"].(string); ok && cacheKey != "" {
|
||||
if !strings.Contains(p.apiBase, "generativelanguage.googleapis.com") {
|
||||
if supportsPromptCacheKey(p.apiBase) {
|
||||
requestBody["prompt_cache_key"] = cacheKey
|
||||
}
|
||||
}
|
||||
|
|
@ -195,6 +195,18 @@ func (p *Provider) Chat(
|
|||
return parseResponse(body)
|
||||
}
|
||||
|
||||
func supportsPromptCacheKey(apiBase string) bool {
|
||||
host := ""
|
||||
if parsed, err := url.Parse(apiBase); err == nil {
|
||||
host = parsed.Hostname()
|
||||
}
|
||||
if host == "" {
|
||||
host = apiBase
|
||||
}
|
||||
host = strings.ToLower(strings.TrimSpace(host))
|
||||
return host == "openai.com" || strings.HasSuffix(host, ".openai.com")
|
||||
}
|
||||
|
||||
func parseResponse(body []byte) (*LLMResponse, error) {
|
||||
var apiResponse struct {
|
||||
Choices []struct {
|
||||
|
|
|
|||
|
|
@ -376,6 +376,92 @@ func TestProviderChat_AcceptsNumericOptionTypes(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestProviderChat_SkipsPromptCacheKeyForNonOpenAIEndpoint(t *testing.T) {
|
||||
var requestBody map[string]any
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := json.NewDecoder(r.Body).Decode(&requestBody); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
resp := map[string]any{
|
||||
"choices": []map[string]any{
|
||||
{
|
||||
"message": map[string]any{"content": "ok"},
|
||||
"finish_reason": "stop",
|
||||
},
|
||||
},
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(resp)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
p := NewProvider("key", server.URL, "")
|
||||
_, err := p.Chat(
|
||||
t.Context(),
|
||||
[]Message{{Role: "user", Content: "hi"}},
|
||||
nil,
|
||||
"gpt-4o",
|
||||
map[string]any{"prompt_cache_key": "agent-123"},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("Chat() error = %v", err)
|
||||
}
|
||||
|
||||
if _, ok := requestBody["prompt_cache_key"]; ok {
|
||||
t.Fatalf("did not expect prompt_cache_key for non-OpenAI endpoint")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSupportsPromptCacheKey(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
apiBase string
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "openai endpoint",
|
||||
apiBase: "https://api.openai.com/v1",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "openai apex endpoint",
|
||||
apiBase: "https://openai.com/v1",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "nvidia endpoint",
|
||||
apiBase: "https://integrate.api.nvidia.com/v1",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "gemini endpoint",
|
||||
apiBase: "https://generativelanguage.googleapis.com/v1beta",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "openrouter endpoint",
|
||||
apiBase: "https://openrouter.ai/api/v1",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "local endpoint",
|
||||
apiBase: "http://localhost:11434/v1",
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := supportsPromptCacheKey(tt.apiBase)
|
||||
if got != tt.want {
|
||||
t.Fatalf("supportsPromptCacheKey(%q) = %v, want %v", tt.apiBase, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeModel_UsesAPIBase(t *testing.T) {
|
||||
if got := normalizeModel("deepseek/deepseek-chat", "https://api.deepseek.com/v1"); got != "deepseek-chat" {
|
||||
t.Fatalf("normalizeModel(deepseek) = %q, want %q", got, "deepseek-chat")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue