Skip to content

Commit d35152b

Browse files
authored
Merge branch 'router-for-me:main' into main
2 parents 60936b5 + c281f4c commit d35152b

File tree

3 files changed

+23
-20
lines changed

3 files changed

+23
-20
lines changed

internal/runtime/executor/usage_helpers.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -482,12 +482,16 @@ func StripUsageMetadataFromJSON(rawJSON []byte) ([]byte, bool) {
482482
cleaned := jsonBytes
483483
var changed bool
484484

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))
486488
cleaned, _ = sjson.DeleteBytes(cleaned, "usageMetadata")
487489
changed = true
488490
}
489491

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))
491495
cleaned, _ = sjson.DeleteBytes(cleaned, "response.usageMetadata")
492496
changed = true
493497
}

internal/translator/antigravity/claude/antigravity_claude_response.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,14 @@ func ConvertAntigravityResponseToClaude(_ context.Context, _ string, originalReq
9999
// This follows the Claude Code API specification for streaming message initialization
100100
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}}}`
101101

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+
102110
// Override default values with actual response metadata if available from the Gemini CLI response
103111
if modelVersionResult := gjson.GetBytes(rawJSON, "response.modelVersion"); modelVersionResult.Exists() {
104112
messageStartTemplate, _ = sjson.Set(messageStartTemplate, "message.model", modelVersionResult.String())

sdk/cliproxy/auth/conductor.go

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,6 @@ func (m *Manager) Execute(ctx context.Context, providers []string, req cliproxye
263263
return cliproxyexecutor.Response{}, &Error{Code: "provider_not_found", Message: "no provider supplied"}
264264
}
265265
rotated := m.rotateProviders(req.Model, normalized)
266-
defer m.advanceProviderCursor(req.Model, normalized)
267266

268267
retryTimes, maxWait := m.retrySettings()
269268
attempts := retryTimes + 1
@@ -302,7 +301,6 @@ func (m *Manager) ExecuteCount(ctx context.Context, providers []string, req clip
302301
return cliproxyexecutor.Response{}, &Error{Code: "provider_not_found", Message: "no provider supplied"}
303302
}
304303
rotated := m.rotateProviders(req.Model, normalized)
305-
defer m.advanceProviderCursor(req.Model, normalized)
306304

307305
retryTimes, maxWait := m.retrySettings()
308306
attempts := retryTimes + 1
@@ -341,7 +339,6 @@ func (m *Manager) ExecuteStream(ctx context.Context, providers []string, req cli
341339
return nil, &Error{Code: "provider_not_found", Message: "no provider supplied"}
342340
}
343341
rotated := m.rotateProviders(req.Model, normalized)
344-
defer m.advanceProviderCursor(req.Model, normalized)
345342

346343
retryTimes, maxWait := m.retrySettings()
347344
attempts := retryTimes + 1
@@ -640,13 +637,20 @@ func (m *Manager) normalizeProviders(providers []string) []string {
640637
return result
641638
}
642639

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.
643643
func (m *Manager) rotateProviders(model string, providers []string) []string {
644644
if len(providers) == 0 {
645645
return nil
646646
}
647-
m.mu.RLock()
647+
648+
// Atomic read-and-increment: get current offset and advance cursor in one lock
649+
m.mu.Lock()
648650
offset := m.providerOffsets[model]
649-
m.mu.RUnlock()
651+
m.providerOffsets[model] = (offset + 1) % len(providers)
652+
m.mu.Unlock()
653+
650654
if len(providers) > 0 {
651655
offset %= len(providers)
652656
}
@@ -662,19 +666,6 @@ func (m *Manager) rotateProviders(model string, providers []string) []string {
662666
return rotated
663667
}
664668

665-
func (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-
678669
func (m *Manager) retrySettings() (int, time.Duration) {
679670
if m == nil {
680671
return 0, 0

0 commit comments

Comments
 (0)