refine the prompt/log UX: show commands, de-emphasize injects
Two spot-check fixes (T-178, T-179), both grounded in a boundary test of the stream-json wire (findings folded into the spike doc): - Harness-injected user messages (skill loads, slash-command expansions, system reminders) carry isSynthetic on the wire (isMeta in the transcript). They were rendering as blue "you" cards though the user never typed them; now UserMessage.injected flags them and the view shows a muted, collapsed "context" card instead. - Permission prompts now show the command/input being permitted (a capped, scrollable code block) so you can see what you approve. Instead of fully hiding a prompted tool-use, once resolved it collapses to a one-line summary with a green (approved) or red (denied) border; the session tracks per-tool_use_id outcome and the view colours it. The result is kept. Corrects an earlier wrong assumption: the Skill tool is auto-allowed (no permission prompt); the inject only appears once the Skill tool is actually invoked, which is why deny-captures missed it. T-178, T-179, D-78. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -174,11 +174,17 @@ class StreamJsonSession {
|
||||
final _pendingCtl = StreamController<ToolPrompt?>.broadcast();
|
||||
|
||||
/// tool_use_ids that surfaced as a prompt — the view hides their raw
|
||||
/// tool-use card (it showed as a prompt) but keeps the result (D-78).
|
||||
/// tool-use card while pending (it shows as a prompt) but keeps the result.
|
||||
final _promptedToolUses = <String>{};
|
||||
|
||||
/// Read-only view of [_promptedToolUses] for the conversation view.
|
||||
/// Resolved outcome per prompted tool_use_id: true = allowed, false = denied.
|
||||
/// Absent = still pending. The view shows resolved tool-uses collapsed with a
|
||||
/// green/red border (D-78).
|
||||
final _toolUseOutcome = <String, bool>{};
|
||||
|
||||
/// Read-only views for the conversation view.
|
||||
Set<String> get promptedToolUseIds => _promptedToolUses;
|
||||
Map<String, bool> get toolUseOutcomes => _toolUseOutcome;
|
||||
|
||||
/// The prompt currently awaiting a decision (queue head), or null.
|
||||
ToolPrompt? get pendingPrompt => _queue.isEmpty ? null : _queue.first;
|
||||
@@ -262,6 +268,7 @@ class StreamJsonSession {
|
||||
final idx = _queue.indexWhere((p) => p.promptId == promptId);
|
||||
if (idx < 0) return; // unknown / already resolved
|
||||
final prompt = _queue.removeAt(idx);
|
||||
if (prompt.toolUseId.isNotEmpty) _toolUseOutcome[prompt.toolUseId] = decision is AllowTool;
|
||||
_proc.writeLine(jsonEncode({
|
||||
'type': 'control_response',
|
||||
'response': {'subtype': 'success', 'request_id': promptId, 'response': decision.toJson()},
|
||||
|
||||
Reference in New Issue
Block a user