Correcting a command before allowing it

An approval card was Allow, Always, or Don't. A model proposing the right
command with one flag wrong therefore cost a whole round trip to explain in
prose. There is an Edit button on it now.

Where the edit lands is the whole of the feature, and it is one line.
`arguments` is the list `_run_calls` hands to `run_tool` as `parsed=`, and
`run_tool` never re-parses -- so writing into it inside `_authorise` is the
only mutation the runner can see. Editing the Item would do nothing: it is
frozen and display-only.

Two things had to move with it. The raw `call["arguments"]` string is rewritten
beside the parsed dict, and the assistant turn is now built *after* `_authorise`
rather than before it -- the old order told the model it ran what it proposed
while something else ran, and every later round would have reasoned from a
transcript that was quietly false. And `_remember_always` reads the edit, or
"always allow this" would store a standing permission for a command nobody
approved; it still derives the pattern itself through `policy.subject`, which
yields nothing for a composed command line.

Nothing is re-checked against the mode or the lists, and that is not a shortcut.
The deny list resolves to ASK rather than to a refusal -- it means "always ask
about this" -- so a person who has typed the command and pressed Allow is
exactly the asking it was demanding, and re-asking would put the same card up
with no way past it. It is the line the terminal panel already draws.

The box is only offered where the detail *is* an argument and can be put back:
a tool with no entry in `tool_labels.DETAIL_KEYS` gets a `k=repr(v)` summary,
and a box there would silently change nothing. Both halves are always in the
DOM with one hidden, rather than the field being created on click -- a field
that does not exist until a handler runs is a field that submits nothing if
the handler fails, and this one decides what runs on somebody's machine.

The transcript says "edited by you". Attributing somebody's own typing to a
model is the same misattribution as the other way round.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jaroslav Beneš
2026-08-04 08:40:51 +02:00
parent ec12c3a981
commit ab2e74974b
7 changed files with 620 additions and 40 deletions
+12
View File
@@ -521,6 +521,18 @@
white-space: pre-wrap;
overflow-wrap: anywhere;
}
/* The same command, correctable. Sized and spaced like the <pre> it replaces
so pressing Edit does not make the card jump. */
.interaction__edit {
width: 100%;
margin: 0 0 var(--sp-2);
padding: var(--sp-3);
font-family: var(--font-mono);
font-size: var(--text-xs);
white-space: pre-wrap;
overflow-wrap: anywhere;
resize: vertical;
}
.interaction__reason { margin: 0; color: var(--ink-muted); font-size: var(--text-xs); }
/* The model's account of what it is about to do. Above the command and quieter
than the title, so the command stays the thing being agreed to. */