Skip to content

fix(chat): finish with length when a Responses upstream reports incomplete reason "length" - #7392

Closed
hedging8563 wants to merge 1 commit into
lidge-jun:devfrom
hedging8563:chat-incomplete-length
Closed

hedging8563 wants to merge 1 commit into
lidge-jun:devfrom
hedging8563:chat-incomplete-length

Conversation

@hedging8563

@hedging8563 hedging8563 commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Volcengine Ark Coding Plan /responses ends a capped turn with status: "incomplete", incomplete_details.reason: "length" (OpenAI uses max_output_tokens). chatCompletionsIncompleteOutcome and responsesJsonToChatCompletion only accept max_output_tokens and content_filter, so Chat Completions returns 502 upstream stream ended early (length) instead of a 200 with finish_reason: "length". Clients treat the 502 as a dead route and fail over although the provider answered.

  • Read the reason through the existing truncationReasonFor() table (src/responses/truncated-stop-reason.ts, already maps length, max_tokens, ...) in chatCompletionsIncompleteOutcome.
  • responsesJsonToChatCompletion now calls that same function instead of its own two-value check.
  • Proxy-synthesized reasons (adapter_eof, upstream_stall_timeout, missing_terminal_event) are not in the table and still fail.

Repro: POST /v1/chat/completions, model volcengine-coding-plan/glm-5.3-flash, max_tokens: 16, non-streaming -> 502 before, 200 finish_reason: "length" after.

Verification (on dev bddd61f, Bun 1.4.3)

  • New tests/chat/incomplete-length-reason.test.ts: 4 tests. Without the fix 3 fail with upstream stream ended early (length); with it all 4 pass.
  • bun test tests/chat tests/server: the same 21 tests fail on unpatched dev and on the patched tree (checked by diffing the fail lists); the patch adds no failures. Those pre-existing failures are in provider-management/account tests, unrelated.
  • tsc --noEmit: clean.
  • Not run: full bun run test.

We run OpenCodex as a shared gateway and hit this through the Volcengine Coding Plan.

Review readiness checklist

This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:

  • Required local validation passed; commands, results, and any full-suite exception are documented.

  • I pushed my PR to a recent dev commit (at most 10 behind; a maintainer may still ask for the exact tip before merge).

  • I resolved all correct Codex and CodeRabbit findings.

  • My PR is ready for review.

Summary by CodeRabbit

  • Bug Fixes
    • Responses marked incomplete due to output limits now consistently report a length finish reason in both streaming and non-streaming chat completions. Content-filter outcomes and other incomplete failures remain unchanged.

@github-actions

Copy link
Copy Markdown
Contributor

✅ Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Oct 19, 2026
@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

⏳ DRAFT

  • review readiness checklist open (0/4 boxes ticked).

What to do

  • Tick all four boxes in the PR description once you're done (currently 0/4).

Review readiness checklist

  • ⬜ Required local validation passed; commands, results, and any full-suite exception are documented.
  • ⬜ I pushed my PR to a recent dev commit (at most 10 behind; a maintainer may still ask for the exact tip before merge).
  • ⬜ I resolved all correct Codex and CodeRabbit findings.
  • ⬜ My PR is ready for review.

0/4 boxes ticked.

This PR stays in draft until every box above is ticked.

@github-actions
github-actions Bot marked this pull request as draft October 19, 2026 21:32
@coderabbitai

coderabbitai Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: lidge-jun/opencodex/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 6613caa4-dd6f-4866-b412-5b82a8cea125
📥 Commits

Reviewing files that changed from the base of the PR and between bddd61f and 45d08af.

📒 Files selected for processing: 2
  • src/chat/outbound.ts
  • tests/chat/incomplete-length-reason.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

📝 Walkthrough

Incomplete Responses API reasons now pass through shared truncation-reason normalization when selecting Chat Completions finish outcomes. Tests cover length, max_output_tokens, content_filter, unsupported reasons, and JSON and buffered SSE projections.

Changes: Incomplete reason mapping

Layer / File(s) Summary
Normalize incomplete reasons and verify projections
src/chat/outbound.ts, tests/chat/incomplete-length-reason.test.ts
The shared outcome normalizes incomplete reasons before selecting length or content_filter; unsupported reasons remain failures. The non-streaming path delegates to this outcome. Tests cover outcome selection and JSON and buffered SSE projections.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~8 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to 45d08

The change is mergeable after normal checks; no actionable risk is identified in the supplied review context.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly identifies the main change: mapping a Responses upstream incomplete reason of "length" to a Chat Completions finish reason of "length". It is specific, concise, and directly matches …
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

The title clearly identifies the main change: mapping a Responses upstream incomplete reason of "length" to a Chat Completions finish reason of "length". It is specific, concise, and directly matches the implementation and tests.

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Ingwannu Ingwannu left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

The shared truncation vocabulary now recognizes the reported length alias in both SSE and JSON projections while proxy EOF/stall reasons remain failures. Two repository-contract items are missing at this exact head:

  • Register tests/chat/incomplete-length-reason.test.ts in BOTH the current layout explicit/domain map and its tests/fixtures/test-layout-expected*.json shard. The complete two-file diff contains neither registration. Regex placement does not replace the explicit expected map.
  • Update the mapped Chat/Responses owning contract for this change to accepted incomplete-reason vocabulary and its failure boundary. The complete diff has no structure/documentation update.

Retain the negative EOF/stall/missing-terminal cases, and add an explicit streamed wire assertion if the fixture currently only collects that stream into a buffered completion. Please refresh current-head validation/readiness after the push; do not weaken the test/layout gates.

@lidge-jun

Copy link
Copy Markdown
Owner

Carried onto current dev in #7539 with @hedging8563 credited via Co-authored-by. That PR addresses the review: the regression moves to tests/responses/chat-incomplete-length-reason.test.ts and is registered in both scripts/test-layout/layout.json and tests/fixtures/test-layout-expected.json. The Chat incomplete vocabulary and its failure boundary are documented in structure/transports/responses-wire-shapes.md, and explicit streamed-wire and handler cases were added. This PR is left open for the maintainer to close.

@lidge-jun

Copy link
Copy Markdown
Owner

Thank you for this work. It has been carried onto current dev in #7539, with your authorship kept as a Co-authored-by trailer, and review continues there. Closing this PR in favour of #7539.

@lidge-jun lidge-jun closed this Oct 22, 2026
lidge-jun added a commit that referenced this pull request Oct 22, 2026
…plete reason "length" (#7539)

Carries #7392 onto current dev.

Co-authored-by: hedging8563 <45883076+hedging8563@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants