Skip to content

feat(reasoning): consolidate replay, opt-in tag parsing, and summary policy - #5566

Closed
luvs01 wants to merge 5 commits into
devfrom
stack/reasoning-roundtrip-boundaries
Closed

luvs01 wants to merge 5 commits into
devfrom
stack/reasoning-roundtrip-boundaries

Conversation

@luvs01

@luvs01 luvs01 commented Sep 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

Consolidate the reasoning roundtrip changes from #5449, #5205 and #5491 into one attributed draft, preserving their distinct behavior changes:

  • Retain the existing empty-reasoning placeholder for signed thinking-only assistant turns even when there is no tool call. Explicit model opt-outs and serving-identity replay boundaries remain intact.
  • Add inlineThinkTagModels as an explicit model opt-in for Chat output that encodes reasoning in inline tags. Operator lists, including [], override registry defaults for this new field. Unlisted models pass through unchanged.
  • Preserve answer whitespace and parse repeated blocks iteratively. Once an initial reasoning block activates the format, later tags remain delimiters even inside code fences; prose or a code fence before initial activation leaves the response unchanged. This is a declared opt-in format, not a Markdown intent detector. Kiro retains its existing single-block behavior.
  • Change the omitted-summary display default only for validated reasoning effort. Explicit summary: "none" stays hidden; invalid or absent effort does not accidentally opt in. Combo-injected defaults add summary auto only when the caller did not specify a summary.

All three other-author originals remain open and unchanged. Current dev's extracted model-field classifier is preserved, and the source's size-cap increase is excluded. No provider preset is newly enabled.

Verification

  • Head 8028c913ab00ed5b402cb0ab9efee65fbe9e7abb, based on dev a6b54297b03fc218105273887ce147c901848d89. Four source commits preserve author and source SHA. Three carries have equal stable patch IDs; the initial inline-parser carry adapts the current classifier and excludes the cap change. Final integration commit retains all contributor trailers.
  • First 13-file run: 389 pass / 7 fail. A subsequent affected five-file run was 202 pass / 3 fail and exposed the actual explicit-empty-list opt-out defect. The corrected final four-file scope passed 110 / 110. Earlier passing parser/Kiro/replay/bridge cases were unchanged; overlapping counts are not added or described as a final complete-suite pass.
  • Regressions cover valid/invalid effort, explicit summary none/auto, empty-list override, transport mismatch, signed empty replay, split tags, whitespace, Unicode, EOF/disposal and a 12,000-block single-chunk versus split-chunk comparison. Hidden/visible bridge output is checked through continuation serialization.
  • Final typecheck, structure, privacy, unchanged-cap ratchet and whitespace checks passed. Documentation built successfully: 497 pages. Independent static review found no new defect in the inspected boundaries; it did not execute tests or live provider calls.
  • Full prepush, changed-import-graph coverage, hosted CI, live-provider acceptance and the required independent security review of the provider-editor policy change remain outstanding. This PR stays draft and does not attest to merge or release readiness.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

Co-authored-by: Joonsuh Park trckstr4422@gmail.com
Co-authored-by: Daniel Sjöstrand 16033062+Danielsjostrand1979@users.noreply.github.com
Co-authored-by: alexph-dev alexph-dev@users.noreply.github.com
Co-authored-by: Yum-wu 1172989563@qq.com

parkjs101 and others added 5 commits September 23, 2026 00:20
Co-authored-by: Daniel Sjöstrand <16033062+Danielsjostrand1979@users.noreply.github.com>
(cherry picked from commit 65ed520)
…kTagModels

A gateway that serves a thinking model without a server-side reasoning parser
returns the chain of thought inside message.content as <think> blocks and sends
neither reasoning_content nor reasoning_details, so Codex renders the whole chain
of thought as the answer. reasoning_split, reasoning.effort and
chat_template_kwargs are ignored by such a gateway, so the recovery can only
happen client side.

Adds the opt-in provider option inlineThinkTagModels. Listed models have their
think blocks split back into reasoning on both the streamed and non-streamed
openai-chat paths. Off by default: 66 registry providers share this adapter and a
gateway that does parse reasoning must keep its visible content byte-exact. Once
enabled the splitter still engages only for a response that opens with a thinking
tag, so an answer that merely mentions one is never rewritten; after it engages it
keeps splitting later blocks, because M-series models interleave thinking with
answer segments. An unterminated block flushes as reasoning rather than being lost.

The parser is the existing Kiro thinking parser, generalized and renamed to
src/adapters/inline-think-tags.ts with an interleaved option. Kiro keeps its
single-block behavior and its byte accounting unchanged.

The file-size baseline is raised only for src/adapters/openai-chat.ts. The two
other offenders the ratchet reports are already present on dev and are untouched.

