blob: b535fa1ac9279c954be5412bbbc3aa86a8034407 [file] [log] [blame]
<html>
<head>
<title>sketch-timeline demo</title>
<link rel="stylesheet" href="demo.css" />
<script type="module" src="../sketch-timeline.ts"></script>
<script>
const messages = [
{
type: "agent",
end_of_turn: false,
content:
"Now I'll create an empty commit with a very long commit message:",
tool_calls: [
{
name: "bash",
input:
'{"command":"git commit --allow-empty -m \\"chore: create empty commit with very long message\\\\n\\\\nThis is an extremely long commit message to demonstrate how Git handles verbose commit messages.\\\\nThis empty commit has no actual code changes, but contains a lengthy explanation.\\\\n\\\\nThe empty commit pattern can be useful in several scenarios:\\\\n1. Triggering CI/CD pipelines without modifying code\\\\n2. Marking significant project milestones or releases\\\\n3. Creating annotated reference points in the commit history\\\\n4. Documenting important project decisions\\\\n\\\\nEmpty commits are created using the --allow-empty flag, which instructs Git to \\\\ncreate a commit even when there are no changes staged for commit. This bypasses\\\\nGit\'s normal behavior of refusing to record a commit that has the exact same\\\\ntree as its parent.\\\\n\\\\nSome technical details about empty commits:\\\\n- They still receive a unique commit hash\\\\n- They appear in the git log like any other commit\\\\n- They can be referenced by other git commands\\\\n- They can be included in merges, rebases, and other git operations\\\\n- They take up minimal space in the repository\\\\n\\\\nThis commit message continues to be extremely verbose just to demonstrate how\\\\nGit handles very long commit messages and how they appear in various Git interfaces.\\\\nThe content of this message is not particularly meaningful but serves to\\\\ndemonstrate the ability to include detailed context when necessary.\\\\n\\\\nMore lines of explanation follow to make this commit message truly excessive...\\\\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ultrices ligula\\\\nnon tellus tincidunt, in volutpat nisi venenatis. Phasellus convallis felis nec\\\\ndiam dignissim, vel fringilla odio ultricies. Morbi feugiat velit in nulla\\\\nconsequat, eget facilisis dui vehicula. Donec fermentum nisl vel justo ultricies,\\\\nut semper libero ultrices. \\\\n\\\\nCras sagittis libero vitae diam eleifend, vel viverra eros tempus.\\\\nSuspendisse potenti. Nullam ac pede. Curabitur blandit hendrerit nibh.\\\\nDonec quis augue ut diam lobortis venenatis. Quisque dapibus justo eget neque.\\\\nInteger sit amet ligula vitae arcu interdum ultrices. Nullam ornare, magna sed\\\\nvenenatis tincidunt, libero urna ullamcorper tortor, ac ultrices neque sem ut massa.\\" --trailer \'Co-Authored-By: sketch <hello@sketch.dev>\' --trailer \'Change-ID: s$(openssl rand -hex 8)k\'"}',
tool_call_id: "toolu_01X67pzGzW2NtTjZnxoXTMc7",
args: '{"command":"git commit --allow-empty -m \\"chore: create empty commit with very long message\\\\n\\\\nThis is an extremely long commit message to demonstrate how Git handles verbose commit messages..."}',
result:
"[detached HEAD abc1234] chore: create empty commit with very long message\n 1 file changed, 1 insertion(+), 1 deletion(-)",
},
],
timestamp: "2025-05-11T21:44:48.760674089Z",
conversation_id: "3qc-ptm3",
usage: {
input_tokens: 6,
cache_creation_input_tokens: 77,
cache_read_input_tokens: 4230,
output_tokens: 668,
cost_usd: 0.01159575,
},
start_time: "2025-05-11T21:44:35.577868468Z",
end_time: "2025-05-11T21:44:48.760670506Z",
elapsed: 13182802037,
idx: 8,
},
{
type: "user",
content: "a user message",
timestamp: "2025-04-14T16:39:30.639533919Z",
conversation_id: "conv-123456",
idx: 0,
},
{
type: "agent",
content: "an agent message with usage information",
timestamp: "2025-04-14T16:39:31.639533919Z",
conversation_id: "conv-123456",
idx: 1,
usage: {
input_tokens: 4,
cache_creation_input_tokens: 2620,
cache_read_input_tokens: 0,
output_tokens: 106,
cost_usd: 0.011427,
},
},
{
type: "agent",
content: "an agent message with a single tool call",
timestamp: "2025-04-14T16:39:32.639533919Z",
conversation_id: "conv-123456",
idx: 2,
tool_calls: [
{
name: "bash",
input: 'find . -type f -name "*.go" | wc -l',
tool_call_id: "call_12345",
args: '{"command": "find . -type f -name \\"*.go\\" | wc -l"}',
result: "486",
},
],
},
{
type: "agent",
content:
"an agent message with a bash command that is extremely long and would create a horizontal scrollbar",
timestamp: "2025-04-14T16:39:32.739533919Z",
conversation_id: "conv-123456",
idx: 2.5,
tool_calls: [
{
name: "bash",
input:
'find /app -type f -name "*.ts" -o -name "*.js" -o -name "*.tsx" -o -name "*.jsx" | xargs grep -l "useState" | while read file; do echo "File: $file"; grep -n "useState" $file | head -5; echo; done | head -50',
tool_call_id: "call_verylongbash",
args: '{"command": "find /app -type f -name \\"*.ts\\" -o -name \\"*.js\\" -o -name \\"*.tsx\\" -o -name \\"*.jsx\\" | xargs grep -l \\"useState\\" | while read file; do echo \\"File: $file\\"; grep -n \\"useState\\" $file | head -5; echo; done | head -50"}',
result:
'File: /app/webui/src/web-components/sketch-chat-input.ts\n97: useState,\n\nFile: /app/webui/src/web-components/sketch-diff-view.ts\n47:import { createRef, ref, useState } from "lit/directives/ref.js";\n110: const [selectedFiles, setSelectedFiles] = useState([]);\n',
},
],
},
{
type: "agent",
content:
"an agent message with a bash command that has a very long output that would create a horizontal scrollbar",
timestamp: "2025-04-14T16:39:32.839533919Z",
conversation_id: "conv-123456",
idx: 2.7,
tool_calls: [
{
name: "bash",
input: "cat /app/webui/package.json | grep -A 5 dependencies",
tool_call_id: "call_longoutput",
args: '{"command": "cat /app/webui/package.json | grep -A 5 dependencies"}',
result:
' "dependencies": {\n "@xterm/addon-fit": "^0.10.0",\n "@xterm/xterm": "^5.5.0",\n "diff2html": "3.4.51",\n "lit": "^3.2.1",\n "marked": "^15.0.7",\n "mermaid": "^11.6.0",\n "sanitize-html": "^2.15.0",\n "vega": "^5.33.0",\n "vega-embed": "^6.29.0",\n "vega-lite": "^5.23.0",\n "react": "^18.2.0",\n "react-dom": "^18.2.0",\n "styled-components": "^6.1.8",\n "tailwindcss": "^3.4.1",\n "typescript": "^5.3.3",\n "zod": "^3.22.4",\n "@types/react": "^18.2.55",\n "@types/react-dom": "^18.2.19",\n "eslint": "^8.56.0",\n "prettier": "^3.2.5"\n },',
},
],
},
{
type: "agent",
content:
"an agent message with two tool calls that will show how the width behaves with very long content that should push the boundaries of the UI layout with really wide tool calls that might stretch beyond the regular message content width",
timestamp: "2025-04-14T16:39:33.639533919Z",
conversation_id: "conv-123456",
idx: 3,
tool_calls: [
{
name: "keyword_search",
input: "Search for files related to the timeline component",
tool_call_id: "call_67890",
args: '{"query": "Find all files related to the timeline component in the project", "search_terms": ["timeline", "message", "component", "web-components"]}',
result:
"Found 3 files: sketch-timeline.ts, sketch-timeline-message.ts, sketch-timeline.demo.html",
},
{
name: "patch",
input: "Update the timeline component CSS",
tool_call_id: "call_abcdef",
args: '{"path": "/app/webui/src/web-components/sketch-timeline.ts", "patches": [{"operation": "replace", "oldText": "width: 100%;", "newText": "width: auto; max-width: 100%;"}, {"operation": "replace", "oldText": "margin-bottom: 20px;", "newText": "margin-bottom: 24px;"}]}',
result: "Applied all patches successfully",
},
],
},
{
type: "user",
content: "another user message",
timestamp: "2025-04-14T16:39:34.639533919Z",
conversation_id: "conv-123456",
idx: 4,
},
{
type: "agent",
content: "an agent message with detailed information and usage data",
timestamp: "2025-04-14T16:39:35.639533919Z",
conversation_id: "conv-123456",
idx: 5,
usage: {
input_tokens: 125,
cache_creation_input_tokens: 0,
cache_read_input_tokens: 3050,
output_tokens: 245,
cost_usd: 0.023456,
},
},
{
type: "tool",
content: "a tool use message",
timestamp: "2025-04-14T16:39:36.639533919Z",
conversation_id: "conv-123456",
idx: 6,
},
{
type: "commit",
end_of_turn: false,
content: "",
commits: [
{
hash: "ece101c103ec231da87f4df05c1b5e6a24e13add",
subject: "Add README.md for web components directory",
body: "This adds documentation for the web components used in the Loop UI,\nincluding a description of each component, usage examples, and\ndevelopment guidelines.\n\nCo-Authored-By: sketch\nadd README.md for webui/src/web-components",
pushed_branch:
"sketch/create-readmemd-for-web-components-directory",
},
],
timestamp: "2025-04-14T16:39:37.639533919Z",
conversation_id: "conv-123456",
idx: 7,
},
{
type: "agent",
content: "an end-of-turn agent message",
end_of_turn: true,
timestamp: "2025-04-14T16:39:38.639533919Z",
conversation_id: "conv-123456",
idx: 8,
usage: {
input_tokens: 85,
cache_creation_input_tokens: 1240,
cache_read_input_tokens: 750,
output_tokens: 178,
cost_usd: 0.018976,
},
},
];
document.addEventListener("DOMContentLoaded", () => {
const appShell = document.querySelector(".app-shell");
const timelineEl = document.querySelector("sketch-timeline");
timelineEl.messages = messages;
timelineEl.scrollContainer = appShell;
const addMessagesCheckbox = document.querySelector("#addMessages");
addMessagesCheckbox.addEventListener("change", toggleAddMessages);
let addingMessages = false;
const addNewMessagesInterval = 1000;
function addNewMessages() {
if (!addingMessages) {
return;
}
const n = new Date().getMilliseconds() % messages.length;
const msgToDup = messages[n];
const dup = JSON.parse(JSON.stringify(msgToDup));
dup.idx = messages.length;
dup.timestamp = new Date().toISOString();
messages.push(dup);
timelineEl.messages = messages.concat();
timelineEl.prop;
timelineEl.requestUpdate();
}
let addMessagesHandler = setInterval(
addNewMessages,
addNewMessagesInterval,
);
function toggleAddMessages() {
addingMessages = !addingMessages;
if (addingMessages) {
} else {
}
}
});
</script>
<style>
/* Fix for bash command overflow */
sketch-timeline-message::part(message-content),
sketch-tool-calls::part(tool-call-card),
sketch-tool-card::part(summary) {
max-width: 100% !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
white-space: nowrap !important;
}
.app-shell {
display: block;
font-family:
system-ui,
-apple-system,
BlinkMacSystemFont,
"Segoe UI",
Roboto,
sans-serif;
color: rgb(51, 51, 51);
line-height: 1.4;
min-height: 100vh;
width: 100%;
position: relative;
overflow-x: hidden;
}
.app-header {
flex-grow: 0;
}
.view-container {
flex-grow: 2;
}
</style>
</head>
<body>
<div class="app-shell">
<div class="app-header">
<h1>sketch-timeline demo</h1>
<input
type="checkbox"
id="addMessages"
title="Automatically add new messages"
/><label for="addMessages">Automatically add new messages</label>
</div>
<div class="view-container">
<div class="chat-view view-active">
<sketch-timeline></sketch-timeline>
</div>
</div>
</div>
</body>
</html>