mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-11-02 19:22:22 +01:00
feat(settings): add a tool approval mode with an explicit off (YOLO) option (#6304)
* feat: add optional tool approval mode Admin-configurable tool_approval_mode setting (ask/auto) for the post-external-context tool approval gate. - ask (default): existing approval flow, gate stays on - auto: bypasses the approval gate for all runs - same effect as ODYSSEUS_TOOL_APPROVAL_GATE=0. Documented honestly in the settings row copy and in THREAT_MODEL.md, per review on #6304. - value validated server-side ({ask, auto}, anything else -> 400) - no new env var: the setting wires to the existing gate control - tests: setting validation + _tool_approval_gate_bypassed behavior * feat: surface deployment gate state on Tool approval row Follow-up to StressTestor's re-review: when ODYSSEUS_TOOL_APPROVAL_GATE is set to a falsy value, the Tool approval row still read 'Always ask' even though the gate was off, misleading admins the other way. GET /api/auth/settings now returns tool_approval_gate_env_disabled (derived from TOOL_APPROVAL_GATE_ENABLED) for admins, and the settings row renders a red notice naming the env var and explaining that the gate is off for every run regardless of the stored setting. Non-admin/scrubbed responses do not expose the deployment state. Test covers both env values and the scrub path. * refactor: rename tool approval mode auto to off The gate-off value is now "off" ("Off (YOLO)" in the UI) so the auto-approve name stays available for the future judged mode. --------- Co-authored-by: Matej <matej@local>
This commit is contained in:
@@ -2463,6 +2463,22 @@
|
||||
<label class="settings-label">Max steps per message</label>
|
||||
<input id="set-agentMaxRounds" type="text" inputmode="numeric" placeholder="20" class="settings-select" style="width:120px;">
|
||||
</div>
|
||||
<div class="settings-row">
|
||||
<label class="settings-label">Tool approval</label>
|
||||
<select id="set-toolApprovalMode" class="settings-select">
|
||||
<option value="ask">Always ask</option>
|
||||
<option value="off">Off (YOLO)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="admin-toggle-sub" style="margin-top:4px;">
|
||||
Auto-approve turns off the tool approval gate (same control as the
|
||||
ODYSSEUS_TOOL_APPROVAL_GATE env var). Bash, host_shell, send_email and
|
||||
delete_email then run without a confirmation even after the agent has
|
||||
seen untrusted external content (email, web pages, documents), so a
|
||||
prompt-injected instruction can reach them directly.
|
||||
</div>
|
||||
<div id="set-toolApprovalEnvNote" class="admin-toggle-sub" style="margin-top:4px;display:none;color:var(--red);"></div>
|
||||
<div id="set-agentMsg" style="font-size:11px;color:color-mix(in srgb, var(--fg) 45%, transparent);"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -10,6 +10,7 @@ export async function initAgentSettings() {
|
||||
var toolsInput = el('set-agentMaxTools');
|
||||
var roundsInput = el('set-agentMaxRounds');
|
||||
var supInput = el('set-agentSupervisorLadder');
|
||||
var approvalModeInput = el('set-toolApprovalMode');
|
||||
var msg = el('set-agentMsg');
|
||||
if (!toolsInput) return;
|
||||
|
||||
@@ -19,6 +20,21 @@ export async function initAgentSettings() {
|
||||
if (settings.agent_max_tool_calls) toolsInput.value = settings.agent_max_tool_calls;
|
||||
if (roundsInput && settings.agent_max_rounds) roundsInput.value = settings.agent_max_rounds;
|
||||
if (supInput) supInput.checked = !!settings.agent_supervisor_ladder;
|
||||
if (approvalModeInput) {
|
||||
approvalModeInput.value =
|
||||
settings.tool_approval_mode === 'off' ? 'off' : 'ask';
|
||||
}
|
||||
var approvalEnvNote = el('set-toolApprovalEnvNote');
|
||||
if (approvalEnvNote) {
|
||||
if (settings.tool_approval_gate_env_disabled) {
|
||||
approvalEnvNote.textContent =
|
||||
'Forced by deployment: ODYSSEUS_TOOL_APPROVAL_GATE is set to a falsy value on this server, so the approval gate is off for every run regardless of this setting.';
|
||||
approvalEnvNote.style.display = 'block';
|
||||
} else {
|
||||
approvalEnvNote.textContent = '';
|
||||
approvalEnvNote.style.display = 'none';
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
// Clamp + coerce a raw input to an int in [lo, hi]; falls back to `dflt`
|
||||
@@ -37,6 +53,10 @@ export async function initAgentSettings() {
|
||||
var payload = { agent_max_tool_calls: tools };
|
||||
if (rounds != null) payload.agent_max_rounds = rounds;
|
||||
if (supInput) payload.agent_supervisor_ladder = !!supInput.checked;
|
||||
if (approvalModeInput) {
|
||||
payload.tool_approval_mode =
|
||||
approvalModeInput.value === 'off' ? 'off' : 'ask';
|
||||
}
|
||||
try {
|
||||
await _postSettings(payload);
|
||||
msg.textContent = (tools > 0 ? 'Limit: ' + tools + ' tool calls' : 'Unlimited tool calls') +
|
||||
@@ -49,6 +69,7 @@ export async function initAgentSettings() {
|
||||
toolsInput.addEventListener('change', save);
|
||||
if (roundsInput) roundsInput.addEventListener('change', save);
|
||||
if (supInput) supInput.addEventListener('change', save);
|
||||
if (approvalModeInput) approvalModeInput.addEventListener('change', save);
|
||||
var cur = parseInt(toolsInput.value, 10) || 0;
|
||||
var curR = roundsInput ? (parseInt(roundsInput.value, 10) || 20) : null;
|
||||
msg.textContent = (cur > 0 ? 'Limit: ' + cur + ' tool calls' : 'Unlimited tool calls') +
|
||||
|
||||
Reference in New Issue
Block a user