exp: sticky agent mode — mode locking + permission-based skill scoping#1719
Closed
yanyihan-xiaomi wants to merge 10 commits into
Closed
exp: sticky agent mode — mode locking + permission-based skill scoping#1719yanyihan-xiaomi wants to merge 10 commits into
yanyihan-xiaomi wants to merge 10 commits into
Conversation
4012f85 to
177b840
Compare
…coping - TUI: lock agent after first message, Build/Plan can switch freely - Show toast when switch blocked, lock on session restore - Remove hidden:true from compose skills, use permission deny/allow - defaults deny compose:*, compose agent allows compose:* - Remove hidden filter from Skill.available()
- Remove composeSkillsBlock() call from prompt.ts (skills now in normal listing)
- Clean compose.txt: remove {{compose_skills}} placeholder
- Update subagent guidance: distill instructions, don't pass skill lists
lock() was broken with /new because the boolean persisted. Now uses session content as the source of truth — /new creates an empty session, naturally allowing mode switching again.
Tab now finds the next valid agent in the group instead of stopping at the first blocked one. Toast only shows when no valid agent exists to switch to (e.g., compose is the only option).
Simple reactive effect: sessionHasMessages = !!lastUserMessage(). No manual lock/unlock needed — works correctly with /new, /session, and message submission automatically.
set() is unguarded (for system use: session restore, plan tools, CLI). userSwitch() has the sticky guard (for user actions: dialog, voice). move() already has its own guard internally.
- plan_enter/plan_exit: deny in compose agent permission (agent.ts) - registry.ts reads permission to filter, no hardcoded agent names - switchBlockedToast: shows subset message (build/plan) or locked message (compose) - i18n: add tui.agent.locked.subset in all locales
a7ddbb0 to
cb8a5bb
Compare
Collaborator
Author
|
Superseded by #1725 — same implementation, clean commit history, ready for discussion. |
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.
Overview
Experimental branch exploring "mode is immutable within a session" interaction model. Will not be merged to main — for trying out and discussion.
Key Changes
1. Sticky Mode
After the first message in a session, the mode is locked:
/newcreates a fresh session and restores free selectionContextual toasts:
2. Permission Replaces Hidden
hidden: truefrom all compose skillscompose:*, compose agent explicitly allowsSkill.available()no longer filters by hidden — relies entirely on permission system3. Plan Tools Scoped to Build/Plan
plan_enter/plan_exit, build and plan explicitly allow both (symmetric)llm.ts:resolveTools()already usesPermission.disabled()to strip denied tools4. Removed composeSkillsBlock() Injection
<available_skills>XML block injection{{compose_skills}}placeholderDesign Tradeoffs
set()vsuserSwitch()separation!!lastUserMessage()/newand/sessionwork correctly by naturemove()skips blocked agentscurrent === target→ no-op, no false toastFREE_SWITCH_GROUPare treated as isolated (sticky). Would need group configuration support.hidden: trueno longer effective: Skills relying on hidden must migrate to permission config<available_skills>blocks: Must distill instructions directly into promptsTry It
Test:
/agents→ try compose → toast: "only switch between build, plan"/new→ free switching restored/sessioninto history → auto-lockedStability Note
Theoretically more stable due to constrained behavior — the model's system prompt (skills + tools) is fixed for the entire session (no prefix cache invalidation from mode switches). However, this is a breaking change that affects custom mode workflows and is not planned to be merged.
Tests
bun test test/agent/agent.test.ts— 48/48 pass (includes new plan tool permission tests)bun test test/session/prompt-skill-mention.test.ts— 8/8 passbun test test/permission— 141/141 passRelated Files
docs/compose/reports/sticky-agent-mode.mdpackages/opencode/src/cli/cmd/tui/context/local.tsxpackages/opencode/src/agent/agent.tspackages/opencode/src/session/prompt.ts,compose.txt