mirror of
https://github.com/patriceckhart/zot.git
synced 2026-06-27 22:06:31 +02:00
Adds a per-tool-call confirmation gate. Default stays yolo mode
(tools run freely, same as today). Pass --no-yolo to require
explicit user approval before each tool invocation.
Interactive TUI:
A dialog appears before every tool call. Shows the tool name and
a one-line preview of its args (command / path / url / etc.)
with four choices, selectable by arrow keys or numeric shortcut:
1. yes (run this call)
2. yes, always this tool (skip prompts for this tool,
session-scoped)
3. yes, always (skip prompts for every tool,
session-scoped)
4. no (refuse and let the model try
something else)
Esc/ctrl+c refuses the current prompt. Esc during a running turn
both cancels the turn AND drains any pending confirm so the
agent goroutine doesn't deadlock. Multiple pending confirms are
queued and answered one at a time with a count visible in the
header.
Type /yolo to disable the gate for the rest of the session
(equivalent to the "yes, always" choice but without needing a
pending prompt). Any currently-open confirm auto-allows so the
agent keeps moving.
Print / JSON / RPC modes:
No interactive prompt is available, so every tool call is
auto-refused with a reason the model can learn from:
"tool call refused: --no-yolo is active and there is no
interactive prompt in this mode; ask the user what to do
instead". Observed behaviour: the model pivots to asking the
user directly instead of looping on the same tool.
Implementation:
internal/core/confirm.go
- ConfirmDecision, Confirmer interface
- ConfirmGate with session-scoped memory for "always this tool"
and "always everything" decisions, both concurrency-safe
- BuildPreview: turns {"command":"ls"} into "ls", etc.
- Lives in core to avoid a modes -> agent import cycle
internal/core/confirm_test.go
- Tests: nil gate allows, nil-inner refuses with reason, one-
shot allow doesn't remember, remember-tool short-circuits
only same tool, remember-all short-circuits everything,
refusal reasons surface, empty-reason gets a default,
runtime AllowAll works, BuildPreview handles each field
internal/agent/modes/confirm_dialog.go
- Queue-based dialog, HandleKey wiring, CancelAll and
AllowAllPending for the two exit cases
internal/agent/modes/interactive.go
- InteractiveConfig gains NoYolo + ConfirmGate fields
- Interactive implements core.Confirmer via a response channel
- Confirm dialog dispatched FIRST in the key-handler chain so
keys never leak to other dialogs while the agent is blocked
- Esc-while-busy also calls confirmDialog.CancelAll so the
agent unblocks
- /yolo slash command handled in runSlash
internal/agent/cli.go
- Constructs the ConfirmGate when args.NoYolo is set,
BeforeToolExecute calls it first, extensions only see calls
the user already approved
- After iv is built, SetConfirmer(iv) wires the gate's inner
so interactive + gate share the same struct
- wireNoYoloAutoRefuse() for print / json modes
internal/agent/args.go
- --no-yolo flag and help text
internal/agent/modes/slash_suggest.go
- /yolo added to slashCatalog
Verified end-to-end: fresh zot --no-yolo -p "read sample.ts" now
returns "I can't read files in this mode (--no-yolo without an
interactive prompt). How would you like to proceed" instead of
actually reading.
|
||
|---|---|---|
| .. | ||
| agent | ||
| assets | ||
| auth | ||
| core | ||
| extproto | ||
| provider | ||
| skills | ||
| tui | ||