History

Merge branch 'router-for-me:main' into main

Luis Pater committed 10 months agov6.6.59-0

Commit d35152b2 parents 60936b5 c281f4c3 files · +23 −20Browse files

Unified · Split

3 files
  1. internal/runtime/executor/usage_helpers.go +6 −2
  2. internal/translator/antigravity/claude/antigravity_claude_response.go +8 −0
  3. sdk/cliproxy/auth/conductor.go +9 −18
internal/runtime/executor/usage_helpers.go+6−2
@@ -482,12 +482,16 @@ func StripUsageMetadataFromJSON(rawJSON []byte) ([]byte, bool) { · 481 unmodified lines
482 cleaned := jsonBytes482 cleaned := jsonBytes
483 var changed bool483 var changed bool
484 484
485 if gjson.GetBytes(cleaned, "usageMetadata").Exists() {485 if usageMetadata = gjson.GetBytes(cleaned, "usageMetadata"); usageMetadata.Exists() {
486 // Rename usageMetadata to cpaUsageMetadata in the message_start event of Claude
487 cleaned, _ = sjson.SetRawBytes(cleaned, "cpaUsageMetadata", []byte(usageMetadata.Raw))
486 cleaned, _ = sjson.DeleteBytes(cleaned, "usageMetadata")488 cleaned, _ = sjson.DeleteBytes(cleaned, "usageMetadata")
487 changed = true489 changed = true
488 }490 }
489 491
490 if gjson.GetBytes(cleaned, "response.usageMetadata").Exists() {492 if usageMetadata = gjson.GetBytes(cleaned, "response.usageMetadata"); usageMetadata.Exists() {
493 // Rename usageMetadata to cpaUsageMetadata in the message_start event of Claude
494 cleaned, _ = sjson.SetRawBytes(cleaned, "response.cpaUsageMetadata", []byte(usageMetadata.Raw))
491 cleaned, _ = sjson.DeleteBytes(cleaned, "response.usageMetadata")495 cleaned, _ = sjson.DeleteBytes(cleaned, "response.usageMetadata")
492 changed = true496 changed = true
493 }497 }
internal/translator/antigravity/claude/antigravity_claude_response.go+8−0
@@ -99,6 +99,14 @@ func ConvertAntigravityResponseToClaude(_ context.Context, _ string, originalReq · 98 unmodified lines
99 // This follows the Claude Code API specification for streaming message initialization99 // This follows the Claude Code API specification for streaming message initialization
100 messageStartTemplate := `{"type": "message_start", "message": {"id": "msg_1nZdL29xx5MUA1yADyHTEsnR8uuvGzszyY", "type": "message", "role": "assistant", "content": [], "model": "claude-3-5-sonnet-20241022", "stop_reason": null, "stop_sequence": null, "usage": {"input_tokens": 0, "output_tokens": 0}}}`100 messageStartTemplate := `{"type": "message_start", "message": {"id": "msg_1nZdL29xx5MUA1yADyHTEsnR8uuvGzszyY", "type": "message", "role": "assistant", "content": [], "model": "claude-3-5-sonnet-20241022", "stop_reason": null, "stop_sequence": null, "usage": {"input_tokens": 0, "output_tokens": 0}}}`
101 101
102 // Use cpaUsageMetadata within the message_start event for Claude.
103 if promptTokenCount := gjson.GetBytes(rawJSON, "response.cpaUsageMetadata.promptTokenCount"); promptTokenCount.Exists() {
104 messageStartTemplate, _ = sjson.Set(messageStartTemplate, "message.usage.input_tokens", promptTokenCount.Int())
105 }
106 if candidatesTokenCount := gjson.GetBytes(rawJSON, "response.cpaUsageMetadata.candidatesTokenCount"); candidatesTokenCount.Exists() {
107 messageStartTemplate, _ = sjson.Set(messageStartTemplate, "message.usage.output_tokens", candidatesTokenCount.Int())
108 }
109
102 // Override default values with actual response metadata if available from the Gemini CLI response110 // Override default values with actual response metadata if available from the Gemini CLI response
103 if modelVersionResult := gjson.GetBytes(rawJSON, "response.modelVersion"); modelVersionResult.Exists() {111 if modelVersionResult := gjson.GetBytes(rawJSON, "response.modelVersion"); modelVersionResult.Exists() {
104 messageStartTemplate, _ = sjson.Set(messageStartTemplate, "message.model", modelVersionResult.String())112 messageStartTemplate, _ = sjson.Set(messageStartTemplate, "message.model", modelVersionResult.String())
sdk/cliproxy/auth/conductor.go+9−18
@@ -263,7 +263,6 @@ func (m *Manager) Execute(ctx context.Context, providers []string, req cliproxye · 262 unmodified lines
263 return cliproxyexecutor.Response{}, &Error{Code: "provider_not_found", Message: "no provider supplied"}263 return cliproxyexecutor.Response{}, &Error{Code: "provider_not_found", Message: "no provider supplied"}
264 }264 }
265 rotated := m.rotateProviders(req.Model, normalized)265 rotated := m.rotateProviders(req.Model, normalized)
266 defer m.advanceProviderCursor(req.Model, normalized)
267 266
268 retryTimes, maxWait := m.retrySettings()267 retryTimes, maxWait := m.retrySettings()
269 attempts := retryTimes + 1268 attempts := retryTimes + 1
@@ -302,7 +301,6 @@ func (m *Manager) ExecuteCount(ctx context.Context, providers []string, req clip · 32 unmodified lines
302 return cliproxyexecutor.Response{}, &Error{Code: "provider_not_found", Message: "no provider supplied"}301 return cliproxyexecutor.Response{}, &Error{Code: "provider_not_found", Message: "no provider supplied"}
303 }302 }
304 rotated := m.rotateProviders(req.Model, normalized)303 rotated := m.rotateProviders(req.Model, normalized)
305 defer m.advanceProviderCursor(req.Model, normalized)
306 304
307 retryTimes, maxWait := m.retrySettings()305 retryTimes, maxWait := m.retrySettings()
308 attempts := retryTimes + 1306 attempts := retryTimes + 1
@@ -341,7 +339,6 @@ func (m *Manager) ExecuteStream(ctx context.Context, providers []string, req cli · 32 unmodified lines
341 return nil, &Error{Code: "provider_not_found", Message: "no provider supplied"}339 return nil, &Error{Code: "provider_not_found", Message: "no provider supplied"}
342 }340 }
343 rotated := m.rotateProviders(req.Model, normalized)341 rotated := m.rotateProviders(req.Model, normalized)
344 defer m.advanceProviderCursor(req.Model, normalized)
345 342
346 retryTimes, maxWait := m.retrySettings()343 retryTimes, maxWait := m.retrySettings()
347 attempts := retryTimes + 1344 attempts := retryTimes + 1
@@ -640,13 +637,20 @@ func (m *Manager) normalizeProviders(providers []string) []string { · 292 unmodified lines
640 return result637 return result
641}638}
642 639
640// rotateProviders returns a rotated view of the providers list starting from the
641// current offset for the model, and atomically increments the offset for the next call.
642// This ensures concurrent requests get different starting providers.
643func (m *Manager) rotateProviders(model string, providers []string) []string {643func (m *Manager) rotateProviders(model string, providers []string) []string {
644 if len(providers) == 0 {644 if len(providers) == 0 {
645 return nil645 return nil
646 }646 }
647 m.mu.RLock()647
648 // Atomic read-and-increment: get current offset and advance cursor in one lock
649 m.mu.Lock()
648 offset := m.providerOffsets[model]650 offset := m.providerOffsets[model]
649 m.mu.RUnlock()651 m.providerOffsets[model] = (offset + 1) % len(providers)
652 m.mu.Unlock()
653
650 if len(providers) > 0 {654 if len(providers) > 0 {
651 offset %= len(providers)655 offset %= len(providers)
652 }656 }
@@ -662,19 +666,6 @@ func (m *Manager) rotateProviders(model string, providers []string) []string { · 9 unmodified lines
662 return rotated666 return rotated
663}667}
664 668
665func (m *Manager) advanceProviderCursor(model string, providers []string) {
666 if len(providers) == 0 {
667 m.mu.Lock()
668 delete(m.providerOffsets, model)
669 m.mu.Unlock()
670 return
671 }
672 m.mu.Lock()
673 current := m.providerOffsets[model]
674 m.providerOffsets[model] = (current + 1) % len(providers)
675 m.mu.Unlock()
676}
677
678func (m *Manager) retrySettings() (int, time.Duration) {669func (m *Manager) retrySettings() (int, time.Duration) {
679 if m == nil {670 if m == nil {
680 return 0, 0671 return 0, 0