Jaspers Hub

jaspers / agents

pluginOfficialReviewed★ 0↓ 0

Research Agents: Lets you define research agents that chat and answer with citations from SEC filings, your documents, and the web, via Jaspers' research-store service.

17 KB
1/* The agents view's own CSS. A plugin view is an iframe of its own, so there is no Tailwind here:
2 the house style by hand. Colours are the app's theme variables with the light value as fallback,
3 so the view follows the app's light and dark. Square everything, one grey line, muted secondary text. */
4
5.ag-root {
6 display: flex;
7 height: 100%;
8 width: 100%;
9 background: var(--jaspers-background, #fff);
10 color: var(--jaspers-foreground, #171717);
11 font: 13px/1.45 var(--jaspers-font-sans, system-ui, -apple-system, sans-serif);
12}
13
14.ag-side {
15 flex: 0 0 280px;
16 display: flex;
17 flex-direction: column;
18 min-width: 0;
19 border-right: 1px solid var(--jaspers-border, #e5e5e5);
20}
21
22.ag-main {
23 flex: 1 1 auto;
24 display: flex;
25 flex-direction: column;
26 min-width: 0;
27}
28
29.ag-bar {
30 flex: 0 0 auto;
31 display: flex;
32 align-items: center;
33 gap: 8px;
34 min-height: 32px;
35 padding: 6px 10px;
36 border-bottom: 1px solid var(--jaspers-border, #e5e5e5);
37}
38
39.ag-title,
40.ag-name {
41 font-weight: 600;
42}
43
44.ag-spacer {
45 flex: 1 1 auto;
46}
47
48.ag-muted {
49 color: var(--jaspers-muted-foreground, #737373);
50}
51
52.ag-error {
53 color: var(--jaspers-destructive, #b91c1c);
54}
55
56.ag-empty {
57 padding: 12px 10px;
58}
59
60.ag-list {
61 flex: 1 1 auto;
62 margin: 0;
63 padding: 0;
64 list-style: none;
65 overflow-y: auto;
66}
67
68.ag-agent {
69 display: flex;
70 align-items: flex-start;
71 border-bottom: 1px solid var(--jaspers-border, #e5e5e5);
72}
73
74.ag-pick {
75 flex: 1 1 auto;
76 display: flex;
77 gap: 8px;
78 min-width: 0;
79 padding: 8px 10px;
80 border: 0;
81 background: none;
82 color: inherit;
83 font: inherit;
84 text-align: left;
85 cursor: pointer;
86}
87
88.ag-pick:hover {
89 background: var(--jaspers-muted, #f5f5f5);
90}
91
92.ag-swatch {
93 flex: 0 0 auto;
94 width: 10px;
95 height: 10px;
96 margin-top: 4px;
97}
98
99.ag-body {
100 min-width: 0;
101}
102
103.ag-line {
104 display: block;
105 overflow: hidden;
106 text-overflow: ellipsis;
107 white-space: nowrap;
108}
109
110.ag-button {
111 margin-left: auto;
112 padding: 2px 10px;
113 border: 1px solid var(--jaspers-primary, #171717);
114 background: var(--jaspers-primary, #171717);
115 color: var(--jaspers-primary-foreground, #fff);
116 font: inherit;
117 cursor: pointer;
118}
119
120.ag-button:disabled {
121 opacity: 0.5;
122 cursor: default;
123}
124
125.ag-link {
126 padding: 8px 10px;
127 border: 0;
128 background: none;
129 color: var(--jaspers-muted-foreground, #737373);
130 font: inherit;
131 cursor: pointer;
132}
133
134.ag-bar .ag-link {
135 padding: 0;
136}
137
138.ag-link:hover {
139 color: var(--jaspers-foreground, #171717);
140}
141
142.ag-danger {
143 color: var(--jaspers-destructive, #b91c1c);
144}
145
146.ag-thread {
147 flex: 1 1 auto;
148 overflow-y: auto;
149 padding: 10px;
150}
151
152.ag-user {
153 margin: 0 0 10px auto;
154 max-width: 80%;
155 width: fit-content;
156 padding: 6px 10px;
157 background: var(--jaspers-muted, #f5f5f5);
158 white-space: pre-wrap;
159}
160
161.ag-answer {
162 margin-bottom: 14px;
163}
164
165.ag-head {
166 display: flex;
167 align-items: center;
168 gap: 6px;
169 margin-bottom: 4px;
170}
171
172.ag-head .ag-swatch {
173 margin-top: 0;
174}
175
176.ag-text {
177 white-space: pre-wrap;
178 overflow-wrap: anywhere;
179}
180
181.ag-searches {
182 margin-bottom: 6px;
183}
184
185.ag-searches summary {
186 cursor: pointer;
187}
188
189.ag-search {
190 margin: 6px 0 0 12px;
191}
192
193.ag-query {
194 font-style: italic;
195}
196
197.ag-passage {
198 margin: 4px 0 0;
199 padding-left: 8px;
200 border-left: 2px solid var(--jaspers-border, #e5e5e5);
201 font-size: 12px;
202}
203
204/* The message box: a box of its own, raised off the tile's foot so the tile's handle stays clear of it. */
205.ag-composer {
206 position: relative;
207 flex: 0 0 auto;
208 padding: 8px 14px 34px;
209}
210
211.ag-compose-box {
212 border: 1px solid var(--jaspers-border, #e5e5e5);
213 background: var(--jaspers-background, #fff);
214}
215
216.ag-compose-box:focus-within {
217 border-color: var(--jaspers-muted-foreground, #737373);
218}
219
220/* Under the words: attachments at the left, the microphone at the right. */
221.ag-compose-tools {
222 display: flex;
223 align-items: center;
224 gap: 6px;
225 padding: 0 6px 6px;
226}
227
228.ag-input {
229 display: block;
230 box-sizing: border-box;
231 width: 100%;
232 padding: 8px 10px;
233 border: 0;
234 resize: none;
235 background: var(--jaspers-background, #fff);
236 color: inherit;
237 font: inherit;
238 outline: none;
239}
240
241.ag-offer {
242 position: absolute;
243 bottom: 100%;
244 left: 0;
245 margin: 0;
246 padding: 0;
247 min-width: 200px;
248 list-style: none;
249 border: 1px solid var(--jaspers-border, #e5e5e5);
250 background: var(--jaspers-background, #fff);
251}
252
253.ag-offer button {
254 display: block;
255 width: 100%;
256 padding: 4px 10px;
257 border: 0;
258 background: none;
259 color: inherit;
260 font: inherit;
261 text-align: left;
262 cursor: pointer;
263}
264
265.ag-offer button:hover {
266 background: var(--jaspers-muted, #f5f5f5);
267}
268
269.ag-failure {
270 padding: 6px 10px;
271 border-top: 1px solid var(--jaspers-border, #e5e5e5);
272 color: var(--jaspers-destructive, #b91c1c);
273}
274
275.ag-form {
276 flex: 1 1 auto;
277 overflow-y: auto;
278 padding: 10px;
279}
280
281.ag-field {
282 display: flex;
283 flex-direction: column;
284 gap: 2px;
285 margin-bottom: 10px;
286}
287
288.ag-label {
289 font-weight: 600;
290}
291
292.ag-hint {
293 font-size: 12px;
294}
295
296.ag-field input,
297.ag-field textarea,
298.ag-field select {
299 box-sizing: border-box;
300 width: 100%;
301 padding: 4px 6px;
302 border: 1px solid var(--jaspers-border, #e5e5e5);
303 border-radius: 0;
304 background: var(--jaspers-background, #fff);
305 color: inherit;
306 font: inherit;
307}
308
309.ag-field textarea {
310 resize: vertical;
311}
312
313.ag-section {
314 margin: 14px 0 10px;
315 padding-top: 10px;
316 border-top: 1px solid var(--jaspers-border, #e5e5e5);
317}
318
319.ag-actions {
320 display: flex;
321 align-items: center;
322 gap: 8px;
323}
324
325.ag-actions .ag-button {
326 margin-left: 0;
327}
328
329.ag-doc {
330 flex: 1 1 auto;
331 min-width: 0;
332 padding: 6px 10px;
333}
334
335.ag-note {
336 padding: 6px 10px;
337 border-top: 1px solid var(--jaspers-border, #e5e5e5);
338 font-size: 12px;
339}
340
341/* A folded field: its line, which opens it, names what it holds. */
342.ag-fold > summary {
343 overflow: hidden;
344 text-overflow: ellipsis;
345 white-space: nowrap;
346 cursor: pointer;
347}
348
349.ag-fold-body {
350 display: flex;
351 flex-direction: column;
352 gap: 4px;
353 padding: 4px 0 0 14px;
354}
355
356.ag-docs {
357 display: flex;
358 flex-direction: column;
359 gap: 2px;
360}
361
362.ag-field .ag-check {
363 display: flex;
364 align-items: center;
365 gap: 6px;
366}
367
368.ag-field .ag-check input {
369 width: auto;
370}
371
372/* An answer's Markdown, sized for the chat: the markdown plugin's rules, smaller. */
373.ag-md {
374 overflow-wrap: anywhere;
375}
376
377.ag-md :where(p, ul, ol, pre, blockquote, .ag-md-table, .ag-md-footnote) {
378 margin: 8px 0 0;
379}
380
381.ag-md :where(h1, h2, h3, h4, h5, h6) {
382 margin: 12px 0 0;
383 font-weight: 600;
384 line-height: 1.35;
385}
386
387.ag-md :where(*) > :first-child,
388.ag-md > :first-child {
389 margin-top: 0;
390}
391
392.ag-md h1 {
393 font-size: 16px;
394}
395
396.ag-md h2 {
397 font-size: 15px;
398}
399
400.ag-md :where(h3, h4, h5, h6) {
401 font-size: 13px;
402}
403
404/* A line break inside a paragraph stays one. */
405.ag-md :where(p, li, th, td) {
406 white-space: pre-line;
407}
408
409.ag-md .ag-md-html {
410 white-space: pre-wrap;
411}
412
413.ag-md ul {
414 padding-left: 18px;
415 list-style: square;
416}
417
418.ag-md ol {
419 padding-left: 22px;
420 list-style: decimal;
421}
422
423.ag-md li + li,
424.ag-md li > :where(ul, ol) {
425 margin-top: 2px;
426}
427
428.ag-md li::marker {
429 color: var(--jaspers-muted-foreground, #737373);
430}
431
432.ag-md .ag-md-task-item {
433 list-style: none;
434}
435
436.ag-md-task {
437 display: inline-block;
438 width: 1.3em;
439 margin-left: -1.3em;
440 color: var(--jaspers-muted-foreground, #737373);
441}
442
443.ag-md code {
444 padding: 0 4px;
445 background: var(--jaspers-muted, #f5f5f5);
446 font-family: var(--jaspers-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
447 font-size: 0.9em;
448}
449
450.ag-md pre {
451 padding: 6px 10px;
452 background: var(--jaspers-muted, #f5f5f5);
453 overflow-x: auto;
454 font: 12px/1.5 var(--jaspers-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
455}
456
457.ag-md pre code {
458 padding: 0;
459 background: none;
460 font-size: inherit;
461}
462
463.ag-md blockquote {
464 margin-left: 0;
465 margin-right: 0;
466 padding-left: 10px;
467 border-left: 2px solid var(--jaspers-border, #e5e5e5);
468 color: var(--jaspers-muted-foreground, #737373);
469}
470
471.ag-md hr {
472 margin: 12px 0;
473 border: 0;
474 border-top: 1px solid var(--jaspers-border, #e5e5e5);
475}
476
477.ag-md a {
478 color: inherit;
479 text-decoration: underline;
480 text-decoration-color: var(--jaspers-muted-foreground, #737373);
481 text-underline-offset: 2px;
482 cursor: pointer;
483}
484
485.ag-md a:hover {
486 text-decoration-color: var(--jaspers-foreground, #171717);
487}
488
489.ag-md-table {
490 overflow-x: auto;
491}
492
493.ag-md-table table {
494 border-collapse: collapse;
495 font-variant-numeric: tabular-nums;
496}
497
498.ag-md-table th,
499.ag-md-table td {
500 padding: 4px 10px;
501 border-bottom: 1px solid var(--jaspers-border, #e5e5e5);
502 vertical-align: top;
503}
504
505.ag-md-table th {
506 font-weight: 600;
507 text-align: left;
508}
509
510.ag-md-table :where(th, td):first-child {
511 padding-left: 0;
512}
513
514.ag-md-footnote {
515 display: grid;
516 grid-template-columns: auto 1fr;
517 column-gap: 6px;
518 color: var(--jaspers-muted-foreground, #737373);
519 font-size: 12px;
520}
521
522.ag-row {
523 display: flex;
524 gap: 6px;
525}
526
527.ag-small {
528 flex: 1 1 auto;
529 min-width: 0;
530 padding: 2px 6px;
531 border: 1px solid var(--jaspers-border, #e5e5e5);
532 border-radius: 0;
533 background: var(--jaspers-background, #fff);
534 color: inherit;
535 font: inherit;
536}
537
538.ag-row .ag-button {
539 margin-left: 0;
540}
541
542.ag-step {
543 margin-bottom: 16px;
544}
545
546.ag-step-body {
547 display: flex;
548 flex-direction: column;
549 gap: 6px;
550 margin: 4px 0 0 18px;
551}
552
553.ag-command {
554 gap: 8px;
555 align-items: center;
556}
557
558.ag-command code {
559 flex: 1;
560 min-width: 0;
561 padding: 6px 10px;
562 background: var(--jaspers-muted, #f5f5f5);
563 overflow-x: auto;
564 white-space: nowrap;
565 user-select: all;
566 font: 12px/1.5 var(--jaspers-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
567}
568
569.ag-done {
570 color: var(--jaspers-foreground, #171717);
571}
572
573.ag-gap {
574 margin-top: 4px;
575}
576
577.ag-model {
578 display: flex;
579 flex-direction: column;
580 gap: 3px;
581 max-width: 520px;
582}
583
584.ag-meter {
585 height: 6px;
586 background: var(--jaspers-muted, #f5f5f5);
587 border: 1px solid var(--jaspers-border, #e5e5e5);
588}
589
590.ag-meter-fill {
591 height: 100%;
592 background: var(--jaspers-primary, #171717);
593 transition: width 300ms;
594}
595
596/* A part of the side panel: its bar, then its body, which scrolls on its own. */
597.ag-panel {
598 flex: 0 0 auto;
599 display: flex;
600 flex-direction: column;
601 min-height: 0;
602}
603
604/* Every section's bar is the same height, its chevron and title in the same place. */
605.ag-panel > .ag-bar {
606 box-sizing: border-box;
607 height: 44px;
608 padding: 0 10px;
609}
610
611/* The open section is as tall as what it holds, so the bars after it stay close under it; past the
612 room there is, it scrolls. */
613.ag-panel.ag-open {
614 flex: 0 1 auto;
615}
616
617.ag-panel-body {
618 flex: 1 1 auto;
619 display: flex;
620 flex-direction: column;
621 min-height: 0;
622 overflow-y: auto;
623}
624
625/* A citation in an answer, and the document window it opens. The mark is the plugin's own colour:
626 its dark value is set at the end. */
627.ag-cite {
628 display: inline-block;
629 margin: 0 1px;
630 padding: 0 4px;
631 border: 1px solid var(--jaspers-border, #e5e5e5);
632 background: var(--jaspers-muted, #f5f5f5);
633 color: var(--jaspers-foreground, #171717);
634 font: 11px/16px var(--jaspers-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
635 vertical-align: 1px;
636 cursor: pointer;
637}
638
639.ag-cite:hover {
640 border-color: var(--jaspers-foreground, #171717);
641}
642
643.ag-cite-missing {
644 color: var(--jaspers-destructive, #b91c1c);
645 cursor: default;
646}
647
648.ag-docwin {
649 position: fixed;
650 top: 12px;
651 right: 12px;
652 bottom: 12px;
653 z-index: 10;
654 display: flex;
655 flex-direction: column;
656 width: min(760px, calc(100% - 24px));
657 border: 1px solid var(--jaspers-border, #e5e5e5);
658 background: var(--jaspers-background, #fff);
659 box-shadow: 0 8px 28px rgba(0, 0, 0, 0.18);
660}
661
662.ag-docbody {
663 flex: 1 1 auto;
664 overflow-y: auto;
665 padding: 8px 14px 24px;
666}
667
668.ag-docsection {
669 border-bottom: 1px solid var(--jaspers-border, #e5e5e5);
670 padding: 4px 0 8px;
671}
672
673.ag-dochead {
674 display: flex;
675 align-items: baseline;
676 gap: 6px;
677 width: 100%;
678 padding: 4px 0;
679 border: 0;
680 background: none;
681 color: inherit;
682 font: inherit;
683 text-align: left;
684 cursor: pointer;
685}
686
687.ag-mark {
688 margin: 0 -6px;
689 padding: 2px 6px;
690 background: var(--ag-mark, #fff3bf);
691 border-left: 3px solid var(--ag-mark-edge, #e0a800);
692}
693
694@media (prefers-color-scheme: dark) {
695 .ag-mark {
696 --ag-mark: #3d3200;
697 --ag-mark-edge: #c89400;
698 }
699}
700
701.ag-audit {
702 margin-top: 4px;
703 font-size: 12px;
704}
705
706/* The paperclip beside the message box and its menu, which opens upward. */
707.ag-attach {
708 position: relative;
709 flex: 0 0 auto;
710}
711
712.ag-icon {
713 display: grid;
714 place-items: center;
715 width: 28px;
716 height: 28px;
717 border: 1px solid transparent;
718 background: none;
719 color: var(--jaspers-muted-foreground, #737373);
720 cursor: pointer;
721}
722
723.ag-icon.ag-danger,
724.ag-icon.ag-danger:hover {
725 color: var(--jaspers-destructive, #b91c1c);
726}
727
728/* A row's icons sit at its right, level with its first line. */
729.ag-agent > .ag-icon {
730 margin-top: 4px;
731}
732
733/* The bars' padding, so a row's last icon lines up under its bar's +. */
734.ag-agent > .ag-icon:last-of-type {
735 margin-right: 10px;
736}
737
738/* A list's + sits at the end of its bar, where a button would. */
739.ag-add {
740 margin-left: auto;
741}
742
743/* Folded, the side panel is only the button that unfolds it. */
744.ag-side.ag-folded {
745 flex-basis: 40px;
746 align-items: center;
747 padding-top: 6px;
748}
749
750.ag-icon:hover,
751.ag-attach:hover > .ag-icon {
752 border-color: var(--jaspers-border, #e5e5e5);
753 color: var(--jaspers-foreground, #171717);
754}
755
756.ag-menu {
757 position: absolute;
758 bottom: calc(100% - 4px);
759 left: 8px;
760 z-index: 5;
761 min-width: 200px;
762 border: 1px solid var(--jaspers-border, #e5e5e5);
763 background: var(--jaspers-background, #fff);
764 box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
765}
766
767.ag-menu-item {
768 position: relative;
769 display: flex;
770 align-items: center;
771 gap: 6px;
772 width: 100%;
773 padding: 6px 10px;
774 border: 0;
775 background: none;
776 color: inherit;
777 font: inherit;
778 text-align: left;
779 cursor: pointer;
780}
781
782.ag-menu-item:hover {
783 background: var(--jaspers-muted, #f5f5f5);
784}
785
786.ag-submenu {
787 bottom: 0;
788 left: 100%;
789 min-width: 300px;
790 max-height: 320px;
791 overflow-y: auto;
792 cursor: default;
793}
794
795.ag-menu-row {
796 display: flex;
797 align-items: center;
798 gap: 8px;
799 padding: 4px 4px 4px 10px;
800}
801
802.ag-menu-row .ag-line {
803 flex: 1 1 auto;
804 min-width: 0;
805}
806
807/* A company: its name and buttons, then how far it is in words and as a bar, each across the row. */
808.ag-company {
809 flex-wrap: wrap;
810 padding-bottom: 8px;
811}
812
813/* A zero basis keeps the name on the buttons' line, however long it is. */
814.ag-company > .ag-doc {
815 flex: 1 1 0;
816}
817
818.ag-company > .ag-whole,
819.ag-company > .ag-meter {
820 flex: 0 0 calc(100% - 20px);
821 margin: 0 10px;
822}
823
824.ag-company > .ag-meter {
825 margin-top: 4px;
826}
827
828/* The skills an answer loaded and the skill files it read, above its searches. */
829.ag-skills {
830 margin: 2px 0 4px;
831}
832
833/* While an answer is written: the model's latest note, then the step it is on, a light passing over it. */
834.ag-working {
835 display: flex;
836 flex-direction: column;
837 gap: 2px;
838 margin-top: 4px;
839}
840
841.ag-thought {
842 color: var(--jaspers-muted-foreground, #737373);
843 font-style: italic;
844 font-size: 12px;
845}
846
847.ag-shimmer {
848 width: fit-content;
849 background: linear-gradient(
850 90deg,
851 var(--jaspers-muted-foreground, #737373) 0%,
852 var(--jaspers-muted-foreground, #737373) 35%,
853 var(--jaspers-foreground, #171717) 50%,
854 var(--jaspers-muted-foreground, #737373) 65%,
855 var(--jaspers-muted-foreground, #737373) 100%
856 );
857 background-size: 250% 100%;
858 -webkit-background-clip: text;
859 background-clip: text;
860 color: transparent;
861 animation: ag-shimmer 1.8s linear infinite;
862}
863
864@keyframes ag-shimmer {
865 from {
866 background-position: 100% 0;
867 }
868 to {
869 background-position: -150% 0;
870 }
871}
872
873@media (prefers-reduced-motion: reduce) {
874 .ag-shimmer {
875 animation: none;
876 background: none;
877 color: var(--jaspers-muted-foreground, #737373);
878 }
879}
880
881/* Under a finished answer: copy it. */
882.ag-answer-foot {
883 display: flex;
884 margin-top: 2px;
885 margin-left: -6px;
886}
887
888/* The companies, each a chip, laid out in rows that wrap. */
889.ag-chips {
890 display: flex;
891 flex-wrap: wrap;
892 align-content: flex-start;
893 gap: 6px;
894 padding: 10px;
895}
896
897.ag-chip-wrap {
898 display: inline-flex;
899}
900
901.ag-chip {
902 position: relative;
903 display: inline-flex;
904 align-items: center;
905 gap: 6px;
906 padding: 5px 10px 6px;
907 overflow: hidden;
908 border: 1px solid var(--jaspers-border, #e5e5e5);
909 background: var(--jaspers-background, #fff);
910 color: inherit;
911 font: inherit;
912 font-weight: 600;
913 cursor: default;
914}
915
916.ag-chip:hover,
917.ag-chip-open {
918 background: var(--jaspers-muted, #f5f5f5);
919}
920
921/* Something failed: the card says what. */
922.ag-chip-mark {
923 width: 6px;
924 height: 6px;
925 background: var(--jaspers-destructive, #b91c1c);
926}
927
928/* How far reading or embedding is, along the chip's foot. */
929.ag-chip-bar {
930 position: absolute;
931 right: 0;
932 bottom: 0;
933 left: 0;
934 height: 2px;
935 background: var(--jaspers-muted, #f5f5f5);
936}
937
938.ag-chip-bar > span {
939 display: block;
940 height: 100%;
941 background: var(--jaspers-primary, #171717);
942}
943
944.ag-agent.ag-chip-card {
945 position: fixed;
946 z-index: 20;
947 box-sizing: border-box;
948 padding-top: 2px;
949 border: 1px solid var(--jaspers-border, #e5e5e5);
950 background: var(--jaspers-background, #fff);
951 box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
952}
953
954/* The microphone, and what it is doing, at the right under the words. */
955.ag-mic {
956 display: inline-flex;
957 align-items: center;
958 gap: 8px;
959 min-width: 0;
960}
961
962.ag-mic-note {
963 overflow: hidden;
964 color: var(--jaspers-muted-foreground, #737373);
965 font-size: 12px;
966 text-overflow: ellipsis;
967 white-space: nowrap;
968}
969
970.ag-mic-on,
971.ag-mic-on:hover {
972 color: var(--jaspers-destructive, #b91c1c);
973}