Skip to content

Commit 8800406

Browse files
committed
feat(ai-chat): support SDK classifier-driven Auto permission mode
Companion to the phoenix-pro change adding a 4th permission mode, 'auto', which routes tool-call approval through the Claude Agent SDK's own model classifier instead of a blanket accept-all. The SDK (pinned ^0.2.126, installed 0.2.141) already supports this — no SDK upgrade needed. - src-node/claude-code-agent.js: default permission mode changed from acceptEdits to auto (matches the browser default); comments updated — no functional hook changes required, since the existing PreToolUse hooks already defer to the SDK for any mode they don't specifically handle. - strings.js: new AI_CHAT_MODE_AUTO / AI_CHAT_MODE_INFO_AUTO strings; renamed 'Full Auto' to 'Allow Everything' throughout (label, consent dialog title/body/button) to stay distinct from the new Auto mode. - Extn-AIChatPanel.less: new mode-classifier dot color for Auto; permission dropdown popup capped against the viewport (90vh) instead of inheriting the shared widget's 160px max-height, which forced an unnecessary scrollbar for 4 two-line items.
1 parent ab41a33 commit 8800406

3 files changed

Lines changed: 35 additions & 16 deletions

File tree

src-node/claude-code-agent.js

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,14 @@ let _planApproved = false;
103103
let _queuedClarification = null;
104104

105105
// Module-level "runtime" permission mode that hooks read at decision time.
106-
// Updated on every sendPrompt and via the setPermissionMode peer when the
107-
// user cycles the panel's permission bar mid-stream — without this, the
108-
// Bash hook would close over the value at query start and continue
109-
// prompting for confirmation even after the user has flipped to Full Auto.
110-
let _runtimePermissionMode = "acceptEdits";
106+
// One of "plan" | "acceptEdits" | "auto" (SDK classifier-approved) |
107+
// "bypassPermissions" (Allow Everything). Updated on every sendPrompt and
108+
// via the setPermissionMode peer when the user cycles the panel's
109+
// permission bar mid-stream — without this, the Bash hook would close over
110+
// the value at query start and continue prompting for confirmation even
111+
// after the user has flipped to Allow Everything. Defaults to "auto" to
112+
// match the browser's default (see AIChatPanel.js's _permissionMode).
113+
let _runtimePermissionMode = "auto";
111114

112115
const nodeConnector = global.createNodeConnector(CONNECTOR_ID, exports);
113116

