@saltcorn/agents 0.5.2 → 0.5.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
@@ -194,8 +194,8 @@ const realTimeCollabScript = (viewname) => {
194
194
  else {
195
195
  //legacy
196
196
  ensure_script_loaded("/static_assets/${
197
- db.connectObj.version_tag
198
- }/socket.io.min.js");
197
+ db.connectObj.version_tag
198
+ }/socket.io.min.js");
199
199
  callback();
200
200
  }`)
201
201
  );
@@ -321,18 +321,21 @@ const run = async (
321
321
  }
322
322
  }
323
323
  }
324
-
325
- interactMarkups.push(
326
- div(
327
- { class: "interaction-segment" },
328
- span({ class: "badge bg-secondary" }, action.name),
329
- typeof interact.content === "string"
330
- ? md.render(interact.content)
331
- : typeof interact.content?.content === "string"
332
- ? md.render(interact.content.content)
333
- : interact.content
334
- )
335
- );
324
+ if (
325
+ typeof interact.content === "string" ||
326
+ typeof interact.content?.content === "string"
327
+ )
328
+ interactMarkups.push(
329
+ div(
330
+ { class: "interaction-segment" },
331
+ span({ class: "badge bg-secondary" }, action.name),
332
+ typeof interact.content === "string"
333
+ ? md.render(interact.content)
334
+ : typeof interact.content?.content === "string"
335
+ ? md.render(interact.content.content)
336
+ : interact.content
337
+ )
338
+ );
336
339
  break;
337
340
  case "tool":
338
341
  if (interact.content !== "Action run") {
@@ -371,7 +374,11 @@ const run = async (
371
374
  for (const skill of get_skill_instances(action.configuration)) {
372
375
  if (skill.formWidget)
373
376
  skill_form_widgets.push(
374
- await skill.formWidget({ user: req.user, klass: "skill-form-widget" })
377
+ await skill.formWidget({
378
+ user: req.user,
379
+ viewname,
380
+ klass: "skill-form-widget",
381
+ })
375
382
  );
376
383
  }
377
384
 
@@ -556,6 +563,9 @@ const run = async (
556
563
  $("div.prev-runs-list").show().parents(".was-col-3").removeClass(["was-col-3","col-0","d-none"]).addClass("col-3").parent().children(".col-12").removeClass("col-12").addClass("col-9")
557
564
  $("div.open-prev-runs").hide()
558
565
  }
566
+ function get_run_id(elem) {
567
+ return $("input[name=run_id").val()
568
+ }
559
569
  function processCopilotResponse(res) {
560
570
  const hadFile = $("input#attach_agent_image").val();
561
571
  $("span.filename-label").text("");
@@ -791,6 +801,36 @@ const debug_info = async (table_id, viewname, config, body, { req, res }) => {
791
801
 
792
802
  return;
793
803
  };
804
+
805
+ const skillroute = async (table_id, viewname, config, body, { req, res }) => {
806
+ const { run_id, triggering_row_id, skillid } = body;
807
+ const action = await Trigger.findOne({ id: config.action_id });
808
+ let triggering_row;
809
+ if (table_id && triggering_row_id) {
810
+ const table = Table.findOne(table_id);
811
+ const pk = table?.pk_name;
812
+ if (table) triggering_row = await table.getRow({ [pk]: triggering_row_id });
813
+ }
814
+ const run = await WorkflowRun.findOne({ id: +run_id });
815
+ if (!run) return;
816
+
817
+ const instances = get_skill_instances(action.configuration);
818
+ const instance = instances.find((i) => i.skillid === skillid);
819
+
820
+ if (!instance?.skillRoute) return;
821
+ const resp = await instance.skillRoute({
822
+ triggering_row,
823
+ run,
824
+ req,
825
+ user: req.user,
826
+ });
827
+ return {
828
+ json: {
829
+ success: "ok",
830
+ ...resp,
831
+ },
832
+ };
833
+ };
794
834
  const wrapAction = (
795
835
  inner_markup,
796
836
  viewname,
@@ -830,5 +870,5 @@ module.exports = {
830
870
  //tableless: true,
831
871
  table_optional: true,
832
872
  run,
833
- routes: { interact, delprevrun, debug_info },
873
+ routes: { interact, delprevrun, debug_info, skillroute },
834
874
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saltcorn/agents",
3
- "version": "0.5.2",
3
+ "version": "0.5.4",
4
4
  "description": "AI agents for Saltcorn",
5
5
  "main": "index.js",
6
6
  "dependencies": {
@@ -12,6 +12,9 @@ const db = require("@saltcorn/data/db");
12
12
  const { eval_expression } = require("@saltcorn/data/models/expression");
13
13
  const { interpolate, sleep } = require("@saltcorn/data/utils");
14
14
  const { features } = require("@saltcorn/data/db/state");
15
+ const { button } = require("@saltcorn/markup/tags");
16
+ const { validID } = require("@saltcorn/markup/layout_utils");
17
+
15
18
  const vm = require("vm");
16
19
 
17
20
  //const { fieldProperties } = require("./helpers");
@@ -25,9 +28,11 @@ class RunJsCodeSkill {
25
28
 
26
29
  constructor(cfg) {
27
30
  Object.assign(this, cfg);
31
+ if (this.mode === "Button")
32
+ this.skillid = `jsbtn${validID(this.button_label || "jscodebtn")}`;
28
33
  }
29
34
 
30
- async runCode({ row, user, req }) {
35
+ async runCode({ row, user, req, ...rest }) {
31
36
  const sysState = getState();
32
37
 
33
38
  const f = vm.runInNewContext(`async () => {${this.js_code}\n}`, {
@@ -78,6 +83,7 @@ class RunJsCodeSkill {
78
83
  request_ip: req?.ip,
79
84
  ...(row || {}),
80
85
  ...sysState.eval_context,
86
+ ...rest,
81
87
  });
82
88
  return await f();
83
89
  }
@@ -86,18 +92,37 @@ class RunJsCodeSkill {
86
92
  return this.add_sys_prompt || "";
87
93
  }
88
94
 
95
+ async skillRoute({ run, triggering_row, req }) {
96
+ return await this.runCode({ row: triggering_row, run, user: req.user.req });
97
+ }
98
+
89
99
  static async configFields() {
90
100
  return [
101
+ {
102
+ name: "mode",
103
+ label: "Mode",
104
+ type: "String",
105
+ required: true,
106
+ attributes: { options: ["Tool", "Button"] },
107
+ },
108
+ {
109
+ name: "button_label",
110
+ label: "Button label",
111
+ type: "String",
112
+ showIf: { mode: "Button" },
113
+ },
91
114
  {
92
115
  name: "tool_name",
93
116
  label: "Tool name",
94
117
  type: "String",
95
118
  class: "validate-identifier",
119
+ showIf: { mode: "Tool" },
96
120
  },
97
121
  {
98
122
  name: "tool_description",
99
123
  label: "Tool description",
100
124
  type: "String",
125
+ showIf: { mode: "Tool" },
101
126
  },
102
127
 
103
128
  {
@@ -106,9 +131,14 @@ class RunJsCodeSkill {
106
131
  input_type: "code",
107
132
  attributes: { mode: "text/javascript" },
108
133
  },
109
- { input_type: "section_header", label: "Tool parameters" },
134
+ {
135
+ input_type: "section_header",
136
+ label: "Tool parameters",
137
+ showIf: { mode: "Tool" },
138
+ },
110
139
  new FieldRepeat({
111
140
  name: "toolargs",
141
+ showIf: { mode: "Tool" },
112
142
  fields: [
113
143
  {
114
144
  name: "name",
@@ -129,16 +159,37 @@ class RunJsCodeSkill {
129
159
  },
130
160
  ],
131
161
  }),
162
+ {
163
+ name: "display_result",
164
+ label: "Display result",
165
+ type: "Bool",
166
+ sublabel: "Show the value returned in JSON format",
167
+ showIf: { mode: "Tool" },
168
+ },
132
169
  {
133
170
  name: "add_sys_prompt",
134
171
  label: "Additional prompt",
135
172
  type: "String",
136
173
  fieldview: "textarea",
174
+ showIf: { mode: "Tool" },
137
175
  },
138
176
  ];
139
177
  }
140
178
 
179
+ async formWidget({ klass, viewname }) {
180
+ if (this.mode === "Button")
181
+ return button(
182
+ {
183
+ type: "button",
184
+ class: ["btn btn-outline-secondary btn-sm btn-xs", klass],
185
+ onclick: `view_post('${viewname}', 'skillroute', {skillid: '${this.skillid}', run_id: get_run_id(this)});`,
186
+ },
187
+ this.button_label
188
+ );
189
+ }
190
+
141
191
  provideTools = () => {
192
+ if (this.mode === "Button") return;
142
193
  let properties = {};
143
194
  (this.toolargs || []).forEach((arg) => {
144
195
  properties[arg.name] = {
@@ -154,12 +205,14 @@ class RunJsCodeSkill {
154
205
  /*renderToolCall({ phrase }, { req }) {
155
206
  return div({ class: "border border-primary p-2 m-2" }, phrase);
156
207
  },*/
157
- renderToolResponse: async (response, { req }) => {
158
- return div(
159
- { class: "border border-success p-2 m-2" },
160
- typeof response === "string" ? response : JSON.stringify(response)
161
- );
162
- },
208
+ renderToolResponse: this.display_result
209
+ ? async (response, { req }) => {
210
+ return div(
211
+ { class: "border border-success p-2 m-2" },
212
+ typeof response === "string" ? response : JSON.stringify(response)
213
+ );
214
+ }
215
+ : undefined,
163
216
  function: {
164
217
  name: this.tool_name,
165
218
  description: this.tool_description,