Skip to content

fix(auth): recognize Interactions finish events in empty-completion detector - #210

Open
warelik wants to merge 2 commits into
kaitranntt:mainfrom
warelik:ao/airouters-15-fix-empty-completion-interactions
Open

fix(auth): recognize Interactions finish events in empty-completion detector#210
warelik wants to merge 2 commits into
kaitranntt:mainfrom
warelik:ao/airouters-15-fix-empty-completion-interactions

Conversation

@warelik

@warelik warelik commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Summary

sdk/cliproxy/auth/empty_completion.go had no Interactions branch, so an Interactions turn ending in a bare finish event with zero output was treated as unknown data and committed as a valid response. The detector now recognizes the Interactions protocol and the finish event, reading usage from metadata.total_usage (falling back to metadata.usage) exactly as the translator does.

Ported from the upstream review on router-for-me/CLIProxyAPI#4881, commit baf43ba5.

Changes

  • Added interactionsEventTypes, interactionsChunk, interactionsMeta, interactionsUsage, interactionsStep, interactionsContent, interactionsDelta, and helper methods.
  • Added evalInteractions, evalInteractionsUsage, and evalInteractionsSteps.
  • Wired evalInteractions into evalJSON.
  • Added interactionsTerminal to emptyCompletionAccum and isTerminalEmpty.

Test plan

  • go build ./...
  • go vet ./sdk/cliproxy/auth/...
  • go test ./sdk/cliproxy/auth/...
  • New TestEmptyCompletionPredicateInteractions cases:
    • bare finish with metadata.total_usage.total_output_tokens: 0 is empty
    • bare finish with metadata.total_usage.total_output_tokens: 7 is not empty

Cross-references

…etector

The Interactions protocol ends a turn with a bare "finish" event whose
usage lives under metadata.total_usage. The empty-completion detector had
no Interactions branch, so every Interactions stream fell through to
unknown data and was committed as a valid response.

Port the event set, chunk shapes, evalInteractions, and the finish
handling from the upstream review on router-for-me/CLIProxyAPI#4881
(commit baf43ba5). A bare finish with zero output tokens is now treated
as an empty completion; one with positive tokens is not.

Relates to kaitranntt#202.

@warelik warelik left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ready — approving.

Verified the port against upstream router-for-me/CLIProxyAPI@baf43ba5 (PR #4881):

  • Port fidelity — the added types block (interactionsEventTypes, interactionsChunk/Meta/Usage/Step/Content/Delta, helpers) and evalInteractions/evalInteractionsUsage/evalInteractionsSteps are byte-identical to upstream (diffed the extracted sections against the upstream blob). The base had no Interactions branch at all, so this is the full port plus the finish delta.
  • WiringevalJSON tries evalInteractions last, same order as upstream; all referenced helpers (hasJSONKey, hasMeaningfulJSONArguments, nonEmptyJSONPayload, tokenCount) exist in the fork; isTerminalEmpty now includes interactionsTerminal; no duplicate declarations; gofmt clean; CI build green.
  • No recognition shadowing — earlier evaluators cannot swallow Interactions events: evalOpenAI needs choices, evalClaude needs its own type set, evalOpenAIResponse has no overlap with the interactions event types (including bare finish), evalGemini needs candidates/usageMetadata/promptFeedback.
  • Translator parity claim checks outinteractions_gemini_response.go handles finish alongside interaction.completed, and translatorcommon.InteractionsUsage resolves metadata.total_usage before metadata.usage, which the detector mirrors.
  • New tests traced by hand — both cases walk isEmptyCompletionPayloadevalSSEevalInteractions to the expected verdicts (zero-output finish → empty; 7 output tokens → not empty).

One non-blocking test-coverage suggestion inline. Fixes the #202 scenario as described.

Comment thread sdk/cliproxy/auth/empty_completion_test.go
Adds the broader predicate, streaming detector, and execute rotation
scaffolding tests that cover the upstream Interactions evaluator branch:
- JSON-shape predicate cases (empty steps, function_call, media, file_uri)
- interaction.completed SSE scaffolds
- TestStreamBootstrapDetectorInteractionsScaffoldAllowsFailover
- TestExecuteInteractionsMeaningfulOutputNotRotated

Also adds emptyPayload/contentPayload fields to emptyCompletionTestExecutor
so non-OpenAI first-auth empty/content responses can be overridden.

Closes kaitranntt#202
@warelik
warelik force-pushed the ao/airouters-15-fix-empty-completion-interactions branch from 4be4c2c to 1302eae Compare August 22, 2026 05:07
warelik added a commit to warelik/CLIProxyAPIPlus that referenced this pull request Aug 22, 2026
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.

Empty-completion detector does not recognize the Interactions protocol

1 participant