@saltcorn/agents 0.8.2 → 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/agent-view.js CHANGED
@@ -54,6 +54,7 @@ const MarkdownIt = require("markdown-it"),
54
54
  md = new MarkdownIt({ html: true, breaks: true, linkify: true });
55
55
  const { isWeb, escapeHtml } = require("@saltcorn/data/utils");
56
56
  const path = require("path");
57
+ const fs = require("fs");
57
58
 
58
59
  const configuration_workflow = (req) =>
59
60
  new Workflow({
@@ -259,6 +260,11 @@ const realTimeCollabScript = (viewname, rndid, layout) => {
259
260
  );
260
261
  };
261
262
 
263
+ const agents_css = fs.readFileSync(
264
+ path.resolve(__dirname, "agents.css"),
265
+ "utf8",
266
+ );
267
+
262
268
  const run = async (
263
269
  table_id,
264
270
  viewname,
@@ -309,13 +315,13 @@ const run = async (
309
315
 
310
316
  const initial_q = state.run_id ? undefined : state._q;
311
317
  if (state.run_id) {
312
- const run = prevRuns
313
- ? prevRuns.find((r) => r.id == state.run_id)
314
- : await WorkflowRun.findOne({
315
- trigger_id: action.id,
316
- ...(shared ? {} : { started_by: req.user?.id }),
317
- id: state.run_id,
318
- });
318
+ let run = prevRuns ? prevRuns.find((r) => r.id == state.run_id) : null;
319
+ if (!run)
320
+ run = await WorkflowRun.findOne({
321
+ trigger_id: action.id,
322
+ ...(shared ? {} : { started_by: req.user?.id }),
323
+ id: state.run_id,
324
+ });
319
325
  const interactMarkups = [];
320
326
  if (run.context.html_interactions) {
321
327
  interactMarkups.push(...run.context.html_interactions);
@@ -656,300 +662,7 @@ const run = async (
656
662
  div({ id: "copilotinteractions" }, runInteractions),
657
663
  stream ? div({ class: "next_response_scratch" }) : "",
658
664
  input_form,
659
- style(
660
- `div.interaction-segment:not(:first-child) {border-top: 1px solid #e7e7e7; }
661
- div.interaction-segment {padding-top: 5px;padding-bottom: 5px;}
662
- div.interaction-segment p {margin-bottom: 0px;}
663
- div.interaction-segment div.card {margin-top: 0.5rem;}
664
- div.interaction-segment.to-right {
665
- display: flex;
666
- flex-direction: row-reverse;
667
- }
668
- div.interaction-segment.to-right div.badgewrap {
669
- display: flex;
670
- flex-direction: row-reverse;
671
- }
672
- div.prevcopilotrun:hover {cursor: pointer; background-color: var(--tblr-secondary-bg-subtle, var(--bs-secondary-bg-subtle, gray));}
673
- div.prevcopilotrun i.fa-trash-alt {display: none;}
674
- div.prevcopilotrun:hover i.fa-trash-alt {display: block;}
675
- .copilot-entry .submit-button:hover { cursor: pointer}
676
- .copilot-entry span.attach_agent_image_wrap i:hover { cursor: pointer}
677
-
678
- .copilot-entry .submit-button {
679
- position: relative;
680
- top: -1.8rem;
681
- left: 0.1rem;
682
- }
683
- .copilot-entry #audioinputicon {
684
- position: relative;
685
- top: -1.8rem;
686
- right: 0.7rem;
687
- cursor: pointer;
688
- float: right;
689
- }
690
- .copilot-entry .debugicon {
691
- position: relative;
692
- top: -1.8rem;
693
- left: 0.1rem;
694
- cursor: pointer;
695
- }
696
- .copilot-entry .cancelbtn {
697
- position: relative;
698
- top: -1.8rem;
699
- left: 0.1rem;
700
- cursor: pointer;
701
- }
702
- .copilot-entry .skill-form-widget {
703
- position: relative;
704
- top: -2rem;
705
- left: 0.4rem;
706
- display: inline;
707
- }
708
- .session-open-sessions, .open-prev-runs {
709
- cursor: pointer;
710
- }
711
- .copilot-entry span.attach_agent_image_wrap {
712
- position: relative;
713
- top: -1.8rem;
714
- left: 0.2rem;
715
- }
716
- .copilot-entry.dragover {
717
- outline: 2px dashed var(--tblr-primary, #0054a6);
718
- outline-offset: -2px;
719
- background: var(--tblr-primary-bg-subtle, rgba(0, 84, 166, 0.05));
720
- border-radius: 0.25rem;
721
- }
722
- .copilot-entry .explainer {
723
- position: relative;
724
- top: -1.2rem;
725
- display: block;
726
- }
727
- .col-0 {
728
- width: 0%
729
- }
730
- .copilot-entry {margin-bottom: -1.25rem; margin-top: 1rem;}
731
- p.prevrun_content {
732
- white-space: nowrap;
733
- overflow: hidden;
734
- margin-bottom: 0px;
735
- display: block;
736
- text-overflow: ellipsis;}
737
- /* Typing / Waiting Indicator */
738
- .agent-waiting-indicator { display:flex; align-items:center; padding:0.75rem 1rem; }
739
- .typing-dots { display:flex; gap:4px; align-items:center; }
740
- .typing-dots span { width:8px; height:8px; border-radius:50%; background:#6c757d; animation:typingBounce 1.4s infinite ease-in-out both; }
741
- .typing-dots span:nth-child(1) { animation-delay:-0.32s; }
742
- .typing-dots span:nth-child(2) { animation-delay:-0.16s; }
743
- .typing-dots span:nth-child(3) { animation-delay:0s; }
744
- @keyframes typingBounce { 0%,80%,100%{transform:scale(.6);opacity:.4} 40%{transform:scale(1);opacity:1} }
745
- /* Modern Chat Layout */
746
- .modern-chat-layout {
747
- display: flex;
748
- flex-direction: column;
749
- height: 100%;
750
- }
751
- .modern-chat-layout #copilotinteractions {
752
- max-height: 70vh;
753
- overflow-y: auto;
754
- padding: 1rem;
755
- display: flex;
756
- flex-direction: column;
757
- gap: 0.75rem;
758
- }
759
- .modern-chat-layout .chat-message {
760
- display: flex;
761
- gap: 0.5rem;
762
- max-width: 85%;
763
- align-items: flex-start;
764
- }
765
- .modern-chat-layout .chat-message.chat-user {
766
- align-self: flex-end;
767
- flex-direction: row-reverse;
768
- }
769
- .modern-chat-layout .chat-message.chat-assistant {
770
- align-self: flex-start;
771
- }
772
- .modern-chat-layout .chat-avatar {
773
- width: 2rem;
774
- height: 2rem;
775
- border-radius: 50%;
776
- display: flex;
777
- align-items: center;
778
- justify-content: center;
779
- flex-shrink: 0;
780
- font-size: 0.85rem;
781
- background: var(--tblr-secondary-bg-subtle, var(--bs-secondary-bg-subtle, #e9ecef));
782
- color: var(--tblr-secondary-color, var(--bs-secondary-color, #6c757d));
783
- }
784
- .modern-chat-layout .chat-user .chat-avatar {
785
- background: #0d6efd;
786
- color: #fff;
787
- }
788
- .modern-chat-layout .chat-bubble {
789
- padding: 0.6rem 1rem;
790
- border-radius: 1rem;
791
- line-height: 1.5;
792
- word-wrap: break-word;
793
- overflow-wrap: break-word;
794
- }
795
- .modern-chat-layout .chat-user .chat-bubble {
796
- background: #0d6efd;
797
- color: #fff;
798
- border-bottom-right-radius: 0.25rem;
799
- }
800
- .modern-chat-layout .chat-assistant .chat-bubble {
801
- background: var(--tblr-secondary-bg-subtle, var(--bs-secondary-bg-subtle, #f0f2f5));
802
- color: var(--tblr-body-color, var(--bs-body-color, #212529));
803
- border-bottom-left-radius: 0.25rem;
804
- }
805
- /* Markdown content inside bubbles */
806
- .modern-chat-layout .chat-bubble h1,
807
- .modern-chat-layout .chat-bubble h2,
808
- .modern-chat-layout .chat-bubble h3,
809
- .modern-chat-layout .chat-bubble h4 {
810
- margin-top: 0.5rem;
811
- margin-bottom: 0.25rem;
812
- }
813
- .modern-chat-layout .chat-bubble h1 { font-size: 1.3rem; }
814
- .modern-chat-layout .chat-bubble h2 { font-size: 1.15rem; }
815
- .modern-chat-layout .chat-bubble h3 { font-size: 1.05rem; }
816
- .modern-chat-layout .chat-bubble h4 { font-size: 1rem; }
817
- .modern-chat-layout .chat-bubble p {
818
- margin-bottom: 0.4rem;
819
- }
820
- .modern-chat-layout .chat-bubble p:last-child {
821
- margin-bottom: 0;
822
- }
823
- .modern-chat-layout .chat-bubble ul,
824
- .modern-chat-layout .chat-bubble ol {
825
- padding-left: 1.5rem;
826
- margin-bottom: 0.4rem;
827
- }
828
- .modern-chat-layout .chat-bubble table {
829
- width: 100%;
830
- border-collapse: collapse;
831
- margin: 0.5rem 0;
832
- font-size: 0.9em;
833
- }
834
- .modern-chat-layout .chat-bubble table th,
835
- .modern-chat-layout .chat-bubble table td {
836
- border: 1px solid rgba(0,0,0,0.15);
837
- padding: 0.3rem 0.5rem;
838
- }
839
- .modern-chat-layout .chat-bubble table th {
840
- background: rgba(0,0,0,0.05);
841
- font-weight: 600;
842
- }
843
- .modern-chat-layout .chat-bubble pre {
844
- background: rgba(0,0,0,0.06);
845
- padding: 0.5rem;
846
- border-radius: 0.5rem;
847
- overflow-x: auto;
848
- margin: 0.4rem 0;
849
- }
850
- .modern-chat-layout .chat-bubble code {
851
- font-size: 0.88em;
852
- }
853
- .modern-chat-layout .chat-bubble p > code {
854
- background: rgba(0,0,0,0.06);
855
- padding: 0.1rem 0.3rem;
856
- border-radius: 0.25rem;
857
- }
858
- .modern-chat-layout .chat-user .chat-bubble pre {
859
- background: rgba(255,255,255,0.15);
860
- }
861
- .modern-chat-layout .chat-user .chat-bubble p > code {
862
- background: rgba(255,255,255,0.15);
863
- }
864
- .modern-chat-layout .chat-user .chat-bubble table th,
865
- .modern-chat-layout .chat-user .chat-bubble table td {
866
- border-color: rgba(255,255,255,0.25);
867
- }
868
- .modern-chat-layout .chat-user .chat-bubble table th {
869
- background: rgba(255,255,255,0.1);
870
- }
871
- /* Skill attribution badge */
872
- .modern-chat-layout .chat-bubble .badge.bg-info {
873
- display: inline-block;
874
- margin-bottom: 6px;
875
- font-size: 0.7rem;
876
- font-weight: 600;
877
- letter-spacing: 0.3px;
878
- text-transform: uppercase;
879
- opacity: 0.85;
880
- }
881
- .modern-chat-layout .chat-bubble .card.bg-secondary-subtle {
882
- border: none;
883
- background-color: rgba(0,0,0,0.03) !important;
884
- margin-bottom: 0.5rem;
885
- }
886
- /* Input area for modern chat */
887
- .modern-chat-layout .copilot-entry {
888
- border-top: 1px solid var(--tblr-border-color, var(--bs-border-color, #dee2e6));
889
- padding-top: 0.75rem;
890
- margin-top: 0.5rem;
891
- }
892
- .modern-chat-layout .copilot-entry textarea {
893
- border-radius: 1.5rem;
894
- padding: 0.6rem 1rem;
895
- resize: none;
896
- }
897
- /* Streaming scratch in modern chat */
898
- .modern-chat-layout .next_response_scratch {
899
- padding: 0 1rem;
900
- }
901
- .modern-chat-layout .next_response_scratch:not(:empty) {
902
- margin-bottom: 0.5rem;
903
- }
904
- /* Interaction segment (tool cards) inside modern chat */
905
- .modern-chat-layout .interaction-segment {
906
- border-top: none;
907
- }
908
- /* Modern Sessions Sidebar */
909
- .modern-sessions-header {
910
- display: flex;
911
- align-items: center;
912
- justify-content: space-between;
913
- padding: 0.6rem 0.75rem;
914
- margin-bottom: 0.75rem;
915
- background: var(--tblr-secondary-bg-subtle, var(--bs-secondary-bg-subtle, #f8f9fa));
916
- border-radius: 0.75rem;
917
- border-bottom: 1px solid var(--tblr-border-color, var(--bs-border-color, #dee2e6));
918
- position: sticky;
919
- top: 0;
920
- z-index: 1;
921
- }
922
- .modern-sessions .modern-session-item {
923
- border-radius: 0.75rem;
924
- padding: 0.65rem 0.75rem;
925
- margin-bottom: 0.4rem;
926
- border: 1px solid var(--tblr-border-color, var(--bs-border-color, #dee2e6));
927
- cursor: pointer;
928
- transition: all 0.15s ease;
929
- }
930
- .modern-sessions .modern-session-item:hover {
931
- box-shadow: 0 2px 8px rgba(0,0,0,0.07);
932
- background-color: var(--tblr-secondary-bg-subtle, var(--bs-secondary-bg-subtle, #f8f9fa));
933
- }
934
- .modern-sessions .modern-session-item.active-session {
935
- border-left: 3px solid #0d6efd;
936
- background-color: rgba(13, 110, 253, 0.05);
937
- }
938
- .modern-sessions .modern-session-item i.fa-trash-alt {
939
- display: none;
940
- font-size: 0.8em;
941
- }
942
- .modern-sessions .modern-session-item:hover i.fa-trash-alt {
943
- display: inline;
944
- }
945
- .modern-sessions .modern-session-item .prevrun_content {
946
- font-size: 0.85em;
947
- color: var(--tblr-secondary-color, var(--bs-secondary-color, #6c757d));
948
- white-space: nowrap;
949
- overflow: hidden;
950
- text-overflow: ellipsis;
951
- }`,
952
- ),
665
+ style(agents_css),
953
666
  script(domReady(`$( "#inputuserinput" ).autogrow({paddingBottom: 20});`)),
954
667
  script(
955
668
  `
@@ -1154,7 +867,37 @@ const run = async (
1154
867
  : '<div class="agent-waiting-indicator"><div class="typing-dots"><span></span><span></span><span></span></div></div>';
1155
868
  $('div.next_response_scratch').before(indicator);
1156
869
  scrollAgentToBottom();
1157
- };`,
870
+ };
871
+ document.addEventListener('click', async (e) => {
872
+ const target = e.target.closest('.copy-to-clipboard-elem');
873
+ if (!target) return;
874
+
875
+ // Check if the click was in the top-right corner where the icon is
876
+ const rect = target.getBoundingClientRect();
877
+ const clickX = e.clientX - rect.left;
878
+ const clickY = e.clientY - rect.top;
879
+
880
+ // Icon is at top: 4px, right: 4px, ~16px size — give a generous hit area
881
+ const iconHitArea = 24;
882
+ const isIconClick =
883
+ clickX >= rect.width - iconHitArea &&
884
+ clickX <= rect.width &&
885
+ clickY >= 0 &&
886
+ clickY <= iconHitArea;
887
+
888
+ if (!isIconClick) return;
889
+
890
+ e.stopPropagation();
891
+ e.preventDefault();
892
+
893
+ try {
894
+ await navigator.clipboard.writeText(target.innerText);
895
+ target.classList.add('copy-success');
896
+ setTimeout(() => target.classList.remove('copy-success'), 1000);
897
+ } catch (err) {
898
+ console.error('Failed to copy:', err);
899
+ }
900
+ });`,
1158
901
  stream &&
1159
902
  domReady(
1160
903
  `$('form.agent-view input[name=page_load_tag]').val(window._sc_pageloadtag)`,
package/agents.css ADDED
@@ -0,0 +1,401 @@
1
+ div.interaction-segment:not(:first-child) {
2
+ border-top: 1px solid #e7e7e7;
3
+ }
4
+ div.interaction-segment {
5
+ padding-top: 5px;
6
+ padding-bottom: 5px;
7
+ }
8
+ div.interaction-segment p {
9
+ margin-bottom: 0px;
10
+ }
11
+ div.interaction-segment div.card {
12
+ margin-top: 0.5rem;
13
+ }
14
+ div.interaction-segment.to-right {
15
+ display: flex;
16
+ flex-direction: row-reverse;
17
+ }
18
+ div.interaction-segment.to-right div.badgewrap {
19
+ display: flex;
20
+ flex-direction: row-reverse;
21
+ }
22
+ div.prevcopilotrun:hover {
23
+ cursor: pointer;
24
+ background-color: var(
25
+ --tblr-secondary-bg-subtle,
26
+ var(--bs-secondary-bg-subtle, gray)
27
+ );
28
+ }
29
+ div.prevcopilotrun i.fa-trash-alt {
30
+ display: none;
31
+ }
32
+ div.prevcopilotrun:hover i.fa-trash-alt {
33
+ display: block;
34
+ }
35
+ .copilot-entry .submit-button:hover {
36
+ cursor: pointer;
37
+ }
38
+ .copilot-entry span.attach_agent_image_wrap i:hover {
39
+ cursor: pointer;
40
+ }
41
+
42
+ .copilot-entry .submit-button {
43
+ position: relative;
44
+ top: -1.8rem;
45
+ left: 0.1rem;
46
+ }
47
+ .copilot-entry #audioinputicon {
48
+ position: relative;
49
+ top: -1.8rem;
50
+ right: 0.7rem;
51
+ cursor: pointer;
52
+ float: right;
53
+ }
54
+ .copilot-entry .debugicon {
55
+ position: relative;
56
+ top: -1.8rem;
57
+ left: 0.1rem;
58
+ cursor: pointer;
59
+ }
60
+ .copilot-entry .cancelbtn {
61
+ position: relative;
62
+ top: -1.8rem;
63
+ left: 0.1rem;
64
+ cursor: pointer;
65
+ }
66
+ .copilot-entry .skill-form-widget {
67
+ position: relative;
68
+ top: -2rem;
69
+ left: 0.4rem;
70
+ display: inline;
71
+ }
72
+ .session-open-sessions,
73
+ .open-prev-runs {
74
+ cursor: pointer;
75
+ }
76
+ .copilot-entry span.attach_agent_image_wrap {
77
+ position: relative;
78
+ top: -1.8rem;
79
+ left: 0.2rem;
80
+ }
81
+ .copilot-entry.dragover {
82
+ outline: 2px dashed var(--tblr-primary, #0054a6);
83
+ outline-offset: -2px;
84
+ background: var(--tblr-primary-bg-subtle, rgba(0, 84, 166, 0.05));
85
+ border-radius: 0.25rem;
86
+ }
87
+ .copilot-entry .explainer {
88
+ position: relative;
89
+ top: -1.2rem;
90
+ display: block;
91
+ }
92
+ .col-0 {
93
+ width: 0%;
94
+ }
95
+ .copilot-entry {
96
+ margin-bottom: -1.25rem;
97
+ margin-top: 1rem;
98
+ }
99
+ p.prevrun_content {
100
+ white-space: nowrap;
101
+ overflow: hidden;
102
+ margin-bottom: 0px;
103
+ display: block;
104
+ text-overflow: ellipsis;
105
+ }
106
+ /* Typing / Waiting Indicator */
107
+ .agent-waiting-indicator {
108
+ display: flex;
109
+ align-items: center;
110
+ padding: 0.75rem 1rem;
111
+ }
112
+ .typing-dots {
113
+ display: flex;
114
+ gap: 4px;
115
+ align-items: center;
116
+ }
117
+ .typing-dots span {
118
+ width: 8px;
119
+ height: 8px;
120
+ border-radius: 50%;
121
+ background: #6c757d;
122
+ animation: typingBounce 1.4s infinite ease-in-out both;
123
+ }
124
+ .typing-dots span:nth-child(1) {
125
+ animation-delay: -0.32s;
126
+ }
127
+ .typing-dots span:nth-child(2) {
128
+ animation-delay: -0.16s;
129
+ }
130
+ .typing-dots span:nth-child(3) {
131
+ animation-delay: 0s;
132
+ }
133
+ @keyframes typingBounce {
134
+ 0%,
135
+ 80%,
136
+ 100% {
137
+ transform: scale(0.6);
138
+ opacity: 0.4;
139
+ }
140
+ 40% {
141
+ transform: scale(1);
142
+ opacity: 1;
143
+ }
144
+ }
145
+ /* Modern Chat Layout */
146
+ .modern-chat-layout {
147
+ display: flex;
148
+ flex-direction: column;
149
+ height: 100%;
150
+ }
151
+ .modern-chat-layout #copilotinteractions {
152
+ max-height: 70vh;
153
+ overflow-y: auto;
154
+ padding: 1rem;
155
+ display: flex;
156
+ flex-direction: column;
157
+ gap: 0.75rem;
158
+ }
159
+ .modern-chat-layout .chat-message {
160
+ display: flex;
161
+ gap: 0.5rem;
162
+ max-width: 85%;
163
+ align-items: flex-start;
164
+ }
165
+ .modern-chat-layout .chat-message.chat-user {
166
+ align-self: flex-end;
167
+ flex-direction: row-reverse;
168
+ }
169
+ .modern-chat-layout .chat-message.chat-assistant {
170
+ align-self: flex-start;
171
+ }
172
+ .modern-chat-layout .chat-avatar {
173
+ width: 2rem;
174
+ height: 2rem;
175
+ border-radius: 50%;
176
+ display: flex;
177
+ align-items: center;
178
+ justify-content: center;
179
+ flex-shrink: 0;
180
+ font-size: 0.85rem;
181
+ background: var(
182
+ --tblr-secondary-bg-subtle,
183
+ var(--bs-secondary-bg-subtle, #e9ecef)
184
+ );
185
+ color: var(--tblr-secondary-color, var(--bs-secondary-color, #6c757d));
186
+ }
187
+ .modern-chat-layout .chat-user .chat-avatar {
188
+ background: #0d6efd;
189
+ color: #fff;
190
+ }
191
+ .modern-chat-layout .chat-bubble {
192
+ padding: 0.6rem 1rem;
193
+ border-radius: 1rem;
194
+ line-height: 1.5;
195
+ word-wrap: break-word;
196
+ overflow-wrap: break-word;
197
+ }
198
+ .modern-chat-layout .chat-user .chat-bubble {
199
+ background: #0d6efd;
200
+ color: #fff;
201
+ border-bottom-right-radius: 0.25rem;
202
+ }
203
+ .modern-chat-layout .chat-assistant .chat-bubble {
204
+ background: var(
205
+ --tblr-secondary-bg-subtle,
206
+ var(--bs-secondary-bg-subtle, #f0f2f5)
207
+ );
208
+ color: var(--tblr-body-color, var(--bs-body-color, #212529));
209
+ border-bottom-left-radius: 0.25rem;
210
+ }
211
+ /* Markdown content inside bubbles */
212
+ .modern-chat-layout .chat-bubble h1,
213
+ .modern-chat-layout .chat-bubble h2,
214
+ .modern-chat-layout .chat-bubble h3,
215
+ .modern-chat-layout .chat-bubble h4 {
216
+ margin-top: 0.5rem;
217
+ margin-bottom: 0.25rem;
218
+ }
219
+ .modern-chat-layout .chat-bubble h1 {
220
+ font-size: 1.3rem;
221
+ }
222
+ .modern-chat-layout .chat-bubble h2 {
223
+ font-size: 1.15rem;
224
+ }
225
+ .modern-chat-layout .chat-bubble h3 {
226
+ font-size: 1.05rem;
227
+ }
228
+ .modern-chat-layout .chat-bubble h4 {
229
+ font-size: 1rem;
230
+ }
231
+ .modern-chat-layout .chat-bubble p {
232
+ margin-bottom: 0.4rem;
233
+ }
234
+ .modern-chat-layout .chat-bubble p:last-child {
235
+ margin-bottom: 0;
236
+ }
237
+ .modern-chat-layout .chat-bubble ul,
238
+ .modern-chat-layout .chat-bubble ol {
239
+ padding-left: 1.5rem;
240
+ margin-bottom: 0.4rem;
241
+ }
242
+ .modern-chat-layout .chat-bubble table {
243
+ width: 100%;
244
+ border-collapse: collapse;
245
+ margin: 0.5rem 0;
246
+ font-size: 0.9em;
247
+ }
248
+ .modern-chat-layout .chat-bubble table th,
249
+ .modern-chat-layout .chat-bubble table td {
250
+ border: 1px solid rgba(0, 0, 0, 0.15);
251
+ padding: 0.3rem 0.5rem;
252
+ }
253
+ .modern-chat-layout .chat-bubble table th {
254
+ background: rgba(0, 0, 0, 0.05);
255
+ font-weight: 600;
256
+ }
257
+ .modern-chat-layout .chat-bubble pre {
258
+ background: rgba(0, 0, 0, 0.06);
259
+ padding: 0.5rem;
260
+ border-radius: 0.5rem;
261
+ overflow-x: auto;
262
+ margin: 0.4rem 0;
263
+ }
264
+ .modern-chat-layout .chat-bubble code {
265
+ font-size: 0.88em;
266
+ }
267
+ .modern-chat-layout .chat-bubble p > code {
268
+ background: rgba(0, 0, 0, 0.06);
269
+ padding: 0.1rem 0.3rem;
270
+ border-radius: 0.25rem;
271
+ }
272
+ .modern-chat-layout .chat-user .chat-bubble pre {
273
+ background: rgba(255, 255, 255, 0.15);
274
+ }
275
+ .modern-chat-layout .chat-user .chat-bubble p > code {
276
+ background: rgba(255, 255, 255, 0.15);
277
+ }
278
+ .modern-chat-layout .chat-user .chat-bubble table th,
279
+ .modern-chat-layout .chat-user .chat-bubble table td {
280
+ border-color: rgba(255, 255, 255, 0.25);
281
+ }
282
+ .modern-chat-layout .chat-user .chat-bubble table th {
283
+ background: rgba(255, 255, 255, 0.1);
284
+ }
285
+ /* Skill attribution badge */
286
+ .modern-chat-layout .chat-bubble .badge.bg-info {
287
+ display: inline-block;
288
+ margin-bottom: 6px;
289
+ font-size: 0.7rem;
290
+ font-weight: 600;
291
+ letter-spacing: 0.3px;
292
+ text-transform: uppercase;
293
+ opacity: 0.85;
294
+ }
295
+ .modern-chat-layout .chat-bubble .card.bg-secondary-subtle {
296
+ border: none;
297
+ background-color: rgba(0, 0, 0, 0.03) !important;
298
+ margin-bottom: 0.5rem;
299
+ }
300
+ /* Input area for modern chat */
301
+ .modern-chat-layout .copilot-entry {
302
+ border-top: 1px solid
303
+ var(--tblr-border-color, var(--bs-border-color, #dee2e6));
304
+ padding-top: 0.75rem;
305
+ margin-top: 0.5rem;
306
+ }
307
+ .modern-chat-layout .copilot-entry textarea {
308
+ border-radius: 1.5rem;
309
+ padding: 0.6rem 1rem;
310
+ resize: none;
311
+ }
312
+ /* Streaming scratch in modern chat */
313
+ .modern-chat-layout .next_response_scratch {
314
+ padding: 0 1rem;
315
+ }
316
+ .modern-chat-layout .next_response_scratch:not(:empty) {
317
+ margin-bottom: 0.5rem;
318
+ }
319
+ /* Interaction segment (tool cards) inside modern chat */
320
+ .modern-chat-layout .interaction-segment {
321
+ border-top: none;
322
+ }
323
+ /* Modern Sessions Sidebar */
324
+ .modern-sessions-header {
325
+ display: flex;
326
+ align-items: center;
327
+ justify-content: space-between;
328
+ padding: 0.6rem 0.75rem;
329
+ margin-bottom: 0.75rem;
330
+ background: var(
331
+ --tblr-secondary-bg-subtle,
332
+ var(--bs-secondary-bg-subtle, #f8f9fa)
333
+ );
334
+ border-radius: 0.75rem;
335
+ border-bottom: 1px solid
336
+ var(--tblr-border-color, var(--bs-border-color, #dee2e6));
337
+ position: sticky;
338
+ top: 0;
339
+ z-index: 1;
340
+ }
341
+ .modern-sessions .modern-session-item {
342
+ border-radius: 0.75rem;
343
+ padding: 0.65rem 0.75rem;
344
+ margin-bottom: 0.4rem;
345
+ border: 1px solid var(--tblr-border-color, var(--bs-border-color, #dee2e6));
346
+ cursor: pointer;
347
+ transition: all 0.15s ease;
348
+ }
349
+ .modern-sessions .modern-session-item:hover {
350
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.07);
351
+ background-color: var(
352
+ --tblr-secondary-bg-subtle,
353
+ var(--bs-secondary-bg-subtle, #f8f9fa)
354
+ );
355
+ }
356
+ .modern-sessions .modern-session-item.active-session {
357
+ border-left: 3px solid #0d6efd;
358
+ background-color: rgba(13, 110, 253, 0.05);
359
+ }
360
+ .modern-sessions .modern-session-item i.fa-trash-alt {
361
+ display: none;
362
+ font-size: 0.8em;
363
+ }
364
+ .modern-sessions .modern-session-item:hover i.fa-trash-alt {
365
+ display: inline;
366
+ }
367
+ .modern-sessions .modern-session-item .prevrun_content {
368
+ font-size: 0.85em;
369
+ color: var(--tblr-secondary-color, var(--bs-secondary-color, #6c757d));
370
+ white-space: nowrap;
371
+ overflow: hidden;
372
+ text-overflow: ellipsis;
373
+ }
374
+ .copy-to-clipboard-elem {
375
+ position: relative;
376
+ }
377
+
378
+ .copy-to-clipboard-elem::before {
379
+ content: "📋";
380
+ position: absolute;
381
+ top: 4px;
382
+ right: 4px;
383
+ font-size: 16px;
384
+ line-height: 1;
385
+ cursor: pointer;
386
+ opacity: 0;
387
+ pointer-events: none;
388
+ transition: opacity 0.15s ease-in-out;
389
+ z-index: 10;
390
+ user-select: none;
391
+ }
392
+
393
+ .copy-to-clipboard-elem:hover::before {
394
+ opacity: 1;
395
+ pointer-events: auto;
396
+ }
397
+
398
+ .copy-to-clipboard-elem.copy-success::before {
399
+ content: "✓";
400
+ color: green;
401
+ }
package/common.js CHANGED
@@ -220,7 +220,7 @@ const wrapSegment = (html, who, to_right, layout, user) =>
220
220
  : layout && layout.startsWith("Modern chat")
221
221
  ? `<div class="chat-message ${to_right ? "chat-user" : "chat-assistant"}">` +
222
222
  `<div class="chat-avatar"${user ? ` title="${user.email} at ${new Date().toString()}"` : ""}><i class="fas ${to_right ? "fa-user" : "fa-robot"}"></i></div>` +
223
- `<div class="chat-bubble">${html}</div>` +
223
+ `<div class="chat-bubble${" copy-to-clipboard-elem"}">${html}</div>` +
224
224
  `</div>`
225
225
  : `<div class="interaction-segment ${to_right ? "to-right" : ""}"><div><div class="badgewrap"><span class="badge bg-secondary">` +
226
226
  who +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saltcorn/agents",
3
- "version": "0.8.2",
3
+ "version": "0.8.4",
4
4
  "description": "AI agents for Saltcorn",
5
5
  "main": "index.js",
6
6
  "dependencies": {