blob: f01b19014ca8f1a8f77764836c007f4f37d86031 [file] [log] [blame]
philip.zeyliger26bc6592025-06-30 20:15:30 -07001/* eslint-disable @typescript-eslint/no-explicit-any */
banksean659b9832025-06-27 00:50:41 +00002/**
3 * Demo module for sketch-call-status component
4 */
5
6import { DemoModule } from "./demo-framework/types";
7import {
8 demoUtils,
9 idleCallStatus,
10 workingCallStatus,
11 heavyWorkingCallStatus,
12 disconnectedCallStatus,
13 workingDisconnectedCallStatus,
14} from "./demo-fixtures/index";
15import type { CallStatusState } from "./demo-fixtures/index";
16
17const demo: DemoModule = {
18 title: "Call Status Demo",
19 description:
20 "Display current LLM and tool call status with visual indicators",
21 imports: ["../sketch-call-status"],
22 styles: ["/dist/tailwind.css"],
23
24 setup: async (container: HTMLElement) => {
25 // Create demo sections
26 const statusVariationsSection = demoUtils.createDemoSection(
27 "Status Variations",
28 "Different states of the call status component",
29 );
30
31 const interactiveSection = demoUtils.createDemoSection(
32 "Interactive Demo",
33 "Dynamically change call status to see real-time updates",
34 );
35
36 // Helper function to create status component with state
37 const createStatusComponent = (
38 id: string,
39 state: CallStatusState,
40 label: string,
41 ) => {
42 const wrapper = document.createElement("div");
43 wrapper.style.cssText =
44 "margin: 15px 0; padding: 10px; border: 1px solid #e1e5e9; border-radius: 6px; background: white;";
45
46 const labelEl = document.createElement("h4");
47 labelEl.textContent = label;
48 labelEl.style.cssText =
49 "margin: 0 0 10px 0; color: #24292f; font-size: 14px; font-weight: 600;";
50
51 const statusComponent = document.createElement(
52 "sketch-call-status",
53 ) as any;
54 statusComponent.id = id;
55 statusComponent.llmCalls = state.llmCalls;
56 statusComponent.toolCalls = state.toolCalls;
57 statusComponent.agentState = state.agentState;
58 statusComponent.isIdle = state.isIdle;
59 statusComponent.isDisconnected = state.isDisconnected;
60
61 wrapper.appendChild(labelEl);
62 wrapper.appendChild(statusComponent);
63 return wrapper;
64 };
65
66 // Create status variations
67 const idleStatus = createStatusComponent(
68 "idle-status",
69 idleCallStatus,
70 "Idle State - No active calls",
71 );
72
73 const workingStatus = createStatusComponent(
74 "working-status",
75 workingCallStatus,
76 "Working State - LLM and tool calls active",
77 );
78
79 const heavyWorkingStatus = createStatusComponent(
80 "heavy-working-status",
81 heavyWorkingCallStatus,
82 "Heavy Working State - Multiple calls active",
83 );
84
85 const disconnectedStatus = createStatusComponent(
86 "disconnected-status",
87 disconnectedCallStatus,
88 "Disconnected State - No connection",
89 );
90
91 const workingDisconnectedStatus = createStatusComponent(
92 "working-disconnected-status",
93 workingDisconnectedCallStatus,
94 "Working but Disconnected - Calls active but no connection",
95 );
96
97 // Interactive demo component
98 const interactiveStatus = document.createElement(
99 "sketch-call-status",
100 ) as any;
101 interactiveStatus.id = "interactive-status";
102 interactiveStatus.llmCalls = 0;
103 interactiveStatus.toolCalls = [];
104 interactiveStatus.agentState = null;
105 interactiveStatus.isIdle = true;
106 interactiveStatus.isDisconnected = false;
107
108 // Control buttons for interactive demo
109 const controlsDiv = document.createElement("div");
110 controlsDiv.style.cssText =
111 "margin-top: 20px; display: flex; flex-wrap: wrap; gap: 10px;";
112
113 const addLLMCallButton = demoUtils.createButton("Add LLM Call", () => {
114 interactiveStatus.llmCalls = interactiveStatus.llmCalls + 1;
115 interactiveStatus.isIdle = false;
116 });
117
118 const removeLLMCallButton = demoUtils.createButton(
119 "Remove LLM Call",
120 () => {
121 interactiveStatus.llmCalls = Math.max(
122 0,
123 interactiveStatus.llmCalls - 1,
124 );
125 if (
126 interactiveStatus.llmCalls === 0 &&
127 interactiveStatus.toolCalls.length === 0
128 ) {
129 interactiveStatus.isIdle = true;
130 }
131 },
132 );
133
134 const addToolCallButton = demoUtils.createButton("Add Tool Call", () => {
135 const toolNames = [
136 "bash",
137 "patch",
138 "think",
139 "keyword_search",
140 "browser_navigate",
141 "codereview",
142 ];
143 const randomTool =
144 toolNames[Math.floor(Math.random() * toolNames.length)];
145 const currentTools = Array.isArray(interactiveStatus.toolCalls)
146 ? [...interactiveStatus.toolCalls]
147 : [];
148 if (!currentTools.includes(randomTool)) {
149 currentTools.push(randomTool);
150 interactiveStatus.toolCalls = currentTools;
151 interactiveStatus.isIdle = false;
152 }
153 });
154
155 const removeToolCallButton = demoUtils.createButton(
156 "Remove Tool Call",
157 () => {
158 const currentTools = Array.isArray(interactiveStatus.toolCalls)
159 ? [...interactiveStatus.toolCalls]
160 : [];
161 if (currentTools.length > 0) {
162 currentTools.pop();
163 interactiveStatus.toolCalls = currentTools;
164 if (interactiveStatus.llmCalls === 0 && currentTools.length === 0) {
165 interactiveStatus.isIdle = true;
166 }
167 }
168 },
169 );
170
171 const toggleConnectionButton = demoUtils.createButton(
172 "Toggle Connection",
173 () => {
174 interactiveStatus.isDisconnected = !interactiveStatus.isDisconnected;
175 },
176 );
177
178 const setAgentStateButton = demoUtils.createButton(
179 "Change Agent State",
180 () => {
181 const states = [
182 null,
183 "analyzing code",
184 "refactoring components",
185 "running tests",
186 "reviewing changes",
187 "generating documentation",
188 ];
189 const currentIndex = states.indexOf(interactiveStatus.agentState);
190 const nextIndex = (currentIndex + 1) % states.length;
191 interactiveStatus.agentState = states[nextIndex];
192 },
193 );
194
195 const resetButton = demoUtils.createButton("Reset to Idle", () => {
196 interactiveStatus.llmCalls = 0;
197 interactiveStatus.toolCalls = [];
198 interactiveStatus.agentState = null;
199 interactiveStatus.isIdle = true;
200 interactiveStatus.isDisconnected = false;
201 });
202
203 controlsDiv.appendChild(addLLMCallButton);
204 controlsDiv.appendChild(removeLLMCallButton);
205 controlsDiv.appendChild(addToolCallButton);
206 controlsDiv.appendChild(removeToolCallButton);
207 controlsDiv.appendChild(toggleConnectionButton);
208 controlsDiv.appendChild(setAgentStateButton);
209 controlsDiv.appendChild(resetButton);
210
211 // Assemble the demo
212 statusVariationsSection.appendChild(idleStatus);
213 statusVariationsSection.appendChild(workingStatus);
214 statusVariationsSection.appendChild(heavyWorkingStatus);
215 statusVariationsSection.appendChild(disconnectedStatus);
216 statusVariationsSection.appendChild(workingDisconnectedStatus);
217
218 const interactiveWrapper = document.createElement("div");
219 interactiveWrapper.style.cssText =
220 "padding: 10px; border: 1px solid #e1e5e9; border-radius: 6px; background: white;";
221 interactiveWrapper.appendChild(interactiveStatus);
222 interactiveWrapper.appendChild(controlsDiv);
223 interactiveSection.appendChild(interactiveWrapper);
224
225 container.appendChild(statusVariationsSection);
226 container.appendChild(interactiveSection);
227
228 // Add some simulation of real activity
229 const simulationInterval = setInterval(() => {
230 const statusComponents = [
231 document.getElementById("working-status") as any,
232 document.getElementById("heavy-working-status") as any,
233 ].filter(Boolean);
234
235 statusComponents.forEach((statusEl) => {
236 if (statusEl && Math.random() > 0.8) {
237 // 20% chance to update
238 // Simulate some activity by slightly changing the number of calls
239 const variation = Math.floor(Math.random() * 3) - 1; // -1, 0, or 1
240 statusEl.llmCalls = Math.max(0, statusEl.llmCalls + variation);
241 }
242 });
243 }, 2000);
244
245 // Store interval for cleanup
246 (container as any).demoInterval = simulationInterval;
247 },
248
249 cleanup: async () => {
250 // Clear any intervals
251 const container = document.getElementById("demo-container");
252 if (container && (container as any).demoInterval) {
253 clearInterval((container as any).demoInterval);
254 delete (container as any).demoInterval;
255 }
256 },
257};
258
259export default demo;