Message timestamps in full mode, API error state, model badges on session list
This commit is contained in:
@@ -259,7 +259,7 @@ export default function SessionReplayPage({ params }: { params: Promise<{ id: st
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{visibleMessages.map((m) => (
|
{visibleMessages.map((m) => (
|
||||||
<MessageBubble key={m.id} message={m} toolResults={toolResults} verbosity={verbosity} />
|
<MessageBubble key={m.id} message={m} toolResults={toolResults} verbosity={verbosity} showTimestamp={verbosity === "full"} />
|
||||||
))}
|
))}
|
||||||
{visibleMessages.length === 0 && !sending && (
|
{visibleMessages.length === 0 && !sending && (
|
||||||
<p className="text-sm py-8 text-center" style={{ color: "var(--text-3)" }}>
|
<p className="text-sm py-8 text-center" style={{ color: "var(--text-3)" }}>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ interface Props {
|
|||||||
message: Message;
|
message: Message;
|
||||||
toolResults: Map<string, { name: string; content: string }>;
|
toolResults: Map<string, { name: string; content: string }>;
|
||||||
verbosity?: Verbosity;
|
verbosity?: Verbosity;
|
||||||
|
showTimestamp?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ReasoningBlock({ text }: { text: string }) {
|
function ReasoningBlock({ text }: { text: string }) {
|
||||||
@@ -72,7 +73,7 @@ function ToolCallBlock({ tc, result, defaultOpen, showResult }: { tc: ToolCall;
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MessageBubble({ message, toolResults, verbosity = "normal" }: Props) {
|
export function MessageBubble({ message, toolResults, verbosity = "normal", showTimestamp = false }: Props) {
|
||||||
const isUser = message.role === "user";
|
const isUser = message.role === "user";
|
||||||
const content = message.content || "";
|
const content = message.content || "";
|
||||||
const reasoning = message.reasoning || "";
|
const reasoning = message.reasoning || "";
|
||||||
@@ -132,6 +133,13 @@ export function MessageBubble({ message, toolResults, verbosity = "normal" }: Pr
|
|||||||
(tool calls only)
|
(tool calls only)
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Timestamp */}
|
||||||
|
{showTimestamp && message.timestamp && (
|
||||||
|
<div className="text-[10px] mt-1" style={{ color: isUser ? "rgba(255,255,255,0.5)" : "var(--text-3)" }}>
|
||||||
|
{new Date(message.timestamp * 1000).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -22,6 +22,11 @@ export function SessionCard({ session }: { session: Session }) {
|
|||||||
<span className="text-[11px]" style={{ color: "var(--text-3)" }}>
|
<span className="text-[11px]" style={{ color: "var(--text-3)" }}>
|
||||||
{session.message_count} msgs
|
{session.message_count} msgs
|
||||||
</span>
|
</span>
|
||||||
|
{session.model && (
|
||||||
|
<span className="text-[11px] font-mono" style={{ color: "var(--text-3)" }}>
|
||||||
|
{session.model.split("/").pop()?.replace("claude-", "").slice(0, 12)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
{tokens > 0 && (
|
{tokens > 0 && (
|
||||||
<span className="text-[11px]" style={{ color: "var(--text-3)" }}>
|
<span className="text-[11px]" style={{ color: "var(--text-3)" }}>
|
||||||
{formatTokens(tokens)}
|
{formatTokens(tokens)}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useHealth, useConfig, useSessions } from "@/lib/hooks";
|
import { useHealth, useConfig, useSessions } from "@/lib/hooks";
|
||||||
|
import { AlertTriangle } from "lucide-react";
|
||||||
|
|
||||||
export function StatusCard() {
|
export function StatusCard() {
|
||||||
const { data: health } = useHealth();
|
const { data: health, isError: healthError } = useHealth();
|
||||||
const { data: config } = useConfig();
|
const { data: config } = useConfig();
|
||||||
const { data: sessions } = useSessions(10);
|
const { data: sessions } = useSessions(10);
|
||||||
|
|
||||||
@@ -11,6 +12,20 @@ export function StatusCard() {
|
|||||||
const model = config?.model || "—";
|
const model = config?.model || "—";
|
||||||
const activeSessions = sessions?.items?.filter((s) => !s.ended_at).length || 0;
|
const activeSessions = sessions?.items?.filter((s) => !s.ended_at).length || 0;
|
||||||
|
|
||||||
|
if (healthError) {
|
||||||
|
return (
|
||||||
|
<div className="card p-4 flex items-center gap-3">
|
||||||
|
<AlertTriangle size={18} style={{ color: "#ff3b30" }} />
|
||||||
|
<div>
|
||||||
|
<div className="text-[13px] font-medium" style={{ color: "#ff3b30" }}>WebAPI Unreachable</div>
|
||||||
|
<div className="text-[11px]" style={{ color: "var(--text-3)" }}>
|
||||||
|
Check that hermes-webapi is running on port 8643
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="card p-4 flex items-center justify-between">
|
<div className="card p-4 flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
Reference in New Issue
Block a user