Repository navigation
fix(thread-control): grant thread control without a wording check - #2271
Merged
Merged
Conversation
…ted negations Reproduces #2267. Both prompts from the issue are denied today, and a denied call gives no reason the model or user can act on.
… its sentence A negation now voids only the thread-control names after it in the same sentence, so an unrelated "don't" no longer denies an explicit request. A denied call now says why: no active turn, a message that did not ask for thread control, or an invalid tool call id. Fixes #2267
Every turn on a provider that supports thread control now gets an active lease. The user's message no longer decides whether the thread-control tools work, so requests such as "Farm this out to Codex" or prompts with an unrelated "don't" are no longer refused. The permission ceiling from ADR-0032 is the real limit and is already enforced: a supervised Coordinator cannot start a full-access delegate, and an unnamed mode inherits the Coordinator's. Codex also stops restarting its session whenever a turn's eligibility flipped, because eligibility is now fixed per provider. Fixes #2267 Part of #2218
# Conflicts: # apps/server/src/features/mcode-mcp/__tests__/thread-control-toolkit.test.ts # packages/thread-orchestration/src/mcode-instructions.ts
chuks-qua
enabled auto-merge (squash)
October 21, 2026 16:03
chuks-qua
added a commit
that referenced
this pull request
Oct 23, 2026
…t a per-turn flag (#2280) * refactor(delegation): drop the per-turn thread-control eligibility flag TurnRequest.threadControlEligible was the last piece of the wording gate. Since #2271 the server set it from the provider alone, so it never varied for a Codex session, but the Codex adapter still used it to decide whether to attach the Delegation toolkit and kept a session restart for an eligibility change that could no longer happen. Codex now attaches the Delegation toolkit to every session, as the Claude, Cursor and Copilot adapters already do. The steer runtime reads whether a turn holds the Delegation lease from the lease directive itself instead of the request flag. Part of #2218 * docs(providers): describe the Delegation toolkit attach flag without per-turn eligibility Part of #2218
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Before this change, the server read the user's message to decide whether a turn got Mcode thread control.
isExplicitMcodeThreadRequestmatched wording such as "mcode thread" plus an action verb and rejected messages with a nearby negation. Requests like "Farm this out to Codex" or "Call delegate_task once. Do not call any other tool." got no lease, and the tool call failed with "Internal thread-control MCP request denied".Now no turn depends on its wording.
isExplicitMcodeThreadRequestand its regexes are deleted. Every turn on a provider that supports internal thread control (claude, codex, cursor, copilot) gets an active lease, and the lease still revokes at turn end.The limit is ADR-0032's permission-mode ceiling. A supervised Coordinator cannot request a full child, and a child with no named mode inherits the Coordinator's.
delegated-task-service.tsandthread-control-service.tsenforce it.A denied call now carries a reason,
invalid_tool_callorno_active_turn, with a message the model and the user can act on.Codex no longer restarts its session when
threadControlEligiblechanges between turns. The flag is now constant per provider, so it never changes.The fix round also:
packages/thread-orchestration/src/mcode-instructions.ts. "Hand work to another provider or model" now uses delegate_task without naming Mcode threads. Native sub-agents stay the default for "sub-agent" requests, and the model never launches a thread just because the user said "sub-agent".Verification:
bun run lintexits 0.thread_launch. Main's new gate tests insrc/mcode-instructions.test.tswere removed along with the gate.Why
The wording check guarded the wrong thing. It read the user's words, not what the delegated work may do, and it refused ordinary requests with an error that gave no cause. ADR-0032 replaces it with the permission-mode ceiling.
Fixes #2267. Part of #2218.
Review Notes
threadControlEligibleplumbing.Need help on this PR? Tag
@codesmith-botwith what you need.