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:
@@ -53,13 +53,19 @@ final class UserMessage extends ConversationItem {
|
||||
required super.timestamp,
|
||||
required super.isSidechain,
|
||||
required this.text,
|
||||
this.injected = false,
|
||||
});
|
||||
|
||||
/// The concatenated text of all `text` parts in the content array.
|
||||
final String text;
|
||||
|
||||
/// True when this "user" message was injected by the harness (a skill load,
|
||||
/// a slash-command expansion, a system reminder) rather than typed by the
|
||||
/// user — the view de-emphasises these (D-78).
|
||||
final bool injected;
|
||||
|
||||
@override
|
||||
String toString() => 'UserMessage(${_shortId(uuid)}, ${text.length} chars)';
|
||||
String toString() => 'UserMessage(${_shortId(uuid)}, ${text.length} chars${injected ? ', injected' : ''})';
|
||||
}
|
||||
|
||||
/// A tool-result delivered from the host back to Claude as a user message.
|
||||
@@ -520,9 +526,14 @@ void _parseUserInto(
|
||||
if (message == null) return;
|
||||
final content = message['content'];
|
||||
|
||||
// Harness-injected user messages (skill loads, slash-command expansions,
|
||||
// system reminders) — `isSynthetic` on the stream-json wire, `isMeta` in the
|
||||
// transcript. The view de-emphasises these (D-78).
|
||||
final injected = envelope['isSynthetic'] == true || envelope['isMeta'] == true;
|
||||
|
||||
if (content is String) {
|
||||
if (content.isNotEmpty) {
|
||||
out.add(UserMessage(uuid: uuid, timestamp: timestamp, isSidechain: isSidechain, text: content));
|
||||
out.add(UserMessage(uuid: uuid, timestamp: timestamp, isSidechain: isSidechain, text: content, injected: injected));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -550,7 +561,7 @@ void _parseUserInto(
|
||||
}
|
||||
}
|
||||
if (textParts.isNotEmpty) {
|
||||
out.add(UserMessage(uuid: uuid, timestamp: timestamp, isSidechain: isSidechain, text: textParts.join('\n')));
|
||||
out.add(UserMessage(uuid: uuid, timestamp: timestamp, isSidechain: isSidechain, text: textParts.join('\n'), injected: injected));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user