(cherry picked from commit f95a0ad)
Review feedback: trimming the remainder after every closing tag also ate indentation that belongs to the answer, which matters when a block sits inside markdown or code. Only the transition out of the leading block trims now; once answer text has been emitted the remainder is preserved byte-exact. Kiro is single-block, so its behavior is unchanged.

(cherry picked from commit 1498eda)
…ries

Keep inline parser answer whitespace and drain interleaved blocks without recursion.
Preserve Kiro single-block behavior and document opt-in tag semantics, including
code examples after activation. Honor explicit operator parser lists, including [].
Use validated effort for omitted-summary visibility and register the source tests.

Adapt the model-rename contribution to the existing extracted field classifier.
The carried source message describes a historical cap increase; this integration
does not carry that increase and keeps the current dev file-size baseline unchanged.
Keep the original source commits and their review follow-up with -x provenance.

Co-authored-by: Joonsuh Park <trckstr4422@gmail.com>
Co-authored-by: Daniel Sjöstrand <16033062+Danielsjostrand1979@users.noreply.github.com>
Co-authored-by: alexph-dev <alexph-dev@users.noreply.github.com>
Co-authored-by: Yum-wu <1172989563@qq.com>
@coderabbitai

coderabbitai Bot commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

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.

@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the enhancement New feature or request label Sep 22, 2026
@lidge-jun

Copy link
Copy Markdown
Owner

리뷰 · 우선순위 61 / 80

이 PR은 생각(reasoning)이 한 바퀴 돌 때 깨지던 세 가지 고침을 한 draft로 모은 작업입니다. 첫째, 서명한 thinking-only 어시스턴트 턴에 도구 호출이 없어도 빈 reasoning_content 자리표시를 남겨, DeepSeek처럼 재전송을 거부하는 업스트림이 다음 요청을 400으로 끊지 않게 합니다. 둘째, 게이트웨이가 생각을 <think> 같은 태그로 답변 본문에 섞어 보낼 때, 운영자가 inlineThinkTagModels에 모델만 넣으면 openai-chat이 그 블록을 다시 reasoning으로 가르게 합니다. 기본은 꺼져 있고, []로 레지스트리 기본값을 막을 수 있으며, 목록에 없는 모델은 글자 하나 안 바꿉니다. 파서는 Kiro용 코드를 inline-think-tags.ts로 빼 공유하고, Kiro는 예전처럼 첫 블록만, Chat opt-in은 여러 블록을 이어서 처리합니다. 셋째, Responses에서 summary를 안 적었을 때, 검증된 effort가 있을 때만 원시 생각을 보이게 바꾸고, combo가 넣는 기본값도 호출자가 summary를 안 고른 경우에만 auto를 붙입니다. base는 dev이고, 원작자 커밋을 cherry-pick으로 유지했으며, 프리셋을 새로 켠 제공자는 없습니다. 관련 테스트·구조 문서·설정 문서도 같이 들어 있습니다.

라인 - src/server/auth-cors.tsinlineThinkTagModels: "editor": 제공자 편집기 정책 표면이 늘어났는데, PR 체크리스트와 본문이 독립 보안 리뷰를 아직 미완료로 적어 두었습니다. draft로 두는 선택은 맞지만, ready 전에 이 한 줄 정책 변경을 반드시 별도 확인해야 합니다.
라인 - src/combos/request.tssummary: "auto" 주입: 예전에는 effort만 넣던 combo 자식 요청이 이제 summary까지 갖게 됩니다. 의도된 표시 기본값 정렬이지만, 생략(=숨김)에 의존하던 클라이언트·브리지 경로가 있으면 체감이 바뀝니다.
라인 - InlineThinkTagParser 활성화 후 코드 펜스 안 태그: 첫 <think>로 포맷이 켜지면 이후 태그는 마크다운을 보지 않고 구분자로만 씁니다. 문서·테스트에 명시된 opt-in 계약이지만, 게이트웨이가 예제 XML을 답에 섞으면 답이 잘릴 수 있으니 운영자 안내가 필요합니다.
라인 - 원본 #5449, #5205, #5491이 아직 open: 이 draft가 정본으로 남을 계획이면, 병합(또는 대체 확정) 때 원본을 close해 중복·무효 PR이 남지 않게 정리하는 편이 낫습니다.

메인테이너의 판단이 필요한 지점

이 한 PR에 replay placeholder, inline 태그 복구, summary/effort 표시 정책을 묶을지, 아니면 합친 검증만 유지하고 원본 세 갈래를 따로 머지할지. 또 combo의 summary: "auto" 기본 주입을 “표시를 살리는 의도”로 받아들일지, 아니면 생략을 계속 숨김으로 둘지. inlineThinkTagModels를 editor 정책에 올리는 보안 리뷰를 ready 전 필수 게이트로 둘지도 결정이 필요합니다.

