Skip to content

feat(settings): convert thought depth for Hy-series models - #129

Merged
orangeboyChen merged 3 commits into
mainfrom
feat/hy-thought-depth
Sep 15, 2026
Merged

orangeboyChen merged 3 commits into
mainfrom
feat/hy-thought-depth

Conversation

@orangeboyChen

Copy link
Copy Markdown
Owner

Hy-series models take their thinking depth as reasoning_effort, whose only accepted values are no_think, low and high. Neither downstream client speaks that vocabulary, so both were being forwarded in a shape the upstream does not accept.

What changes

Downstream Sends Now becomes
Claude Code (/v1/messages) thinking: {type, budget_tokens} reasoning_effort: no_think / low / high
Codex (/v1/responses) reasoning.effort: minimal…max reasoning.effort: no_think / low / high

OpenAI effort levels collapse onto the nearest Hy level instead of being dropped, and Anthropic budget_tokens is bucketed against the output sizes the levels correspond to — no_think caps at 8K, low sits around 16K, high reaches 64K. An enabled thinking block with no budget resolves to high, since the caller did ask for thinking.

Scope

The mapping table is fixed by the upstream contract, so the console gets an off/on switch only, defaulting to off — with it off every request is byte-identical to before. Model matching is case-insensitive and prefix-based, so hy3 and hy3-ioa match while hunyuan-* (a separate product line with its own thinking parameter) is deliberately excluded. Conversion is skipped for non-Hy models so upstreams that already understand these fields are untouched.

Exposed as CODEBUDDY_HY_THOUGHT_DEPTH, also settable as an environment variable. It accepts on/off as well as 1/0, true/false. Unrecognized values fall back to off, so a mistyped setting cannot silently rewrite thinking depth for every Hy request.

Verification

All five repo gates pass: lint, format:check, typecheck, build, and test:coverage.

  • 360 tests pass across 24 files; 34 of them are new.
  • Coverage 94.2% statements / 87.83% branches, above the 90/90/70/90 floor.
  • lib/server/shared/hy-thought-depth.ts is at 100% line and 100% branch coverage (40/40 lines, 51/51 branches).
  • test:patch-branches reports 100% changed-branch coverage.

Tests cover both downstreams end-to-end (that Claude Code's thinking reaches upstream as reasoning_effort: high, and Codex's medium becomes low), plus the off-switch and non-Hy model cases where nothing must change.

🤖 Generated with Claude Code

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6653b6f2c8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/server/proxy/codebuddy.ts Outdated
orangeboyChen and others added 3 commits September 16, 2026 01:43
Hy models take their thinking depth as `reasoning_effort`, whose only accepted
values are `no_think`, `low` and `high`. Neither downstream client speaks that
vocabulary: Claude Code sends Anthropic `thinking` (a `{type, budget_tokens}`
object), and Codex sends Responses `reasoning.effort` using the finer-grained
`minimal`/`low`/`medium`/`high`/`xhigh`/`max` scale. Forwarding either verbatim
means the upstream rejects the request or silently ignores the caller's intent.

This translates both onto the Hy vocabulary. OpenAI effort levels collapse onto
the nearest Hy level rather than being dropped, and Anthropic `budget_tokens` is
bucketed against the output sizes the levels correspond to (`no_think` caps at
8K, `low` sits around 16K, `high` reaches 64K). An enabled thinking block with
no budget resolves to `high`, since the caller did ask for thinking.

The mapping itself is fixed by the upstream contract, so the console only gets
an off/on switch; it defaults to off, leaving every request byte-identical to
before. Model matching is case-insensitive and prefix-based so `hy3` and
`hy3-ioa` both match, while `hunyuan-*` is a separate product line with its own
thinking parameter and is deliberately excluded. Conversion is skipped for
non-Hy models so upstreams that already understand these fields are untouched.

Gated behind CODEBUDDY_HY_THOUGHT_DEPTH (also settable as an environment
variable) and labeled in all three locales. Unrecognized values fall back to
off, so a mistyped setting cannot silently rewrite thinking depth for every Hy
request.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every model id starting with `hy` is a Hy-series model, so matching was
narrower than it should have been: it enumerated three prefixes, which
silently missed any Hy release that did not match one of them.

The upstream decides which model ids exist, so the test is now a single
case-insensitive `hy` prefix check. A future `hy4` is covered without a code
change. `hunyuan-*` remains excluded, but as a consequence of being a different
prefix rather than of a deliberate carve-out.

Also spells out that the Anthropic budget cut points are ours: the upstream
documents the output size behind each level, not the reverse mapping, so the
comment now says which direction is specified and which is inferred.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Translating Claude Code's `thinking` into `reasoning_effort` left the original
block in place, so a Hy request carried the same intent twice in two different
vocabularies. An upstream that rejects the unsupported shape — the exact case
this option exists to fix — would still have failed despite also receiving the
converted field, so the translation bought nothing.

`resolveHyChatReasoningEffort` becomes `resolveHyChatThinking`, returning the
converted effort and the `thinking` value to forward as a pair. `thinking` is
dropped only when it actually produced a value; an unrecognized shape is
forwarded untouched, so a request we cannot interpret is never silently
rewritten.

Also rebased onto main, which absorbed the local web search work. That branch
introduced real boolean settings with a Switch, so the off/on string toggle is
replaced by `CODEBUDDY_HY_THOUGHT_DEPTH_ENABLED` and the bespoke normalizer is
dropped in favour of the generic boolean handling. Environment and docs updated
to match.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Sep 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.14%. Comparing base (3fd575f) to head (5d86d9a).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #129      +/-   ##
==========================================
+ Coverage   95.09%   95.14%   +0.05%     
==========================================
  Files          26       27       +1     
  Lines        4950     5009      +59     
  Branches     1432     1457      +25     
==========================================
+ Hits         4707     4766      +59     
  Misses        243      243              
Flag Coverage Δ
unittests 95.14% <100.00%> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@orangeboyChen
orangeboyChen merged commit d199c7f into main Sep 15, 2026
7 checks passed
@orangeboyChen
orangeboyChen deleted the feat/hy-thought-depth branch September 15, 2026 17:57
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