blob: 845967b4c1ec878191339029c69888566a21345e [file] [log] [blame]
/* eslint-disable @typescript-eslint/no-explicit-any */
/**
* Demo module for sketch-timeline component
*/
import { DemoModule } from "./demo-framework/types";
import { demoUtils } from "./demo-fixtures/index";
import type { AgentMessage } from "../../types";
// Mock messages for demo
function createMockMessage(props: Partial<AgentMessage> = {}): AgentMessage {
return {
idx: props.idx || 0,
type: props.type || "agent",
content: props.content || "Hello world",
timestamp: props.timestamp || "2023-05-15T12:00:00Z",
elapsed: props.elapsed || 1500000000, // 1.5 seconds in nanoseconds
end_of_turn: props.end_of_turn || false,
conversation_id: props.conversation_id || "conv123",
tool_calls: props.tool_calls || [],
commits: props.commits || undefined,
usage: props.usage,
hide_output: props.hide_output || false,
...props,
};
}
function createMockMessages(count: number): AgentMessage[] {
return Array.from({ length: count }, (_, i) =>
createMockMessage({
idx: i,
content: `Message ${i + 1}: This is a sample message to demonstrate the timeline component.`,
type: i % 3 === 0 ? "user" : "agent",
timestamp: new Date(Date.now() - (count - i) * 60000).toISOString(),
tool_calls:
i % 4 === 0
? [
{
name: "bash",
input: `echo "Tool call example ${i}"`,
tool_call_id: `call_${i}`,
args: `{"command": "echo 'Tool call example ${i}'"}`,
result: `Tool call example ${i}`,
},
]
: [],
usage:
i % 5 === 0
? {
input_tokens: 10 + i,
cache_creation_input_tokens: 0,
cache_read_input_tokens: 0,
output_tokens: 50 + i * 2,
cost_usd: 0.001 * (i + 1),
}
: undefined,
}),
);
}
const demo: DemoModule = {
title: "Timeline Demo",
description:
"Interactive timeline component for displaying conversation messages with various states",
imports: ["../sketch-timeline"],
styles: ["/dist/tailwind.css"],
setup: async (container: HTMLElement) => {
// Create demo sections
const basicSection = demoUtils.createDemoSection(
"Basic Timeline",
"Timeline with a few sample messages",
);
const statesSection = demoUtils.createDemoSection(
"Timeline States",
"Different loading and thinking states",
);
const interactiveSection = demoUtils.createDemoSection(
"Interactive Demo",
"Add messages and control timeline behavior",
);
// Basic timeline with sample messages
const basicMessages = createMockMessages(5);
const basicTimeline = document.createElement("sketch-timeline") as any;
basicTimeline.messages = basicMessages;
basicTimeline.style.cssText =
"height: 400px; border: 1px solid #e1e5e9; border-radius: 6px; margin: 10px 0;";
// Create a scroll container for the basic timeline
const basicScrollContainer = document.createElement("div");
basicScrollContainer.style.cssText = "height: 400px; overflow-y: auto;";
basicScrollContainer.appendChild(basicTimeline);
basicTimeline.scrollContainer = { value: basicScrollContainer };
basicSection.appendChild(basicScrollContainer);
// Timeline with loading state
const loadingTimeline = document.createElement("sketch-timeline") as any;
loadingTimeline.messages = [];
loadingTimeline.isLoadingOlderMessages = false;
loadingTimeline.style.cssText =
"height: 200px; border: 1px solid #e1e5e9; border-radius: 6px; margin: 10px 0;";
const loadingWrapper = document.createElement("div");
loadingWrapper.style.cssText = "margin: 15px 0;";
const loadingLabel = document.createElement("h4");
loadingLabel.textContent = "Loading State (No messages)";
loadingLabel.style.cssText =
"margin: 0 0 10px 0; color: #24292f; font-size: 14px; font-weight: 600;";
loadingWrapper.appendChild(loadingLabel);
loadingWrapper.appendChild(loadingTimeline);
statesSection.appendChild(loadingWrapper);
// Timeline with thinking state
const thinkingMessages = createMockMessages(3);
const thinkingTimeline = document.createElement("sketch-timeline") as any;
thinkingTimeline.messages = thinkingMessages;
thinkingTimeline.llmCalls = 2;
thinkingTimeline.toolCalls = ["bash", "patch"];
thinkingTimeline.agentState = "thinking";
thinkingTimeline.style.cssText =
"height: 300px; border: 1px solid #e1e5e9; border-radius: 6px; margin: 10px 0;";
// Set initial load complete for thinking timeline
setTimeout(() => {
(thinkingTimeline as any).isInitialLoadComplete = true;
thinkingTimeline.requestUpdate();
}, 100);
const thinkingWrapper = document.createElement("div");
thinkingWrapper.style.cssText = "margin: 15px 0;";
const thinkingLabel = document.createElement("h4");
thinkingLabel.textContent = "Thinking State (Agent is active)";
thinkingLabel.style.cssText =
"margin: 0 0 10px 0; color: #24292f; font-size: 14px; font-weight: 600;";
const thinkingScrollContainer = document.createElement("div");
thinkingScrollContainer.style.cssText = "height: 300px; overflow-y: auto;";
thinkingScrollContainer.appendChild(thinkingTimeline);
thinkingTimeline.scrollContainer = { value: thinkingScrollContainer };
thinkingWrapper.appendChild(thinkingLabel);
thinkingWrapper.appendChild(thinkingScrollContainer);
statesSection.appendChild(thinkingWrapper);
// Interactive timeline
const interactiveMessages = createMockMessages(8);
const interactiveTimeline = document.createElement(
"sketch-timeline",
) as any;
interactiveTimeline.messages = interactiveMessages;
interactiveTimeline.style.cssText =
"height: 400px; border: 1px solid #e1e5e9; border-radius: 6px; margin: 10px 0;";
// Set initial load complete for interactive timeline
setTimeout(() => {
(interactiveTimeline as any).isInitialLoadComplete = true;
interactiveTimeline.requestUpdate();
}, 100);
const interactiveScrollContainer = document.createElement("div");
interactiveScrollContainer.style.cssText =
"height: 400px; overflow-y: auto;";
interactiveScrollContainer.appendChild(interactiveTimeline);
interactiveTimeline.scrollContainer = { value: interactiveScrollContainer };
// Control buttons for interactive demo
const controlsDiv = document.createElement("div");
controlsDiv.style.cssText =
"margin-top: 20px; display: flex; flex-wrap: wrap; gap: 10px;";
const addMessageButton = demoUtils.createButton("Add User Message", () => {
const newMessage = createMockMessage({
idx: interactiveMessages.length,
content: `New user message added at ${new Date().toLocaleTimeString()}`,
type: "user",
timestamp: new Date().toISOString(),
});
interactiveMessages.push(newMessage);
interactiveTimeline.messages = [...interactiveMessages];
});
const addAgentMessageButton = demoUtils.createButton(
"Add Agent Message",
() => {
const newMessage = createMockMessage({
idx: interactiveMessages.length,
content: `New agent response added at ${new Date().toLocaleTimeString()}`,
type: "agent",
timestamp: new Date().toISOString(),
tool_calls:
Math.random() > 0.5
? [
{
name: "bash",
input: "date",
tool_call_id: `call_${Date.now()}`,
args: '{"command": "date"}',
result: new Date().toString(),
},
]
: [],
});
interactiveMessages.push(newMessage);
interactiveTimeline.messages = [...interactiveMessages];
},
);
const toggleThinkingButton = demoUtils.createButton(
"Toggle Thinking",
() => {
if (
interactiveTimeline.llmCalls > 0 ||
interactiveTimeline.toolCalls.length > 0
) {
interactiveTimeline.llmCalls = 0;
interactiveTimeline.toolCalls = [];
} else {
interactiveTimeline.llmCalls = 1;
interactiveTimeline.toolCalls = ["bash"];
}
},
);
const toggleCompactButton = demoUtils.createButton(
"Toggle Compact Padding",
() => {
interactiveTimeline.compactPadding =
!interactiveTimeline.compactPadding;
},
);
const clearMessagesButton = demoUtils.createButton("Clear Messages", () => {
interactiveMessages.length = 0;
interactiveTimeline.messages = [];
});
const resetDemoButton = demoUtils.createButton("Reset Demo", () => {
interactiveMessages.length = 0;
interactiveMessages.push(...createMockMessages(8));
interactiveTimeline.messages = [...interactiveMessages];
interactiveTimeline.llmCalls = 0;
interactiveTimeline.toolCalls = [];
interactiveTimeline.compactPadding = false;
});
controlsDiv.appendChild(addMessageButton);
controlsDiv.appendChild(addAgentMessageButton);
controlsDiv.appendChild(toggleThinkingButton);
controlsDiv.appendChild(toggleCompactButton);
controlsDiv.appendChild(clearMessagesButton);
controlsDiv.appendChild(resetDemoButton);
const interactiveWrapper = document.createElement("div");
interactiveWrapper.style.cssText =
"padding: 10px; border: 1px solid #e1e5e9; border-radius: 6px; background: white;";
interactiveWrapper.appendChild(interactiveScrollContainer);
interactiveWrapper.appendChild(controlsDiv);
interactiveSection.appendChild(interactiveWrapper);
// Set initial load complete for basic timeline
setTimeout(() => {
(basicTimeline as any).isInitialLoadComplete = true;
basicTimeline.requestUpdate();
}, 100);
// Assemble the demo
container.appendChild(basicSection);
container.appendChild(statesSection);
container.appendChild(interactiveSection);
// Store references for cleanup
(container as any).timelines = [
basicTimeline,
loadingTimeline,
thinkingTimeline,
interactiveTimeline,
];
},
cleanup: async () => {
// Clean up any timers or listeners if needed
const container = document.getElementById("demo-container");
if (container && (container as any).timelines) {
const timelines = (container as any).timelines;
timelines.forEach((timeline: any) => {
// Reset timeline state
timeline.llmCalls = 0;
timeline.toolCalls = [];
timeline.messages = [];
});
delete (container as any).timelines;
}
},
};
export default demo;