너의 추천

draft 유지한 채, 영향 테스트 범위와 호스트 CI·전체 prepush·독립 보안 리뷰(특히 editor 정책)가 통과한 뒤에만 ready로 올리세요. 병합 시 #5449/#5205/#5491은 superseded로 닫고, inlineThinkTagModels는 레지스트리 기본 on 없이 운영자 opt-in만 유지하세요. types/config 쪽 필드 추가는 기존 rename·policy 파이프에 잘 맞춰져 있으니, 같은 주제의 낡은 중복 PR만 정리하면 됩니다.

이 댓글은 grok-bot이 작성했습니다

@lidge-jun

Copy link
Copy Markdown
Owner

Carried into #5619 at 8028c91 with your authorship and every co-author trailer kept. Follow-ups resolve the provider-guide conflict by keeping both paragraphs, correct the whitespace contract, and make the inline think-tag parser linear in both block count and leading-whitespace deltas. Closing in favor of #5619. Thank you!

@lidge-jun lidge-jun closed this Sep 23, 2026
lidge-jun added a commit that referenced this pull request Sep 23, 2026
… fixes (#5619)

* fix(cursor): bound capability reads and buffered tool budgets (#5533)

Carries #5533 (and the closed #5233 it consolidates) onto current dev.

Co-authored-by: Epinephrine <luvs01@hanmail.net>

* fix(moonshot): bound normalized tool-schema expansion (#5547)

Carries #5547, which consolidates #5464 and the request-wide inline budget, onto current dev.

Co-authored-by: yeongjunyoo <47925973+yeongjunyoo@users.noreply.github.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Epinephrine <luvs01@hanmail.net>

* fix(moonshot): restore rejected inline budgets and charge nested growth once

A rejected sibling-reference expansion now restores the byte, node and expansion allowances it consumed, and outer growth no longer re-charges nested copies, so later independent expansions in the same request keep their allowance. Documents the provider-driven object type inference as a deliberate tradeoff and rewrites ADR-0355 in English.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* feat(reasoning): consolidate replay, opt-in tag parsing, and summary policy (#5566)

Carries #5566, which consolidates #5449, #5205 and #5491, onto current dev. The provider guide keeps the current bridge replay paragraph and adds the inline-tag and summary paragraphs.

Co-authored-by: Joonsuh Park <trckstr4422@gmail.com>
Co-authored-by: Daniel Sjöstrand <16033062+Danielsjostrand1979@users.noreply.github.com>
Co-authored-by: alexph-dev <alexph-dev@users.noreply.github.com>
Co-authored-by: Yum-wu <1172989563@qq.com>

* fix: bound Fernet slot runs, Kiro error-body read, and skill-path line slice (#5310)

Carries #5310 onto current dev. The follow-up commit makes the Fernet run cap fail closed and moves the Kiro regression out of the capped stream suite.

* docs(reasoning): reconcile inline-tag whitespace contract

Interleaved inline-tag parsing preserves answer whitespace; only Kiro single-block mode drops the whitespace after its leading block.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(responses): fail closed on Fernet run overflow and keep the Kiro suite under its cap

A slot with more than 64 structurally valid Fernet runs is now treated as unreadable or omitted as a whole, so no unexamined tail reaches the provider as text. The bounded Kiro fallback error-body regression moves byte for byte into a registered sibling file, and the Kiro, Responses and inbound contracts document the new bounds.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(reasoning): scan inline think tags with a moving cursor

The parser copied, rescanned and reserved the whole remaining response after every block, so one upstream chunk carrying many short blocks cost quadratic work. It now scans each chunk from an offset and charges the translator budget only for retained carry: undecided leading input or a trailing tag fragment.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(reasoning): keep undecided leading whitespace incremental

Before the format was decided, every content delta rebuilt, trimmed and re-reserved the whole leading prefix, so a stream of one-character whitespace deltas cost quadratic work. Leading whitespace is now kept in segments whose bytes are reserved once and joined only when the format is decided or the stream flushes.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(meta-muse): consolidate login admission and bounded response handling (#5591)

Carries #5591, which consolidates the closed #5234 and #5432, onto current dev. The provider contract keeps the inline-tag paragraph and adds the Meta Muse admission paragraph.

Co-authored-by: Epinephrine <luvs01@hanmail.net>

* fix(claude-desktop): keep applied state consistent across profile edits (#5590)

Carries #5590, which consolidates the closed #5337, onto current dev.

Co-authored-by: Epinephrine <luvs01@hanmail.net>
Co-authored-by: luvs01 <luvs01@users.noreply.github.com>

* fix(claude-desktop): commit applied markers only over the observed baseline

Both Desktop writers, provider-change auto-apply and client sync, now capture the desired profile and its applied marker before the Desktop write and commit the new marker only if profile presence, content, fingerprint and timestamp are unchanged. A concurrent edit, deletion or newer marker keeps its state and the write reports a skipped marker. The provider-change path no longer saves a whole stale config snapshot.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(claude-desktop): commit profile edits against the persisted marker

The Desktop profile PUT built its response from an earlier snapshot and saved that whole snapshot, so a marker committed by another writer during the awaited state build could be replaced by an older one. The edit now commits in one persisted-config mutation that keeps the latest marker for unchanged content and answers 409 when the profile itself changed meanwhile. The Meta Muse overflow test now asserts that the bounded-body limit, not a generic failure, produced the error.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(claude-desktop): report an unreadable config separately from an edit conflict

A missing or invalid config now answers 500 with its reason; only a concurrent profile change or exhausted rebase answers 409.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* feat(desktop): consolidate consent-based runtime takeover and ownership contracts (#5564)

Carries #5564, which consolidates #5459 and #5457, onto current dev. The review screenshot stays in the pull request description rather than the tree.

Co-authored-by: jun <bitkyc08@gmail.com>
Co-authored-by: sanggyulee <andy53295774@gmail.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(desktop): bind takeover stop to the approved runtime and fail closed

Desktop takeover re-resolves ownership immediately before stopping and passes the approved PID, endpoint, config home, CLI version and compatibility token to an opt-in guarded stop. The guard is checked under the ownership mutation lease before any manager or signal stop; the approved PID and endpoint must settle and the service manager must then be proven inactive, otherwise the stop answers approval-changed or manager-still-active and the desktop neither waits for silence nor claims. Unreadable or unparseable stop output is terminal as well. A second unreadable service-state read now blocks takeover, Windows managing-CLI discovery follows PATHEXT with file-only candidates and refuses command-interpreter metacharacters, the claim refusal test uses real sandbox state, and the runtime and desktop contracts record that the claim token is a consistency check rather than consent proof. Plain ocx stop is unchanged.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(desktop): keep plain stop entry points and format the takeover changes

Desktop exit keeps its plain runtime_stop::run entry while takeover uses run_approved, AttachPlan::Ask no longer carries an unread field, the Rust changes follow rustfmt, the plain CLI stop path keeps its literal outcome return, the stop source oracles follow the reader and outcome union that now include the two guarded refusals, and the runtime contract fits its 600-line budget.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(desktop): run takeover seam tests without tokio macros and harden manager and shim checks

The two async takeover seam tests now run on the shell runtime already used by the crate instead of tokio test macros, which this crate does not enable. Windows command-shim probes refuse command-interpreter metacharacters in every recorded argument as well as the executable, and the guarded stop re-inspects the service manager identity immediately before the manager command, answering approval-changed without stopping if it moved.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(responses): keep effort-based reasoning visible after routing

Final-route normalization recomputed hideThinkingSummary without the validated active-effort condition, so routed Chat and Kiro requests with an active effort and an omitted summary still hid raw reasoning. It now uses the same predicate as the parser; explicit "none" and requests without an active effort stay hidden.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(service): match the running CLI case-insensitively only on Windows

On case-sensitive filesystems a PATH executable that differs only in case is a different file, so it must get its own version probe instead of reporting the running CLI version.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(meta-muse): require the dashboard session for manual login codes

The manual-code continuation now applies the same dashboard-session admission as the login start, so a management token cannot advance a pending Meta Muse login.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(reasoning): reserve the joined leading-whitespace copy

Joining retained leading whitespace allocated a second copy outside the translator budget; the join is now reserved first and released once the segments are cleared.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(service): skip CLI probes for an absent runtime and treat failed systemd units as stopped

Resolve no longer spawns managing-CLI version probes when no runtime is live, since takeover is only offered for a live runtime. A systemd unit reported failed with no main PID is stopped, so a guarded stop that leaves it failed succeeds and a leftover failed unit does not block takeover.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(service): keep failed systemd units fail-closed and assess takeover only for a live runtime in tests

systemd can report failed before an automatic restart, so failed with no main PID is again treated as unknown rather than stopped. The resolve contract tests that assert ownership and takeover fields now use a live runtime, matching the skip of managing-CLI probes when no runtime is live.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

---------

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: Epinephrine <luvs01@hanmail.net>
Co-authored-by: yeongjunyoo <47925973+yeongjunyoo@users.noreply.github.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Joonsuh Park <trckstr4422@gmail.com>
Co-authored-by: Daniel Sjöstrand <16033062+Danielsjostrand1979@users.noreply.github.com>
Co-authored-by: alexph-dev <alexph-dev@users.noreply.github.com>
Co-authored-by: Yum-wu <1172989563@qq.com>
Co-authored-by: luvs01 <luvs01@users.noreply.github.com>
Co-authored-by: sanggyulee <andy53295774@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants