@saltcorn/agents 0.6.0 → 0.6.2

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
@@ -30,6 +30,7 @@ const {
30
30
  textarea,
31
31
  label,
32
32
  a,
33
+ br,
33
34
  } = require("@saltcorn/markup/tags");
34
35
  const { getState } = require("@saltcorn/data/db/state");
35
36
  const {
@@ -265,135 +266,138 @@ const run = async (
265
266
  id: state.run_id,
266
267
  });
267
268
  const interactMarkups = [];
268
- for (const interact of run.context.interactions) {
269
- switch (interact.role) {
270
- case "user":
271
- if (interact.content?.[0]?.type === "image_url") {
272
- const image_url = interact.content[0].image_url.url;
273
- if (image_url.startsWith("data"))
269
+ if (run.context.html_interactions) {
270
+ interactMarkups.push(...run.context.html_interactions);
271
+ } else
272
+ for (const interact of run.context.interactions) {
273
+ switch (interact.role) {
274
+ case "user":
275
+ if (interact.content?.[0]?.type === "image_url") {
276
+ const image_url = interact.content[0].image_url.url;
277
+ if (image_url.startsWith("data"))
278
+ interactMarkups.push(
279
+ div(
280
+ { class: "interaction-segment" },
281
+ span({ class: "badge bg-secondary" }, "You"),
282
+ "File",
283
+ ),
284
+ );
285
+ else
286
+ interactMarkups.push(
287
+ div(
288
+ { class: "interaction-segment" },
289
+ span({ class: "badge bg-secondary" }, "You"),
290
+ a({ href: image_url, target: "_blank" }, "File"),
291
+ ),
292
+ );
293
+ } else
274
294
  interactMarkups.push(
275
295
  div(
276
296
  { class: "interaction-segment" },
277
297
  span({ class: "badge bg-secondary" }, "You"),
278
- "File",
298
+ md.render(interact.content),
279
299
  ),
280
300
  );
281
- else
282
- interactMarkups.push(
283
- div(
284
- { class: "interaction-segment" },
285
- span({ class: "badge bg-secondary" }, "You"),
286
- a({ href: image_url, target: "_blank" }, "File"),
287
- ),
301
+ break;
302
+ case "assistant":
303
+ case "system":
304
+ for (const tool_call of interact.tool_calls || []) {
305
+ const toolSkill = find_tool(
306
+ tool_call.function?.name,
307
+ action.configuration,
288
308
  );
289
- } else
290
- interactMarkups.push(
291
- div(
292
- { class: "interaction-segment" },
293
- span({ class: "badge bg-secondary" }, "You"),
294
- md.render(interact.content),
295
- ),
296
- );
297
- break;
298
- case "assistant":
299
- case "system":
300
- for (const tool_call of interact.tool_calls || []) {
301
- const toolSkill = find_tool(
302
- tool_call.function?.name,
303
- action.configuration,
304
- );
305
- if (toolSkill) {
306
- const row = JSON.parse(tool_call.function.arguments);
307
- if (toolSkill.tool.renderToolCall) {
308
- const rendered = await toolSkill.tool.renderToolCall(row, {
309
- req,
310
- });
311
- if (rendered)
312
- interactMarkups.push(
313
- wrapSegment(
314
- wrapCard(
315
- toolSkill.skill.skill_label ||
316
- toolSkill.skill.constructor.skill_name,
317
- rendered,
309
+ if (toolSkill) {
310
+ const row = JSON.parse(tool_call.function.arguments);
311
+ if (toolSkill.tool.renderToolCall) {
312
+ const rendered = await toolSkill.tool.renderToolCall(row, {
313
+ req,
314
+ });
315
+ if (rendered)
316
+ interactMarkups.push(
317
+ wrapSegment(
318
+ wrapCard(
319
+ toolSkill.skill.skill_label ||
320
+ toolSkill.skill.constructor.skill_name,
321
+ rendered,
322
+ ),
323
+ action.name,
318
324
  ),
319
- action.name,
320
- ),
321
- );
325
+ );
326
+ }
322
327
  }
323
328
  }
324
- }
325
- for (const image_call of interact.content?.image_calls || []) {
326
- const toolSkill = find_image_tool(action.configuration);
327
- if (toolSkill) {
328
- if (toolSkill.tool.renderToolResponse) {
329
- const rendered = await toolSkill.tool.renderToolResponse(
330
- image_call,
331
- {
332
- req,
333
- },
334
- );
329
+ for (const image_call of interact.content?.image_calls || []) {
330
+ const toolSkill = find_image_tool(action.configuration);
331
+ if (toolSkill) {
332
+ if (toolSkill.tool.renderToolResponse) {
333
+ const rendered = await toolSkill.tool.renderToolResponse(
334
+ image_call,
335
+ {
336
+ req,
337
+ },
338
+ );
335
339
 
336
- if (rendered)
337
- interactMarkups.push(
338
- wrapSegment(
339
- wrapCard(
340
- toolSkill.skill.skill_label ||
341
- toolSkill.skill.constructor.skill_name,
342
- rendered,
340
+ if (rendered)
341
+ interactMarkups.push(
342
+ wrapSegment(
343
+ wrapCard(
344
+ toolSkill.skill.skill_label ||
345
+ toolSkill.skill.constructor.skill_name,
346
+ rendered,
347
+ ),
348
+ action.name,
343
349
  ),
344
- action.name,
345
- ),
346
- );
350
+ );
351
+ }
347
352
  }
348
353
  }
349
- }
350
- if (
351
- typeof interact.content === "string" ||
352
- typeof interact.content?.content === "string"
353
- )
354
- interactMarkups.push(
355
- div(
356
- { class: "interaction-segment" },
357
- span({ class: "badge bg-secondary" }, action.name),
358
- typeof interact.content === "string"
359
- ? md.render(interact.content)
360
- : typeof interact.content?.content === "string"
361
- ? md.render(interact.content.content)
362
- : interact.content,
363
- ),
364
- );
365
- break;
366
- case "tool":
367
- if (interact.content !== "Action run") {
368
- let markupContent;
369
- const toolSkill = find_tool(interact.name, action.configuration);
370
- try {
371
- if (toolSkill?.tool?.renderToolResponse)
372
- markupContent = await toolSkill?.tool?.renderToolResponse?.(
373
- JSON.parse(interact.content),
374
- {
375
- req,
376
- },
377
- );
378
- } catch {
379
- markupContent = pre(interact.content);
380
- }
381
- if (markupContent)
354
+ if (
355
+ typeof interact.content === "string" ||
356
+ typeof interact.content?.content === "string"
357
+ )
382
358
  interactMarkups.push(
383
- wrapSegment(
384
- wrapCard(
385
- toolSkill?.skill?.skill_label ||
386
- toolSkill?.skill?.constructor.skill_name ||
387
- interact.name,
388
- markupContent,
389
- ),
390
- action.name,
359
+ div(
360
+ { class: "interaction-segment" },
361
+ span({ class: "badge bg-secondary" }, action.name),
362
+ typeof interact.content === "string"
363
+ ? md.render(interact.content)
364
+ : typeof interact.content?.content === "string"
365
+ ? md.render(interact.content.content)
366
+ : interact.content,
391
367
  ),
392
368
  );
393
- }
394
- break;
369
+ break;
370
+ case "tool":
371
+ if (interact.content !== "Action run") {
372
+ let markupContent;
373
+ const toolSkill = find_tool(interact.name, action.configuration);
374
+ try {
375
+ if (toolSkill?.tool?.renderToolResponse)
376
+ markupContent = await toolSkill?.tool?.renderToolResponse?.(
377
+ JSON.parse(interact.content),
378
+ {
379
+ req,
380
+ },
381
+ );
382
+ } catch {
383
+ markupContent = pre(interact.content);
384
+ }
385
+ if (markupContent)
386
+ interactMarkups.push(
387
+ wrapSegment(
388
+ wrapCard(
389
+ toolSkill?.skill?.skill_label ||
390
+ toolSkill?.skill?.constructor.skill_name ||
391
+ interact.name,
392
+ markupContent,
393
+ ),
394
+ action.name,
395
+ ),
396
+ );
397
+ }
398
+ break;
399
+ }
395
400
  }
396
- }
397
401
  runInteractions = interactMarkups.join("");
398
402
  }
399
403
  const skill_form_widgets = [];
@@ -518,7 +522,9 @@ const run = async (
518
522
 
519
523
  p(
520
524
  { class: "prevrun_content" },
521
- run.context.interactions[0]?.content?.substring?.(0, 80),
525
+ run.context.interactions
526
+ .find((i) => typeof i?.content === "string")
527
+ ?.content?.substring?.(0, 80),
522
528
  ),
523
529
  ),
524
530
  ),
@@ -615,6 +621,7 @@ const run = async (
615
621
  function processCopilotResponse(res) {
616
622
  console.log("processCopilotResponse", res)
617
623
  const hadFile = $("input#attach_agent_image").val();
624
+ let fileBadge = hadFile ? '<span class="badge text-bg-info"><i class="fas fa-image me-1"></i>'+$("input#attach_agent_image")[0].files?.item?.(0)?.name||"File"+'</span>': ""
618
625
  $("span.filename-label").text("");
619
626
  $("input#attach_agent_image").val(null);
620
627
  $("#sendbuttonicon").attr("class","far fa-paper-plane");
@@ -622,9 +629,9 @@ const run = async (
622
629
  if(res.run_id && (!$runidin.val() || $runidin.val()=="undefined"))
623
630
  $runidin.val(res.run_id);
624
631
  const wrapSegment = (html, who) => '<div class="interaction-segment"><span class="badge bg-secondary">'+who+'</span>'+html+'</div>'
625
- $("#copilotinteractions").append(wrapSegment('<p>'+$("textarea[name=userinput]").val()+'</p>', "You"))
626
- if(hadFile)
627
- $("#copilotinteractions").append(wrapSegment('File', "You"))
632
+ const user_input = $("textarea[name=userinput]").val()
633
+ if(user_input)
634
+ $("#copilotinteractions").append(wrapSegment('<p>'+user_input+'</p>'+fileBadge, "You"))
628
635
  $("textarea[name=userinput]").val("")
629
636
  $('form.agent-view div.next_response_scratch').html("")
630
637
  window['stream scratch ${viewname} ${rndid}'] = []
@@ -736,6 +743,7 @@ const interact = async (table_id, viewname, config, body, { req, res }) => {
736
743
  context: {
737
744
  implemented_fcall_ids: [],
738
745
  interactions: [...ini_interacts],
746
+ html_interactions: [],
739
747
  funcalls: {},
740
748
  triggering_row_id,
741
749
  },
@@ -743,6 +751,7 @@ const interact = async (table_id, viewname, config, body, { req, res }) => {
743
751
  } else {
744
752
  run = await WorkflowRun.findOne({ id: +run_id });
745
753
  }
754
+ let fileBadges = "";
746
755
  if (config.image_upload && req.files?.file) {
747
756
  const file = await File.from_req_files(
748
757
  req.files.file,
@@ -750,6 +759,11 @@ const interact = async (table_id, viewname, config, body, { req, res }) => {
750
759
  100,
751
760
  // file_field?.attributes?.folder
752
761
  );
762
+ fileBadges = span(
763
+ { class: "badge text-bg-info" },
764
+ i({ class: "fas fa-image me-1" }),
765
+ file.filename,
766
+ );
753
767
  const baseUrl = getState().getConfig("base_url").replace(/\/$/, "");
754
768
  let imageurl;
755
769
  if (
@@ -774,6 +788,7 @@ const interact = async (table_id, viewname, config, body, { req, res }) => {
774
788
  ...(run.context.interactions || []),
775
789
  { role: "user", content: userinput },
776
790
  ],
791
+ html_interactions: [wrapSegment(p(userinput) + fileBadges, "You")],
777
792
  });
778
793
  const dyn_updates = getState().getConfig("enable_dynamic_updates", true);
779
794
  const process_promise = process_interaction(
@@ -793,6 +808,7 @@ const interact = async (table_id, viewname, config, body, { req, res }) => {
793
808
  db.getTenantSchema(),
794
809
  {
795
810
  error: e?.message || e,
811
+ page_load_tag: req?.headers?.["page-load-tag"],
796
812
  },
797
813
  [req.user.id],
798
814
  );
package/common.js CHANGED
@@ -236,16 +236,20 @@ const process_interaction = async (
236
236
  interactions: complArgs.chat,
237
237
  });
238
238
  const responses = [];
239
- const add_response = (resp) => {
239
+ const add_response = async (resp) => {
240
240
  if (dyn_updates)
241
241
  getState().emitDynamicUpdate(
242
242
  db.getTenantSchema(),
243
243
  {
244
244
  eval_js: `processCopilotResponse({response: ${JSON.stringify(resp)}, run_id: ${run.id}})`,
245
+ page_load_tag: req?.headers?.["page-load-tag"],
245
246
  },
246
247
  [req.user.id],
247
248
  );
248
249
  else responses.push(resp);
250
+ await addToContext(run, {
251
+ html_interactions: [resp],
252
+ });
249
253
  };
250
254
  if (answer && typeof answer === "object" && answer.image_calls) {
251
255
  for (const image_call of answer.image_calls) {
@@ -356,7 +360,7 @@ const process_interaction = async (
356
360
  req,
357
361
  });
358
362
  if (rendered)
359
- add_responses(
363
+ add_response(
360
364
  wrapSegment(
361
365
  wrapCard(
362
366
  tool.skill.skill_label ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saltcorn/agents",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "AI agents for Saltcorn",
5
5
  "main": "index.js",
6
6
  "dependencies": {
@@ -10,6 +10,10 @@ const { interpolate } = require("@saltcorn/data/utils");
10
10
  class RetrievalByEmbedding {
11
11
  static skill_name = "Retrieval by embedding";
12
12
 
13
+ get skill_label() {
14
+ return `Searching...`;
15
+ }
16
+
13
17
  constructor(cfg) {
14
18
  Object.assign(this, cfg);
15
19
  }