@saltcorn/agents 0.8.8 → 0.8.10
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 +71 -19
- package/agents.css +48 -2
- package/package.json +1 -1
package/agent-view.js
CHANGED
|
@@ -337,14 +337,25 @@ const run = async (
|
|
|
337
337
|
let hasInputForm = true;
|
|
338
338
|
|
|
339
339
|
const initial_q = state.run_id ? undefined : state._q;
|
|
340
|
+
let run;
|
|
340
341
|
if (state.run_id) {
|
|
341
|
-
|
|
342
|
+
run = prevRuns ? prevRuns.find((r) => r.id == state.run_id) : null;
|
|
342
343
|
if (!run)
|
|
343
344
|
run = await WorkflowRun.findOne({
|
|
344
345
|
trigger_id: action.id,
|
|
345
|
-
|
|
346
|
+
//...(shared ? {} : { started_by: req.user?.id }),
|
|
346
347
|
id: state.run_id,
|
|
347
348
|
});
|
|
349
|
+
|
|
350
|
+
if (
|
|
351
|
+
run &&
|
|
352
|
+
!shared &&
|
|
353
|
+
run.started_by != req.user?.id &&
|
|
354
|
+
run.context.share_token !== (state.share_token || "none")
|
|
355
|
+
)
|
|
356
|
+
run = null;
|
|
357
|
+
}
|
|
358
|
+
if (run) {
|
|
348
359
|
const interactMarkups = [];
|
|
349
360
|
if (run.context.html_interactions) {
|
|
350
361
|
interactMarkups.push(...run.context.html_interactions);
|
|
@@ -508,9 +519,7 @@ const run = async (
|
|
|
508
519
|
onsubmit: `event.preventDefault();const _fd=new FormData(this);spin_send_button();view_post('${viewname}', 'interact', _fd, ${dyn_updates ? "null" : "processCopilotResponse"});return false;`,
|
|
509
520
|
class: [
|
|
510
521
|
"form-namespace copilot agent-view",
|
|
511
|
-
footerInputMode
|
|
512
|
-
? "mt-auto sticky-bottom bg-body py-1"
|
|
513
|
-
: "mt-2",
|
|
522
|
+
footerInputMode ? "mt-auto sticky-bottom bg-body py-1" : "mt-2",
|
|
514
523
|
],
|
|
515
524
|
method: "post",
|
|
516
525
|
},
|
|
@@ -704,10 +713,21 @@ const run = async (
|
|
|
704
713
|
`
|
|
705
714
|
function scrollAgentToBottom() {
|
|
706
715
|
const container = document.getElementById('copilotinteractions');
|
|
707
|
-
if (container)
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
}
|
|
716
|
+
if (!container) return;
|
|
717
|
+
// The message list scrolls internally when its height is bounded.
|
|
718
|
+
if (container.scrollHeight > container.clientHeight + 2) {
|
|
719
|
+
container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' });
|
|
720
|
+
}
|
|
721
|
+
const layout = container.closest('.modern-chat-layout');
|
|
722
|
+
if (layout) {
|
|
723
|
+
// Footer-sticky modern chat: the page scrolls while the input bar is
|
|
724
|
+
// position:sticky, so scrollIntoView() on the bar is a no-op (it
|
|
725
|
+
// always reports as already "in view"). Scroll the page down by the
|
|
726
|
+
// amount the chat extends past the viewport bottom, so the newest
|
|
727
|
+
// content + input bar end up at the bottom of the screen.
|
|
728
|
+
const overshoot = layout.getBoundingClientRect().bottom - window.innerHeight;
|
|
729
|
+
if (overshoot > 0) window.scrollBy({ top: overshoot + 8, behavior: 'smooth' });
|
|
730
|
+
} else {
|
|
711
731
|
const inputForm = document.querySelector('form.agent-view');
|
|
712
732
|
if (inputForm) inputForm.scrollIntoView({ behavior: 'smooth', block: 'end' });
|
|
713
733
|
}
|
|
@@ -749,9 +769,10 @@ const run = async (
|
|
|
749
769
|
const user_input = $("textarea[name=userinput]").val()
|
|
750
770
|
if(user_input && (!${JSON.stringify(dyn_updates)}))
|
|
751
771
|
$("#copilotinteractions").append(wrapSegment('<p>'+user_input+'</p>'+fileBadge, "You", true))
|
|
752
|
-
$("textarea[name=userinput]").val("")
|
|
772
|
+
$("textarea[name=userinput]").val("").trigger("update.autogrow")
|
|
753
773
|
$('div.next_response_scratch').html("")
|
|
754
774
|
window['stream scratch ${viewname} ${rndid}'] = []
|
|
775
|
+
$("button.modern-share").show()
|
|
755
776
|
if(res.response) {
|
|
756
777
|
$(".agent-waiting-indicator").remove();
|
|
757
778
|
$("#copilotinteractions").append(res.response);
|
|
@@ -1044,6 +1065,20 @@ const run = async (
|
|
|
1044
1065
|
if (a) { try { a.pause(); } catch(e){} a.src = ''; }
|
|
1045
1066
|
}
|
|
1046
1067
|
};
|
|
1068
|
+
|
|
1069
|
+
window.share_agent_chat = function(btn, viewname) {
|
|
1070
|
+
const runid = $("input[name=run_id").val()
|
|
1071
|
+
view_post(viewname, 'share_chat', {run_id:runid}, async (data)=>{
|
|
1072
|
+
console.log(data)
|
|
1073
|
+
const clipboardItemData = {
|
|
1074
|
+
["text/plain"]: window.location.origin+'/view/'+viewname+'?run_id='+runid+(data.share_token ? "&share_token="+data.share_token:"")
|
|
1075
|
+
};
|
|
1076
|
+
const clipboardItem = new ClipboardItem(clipboardItemData);
|
|
1077
|
+
await navigator.clipboard.write([clipboardItem]);
|
|
1078
|
+
common_done({notify: "Share link copied to clipboard", remove_delay: 1})
|
|
1079
|
+
|
|
1080
|
+
})
|
|
1081
|
+
};
|
|
1047
1082
|
/* Restore toggle state on load */
|
|
1048
1083
|
(function() {
|
|
1049
1084
|
try {
|
|
@@ -1166,16 +1201,22 @@ const run = async (
|
|
|
1166
1201
|
i({ class: "fas fa-bars" }),
|
|
1167
1202
|
)
|
|
1168
1203
|
: "",
|
|
1169
|
-
span(
|
|
1170
|
-
|
|
1171
|
-
|
|
1204
|
+
span({ class: "flex-grow-1 text-truncate fw-semibold" }, headerTitle),
|
|
1205
|
+
button(
|
|
1206
|
+
{
|
|
1207
|
+
type: "button",
|
|
1208
|
+
style: run ? undefined : { display: "none" },
|
|
1209
|
+
class: "btn btn-sm btn-outline-secondary modern-share",
|
|
1210
|
+
onclick: `share_agent_chat(this, '${viewname}')`,
|
|
1211
|
+
title: req.__("Share chat"),
|
|
1212
|
+
},
|
|
1213
|
+
i({ class: "fas fa-share-alt" }),
|
|
1172
1214
|
),
|
|
1173
1215
|
hasTTS
|
|
1174
1216
|
? button(
|
|
1175
1217
|
{
|
|
1176
1218
|
type: "button",
|
|
1177
|
-
class:
|
|
1178
|
-
"btn btn-sm btn-outline-secondary modern-tts-toggle",
|
|
1219
|
+
class: "btn btn-sm btn-outline-secondary modern-tts-toggle",
|
|
1179
1220
|
onclick: `toggle_agent_tts(this, '${viewname}')`,
|
|
1180
1221
|
title: req.__("Read responses aloud"),
|
|
1181
1222
|
"data-tts-state": "off",
|
|
@@ -1199,10 +1240,7 @@ const run = async (
|
|
|
1199
1240
|
? div(
|
|
1200
1241
|
{ class: "modern-chat-noncard d-flex flex-column" },
|
|
1201
1242
|
modern_chat_header,
|
|
1202
|
-
div(
|
|
1203
|
-
{ class: "modern-chat-layout d-flex flex-column" },
|
|
1204
|
-
main_inner,
|
|
1205
|
-
),
|
|
1243
|
+
div({ class: "modern-chat-layout d-flex flex-column" }, main_inner),
|
|
1206
1244
|
)
|
|
1207
1245
|
: layout === "No card"
|
|
1208
1246
|
? div({ class: "mx-1" }, main_inner)
|
|
@@ -1409,6 +1447,19 @@ const cancel = async (table_id, viewname, config, body, { req, res }) => {
|
|
|
1409
1447
|
return;
|
|
1410
1448
|
};
|
|
1411
1449
|
|
|
1450
|
+
const share_chat = async (table_id, viewname, config, body, { req, res }) => {
|
|
1451
|
+
const { run_id } = body;
|
|
1452
|
+
const run = await WorkflowRun.findOne({ id: +run_id });
|
|
1453
|
+
if (run.context.share_token)
|
|
1454
|
+
return { json: { share_token: run.context.share_token } };
|
|
1455
|
+
else {
|
|
1456
|
+
if (run.started_by != req.user?.id && !config.shared) return;
|
|
1457
|
+
const rndid = Math.floor(Math.random() * 16777215).toString(16);
|
|
1458
|
+
await run.update({ context: { ...run.context, share_token: rndid } });
|
|
1459
|
+
return { json: { share_token: rndid } };
|
|
1460
|
+
}
|
|
1461
|
+
};
|
|
1462
|
+
|
|
1412
1463
|
const debug_info = async (table_id, viewname, config, body, { req, res }) => {
|
|
1413
1464
|
const { run_id, triggering_row_id } = body;
|
|
1414
1465
|
const action =
|
|
@@ -1726,6 +1777,7 @@ module.exports = {
|
|
|
1726
1777
|
execute_user_action,
|
|
1727
1778
|
cancel,
|
|
1728
1779
|
tts,
|
|
1780
|
+
share_chat,
|
|
1729
1781
|
},
|
|
1730
1782
|
mobile_render_server_side: true,
|
|
1731
1783
|
};
|
package/agents.css
CHANGED
|
@@ -411,19 +411,65 @@ p.prevrun_content {
|
|
|
411
411
|
Everything else uses Bootstrap utility classes in the markup; only
|
|
412
412
|
the rules below are custom and cannot be expressed via utilities. */
|
|
413
413
|
.modern-chat-shell.chat-wide .modern-sessions-offcanvas {
|
|
414
|
-
position:
|
|
414
|
+
position: sticky !important;
|
|
415
|
+
top: 1rem;
|
|
416
|
+
align-self: flex-start;
|
|
417
|
+
max-height: calc(100vh - 2rem);
|
|
418
|
+
overflow-y: auto;
|
|
415
419
|
transform: none !important;
|
|
420
|
+
transition: none !important;
|
|
416
421
|
visibility: visible !important;
|
|
417
422
|
z-index: auto !important;
|
|
418
423
|
width: 260px;
|
|
419
424
|
max-width: 260px;
|
|
420
425
|
flex: 0 0 260px;
|
|
421
426
|
background: transparent;
|
|
422
|
-
height: auto;
|
|
423
427
|
box-shadow: none;
|
|
424
428
|
}
|
|
425
429
|
.modern-chat-shell.chat-wide .modern-chat-hamburger { display: none; }
|
|
426
430
|
|
|
431
|
+
/* Slim, subtle scrollbars for the scrollable chat areas (sessions sidebar
|
|
432
|
+
and the message list). Firefox uses scrollbar-width/-color; WebKit/Blink
|
|
433
|
+
use the ::-webkit-scrollbar pseudo-elements. The thumb is mostly
|
|
434
|
+
transparent and only becomes clearly visible on hover, so the scrollbar
|
|
435
|
+
doesn't visually clutter the layout. */
|
|
436
|
+
.modern-chat-shell.chat-wide .modern-sessions-offcanvas,
|
|
437
|
+
.modern-chat-layout #copilotinteractions {
|
|
438
|
+
scrollbar-width: thin;
|
|
439
|
+
scrollbar-color: transparent transparent;
|
|
440
|
+
}
|
|
441
|
+
.modern-chat-shell.chat-wide .modern-sessions-offcanvas:hover,
|
|
442
|
+
.modern-chat-layout #copilotinteractions:hover {
|
|
443
|
+
scrollbar-color: rgba(0, 0, 0, 0.25) transparent;
|
|
444
|
+
}
|
|
445
|
+
.modern-chat-shell.chat-wide .modern-sessions-offcanvas::-webkit-scrollbar,
|
|
446
|
+
.modern-chat-layout #copilotinteractions::-webkit-scrollbar {
|
|
447
|
+
width: 6px;
|
|
448
|
+
height: 6px;
|
|
449
|
+
}
|
|
450
|
+
.modern-chat-shell.chat-wide
|
|
451
|
+
.modern-sessions-offcanvas::-webkit-scrollbar-track,
|
|
452
|
+
.modern-chat-layout #copilotinteractions::-webkit-scrollbar-track {
|
|
453
|
+
background: transparent;
|
|
454
|
+
}
|
|
455
|
+
.modern-chat-shell.chat-wide
|
|
456
|
+
.modern-sessions-offcanvas::-webkit-scrollbar-thumb,
|
|
457
|
+
.modern-chat-layout #copilotinteractions::-webkit-scrollbar-thumb {
|
|
458
|
+
background-color: transparent;
|
|
459
|
+
border-radius: 10px;
|
|
460
|
+
transition: background-color 0.2s ease;
|
|
461
|
+
}
|
|
462
|
+
.modern-chat-shell.chat-wide
|
|
463
|
+
.modern-sessions-offcanvas:hover::-webkit-scrollbar-thumb,
|
|
464
|
+
.modern-chat-layout #copilotinteractions:hover::-webkit-scrollbar-thumb {
|
|
465
|
+
background-color: rgba(0, 0, 0, 0.25);
|
|
466
|
+
}
|
|
467
|
+
.modern-chat-shell.chat-wide
|
|
468
|
+
.modern-sessions-offcanvas::-webkit-scrollbar-thumb:hover,
|
|
469
|
+
.modern-chat-layout #copilotinteractions::-webkit-scrollbar-thumb:hover {
|
|
470
|
+
background-color: rgba(0, 0, 0, 0.4);
|
|
471
|
+
}
|
|
472
|
+
|
|
427
473
|
/* Bootstrap has no `:empty` utility — collapse the interaction list when
|
|
428
474
|
it has no content so the input form sits directly under the header. */
|
|
429
475
|
.modern-chat-layout #copilotinteractions:empty { display: none; }
|