Skip to content

Review only: HOUSE-79 upstream v8.0.44, part 5 of 13: antigravity, gemini, openai-compat executors - #18

Closed
ericlitman wants to merge 1 commit into
review/house79/base-05from
review/house79/chunk-05
Closed

ericlitman wants to merge 1 commit into
review/house79/base-05from
review/house79/chunk-05

Conversation

@ericlitman

@ericlitman ericlitman commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Review only. Do not merge. This PR is one part of the review of #13, the merge of upstream v8.0.44 into the fork. That PR's diff (966 files) is too large for one review round.

  • This part covers: antigravity, gemini, openai-compat executors.
  • The head tree is identical to Merge upstream v8.0.44 into the fork (HOUSE-79) #13 head tree (c88d701f7bc0894cde517ca7f931f5c05749cd74). The base is that tree with only this part's files restored to main (c265779f), so the diff is this part's files alone and the surrounding code is the real final code.
  • The 13 parts together cover every production file the sync changes (410 paths). Tests, golden data, generated model catalogs, images, docs and go.sum are in no part's diff.
  • The code is upstream's, except where our fork's soonest-reset selector, quota observations, quota reserves, usage reads and Terra injection touch it. Review it as code we are about to deploy to the proxy every one of our agents uses: report defects that would affect our deployment.

Linear: HOUSE-79

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

@mergify

mergify Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

This pull request does not currently match the merge queue conditions, so it cannot be queued from here. The box comes back if it matches again.

@unfret

unfret Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

🛑 6 blocking findings

🟡 Medium · Close stream output before waiting for delivery acknowledgment

🟡 Medium · Aliased non-GPT reasoning signatures are discarded

🟡 Medium · Ignore null error fields in successful stream frames

🟡 Medium · Do not cache continuations for unstored interactions

🟡 Medium · Token counting uses the pre-finalization model

🟡 Medium · Bound incomplete JSON buffering to one SSE event

Walkthrough

This review-only slice of the upstream v8.0.44 sync brings in the new antigravity, Gemini/Vertex, AI Studio and OpenAI-compatible executor code. Requests that fail translation are now refused before any token refresh or upstream call, and payload rules are applied last, just before sending. Streams also stop cleanly on blocked prompts, translated error frames, or upstream EOF without a finish reason. Vertex gains routes to its OpenAI-compatible endpoint (for partner models like publisher/model) and a native Interactions route. Reasoning-signature replay and the Responses sanitizer get stricter scoping by caller, provider family and router.

Area What changes Review notes
Antigravity streaming and replay Usage is captured before filtering. JSON split across lines is reassembled. In-band error frames become stream errors. Replay commit and usage publication wait for a delivered terminal chunk and for delivery acknowledgment. The replay ledger is namespaced by a trusted caller scope. Close stream output before waiting for delivery acknowledgment
Ignore null error fields in successful stream frames
Bound incomplete JSON buffering to one SSE event
Antigravity requests Translation errors surface early, and payload config runs through a deferred finalizer. Tool-schema cleaning is per-declaration, with Claude union flattening. Claude 5.5 structured output becomes prompt instructions. Trailing thought-only turns are dropped. INSUFFICIENT_G1_CREDITS_BALANCE now counts as quota exhausted. Token counting uses the pre-finalization model
Gemini / Vertex / AI Studio Adds a prompt-block error, a missing-finishReason truncation error for Claude/OpenAI clients, and buffered stream channels. AI Studio relay chunks are split into per-frame SSE. Adds Vertex OpenAPI and Interactions routing. The Vertex default location changes to global, and US/EU REP hosts are added. Interactions helpers move into helps, along with an antigravity interactions continuation cache. Do not cache continuations for unstored interactions
OpenAI-compat and signatures Executors are split into credential-taking variants so Vertex can reuse them. The User-Agent is only defaulted, no longer forced. The Responses stream is finalized at EOF when the translator permits it. Reasoning encrypted_content is now gated by target provider family, Meta native vs routed, and OpenRouter suffix handling. Aliased non-GPT reasoning signatures are discarded
Since the last review
  • New: Close stream output before waiting for delivery acknowledgment
  • New: Aliased non-GPT reasoning signatures are discarded
  • New: Ignore null error fields in successful stream frames
  • New: Do not cache continuations for unstored interactions
  • New: Token counting uses the pre-finalization model
  • New: Bound incomplete JSON buffering to one SSE event
Repair prompt

Read the Unfret check run for mobilyze-llc/CLIProxyAPI#18 at head c3699df1243745950698f8da5fa9ce59defd7c58 (run panel:c3699df1243745950698f8da5fa9ce59defd7c58:3K2RclLNgzp:zNxk4q8yiCw, check). Use the check's App id and GET /repos/mobilyze-llc/CLIProxyAPI/check-runs/122312290308; its output.text contains the structured result. Compare it with the current code and head, verify that each listed mandatory finding still applies, repair only those that do, honor the repository constraints, and validate the changes. Leave advisories and accepted risks alone. A manually resolved thread is not a waiver.

Details
Lane / stage Model Effort Outcome Duration
broad-gpt-5.6-sol-xhigh / review openai/gpt-5.6-sol → gpt-5.6-sol · primary xhigh succeeded 10 min 29 s
broad-opus-5.5-max / review Not recorded Not recorded failed Not recorded
focal-gpt-5.6-sol-xhigh copy / review openai/gpt-6.1-sol → gpt-6.1-sol · primary xhigh succeeded 15 min 2 s
focal-gpt-5.6-sol-xhigh copy 2 / review openai/gpt-6.1-sol → gpt-6.1-sol · primary xhigh succeeded 18 min 2 s
judge / judge openai/gpt-6-astra → gpt-6-astra · primary high succeeded 1 min 35 s

