@saltcorn/agents 0.7.10 → 0.7.12
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 +98 -19
- package/common.js +42 -9
- package/package.json +1 -1
- package/skills/PlanApproval.js +103 -0
package/agent-view.js
CHANGED
|
@@ -61,6 +61,14 @@ const configuration_workflow = (req) =>
|
|
|
61
61
|
{
|
|
62
62
|
name: "Agent action",
|
|
63
63
|
form: async (context) => {
|
|
64
|
+
let run_id_field_opts;
|
|
65
|
+
if (context.table_id) {
|
|
66
|
+
const table = Table.findOne({ id: context.table_id });
|
|
67
|
+
run_id_field_opts = table.fields
|
|
68
|
+
.filter((f) => f.type?.name === "Integer" && !f.primary_key)
|
|
69
|
+
.map((f) => f.name);
|
|
70
|
+
}
|
|
71
|
+
|
|
64
72
|
const agent_actions = await Trigger.find({ action: "Agent" });
|
|
65
73
|
return new Form({
|
|
66
74
|
fields: [
|
|
@@ -114,13 +122,29 @@ const configuration_workflow = (req) =>
|
|
|
114
122
|
sublabel:
|
|
115
123
|
"Appears below the input box. Use for additional instructions.",
|
|
116
124
|
},
|
|
125
|
+
...(run_id_field_opts
|
|
126
|
+
? [
|
|
127
|
+
{
|
|
128
|
+
name: "run_id_field",
|
|
129
|
+
type: "String",
|
|
130
|
+
label: "Run ID field",
|
|
131
|
+
sublabel: "Set this field to the run ID",
|
|
132
|
+
attributes: { options: run_id_field_opts },
|
|
133
|
+
},
|
|
134
|
+
]
|
|
135
|
+
: []),
|
|
117
136
|
{
|
|
118
137
|
name: "layout",
|
|
119
138
|
label: "Layout",
|
|
120
139
|
type: "String",
|
|
121
140
|
required: true,
|
|
122
141
|
attributes: {
|
|
123
|
-
options: [
|
|
142
|
+
options: [
|
|
143
|
+
"Standard",
|
|
144
|
+
"No card",
|
|
145
|
+
"Modern chat",
|
|
146
|
+
"Modern chat - no card",
|
|
147
|
+
],
|
|
124
148
|
},
|
|
125
149
|
},
|
|
126
150
|
{
|
|
@@ -289,9 +313,7 @@ const run = async (
|
|
|
289
313
|
if (interact.content?.[0]?.type === "image_url") {
|
|
290
314
|
const image_url = interact.content[0].image_url.url;
|
|
291
315
|
if (image_url.startsWith("data"))
|
|
292
|
-
interactMarkups.push(
|
|
293
|
-
wrapSegment("File", "You", true, layout),
|
|
294
|
-
);
|
|
316
|
+
interactMarkups.push(wrapSegment("File", "You", true, layout));
|
|
295
317
|
else
|
|
296
318
|
interactMarkups.push(
|
|
297
319
|
wrapSegment(
|
|
@@ -303,12 +325,7 @@ const run = async (
|
|
|
303
325
|
);
|
|
304
326
|
} else
|
|
305
327
|
interactMarkups.push(
|
|
306
|
-
wrapSegment(
|
|
307
|
-
md.render(interact.content),
|
|
308
|
-
"You",
|
|
309
|
-
true,
|
|
310
|
-
layout,
|
|
311
|
-
),
|
|
328
|
+
wrapSegment(md.render(interact.content), "You", true, layout),
|
|
312
329
|
);
|
|
313
330
|
break;
|
|
314
331
|
case "assistant":
|
|
@@ -494,8 +511,7 @@ const run = async (
|
|
|
494
511
|
),
|
|
495
512
|
explainer && small({ class: "explainer" }, i(explainer)),
|
|
496
513
|
),
|
|
497
|
-
stream &&
|
|
498
|
-
realTimeCollabScript(viewname, rndid, layout),
|
|
514
|
+
stream && realTimeCollabScript(viewname, rndid, layout),
|
|
499
515
|
);
|
|
500
516
|
|
|
501
517
|
const isModernSidebar = layout && layout.startsWith("Modern chat");
|
|
@@ -527,7 +543,8 @@ const run = async (
|
|
|
527
543
|
)
|
|
528
544
|
: div(
|
|
529
545
|
{
|
|
530
|
-
class:
|
|
546
|
+
class:
|
|
547
|
+
"d-flex flex-wrap justify-content-between align-middle mb-2",
|
|
531
548
|
},
|
|
532
549
|
div(
|
|
533
550
|
{ class: "d-flex" },
|
|
@@ -564,7 +581,10 @@ const run = async (
|
|
|
564
581
|
(isActive ? " active-session" : ""),
|
|
565
582
|
},
|
|
566
583
|
div(
|
|
567
|
-
{
|
|
584
|
+
{
|
|
585
|
+
class:
|
|
586
|
+
"d-flex justify-content-between align-items-center mb-1",
|
|
587
|
+
},
|
|
568
588
|
small(
|
|
569
589
|
{ class: "text-muted text-truncate", style: "min-width:0" },
|
|
570
590
|
localeDateTime(run.started_at),
|
|
@@ -592,10 +612,7 @@ const run = async (
|
|
|
592
612
|
onclick: `delprevrun(event, ${run.id})`,
|
|
593
613
|
}),
|
|
594
614
|
),
|
|
595
|
-
p(
|
|
596
|
-
{ class: "prevrun_content" },
|
|
597
|
-
preview,
|
|
598
|
-
),
|
|
615
|
+
p({ class: "prevrun_content" }, preview),
|
|
599
616
|
);
|
|
600
617
|
}),
|
|
601
618
|
)
|
|
@@ -1108,7 +1125,10 @@ const run = async (
|
|
|
1108
1125
|
const isModern = layout && layout.startsWith("Modern chat");
|
|
1109
1126
|
const main_chat =
|
|
1110
1127
|
layout === "Modern chat"
|
|
1111
|
-
? div(
|
|
1128
|
+
? div(
|
|
1129
|
+
{ class: "card" },
|
|
1130
|
+
div({ class: "card-body modern-chat-layout" }, main_inner),
|
|
1131
|
+
)
|
|
1112
1132
|
: layout === "Modern chat - no card"
|
|
1113
1133
|
? div({ class: "modern-chat-layout" }, main_inner)
|
|
1114
1134
|
: layout === "No card"
|
|
@@ -1157,6 +1177,14 @@ const interact = async (table_id, viewname, config, body, { req, res }) => {
|
|
|
1157
1177
|
triggering_row_id,
|
|
1158
1178
|
},
|
|
1159
1179
|
});
|
|
1180
|
+
if (table_id && config.run_id_field && triggering_row_id) {
|
|
1181
|
+
const table = Table.findOne(table_id);
|
|
1182
|
+
await table.updateRow(
|
|
1183
|
+
{ [config.run_id_field]: run.id },
|
|
1184
|
+
triggering_row_id,
|
|
1185
|
+
);
|
|
1186
|
+
if (triggering_row) triggering_row[config.run_id_field] = run.id;
|
|
1187
|
+
}
|
|
1160
1188
|
} else {
|
|
1161
1189
|
run = await WorkflowRun.findOne({ id: +run_id });
|
|
1162
1190
|
}
|
|
@@ -1437,6 +1465,57 @@ const execute_user_action = async (
|
|
|
1437
1465
|
...uadata.tool_call.input,
|
|
1438
1466
|
...uadata.input,
|
|
1439
1467
|
});
|
|
1468
|
+
if (result.generate_prompt) {
|
|
1469
|
+
const action =
|
|
1470
|
+
config.agent_action || (await Trigger.findOne({ id: config.action_id }));
|
|
1471
|
+
run.context.interactions.push({
|
|
1472
|
+
role: "user",
|
|
1473
|
+
content: result.generate_prompt,
|
|
1474
|
+
});
|
|
1475
|
+
const dyn_updates = getState().getConfig("enable_dynamic_updates", true);
|
|
1476
|
+
|
|
1477
|
+
if (dyn_updates && uadata.click_replace_text) {
|
|
1478
|
+
getState().emitDynamicUpdate(
|
|
1479
|
+
db.getTenantSchema(),
|
|
1480
|
+
{
|
|
1481
|
+
eval_js: `spin_send_button();${`$("button[data-useraction-id=${uadata.rndid}]").replaceWith("${uadata.click_replace_text}")`}`,
|
|
1482
|
+
page_load_tag: req?.headers?.["page-load-tag"],
|
|
1483
|
+
},
|
|
1484
|
+
[req.user.id],
|
|
1485
|
+
);
|
|
1486
|
+
// remove from html_interactions
|
|
1487
|
+
run.context.html_interactions = run.context.html_interactions.map(
|
|
1488
|
+
(hi) => {
|
|
1489
|
+
if (hi.includes(`button data-useraction-id="${uadata.rndid}"`))
|
|
1490
|
+
return wrapSegment(
|
|
1491
|
+
uadata.click_replace_text,
|
|
1492
|
+
"You",
|
|
1493
|
+
true,
|
|
1494
|
+
config.layout,
|
|
1495
|
+
);
|
|
1496
|
+
return hi;
|
|
1497
|
+
},
|
|
1498
|
+
);
|
|
1499
|
+
await run.update({ context: run.context });
|
|
1500
|
+
}
|
|
1501
|
+
await process_interaction(
|
|
1502
|
+
run,
|
|
1503
|
+
action.configuration,
|
|
1504
|
+
req,
|
|
1505
|
+
action.name,
|
|
1506
|
+
[],
|
|
1507
|
+
{}, //row?
|
|
1508
|
+
config,
|
|
1509
|
+
dyn_updates,
|
|
1510
|
+
);
|
|
1511
|
+
const { generate_prompt, ...restResult } = result;
|
|
1512
|
+
return {
|
|
1513
|
+
json: {
|
|
1514
|
+
success: "ok",
|
|
1515
|
+
...restResult,
|
|
1516
|
+
},
|
|
1517
|
+
};
|
|
1518
|
+
}
|
|
1440
1519
|
return {
|
|
1441
1520
|
json: {
|
|
1442
1521
|
success: "ok",
|
package/common.js
CHANGED
|
@@ -41,6 +41,7 @@ const get_skills = () => {
|
|
|
41
41
|
require("./skills/WebSearch"),
|
|
42
42
|
require("./skills/Subagent"),
|
|
43
43
|
require("./skills/ExternalSkill"),
|
|
44
|
+
require("./skills/PlanApproval"),
|
|
44
45
|
//require("./skills/AdaptiveFeedback"),
|
|
45
46
|
...exchange_skills,
|
|
46
47
|
];
|
|
@@ -416,17 +417,49 @@ const process_interaction = async (
|
|
|
416
417
|
myHasResult = true;
|
|
417
418
|
let result = await tool.tool.process(tool_call.input, {
|
|
418
419
|
req,
|
|
419
|
-
});
|
|
420
|
+
});
|
|
421
|
+
const tool_response = result.add_response || result;
|
|
420
422
|
toolResults[tool_call.tool_call_id] = result;
|
|
421
423
|
if (result?.stop) stop = true;
|
|
424
|
+
if (result?.add_user_action && viewname) {
|
|
425
|
+
const user_actions = Array.isArray()
|
|
426
|
+
? result.add_user_action
|
|
427
|
+
: [result.add_user_action];
|
|
428
|
+
for (const uact of user_actions) {
|
|
429
|
+
uact.rndid = Math.floor(Math.random() * 16777215).toString(16);
|
|
430
|
+
uact.tool_call = tool_call;
|
|
431
|
+
}
|
|
432
|
+
await addToContext(run, {
|
|
433
|
+
user_actions,
|
|
434
|
+
});
|
|
435
|
+
add_response(
|
|
436
|
+
div(
|
|
437
|
+
{ class: "d-flex mb-2" },
|
|
438
|
+
user_actions.map((ua) =>
|
|
439
|
+
button(
|
|
440
|
+
{
|
|
441
|
+
"data-useraction-id": ua.rndid,
|
|
442
|
+
class: "btn btn-primary", //press_store_button(this, true);
|
|
443
|
+
onclick: `view_post('${viewname}', 'execute_user_action', {uaname: "${ua.name}",rndid: "${ua.rndid}", run_id: ${run.id}}, processExecuteResponse)`,
|
|
444
|
+
},
|
|
445
|
+
ua.label,
|
|
446
|
+
),
|
|
447
|
+
),
|
|
448
|
+
),
|
|
449
|
+
);
|
|
450
|
+
}
|
|
422
451
|
if (
|
|
423
|
-
(typeof
|
|
424
|
-
|
|
452
|
+
(typeof tool_response === "object" &&
|
|
453
|
+
Object.keys(tool_response || {}).length) ||
|
|
454
|
+
typeof tool_response === "string"
|
|
425
455
|
) {
|
|
426
456
|
if (tool.tool.renderToolResponse) {
|
|
427
|
-
const rendered = await tool.tool.renderToolResponse(
|
|
428
|
-
|
|
429
|
-
|
|
457
|
+
const rendered = await tool.tool.renderToolResponse(
|
|
458
|
+
tool_response,
|
|
459
|
+
{
|
|
460
|
+
req,
|
|
461
|
+
},
|
|
462
|
+
);
|
|
430
463
|
if (rendered)
|
|
431
464
|
add_response(
|
|
432
465
|
wrapSegment(
|
|
@@ -441,14 +474,14 @@ const process_interaction = async (
|
|
|
441
474
|
}
|
|
442
475
|
await sysState.functions.llm_add_message.run(
|
|
443
476
|
"tool_response",
|
|
444
|
-
!
|
|
477
|
+
!tool_response || typeof tool_response === "string"
|
|
445
478
|
? {
|
|
446
479
|
type: "text",
|
|
447
|
-
value:
|
|
480
|
+
value: tool_response || "Action run",
|
|
448
481
|
}
|
|
449
482
|
: {
|
|
450
483
|
type: "json",
|
|
451
|
-
value: JSON.parse(JSON.stringify(
|
|
484
|
+
value: JSON.parse(JSON.stringify(tool_response)),
|
|
452
485
|
},
|
|
453
486
|
{
|
|
454
487
|
chat: run.context.interactions,
|
package/package.json
CHANGED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
const { div, pre, a } = require("@saltcorn/markup/tags");
|
|
2
|
+
const Workflow = require("@saltcorn/data/models/workflow");
|
|
3
|
+
const Form = require("@saltcorn/data/models/form");
|
|
4
|
+
const Table = require("@saltcorn/data/models/table");
|
|
5
|
+
const User = require("@saltcorn/data/models/user");
|
|
6
|
+
const File = require("@saltcorn/data/models/file");
|
|
7
|
+
const View = require("@saltcorn/data/models/view");
|
|
8
|
+
const Trigger = require("@saltcorn/data/models/trigger");
|
|
9
|
+
const FieldRepeat = require("@saltcorn/data/models/fieldrepeat");
|
|
10
|
+
const { getState } = require("@saltcorn/data/db/state");
|
|
11
|
+
const db = require("@saltcorn/data/db");
|
|
12
|
+
const { eval_expression } = require("@saltcorn/data/models/expression");
|
|
13
|
+
const { interpolate, sleep } = require("@saltcorn/data/utils");
|
|
14
|
+
const { features } = require("@saltcorn/data/db/state");
|
|
15
|
+
const { button } = require("@saltcorn/markup/tags");
|
|
16
|
+
const { validID } = require("@saltcorn/markup/layout_utils");
|
|
17
|
+
|
|
18
|
+
const vm = require("vm");
|
|
19
|
+
|
|
20
|
+
//const { fieldProperties } = require("./helpers");
|
|
21
|
+
|
|
22
|
+
class PlanApprovalSkill {
|
|
23
|
+
static skill_name = "Plan approval";
|
|
24
|
+
|
|
25
|
+
get skill_label() {
|
|
26
|
+
return "Plan approval";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
constructor(cfg) {
|
|
30
|
+
Object.assign(this, cfg);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static async configFields() {
|
|
34
|
+
return [
|
|
35
|
+
{
|
|
36
|
+
name: "ini_sys_prompt",
|
|
37
|
+
label: "Initial system prompt",
|
|
38
|
+
type: "String",
|
|
39
|
+
fieldview: "textarea",
|
|
40
|
+
sublabel: "Refer to the tool as <code>submit_plan_for_approval</code>",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: "approval_prompt",
|
|
44
|
+
label: "Prompt on approval",
|
|
45
|
+
type: "String",
|
|
46
|
+
fieldview: "textarea",
|
|
47
|
+
sublabel: "If the user approves the plan, what should the agent do?",
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
systemPrompt() {
|
|
52
|
+
return this.ini_sys_prompt;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get userActions() {
|
|
56
|
+
return {
|
|
57
|
+
approve_plan: async () => {
|
|
58
|
+
return { generate_prompt: this.approval_prompt };
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
provideTools = () => {
|
|
64
|
+
return {
|
|
65
|
+
type: "function",
|
|
66
|
+
process: async (row) => {
|
|
67
|
+
console.log("process plan row", row);
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
stop: true,
|
|
71
|
+
add_response: row.plan,
|
|
72
|
+
add_user_action: {
|
|
73
|
+
name: "approve_plan",
|
|
74
|
+
type: "button",
|
|
75
|
+
label: `Approve`,
|
|
76
|
+
click_replace_text: "Approved",
|
|
77
|
+
input: {},
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
},
|
|
81
|
+
renderToolCall({ plan }) {
|
|
82
|
+
return plan;
|
|
83
|
+
},
|
|
84
|
+
function: {
|
|
85
|
+
name: "submit_plan_for_approval",
|
|
86
|
+
description:
|
|
87
|
+
"Submit a plan for approval by the user. If the plan is approved, further instructions about executing it may be given",
|
|
88
|
+
parameters: {
|
|
89
|
+
type: "object",
|
|
90
|
+
required: ["plan"],
|
|
91
|
+
properties: {
|
|
92
|
+
plan: {
|
|
93
|
+
description: "The plan",
|
|
94
|
+
type: "string",
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
module.exports = PlanApprovalSkill;
|