feat(briefing): UI polish for agentic briefing messages

Three visual improvements for the briefing conversation:

1. Intermediate tool-call messages (empty content, briefing_intermediate:
   true) now render as a compact dashed status row with per-tool pills
   showing result counts, instead of an empty assistant bubble followed
   by a stack of ToolCallCards. Click to expand the full cards.

2. Slot badge on non-intermediate briefing messages — "Full Briefing"
   for compilation, "Morning/Midday/Afternoon Update" for slot
   injections. Slot updates get a softer bubble treatment (transparent
   background, muted border, smaller text) so the compilation stays
   visually dominant.

3. Slot separator now triggers on briefing_slot metadata (not the
   compilation-only rss_item_ids), and uses a look-behind so it only
   fires when there's a prior slot message — no separator above the
   first briefing of the day.

New component: BriefingToolStatusRow.vue handles the intermediate
pill row and delegates to ToolCallCard when expanded.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-10 22:10:31 -04:00
parent 06dbc0e27a
commit 593d737e26
3 changed files with 264 additions and 23 deletions
+22 -21
View File
@@ -289,6 +289,23 @@ async function send(text: string) {
await onSubmit({ content: text })
}
// ── Briefing slot separator helper ────────────────────────────────────────────
function hasEarlierBriefingSlot(index: number): boolean {
const msgs = store.currentConversation?.messages ?? []
for (let i = 0; i < index; i++) {
const m = msgs[i]
const meta = m?.metadata as Record<string, unknown> | null | undefined
if (
m?.role === 'assistant' &&
meta?.briefing_slot != null &&
!meta?.briefing_intermediate
) {
return true
}
}
return false
}
defineExpose({ focus, prefill, send })
</script>
@@ -303,13 +320,11 @@ defineExpose({ focus, prefill, send })
v-for="(msg, index) in store.currentConversation?.messages ?? []"
:key="msg.id"
>
<!-- Briefing slot separator: shown before a 2nd+ briefing slot message -->
<!-- Briefing slot separator: before any non-first slot message (skip intermediate tool-call rows) -->
<div
v-if="briefingMode && index > 0 && msg.role === 'assistant' && msg.metadata?.rss_item_ids"
v-if="briefingMode && msg.role === 'assistant' && msg.metadata?.briefing_slot && !msg.metadata?.briefing_intermediate && hasEarlierBriefingSlot(index)"
class="briefing-slot-separator"
>
<span>New Briefing Update</span>
</div>
></div>
<ChatMessage
:message="msg"
@save-as-note="handleSaveAsNote"
@@ -537,24 +552,10 @@ defineExpose({ focus, prefill, send })
/* Briefing slot separator */
.briefing-slot-separator {
display: flex;
align-items: center;
gap: 0.75rem;
margin: 1.25rem 0 0.5rem;
color: var(--color-text-muted, #888);
font-size: 0.7rem;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
opacity: 0.7;
}
.briefing-slot-separator::before,
.briefing-slot-separator::after {
content: '';
flex: 1;
height: 1px;
margin: 1.25rem 0 0.75rem;
background: var(--color-border, #333);
opacity: 0.5;
opacity: 0.35;
}
/* Context sidebar */