@saltcorn/agents 0.7.5 → 0.7.7
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/action.js +21 -17
- package/agent-view.js +130 -11
- package/common.js +25 -23
- package/package.json +1 -1
- package/skills/GenerateAndRunJsCode.js +61 -13
- package/skills/Subagent.js +19 -6
- package/tests/action.test.js +14 -3
package/action.js
CHANGED
|
@@ -90,24 +90,28 @@ module.exports = {
|
|
|
90
90
|
run_id,
|
|
91
91
|
req,
|
|
92
92
|
is_sub_agent,
|
|
93
|
+
agent_view_config,
|
|
94
|
+
dyn_updates,
|
|
93
95
|
...rest
|
|
94
96
|
}) => {
|
|
95
97
|
const userinput = interpolate(configuration.prompt, row, user);
|
|
96
98
|
|
|
97
|
-
const run =
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
99
|
+
const run =
|
|
100
|
+
rest.run ||
|
|
101
|
+
(run_id
|
|
102
|
+
? await WorkflowRun.findOne({ id: run_id })
|
|
103
|
+
: await WorkflowRun.create({
|
|
104
|
+
status: "Running",
|
|
105
|
+
started_by: user?.id,
|
|
106
|
+
trigger_id: trigger_id || undefined,
|
|
107
|
+
context: {
|
|
108
|
+
implemented_fcall_ids: [],
|
|
109
|
+
interactions: [],
|
|
110
|
+
funcalls: {},
|
|
111
|
+
},
|
|
112
|
+
}));
|
|
113
|
+
|
|
114
|
+
run.context.interactions.push({ role: "user", content: userinput });
|
|
111
115
|
return await process_interaction(
|
|
112
116
|
run,
|
|
113
117
|
configuration,
|
|
@@ -115,9 +119,9 @@ module.exports = {
|
|
|
115
119
|
undefined,
|
|
116
120
|
[],
|
|
117
121
|
row,
|
|
118
|
-
{ stream: false },
|
|
119
|
-
|
|
120
|
-
is_sub_agent
|
|
122
|
+
agent_view_config || { stream: false },
|
|
123
|
+
dyn_updates,
|
|
124
|
+
is_sub_agent,
|
|
121
125
|
);
|
|
122
126
|
},
|
|
123
127
|
};
|
package/agent-view.js
CHANGED
|
@@ -18,6 +18,7 @@ const {
|
|
|
18
18
|
input,
|
|
19
19
|
h4,
|
|
20
20
|
h3,
|
|
21
|
+
h2,
|
|
21
22
|
style,
|
|
22
23
|
h5,
|
|
23
24
|
button,
|
|
@@ -192,13 +193,15 @@ const realTimeCollabScript = (viewname, rndid, layout) => {
|
|
|
192
193
|
['${view.getRealTimeEventName(
|
|
193
194
|
"STREAM_CHUNK",
|
|
194
195
|
)}' + \`?page_load_tag=\${_sc_pageloadtag}\`]: async (data) => {
|
|
196
|
+
$(".agent-waiting-indicator").remove();
|
|
195
197
|
window['stream scratch ${viewname} ${rndid}'].push(data.content)
|
|
196
198
|
const rendered = md.render(window['stream scratch ${viewname} ${rndid}'].join(""));
|
|
197
|
-
$('
|
|
199
|
+
$('div.next_response_scratch').html(
|
|
198
200
|
(${JSON.stringify(layout || "")} || "").startsWith("Modern chat")
|
|
199
201
|
? '<div class="chat-message chat-assistant"><div class="chat-avatar"><i class="fas fa-robot"></i></div><div class="chat-bubble">' + rendered + '</div></div>'
|
|
200
202
|
: rendered
|
|
201
203
|
);
|
|
204
|
+
scrollAgentToBottom();
|
|
202
205
|
}
|
|
203
206
|
}
|
|
204
207
|
};
|
|
@@ -434,7 +437,7 @@ const run = async (
|
|
|
434
437
|
const rndid = Math.floor(Math.random() * 16777215).toString(16);
|
|
435
438
|
const input_form = form(
|
|
436
439
|
{
|
|
437
|
-
onsubmit: `event.preventDefault();spin_send_button();view_post('${viewname}', 'interact',
|
|
440
|
+
onsubmit: `event.preventDefault();const _fd=new FormData(this);spin_send_button();view_post('${viewname}', 'interact', _fd, ${dyn_updates ? "null" : "processCopilotResponse"});return false;`,
|
|
438
441
|
class: ["form-namespace copilot mt-2 agent-view"],
|
|
439
442
|
method: "post",
|
|
440
443
|
},
|
|
@@ -492,8 +495,7 @@ const run = async (
|
|
|
492
495
|
explainer && small({ class: "explainer" }, i(explainer)),
|
|
493
496
|
),
|
|
494
497
|
stream &&
|
|
495
|
-
realTimeCollabScript(viewname, rndid, layout)
|
|
496
|
-
div({ class: "next_response_scratch" }),
|
|
498
|
+
realTimeCollabScript(viewname, rndid, layout),
|
|
497
499
|
);
|
|
498
500
|
|
|
499
501
|
const isModernSidebar = layout && layout.startsWith("Modern chat");
|
|
@@ -612,6 +614,7 @@ const run = async (
|
|
|
612
614
|
req.__("Sessions"),
|
|
613
615
|
),
|
|
614
616
|
div({ id: "copilotinteractions" }, runInteractions),
|
|
617
|
+
stream ? div({ class: "next_response_scratch" }) : "",
|
|
615
618
|
input_form,
|
|
616
619
|
style(
|
|
617
620
|
`div.interaction-segment:not(:first-child) {border-top: 1px solid #e7e7e7; }
|
|
@@ -685,6 +688,14 @@ const run = async (
|
|
|
685
688
|
margin-bottom: 0px;
|
|
686
689
|
display: block;
|
|
687
690
|
text-overflow: ellipsis;}
|
|
691
|
+
/* Typing / Waiting Indicator */
|
|
692
|
+
.agent-waiting-indicator { display:flex; align-items:center; padding:0.75rem 1rem; }
|
|
693
|
+
.typing-dots { display:flex; gap:4px; align-items:center; }
|
|
694
|
+
.typing-dots span { width:8px; height:8px; border-radius:50%; background:#6c757d; animation:typingBounce 1.4s infinite ease-in-out both; }
|
|
695
|
+
.typing-dots span:nth-child(1) { animation-delay:-0.32s; }
|
|
696
|
+
.typing-dots span:nth-child(2) { animation-delay:-0.16s; }
|
|
697
|
+
.typing-dots span:nth-child(3) { animation-delay:0s; }
|
|
698
|
+
@keyframes typingBounce { 0%,80%,100%{transform:scale(.6);opacity:.4} 40%{transform:scale(1);opacity:1} }
|
|
688
699
|
/* Modern Chat Layout */
|
|
689
700
|
.modern-chat-layout {
|
|
690
701
|
display: flex;
|
|
@@ -811,6 +822,21 @@ const run = async (
|
|
|
811
822
|
.modern-chat-layout .chat-user .chat-bubble table th {
|
|
812
823
|
background: rgba(255,255,255,0.1);
|
|
813
824
|
}
|
|
825
|
+
/* Skill attribution badge */
|
|
826
|
+
.modern-chat-layout .chat-bubble .badge.bg-info {
|
|
827
|
+
display: inline-block;
|
|
828
|
+
margin-bottom: 6px;
|
|
829
|
+
font-size: 0.7rem;
|
|
830
|
+
font-weight: 600;
|
|
831
|
+
letter-spacing: 0.3px;
|
|
832
|
+
text-transform: uppercase;
|
|
833
|
+
opacity: 0.85;
|
|
834
|
+
}
|
|
835
|
+
.modern-chat-layout .chat-bubble .card.bg-secondary-subtle {
|
|
836
|
+
border: none;
|
|
837
|
+
background-color: rgba(0,0,0,0.03) !important;
|
|
838
|
+
margin-bottom: 0.5rem;
|
|
839
|
+
}
|
|
814
840
|
/* Input area for modern chat */
|
|
815
841
|
.modern-chat-layout .copilot-entry {
|
|
816
842
|
border-top: 1px solid var(--tblr-border-color, var(--bs-border-color, #dee2e6));
|
|
@@ -881,6 +907,16 @@ const run = async (
|
|
|
881
907
|
script(domReady(`$( "#inputuserinput" ).autogrow({paddingBottom: 20});`)),
|
|
882
908
|
script(
|
|
883
909
|
`
|
|
910
|
+
function scrollAgentToBottom() {
|
|
911
|
+
const container = document.getElementById('copilotinteractions');
|
|
912
|
+
if (container) {
|
|
913
|
+
if (container.scrollHeight > container.clientHeight) {
|
|
914
|
+
container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' });
|
|
915
|
+
}
|
|
916
|
+
const inputForm = document.querySelector('form.agent-view');
|
|
917
|
+
if (inputForm) inputForm.scrollIntoView({ behavior: 'smooth', block: 'end' });
|
|
918
|
+
}
|
|
919
|
+
}
|
|
884
920
|
function close_session_list() {
|
|
885
921
|
$("div.prev-runs-list").hide().parents(".col-3").removeClass("col-3").addClass("was-col-3").parent().children(".col-9").removeClass("col-9").addClass("col-12")
|
|
886
922
|
$("div.open-prev-runs").show()
|
|
@@ -916,14 +952,21 @@ const run = async (
|
|
|
916
952
|
if(user_input && (!${JSON.stringify(dyn_updates)}))
|
|
917
953
|
$("#copilotinteractions").append(wrapSegment('<p>'+user_input+'</p>'+fileBadge, "You", true))
|
|
918
954
|
$("textarea[name=userinput]").val("")
|
|
919
|
-
$('
|
|
955
|
+
$('div.next_response_scratch').html("")
|
|
920
956
|
window['stream scratch ${viewname} ${rndid}'] = []
|
|
921
|
-
if(res.response)
|
|
922
|
-
$("
|
|
957
|
+
if(res.response) {
|
|
958
|
+
$(".agent-waiting-indicator").remove();
|
|
959
|
+
$("#copilotinteractions").append(res.response);
|
|
960
|
+
scrollAgentToBottom();
|
|
961
|
+
}
|
|
923
962
|
}
|
|
924
963
|
window.processCopilotResponse = processCopilotResponse;
|
|
925
964
|
window.final_agent_response = () => {
|
|
926
965
|
$("#sendbuttonicon").attr("class","far fa-paper-plane");
|
|
966
|
+
$(".agent-waiting-indicator").remove();
|
|
967
|
+
$("textarea[name=userinput]").prop("disabled", false).attr("placeholder", ${JSON.stringify(placeholder || "How can I help you?")}).focus();
|
|
968
|
+
$(".copilot-entry .submit-button").css("pointer-events", "");
|
|
969
|
+
scrollAgentToBottom();
|
|
927
970
|
}
|
|
928
971
|
window._agentDT = new DataTransfer();
|
|
929
972
|
function setAgentFiles(files) {
|
|
@@ -1046,6 +1089,14 @@ const run = async (
|
|
|
1046
1089
|
}
|
|
1047
1090
|
function spin_send_button() {
|
|
1048
1091
|
$("#sendbuttonicon").attr("class","fas fa-spinner fa-spin");
|
|
1092
|
+
$("textarea[name=userinput]").prop("disabled", true).attr("placeholder", "Waiting for response...");
|
|
1093
|
+
$(".copilot-entry .submit-button").css("pointer-events", "none");
|
|
1094
|
+
const isModernLayout = ${JSON.stringify((layout || "").startsWith("Modern chat"))};
|
|
1095
|
+
const indicator = isModernLayout
|
|
1096
|
+
? '<div class="agent-waiting-indicator chat-message chat-assistant"><div class="chat-avatar"><i class="fas fa-robot"></i></div><div class="chat-bubble"><div class="typing-dots"><span></span><span></span><span></span></div></div></div>'
|
|
1097
|
+
: '<div class="agent-waiting-indicator"><div class="typing-dots"><span></span><span></span><span></span></div></div>';
|
|
1098
|
+
$('div.next_response_scratch').before(indicator);
|
|
1099
|
+
scrollAgentToBottom();
|
|
1049
1100
|
};`,
|
|
1050
1101
|
stream &&
|
|
1051
1102
|
domReady(
|
|
@@ -1238,12 +1289,80 @@ const debug_info = async (table_id, viewname, config, body, { req, res }) => {
|
|
|
1238
1289
|
);
|
|
1239
1290
|
sysPrompt = complArgs.systemPrompt;
|
|
1240
1291
|
}
|
|
1292
|
+
const apiJson = JSON.stringify(run.context.api_interactions, null, 2);
|
|
1241
1293
|
const debug_html = div(
|
|
1242
|
-
|
|
1294
|
+
{ class: "accordion", id: "debugAccordion" },
|
|
1243
1295
|
div(
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1296
|
+
{ class: "accordion-item" },
|
|
1297
|
+
h2(
|
|
1298
|
+
{ class: "accordion-header", id: "debugHeadPrompt" },
|
|
1299
|
+
button(
|
|
1300
|
+
{
|
|
1301
|
+
class: "accordion-button collapsed",
|
|
1302
|
+
type: "button",
|
|
1303
|
+
"data-bs-toggle": "collapse",
|
|
1304
|
+
"data-bs-target": "#debugCollapsePrompt",
|
|
1305
|
+
"aria-expanded": "false",
|
|
1306
|
+
"aria-controls": "debugCollapsePrompt",
|
|
1307
|
+
},
|
|
1308
|
+
"System prompt",
|
|
1309
|
+
),
|
|
1310
|
+
),
|
|
1311
|
+
div(
|
|
1312
|
+
{
|
|
1313
|
+
id: "debugCollapsePrompt",
|
|
1314
|
+
class: "accordion-collapse collapse",
|
|
1315
|
+
"aria-labelledby": "debugHeadPrompt",
|
|
1316
|
+
"data-bs-parent": "#debugAccordion",
|
|
1317
|
+
},
|
|
1318
|
+
div(
|
|
1319
|
+
{ class: "accordion-body" },
|
|
1320
|
+
pre({ style: "white-space:pre-wrap" }, text(escapeHtml(sysPrompt))),
|
|
1321
|
+
),
|
|
1322
|
+
),
|
|
1323
|
+
),
|
|
1324
|
+
div(
|
|
1325
|
+
{ class: "accordion-item" },
|
|
1326
|
+
h2(
|
|
1327
|
+
{ class: "accordion-header", id: "debugHeadAPI" },
|
|
1328
|
+
button(
|
|
1329
|
+
{
|
|
1330
|
+
class: "accordion-button",
|
|
1331
|
+
type: "button",
|
|
1332
|
+
"data-bs-toggle": "collapse",
|
|
1333
|
+
"data-bs-target": "#debugCollapseAPI",
|
|
1334
|
+
"aria-expanded": "true",
|
|
1335
|
+
"aria-controls": "debugCollapseAPI",
|
|
1336
|
+
},
|
|
1337
|
+
"API interactions",
|
|
1338
|
+
),
|
|
1339
|
+
),
|
|
1340
|
+
div(
|
|
1341
|
+
{
|
|
1342
|
+
id: "debugCollapseAPI",
|
|
1343
|
+
class: "accordion-collapse collapse show",
|
|
1344
|
+
"aria-labelledby": "debugHeadAPI",
|
|
1345
|
+
"data-bs-parent": "#debugAccordion",
|
|
1346
|
+
},
|
|
1347
|
+
div(
|
|
1348
|
+
{ class: "accordion-body" },
|
|
1349
|
+
button(
|
|
1350
|
+
{
|
|
1351
|
+
class: "btn btn-sm btn-outline-secondary mb-2",
|
|
1352
|
+
onclick: `
|
|
1353
|
+
var t=document.getElementById('debugApiPre').textContent;
|
|
1354
|
+
navigator.clipboard.writeText(t).then(function(){
|
|
1355
|
+
var b=event.target;b.textContent='Copied!';
|
|
1356
|
+
setTimeout(function(){b.textContent='Copy to clipboard'},1500)
|
|
1357
|
+
})`,
|
|
1358
|
+
},
|
|
1359
|
+
"Copy to clipboard",
|
|
1360
|
+
),
|
|
1361
|
+
pre(
|
|
1362
|
+
{ id: "debugApiPre", style: "white-space:pre-wrap" },
|
|
1363
|
+
text(escapeHtml(apiJson)),
|
|
1364
|
+
),
|
|
1365
|
+
),
|
|
1247
1366
|
),
|
|
1248
1367
|
),
|
|
1249
1368
|
);
|
package/common.js
CHANGED
|
@@ -489,6 +489,8 @@ const process_interaction = async (
|
|
|
489
489
|
chat,
|
|
490
490
|
req,
|
|
491
491
|
run,
|
|
492
|
+
agent_view_config: agentsViewCfg,
|
|
493
|
+
dyn_updates,
|
|
492
494
|
async generate(prompt, opts = {}) {
|
|
493
495
|
generateUsed = true;
|
|
494
496
|
return await sysState.functions.llm_generate.run(prompt, {
|
|
@@ -513,7 +515,7 @@ const process_interaction = async (
|
|
|
513
515
|
});
|
|
514
516
|
if (generateUsed)
|
|
515
517
|
await addToContext(run, {
|
|
516
|
-
interactions:
|
|
518
|
+
interactions: run.context.interactions,
|
|
517
519
|
});
|
|
518
520
|
if (postprocres.stop) stop = true;
|
|
519
521
|
if (postprocres.add_system_prompt)
|
|
@@ -544,35 +546,35 @@ const process_interaction = async (
|
|
|
544
546
|
layout,
|
|
545
547
|
),
|
|
546
548
|
);
|
|
547
|
-
|
|
548
|
-
// run.context.interactions.forEach((ic) => {});
|
|
549
|
+
|
|
549
550
|
const result = add_resp;
|
|
550
551
|
await sysState.functions.llm_add_message.run(
|
|
551
552
|
"assistant",
|
|
553
|
+
|
|
552
554
|
!result || typeof result === "string"
|
|
553
|
-
?
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
}
|
|
557
|
-
: {
|
|
558
|
-
type: "json",
|
|
559
|
-
value: JSON.parse(JSON.stringify(result)),
|
|
560
|
-
},
|
|
555
|
+
? result || "Action run"
|
|
556
|
+
: JSON.stringify(result),
|
|
557
|
+
|
|
561
558
|
{
|
|
562
559
|
chat: run.context.interactions,
|
|
563
560
|
},
|
|
564
561
|
);
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
562
|
+
await addToContext(run, {
|
|
563
|
+
interactions: run.context.interactions,
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
if (!postprocres.stop) {
|
|
567
|
+
await sysState.functions.llm_add_message.run(
|
|
568
|
+
"user",
|
|
569
|
+
postprocres.follow_up_prompt || "Continue with the query",
|
|
570
|
+
{
|
|
571
|
+
chat: run.context.interactions,
|
|
572
|
+
},
|
|
573
|
+
);
|
|
574
|
+
await addToContext(run, {
|
|
575
|
+
interactions: run.context.interactions,
|
|
576
|
+
});
|
|
577
|
+
myHasResult = true;
|
|
576
578
|
}
|
|
577
579
|
if (postprocres.add_user_action && viewname) {
|
|
578
580
|
const user_actions = Array.isArray()
|
|
@@ -635,7 +637,7 @@ const process_interaction = async (
|
|
|
635
637
|
return {
|
|
636
638
|
json: {
|
|
637
639
|
success: "ok",
|
|
638
|
-
...(is_sub_agent ? { raw_responses } : {}),
|
|
640
|
+
...(is_sub_agent && !stream ? { raw_responses } : {}),
|
|
639
641
|
response: [...prevResponses, ...responses].join(""),
|
|
640
642
|
run_id: run?.id,
|
|
641
643
|
},
|
package/package.json
CHANGED
|
@@ -18,6 +18,24 @@ const { validID } = require("@saltcorn/markup/layout_utils");
|
|
|
18
18
|
const vm = require("vm");
|
|
19
19
|
const { replaceUserContinue } = require("../common");
|
|
20
20
|
|
|
21
|
+
function extractCode(str) {
|
|
22
|
+
// Try ```javascript fence
|
|
23
|
+
if (str.includes("```javascript")) {
|
|
24
|
+
return str.split("```javascript")[1].split("```")[0];
|
|
25
|
+
}
|
|
26
|
+
// Try ```js fence
|
|
27
|
+
if (str.includes("```js\n") || str.includes("```js\r")) {
|
|
28
|
+
return str.split(/```js\s/)[1].split("```")[0];
|
|
29
|
+
}
|
|
30
|
+
// Try generic ``` fence (code is between first and second ```)
|
|
31
|
+
const fenceMatch = str.match(/```\s*\n([\s\S]*?)```/);
|
|
32
|
+
if (fenceMatch) {
|
|
33
|
+
return fenceMatch[1];
|
|
34
|
+
}
|
|
35
|
+
// No fences found - return raw string
|
|
36
|
+
return str;
|
|
37
|
+
}
|
|
38
|
+
|
|
21
39
|
//const { fieldProperties } = require("./helpers");
|
|
22
40
|
|
|
23
41
|
class GenerateAndRunJsCodeSkill {
|
|
@@ -105,6 +123,14 @@ class GenerateAndRunJsCodeSkill {
|
|
|
105
123
|
sublabel: "Allow calls to functions from codepages and modules",
|
|
106
124
|
type: "Bool",
|
|
107
125
|
},
|
|
126
|
+
{
|
|
127
|
+
name: "follow_up_prompt",
|
|
128
|
+
label: "Follow-up prompt",
|
|
129
|
+
sublabel:
|
|
130
|
+
"If set, the agent will continue processing after code execution with this prompt. Leave empty to stop after code result.",
|
|
131
|
+
type: "String",
|
|
132
|
+
fieldview: "textarea",
|
|
133
|
+
},
|
|
108
134
|
...(Table.subClass
|
|
109
135
|
? [
|
|
110
136
|
{
|
|
@@ -171,26 +197,34 @@ return { x, y }
|
|
|
171
197
|
|
|
172
198
|
${extra || ""}
|
|
173
199
|
|
|
200
|
+
CRITICAL: Your response must contain ONLY a single JavaScript code block wrapped in \`\`\`javascript ... \`\`\` fences. Do not include any text, explanation, or commentary before or after the code block.
|
|
201
|
+
|
|
174
202
|
Now generate the JavaScript code required by the user.`,
|
|
175
203
|
);
|
|
176
204
|
getState().log(
|
|
177
205
|
6,
|
|
178
206
|
"Generated code:\n--BEGIN CODE--\n" + str + "\n--END CODE--\n",
|
|
179
207
|
);
|
|
180
|
-
const js_code = str
|
|
181
|
-
? str.split("```javascript")[1].split("```")[0]
|
|
182
|
-
: str;
|
|
208
|
+
const js_code = extractCode(str);
|
|
183
209
|
return js_code;
|
|
184
210
|
};
|
|
185
211
|
const js_code = await gen_the_code();
|
|
186
212
|
emit_update("Running code");
|
|
213
|
+
const ensureResult = (res) => {
|
|
214
|
+
if (res && typeof res === "object") return JSON.stringify(res);
|
|
215
|
+
if (res !== undefined && res !== null && res !== "") return res;
|
|
216
|
+
return "Code executed successfully but returned no output.";
|
|
217
|
+
};
|
|
187
218
|
try {
|
|
188
219
|
const res = await this.runCode(js_code, { user: req.user });
|
|
189
|
-
//console.log("code response", res);
|
|
190
220
|
getState().log(6, "Code answer: " + JSON.stringify(res));
|
|
221
|
+
const effectiveRes = ensureResult(res);
|
|
191
222
|
return {
|
|
192
|
-
stop: typeof res === "string",
|
|
193
|
-
add_response:
|
|
223
|
+
stop: typeof res === "string" && !this.follow_up_prompt,
|
|
224
|
+
add_response: effectiveRes,
|
|
225
|
+
...(this.follow_up_prompt
|
|
226
|
+
? { follow_up_prompt: this.follow_up_prompt }
|
|
227
|
+
: {}),
|
|
194
228
|
};
|
|
195
229
|
} catch (err) {
|
|
196
230
|
console.error(err);
|
|
@@ -208,13 +242,27 @@ ${err.message}
|
|
|
208
242
|
|
|
209
243
|
Correct this error.
|
|
210
244
|
`);
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
245
|
+
try {
|
|
246
|
+
const res = await this.runCode(retry_js_code, {
|
|
247
|
+
user: req.user,
|
|
248
|
+
});
|
|
249
|
+
getState().log(6, "Code retry answer: " + JSON.stringify(res));
|
|
250
|
+
const effectiveRes = ensureResult(res);
|
|
251
|
+
return {
|
|
252
|
+
stop: typeof res === "string" && !this.follow_up_prompt,
|
|
253
|
+
add_response: effectiveRes,
|
|
254
|
+
...(this.follow_up_prompt
|
|
255
|
+
? { follow_up_prompt: this.follow_up_prompt }
|
|
256
|
+
: {}),
|
|
257
|
+
};
|
|
258
|
+
} catch (retryErr) {
|
|
259
|
+
console.error(retryErr);
|
|
260
|
+
return {
|
|
261
|
+
add_response:
|
|
262
|
+
"Error: code generation failed after retry: " +
|
|
263
|
+
retryErr.message,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
218
266
|
}
|
|
219
267
|
},
|
|
220
268
|
function: {
|
package/skills/Subagent.js
CHANGED
|
@@ -52,6 +52,12 @@ class SubagentToSkill {
|
|
|
52
52
|
sublabel: `Optional. The prompt initialising the subagent. Example: "Continue answering my query using the tool now at you disposal"`,
|
|
53
53
|
type: "String",
|
|
54
54
|
},
|
|
55
|
+
{
|
|
56
|
+
name: "handoff_prompt",
|
|
57
|
+
label: "Handoff prompt",
|
|
58
|
+
sublabel: `Optional. A prompt to process the results of the subagent. Example: "Analyze this response in relation to my query"`,
|
|
59
|
+
type: "String",
|
|
60
|
+
},
|
|
55
61
|
];
|
|
56
62
|
}
|
|
57
63
|
|
|
@@ -78,8 +84,10 @@ class SubagentToSkill {
|
|
|
78
84
|
emit_update,
|
|
79
85
|
run,
|
|
80
86
|
chat,
|
|
87
|
+
agent_view_config,
|
|
88
|
+
dyn_updates,
|
|
81
89
|
}) => {
|
|
82
|
-
getState().log(6, "Running subagent", this.agent_name);
|
|
90
|
+
getState().log(6, "Running subagent", this.agent_name);
|
|
83
91
|
const subres = await agent_action.run({
|
|
84
92
|
row: {},
|
|
85
93
|
configuration: {
|
|
@@ -89,15 +97,20 @@ class SubagentToSkill {
|
|
|
89
97
|
"Your instructions and tools have changed. Continue answering my query using the instructions and tools at you disposal, if any",
|
|
90
98
|
},
|
|
91
99
|
user: req.user,
|
|
92
|
-
|
|
100
|
+
run,
|
|
93
101
|
is_sub_agent: true,
|
|
102
|
+
agent_view_config,
|
|
103
|
+
dyn_updates,
|
|
94
104
|
req,
|
|
95
105
|
});
|
|
96
|
-
getState().log(6, "Subagent response", subres
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
return { add_responses: subres.json.raw_responses };
|
|
106
|
+
getState().log(6, "Subagent response", JSON.stringify(subres, null, 2));
|
|
107
|
+
//if (subres.json.raw_responses)
|
|
108
|
+
// return { add_responses: subres.json.raw_responses };
|
|
100
109
|
return {
|
|
110
|
+
...(this.handoff_prompt
|
|
111
|
+
? { follow_up_prompt: this.handoff_prompt }
|
|
112
|
+
: { stop: true }),
|
|
113
|
+
|
|
101
114
|
//stop: true,
|
|
102
115
|
//add_response: result,
|
|
103
116
|
};
|
package/tests/action.test.js
CHANGED
|
@@ -38,7 +38,7 @@ beforeAll(async () => {
|
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
await getState().refresh_triggers(false);
|
|
41
|
-
|
|
41
|
+
await getState().setConfig("log_level", 6);
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
jest.setTimeout(40000);
|
|
@@ -46,6 +46,13 @@ jest.setTimeout(40000);
|
|
|
46
46
|
const user = { id: 1, role_id: 1 };
|
|
47
47
|
const action = require("../action");
|
|
48
48
|
|
|
49
|
+
const getLastInteraction = async ({ run_id }) => {
|
|
50
|
+
const run = await WorkflowRuns.findOne({ id: run_id });
|
|
51
|
+
return JSON.stringify(
|
|
52
|
+
run.context.interactions[run.context.interactions.length - 1],
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
49
56
|
for (const nameconfig of require("./configs")) {
|
|
50
57
|
const { name, ...config } = nameconfig;
|
|
51
58
|
describe("agent action with " + name, () => {
|
|
@@ -114,7 +121,10 @@ for (const nameconfig of require("./configs")) {
|
|
|
114
121
|
user,
|
|
115
122
|
req: { user },
|
|
116
123
|
});
|
|
117
|
-
|
|
124
|
+
|
|
125
|
+
const lastInteraction = await getLastInteraction(result.json);
|
|
126
|
+
|
|
127
|
+
expect(result.json.response || lastInteraction).toContain("987");
|
|
118
128
|
});
|
|
119
129
|
it("run multiple subagents concurrenty", async () => {
|
|
120
130
|
const configuration = { ...require("./agentcfg").agent1 };
|
|
@@ -134,7 +144,8 @@ for (const nameconfig of require("./configs")) {
|
|
|
134
144
|
user,
|
|
135
145
|
req: { user },
|
|
136
146
|
});
|
|
137
|
-
|
|
147
|
+
const lastInteraction = await getLastInteraction(result.json);
|
|
148
|
+
expect(lastInteraction).toContain("987");
|
|
138
149
|
});
|
|
139
150
|
});
|
|
140
151
|
|