feat(shell): unified approval modes with toolbar badges and temporary toasts#2249
feat(shell): unified approval modes with toolbar badges and temporary toasts#2249baldasso wants to merge 1 commit into
Conversation
| type Response = Literal["approve", "approve_for_session", "reject"] | ||
|
|
||
| # Actions that touch files but do not execute arbitrary shell commands. | ||
| _FILE_ACTIONS = frozenset({"edit", "edit_outside", "replace"}) |
There was a problem hiding this comment.
🔴 _FILE_ACTIONS contains wrong action strings, making 'files' approval mode completely non-functional
The _FILE_ACTIONS frozenset at src/kimi_cli/soul/approval.py:21 contains {"edit", "edit_outside", "replace"}, but these strings are never used as action names anywhere in the codebase. The actual action strings passed to approval.request() come from the FileActions StrEnum (src/kimi_cli/tools/file/__init__.py:10-13): "edit file" (FileActions.EDIT) and "edit file outside of working directory" (FileActions.EDIT_OUTSIDE). The string "replace" is never used as an action at all.
This causes two failures:
_should_auto_approve()in "files" mode never auto-approves (line 198-199):action in _FILE_ACTIONSis alwaysFalse, so the "files" mode behaves identically to "ask" — the user is still prompted for every file edit.approve_for_sessionnever promotes to "files" mode (line 301): The conditionaction in _FILE_ACTIONSis alwaysFalse, so approving a file action "for session" always falls through to theelifat line 303 and escalates directly to"all"mode, skipping the intended intermediate"files"mode entirely.
| _FILE_ACTIONS = frozenset({"edit", "edit_outside", "replace"}) | |
| _FILE_ACTIONS = frozenset({"edit file", "edit file outside of working directory"}) |
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Fixed. _FILE_ACTIONS now uses the actual action strings from FileActions enum: "edit file" and "edit file outside of working directory".
There was a problem hiding this comment.
💡 Codex Review
kimi-cli/src/kimi_cli/soul/approval.py
Line 15 in 2e8d9de
In edits mode, file tools still prompt because the actions passed by WriteFile/StrReplaceFile are the FileActions values ("edit file" and "edit file outside of working directory"), not "edit" or "edit_outside". With approval_mode == "files", _should_auto_approve() therefore returns false for normal file writes/edits and falls through to the manual approval request, so the new edits mode does not actually auto-approve its primary workflow.
ℹ️ 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".
| approval_state = ApprovalState( | ||
| yolo=effective_yolo, | ||
| approval_mode=effective_mode, | ||
| yolo=session.state.approval.yolo, | ||
| afk=session.state.approval.afk, |
There was a problem hiding this comment.
Preserve the --yolo flag in approval state
When an interactive session is started with --yolo, effective_mode becomes "all" but the shared state keeps yolo from the persisted session instead of the invocation flag. In that scenario /yolo checks is_yolo_flag(), sees false, and turns yolo on rather than disabling auto-approval on the first toggle, which is a regression from the previous effective_yolo = yolo or session.state.approval.yolo behavior.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed. ApprovalState now receives yolo or session.state.approval.yolo, so invocation-time --yolo correctly sets the internal yolo flag and /yolo toggle works as expected on first use.
2e8d9de to
e9fbf13
Compare
|
Fixed both issues flagged by the AI reviews:
Amended and force-pushed. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e9fbf13ef8
ℹ️ 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".
| elif approval.auto_approve_actions: | ||
| approval.approval_mode = "edits" |
There was a problem hiding this comment.
Avoid promoting arbitrary legacy approvals to edits
When resuming a legacy session where "Approve for session" was used for a non-file action such as ShellTool's "run command", this migration sets approval_mode to "edits" just because auto_approve_actions is non-empty. The old action set is still preserved and checked later, so shell commands remain auto-approved while the toolbar only says edits, and the new edits mode also starts auto-approving all file edits; that both misrepresents and broadens the resumed session's approval scope.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed. Removed the promotion of auto_approve_actions to edits mode. The legacy set continues to work under manual mode (checked in Approval.request), so promoting it would have both broadened the approval scope and misrepresented the state in the toolbar.
e9fbf13 to
d6df535
Compare
|
All three AI-review issues are now fixed in the amended commit:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d6df53555c
ℹ️ 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".
| elif approval_mode == "manual" and auto_approve_actions: | ||
| approval_mode = "edits" |
There was a problem hiding this comment.
Avoid promoting legacy action approvals to edits
Fresh evidence: load_session_state() now intentionally leaves legacy auto_approve_actions in manual mode, but Runtime.create() still passes that set into this constructor, and this branch promotes any non-empty set to edits. Resuming a session that previously approved only a non-file action such as run command therefore shows edits mode and starts auto-approving all file edits while the old shell action remains auto-approved via the preserved set, broadening the session's approval scope.
Useful? React with 👍 / 👎.
What problem does this solve?
Right now, Kimi has four different ways to control auto-approval:
--yoloflag--afkflag/yoloslash command/afkslash commandThey all do slightly different things, overlap in confusing ways, and—most importantly—there's no way to see which one is active without remembering what you typed five minutes ago. New users have no mental model for how permission levels work.
This PR fixes that by introducing a single, progressive three-level system that's always visible in the UI.
Closes #2105
Closes #1631
The new model: manual → edits → auto
Plan mode is included in the cycle as a fourth stop (
manual → edits → auto → plan → manual) so you can jump into read-only planning without hunting for the slash command.What it looks like
Bottom toolbar — always know your mode
◐ edits(green) when file operations are auto-approved● auto(amber) when everything is auto-approvedInput border — instant visual feedback
── input ──grey solid╌╌ input · edits ════════green dashed╌╌ input · auto ════════amber dashed╌╌ input · plan ════════blue dashedShift+Tab to cycle
Press Shift+Tab to cycle through modes. A descriptive toast appears for 5 seconds:
Then it disappears. No permanent clutter.
Demo
Screen.Recording.2026-05-12.at.16.36.13.mov
How we got here
This design directly addresses three long-standing community requests:
editsmode is exactly thatThe naming (
manual/edits/auto) was chosen for literal, impossible-to-misunderstand clarity over clever metaphors. Safety-critical UI should not be cute.Backward compatibility — your existing sessions still work
state.jsonfiles withyolo=Trueorafk=Trueload seamlessly; they map toapproval_mode="auto"/yoloand/afkslash commands still work (they setautomode internally)--yoloand--afkCLI flags still workyolo,afk,auto_approve_actions) are preserved inApprovalStateDataThe old flags are now "implementation details" — the UI speaks the new language.
Technical details
ApprovalMode = Literal["manual", "edits", "auto"]replaces boolean flag soup in the approval state machine_migrate_legacy_approval_state()promotes old flags on session loadedits; anything else promotes toautoTesting
Checklist
ApprovalModetype alias used everywhere