@saltcorn/agents 0.3.3 → 0.3.5
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 +1 -1
- package/common.js +25 -4
- package/package.json +1 -1
- package/skills/EmbeddingRetrieval.js +23 -6
- package/skills/FTSRetrieval.js +21 -11
package/agent-view.js
CHANGED
package/common.js
CHANGED
|
@@ -42,7 +42,7 @@ const find_tool = (name, config) => {
|
|
|
42
42
|
: Array.isArray(skillTools)
|
|
43
43
|
? skillTools
|
|
44
44
|
: [skillTools];
|
|
45
|
-
const found = tools.find((t) => t?.function
|
|
45
|
+
const found = tools.find((t) => t?.function?.name === name);
|
|
46
46
|
if (found) return { tool: found, skill };
|
|
47
47
|
}
|
|
48
48
|
};
|
|
@@ -139,6 +139,23 @@ const wrapCard = (title, ...inners) =>
|
|
|
139
139
|
div({ class: "card-body" }, inners)
|
|
140
140
|
);
|
|
141
141
|
|
|
142
|
+
const only_response_text_if_present = (interact) => {
|
|
143
|
+
if (
|
|
144
|
+
interact.role === "tool" &&
|
|
145
|
+
interact.call_id &&
|
|
146
|
+
interact.content?.[0] === "{"
|
|
147
|
+
) {
|
|
148
|
+
try {
|
|
149
|
+
const result = JSON.parse(interact.content);
|
|
150
|
+
if (result.responseText)
|
|
151
|
+
return { ...interact, content: result.responseText };
|
|
152
|
+
} catch {
|
|
153
|
+
//ignore, not json content
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return interact;
|
|
157
|
+
};
|
|
158
|
+
|
|
142
159
|
const process_interaction = async (
|
|
143
160
|
run,
|
|
144
161
|
config,
|
|
@@ -147,7 +164,7 @@ const process_interaction = async (
|
|
|
147
164
|
prevResponses = []
|
|
148
165
|
) => {
|
|
149
166
|
const complArgs = await getCompletionArguments(config, req.user);
|
|
150
|
-
complArgs.chat = run.context.interactions;
|
|
167
|
+
complArgs.chat = run.context.interactions.map(only_response_text_if_present);
|
|
151
168
|
//complArgs.debugResult = true;
|
|
152
169
|
//console.log("complArgs", JSON.stringify(complArgs, null, 2));
|
|
153
170
|
|
|
@@ -198,7 +215,11 @@ const process_interaction = async (
|
|
|
198
215
|
]
|
|
199
216
|
: [{ role: "assistant", content: answer }],
|
|
200
217
|
});
|
|
201
|
-
if (
|
|
218
|
+
if (
|
|
219
|
+
answer &&
|
|
220
|
+
typeof answer === "object" &&
|
|
221
|
+
(answer.tool_calls || answer.mcp_calls)
|
|
222
|
+
) {
|
|
202
223
|
if (answer.content)
|
|
203
224
|
responses.push(wrapSegment(md.render(answer.content), agent_label));
|
|
204
225
|
//const actions = [];
|
|
@@ -211,7 +232,7 @@ const process_interaction = async (
|
|
|
211
232
|
funcalls: { [tool_call.id]: tool_call.function },
|
|
212
233
|
});
|
|
213
234
|
|
|
214
|
-
const tool = find_tool(tool_call.function
|
|
235
|
+
const tool = find_tool(tool_call.function?.name, config);
|
|
215
236
|
|
|
216
237
|
if (tool) {
|
|
217
238
|
if (tool.tool.renderToolCall) {
|
package/package.json
CHANGED
|
@@ -5,6 +5,7 @@ const Table = require("@saltcorn/data/models/table");
|
|
|
5
5
|
const View = require("@saltcorn/data/models/view");
|
|
6
6
|
const { getState } = require("@saltcorn/data/db/state");
|
|
7
7
|
const db = require("@saltcorn/data/db");
|
|
8
|
+
const { interpolate } = require("@saltcorn/data/utils");
|
|
8
9
|
|
|
9
10
|
class RetrievalByEmbedding {
|
|
10
11
|
static skill_name = "Retrieval by embedding";
|
|
@@ -109,6 +110,14 @@ class RetrievalByEmbedding {
|
|
|
109
110
|
type: "String",
|
|
110
111
|
fieldview: "textarea",
|
|
111
112
|
},
|
|
113
|
+
{
|
|
114
|
+
name: "doc_format",
|
|
115
|
+
label: "Document format",
|
|
116
|
+
type: "String",
|
|
117
|
+
fieldview: "textarea",
|
|
118
|
+
sublabel:
|
|
119
|
+
"Format of text to send to LLM, use <code>{{ }}</code> to access variables in the document table. If not set, document will be sent as JSON",
|
|
120
|
+
},
|
|
112
121
|
];
|
|
113
122
|
}
|
|
114
123
|
|
|
@@ -124,7 +133,7 @@ class RetrievalByEmbedding {
|
|
|
124
133
|
: table0;
|
|
125
134
|
return {
|
|
126
135
|
type: "function",
|
|
127
|
-
process: async ({ phrase_or_question }) => {
|
|
136
|
+
process: async ({ phrase_or_question }, { req }) => {
|
|
128
137
|
const [table_name, field_name] = this.vec_field.split(".");
|
|
129
138
|
const table = Table.findOne({ name: table_name });
|
|
130
139
|
if (!table)
|
|
@@ -149,12 +158,20 @@ class RetrievalByEmbedding {
|
|
|
149
158
|
rows.forEach((r) => {
|
|
150
159
|
delete r[field_name];
|
|
151
160
|
});
|
|
161
|
+
|
|
162
|
+
const set_doc_format = (rows) => {
|
|
163
|
+
if (!this.doc_format) return { rows };
|
|
164
|
+
const responseText = rows
|
|
165
|
+
.map((row) => interpolate(this.doc_format, row, req.user))
|
|
166
|
+
.join("\n");
|
|
167
|
+
return { rows, responseText };
|
|
168
|
+
};
|
|
152
169
|
if (!rows.length)
|
|
153
170
|
return {
|
|
154
|
-
|
|
171
|
+
responseText:
|
|
155
172
|
"There are no documents related to: " + phrase_or_question,
|
|
156
173
|
};
|
|
157
|
-
else if (!this.doc_relation) return
|
|
174
|
+
else if (!this.doc_relation) return set_doc_format(rows);
|
|
158
175
|
else {
|
|
159
176
|
const relField = table.getField(this.doc_relation);
|
|
160
177
|
const relTable = Table.findOne(relField.reftable_name);
|
|
@@ -167,10 +184,10 @@ class RetrievalByEmbedding {
|
|
|
167
184
|
const docs = ids
|
|
168
185
|
.map((id) => docsUnsorted.find((d) => d.id == id))
|
|
169
186
|
.filter(Boolean);
|
|
170
|
-
return
|
|
187
|
+
return set_doc_format(docs);
|
|
171
188
|
}
|
|
172
189
|
},
|
|
173
|
-
renderToolResponse: async ({
|
|
190
|
+
renderToolResponse: async ({ responseText, rows }, { req }) => {
|
|
174
191
|
if (rows) {
|
|
175
192
|
const view = View.findOne({ name: this.list_view });
|
|
176
193
|
|
|
@@ -186,7 +203,7 @@ class RetrievalByEmbedding {
|
|
|
186
203
|
return viewRes;
|
|
187
204
|
} else return "";
|
|
188
205
|
}
|
|
189
|
-
return div(
|
|
206
|
+
return div(responseText);
|
|
190
207
|
},
|
|
191
208
|
function: {
|
|
192
209
|
name: this.toolName,
|
package/skills/FTSRetrieval.js
CHANGED
|
@@ -5,6 +5,7 @@ const Table = require("@saltcorn/data/models/table");
|
|
|
5
5
|
const View = require("@saltcorn/data/models/view");
|
|
6
6
|
const { getState } = require("@saltcorn/data/db/state");
|
|
7
7
|
const db = require("@saltcorn/data/db");
|
|
8
|
+
const { interpolate } = require("@saltcorn/data/utils");
|
|
8
9
|
|
|
9
10
|
class RetrievalByFullTextSearch {
|
|
10
11
|
static skill_name = "Retrieval by full-text search";
|
|
@@ -84,13 +85,14 @@ class RetrievalByFullTextSearch {
|
|
|
84
85
|
type: "String",
|
|
85
86
|
fieldview: "textarea",
|
|
86
87
|
},
|
|
87
|
-
|
|
88
|
-
name: "
|
|
89
|
-
label: "
|
|
88
|
+
{
|
|
89
|
+
name: "doc_format",
|
|
90
|
+
label: "Document format",
|
|
90
91
|
type: "String",
|
|
92
|
+
fieldview: "textarea",
|
|
91
93
|
sublabel:
|
|
92
|
-
"
|
|
93
|
-
}
|
|
94
|
+
"Format of text to send to LLM, use <code>{{ }}</code> to access variables in the document table. If not set, document will be sent as JSON",
|
|
95
|
+
},
|
|
94
96
|
];
|
|
95
97
|
}
|
|
96
98
|
|
|
@@ -103,7 +105,7 @@ class RetrievalByFullTextSearch {
|
|
|
103
105
|
const table = Table.findOne(this.table_name);
|
|
104
106
|
return {
|
|
105
107
|
type: "function",
|
|
106
|
-
process: async ({ phrase }) => {
|
|
108
|
+
process: async ({ phrase }, { req }) => {
|
|
107
109
|
const scState = getState();
|
|
108
110
|
const language = scState.pg_ts_config;
|
|
109
111
|
const use_websearch = scState.getConfig("search_use_websearch", false);
|
|
@@ -127,16 +129,23 @@ class RetrievalByFullTextSearch {
|
|
|
127
129
|
});
|
|
128
130
|
});
|
|
129
131
|
}
|
|
130
|
-
if (rows.length)
|
|
132
|
+
if (rows.length)
|
|
133
|
+
if (!this.doc_format) return { rows };
|
|
134
|
+
else {
|
|
135
|
+
const responseText = rows
|
|
136
|
+
.map((row) => interpolate(this.doc_format, row, req.user))
|
|
137
|
+
.join("\n");
|
|
138
|
+
return { rows, responseText };
|
|
139
|
+
}
|
|
131
140
|
else
|
|
132
141
|
return {
|
|
133
|
-
|
|
142
|
+
responseText: "There are no rows related to: " + phrase,
|
|
134
143
|
};
|
|
135
144
|
},
|
|
136
145
|
/*renderToolCall({ phrase }, { req }) {
|
|
137
146
|
return div({ class: "border border-primary p-2 m-2" }, phrase);
|
|
138
147
|
},*/
|
|
139
|
-
renderToolResponse: async ({
|
|
148
|
+
renderToolResponse: async ({ responseText, rows }, { req }) => {
|
|
140
149
|
if (rows) {
|
|
141
150
|
const view = View.findOne({ name: this.list_view });
|
|
142
151
|
|
|
@@ -148,7 +157,7 @@ class RetrievalByFullTextSearch {
|
|
|
148
157
|
return viewRes;
|
|
149
158
|
} else return "";
|
|
150
159
|
}
|
|
151
|
-
return div({ class: "border border-success p-2 m-2" },
|
|
160
|
+
return div({ class: "border border-success p-2 m-2" }, responseText);
|
|
152
161
|
},
|
|
153
162
|
function: {
|
|
154
163
|
name: this.toolName,
|
|
@@ -161,7 +170,8 @@ class RetrievalByFullTextSearch {
|
|
|
161
170
|
properties: {
|
|
162
171
|
phrase: {
|
|
163
172
|
type: "string",
|
|
164
|
-
description:
|
|
173
|
+
description:
|
|
174
|
+
"The phrase to search the table with. The search phrase is the synatx used by web search engines: use double quotes for exact match, unquoted text for words in any order, dash (minus sign) to exclude a word. Do not use SQL or any other formal query language.",
|
|
165
175
|
},
|
|
166
176
|
},
|
|
167
177
|
},
|