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