PageSourceSearch

https://liquidai-lfm2-5-8b-a1b.hf.space/

html liquidai-lfm2-5-8b-a1b.hf.space collected 2026-10-03 10:19:06 UTC 90,341 bytes, 2,449 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="UTF-8">
5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6    <title>Liquid AI LFM 2.5 - Supercharged Edge Assistant</title>
7    <!-- Premium Fonts -->
8    <link rel="preconnect" href="https://fonts.googleapis.com">
9    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10    <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Outfit:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
11    <!-- FontAwesome Icons -->
12    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
13    <!-- Prism.js Tomorrow Theme for premium code highlighting -->
14    <link href="https://cdn.jsdelivr.net/npm/[email protected]/themes/prism-tomorrow.min.css" rel="stylesheet" />
15    
16    <style>
17        :root {
18            --bg-primary: #faf9f6;       /* Clean warm off-white */
19            --bg-secondary: #ffffff;     /* Pure white for panels, cards */
20            --bg-tertiary: #f4f3f0;      /* Soft warm grey for boundaries / active items */
21            --text-primary: #000000;     /* True corporate black */
22            --text-secondary: #636366;   /* Subtle warm medium grey */
23            --glass-bg: #ffffff;
24            --glass-border: #e2e1df;     /* Clean warm borders */
25            --glass-border-hover: #000000;
26            --radius-lg: 20px;           /* Modern card rounding */
27            --radius-md: 14px;
28            --radius-sm: 10px;
29            --accent-teal: #10b981;      /* Crisp mint green for success/connected state */
30        }
31
32        * {
33            margin: 0;
34            padding: 0;
35            box-sizing: border-box;
36            font-family: 'Outfit', sans-serif;
37            scroll-behavior: smooth;
38        }
39
40        body {
41            background-color: var(--bg-primary);
42            color: var(--text-primary);
43            overflow: hidden;
44            height: 100vh;
45            display: flex;
46        }
47
48        /* --- Scrollbar styling --- */
49        ::-webkit-scrollbar {
50            width: 6px;
51            height: 6px;
52        }
53        ::-webkit-scrollbar-track {
54            background: rgba(0, 0, 0, 0.01);
55        }
56        ::-webkit-scrollbar-thumb {
57            background: rgba(0, 0, 0, 0.1);
58            border-radius: 10px;
59        }
60        ::-webkit-scrollbar-thumb:hover {
61            background: #000000;
62        }
63
64        /* --- Main Layout --- */
65        .app-container {
66            display: flex;
67            width: 100%;
68            height: 100vh;
69            position: relative;
70        }
71
72        /* --- Sidebar Panel --- */
73        aside {
74            width: 320px;
75            background-color: var(--bg-secondary);
76            border-right: 1px solid var(--glass-border);
77            display: flex;
78            flex-direction: column;
79            height: 100%;
80            z-index: 10;
81            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
82        }
83
84        .sidebar-header {
85            padding: 20px 24px;
86            border-bottom: 1px solid var(--glass-border);
87            display: flex;
88            align-items: center;
89            justify-content: space-between;
90        }
91
92        .brand {
93            display: flex;
94            align-items: center;
95            gap: 8px;
96        }
97
98        .new-chat-btn {
99            background: #000000;
100            border: none;
101            border-radius: 9999px;
102            color: #ffffff;
103            padding: 12px 24px;
104            margin: 16px 24px 8px;
105            cursor: pointer;
106            display: flex;
107            align-items: center;
108            justify-content: center;
109            gap: 10px;
110            font-weight: 600;
111            font-size: 14px;
112            transition: all 0.2s ease;
113        }
114
115        .new-chat-btn:hover {
116            background: #222222;
117            transform: translateY(-1px);
118            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
119        }
120
121        /* --- Settings Panel --- */
122        .sidebar-sections {
123            flex: 1;
124            overflow-y: auto;
125            padding: 8px 24px 24px;
126            display: flex;
127            flex-direction: column;
128            gap: 20px;
129        }
130
131        .section-title {
132            font-size: 11px;
133            font-weight: 700;
134            text-transform: uppercase;
135            letter-spacing: 1.5px;
136            color: var(--text-secondary);
137            margin-bottom: 8px;
138            display: flex;
139            align-items: center;
140            gap: 8px;
141        }
142
143        .sidebar-card {
144            background: var(--bg-secondary);
145            border: 1px solid var(--glass-border);
146            border-radius: var(--radius-md);
147            padding: 16px;
148            display: flex;
149            flex-direction: column;
150            gap: 14px;
151        }
152
153        .setting-group {
154            display: flex;
155            flex-direction: column;
156            gap: 6px;
157        }
158
159        .setting-label {
160            font-size: 12px;
161            font-weight: 600;
162            color: var(--text-secondary);
163            display: flex;
164            justify-content: space-between;
165        }
166
167        .setting-val {
168            color: #000000;
169            font-weight: 700;
170            font-family: 'JetBrains Mono', monospace;
171        }
172
173        .setting-slider {
174            -webkit-appearance: none;
175            width: 100%;
176            height: 4px;
177            border-radius: 5px;
178            background: var(--bg-tertiary);
179            outline: none;
180            cursor: pointer;
181        }
182
183        .setting-slider::-webkit-slider-thumb {
184            -webkit-appearance: none;
185            appearance: none;
186            width: 14px;
187            height: 14px;
188            border-radius: 50%;
189            background: #000000;
190            transition: transform 0.1s ease;
191        }
192
193        .setting-slider::-webkit-slider-thumb:hover {
194            transform: scale(1.25);
195        }
196
197        .form-select {
198            width: 100%;
199            background-color: var(--bg-tertiary);
200            border: 1px solid var(--glass-border);
201            border-radius: var(--radius-sm);
202            color: var(--text-primary);
203            padding: 8px 12px;
204            outline: none;
205            font-size: 13.5px;
206            cursor: pointer;
207            transition: border-color 0.2s ease;
208        }
209
210        .form-select:focus {
211            border-color: #000000;
212        }
213
214        .form-textarea {
215            width: 100%;
216            background-color: var(--bg-tertiary);
217            border: 1px solid var(--glass-border);
218            border-radius: var(--radius-sm);
219            color: var(--text-primary);
220            padding: 10px;
221            outline: none;
222            font-size: 13px;
223            resize: none;
224            height: 80px;
225            line-height: 1.4;
226            transition: border-color 0.2s ease;
227        }
228
229        .form-textarea:focus {
230            border-color: #000000;
231        }
232
233        /* --- Chat History List --- */
234        .chat-list {
235            display: flex;
236            flex-direction: column;
237            gap: 6px;
238            max-height: 160px;
239            overflow-y: auto;
240            padding-right: 4px;
241        }
242
243        .chat-item {
244            display: flex;
245            align-items: center;
246            justify-content: space-between;
247            padding: 8px 12px;
248            border-radius: var(--radius-sm);
249            cursor: pointer;
250            background: transparent;
251            transition: all 0.2s ease;
252            font-size: 13.5px;
253            border: 1px solid transparent;
254            color: var(--text-secondary);
255        }
256
257        .chat-item:hover {
258            background: var(--bg-tertiary);
259            color: var(--text-primary);
260        }
261
262        .chat-item.active {
263            background: var(--bg-tertiary);
264            border-color: var(--glass-border);
265            color: #000000;
266            font-weight: 600;
267        }
268
269        .chat-item-title {
270            white-space: nowrap;
271            overflow: hidden;
272            text-overflow: ellipsis;
273            max-width: 200px;
274            pointer-events: none;
275        }
276
277        .delete-chat-btn {
278            background: none;
279            border: none;
280            color: #c1c1c4;
281            cursor: pointer;
282            transition: color 0.2s ease;
283        }
284
285        .delete-chat-btn:hover {
286            color: #ef4444;
287        }
288
289        /* --- Main Content Panel --- */
290        main {
291            flex: 1;
292            display: flex;
293            flex-direction: column;
294            height: 100%;
295            position: relative;
296        }
297
298        /* --- Header Navigation & Tabs --- */
299        .main-header {
300            height: 72px;
301            background: #ffffff;
302            border-bottom: 1px solid var(--glass-border);
303            display: flex;
304            align-items: center;
305            justify-content: space-between;
306            padding: 0 32px;
307            z-index: 9;
308        }
309
310        .hamburger {
311            display: none;
312            cursor: pointer;
313            font-size: 20px;
314            color: var(--text-secondary);
315            transition: color 0.2s ease;
316        }
317
318        .hamburger:hover {
319            color: var(--text-primary);
320        }
321
322        /* Top header brand elements */
323        .header-brand-section {
324            display: flex;
325            align-items: center;
326            gap: 16px;
327        }
328
329        .header-nav-links {
330            display: flex;
331            gap: 28px;
332            align-items: center;
333        }
334
335        .header-nav-links a {
336            color: var(--text-primary);
337            text-decoration: none;
338            font-size: 12px;
339            font-weight: 600;
340            letter-spacing: 0.8px;
341            opacity: 0.65;
342            transition: opacity 0.2s ease;
343            text-transform: uppercase;
344        }
345
346        .header-nav-links a:hover {
347            opacity: 1;
348        }
349
350        .nav-tabs {
351            display: flex;
352            gap: 4px;
353            background: var(--bg-tertiary);
354            padding: 4px;
355            border-radius: 9999px;
356            border: 1px solid var(--glass-border);
357        }
358
359        .tab-btn {
360            background: transparent;
361            border: none;
362            color: var(--text-secondary);
363            font-weight: 600;
364            font-size: 13px;
365            padding: 6px 14px;
366            border-radius: 9999px;
367            cursor: pointer;
368            display: flex;
369            align-items: center;
370            gap: 6px;
371            transition: all 0.2s ease;
372        }
373
374        .tab-btn.active {
375            background: #000000;
376            color: #ffffff;
377            box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
378        }
379
380        .tab-btn:hover:not(.active) {
381            color: var(--text-primary);
382            background: rgba(0, 0, 0, 0.03);
383        }
384
385        .status-container {
386            display: flex;
387            align-items: center;
388            gap: 8px;
389            font-size: 12px;
390            font-weight: 500;
391            color: var(--text-secondary);
392        }
393
394        .status-dot {
395            width: 7px;
396            height: 7px;
397            border-radius: 50%;
398            background-color: #10b981;
399            position: relative;
400        }
401
402        .status-dot::after {
403            content: '';
404            position: absolute;
405            width: 100%;
406            height: 100%;
407            border-radius: 50%;
408            background: inherit;
409            animation: ping 1.5s infinite;
410        }
411
412        /* --- Tab View Panels --- */
413        .tab-panel {
414            display: none;
415            flex: 1;
416            flex-direction: column;
417            overflow: hidden;
418            position: relative;
419        }
420
421        .tab-panel.active {
422            display: flex;
423        }
424
425        /* --- Chat Assistant View --- */
426        .chat-history-scroll {
427            flex: 1;
428            overflow-y: auto;
429            padding: 32px 32px 100px;
430            display: flex;
431            flex-direction: column;
432            gap: 24px;
433        }
434
435        /* Centered minimal welcome view */
436        .welcome-view {
437            max-width: 600px;
438            width: 100%;
439            margin: auto;
440            display: flex;
441            flex-direction: column;
442            align-items: center;
443            justify-content: center;
444            gap: 16px;
445            padding: 80px 24px 120px;
446            text-align: center;
447            animation: slide-up 0.4s cubic-bezier(0.4, 0, 0.2, 1);
448        }
449
450        .welcome-main-title {
451            font-size: 32px;
452            font-weight: 700;
453            color: #000000;
454            letter-spacing: -0.8px;
455        }
456
457        .welcome-main-subtitle {
458            font-size: 14px;
459            line-height: 1.5;
460            color: var(--text-secondary);
461            max-width: 440px;
462            margin-bottom: 8px;
463        }
464
465        .starters-minimal {
466            display: flex;
467            flex-wrap: wrap;
468            gap: 8px;
469            justify-content: center;
470            width: 100%;
471        }
472
473        .starter-pill {
474            background: #ffffff;
475            border: 1px solid #e2e1df;
476            padding: 8px 16px;
477            border-radius: 9999px;
478            font-size: 13px;
479            font-weight: 500;
480            color: var(--text-primary);
481            cursor: pointer;
482            transition: all 0.2s ease;
483        }
484
485        .starter-pill:hover {
486            background: #000000;
487            color: #ffffff;
488            border-color: #000000;
489            transform: translateY(-1px);
490        }
491
492        /* --- Chat Bubbles --- */
493        .message-row {
494            display: flex;
495            width: 100%;
496            animation: slide-up 0.3s cubic-bezier(0.4, 0, 0.2, 1);
497        }
498
499        .message-row.user-row {
500            justify-content: flex-end;
501        }
502
503        .message-bubble {
504            max-width: 80%;
505            padding: 16px 20px;
506            border-radius: var(--radius-lg);
507            position: relative;
508            line-height: 1.6;
509            font-size: 15px;
510        }
511
512        .user-row .message-bubble {
513            background: #f4f3f0;
514            border: 1px solid #dcdad7;
515            border-bottom-right-radius: 4px;
516            color: var(--text-primary);
517        }
518
519        .assistant-row .message-bubble {
520            background: #ffffff;
521            border: 1px solid var(--glass-border);
522            border-bottom-left-radius: 4px;
523            color: var(--text-primary);
524            display: flex;
525            flex-direction: column;
526            gap: 12px;
527            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.02);
528        }
529
530        /* --- Collapsible Thinking Accordion --- */
531        .thinking-accordion {
532            background: #faf9f6;
533            border: 1px solid #e2e1df;
534            border-radius: var(--radius-md);
535            overflow: hidden;
536            transition: all 0.3s ease;
537            border-left: 3px solid #000000;
538        }
539
540        .thinking-header {
541            padding: 12px 16px;
542            display: flex;
543            align-items: center;
544            justify-content: space-between;
545            cursor: pointer;
546            user-select: none;
547            font-size: 13px;
548            font-weight: 600;
549            color: #000000;
550            transition: background-color 0.2s ease;
551        }
552
553        .thinking-header:hover {
554            background-color: var(--bg-tertiary);
555        }
556
557        .thinking-status {
558            display: flex;
559            align-items: center;
560            gap: 8px;
561        }
562
563        .thinking-status i.spinner-icon {
564            animation: spin 1.5s linear infinite;
565        }
566
567        .thinking-status i.check-icon {
568            color: #10b981;
569        }
570
571        .thinking-body {
572            padding: 16px;
573            font-size: 13px;
574            color: var(--text-secondary);
575            border-top: 1px solid #e2e1df;
576            line-height: 1.6;
577            background: #ffffff;
578            white-space: pre-wrap;
579            font-family: 'JetBrains Mono', monospace;
580        }
581
582        .thinking-accordion.collapsed .thinking-body {
583            display: none;
584        }
585
586        .chevron-icon {
587            transition: transform 0.2s ease;
588        }
589
590        .thinking-accordion.collapsed .chevron-icon {
591            transform: rotate(-90deg);
592        }
593
594        /* --- Text Output Styling (Markdown) --- */
595        .message-content {
596            word-break: break-word;
597        }
598
599        .message-content p {
600            margin-bottom: 12px;
601        }
602
603        .message-content p:last-child {
604            margin-bottom: 0;
605        }
606
607        .message-content strong {
608            color: #000000;
609            font-weight: 600;
610        }
611
612        .message-content ul, .message-content ol {
613            margin-left: 20px;
614            margin-bottom: 12px;
615        }
616
617        .message-content li {
618            margin-bottom: 4px;
619        }
620
621        .message-content code {
622            font-family: 'JetBrains Mono', monospace;
623            background-color: var(--bg-tertiary);
624            padding: 3px 6px;
625            border-radius: var(--radius-sm);
626            font-size: 13px;
627            color: #a11; /* warm burgundy classic light theme style */
628            border: 1px solid #e2e1df;
629        }
630
631        /* --- Code Block Wrapper --- */
632        .code-block-wrapper {
633            position: relative;
634            margin: 16px 0;
635            border-radius: var(--radius-md);
636            overflow: hidden;
637            border: 1px solid #e2e1df;
638            background-color: #1c1b18; /* Premium warm charcoal */
639        }
640
641        .code-block-header {
642            display: flex;
643            justify-content: space-between;
644            align-items: center;
645            background-color: #151412;
646            padding: 10px 16px;
647            border-bottom: 1px solid rgba(255, 255, 255, 0.04);
648            font-size: 11.5px;
649            color: #a3a3a3;
650        }
651
652        .code-block-lang {
653            text-transform: uppercase;
654            font-family: 'JetBrains Mono', monospace;
655            font-weight: 700;
656            color: #faf9f6;
657        }
658
659        .copy-code-btn {
660            background: none;
661            border: none;
662            color: #a3a3a3;
663            cursor: pointer;
664            transition: color 0.2s ease;
665            display: flex;
666            align-items: center;
667            gap: 6px;
668            font-siz
668e: 11.5px;
669        }
670
671        .copy-code-btn:hover {
672            color: #ffffff;
673        }
674
675        .message-content pre {
676            margin: 0 !important;
677            padding: 16px !important;
678            background-color: transparent !important;
679            overflow-x: auto;
680        }
681
682        .message-content pre code {
683            font-size: 13px;
684            background: none;
685            border: none;
686            padding: 0;
687            color: #f5f5f7;
688            font-family: 'JetBrains Mono', monospace;
689        }
690
691        .message-content blockquote {
692            border-left: 3px solid #000000;
693            padding-left: 16px;
694            margin: 16px 0;
695            color: var(--text-secondary);
696            font-style: italic;
697        }
698
699        .message-content table {
700            width: 100%;
701            border-collapse: collapse;
702            margin: 16px 0;
703            font-size: 14px;
704        }
705
706        .message-content th, .message-content td {
707            border: 1px solid var(--glass-border);
708            padding: 10px 12px;
709            text-align: left;
710        }
711
712        .message-content th {
713            background-color: var(--bg-tertiary);
714            color: #000000;
715            font-weight: 600;
716        }
717
718        .message-content tr:nth-child(even) {
719            background-color: rgba(0, 0, 0, 0.01);
720        }
721
722        /* --- Footer Input Bar --- */
723        .footer-input-bar {
724            position: absolute;
725            bottom: 0;
726            left: 0;
727            width: 100%;
728            padding: 24px 32px 32px;
729            background: linear-gradient(to top, var(--bg-primary) 70%, transparent);
730            pointer-events: none;
731        }
732
733        .input-wrapper {
734            max-width: 800px;
735            margin: auto;
736            background: #ffffff;
737            border: 1px solid #dcdad7;
738            border-radius: var(--radius-lg);
739            padding: 8px 14px;
740            display: flex;
741            align-items: center;
742            gap: 12px;
743            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.04);
744            pointer-events: auto;
745            transition: border-color 0.25s ease, box-shadow 0.25s ease;
746        }
747
748        .input-wrapper:focus-within {
749            border-color: #000000;
750            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.06), 0 0 0 1px #000000;
751        }
752
753        .chat-textarea {
754            flex: 1;
755            background: transparent;
756            border: none;
757            outline: none;
758            color: var(--text-primary);
759            resize: none;
760            height: 44px;
761            min-height: 44px;
762            max-height: 200px;
763            padding: 10px 4px;
764            font-size: 15px;
765            line-height: 1.5;
766            transition: height 0.1s ease;
767        }
768
769        .action-btn-circle {
770            width: 40px;
771            height: 40px;
772            border-radius: 50%;
773            border: none;
774            display: flex;
775            align-items: center;
776            justify-content: center;
777            cursor: pointer;
778            transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
779        }
780
781        .send-btn {
782            background: #000000;
783            color: #ffffff;
784            box-shadow: none;
785        }
786
787        .send-btn:hover {
788            transform: scale(1.05);
789            background: #222222;
790        }
791
792        .stop-btn {
793            background: #fee2e2;
794            color: #ef4444;
795            border: 1px solid #fca5a5;
796            display: none;
797        }
798
799        .stop-btn:hover {
800            background: #fecaca;
801        }
802
803        .char-counter {
804            font-size: 11px;
805            color: var(--text-secondary);
806            font-family: 'JetBrains Mono', monospace;
807            align-self: flex-end;
808            margin-bottom: 8px;
809            user-select: none;
810        }
811
812        /* --- Tool Sandbox View Panel --- */
813        .sandbox-container {
814            display: grid;
815            grid-template-columns: 340px 1fr;
816            height: calc(100vh - 72px);
817            overflow: hidden;
818        }
819
820        .sandbox-control {
821            border-right: 1px solid var(--glass-border);
822            padding: 24px;
823            background: var(--bg-secondary);
824            display: flex;
825            flex-direction: column;
826            gap: 20px;
827            overflow-y: auto;
828        }
829
830        .sandbox-interactive {
831            display: flex;
832            flex-direction: column;
833            overflow: hidden;
834            position: relative;
835            height: 100%;
836        }
837
838        .tool-chip-list {
839            display: flex;
840            flex-direction: column;
841            gap: 10px;
842        }
843
844        .tool-chip {
845            border: 1px solid var(--glass-border);
846            background: var(--bg-secondary);
847            border-radius: var(--radius-md);
848            padding: 12px;
849            display: flex;
850            flex-direction: column;
851            gap: 6px;
852            transition: all 0.2s ease;
853        }
854
855        .tool-chip:hover {
856            border-color: #000000;
857            background: var(--bg-tertiary);
858        }
859
860        .tool-chip-header {
861            display: flex;
862            align-items: center;
863            justify-content: space-between;
864        }
865
866        .tool-name-badge {
867            font-family: 'JetBrains Mono', monospace;
868            font-size: 12px;
869            color: #000000;
870            background: var(--bg-tertiary);
871            padding: 3px 8px;
872            border-radius: var(--radius-sm);
873            border: 1px solid var(--glass-border);
874            font-weight: 600;
875        }
876
877        .tool-chip-desc {
878            font-size: 12px;
879            color: var(--text-secondary);
880            line-height: 1.4;
881        }
882
883        /* --- Intercepted Tool Bubble --- */
884        .tool-call-card {
885            background: #ffffff;
886            border: 1px solid var(--glass-border);
887            border-radius: var(--radius-lg);
888            padding: 20px;
889            margin: 16px 0;
890            display: flex;
891            flex-direction: column;
892            gap: 12px;
893            border-left: 4px solid #000000;
894            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.02);
895        }
896
897        .tool-call-header {
898            display: flex;
899            align-items: center;
900            gap: 10px;
901            font-weight: 700;
902            color: #000000;
903            font-size: 14px;
904        }
905
906        .tool-call-code {
907            font-family: 'JetBrains Mono', monospace;
908            background-color: #1c1b18;
909            padding: 12px;
910            border-radius: var(--radius-md);
911            border: 1px solid #e2e1df;
912            color: #f1f5f9;
913            font-size: 13px;
914            overflow-x: auto;
915        }
916
917        .tool-result-section {
918            display: flex;
919            flex-direction: column;
920            gap: 8px;
921            border-top: 1px solid var(--glass-border);
922            padding-top: 14px;
923        }
924
925        .tool-result-title {
926            font-size: 11px;
927            font-weight: 700;
928            text-transform: uppercase;
929            letter-spacing: 0.5px;
930            color: var(--text-secondary);
931        }
932
933        .tool-result-input {
934            width: 100%;
935            background-color: #f4f3f0;
936            border: 1px solid var(--glass-border);
937            border-radius: var(--radius-sm);
938            color: #000000;
939            font-family: 'JetBrains Mono', monospace;
940            font-size: 13px;
941            padding: 10px;
942            outline: none;
943        }
944
945        .tool-result-input:focus {
946            border-color: #000000;
947        }
948
949        .tool-execute-btn {
950            background: #000000;
951            color: white;
952            border: none;
953            border-radius: 9999px;
954            padding: 10px 20px;
955            font-weight: 600;
956            font-size: 13px;
957            cursor: pointer;
958            align-self: flex-start;
959            display: flex;
960            align-items: center;
961            gap: 8px;
962            transition: all 0.2s ease;
963        }
964
965        .tool-execute-btn:hover {
966            background: #222222;
967            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
968            transform: translateY(-1px);
969        }
970
971        .tool-executed-badge {
972            background: var(--bg-tertiary);
973            color: #000000;
974            border: 1px solid var(--glass-border);
975            padding: 6px 12px;
976            border-radius: 9999px;
977            font-size: 12px;
978            font-weight: 600;
979            display: flex;
980            align-items: center;
981            gap: 6px;
982            align-self: flex-start;
983        }
984
985        /* --- Keyframe Animations --- */
986        @keyframes spin {
987            0% { transform: rotate(0deg); }
988            100% { transform: rotate(360deg); }
989        }
990
991        @keyframes float {
992            0% { transform: translateY(0px); }
993            50% { transform: translateY(-10px); }
994            100% { transform: translateY(0px); }
995        }
996
997        @keyframes ping {
998            75%, 100% {
999                transform: scale(2.5);
1000                opacity: 0;
1001            }
1002        }
1003
1004        @keyframes slide-up {
1005            from {
1006                opacity: 0;
1007                transform: translateY(12px);
1008            }
1009            to {
1010                opacity: 1;
1011                transform: translateY(0);
1012            }
1013        }
1014
1015        /* --- Media Queries --- */
1016        @media (max-width: 900px) {
1017            aside {
1018                position: absolute;
1019                left: -320px;
1020                height: 100%;
1021                box-shadow: 10px 0 30px rgba(0, 0, 0, 0.1);
1022            }
1023
1024            aside.open {
1025                left: 0;
1026            }
1027
1028            .hamburger {
1029                display: block;
1030            }
1031
1032            .sandbox-container {
1033                grid-template-columns: 1fr;
1034            }
1035
1036            .sandbox-control {
1037                display: none;
1038            }
1039
1040            /* --- Custom mobile clean design --- */
1041            .header-nav-links {
1042                display: none !important;
1043            }
1044
1045            .main-header {
1046                padding: 0 16px;
1047                height: 60px;
1048            }
1049
1050            .status-container span {
1051                display: none !important; /* Hide text, keep green dot */
1052            }
1053
1054            .status-container {
1055                gap: 0;
1056            }
1057
1058            .nav-tabs {
1059                gap: 2px;
1060                padding: 2px;
1061            }
1062
1063            .tab-btn {
1064                font-size: 11px;
1065                padding: 5px 10px;
1066                gap: 4px;
1067            }
1068
1069            .welcome-view {
1070                grid-template-columns: 1fr !important;
1071                gap: 24px !important;
1072                padding: 24px 16px 120px !important;
1073                text-align: center !important;
1074            }
1075
1076            .welcome-left {
1077                align-items: center !important;
1078                text-align: center !important;
1079            }
1080
1081            .welcome-main-title {
1082                font-size: 28px !important;
1083                letter-spacing: -0.6px !important;
1084                text-align: center !important;
1085            }
1086
1087            .welcome-main-subtitle {
1088                font-size: 13.5px !important;
1089                text-align: center !important;
1090                max-width: 100% !important;
1091            }
1092
1093            .welcome-action-buttons {
1094                justify-content: center !important;
1095                width: 100% !important;
1096            }
1097
1098            .btn-pill {
1099                padding: 10px 20px !important;
1100                font-size: 13px !important;
1101            }
1102
1103            .starters-grid {
1104                grid-template-columns: 1fr !important;
1105                gap: 10px !important;
1106                width: 100% !important;
1107            }
1108
1109            .starter-card {
1110                padding: 12px 16px !important;
1111            }
1112
1113            .welcome-right {
1114                margin-top: 16px !important;
1115                width: 100% !important;
1116                display: flex !important;
1117                justify-content: center !important;
1118            }
1119
1120            .partnership-card {
1121                padding: 20px !important;
1122                max-width: 100% !important;
1123                gap: 20px !important;
1124                border-radius: 16px !important;
1125            }
1126
1127            .partner-divider {
1128                height: 36px !important;
1129            }
1130
1131            .partnership-logos {
1132                gap: 16px !important;
1133                padding: 8px 0 !important;
1134            }
1135
1136            .partner-logo img {
1137                height: 36px !important;
1138            }
1139
1140            .partnership-footer {
1141                font-size: 12px !important;
1142            }
1143
1144            .chat-history-scroll {
1145                padding: 16px 16px 90px !important;
1146                gap: 16px !important;
1147            }
1148
1149            .message-bubble {
1150                max-width: 92% !important;
1151                padding: 12px 16px !important;
1152                font-size: 14px !important;
1153            }
1154
1155            .footer-input-bar {
1156                padding: 12px 12px 16px !important;
1157            }
1158
1159            .input-wrapper {
1160                padding: 6px 10px !important;
1161                gap: 8px !important;
1162                border-radius: 14px !important;
1163            }
1164
1165            .chat-textarea {
1166                height: 38px !important;
1167                min-height: 38px !important;
1168                font-size: 14px !important;
1169                padding: 8px 2px !important;
1170            }
1171
1172            .char-counter {
1173                display: none !important;
1174            }
1175        }
1176
1177        /* --- Google-style Minimalist Chat Redesign --- */
1178        .chat-empty .chat-history-scroll {
1179            display: none;
1180        }
1181
1182        .chat-empty .landing-container {
1183            display: flex;
1184        }
1185
1186        .chat-empty .footer-input-bar {
1187            position: relative;
1188            padding: 0 24px 60px;
1189            background: transparent;
1190            width: 100%;
1191            max-width: 680px;
1192            margin: 0 auto;
1193            pointer-events: auto;
1194        }
1195
1196        .chat-empty .footer-input-bar .input-wrapper {
1197            box-shadow: 0 12px 36px rgba(0, 0, 0, 0.05);
1198            border: 1px solid #dcdad7;
1199            border-radius: 28px;
1200        }
1201
1202        /* --- Landing Welcome Container --- */
1203        .landing-container {
1204            display: none;
1205            flex-direction: column;
1206            align-items: center;
1207            justify-content: center;
1208            flex: 1;
1209            width: 100%;
1210            max-width: 680px;
1211            margin: auto;
1212            padding: 60px 24px 20px;
1213            text-align: center;
1214            gap: 32px;
1215            animation: slide-up 0.4s cubic-bezier(0.4, 0, 0.2, 1);
1216        }
1217
1218        .landing-brand {
1219            display: flex;
1220            flex-direction: column;
1221            align-items: center;
1222            gap: 16px;
1223        }
1224
1225        .landing-logo {
1226            width: 64px;
1227            height: 64px;
1228            border-radius: 16px;
1229            box-shadow: 0 8px 24px rgba(0, 0, 0, 0.06);
1230            background: #ffffff;
1231            padding: 2px;
1232            border: 1px solid #e2e1df;
1233            animation: float 5s ease-in-out infinite;
1234        }
1235
1236        .landing-title {
1237            font-size: 36px;
1238            font-weight: 700;
1239            color: #000000;
1240            letter-spacing: -1px;
1241        }
1242
1243        .landing-subtitle {
1244            font-size: 15px;
1245            color: var(--text-secondary);
1246            max-width: 480px;
1247            line-height: 1.5;
1248        }
1249
1250        .landing-starters {
1251            display: flex;
1252            flex-wrap: wrap;
1253            gap: 10px;
1254            justify-content: center;
1255            width: 100%;
1256        }
1257
1258        .starter-pill {
1259            background: #ffffff;
1260            border: 1px solid #dcdad7;
1261            padding: 10px 18px;
1262            border-radius: 9999px;
1263            font-size: 13.5px;
1264            font-weight: 500;
1265            color: var(--text-primary);
1266            cursor: pointer;
1267            transition: all 0.2s ease;
1268            display: flex;
1269            align-items: center;
1270            gap: 8px;
1271        }
1272
1273        .starter-pill i {
1274            color: var(--text-secondary);
1275            font-size: 12px;
1276        }
1277
1278        .starter-pill:hover {
1279            background: #000000;
1280            color: #ffffff;
1281            border-color: #000000;
1282            transform: translateY(-1px);
1283            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
1284        }
1285
1286        .starter-pill:hover i {
1287            color: #ffffff;
1288        }
1289
1290        /* --- Collapsible Sidebar Settings Footer --- */
1291        .sidebar-footer {
1292            border-top: 1px solid var(--glass-border);
1293            background: var(--bg-secondary);
1294            padding: 16px 24px;
1295        }
1296
1297        .developer-toggle {
1298            display: flex;
1299            align-items: center;
1300            justify-content: space-between;
1301            cursor: pointer;
1302            font-size: 13px;
1303            font-weight: 600;
1304            color: var(--text-secondary);
1305            user-select: none;
1306            transition: color 0.2s ease;
1307        }
1308
1309        .developer-toggle:hover {
1310            color: var(--text-primary);
1311        }
1312
1313        .dev-chevron {
1314            transition: transform 0.2s ease;
1315        }
1316
1317        .developer-content {
1318            max-height: 500px;
1319            overflow-y: auto;
1320            transition: max-height 0.3s ease, opacity 0.3s ease;
1321            opacity: 1;
1322            display: flex;
1323            flex-direction: column;
1324            gap: 12px;
1325            padding-top: 12px;
1326        }
1327
1328        .developer-content.collapsed {
1329            max-height: 0;
1330            opacity: 0;
1331            overflow: hidden;
1332            padding-top: 0;
1333            pointer-events: none;
1334        }
1335
1336        /* --- Elegant Toggle Switch --- */
1337        .switch {
1338            position: relative;
1339            display: inline-block;
1340            width: 36px;
1341            height: 20px;
1342        }
1343
1344        .switch input { 
1345            opacity: 0;
1346            width: 0;
1347            height: 0;
1348        }
1349
1350        .slider.round {
1351            position: absolute;
1352            cursor: pointer;
1353            top: 0;
1354            left: 0;
1355            right: 0;
1356            bottom: 0;
1357            background-color: var(--bg-tertiary);
1358            border: 1px solid var(--glass-border);
1359            transition: .2s;
1360            border-radius: 34px;
1361        }
1362
1363        .slider.round:before {
1364            position: absolute;
1365            content: "";
1366            height: 14px;
1367            width: 14px;
1368            left: 2px;
1369            bottom: 2px;
1370            background-color: #000000;
1371            transition: .2s;
1372            border-radius: 50%;
1373        }
1374
1375        input:checked + .slider {
1376            background-color: #000000;
1377            border-color: #000000;
1378        }
1379
1380        input:checked + .slider:before {
1381            transform: translateX(16px);
1382            background-color: #ffffff;
1383        }
1384
1385        /* --- Footer Disclaimer --- */
1386        .input-footer-note {
1387            font-size: 11px;
1388            color: var(--text-secondary);
1389            text-align: center;
1390            margin-top: 8px;
1391            font-weight: 400;
1392            pointer-events: auto;
1393            letter-spacing: 0.2px;
1394        }
1395    </style>
1396</head>
1397<body>
1398
1399    <div class="app-container">
1400        <!-- Sidebar Configurator -->
1401        <aside id="sidebar">
1402            <div class="sidebar-header">
1403                <div class="brand">
1404                    <img src="https://cdn-avatars.huggingface.co/v1/production/uploads/61b8e2ba285851687028d395/EsTgVtnM2IqVRKgPdfqcB.png" alt="Liquid AI Logo" style="width: 28px; height: 28px; border-radius: 6px; object-fit: contain; flex-shrink: 0;">
1405                    <span style="font-family: 'Inter', sans-serif; font-size: 16px; font-weight: 700; color: #000000; letter-spacing: -0.3px;">Liquid AI</span>
1406                    <span style="font-family:'JetBrains Mono',monospace; font-size:10px; background:#f4f3f0; padding:2px 6px; border-radius:4px; color:#636366; font-weight:500; margin-left: 4px;">LFM 2.5</span>
1407                </div>
1408                <button class="delete-chat-btn" onclick="toggleSidebar()" style="font-size: 16px;"><i class="fa-solid fa-chevron-left"></i></button>
1409            </div>
1410
1411            <button class="new-chat-btn" onclick="createNewChat()">
1412                <i class="fa-solid fa-plus"></i> New Conversation
1413            </button>
1414
1415            <!-- Scrollable Conversations List -->
1416            <div class="sidebar-sections" style="flex: 1; overflow-y: auto;">
1417                <div class="setting-group" style="height: 100%; display: flex; flex-direction: column;">
1418                    <span class="section-title"><i class="fa-solid fa-clock-rotate-left"></i> Recent Conversations</span>
1419                    <div class="chat-list" id="chat-history-list" style="flex: 1; max-height: none;">
1420                        <!-- Loaded dynamically -->
1421                    </div>
1422                </div>
1423            </div>
1424
1425            <!-- Collapsible Settings Panel locked at bottom -->
1426            <div class="sidebar-footer">
1427                <div class="developer-toggle" onclick="toggleDeveloperSettings()">
1428                    <span><i class="fa-solid fa-sliders"></i> Developer Settings</span>
1429                    <i class="fa-solid fa-chevron-down dev-chevron"></i>
1430                </div>
1431                <div class="developer-content collapsed" id="developer-settings-content">
1432                    <!-- Sandbox Toggle -->
1433                    <div class="setting-group" style="flex-direction: row; justify-content: space-between; align-items: center; margin-top: 10px;">
1434                        <span class="setting-label">Enable Agent Sandbox</span>
1435                        <label class="switch">
1436                            <input type="checkbox" id="sandbox-mode-toggle" onchange="toggleSandboxMode(this.checked)">
1437                            <span class="slider round"></span>
1438                        </label>
1439                    </div>
1440
1441                    <!-- Temperature -->
1442                    <div class="setting-group" style="margin-top: 10px;">
1443                        <div class="setting-label">
1444                            <span>Temperature</span>
1445                            <span class="setting-val" id="temp-val">0.2</span>
1446                        </div>
1447                        <input type="range" class="setting-slider" id="temp-slider" min="0" max="1.5" step="0.05" value="0.2" oninput="updateParam('temp', this.value)">
1448                    </div>
1449
1450                    <!-- Top-K -->
1451                    <div class="setting-group" style="margin-top: 10px;">
1452                        <div class="setting-label">
1453                            <span>Top-K</span>
1454                            <span class="setting-val" id="topk-val">80</span>
1455                        </div>
1456                        <input type="range" class="setting-slider" id="topk-slider" min="1" max="200" step="1" value="80" oninput="updateParam('topk', this.value)">
1457                    </div>
1458
1459                    <!-- Repetition Penalty -->
1460                    <div class="setting-group" style="margin-top: 10px;">
1461                        <div class="setting-label">
1462                            <span>Repetition Penalty</span>
1463                            <span class="setting-val" id="rep-val">1.05</span>
1464                        </div>
1465                        <input type="range" class="setting-slider" id="rep-slider" min="1" max="1.5" step="0.01" value="1.05" oninput="updateParam('rep', this.value)">
1466                    </div>
1467
1468                    <!-- Max Tokens -->
1469                    <div class="setting-group" style="margin-top: 10px;">
1470                        <div class="setting-label">
1471                            <span>Max Tokens</span>
1472                            <span class="setting-val" id="tokens-val">2048</span>
1473                        </div>
1474                        <input type="range" class="setting-slider" id="tokens-slider" min="256" max="4096" step="128" value="2048" oninput="updateParam('tokens', this.value)">
1475                    </div>
1476
1477                    <!-- Persona Selection -->
1478                    <div class="setting-group" style="margin-top: 10px;">
1479                        <span class="setting-label">System Persona</span>
1480                        <select class="form-select" id="persona-select" onchange="applyPersona(this.value)" style="margin-top: 4px;">
1481                            <option value="general">Default Personal Assistant</option>
1482                            <option value="math">Reasoning & Logic Solver</option>
1483                            <option value="coder">Software Engineer</option>
1484                            <option value="translator">Multilingual Translator</option>
1485                            <option value="custom">Custom System Prompt</option>
1486                        </select>
1487                        <textarea class="form-textarea" id="system-prompt" style="margin-top: 8px;" oninput="saveCurrentChatSettings()" placeholder="Enter custom instructions..."></textarea>
1488                    </div>
1489                </div>
1490            </div>
1491        </aside>
1492        <!-- Main Body Area -->
1493        <main>
1494            <!-- Navigation Header -->
1495            <div class="main-header">
1496                <div class="header-brand-section">
1497                    <i class="fa-solid fa-bars hamburger" onclick="toggleSidebar()"></i>
1498                    <div class="brand" style="margin-left: 8px;">
1499                        <img src="https://cdn-avatars.huggingface.co/v1/production/uploads/61b8e2ba285851687028d395/EsTgVtnM2IqVRKgPdfqcB.png" alt="Liquid AI Logo" style="width: 24px; height: 24px; border-radius: 5px; object-fit: contain; flex-shrink: 0;">
1500                        <span style="font-family: 'Inter', sans-serif; font-size: 15px; font-weight: 700; color: #000000; letter-spacing: -0.3px; margin-left: 6px;">Liquid AI</span>
1501                    </div>
1502                </div>
1503
1504                <div style="display: flex; align-items: center; gap: 16px;">
1505                    <div class="nav-tabs" style="display: none;">
1506                        <button class="tab-btn active" id="tab-chat" onclick="switchTab('chat')">
1507                            <i class="fa-solid fa-message"></i> Chat
1508                        </button>
1509                        <button class="tab-btn" id="tab-sandbox" onclick="switchTab('sandbox')">
1510                            <i class="fa-solid fa-laptop-code"></i> Developer Sandbox
1511                        </button>
1512                    </div>
1513                    <div class="status-container">
1514                        <div class="status-dot"></div>
1515                        <span id="connection-status">Connecting...</span>
1516                    </div>
1517                </div>
1518            </div>
1519
1520            <!-- Tab View 1: Chat Assistant -->
1521            <div class="tab-panel active chat-empty" id="panel-chat">
1522                <!-- Chat Messages Scroll Area -->
1523                <div class="chat-history-scroll" id="chat-history-scroll">
1524                    <!-- Rendered messages will go here -->
1525                </div>
1526
1527                <!-- Centered Landing Layout (only visible when chat-empty is active) -->
1528                <div class="landing-container" id="landing-container">
1529                    <div class="landing-brand">
1530                        <img src="https://cdn-avatars.huggingface.co/v1/production/uploads/61b8e2ba285851687028d395/EsTgVtnM2IqVRKgPdfqcB.png" alt="Liquid AI Logo" class="landing-logo">
1531                        <h1 class="landing-title">How can I help today?</h1>
1532                        <p class="landing-subtitle">LFM 2.5 delivers supercharged, private edge-native intelligence.</p>
1533                    </div>
1534                    
1535                    <!-- Suggestions/Starter Pills -->
1536                    <div class="landing-starters">
1537                        <button class="starter-pill" onclick="loadStarter('Explain the concept of quantum computing in simple terms for a child.')">
1538                            <i class="fa-solid fa-lightbulb"></i> Explain Quantum Computing
1539                        </button>
1540                        <button class="starter-pill" onclick="loadStarter('Write a clean Python script to find all prime numbers up to a given limit.')">
1541                            <i class="fa-solid fa-code"></i> Python Primes Script
1542                        </button>
1543                        <button class="starter-pill" onclick="loadStarter('Write a short, engaging sci-fi story about a rogue robot in 3 sentences.')">
1544                            <i class="fa-solid fa-pen-nib"></i> Write Sci-Fi Story
1545                        </button>
1546                    </div>
1547                </div>
1548
1549                <!-- Unified Input Footer -->
1550                <div class="footer-input-bar" id="chat-input-bar">
1551                    <div class="input-wrapper">
1552                        <textarea class="chat-textarea" id="chat-input" placeholder="Ask LFM 2.5 anything..." rows="1" onkeydown="handleInputKeyDown(event)"></textarea>
1553                        <button class="action-btn-circle send-btn" id="send-button" onclick="submitUserPrompt()">
1554                            <i class="fa-solid fa-arrow-up"></i>
1555                        </button>
1556                        <button class="action-btn-circle stop-btn" id="stop-button" onclick="cancelActiveGeneration()">
1557                            <i class="fa-solid fa-stop"></i>
1558                        </button>
1559                    </div>
1560                    <div class="input-footer-note">
1561                        LFM 2.5 may produce inaccurate information. Direct, secure edge-native intelligence.
1562                    </div>
1563                </div>
1564            </div>
1565
1566            <!-- Tab View 2: Tool Sandbox -->
1567            <div class="tab-panel" id="panel-sandbox">
1568                <div class="sandbox-container">
1569                    <!-- Sandbox sidebar controls -->
1570                    <div class="sandbox-control">
1571                        <span class="section-title"><i class="fa-solid fa-briefcase"></i> Active Tools</span>
1572                        <p style="font-size: 13px; color: var(--text-secondary); line-height: 1.4;">
1573                            LFM2.5 natively outputs Pythonic function calls between <code>&lt;|tool_call_start|&gt;</code> and <code>&lt;|tool_call_end|&gt;</code> special tokens. 
1574                        </p>
1575                        <div class="tool-chip-list">
1576                            <div class="tool-chip">
1577                                <div class="tool-chip-header">
1578                                    <span class="tool-name-badge">get_candidate_status</span>
1579                                </div>
1580                                <div class="tool-chip-desc">Retrieves the recruitment status of a candidate. Argument: <code>candidate_id (str)</code>.</div>
1581                            </div>
1582                            <div class="tool-chip">
1583                                <div class="tool-chip-header">
1584                                    <span class="tool-name-badge">get_weather</span>
1585                                </div>
1586                                <div class="tool-chip-desc">Queries live weather conditions. Arguments: <code>location (str)</code>.</div>
1587                            </div>
1588                            <div class="tool-chip">
1589                                <div class="tool-chip-header">
1590                                    <span class="tool-name-badge">search_products</span>
1591                                </div>
1592                                <div class="tool-chip-desc">Searches local inventories. Argument: <code>query (str)</code>.</div>
1593                            </div>
1594                        </div>
1595                        <span class="section-title"><i class="fa-solid fa-circle-question"></i> Sample Prompts</span>
1596                        <div class="starter-card" style="padding: 12px;" onclick="loadSandboxStarter('What is the current status of candidate ID 12345?')">
1597                            <div class="starter-card-title" style="font-size:13.5px;"><i class="fa-solid fa-user-tag"></i> Candidate Status</div>
1598                            <div class="starter-card-desc" style="font-size:11.5px;">Triggers get_candidate_status call.</div>
1599                        </div>
1600                        <div class="starter-card" style="padding: 12px;" onclick="loadSandboxStarter('Can you check if it is raining in Seattle right now?')">
1601                            <div class="starter-card-title" style="font-size:13.5px;"><i class="fa-solid fa-cloud-sun"></i> Weather Check</div>
1602                            <div class="starter-card-desc" style="font-size:11.5px;">Triggers get_weather call.</div>
1603                        </div>
1604                    </div>
1605
1606                    <!-- Sandbox Interactive Chat -->
1607                    <div class="sandbox-interactive">
1608                        <div class="chat-history-scroll" id="sandbox-history-scroll">
1609                            <!-- Sandbox Welcome Message -->
1610                            <div class="welcome-view" id="sandbox-welcome-view">
1611                                <img src="https://cdn-avatars.huggingface.co/v1/production/uploads/61b8e2ba285851687028d395/EsTgVtnM2IqVRKgPdfqcB.png" alt="Liquid AI" style="width: 56px; height: 56px; border-radius: 12px; margin-bottom: 8px;">
1612                                <h1 class="welcome-main-title">Agentic Sandbox</h1>
1613                                <p class="welcome-main-subtitle">
1614                                    Test the native function-calling capabilities of LFM 2.5.
1615                                </p>
1616                                
1617                                <div class="starters-minimal">
1618                                    <button class="starter-pill" onclick="loadSandboxStarter('What is the current status of candidate ID 12345?')">Candidate Status</button>
1619                                    <button class="starter-pill" onclick="loadSandboxStarter('Can you check if it is raining in Seattle right now?')">Weather Check</button>
1620                                </div>
1621                            </div>
1622                        </div>
1623
1624                        <!-- Sandbox Input Bar -->
1625                        <div class="footer-input-bar">
1626                            <div class="input-wrapper">
1627                                <textarea class="chat-textarea" id="sandbox-input" placeholder="Type a prompt to trigger a tool call..." rows="1" onkeydown="handleSandboxInputKeyDown(event)"></textarea>
1628                                <button class="action-btn-circle send-btn" style="background: linear-gradient(135deg, var(--accent-teal), var(--accent-glow));" id="sandbox-send-button" onclick="submitSandboxPrompt()">
1629                                    <i class="fa-solid fa-play"></i>
1630                                </button>
1631                                <button class="action-btn-circle stop-btn" id="sandbox-stop-button" onclick="cancelActiveGeneration()">
1632                                    <i class="fa-solid fa-stop"></i>
1633                                </button>
1634                            </div>
1635                        </div>
1636                    </div>
1637                </div>
1638            </div>
1639        </main>
1640    </div>
1641
1642    <!-- Scripts: Marked.js, Prism.js, and Gradio JS Client -->
1643    
1643<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
1643
1644    
1644<script src="https://cdn.jsdelivr.net/npm/[email protected]/components/prism-core.min.js"></script>
1644
1645    
1645<script src="https://cdn.jsdelivr.net/npm/[email protected]/plugins/autoloader/prism-autoloader.min.js"></script>
1645
1646
1647    
1647<script type="module">
1648        import { client } from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js";
1649
1650        // Global State variables
1651        let gradioClient = null;
1652        let activeJob = null;
1653        let chats = [];
1654        let activeChatId = null;
1655
1656        // Tool Sandbox execution state
1657        let sandboxHistory = [];
1658        let sandboxActiveJob = null;
1659
1660        // Custom personas definitions
1661        const personas = {
1662            general: "You are a helpful assistant trained by Liquid AI. Be clear, precise, and highly constructive.",
1663            math: "You are a specialized reasoning and logical deduction solver trained by Liquid AI. Deeply analyze all problems step-by-step. Always reason thoroughly inside <think>...</think> tags before writing your final verified solution.",
1664            coder: "You are an expert software engineer trained by Liquid AI. Write highly optimized, well-documented, clean code following best practices. Focus on readability and execution performance.",
1665            translator: "You are an expert translator. Help the user translate phrases perfectly, retaining nuances, local idioms, and stylistic traits in multiple target languages."
1666        };
1667
1668        // UI Initializer
1669        window.addEventListener('DOMContentLoaded', async () => {
1670            initApp();
1671            await connectGradio();
1672        });
1673
1674        // Toggle Sidebar view
1675        window.toggleSidebar = function() {
1676            const sidebar = document.getElementById('sidebar');
1677            sidebar.classList.toggle('open');
1678        }
1679
1680        // Toggle collapsible Developer settings panel in sidebar
1681        window.toggleDeveloperSettings = function() {
1682            const content = document.getElementById('developer-settings-content');
1683            const chevron = document.querySelector('.dev-chevron');
1684            content.classList.toggle('collapsed');
1685            if (chevron) {
1686                chevron.style.transform = content.classList.contains('collapsed') ? 'rotate(0deg)' : 'rotate(180deg)';
1687            }
1688        }
1689
1690        // Toggle visibility of sandbox tab in navigation header
1691        window.toggleSandboxMode = function(enabled) {
1692            const tabs = document.querySelector('.nav-tabs');
1693            if (tabs) {
1694                tabs.style.display = enabled ? 'flex' : 'none';
1695            }
1696            if (!enabled) {
1697                switchTab('chat');
1698            }
1699        }
1700
1701        // Initialize state, localstorage, and setup UI handlers
1702        function initApp() {
1703            // Load chats from LocalStorage
1704            const storedChats = localStorage.getItem('lfm25_chats');
1705            if (storedChats) {
1706                chats = JSON.parse(storedChats);
1707            }
1708
1709            if (chats.length === 0) {
1710                createNewChat();
1711            } else {
1712                activeChatId = chats[0].id;
1713                renderChatList();
1714                loadActiveChat();
1715            }
1716
1717            // Setup input listener to autosize height
1718            const chatInput = document.getElementById('chat-input');
1719            chatInput.addEventListener('input', () => {
1720                chatInput.style.height = 'auto';
1721                chatInput.style.height = (chatInput.scrollHeight) + 'px';
1722            });
1723
1724            const sandboxInput = document.getElementById('sandbox-input');
1725            sandboxInput.addEventListener('input', () => {
1726                sandboxInput.style.height = 'auto';
1727                sandboxInput.style.height = (sandboxInput.scrollHeight) + 'px';
1728            });
1729        }
1730
1731        // Connect to the backend Gradio Server
1732        async function connectGradio() {
1733            const statusText = document.getElementById('connection-status');
1734            const dot = document.querySelector('.status-dot');
1735            try {
1736                // Connect directly to backend host origin
1737                gradioClient = await client(window.location.origin);
1738                statusText.innerText = "Backend Connected";
1739                dot.style.backgroundColor = "var(--accent-teal)";
1740                dot.style.boxShadow = "0 0 8px var(--accent-teal)";
1741            } catch (err) {
1742                console.error("Gradio connection failed:", err);
1743                statusText.innerText = "Demo Mode (Mock Offline)";
1744                dot.style.backgroundColor = "#eab308";
1745                dot.style.boxShadow = "0 0 8px #eab308";
1746            }
1747        }
1748
1749        // Tab selection logic
1750        window.switchTab = function(tabName) {
1751            document.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('active'));
1752            document.querySelectorAll('.tab-panel').forEach(panel => panel.classList.remove('active'));
1753
1754            if (tabName === 'chat') {
1755                document.getElementById('tab-chat').classList.add('active');
1756                document.getElementById('panel-chat').classList.add('active');
1757            } else {
1758                document.getElementById('tab-sandbox').classList.add('active');
1759                document.getElementById('panel-sandbox').classList.add('active');
1760            }
1761        }
1762
1763        /* --- Chat history management --- */
1764        window.createNewChat = function() {
1765            const newChat = {
1766                id: 'chat_' + Date.now(),
1767                title: 'New Discussion',
1768                history: [],
1769                systemPrompt: personas.general,
1770                selectedPersona: 'general',
1771                params: {
1772                    temperature: 0.2,
1773                    top_k: 80,
1774                    repetition_penalty: 1.05,
1775                    max_new_tokens: 2048
1776                }
1777            };
1778            chats.unshift(newChat);
1779            activeChatId = newChat.id;
1780            saveChatsToStorage();
1781            renderChatList();
1782            loadActiveChat();
1783        }
1784
1785        function saveChatsToStorage() {
1786            localStorage.setItem('lfm25_chats', JSON.stringify(chats));
1787        }
1788
1789        function renderChatList() {
1790            const list = document.getElementById('chat-history-list');
1791            list.innerHTML = '';
1792            chats.forEach(chat => {
1793                const item = document.createElement('div');
1794                item.className = `chat-item ${chat.id === activeChatId ? 'active' : ''}`;
1795                item.onclick = () => selectChat(chat.id);
1796
1797                item.innerHTML = `
1798                    <span class="chat-item-title"><i class="fa-regular fa-message" style="margin-right:8px;"></i>${chat.title}</span>
1799                    <button class="delete-chat-btn" onclick="event.stopPropagation(); deleteChat('${chat.id}')"><i class="fa-solid fa-trash-can"></i></button>
1800                `;
1801                list.appendChild(item);
1802            });
1803        }
1804
1805        window.selectChat = function(chatId) {
1806            activeChatId = chatId;
1807            renderChatList();
1808            loadActiveChat();
1809            
1810            // Close sidebar on mobile after selection
1811            if (window.innerWidth <= 900) {
1812                toggleSidebar();
1813            }
1814        }
1815
1816        window.deleteChat = function(chatId) {
1817            chats = chats.filter(c => c.id !== chatId);
1818            if (chats.length === 0) {
1819                createNewChat();
1820            } else {
1821                if (activeChatId === chatId) {
1822                    activeChatId = chats[0].id;
1823                }
1824                saveChatsToStorage();
1825                renderChatList();
1826                loadActiveChat();
1827            }
1828        }
1829
1830        function loadActiveChat() {
1831            const chat = chats.find(c => c.id === activeChatId);
1832            if (!chat) return;
1833
1834            // Load parameters into inputs
1835            document.getElementById('temp-slider').value = chat.params.temperature;
1836            document.getElementById('temp-val').innerText = chat.params.temperature;
1837            document.getElementById('topk-slider').value = chat.params.top_k;
1838            document.getElementById('topk-val').innerText = chat.params.top_k;
1839            document.getElementById('rep-slider').value = chat.params.repetition_penalty;
1840            document.getElementById('rep-val').innerText = chat.params.repetition_penalty;
1841            document.getElementById('tokens-slider').value = chat.params.max_new_tokens;
1842            document.getElementById('tokens-val').innerText = chat.params.max_new_tokens;
1843
1844            document.getElementById('persona-select').value = chat.selectedPersona;
1845            document.getElementById('system-prompt').value = chat.systemPrompt;
1846
1847            // Render Messages
1848            const scrollArea = document.getElementById('chat-history-scroll');
1849            scrollArea.innerHTML = '';
1850
1851            const chatPanel = document.getElementById('panel-chat');
1852            if (chat.history.length === 0) {
1853                chatPanel.classList.add('chat-empty');
1854            } else {
1855                chatPanel.classList.remove('chat-empty');
1856                chat.history.forEach(msg => {
1857                    appendMessageBubble(msg.role, msg.content, false);
1858                });
1859            }
1860            scrollArea.scrollTop = scrollArea.scrollHeight;
1861        }
1862
1863        window.updateParam = function(paramType, val) {
1864            const chat = chats.find(c => c.id === activeChatId);
1865            if (!chat) return;
1866
1867            if (paramType === 'temp') {
1868                chat.params.temperature = parseFloat(val);
1869                document.getElementById('temp-val').innerText = val;
1870            } else if (paramType === 'topk') {
1871                chat.params.top_k = parseInt(val);
1872                document.getElementById('topk-val').innerText = val;
1873            } else if (paramType === 'rep') {
1874                chat.params.repetition_penalty = parseFloat(val);
1875                document.getElementById('rep-val').innerText = val;
1876            } else if (paramType === 'tokens') {
1877                chat.params.max_new_tokens = parseInt(val);
1878                document.getElementById('tokens-val').innerText = val;
1879            }
1880            saveChatsToStorage();
1881        }
1882
1883        window.applyPersona = function(personaKey) {
1884            const chat = chats.find(c => c.id === activeChatId);
1885            if (!chat) return;
1886
1887            chat.selectedPersona = personaKey;
1888            if (personaKey !== 'custom') {
1889                chat.systemPrompt = personas[personaKey];
1890                document.getElementById('system-prompt').value = personas[personaKey];
1891            }
1892            saveChatsToStorage();
1893        }
1894
1895        window.saveCurrentChatSettings = function() {
1896            const chat = chats.find(c => c.id === activeChatId);
1897            if (!chat) return;
1898            chat.systemPrompt = document.getElementById('system-prompt').value;
1899            chat.selectedPersona = 'custom';
1900            document.getElementById('persona-select').value = 'custom';
1901            saveChatsToStorage();
1902        }
1903
1904        /* --- Quick Prompts --- */
1905        window.loadStarter = function(promptText) {
1906            document.getElementById('chat-input').value = promptText;
1907            document.getElementById('chat-input').dispatchEvent(new Event('input'));
1908            submitUserPrompt();
1909        }
1910
1911        window.loadSandboxStarter = function(promptText) {
1912            document.getElementById('sandbox-input').value = promptText;
1913            document.getElementById('sandbox-input').dispatchEvent(new Event('input'));
1914            submitSandboxPrompt();
1915        }
1916
1917        /* --- Custom Reasoning and Tool Call Parser --- */
1918        function parseResponseText(text) {
1919            let thinking = "";
1920            let answer = "";
1921            let isThinking = false;
1922            let hasThought = false;
1923
1924            const thinkStartIdx = text.indexOf("<think>");
1925            const thinkEndIdx = text.indexOf("</think>");
1926
1927            if (thinkStartIdx !== -1) {
1928                if (thinkEndIdx !== -1) {
1929                    thinking = text.substring(thinkStartIdx + 7, thinkEndIdx).trim();
1930                    answer = text.substring(thinkEndIdx + 8).trim();
1931                    hasThought = true;
1932                } else {
1933                    thinking = text.substring(thinkStartIdx + 7);
1934                    isThinking = true;
1935                }
1936            } else {
1937                answer = text;
1938            }
1939
1940            return { thinking, answer, isThinking, hasThought };
1941        }
1942
1943        // Custom parser to check for pythonic tool calls
1944        function parseToolCalls(text) {
1945            const toolStart = text.indexOf("<|tool_call_start|>");
1946            const toolEnd = text.indexOf("<|tool_call_end|>");
1947
1948            if (toolStart !== -1) {
1949                if (toolEnd !== -1) {
1950                    const toolContent = text.substring(toolStart + 19, toolEnd).trim();
1951                    const cleanAnswer = text.substring(0, toolStart).trim() + " " + text.substring(toolEnd + 17).trim();
1952                    return { hasCall: true, completed: true, callContent: toolContent, cleanAnswer };
1953                } else {
1954                    const toolContent = text.substring(toolStart + 19).trim();
1955                    const cleanAnswer = text.substring(0, toolStart).trim();
1956                    return { hasCall: true, completed: false, callContent: toolContent, cleanAnswer };
1957                }
1958            }
1959            return { hasCall: false, completed: false, callContent: "", cleanAnswer: text };
1960        }
1961
1962        /* --- UI Render Utilities --- */
1963        function appendMessageBubble(role, initialContent, isStreaming = false) {
1964            const scrollArea = document.getElementById(
1965                document.getElementById('tab-chat').classList.contains('active') ? 'chat-history-scroll' : 'sandbox-history-scroll'
1966            );
1967            
1968            // Remove empty class if messages are added to standard chat
1969            const chatPanel = document.getElementById('panel-chat');
1970            if (chatPanel && chatPanel.classList.contains('chat-empty') && scrollArea.id === 'chat-history-scroll') {
1971                chatPanel.classList.remove('chat-empty');
1972            }
1973            const sandboxWelcome = document.getElementById('sandbox-welcome-view');
1974            if (sandboxWelcome && sandboxWelcome.parentNode && scrollArea.id === 'sandbox-history-scroll') {
1975                sandboxWelcome.style.display = 'none';
1976            }
1977
1978            const row = document.createElement('div');
1979            row.className = `message-row ${role === 'user' ? 'user-row' : 'assistant-row'}`;
1980            
1981            const bubble = document.createElement('div');
1982            bubble.className = 'message-bubble';
1983
1984            if (role === 'user') {
1985                bubble.innerText = initialContent;
1986                row.appendChild(bubble);
1987                scrollArea.appendChild(row);
1988                scrollArea.scrollTop = scrollArea.scrollHeight;
1989                return bubble;
1990            }
1991
1992            // Create structure for Assistant bubble (Reasoning Block + Answer Block)
1993            const thinkingAccordion = document.createElement('div');
1994            thinkingAccordion.className = 'thinking-accordion collapsed';
1995            thinkingAccordion.innerHTML = `
1996                <div class="thinking-header" onclick="this.parentNode.classList.toggle('collapsed')">
1997                    <span class="thinking-status">
1998                        <i class="fa-solid fa-brain thinking-icon spinner-icon"></i>
1999                        <span class="thinking-title-text">Thinking Process...</span>
2000                    </span>
2001                    <i class="fa-solid fa-chevron-down chevron-icon"></i>
2002                </div>
2003                <div class="thinking-body"></div>
2004            `;
2005            
2006            const contentDiv = document.createElement('div');
2007            contentDiv.className = 'message-content';
2008
2009            bubble.appendChild(thinkingAccordion);
2010            bubble.appendChild(contentDiv);
2011            row.appendChild(bubble);
2012            scrollArea.appendChild(row);
2013            scrollArea.scrollTop = scrollArea.scrollHeight;
2014
2015            if (!isStreaming) {
2016                updateAssistantBubble(bubble, initialContent, false);
2017            }
2018
2019            return bubble;
2020        }
2021
2022        // Live update the elements inside assistant bubble
2023        function updateAssistantBubble(bubbleElement, rawContent, isStreaming = true) {
2024            const thinkingAccordion = bubbleElement.querySelector('.thinking-accordion');
2025            const thinkingBody = bubbleElement.querySelector('.thinking-body');
2026            const titleText = bubbleElement.querySelector('.thinking-title-text');
2027            const spinnerIcon = bubbleElement.querySelector('.thinking-icon');
2028            const contentDiv = bubbleElement.querySelector('.message-content');
2029            const scrollArea = bubbleElement.closest('.chat-history-scroll');
2030
2031            const parsed = parseResponseText(rawContent);
2032
2033            // Handle Thinking Trace
2034            if (parsed.thinking) {
2035                thinkingAccordion.style.display = 'block';
2036                thinkingBody.innerText = parsed.thinking;
2037                
2038                if (parsed.isThinking) {
2039                    thinkingAccordion.classList.remove('collapsed'); // open while thinking
2040                    titleText.innerText = "Thinking Process...";
2041                    spinnerIcon.className = "fa-solid fa-cog thinking-icon spinner-icon";
2042                } else if (parsed.hasThought) {
2043                    titleText.innerText = "Thinking complete";
2044                    spinnerIcon.className = "fa-solid fa-circle-check thinking-icon check-icon";
2045                }
2046            } else {
2047                thinkingAccordion.style.display = 'none';
2048            }
2049
2050            // Handle Answer content (parse markdown)
2051            if (parsed.answer) {
2052                // If in sandbox, check for tool calls
2053                const toolCheck = parseToolCalls(parsed.answer);
2054                if (toolCheck.hasCall) {
2055                    contentDiv.innerHTML = marked.parse(toolCheck.cleanAnswer);
2056                    
2057                    // Render tool card
2058                    let toolCard = bubbleElement.querySelector('.tool-call-card');
2059                    if (!toolCard) {
2060                        toolCard = document.createElement('div');
2061                        toolCard.className = 'tool-call-card';
2062                        bubbleElement.appendChild(toolCard);
2063                    }
2064
2065                    if (toolCheck.completed) {
2066                        renderCompletedToolCall(toolCard, toolCheck.callContent);
2067                    } else {
2068                        toolCard.innerHTML = `
2069                            <div class="tool-call-header">
2070                                <i class="fa-solid fa-terminal"></i> Executing Edge Agent Tool...
2071                            </div>
2072                            <div class="tool-call-code">${toolCheck.callContent}</div>
2073                        `;
2074                    }
2075                } else {
2076                    contentDiv.innerHTML = marked.parse(parsed.answer);
2077                }
2078
2079                // Add syntax highlighting & action overlays to code elements
2080                addCodeFormattingAndHighlighting(contentDiv);
2081            } else {
2082                contentDiv.innerHTML = '';
2083            }
2084
2085            // Keep scrolling to bottom as text arrives
2086            if (isStreaming) {
2087                scrollArea.scrollTop = scrollArea.scrollHeight;
2088            }
2089        }
2090
2091        // Add prism code block syntax wrapping and Copy buttons
2092        function addCodeFormattingAndHighlighting(container) {
2093            const preElements = container.querySelectorAll('pre');
2094            preElements.forEach(pre => {
2095                if (pre.parentNode.classList.contains('code-block-wrapper')) return;
2096
2097                const code = pre.querySelector('code');
2098                let lang = 'code';
2099                if (code) {
2100                    const classes = code.className.split(' ');
2101                    const langClass = classes.find(c => c.startsWith('language-'));
2102                    if (langClass) {
2103                        lang = langClass.replace('language-', '');
2104                    }
2105                }
2106
2107                const wrapper = document.createElement('div');
2108                wrapper.className = 'code-block-wrapper';
2109                
2110                const header = document.createElement('div');
2111                header.className = 'code-block-header';
2112                header.innerHTML = `
2113                    <span class="code-block-lang">${lang}</span>
2114                    <button class="copy-code-btn" onclick="copyCode(this)">
2115                        <i class="fa-regular fa-clipboard"></i> Copy
2116                    </button>
2117                `;
2118
2119                pre.parentNode.insertBefore(wrapper, pre);
2120                wrapper.appendChild(header);
2121                wrapper.appendChild(pre);
2122
2123                if (code) {
2124                    Prism.highlightElement(code);
2125                }
2126            });
2127        }
2128
2129        window.copyCode = function(button) {
2130            const wrapper = button.closest('.code-block-wrapper');
2131            const code = wrapper.querySelector('code');
2132            if (code) {
2133                navigator.clipboard.writeText(code.innerText).then(() => {
2134                    button.innerHTML = `<i class="fa-solid fa-check" style="color:var(--accent-teal)"></i> Copied!`;
2135                    setTimeout(() => {
2136                        button.innerHTML = `<i class="fa-regular fa-clipboard"></i> Copy`;
2137                    }, 2000);
2138                });
2139            }
2140        }
2141
2142        /* --- Mocking the Tool Sandbox Executions --- */
2143        function renderCompletedToolCall(cardElement, callText) {
2144            if (cardElement.dataset.executed === "true") return;
2145
2146            // Format: get_candidate_status(candidate_id="12345")
2147            // Parse name and arguments
2148            const nameMatch = callText.match(/^([a-zA-Z0-9_]+)\((.*)\)$/);
2149            let toolName = "Unknown Tool";
2150            let toolArgs = callText;
2151
2152            if (nameMatch) {
2153                toolName = nameMatch[1];
2154                toolArgs = nameMatch[2];
2155            }
2156
2157            // Create prefilled mock values based on predicted tools
2158            let mockResult = "{}";
2159            if (toolName === "get_candidate_status") {
2160                mockResult = `[{"candidate_id": "12345", "status": "Interview Scheduled", "position": "Clinical Research Associate", "date": "2023-11-20"}]`;
2161            } else if (toolName === "get_weather") {
2162                mockResult = `{"location": "Seattle", "temperature": "14°C", "condition": "Overcast Rain", "humidity": "82%"}`;
2163            } else if (toolName === "search_products") {
2164                mockResult = `[{"item": "Liquid Edge Tensor-B", "stock": 42, "price": "$899"}]`;
2165            }
2166
2167            cardElement.innerHTML = `
2168                <div class="tool-call-header" style="color:var(--accent-teal)">
2169                    <i class="fa-solid fa-circle-play"></i> Tool Call Triggered: <span style="font-family:'JetBrains Mono'">${toolName}</span>
2170                </div>
2171                <div class="tool-call-code">${callText}</div>
2172                <div class="tool-result-section">
2173                    <span class="tool-result-title">Configure Sandbox Output Result:</span>
2174                    <input type="text" class="tool-result-input" id="sandbox-res-input" value='${mockResult}'>
2175                    <button class="tool-execute-btn" onclick="executeMockTool(this, '${toolName}')">
2176                        <i class="fa-solid fa-gears"></i> Return Payload to Model
2177                    </button>
2178                </div>
2179            `;
2180        }
2181
2182        // Return tool results back to chat loop
2183        window.executeMockTool = async function(button, toolName) {
2184            const card = button.closest('.tool-call-card');
2185            const resultInput = card.querySelector('#sandbox-res-input');
2186            const resultPayload = resultInput.value;
2187
2188            // Mark as executed
2189            card.dataset.executed = "true";
2190            
2191            // Replace execute section with a static badge
2192            const section = card.querySelector('.tool-result-section');
2193            section.innerHTML = `
2194                <div class="tool-executed-badge">
2195                    <i class="fa-solid fa-clipboard-check"></i> Executed Result returned successfully.
2196                </div>
2197                <div class="tool-call-code" style="color:var(--accent-secondary); margin-top:8px;">${resultPayload}</div>
2198            `;
2199
2200            // Append mock result to backend payload context
2201            sandboxHistory.push({
2202                "role": "tool",
2203                "content": resultPayload
2204            });
2205
2206            // Start streaming the next assistant output response
2207            const bubble = appendMessageBubble('assistant', 'Synthesizing final response...', true);
2208            let fullText = "";
2209
2210            try {
2211                toggleInputButtons(true);
2212                const chat = chats.find(c => c.id === activeChatId);
2213                const params = chat ? chat.params : { temperature: 0.2, top_k: 80, repetition_penalty: 1.05, max_new_tokens: 2048 };
2214                
2215                // Fetch next token predictions
2216                const job = gradioClient.submit("/chat", {
2217                    message: "", // Empty prompt since we're continuing the tool-history loop
2218                    history_json: JSON.stringify(sandboxHistory),
2219                    system_prompt: `List of tools: [{"name": "get_candidate_status", "description": "Retrieves the current status of a candidate", "parameters": {"candidate_id": "string"}}
2219, {"name": "get_weather", "description": "Queries weather conditions", "parameters": {"location": "string"}}]`,
2220                    temperature: params.temperature,
2221                    top_k: params.top_k,
2222                    repetition_penalty: params.repetition_penalty,
2223                    max_new_tokens: params.max_new_tokens
2224                });
2225                
2226                activeJob = job;
2227
2228                for await (const event of job) {
2229                    if (event.type === "data") {
2230                        fullText = event.data[0];
2231                        updateAssistantBubble(bubble, fullText, true);
2232                    }
2233                }
2234                
2235                activeJob = null;
2236                toggleInputButtons(false);
2237                
2238                // Add output answer to sandbox memory
2239                sandboxHistory.push({
2240                    "role": "assistant",
2241                    "content": fullText
2242                });
2243
2244            } catch (err) {
2245                console.error("Sandbox resumption failed:", err);
2246                bubble.querySelector('.message-content').innerText = "Offline Mode Mock: Synthesis complete.";
2247                toggleInputButtons(false);
2248            }
2249        }
2250
2251        /* --- Send Chat Prompt Flow --- */
2252        window.submitUserPrompt = async function() {
2253            const inputField = document.getElementById('chat-input');
2254            const prompt = inputField.value.trim();
2255            if (!prompt) return;
2256
2257            // Reset Input height
2258            inputField.value = '';
2259            inputField.style.height = '44px';
2260
2261            const chat = chats.find(c => c.id === activeChatId);
2262            if (!chat) return;
2263
2264            // Rename discussion if it's default
2265            if (chat.history.length === 0) {
2266                chat.title = prompt.substring(0, 24) + (prompt.length > 24 ? '...' : '');
2267                renderChatList();
2268            }
2269
2270            // Append User message
2271            appendMessageBubble('user', prompt);
2272            
2273            // Save to memory
2274            chat.history.push({"role": "user", "content": prompt});
2275            saveChatsToStorage();
2276
2277            // Setup streaming assistant bubble
2278            const bubble = appendMessageBubble('assistant', 'Thinking...', true);
2279            let fullText = "";
2280
2281            if (!gradioClient) {
2282                // If server is not running locally, mock a premium response
2283                setTimeout(() => {
2284                    fullText = "<think>\nUser has queried LFM2.5 locally.\nI will generate a premium welcome/offline message explaining edge intelligence.\n</think>\nHello! I am **Liquid LFM2.5**, running inside a custom **gradio.Server** environment.\n\nIt seems I am currently running in offline mock-up mode, or my local PyTorch/ZeroGPU server is still loading models on Hugging Face.\n\n### Model Key Details:\n- **Parameters**: 8.3 Billion total / 1.5 Billion active MoE structure.\n- **Architecture**: Liquid Neural Networks (LNN) + 18 Double-gated LIV convolutions + 6 GQA layers.\n- **Context**: 131,072 max length.\n\nOnce the backend completes cold-start initialization, my live inference streaming will function here!";
2285                    updateAssistantBubble(bubble, fullText, false);
2286                }, 1000);
2287                return;
2288            }
2289
2290            try {
2291                toggleInputButtons(true);
2292                
2293                // Submit to gradio client
2294                const job = gradioClient.submit("/chat", {
2295                    message: prompt,
2296                    history_json: JSON.stringify(chat.history.slice(0, -1)), // Send preceding history
2297                    system_prompt: chat.systemPrompt,
2298                    temperature: chat.params.temperature,
2299                    top_k: chat.params.top_k,
2300                    repetition_penalty: chat.params.repetition_penalty,
2301                    max_new_tokens: chat.params.max_new_tokens
2302                });
2303
2304                activeJob = job;
2305
2306                for await (const event of job) {
2307                    if (event.type === "data") {
2308                        fullText = event.data[0];
2309                        updateAssistantBubble(bubble, fullText, true);
2310                    }
2311                }
2312
2313                activeJob = null;
2314                toggleInputButtons(false);
2315
2316                // Add to history
2317                chat.history.push({"role": "assistant", "content": fullText});
2318                saveChatsToStorage();
2319
2320            } catch (err) {
2321                console.error("Inference call failed:", err);
2322                bubble.querySelector('.message-content').innerHTML = `<span style="color:#ef4444;"><i class="fa-solid fa-triangle-exclamation"></i>
2322 Inference Connection Error: ${err.message || err}</span>`;
2323                toggleInputButtons(false);
2324            }
2325        }
2326
2327        /* --- Tool Sandbox prompt submission --- */
2328        window.submitSandboxPrompt = async function() {
2329            const inputField = document.getElementById('sandbox-input');
2330            const prompt = inputField.value.trim();
2331            if (!prompt) return;
2332
2333            inputField.value = '';
2334            inputField.style.height = '44px';
2335
2336            // Reset Sandbox context
2337            sandboxHistory = [];
2338            document.getElementById('sandbox-history-scroll').innerHTML = '';
2339
2340            // User input
2341            appendMessageBubble('user', prompt);
2342            sandboxHistory.push({"role": "user", "content": prompt});
2343
2344            // Start assistant response
2345            const bubble = appendMessageBubble('assistant', 'Constructing tool call...', true);
2346            let fullText = "";
2347
2348            if (!gradioClient) {
2349                setTimeout(() => {
2350                    fullText = "Checking local indexes... <|tool_call_start|>[get_candidate_status(candidate_id=\"12345\")]<|tool_call_end|>";
2351                    updateAssistantBubble(bubble, fullText, false);
2352                    sandboxHistory.push({"role": "assistant", "content": fullText});
2353                }, 1000);
2354                return;
2355            }
2356
2357            try {
2358                toggleInputButtons(true);
2359                const chat = chats.find(c => c.id === activeChatId);
2360                const params = chat ? chat.params : { temperature: 0.2, top_k: 80, repetition_penalty: 1.05, max_new_tokens: 2048 };
2361
2362                // Build agent system prompt defining active tools
2363                const agentSystemPrompt = `List of tools: [{"name": "get_candidate_status", "description": "Retrieves the recruitment status of a candidate in the recruitment process", "parameters": {"type": "object", "properties": {"candidate_id": {"type": "string", "description": "Unique identifier for the candidate"}}, "required": ["candidate_id"]}}, {"name": "get_weather", "description": "Queries weather conditions", "parameters": {"type": "object", "properties": {"location": {"type": "string", "description": "Name of the city"}}, "required": ["location"]}}]`;
2364
2365                const job = gradioClient.submit("/chat", {
2366                    message: prompt,
2367                    history_json: JSON.stringify([]), // Fresh agent context
2368                    system_prompt: agentSystemPrompt,
2369                    temperature: params.temperature,
2370                    top_k: params.top_k,
2371                    repetition_penalty: params.repetition_penalty,
2372                    max_new_tokens: params.max_new_tokens
2373                });
2374
2375                activeJob = job;
2376
2377                for await (const event of job) {
2378                    if (event.type === "data") {
2379                        fullText = event.data[0];
2380                        updateAssistantBubble(bubble, fullText, true);
2381                    }
2382                }
2383
2384                activeJob = null;
2385                toggleInputButtons(false);
2386                sandboxHistory.push({"role": "assistant", "content": fullText});
2387
2388            } catch (err) {
2389                console.error("Sandbox initial call failed:", err);
2390                bubble.querySelector('.message-content').innerText = `Error: ${err.message || err}`;
2391                toggleInputButtons(false);
2392            }
2393        }
2394
2395        // Toggle visibility of send / stop buttons during streaming
2396        function toggleInputButtons(isGenerating) {
2397            const sendBtn = document.getElementById('send-button');
2398            const stopBtn = document.getElementById('stop-button');
2399            const sandboxSend = document.getElementById('sandbox-send-button');
2400            const sandboxStop = document.getElementById('sandbox-stop-button');
2401
2402            if (isGenerating) {
2403                if (sendBtn) sendBtn.style.display = 'none';
2404                if (stopBtn) stopBtn.style.display = 'flex';
2405                if (sandboxSend) sandboxSend.style.display = 'none';
2406                if (sandboxStop) sandboxStop.style.display = 'flex';
2407            } else {
2408                if (sendBtn) sendBtn.style.display = 'flex';
2409                if (stopBtn) stopBtn.style.display = 'none';
2410                if (sandboxSend) sandboxSend.style.display = 'flex';
2411                if (sandboxStop) sandboxStop.style.display = 'none';
2412            }
2413        }
2414
2415        window.cancelActiveGeneration = function() {
2416            if (activeJob) {
2417                activeJob.cancel();
2418                activeJob = null;
2419            }
2420            toggleInputButtons(false);
2421        }
2422
2423        /* --- Key press triggers --- */
2424        window.handleInputKeyDown = function(event) {
2425            if (event.key === 'Enter' && !event.shiftKey) {
2426                event.preventDefault();
2427                submitUserPrompt();
2428            }
2429        }
2430
2431        window.handleSandboxInputKeyDown = function(event) {
2432            if (event.key === 'Enter' && !event.shiftKey) {
2433                event.preventDefault();
2434                submitSandboxPrompt();
2435            }
2436        }
2437
2438        window.focusChatInput = function() {
2439            const input = document.getElementById('chat-input');
2440            if (input) input.focus();
2441        }
2442
2443        window.focusSandboxInput = function() {
2444            const input = document.getElementById('sandbox-input');
2445            if (input) input.focus();
2446        }
2447    </script>
2447
2448</body>
2449</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.