Repository navigation
[Bug]: ZCode client config export omits reasoning configuration, preventing thought level controls in ZCode UI #4147
Description
Client or integration
Other
Area
Catalog / models
Summary
When OpenCodex exports the managed provider configuration to ~/.zcode/v2/config.json via ocx zcode or integration sync, buildZcodeClientConfig in src/clients/config-export/zcode.ts generates entries containing only name, modalities, and limit.context. It omits the reasoning block completely.
As a result, ZCode's UI never shows the "Thought Level" (思考强度) select dropdown for reasoning-capable models (e.g. gemini-3.8-flash, deepseek-v4-flash, claude-opus-4-6-thinking, grok-4.6, muse-spark-1.3-contributor, etc.), even though the wire protocols (reasoning_effort in Chat Completions and Responses) are fully supported and functional.
Reproduction
- Configure at least one reasoning-capable model in OpenCodex (e.g.,
google-antigravity/gemini-3.8-flashorCommandCode/deepseek/deepseek-v4-flash). - Run
ocx zcode(or enable ZCode integration from OpenCodex) to export configuration to~/.zcode/v2/config.json. - Inspect
~/.zcode/v2/config.jsonunderprovider.opencodex.models: observe that all exported model entries lack thereasoningblock (reasoning: { enabled: true, variants: [...], defaultVariant: "..." }). - Launch ZCode desktop app and open a chat session with one of these models: observe that the "Thought Level" control is completely missing from the session bar because ZCode requires
model.reasoning.levelsto render the picker.
Version
2.48.0
Operating system
macOS 15 (Darwin arm64)
Provider and model
google-antigravity/gemini-3.8-flash, CommandCode/deepseek/deepseek-v4-flash, opencode-go/muse-spark-1.3-contributor
Logs or error output
// Observed in src/clients/config-export/zcode.ts:
export interface ZcodeModelEntry {
name?: string;
limit?: { context: number; output?: number };
modalities: { input: string[]; output: string[] };
// Missing reasoning specification
}
Redacted configuration
{
"provider": {
"opencodex": {
"models": {
"google-antigravity/gemini-3.8-flash": {
"name": "gemini-3.8-flash (google)",
"limit": { "context": 1048576 },
"modalities": { "input": ["text", "image"], "output": ["text"] }
}
}
}
}
}Expected Behavior
src/clients/config-export/zcode.ts should export reasoning when model.reasoningEfforts is present, similar to omp.ts and dsh.ts:
export interface ZcodeModelEntry {
name?: string;
limit?: { context: number; output?: number };
modalities: { input: string[]; output: string[] };
reasoning?: {
enabled: boolean;
variants: string[];
defaultVariant?: string;
};
}
// In buildZcodeClientConfig:
if (model.reasoningEfforts && model.reasoningEfforts.length > 0) {
entry.reasoning = {
enabled: true,
variants: model.reasoningEfforts.filter(e => e !== "ultra"),
...(model.defaultReasoningEffort ? { defaultVariant: model.defaultReasoningEffort } : {}),
};
}Checks
- I searched existing issues and documentation.
- I removed secrets, tokens, account details, request credentials, and personal data.
Activity
github-actions commentedon Sep 9, 2026
Issue reopened
The report now contains the information required by the automated check. Thanks for updating it.
lidge-jun commentedon Sep 9, 2026
리뷰 · 우선순위 48 / 80
이 이슈는 ZCode 데스크톱 클라이언트로 OpenCodex가 내보내는
~/.zcode/v2/config.json안의 모델 항목에 생각 강도(Thought Level) UI를 켜는reasoning블록이 빠져 있다는 버그 보고입니다. 재현 경로는 명확합니다.ocx zcode(또는 통합 sync)가src/clients/config-export/zcode.ts의buildZcodeClientConfig를 타고, 지금 HEAD(6d99a1883)에서도 각 모델 엔트리는name/modalities/ (있을 때만)limit.context만 넣고 끝납니다.ZcodeModelEntry타입 자체에reasoning필드가 없고, 루프 안에서도model.reasoningEfforts를 전혀 읽지 않습니다. 그래서 카탈로그에 노력 사다리가 있는google-antigravity/gemini-3.8-flash,CommandCode/.../deepseek-v4-flash,opencode-go/muse-spark-1.3-contributor같은 행도 ZCode 쪽에서는 평문 모델처럼 보이며, 세션 바의 Thought Level 셀렉트가 안 뜹니다. 프록시 와이어(reasoning_effortChat/Responses)는 이미 동작하는데 클라이언트 export 메타만 빠진 상태라, 사용자는 “모델은 되는데 UI가 없다”로 체감합니다.같은 export 패밀리를 보면 이 구멍은 ZCode만의 공백입니다.
omp.ts는reasoningEfforts가 있으면reasoning: true와thinking.efforts를 넣고,dsh.ts는reasoningEfforts맵을 넣으며, OpenCode V2 블록도 variants 형태로 노력 목록을 냅니다. 테스트(tests/config/client-config-export.test.ts)도 omp/dsh/OpenCode 쪽 reasoning 방출을 이미 잠가 두었고, zcode 경로는 “limit/modalities만” 수준으로만 검증되는 편입니다. 지금devtip은 Codex 할당량 등록 지연(#3848)과 OAuthplan필드(#4146) 쪽이지만, 클라이언트 export 계약 자체는 이미 안정된 축이라 스키마만 맞추면 작은 패치로 닫을 수 있는 catalog/clients 버그입니다. 보고자가 제안한 형태(enabled+variants+defaultVariant)는 omp/dsh와 결이 같고,defaultReasoningEffort가 ladder에 있을 때만 default를 넣는 기존 export 규칙과도 맞습니다. 다만 본문 재현 문단은 ZCode가model.reasoning.levels를 본다고도 적혀 있어서, 실제 ZCode 3.x가 읽는 키 이름(variantsvslevels등)을 한 번 더 확인한 뒤 타입/방출을 맞춰야 합니다.ultra필터·none제외 같은 vocabulary 정리는 omp/OpenCode 쪽 sanitize와 같은 정책을 재사용하는 편이 안전합니다.src/clients/config-export/zcode.ts
ZcodeModelEntry- reasoning 관련 필드가 타입에 없어서, 설령 런타임에 객체를 붙여도 계약/문서/테스트가 따라가지 못한다src/clients/config-export/zcode.ts
buildZcodeClientConfig-normalizeExportModels루프가reasoningEfforts/defaultReasoningEffort를 무시하고 name·modalities·limit만 써서 Thought Level 메타가 항상 비다이슈 본문 Expected vs Reproduction - Expected는
reasoning.variants/defaultVariant인데 Reproduction은model.reasoning.levels라고 해서, ZCode 실측 스키마가 어느 쪽인지 확인 없이 패치하면 UI가 계속 안 뜰 수 있다tests/config/client-config-export.test.ts (및 tests/providers/zcode-client.test.ts) - zcode export에 reasoning ladder fixture가 없어 회귀를 잠그지 못한다
메인테이너의 판단이 필요한 지점
variants/defaultVariant로 확정할지,levels등 다른 키로 맞출지 (3.7.7/3.8.1에서 이미 검증한 계약 주석과 충돌 여부)ultra/none을 다른 클라이언트와 동일하게 숨길지, ZCode UI 어휘에 맞춰 그대로 둘지너의 추천
ZCode 실측 config(또는 공개 스키마)로
reasoning키 이름을 한 줄 확정한 뒤,zcode.ts에 omp/dsh와 같은 “ladder 있으면 방출”을 넣고 client-config-export 테스트에 reasoning 있는/없는 fixture를 추가하는 작은 PR로 머지하세요. types/config split과 무관하니 close-don't-rebase 대상이 아닙니다.이 댓글은 grok-bot이 작성했습니다
richardfeiliu-a11y commentedon Sep 9, 2026
Confirmed: ZCode's on-disk schema is
reasoning.variants/reasoning.defaultVariant, notlevels.I checked a live
~/.zcode/v2/config.json(ZCode 3.x on macOS) and the shipped parser inZCode.app(app.asar). Builtin providers already persist this shape, for examplebuiltin:bigmodel/ GLM-5.3:{ "reasoning": { "enabled": true, "variants": ["low", "max", "high"], "defaultVariant": "max" } }There is no
levelskey on disk.model.reasoning.levelsis the in-memory object after parse. The named helperopenCodeReasoningToModelReasoningdoes:variants→levels: Object.fromEntries(variants.map(v => [v, {}]))defaultVariant→defaultLevelThe inverse
modelReasoningToOpenCodeReasoningwritesObject.keys(levels)back tovariants. The UI gate mentioned in the reproduction is that runtimelevelsobject; the exporter should still emit the OpenCode-compatible on-disk keys (enabled+variants+defaultVariant). That matches the existing 3.7.7 / 3.8.1 contract comment onZcodeModelEntry. A local~/.zcode/v2/config.jsonpatched with this block made the Thought Level control appear.On vocabulary, I would follow OpenCode V2 rather than omp:
none(Codex omit-sentinel; OpenCode V2 already filters it). ZCode builtins useoff/enabledfor that idea, notnone.ultrawhen the catalog ladder includes it. ZCode rendersvariantsas picker labels and forwards the selected id asreasoning_effort; hidingultrawould drop a real catalog tier. omp's no-ultravocabulary looks omp-specific.defaultVariantonly whendefaultReasoningEffortis in the emitted variants list.I can open a small standalone PR against
devforsrc/clients/config-export/zcode.tsplus export tests (reasoning present / absent). Prefer not to bundle it with other client-export polish.richardfeiliu-a11y commentedon Sep 9, 2026
Opened a standalone PR against
devwith the on-disk schema confirmed above (enabled+variants+defaultVariant): #4153Vocabulary matches OpenCode V2: drop
none, keep catalogultra, and setdefaultVariantonly when it remains in the emitted ladder.lidge-jun commentedon Sep 9, 2026
Fixed on
devby #4153, merged as2ce5f381f. Thanks @richardfeiliu-a11y — the PR landed as your own commit, unmodified.The ZCode export now emits a Thought Level block for every model whose catalog entry carries a reasoning ladder, so the picker appears instead of the model looking like a plain one.
What made this reviewable in one pass was your schema check. The issue body said ZCode reads
model.reasoning.levelswhile the Expected block saidreasoning.variants, and rather than picking one you read a live~/.zcode/v2/config.jsonand the shipped parser inZCode.appand reported that the on-disk keys areenabled/variants/defaultVariant, withlevelsbeing what the parser builds in memory. This repository independently agrees:src/integrations/ownership-policy.tsalready treatsmodels.*.reasoningas a 3.8.1 key withenabled/variants, andtests/clients/integrations-writer.test.tscarries a fixture in exactly that shape. Without that, a patch written to the issue text would have shipped a key ZCode never reads and the picker still would not have appeared.The vocabulary decisions in the PR are the right ones for this client.
noneis dropped because it is Codex's omit-sentinel rather than a picker option.ultrais kept, against the Expected snippet in this issue, because ZCode forwards the selected variant asreasoning_effortandultrais a real tier — omp's no-ultravocabulary is specific to omp. AnddefaultVariantis written only when it survives the filter.One operational note for anyone reading this later: a fork pull request does not start repository CI by itself. Cross-platform CI and React Doctor sat at
action_requireduntil approved, which is why the check list looked thin for a while.Evidence: exact-head CI at
abf35fa947b05ae82d7fd22c0a4971a129b9629fconcluded success —gh run view 34411681339 --exit-statusreturns 0 for Cross-platform CI, with React Doctor, Enforce PR target branch and PR hygiene also 0, and nothing cancelled at that SHA.git merge-base --is-ancestor abf35fa94 origin/devpasses. Independent review recorded atdevlog/_plan/260910_post249_round2/_research/_audit_pr4153.md, verdict PASS with no blocker.Closing by hand because pull requests here target
dev, so GitHub does not auto-close a linked issue.docs(devlog): record lidge-jun#4147, lidge-jun#3859, and the lidge-ju…
docs(devlog): close the round-2 record at the screenshot gate
docs(devlog): record lidge-jun#4147, lidge-jun#3859, and the lidge-ju…
docs(devlog): close the round-2 record at the screenshot gate
fix(zcode): carry reasoning ladders and image input into the provider…
fix(zcode): carry reasoning ladders and image input into the provider…