First review of this pull request.
3 reviewers finished.
Commit c3699df.
Check run.
Run: GET /unfret/run/panel:c3699df1243745950698f8da5fa9ce59defd7c58:3K2RclLNgzp:zNxk4q8yiCw.

@unfret review · @unfret status · @unfret help

@unfret unfret Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛑 6 blocking findings
🟡 Medium · Close stream output before waiting for delivery acknowledgment
🟡 Medium · Aliased non-GPT reasoning signatures are discarded
🟡 Medium · Ignore null error fields in successful stream frames
🟡 Medium · Do not cache continuations for unstored interactions
🟡 Medium · Token counting uses the pre-finalization model
🟡 Medium · Bound incomplete JSON buffering to one SSE event
Check

Comment on lines +387 to +389
if deliveryErr, tracked := usage.WaitStreamDelivery(ctx); tracked && deliveryErr == nil {
return
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Close stream output before waiting for delivery acknowledgment

When a consumer uses WithStreamDelivery and acknowledges delivery after draining Chunks, cancellation while the scanner awaits another upstream chunk reaches this wait before close(out). The producer waits for acknowledgment while the consumer waits for EOF, deadlocking the canceled stream and retaining its response body. The stream-delivery contract explicitly requires producers to close their output before waiting.

}
requested := thinking.ParseSuffix(helps.PayloadRequestedModel(opts, req.Model)).ModelName
switch signature.SignatureProviderFromModelName(requested) {
case signature.SignatureProviderMeta, signature.SignatureProviderGrok, signature.SignatureProviderGPT:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Aliased non-GPT reasoning signatures are discarded

When an opaque resolved model is an alias for a requested Claude, Gemini, Kimi, or SWE model, this switch does not fall back to the requested model even though the sanitizer explicitly supports those providers. On /responses/compact, a valid provider signature is consequently classified as foreign and removed, potentially along with its item ID, so the upstream continuation loses its required reasoning state or is rejected.

Comment on lines +299 to +304
if errorResult := gjson.GetBytes(payload, "error"); errorResult.Exists() {
statusCode := int(errorResult.Get("code").Int())
if statusCode < http.StatusBadRequest || statusCode > 599 {
statusCode = http.StatusBadGateway
}
streamErr = newAntigravityStatusErr(statusCode, payload)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Ignore null error fields in successful stream frames

A configured Antigravity-compatible relay can include an optional "error":null alongside valid response candidates. GJSON reports that field as existing, so this condition converts the successful frame into a 502 error and terminates the stream before delivering its answer. Check for a non-null error value rather than field presence alone. Also reported for this defect: - Exclude JSON null from the stream error check (internal/runtime/executor/antigravity_executor_stream.go:299): For a successful HTTP-200 frame containing both "error":null and valid response.candidates, GJSON's Exists() returns true for the null field. This branch therefore discards the successful answer and emits a 502 before translation. A local executor reproduction confirms the failure; without this new check, the same frame delivers its answer. Require a non-null error node before taking the error path.

Also affects:

if callKey == "" {
return
}
antigravityInteractionsSessions.Put(s.key+":"+callKey, cache.InteractionsContinuation{ID: s.id, Environment: s.environment})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Do not cache continuations for unstored interactions

A native Interactions request with store:false can return an ID and requires_action, but that ID cannot be used for subsequent continuation. This unconditional cache write ignores the outgoing storage policy. On the next matching tool-result turn, PrepareAntigravityInteractions injects the unstored ID and removes the full history, causing upstream to reject a request that previously worked statelessly. Only cache continuation IDs for interactions actually stored upstream.

return cliproxyexecutor.Response{}, err
}

translated = helps.NewPayloadFinalizer(e.cfg, e.Identifier(), baseModel, to.String(), "", originalTranslatedForPayload, req, opts)(translated)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Token counting uses the pre-finalization model

This finalizer can apply a payload rule that changes the final model, but modelForCounting was already fixed to baseModel and the tokenizer is selected from that old value. For example, a rule rewriting a GPT-3.5 request to GPT-4o counts the finalized messages with the wrong encoding and returns an incorrect token total.

Comment on lines +283 to +288
if len(trimmedLine) > 0 {
pendingJSON = append(pendingJSON, '\n')
pendingJSON = append(pendingJSON, trimmedLine...)
}
if !gjson.ValidBytes(pendingJSON) {
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Bound incomplete JSON buffering to one SSE event

An incomplete event such as data: {\n\n leaves pendingJSON populated across the blank-line event boundary. Every subsequent valid content or terminal event is appended to that invalid buffer and skipped indefinitely. A reproduction with a valid answer following that event returns no answer and no StreamChunk.Err; the parser must reject or reset the incomplete event rather than consume the rest of the stream. Also reported for this defect: - Do not let malformed JSON consume subsequent SSE frames (internal/runtime/executor/antigravity_executor_stream.go:287-288): Once pendingJSON contains malformed data, this continue also skips SSE frame boundaries and appends every later event to the invalid prefix. For example, data: {"unused": followed by a blank line and a valid completion frame loses the entire answer and closes Chunks without an error. The base parser still delivered the later valid frame. Reject or isolate the malformed frame instead of silently swallowing subsequent output.

Also affects:

@ericlitman

Copy link
Copy Markdown
Contributor Author

Closing: the review scope changed. Eric (2026-10-27): "i don't want to fix anything that's an issue in upstream - our only goal here is to validate our changes". Upstream code is out of scope. Our fork's own changes on v8.0.44 get one review PR instead. Findings from this part are recorded in the HOUSE-79 adjudication record. None was a defect in our code.

@ericlitman ericlitman closed this Oct 27, 2026
@ericlitman
ericlitman deleted the review/house79/chunk-05 branch October 27, 2026 19:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant