@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.
Files changed (3) hide show
  1. package/agent-view.js +71 -19
  2. package/agents.css +48 -2
  3. 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
- let run = prevRuns ? prevRuns.find((r) => r.id == state.run_id) : null;
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
- ...(shared ? {} : { started_by: req.user?.id }),
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
- if (container.scrollHeight > container.clientHeight) {
709
- container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' });
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
- { class: "flex-grow-1 text-truncate fw-semibold" },
1171
- headerTitle,
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: static !important;
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; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saltcorn/agents",
3
- "version": "0.8.8",
3
+ "version": "0.8.10",
4
4
  "description": "AI agents for Saltcorn",
5
5
  "main": "index.js",
6
6
  "dependencies": {