@@ -661,7 +664,7 @@ exports.answerPlanModeWriteConfirm = async function (params) {
661664
* Apply a mid-stream permission-mode change so hooks running for the rest
662665
* of the turn use the new value. Called from the browser when the user
663666
* cycles the permission bar (so e.g. Bash stops prompting immediately
664-
* after switching from Edit Mode to Full Auto). The next sendPrompt also
667+
* after switching from Edit Mode to Allow Everything). The next sendPrompt also
665668
* passes permissionMode in params, so this peer is only strictly required
666669
* during streaming — but calling it on every cycle keeps the agent's
667670
* tracker authoritative.
@@ -758,7 +761,7 @@ async function _runQuery(requestId, prompt, projectPath, model, signal, locale,
758761
// Sync the runtime mutable that hooks read for permission decisions —
759762
// setPermissionMode (peer) updates this same variable when the user
760763
// cycles modes mid-stream.
761-
_runtimePermissionMode = permissionMode || "acceptEdits";
764+
_runtimePermissionMode = permissionMode || "auto";
762765
let editCount = 0;
763766
let toolCounter = 0;
764767
// SDK tool_use id (e.g. "toolu_01...") → our sequential toolCounter so a
@@ -901,7 +904,7 @@ async function _runQuery(requestId, prompt, projectPath, model, signal, locale,
901904
}
902905
},
903906
mcpServers: { "phoenix-editor": editorMcpServer },
904-
permissionMode: permissionMode || "acceptEdits",
907+
permissionMode: permissionMode || "auto",
905908
appendSystemPrompt:
906909
"When modifying an existing file, always prefer the Edit tool " +
907910
"(find-and-replace) instead of the Write tool. The Write tool should ONLY be used " +
@@ -1288,11 +1291,15 @@ async function _runQuery(requestId, prompt, projectPath, model, signal, locale,
12881291
async (input) => {
12891292
// Read from the runtime mutable so mid-stream
12901293
// permission-mode flips (e.g. user switches Edit
1291-
// Mode → Full Auto while bash is in flight) take
1292-
// effect on the NEXT bash call without waiting
1293-
// for the next prompt.
1294+
// Mode → Allow Everything while bash is in flight)
1295+
// take effect on the NEXT bash call without
1296+
// waiting for the next prompt.
12941297
if (_runtimePermissionMode !== "acceptEdits") {
1295-
// Plan mode: SDK handles. Full Auto: allow freely.
1298+
// Plan mode: SDK handles. Auto: SDK's own
1299+
// classifier decides. Allow Everything: allow
1300+
// freely. Either way, Phoenix's own
1301+
// confirm-dialog/safe-bash-allowlist below is
1302+
// only for Edit Mode's manual approval flow.
12961303
return {};
12971304
}
12981305
// Edit Mode: ask user confirmation before running bash

src/nls/root/strings.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2660,9 +2660,9 @@ define({
26602660
"AI_CHAT_FILE_NOT_FOUND_MSG": "Could not open <span class=\"dialog-filename\">{0}</span>. The file may have been moved or deleted.",
26612661
"AI_CHAT_UNDO_RESTORE_WARNING_TITLE": "AI Undo & Restore",
26622662
"AI_CHAT_UNDO_RESTORE_WARNING_BODY": "This will only undo changes made by the AI. Changes made outside the AI won’t be restored and may be lost. For full version history, use version control like Git.",
2663-
"AI_CHAT_FULL_AUTO_WARNING_TITLE": "Switch to Full Auto Mode?",
2664-
"AI_CHAT_FULL_AUTO_WARNING_BODY": "Full Auto mode lets the AI run any tool — Bash commands, file edits, file deletions, web fetches — without asking you first.<br><br>This is convenient for trusted scratch projects, but can be risky: a misjudged step could overwrite or delete files, run a destructive shell command, or push unintended changes. Use version control (Git) so you can recover if something goes wrong.<br><br>Only enable Full Auto in projects you trust. You can switch back to Edit Mode at any time using <kbd>Shift+Tab</kbd> or by clicking the mode bar.",
2665-
"AI_CHAT_FULL_AUTO_WARNING_PROCEED": "Enable Full Auto",
2663+
"AI_CHAT_FULL_AUTO_WARNING_TITLE": "Switch to Allow Everything Mode?",
2664+
"AI_CHAT_FULL_AUTO_WARNING_BODY": "Allow Everything mode lets the AI run any tool — Bash commands, file edits, file deletions, web fetches — without asking you first.<br><br>This is convenient for trusted scratch projects, but can be risky: a misjudged step could overwrite or delete files, run a destructive shell command, or push unintended changes. Use version control (Git) so you can recover if something goes wrong.<br><br>Only enable Allow Everything in projects you trust. You can switch back to Edit Mode at any time using <kbd>Shift+Tab</kbd> or by clicking the mode bar.",
2665+
"AI_CHAT_FULL_AUTO_WARNING_PROCEED": "Enable Allow Everything",
26662666
"AI_CHAT_ONBOARDING_REVIEW_PROMPT": "Ready to build",
26672667
"AI_CHAT_ONBOARDING_SEND": "Send",
26682668
"AI_CHAT_SHOW_DIFF": "Show diff",
@@ -2699,9 +2699,11 @@ define({
26992699
"AI_CHAT_PLAN_REVISE_DEFAULT": "Please revise the plan.",
27002700
"AI_CHAT_MODE_PLAN": "Plan Mode",
27012701
"AI_CHAT_MODE_EDIT": "AI Edit Mode",
2702-
"AI_CHAT_MODE_FULL_AUTO": "Full Auto",
2702+
"AI_CHAT_MODE_AUTO": "Auto",
2703+
"AI_CHAT_MODE_FULL_AUTO": "Allow Everything",
27032704
"AI_CHAT_MODE_INFO_PLAN": "AI will propose a plan before making changes (Click to switch)",
27042705
"AI_CHAT_MODE_INFO_EDIT": "AI can edit files. Shell commands need approval (Click to switch)",
2706+
"AI_CHAT_MODE_INFO_AUTO": "AI uses judgment to auto-approve safe actions and asks about risky ones (Click to switch)",
27052707
"AI_CHAT_MODE_INFO_FULL_AUTO": "AI can edit files and run commands without approval (Click to switch)",
27062708
"AI_CHAT_PERMISSION_SELECT_TITLE": "Choose how much the AI can do without approval [or Shift+Tab]",
27072709
"AI_CHAT_AUTH_ERROR_NOTICE": "Claude Code is signed out or your login has expired.",

src/styles/Extn-AIChatPanel.less

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,12 @@
454454
.dropdownbutton-popup.ai-permission-dropdown-popup {
455455
min-width: 220px;
456456
max-width: 320px;
457+
// Override the shared .dropdownbutton-popup.dropdown-menu 160px cap
458+
// (brackets_patterns_override.less) — 4 two-line items run ~200px,
459+
// past that cap, which forced a scrollbar for a list that otherwise
460+
// fits easily. Cap against the viewport instead so it only scrolls
461+
// if it would genuinely run past the screen.
462+
max-height: 90vh;
457463

458464
li a {
459465
white-space: normal;
@@ -2726,6 +2732,10 @@
27262732
&.mode-plan {
27272733
background-color: #3498db;
27282734
}
2735+
2736+
&.mode-classifier {
2737+
background-color: #9b59b6;
2738+
}
27292739
}
27302740

27312741
.ai-permission-label {

0 commit comments

Comments
 (0)