Commit Graph

625 Commits

Author SHA1 Message Date
Luis Pater
8564142fb0 fix(claude): preserve non-result block positions during tool result alignment
- Maintain non-tool-result content blocks at their original indices in `AlignClaudeToolResults` instead of moving them after results.
- Reorder tool results in-place into their original slot indices based on preceding tool use IDs.

Closes: #5484
2026-09-07 01:09:18 +08:00
sususu
f6d19a329c fix(gemini): ensure functionResponse normalizes to user role in Gemini request normalizer 2026-09-04 18:21:37 +08:00
sususu
f2041a2c78 fix(antigravity): use ContentHasGeminiFunctionResponse instead of gjson projection 2026-09-04 18:21:37 +08:00
sususu
e56fae88c0 fix(translator): flush pending developer notice before intervening user turn 2026-09-04 18:21:37 +08:00
sususu
0fe19ede90 fix(translator): preserve Gemini prompt cache by demoting mid-session developer messages (#5490)
- Responses API: only hoist developer/system messages before conversation starts to systemInstruction, keeping token 0 cache prefix immutable. Demote mid-session developer messages to user role and merge consecutive user turns via MergeAdjacentGeminiUserContents without crossing functionResponse boundaries.
- Tool Call Buffer: buffer mid-session developer messages during pending function calls and emit after functionResponse, preserving valid tool pairing and reason replay.
- Chat Completions API: apply the same leading/mid-session distinction for system/developer messages and guard against empty parts.
- Claude Messages API: align role: "developer" in messages with role: "system", demoting to <system-reminder> user turns and avoiding upstream 400s.
- Validation: update ValidateGeminiFunctionCallPairing to allow intervening user turns before functionResponse, matching upstream Antigravity tolerance.
- Role Normalization: ensure functionResponse turns in Antigravity are always normalized to role: "user".
2026-09-04 18:21:37 +08:00
Luis Pater
aa36527752 fix(translator/claude): downgrade strict mode when schema misses required properties
- Recursively inspect JSON schema properties to detect optional fields not listed in the `required` array.
- Downgrade `strict` to false when schemas contain optional properties to prevent backend HTTP 400 rejections.

Closes: #5463
2026-09-04 02:02:19 +08:00
Luis Pater
6a26e92a8c fix(translator/interactions): avoid tool name collisions with Antigravity intrinsic tools
- Prefix colliding tool names (`read_file`, `write_file`, `execute_code`) with `external_` when sending requests upstream to Antigravity models.
- Strip the `external_` prefix from Antigravity responses so clients receive the original tool names.
- Apply the name mapping across tool definitions, tool calls, tool results, and tool choice in both Chat Completions and Responses translators.

Closes: #5462
2026-09-04 01:55:33 +08:00
Luis Pater
ba2cdea3b9 fix(translator/claude): handle incomplete status and terminal state on max_tokens
- Map Claude `max_tokens` stop reason to `response.incomplete` with `max_output_tokens` incomplete details.
- Propagate `incomplete` status to trailing output items across streaming and non-streaming responses.
- Defer and track output item finalization to ensure correct status and arguments when turns are truncated.

Closes: #5439
2026-09-04 00:39:18 +08:00
Luis Pater
f804fb5f30 fix(translator/claude): defer message_delta and cache streaming usage
- Cache token usage metrics from streaming chunks instead of prematurely finalizing content blocks.
- Defer `message_delta` and `message_stop` emissions until encountering a finish reason, a trailing usage chunk, or stream completion.

Closes: #5419
2026-09-03 22:14:30 +08:00
Luis Pater
728ea8b855 fix(translator/gemini): nest image parts inside functionResponse
- Embed image parts under `functionResponse.parts` as `inlineData` instead of appending them as sibling parts to the function response.

Closes: #5415
2026-09-03 21:53:49 +08:00
Luis Pater
8deeb4ac31 fix(antigravity): preserve unsigned gemini thinking blocks with trailing carriers
- Precompute carrier context in signature validation to preserve unsigned Gemini thinking blocks followed by valid trailing carriers.
- Avoid dropping unsigned thinking blocks during request translation for Gemini models.
- Validate carrier directions and placement against adjacent semantic content blocks.

Closes: #4628
2026-09-01 21:56:18 +08:00
Luis Pater
15231e9fdc fix(antigravity): support native thinking signatures without prefixes in claude translator
- Emit provider-native signatures without model group prefixes in Claude responses.
- Validate client-provided signatures directly and restrict signature cache recovery to omitted signatures.

Closes: #4445
2026-09-01 20:36:26 +08:00
Luis Pater
893abbabc2 feat(translator): support cache write tokens in claude responses
- Extract cache write tokens from OpenAI and Codex usage details.
- Map cache write tokens to Claude `cache_creation_input_tokens` for streaming and non-streaming responses.

Closes: #4262
2026-09-01 19:56:40 +08:00
Luis Pater
17a65ee547 fix(codex): support reasoning_text in openai chat completion responses
- Handle `response.reasoning_text.delta` and `response.reasoning_text.done` stream events for delta reasoning content.
- Extract `reasoning_text` content from output reasoning items in non-streaming responses.

Closes: #5378
2026-09-01 18:12:52 +08:00
Luis Pater
9fdc460585 fix(claude): preserve tool pairing across intervening system messages
- Preserve pending tool use IDs across message-level system reminders to maintain tool call and result alignment.
- Merge adjacent Gemini request contents for consecutive user and system reminder turns.
- Relax tool response reordering condition and preserve non-response parts in Antigravity executor.
- Align tool results and buffer pending system reminders in OpenAI translator.

Closes: #5354
2026-08-31 19:27:20 +08:00
Luis Pater
6c6473f899 fix(openai): ignore empty tool calls array in responses translation
- Ensure the `tool_calls` array is non-empty before stopping reasoning and terminating output items.

Closes: #5333
2026-08-30 13:47:18 +08:00
Luis Pater
c350d3f520 fix(claude): strip trailing thinking blocks from assistant messages
- Strip trailing `thinking` and `redacted_thinking` blocks from the final assistant message during OpenAI responses translation.
- Drop the assistant message if no content blocks remain after stripping trailing thinking blocks.

Closes: #5321
2026-08-29 05:07:19 +08:00
Luis Pater
6f25b9a149 fix(claude): drop unsupported assistant prefill for opus-5 and sonnet-4-6
- Strip trailing assistant prefill messages for Opus 5 and Sonnet 4.6 model families in addition to Fable models during OpenAI responses translation.

Closes: #5319
2026-08-29 04:58:59 +08:00
Luis Pater
07d8156375 fix(claude): collapse consecutive thinking blocks in openai responses translation
- Replace consecutive thinking blocks with the latest reasoning item in assistant messages.
- Flush pending tool use parts upon encountering subsequent reasoning items to maintain proper block separation.

Closes: #5317
2026-08-29 04:26:46 +08:00
Luis Pater
be1763e59e fix(claude): fallback to array index when tool call index is omitted
- Fall back to array index in tool calls accumulator when the `index` field is missing.
- Ensure parallel tool calls without explicit indices are accumulated properly during streaming.

Closes: #5058
2026-08-29 01:22:20 +08:00
Luis Pater
677dbe1dc5 fix(claude): emit message_delta when openai streaming finish reason is omitted
- Ensure `message_delta` is emitted on tool call usage chunks and stream completion even if `finish_reason` is missing or null.
- Add `terminalOpenAIFinishReason` fallback to map missing finish reasons to standard stop reasons.
- Consolidate content block finalization into `finalizeOpenAIAnthropicContentBlocks` and delta emission into `emitAnthropicMessageDelta`.

Closes: #5308
2026-08-29 01:22:18 +08:00
Luis Pater
f8c45c30c5 feat(codex): map claude output_config format to text format
- Map Claude `output_config.format` with `json_schema` type to Codex `text.format`.
- Preserve custom schema name and strict configuration with appropriate defaults.

Closes: #5280
2026-08-27 18:19:04 +08:00
Luis Pater
8ee9add75d fix(claude): drop trailing assistant prefill for fable models
- Drop unsupported trailing assistant prefill messages when converting requests for Claude Fable models.
- Fall back to an empty user message turn when dropping assistant messages leaves the request empty.

Closes: #5279
2026-08-27 18:04:56 +08:00
Luis Pater
06997df44a fix(gemini): cache trailing text thought signatures instead of emitting carriers
- Cache trailing thought signatures associated with preceding text blocks via best-effort cache.
- Suppress emitting detached thinking carrier blocks after visible text in streaming and non-streaming responses.

Closes: #5272
2026-08-27 17:21:58 +08:00
Luis Pater
6f6856e784 fix(gemini): map cached content tokens to claude cache read usage
- Deduct `cachedContentTokenCount` from `promptTokenCount` for `usage.input_tokens`.
- Set `usage.cache_read_input_tokens` when cached tokens are present in streaming and non-streaming responses.

Closes: #5238
2026-08-27 04:19:22 +08:00
Luis Pater
4fa1de2f9b feat(claude): support server-side web search translation for openai responses
- Map Claude `server_tool_use` and `web_search_tool_result` content blocks to OpenAI Responses `web_search_call` items in streaming and non-streaming modes.
- Support replaying `web_search_call` items and text search annotations back to Claude server tool blocks and citations.

Closes: #5236
2026-08-27 04:04:11 +08:00
Luis Pater
cb8746fb63 fix(claude): use zero-based sequential index for streamed tool calls
- Track tool call indices independently using a sequential counter instead of reusing Claude content block indices.
- Set the sequential tool call index when emitting streaming delta chunks.

Closes: #5229
2026-08-27 02:39:02 +08:00
sususu98
998dcfeba2 fix(antigravity): safely synthesize terminal finish reasons (#5230)
The Antigravity backend sometimes ends a 200 stream without ever emitting
finishReason. Evidence from local request logs: 25 of 18,346 captured
cloudcode-pa streams have no finishReason at all (gemini-3.7-flash x23,
gemini-3.6-flash x2). Gemini and OpenAI chat clients then never see a
terminal event and wait forever.

Only synthesize on a clean end of stream
- The [DONE] tail is now translated only when scanner.Err() is nil. A
  truncated upstream stream previously still produced a terminal event:
  replaying a cut stream to a Claude client emitted the full
  content_block_stop / message_delta / message_stop sequence, so the
  truncation was reported as a completed message.
- Only Antigravity translators synthesize on [DONE], so the other
  executors that emit the tail before checking scanner.Err() cannot leak a
  fake terminal event and are left unchanged.

Never finalize a stream that produced nothing
- Synthesis requires at least one chunk carrying candidates or token
  accounting. Both translators share the same check, and presence alone is
  not enough: `{}`, `{"response":{}}` and `{"response":{"candidates":[]}}`
  leave the stream unstarted.
- Without that guard the synthetic chunk defeats the existing empty_stream
  detection in sdk/cliproxy/auth/conductor_stream.go, which only fires when
  the executor produced no chunk at all. An empty 200 would be reported as
  a successful empty completion instead of a failure.

Synthetic chunks mirror the observed upstream shape
- All 18,321 real terminal chunks carry candidates/usageMetadata/
  modelVersion/responseId with a model-role candidate whose parts are
  [{"text":""}]. The Gemini synthetic chunk now reproduces that shape and
  key order instead of a bare finishReason candidate.
- The last known usage snapshot is carried into the synthetic chunk.
  Without it the final chunk a client sees reports no tokens, because
  FilterSSEUsageMetadata renames non-terminal usage to cpaUsageMetadata
  and the Gemini path restores it per chunk.
- The OpenAI chat path keeps the latest cpaUsageMetadata as pending usage
  and emits it on [DONE] for the same reason.

Do not mistake an intermediate chunk for the terminal one
- A chunk carrying usage but no finishReason stays non-terminal.
  FilterSSEUsageMetadata forwards real usageMetadata on such a chunk only
  after an earlier chunk already carried finishReason, which the existing
  condition covers; finalizing on usage alone would cut the stream short.
- finish_reason and native_finish_reason are resolved by one shared
  helper, so the upstream terminal chunk and the synthesized [DONE] chunk
  cannot drift apart.
- The non-stream Gemini conversion defaults a missing finishReason for
  every candidate rather than only the first one.

Also fixes the unreachable alt != "" branch, which parsed an always-nil
buffer, and replaces an unchecked param type assertion.

Verified by replaying byte-exact upstream bodies extracted from request
logs through a mock backend, comparing this change against the unmodified
branch point: clean streams keep exactly one terminal event, streams
without finishReason gain one carrying the last usage snapshot, a stream
cut mid-chunk surfaces the read error with no terminal event, and an empty
200 now fails with empty_stream instead of reporting a successful empty
completion.
2026-08-25 15:13:04 +08:00
Luis Pater
f2b1996b3f fix(gemini,antigravity): align parallel tool results with preceding tool calls
- Add `AlignClaudeToolResults` to order `tool_result` blocks to match the preceding `tool_use` IDs while preserving other content parts.
- Apply tool result alignment in Claude-to-Gemini and Claude-to-Antigravity request translators.
- Preserve mixed non-response parts when normalizing and reordering parallel function responses in Antigravity executor.

Closes: #5199
2026-08-25 14:57:46 +08:00
Luis Pater
9d0a60bfc3 fix(gemini,antigravity): preserve function/tool results as raw strings
- Keep `functionResponse.response.result` as a string in Gemini responses translation instead of JSON-parsing tool output.
- Apply the same string-preserving behavior for antigravity tool responses to avoid upstream 400 errors from parsed payloads.
2026-08-23 15:09:34 +08:00
Luis Pater
d5b57a2d8a fix(openai): validate and filter thought signatures in responses conversion
Closes: #5166
2026-08-22 17:30:26 +08:00
Luis Pater
ab8f00dbd9 fix(claude): derive stable request-scoped metadata.user_id for converters
Closes: #5153
2026-08-22 16:01:25 +08:00
Luis Pater
b3f72cef65 fix(gemini): normalize Claude thinking signatures in Gemini request and response conversion
Closes: #5151
2026-08-22 15:35:54 +08:00
Luis Pater
65071f7c47 test(claude): expand OpenAI conversion tests for reasoning_content and stream/non-stream parity
Closes: #5148
2026-08-22 13:20:00 +08:00
Luis Pater
d9869ed908 test(openai): expand reasoning fallback coverage in OpenAI responses non-stream conversion tests
Closes: #5147
2026-08-22 13:08:11 +08:00
Luis Pater
b1c000590b fix(gemini): include empty annotations/logprobs in response.output_item.done message content
Closes: #5116
2026-08-21 04:16:08 +08:00
Luis Pater
68e96c2716 fix(openai): map max_completion_tokens to Antigravity maxOutputTokens
- Add `max_completion_tokens` fallback handling in OpenAI→Antigravity request conversion.
- Keep `max_tokens` as the preferred source when both fields are present.

Closes: #5108
2026-08-21 03:52:26 +08:00
Luis Pater
5b232e3e98 fix(gemini): generate deterministic sequential IDs for Gemini tool call pairing in Codex/Claude conversions
Closes: #5107
2026-08-21 03:21:55 +08:00
Luis Pater
3db591eecd fix(gemini): preserve Gemini thought signatures in non-stream Claude conversion
Closes: #5106
2026-08-21 03:04:12 +08:00
Luis Pater
8eb3ac2e03 fix(openai): fallback to reasoning when reasoning_content is missing in response conversion
Closes: #5105
2026-08-21 02:41:37 +08:00
Luis Pater
aa5dccc236 fix(claude): use message.reasoning_content for converted thinking output
Closes: #5104
2026-08-21 02:16:01 +08:00
Luis Pater
556328c122 feat(gemini): add namespace-aware OpenAI Responses tool resolution and custom tool call conversion
- Add shared tool descriptor collection and winner selection for Responses tools (top-level vs `additional_tools`, direct vs namespace child, and ordering rules).
- Introduce sanitized Gemini function name mapping with collision disambiguation and 64-char-safe truncation.
- Build forward/reverse tool identity maps for restoring original tool identity (`name`, `namespace`, `custom`) during translation.
- Update Gemini→Responses streaming conversion to emit proper custom tool call events and identity-aware function call events.
- Add helpers for translating `tool_choice` to Gemini config and unwrapping custom tool input payloads.

Closes: #5088
2026-08-20 13:47:15 +08:00
Luis Pater
2005788fc3 fix(codex): filter out prompt_cache_retention in OpenAI→Codex responses request conversion
Closes: #5068
2026-08-19 21:29:03 +08:00
sususu98
79ef3618d6 fix(antigravity): attach sibling tool images to the nearest functionResponse (#5075)
Responses→Gemini emits functionResponse plus sibling inline_data, but
fixCLIToolResponse previously dropped those images when regrouping tool
turns. Cloud Code Assist only sees tool images nested in
functionResponse.parts with an explicit mimeType, and parallel tool
results must stay bound to the nearest preceding functionResponse
instead of last-wins.

Closes #5070
2026-08-19 18:58:04 +08:00
Luis Pater
497673bf6b feat(antigravity): add video_url content part support to OpenAI request conversion
Closes: #5056
2026-08-19 02:18:39 +08:00
Luis Pater
4ac37ed3cd fix(claude): always send stop as an array when converting stop_sequences in OpenAI requests
Closes: #5054
2026-08-18 21:14:21 +08:00
Luis Pater
3230e37023 fix(claude): accept both max_tokens and max_completion_tokens in OpenAI→Claude request conversion
- Prefer `max_tokens` when both `max_tokens` and `max_completion_tokens` are present, otherwise use whichever exists.
- Default to existing template `max_tokens` limit when neither field is provided.
- Add regression coverage for all token-limit source/preference paths.

Closes: #5040
2026-08-18 13:46:27 +08:00
Luis Pater
20f84e78c1 fix(gemini): support mixed and structured function_call_output handling in OpenAI→Gemini responses translation
Closes: #5039
2026-08-18 13:37:37 +08:00
Luis Pater
7eefab98b8 feat(claude): map OpenAI service_tier to Claude speed in responses requests
- Translate `service_tier: "priority"` to `speed: "fast"` in `ConvertOpenAIResponsesRequestToClaude`.
- Leave `speed` unset for default/absent/standard/unsupported `service_tier` values.

Closes: #5003
2026-08-16 05:36:42 +08:00
Luis Pater
7efe0a7c11 pref(claude): keep raw Claude tool IDs for deduplication in request translation
- Use original `call_id` / `tool_call_id` values as keys for tool-result/message caches and emitted-id tracking in Claude OpenAI request translators.
- Avoid mixed sanitized-vs-raw ID lookups that could cause duplicate or missed deduplication of repeated tool outputs.
2026-08-16 03:06:44 +08:00