diff --git a/frontend/src/components/BriefingToolStatusRow.vue b/frontend/src/components/BriefingToolStatusRow.vue
new file mode 100644
index 0000000..7ba64c4
--- /dev/null
+++ b/frontend/src/components/BriefingToolStatusRow.vue
@@ -0,0 +1,168 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/components/ChatMessage.vue b/frontend/src/components/ChatMessage.vue
index 14dc4d1..ebb6f67 100644
--- a/frontend/src/components/ChatMessage.vue
+++ b/frontend/src/components/ChatMessage.vue
@@ -3,8 +3,16 @@ import { computed } from "vue";
import { renderMarkdown } from "@/utils/markdown";
import { useSettingsStore } from "@/stores/settings";
import ToolCallCard from "@/components/ToolCallCard.vue";
+import BriefingToolStatusRow from "@/components/BriefingToolStatusRow.vue";
import type { Message } from "@/types/chat";
+const SLOT_LABELS: Record = {
+ compilation: "Full Briefing",
+ morning: "Morning Update",
+ midday: "Midday Update",
+ afternoon: "Afternoon Update",
+};
+
const settingsStore = useSettingsStore();
const props = defineProps<{
@@ -41,6 +49,30 @@ function formatMs(ms: number | null | undefined): string {
return `${(ms / 1000).toFixed(1)}s`;
}
+const metadata = computed(() => (props.message.metadata ?? {}) as Record);
+
+const isBriefingIntermediate = computed(
+ () => props.message.role === "assistant" && metadata.value.briefing_intermediate === true,
+);
+
+const briefingSlot = computed(() => {
+ const slot = metadata.value.briefing_slot;
+ return typeof slot === "string" ? slot : null;
+});
+
+const slotLabel = computed(() => {
+ const slot = briefingSlot.value;
+ if (!slot) return null;
+ return SLOT_LABELS[slot] ?? slot;
+});
+
+const isSlotUpdate = computed(
+ () =>
+ !isBriefingIntermediate.value &&
+ briefingSlot.value != null &&
+ briefingSlot.value !== "compilation",
+);
+
const timingParts = computed((): string[] => {
const t = props.message.timing;
if (!t) return [];
@@ -57,11 +89,16 @@ const timingParts = computed((): string[] => {
-