diff --git a/examples/kitchen-sink/frontend/App.tsx b/examples/kitchen-sink/frontend/App.tsx index 171276ba5e..bd8cee5e0f 100644 --- a/examples/kitchen-sink/frontend/App.tsx +++ b/examples/kitchen-sink/frontend/App.tsx @@ -5,6 +5,7 @@ import { Highlight, themes } from "prism-react-renderer"; import { Code, Compass, + Clipboard, Database, FlaskConical, GitBranch, @@ -1095,6 +1096,7 @@ function MockAgenticLoopPanel({ page }: { page: PageConfig }) { validationErrors: 0, }); const [logs, setLogs] = useState([]); + const [eventLogCopied, setEventLogCopied] = useState(false); const handleRef = useRef(null); const socketRef = useRef(null); @@ -1102,6 +1104,7 @@ function MockAgenticLoopPanel({ page }: { page: PageConfig }) { const activeRequestRef = useRef(null); const reconnectTimerRef = useRef | null>(null); const progressTimerRef = useRef | null>(null); + const copyResetTimerRef = useRef | null>(null); const reconnectStartedAtRef = useRef(null); const mainSocketCleanupRef = useRef<(() => void) | null>(null); const closedByUserRef = useRef(false); @@ -1121,6 +1124,21 @@ function MockAgenticLoopPanel({ page }: { page: PageConfig }) { [], ); + const copyEventLog = useCallback(async () => { + if (logs.length === 0) return; + + const text = logs + .map((entry) => `${entry.time}\t${entry.level}\t${entry.message}`) + .join("\n"); + await navigator.clipboard.writeText(text); + setEventLogCopied(true); + if (copyResetTimerRef.current) clearTimeout(copyResetTimerRef.current); + copyResetTimerRef.current = setTimeout(() => { + setEventLogCopied(false); + copyResetTimerRef.current = null; + }, 1500); + }, [logs]); + const clearProgressTimer = useCallback(() => { if (progressTimerRef.current) { clearTimeout(progressTimerRef.current); @@ -1642,6 +1660,7 @@ function MockAgenticLoopPanel({ page }: { page: PageConfig }) { useEffect(() => { return () => { if (reconnectTimerRef.current) clearTimeout(reconnectTimerRef.current); + if (copyResetTimerRef.current) clearTimeout(copyResetTimerRef.current); clearProgressTimer(); mainSocketCleanupRef.current?.(); mainSocketCleanupRef.current = null; @@ -1811,9 +1830,22 @@ function MockAgenticLoopPanel({ page }: { page: PageConfig }) {

Event Log

- +
+ + +
{logs.length === 0 ? ( diff --git a/examples/kitchen-sink/index.html b/examples/kitchen-sink/index.html index f14c3cc97e..9ec364272b 100644 --- a/examples/kitchen-sink/index.html +++ b/examples/kitchen-sink/index.html @@ -746,6 +746,18 @@ gap: 12px; } + .agentic-header-actions { + display: flex; + gap: 8px; + } + + button.icon-button { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 9px 12px; + } + .agentic-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));