@tyvm/knowhow 0.0.48 → 0.0.49
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/package.json +1 -1
- package/src/agents/base/base.ts +9 -1
- package/src/chat/modules/AgentModule.ts +22 -3
- package/src/embeddings.ts +2 -4
- package/src/processors/CustomVariables.ts +48 -70
- package/src/processors/TokenCompressor.ts +5 -4
- package/src/processors/ToolResponseCache.ts +6 -9
- package/tests/processors/CustomVariables.test.ts +110 -55
- package/tests/processors/TokenCompressor.test.ts +48 -49
- package/tests/processors/ToolResponseCache.test.ts +309 -261
- package/ts_build/package.json +1 -1
- package/ts_build/src/agents/base/base.d.ts +5 -0
- package/ts_build/src/agents/base/base.js +3 -1
- package/ts_build/src/agents/base/base.js.map +1 -1
- package/ts_build/src/chat/modules/AgentModule.js +9 -1
- package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
- package/ts_build/src/embeddings.js +2 -4
- package/ts_build/src/embeddings.js.map +1 -1
- package/ts_build/src/processors/CustomVariables.js +36 -47
- package/ts_build/src/processors/CustomVariables.js.map +1 -1
- package/ts_build/src/processors/TokenCompressor.js +2 -2
- package/ts_build/src/processors/TokenCompressor.js.map +1 -1
- package/ts_build/src/processors/ToolResponseCache.js +6 -8
- package/ts_build/src/processors/ToolResponseCache.js.map +1 -1
- package/ts_build/tests/processors/CustomVariables.test.js +41 -38
- package/ts_build/tests/processors/CustomVariables.test.js.map +1 -1
- package/ts_build/tests/processors/TokenCompressor.test.js +4 -5
- package/ts_build/tests/processors/TokenCompressor.test.js.map +1 -1
- package/ts_build/tests/processors/ToolResponseCache.test.js +89 -78
- package/ts_build/tests/processors/ToolResponseCache.test.js.map +1 -1
package/package.json
CHANGED
package/src/agents/base/base.ts
CHANGED
|
@@ -31,6 +31,11 @@ export interface AgentContext {
|
|
|
31
31
|
Clients?: AIClient;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
export interface ToolCallEvent {
|
|
35
|
+
toolCall: ToolCall;
|
|
36
|
+
functionResp: any;
|
|
37
|
+
}
|
|
38
|
+
|
|
34
39
|
export abstract class BaseAgent implements IAgent {
|
|
35
40
|
abstract name: string;
|
|
36
41
|
abstract description: string;
|
|
@@ -62,7 +67,8 @@ export abstract class BaseAgent implements IAgent {
|
|
|
62
67
|
newThread: "new_thread",
|
|
63
68
|
threadUpdate: "thread_update",
|
|
64
69
|
costUpdate: "cost_update",
|
|
65
|
-
|
|
70
|
+
toolCall: "tool:pre_call",
|
|
71
|
+
toolUsed: "tool:post_call",
|
|
66
72
|
done: "done",
|
|
67
73
|
pause: "pause",
|
|
68
74
|
kill: "kill",
|
|
@@ -294,6 +300,8 @@ export abstract class BaseAgent implements IAgent {
|
|
|
294
300
|
abstract getInitialMessages(userInput: string): Promise<Message[]>;
|
|
295
301
|
|
|
296
302
|
async processToolMessages(toolCall: ToolCall) {
|
|
303
|
+
this.agentEvents.emit(this.eventTypes.toolCall, { toolCall });
|
|
304
|
+
|
|
297
305
|
const { functionResp, toolMessages } = await this.tools.callTool(
|
|
298
306
|
toolCall,
|
|
299
307
|
this.getEnabledToolNames()
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
} from "../../processors/index";
|
|
21
21
|
import { TaskInfo, ChatSession } from "../types";
|
|
22
22
|
import { agents } from "../../agents";
|
|
23
|
+
import { ToolCallEvent } from "src/agents/base/base";
|
|
23
24
|
|
|
24
25
|
export class AgentModule extends BaseChatModule {
|
|
25
26
|
name = "agent";
|
|
@@ -719,10 +720,28 @@ ${reason}
|
|
|
719
720
|
]);
|
|
720
721
|
|
|
721
722
|
// Set up event listeners
|
|
723
|
+
if (!agent.agentEvents.listenerCount(agent.eventTypes.toolCall)) {
|
|
724
|
+
agent.agentEvents.on(
|
|
725
|
+
agent.eventTypes.toolCall,
|
|
726
|
+
(responseMsg: ToolCallEvent) => {
|
|
727
|
+
console.time(JSON.stringify(responseMsg.toolCall.function.name));
|
|
728
|
+
console.log(
|
|
729
|
+
` 🔨 Tool: ${responseMsg.toolCall.function.name}\n Args: ${responseMsg.toolCall.function.arguments}\n`
|
|
730
|
+
);
|
|
731
|
+
}
|
|
732
|
+
);
|
|
733
|
+
}
|
|
722
734
|
if (!agent.agentEvents.listenerCount(agent.eventTypes.toolUsed)) {
|
|
723
|
-
agent.agentEvents.on(
|
|
724
|
-
|
|
725
|
-
|
|
735
|
+
agent.agentEvents.on(
|
|
736
|
+
agent.eventTypes.toolUsed,
|
|
737
|
+
(responseMsg: ToolCallEvent) => {
|
|
738
|
+
console.timeEnd(JSON.stringify(responseMsg.toolCall.function.name));
|
|
739
|
+
console.log(
|
|
740
|
+
` 🔨 Tool Response:
|
|
741
|
+
${JSON.stringify(responseMsg.functionResp, null, 2)}`
|
|
742
|
+
);
|
|
743
|
+
}
|
|
744
|
+
);
|
|
726
745
|
}
|
|
727
746
|
|
|
728
747
|
const taskCompleted = new Promise<string>((resolve) => {
|
package/src/embeddings.ts
CHANGED
|
@@ -136,11 +136,10 @@ export async function embedSource(
|
|
|
136
136
|
inputs = [source.input];
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
console.log(`
|
|
139
|
+
console.log(`Checking ${inputs.length} files`);
|
|
140
140
|
if (inputs.length > 1000) {
|
|
141
141
|
console.error("Large number of files detected. This may take a while");
|
|
142
142
|
}
|
|
143
|
-
console.log(inputs);
|
|
144
143
|
const embeddings: Embeddable[] = await loadEmbedding(source.output);
|
|
145
144
|
let batch = [];
|
|
146
145
|
let index = 0;
|
|
@@ -231,7 +230,6 @@ export async function embed(
|
|
|
231
230
|
}
|
|
232
231
|
|
|
233
232
|
if (alreadyEmbedded) {
|
|
234
|
-
console.log("Skipping", chunkId);
|
|
235
233
|
continue;
|
|
236
234
|
}
|
|
237
235
|
|
|
@@ -468,7 +466,7 @@ export async function queryEmbedding<E>(
|
|
|
468
466
|
model = EmbeddingModels.openai.EmbeddingAda2
|
|
469
467
|
) {
|
|
470
468
|
const providerEmbeddings = await Clients.createEmbedding("", {
|
|
471
|
-
input: takeFirstNWords(query, 5000),
|
|
469
|
+
input: takeFirstNWords(query, 5000).slice(0, 16000),
|
|
472
470
|
model,
|
|
473
471
|
});
|
|
474
472
|
const queryVector = providerEmbeddings.data[0].embedding;
|
|
@@ -101,18 +101,24 @@ export class CustomVariables {
|
|
|
101
101
|
*/
|
|
102
102
|
private listVariables(): string {
|
|
103
103
|
const variableNames = Object.keys(this.variables);
|
|
104
|
-
|
|
104
|
+
|
|
105
105
|
if (variableNames.length === 0) {
|
|
106
106
|
return "No variables are currently stored.";
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
const variableList = variableNames
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
109
|
+
const variableList = variableNames
|
|
110
|
+
.map((name) => {
|
|
111
|
+
const value = this.variables[name];
|
|
112
|
+
const preview =
|
|
113
|
+
typeof value === "string"
|
|
114
|
+
? value.length > 50
|
|
115
|
+
? value.substring(0, 50) + "..."
|
|
116
|
+
: value
|
|
117
|
+
: JSON.stringify(value).substring(0, 50) +
|
|
118
|
+
(JSON.stringify(value).length > 50 ? "..." : "");
|
|
119
|
+
return `- ${name}: ${preview}`;
|
|
120
|
+
})
|
|
121
|
+
.join("\n");
|
|
116
122
|
|
|
117
123
|
return `Currently stored variables (${variableNames.length}):\n${variableList}`;
|
|
118
124
|
}
|
|
@@ -146,17 +152,17 @@ export class CustomVariables {
|
|
|
146
152
|
// Check if ALL variables are undefined - if so, return just the error message for the first one
|
|
147
153
|
const variableMatches = value.match(/\{\{([a-zA-Z0-9_]+)\}\}/g);
|
|
148
154
|
if (variableMatches) {
|
|
149
|
-
const allUndefined = variableMatches.every(match => {
|
|
150
|
-
const varName = match.replace(/[{}]/g,
|
|
155
|
+
const allUndefined = variableMatches.every((match) => {
|
|
156
|
+
const varName = match.replace(/[{}]/g, "");
|
|
151
157
|
return !(varName in this.variables);
|
|
152
158
|
});
|
|
153
|
-
|
|
159
|
+
|
|
154
160
|
if (allUndefined && variableMatches.length > 0) {
|
|
155
|
-
const firstUndefinedVar = variableMatches[0].replace(/[{}]/g,
|
|
161
|
+
const firstUndefinedVar = variableMatches[0].replace(/[{}]/g, "");
|
|
156
162
|
return `{{ERROR: Variable "${firstUndefinedVar}" is not defined}}`;
|
|
157
163
|
}
|
|
158
164
|
}
|
|
159
|
-
|
|
165
|
+
|
|
160
166
|
// Otherwise, proceed with partial substitution
|
|
161
167
|
return value.replace(/\{\{([a-zA-Z0-9_]+)\}\}/g, (match, varName) => {
|
|
162
168
|
// Prevent infinite recursion
|
|
@@ -251,62 +257,34 @@ export class CustomVariables {
|
|
|
251
257
|
*/
|
|
252
258
|
private registerTools(toolsService: ToolsService): void {
|
|
253
259
|
// Register setVariable tool
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
return await this.storeToolCallToVariable(
|
|
283
|
-
varName,
|
|
284
|
-
toolName,
|
|
285
|
-
toolArgs
|
|
286
|
-
);
|
|
287
|
-
},
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// Register listVariables tool
|
|
292
|
-
if (!toolsService.getTool(this.listVariablesToolName)) {
|
|
293
|
-
toolsService.addTool(listVariablesToolDefinition);
|
|
294
|
-
toolsService.addFunctions({
|
|
295
|
-
[this.listVariablesToolName]: () => {
|
|
296
|
-
return this.listVariables();
|
|
297
|
-
},
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
// Register deleteVariable tool
|
|
302
|
-
if (!toolsService.getTool(this.deleteVariableToolName)) {
|
|
303
|
-
toolsService.addTool(deleteVariableToolDefinition);
|
|
304
|
-
toolsService.addFunctions({
|
|
305
|
-
[this.deleteVariableToolName]: (varName: string) => {
|
|
306
|
-
return this.deleteVariable(varName);
|
|
307
|
-
},
|
|
308
|
-
});
|
|
309
|
-
}
|
|
260
|
+
toolsService.addTools([
|
|
261
|
+
setVariableToolDefinition,
|
|
262
|
+
getVariableToolDefinition,
|
|
263
|
+
storeToolCallToVariableDefinition,
|
|
264
|
+
listVariablesToolDefinition,
|
|
265
|
+
deleteVariableToolDefinition,
|
|
266
|
+
]);
|
|
267
|
+
toolsService.addFunctions({
|
|
268
|
+
[this.setVariableToolName]: (name: string, contents: any) => {
|
|
269
|
+
return this.setVariable(name, contents);
|
|
270
|
+
},
|
|
271
|
+
[this.getVariableToolName]: (varName: string) => {
|
|
272
|
+
return this.getVariable(varName);
|
|
273
|
+
},
|
|
274
|
+
[this.storeToolCallToolName]: async (
|
|
275
|
+
varName: string,
|
|
276
|
+
toolName: string,
|
|
277
|
+
toolArgs: string
|
|
278
|
+
) => {
|
|
279
|
+
return await this.storeToolCallToVariable(varName, toolName, toolArgs);
|
|
280
|
+
},
|
|
281
|
+
[this.listVariablesToolName]: () => {
|
|
282
|
+
return this.listVariables();
|
|
283
|
+
},
|
|
284
|
+
[this.deleteVariableToolName]: (varName: string) => {
|
|
285
|
+
return this.deleteVariable(varName);
|
|
286
|
+
},
|
|
287
|
+
});
|
|
310
288
|
}
|
|
311
289
|
|
|
312
290
|
/**
|
|
@@ -434,4 +412,4 @@ export const deleteVariableToolDefinition: Tool = {
|
|
|
434
412
|
required: ["varName"],
|
|
435
413
|
},
|
|
436
414
|
},
|
|
437
|
-
};
|
|
415
|
+
};
|
|
@@ -116,8 +116,9 @@ export class TokenCompressor {
|
|
|
116
116
|
|
|
117
117
|
// For nested properties (path !== ""), use maxTokens to avoid recompressing stored data
|
|
118
118
|
// For top-level content (path === ""), use compressionThreshold to determine compression
|
|
119
|
-
const thresholdToUse =
|
|
120
|
-
|
|
119
|
+
const thresholdToUse =
|
|
120
|
+
path === "" ? this.compressionThreshold : this.maxTokens;
|
|
121
|
+
|
|
121
122
|
if (tokens <= thresholdToUse) {
|
|
122
123
|
return content;
|
|
123
124
|
}
|
|
@@ -320,8 +321,8 @@ export class TokenCompressor {
|
|
|
320
321
|
}
|
|
321
322
|
|
|
322
323
|
registerTool(toolsService?: ToolsService): void {
|
|
323
|
-
if (toolsService
|
|
324
|
-
toolsService.
|
|
324
|
+
if (toolsService) {
|
|
325
|
+
toolsService.addTools([expandTokensDefinition]);
|
|
325
326
|
toolsService.addFunctions({
|
|
326
327
|
[this.toolName]: (key: string) => {
|
|
327
328
|
const data = this.retrieveString(key);
|
|
@@ -130,7 +130,6 @@ export class ToolResponseCache {
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
try {
|
|
133
|
-
|
|
134
133
|
// First parse the stored string as JSON, then handle nested JSON strings
|
|
135
134
|
const jsonData = this.tryParseJson(data);
|
|
136
135
|
if (!jsonData) {
|
|
@@ -207,14 +206,12 @@ export class ToolResponseCache {
|
|
|
207
206
|
* Registers the jqToolResponse tool with the ToolsService
|
|
208
207
|
*/
|
|
209
208
|
registerTool(toolsService: ToolsService): void {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
});
|
|
217
|
-
}
|
|
209
|
+
toolsService.addTools([jqToolResponseDefinition]);
|
|
210
|
+
toolsService.addFunctions({
|
|
211
|
+
[this.toolName]: async (toolCallId: string, jqQuery: string) => {
|
|
212
|
+
return await this.queryToolResponse(toolCallId, jqQuery);
|
|
213
|
+
},
|
|
214
|
+
});
|
|
218
215
|
}
|
|
219
216
|
}
|
|
220
217
|
|
|
@@ -8,7 +8,7 @@ describe("CustomVariables", () => {
|
|
|
8
8
|
|
|
9
9
|
beforeEach(() => {
|
|
10
10
|
mockToolsService = {
|
|
11
|
-
|
|
11
|
+
addTools: jest.fn(),
|
|
12
12
|
addFunctions: jest.fn(),
|
|
13
13
|
getTool: jest.fn().mockReturnValue(undefined),
|
|
14
14
|
callTool: jest.fn(),
|
|
@@ -23,12 +23,12 @@ describe("CustomVariables", () => {
|
|
|
23
23
|
|
|
24
24
|
describe("constructor", () => {
|
|
25
25
|
it("should register all variable tools with ToolsService", () => {
|
|
26
|
-
expect(mockToolsService.
|
|
27
|
-
expect(mockToolsService.addFunctions).toHaveBeenCalledTimes(
|
|
26
|
+
expect(mockToolsService.addTools).toHaveBeenCalledTimes(1);
|
|
27
|
+
expect(mockToolsService.addFunctions).toHaveBeenCalledTimes(1);
|
|
28
28
|
|
|
29
29
|
// Verify all tools are registered
|
|
30
|
-
const addToolCalls = mockToolsService.
|
|
31
|
-
const toolNames = addToolCalls.map(
|
|
30
|
+
const addToolCalls = mockToolsService.addTools.mock.calls;
|
|
31
|
+
const toolNames = addToolCalls[0][0].map((args) => args.function.name);
|
|
32
32
|
|
|
33
33
|
expect(toolNames).toContain("setVariable");
|
|
34
34
|
expect(toolNames).toContain("getVariable");
|
|
@@ -37,12 +37,15 @@ describe("CustomVariables", () => {
|
|
|
37
37
|
expect(toolNames).toContain("deleteVariable");
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
it("should
|
|
41
|
-
mockToolsService.getTool.mockReturnValue({
|
|
40
|
+
it("should overwrite tools if they already exist", () => {
|
|
41
|
+
mockToolsService.getTool.mockReturnValue({
|
|
42
|
+
type: "function",
|
|
43
|
+
function: { name: "setVariable" },
|
|
44
|
+
} as any);
|
|
42
45
|
const newCustomVariables = new CustomVariables(mockToolsService);
|
|
43
46
|
|
|
44
|
-
// Should still be called
|
|
45
|
-
expect(mockToolsService.
|
|
47
|
+
// Should still be called once per instance creation
|
|
48
|
+
expect(mockToolsService.addTools).toHaveBeenCalledTimes(2);
|
|
46
49
|
});
|
|
47
50
|
});
|
|
48
51
|
|
|
@@ -51,7 +54,9 @@ describe("CustomVariables", () => {
|
|
|
51
54
|
|
|
52
55
|
beforeEach(() => {
|
|
53
56
|
const addFunctionsCalls = mockToolsService.addFunctions.mock.calls;
|
|
54
|
-
const setVariableCall = addFunctionsCalls.find(
|
|
57
|
+
const setVariableCall = addFunctionsCalls.find(
|
|
58
|
+
(call) => call[0].setVariable
|
|
59
|
+
);
|
|
55
60
|
setVariableFunction = setVariableCall[0].setVariable;
|
|
56
61
|
});
|
|
57
62
|
|
|
@@ -86,7 +91,9 @@ describe("CustomVariables", () => {
|
|
|
86
91
|
|
|
87
92
|
beforeEach(() => {
|
|
88
93
|
const addFunctionsCalls = mockToolsService.addFunctions.mock.calls;
|
|
89
|
-
const setVariableCall = addFunctionsCalls.find(
|
|
94
|
+
const setVariableCall = addFunctionsCalls.find(
|
|
95
|
+
(call) => call[0].setVariable
|
|
96
|
+
);
|
|
90
97
|
setVariableFunction = setVariableCall[0].setVariable;
|
|
91
98
|
});
|
|
92
99
|
|
|
@@ -122,8 +129,12 @@ describe("CustomVariables", () => {
|
|
|
122
129
|
|
|
123
130
|
beforeEach(() => {
|
|
124
131
|
const addFunctionsCalls = mockToolsService.addFunctions.mock.calls;
|
|
125
|
-
const setVariableCall = addFunctionsCalls.find(
|
|
126
|
-
|
|
132
|
+
const setVariableCall = addFunctionsCalls.find(
|
|
133
|
+
(call) => call[0].setVariable
|
|
134
|
+
);
|
|
135
|
+
const getVariableCall = addFunctionsCalls.find(
|
|
136
|
+
(call) => call[0].getVariable
|
|
137
|
+
);
|
|
127
138
|
setVariableFunction = setVariableCall[0].setVariable;
|
|
128
139
|
getVariableFunction = getVariableCall[0].getVariable;
|
|
129
140
|
});
|
|
@@ -166,8 +177,12 @@ describe("CustomVariables", () => {
|
|
|
166
177
|
|
|
167
178
|
beforeEach(() => {
|
|
168
179
|
const addFunctionsCalls = mockToolsService.addFunctions.mock.calls;
|
|
169
|
-
const setVariableCall = addFunctionsCalls.find(
|
|
170
|
-
|
|
180
|
+
const setVariableCall = addFunctionsCalls.find(
|
|
181
|
+
(call) => call[0].setVariable
|
|
182
|
+
);
|
|
183
|
+
const listVariablesCall = addFunctionsCalls.find(
|
|
184
|
+
(call) => call[0].listVariables
|
|
185
|
+
);
|
|
171
186
|
setVariableFunction = setVariableCall[0].setVariable;
|
|
172
187
|
listVariablesFunction = listVariablesCall[0].listVariables;
|
|
173
188
|
});
|
|
@@ -204,8 +219,12 @@ describe("CustomVariables", () => {
|
|
|
204
219
|
|
|
205
220
|
beforeEach(() => {
|
|
206
221
|
const addFunctionsCalls = mockToolsService.addFunctions.mock.calls;
|
|
207
|
-
const setVariableCall = addFunctionsCalls.find(
|
|
208
|
-
|
|
222
|
+
const setVariableCall = addFunctionsCalls.find(
|
|
223
|
+
(call) => call[0].setVariable
|
|
224
|
+
);
|
|
225
|
+
const deleteVariableCall = addFunctionsCalls.find(
|
|
226
|
+
(call) => call[0].deleteVariable
|
|
227
|
+
);
|
|
209
228
|
setVariableFunction = setVariableCall[0].setVariable;
|
|
210
229
|
deleteVariableFunction = deleteVariableCall[0].deleteVariable;
|
|
211
230
|
});
|
|
@@ -213,7 +232,9 @@ describe("CustomVariables", () => {
|
|
|
213
232
|
it("should delete existing variables", () => {
|
|
214
233
|
setVariableFunction("testVar", "test value");
|
|
215
234
|
const result = deleteVariableFunction("testVar");
|
|
216
|
-
expect(result).toContain(
|
|
235
|
+
expect(result).toContain(
|
|
236
|
+
'Variable "testVar" has been deleted successfully'
|
|
237
|
+
);
|
|
217
238
|
expect(customVariables.getVariableNames()).not.toContain("testVar");
|
|
218
239
|
});
|
|
219
240
|
|
|
@@ -229,11 +250,17 @@ describe("CustomVariables", () => {
|
|
|
229
250
|
});
|
|
230
251
|
|
|
231
252
|
describe("storeToolCallToVariable functionality", () => {
|
|
232
|
-
let storeToolCallFunction: (
|
|
253
|
+
let storeToolCallFunction: (
|
|
254
|
+
varName: string,
|
|
255
|
+
toolName: string,
|
|
256
|
+
toolArgs: string
|
|
257
|
+
) => Promise<string>;
|
|
233
258
|
|
|
234
259
|
beforeEach(() => {
|
|
235
260
|
const addFunctionsCalls = mockToolsService.addFunctions.mock.calls;
|
|
236
|
-
const storeToolCallCall = addFunctionsCalls.find(
|
|
261
|
+
const storeToolCallCall = addFunctionsCalls.find(
|
|
262
|
+
(call) => call[0].storeToolCallToVariable
|
|
263
|
+
);
|
|
237
264
|
storeToolCallFunction = storeToolCallCall[0].storeToolCallToVariable;
|
|
238
265
|
});
|
|
239
266
|
|
|
@@ -243,38 +270,56 @@ describe("CustomVariables", () => {
|
|
|
243
270
|
toolCallId: "test-call-id",
|
|
244
271
|
functionName: "testTool",
|
|
245
272
|
functionArgs: { param1: "value1" },
|
|
246
|
-
functionResp: { success: true, data: "test data" }
|
|
273
|
+
functionResp: { success: true, data: "test data" },
|
|
247
274
|
};
|
|
248
275
|
mockToolsService.callTool.mockResolvedValue(mockResult);
|
|
249
276
|
|
|
250
|
-
const result = await storeToolCallFunction(
|
|
277
|
+
const result = await storeToolCallFunction(
|
|
278
|
+
"resultVar",
|
|
279
|
+
"testTool",
|
|
280
|
+
'{"param1": "value1"}'
|
|
281
|
+
);
|
|
251
282
|
|
|
252
|
-
expect(result).toContain(
|
|
283
|
+
expect(result).toContain(
|
|
284
|
+
'Tool call result for "testTool" has been stored in variable "resultVar"'
|
|
285
|
+
);
|
|
253
286
|
expect(mockToolsService.callTool).toHaveBeenCalledWith({
|
|
254
287
|
id: expect.any(String),
|
|
255
288
|
type: "function",
|
|
256
289
|
function: {
|
|
257
290
|
name: "testTool",
|
|
258
|
-
arguments: { param1: "value1" }
|
|
259
|
-
}
|
|
291
|
+
arguments: { param1: "value1" },
|
|
292
|
+
},
|
|
260
293
|
});
|
|
261
294
|
});
|
|
262
295
|
|
|
263
296
|
it("should return error for invalid JSON arguments", async () => {
|
|
264
|
-
const result = await storeToolCallFunction(
|
|
297
|
+
const result = await storeToolCallFunction(
|
|
298
|
+
"resultVar",
|
|
299
|
+
"testTool",
|
|
300
|
+
"invalid json"
|
|
301
|
+
);
|
|
265
302
|
expect(result).toContain("Error: Invalid JSON in toolArgs parameter");
|
|
266
303
|
});
|
|
267
304
|
|
|
268
305
|
it("should return error for invalid variable names", async () => {
|
|
269
|
-
const result = await storeToolCallFunction(
|
|
306
|
+
const result = await storeToolCallFunction(
|
|
307
|
+
"invalid-name",
|
|
308
|
+
"testTool",
|
|
309
|
+
"{}"
|
|
310
|
+
);
|
|
270
311
|
expect(result).toContain("Error: Invalid variable name");
|
|
271
312
|
});
|
|
272
313
|
|
|
273
314
|
it("should handle tool execution errors", async () => {
|
|
274
|
-
mockToolsService.callTool.mockRejectedValue(
|
|
315
|
+
mockToolsService.callTool.mockRejectedValue(
|
|
316
|
+
new Error("Tool execution failed")
|
|
317
|
+
);
|
|
275
318
|
|
|
276
319
|
const result = await storeToolCallFunction("resultVar", "testTool", "{}");
|
|
277
|
-
expect(result).toContain(
|
|
320
|
+
expect(result).toContain(
|
|
321
|
+
"Error storing tool call result: Tool execution failed"
|
|
322
|
+
);
|
|
278
323
|
});
|
|
279
324
|
});
|
|
280
325
|
|
|
@@ -283,7 +328,9 @@ describe("CustomVariables", () => {
|
|
|
283
328
|
|
|
284
329
|
beforeEach(() => {
|
|
285
330
|
const addFunctionsCalls = mockToolsService.addFunctions.mock.calls;
|
|
286
|
-
const setVariableCall = addFunctionsCalls.find(
|
|
331
|
+
const setVariableCall = addFunctionsCalls.find(
|
|
332
|
+
(call) => call[0].setVariable
|
|
333
|
+
);
|
|
287
334
|
setVariableFunction = setVariableCall[0].setVariable;
|
|
288
335
|
});
|
|
289
336
|
|
|
@@ -294,14 +341,16 @@ describe("CustomVariables", () => {
|
|
|
294
341
|
const messages = [
|
|
295
342
|
{
|
|
296
343
|
role: "user" as const,
|
|
297
|
-
content: "{{greeting}} {{userName}}, how are you today?"
|
|
298
|
-
}
|
|
344
|
+
content: "{{greeting}} {{userName}}, how are you today?",
|
|
345
|
+
},
|
|
299
346
|
];
|
|
300
347
|
|
|
301
348
|
const processor = customVariables.createProcessor();
|
|
302
349
|
const modifiedMessages = [...messages];
|
|
303
350
|
await processor(messages, modifiedMessages);
|
|
304
|
-
expect(modifiedMessages[0].content).toBe(
|
|
351
|
+
expect(modifiedMessages[0].content).toBe(
|
|
352
|
+
"Hello Alice, how are you today?"
|
|
353
|
+
);
|
|
305
354
|
});
|
|
306
355
|
|
|
307
356
|
it("should handle multiple substitutions in single message", async () => {
|
|
@@ -312,8 +361,8 @@ describe("CustomVariables", () => {
|
|
|
312
361
|
const messages = [
|
|
313
362
|
{
|
|
314
363
|
role: "user" as const,
|
|
315
|
-
content: "{{var1}} and {{var2}} and {{var3}}"
|
|
316
|
-
}
|
|
364
|
+
content: "{{var1}} and {{var2}} and {{var3}}",
|
|
365
|
+
},
|
|
317
366
|
];
|
|
318
367
|
|
|
319
368
|
const processor = customVariables.createProcessor();
|
|
@@ -328,30 +377,34 @@ describe("CustomVariables", () => {
|
|
|
328
377
|
const messages = [
|
|
329
378
|
{
|
|
330
379
|
role: "user" as const,
|
|
331
|
-
content: "Configuration: {{config}}"
|
|
332
|
-
}
|
|
380
|
+
content: "Configuration: {{config}}",
|
|
381
|
+
},
|
|
333
382
|
];
|
|
334
383
|
|
|
335
384
|
const processor = customVariables.createProcessor();
|
|
336
385
|
const modifiedMessages = [...messages];
|
|
337
386
|
await processor(messages, modifiedMessages);
|
|
338
|
-
|
|
339
|
-
expect(modifiedMessages[0].content).toBe(
|
|
387
|
+
|
|
388
|
+
expect(modifiedMessages[0].content).toBe(
|
|
389
|
+
'Configuration: {"api":"v1","timeout":5000}'
|
|
390
|
+
);
|
|
340
391
|
});
|
|
341
392
|
|
|
342
393
|
it("should return error for undefined variables", async () => {
|
|
343
394
|
const messages = [
|
|
344
395
|
{
|
|
345
396
|
role: "user" as const,
|
|
346
|
-
content: "Hello {{undefinedVar}}"
|
|
347
|
-
}
|
|
397
|
+
content: "Hello {{undefinedVar}}",
|
|
398
|
+
},
|
|
348
399
|
];
|
|
349
400
|
|
|
350
401
|
const processor = customVariables.createProcessor();
|
|
351
402
|
const modifiedMessages = [...messages];
|
|
352
403
|
await processor(messages, modifiedMessages);
|
|
353
|
-
|
|
354
|
-
expect(modifiedMessages[0].content).toBe(
|
|
404
|
+
|
|
405
|
+
expect(modifiedMessages[0].content).toBe(
|
|
406
|
+
'{{ERROR: Variable "undefinedVar" is not defined}}'
|
|
407
|
+
);
|
|
355
408
|
});
|
|
356
409
|
|
|
357
410
|
it("should handle partial substitutions with mixed defined/undefined vars", async () => {
|
|
@@ -360,15 +413,17 @@ describe("CustomVariables", () => {
|
|
|
360
413
|
const messages = [
|
|
361
414
|
{
|
|
362
415
|
role: "user" as const,
|
|
363
|
-
content: "{{defined}} and {{undefined}}"
|
|
364
|
-
}
|
|
416
|
+
content: "{{defined}} and {{undefined}}",
|
|
417
|
+
},
|
|
365
418
|
];
|
|
366
419
|
|
|
367
420
|
const processor = customVariables.createProcessor();
|
|
368
421
|
const modifiedMessages = [...messages];
|
|
369
422
|
await processor(messages, modifiedMessages);
|
|
370
|
-
|
|
371
|
-
expect(modifiedMessages[0].content).toBe(
|
|
423
|
+
|
|
424
|
+
expect(modifiedMessages[0].content).toBe(
|
|
425
|
+
'value and {{ERROR: Variable "undefined" is not defined}}'
|
|
426
|
+
);
|
|
372
427
|
});
|
|
373
428
|
|
|
374
429
|
it("should preserve message structure while substituting content", async () => {
|
|
@@ -378,18 +433,18 @@ describe("CustomVariables", () => {
|
|
|
378
433
|
{
|
|
379
434
|
role: "assistant" as const,
|
|
380
435
|
content: "Original {{test}} content",
|
|
381
|
-
metadata: { id: "test-id" }
|
|
382
|
-
}
|
|
436
|
+
metadata: { id: "test-id" },
|
|
437
|
+
},
|
|
383
438
|
];
|
|
384
439
|
|
|
385
440
|
const processor = customVariables.createProcessor();
|
|
386
441
|
const modifiedMessages = [...messages];
|
|
387
442
|
await processor(messages, modifiedMessages);
|
|
388
|
-
|
|
443
|
+
|
|
389
444
|
expect(modifiedMessages[0]).toEqual({
|
|
390
445
|
role: "assistant",
|
|
391
446
|
content: "Original replaced content",
|
|
392
|
-
metadata: { id: "test-id" }
|
|
447
|
+
metadata: { id: "test-id" },
|
|
393
448
|
});
|
|
394
449
|
});
|
|
395
450
|
|
|
@@ -400,8 +455,8 @@ describe("CustomVariables", () => {
|
|
|
400
455
|
const messages = [
|
|
401
456
|
{
|
|
402
457
|
role: "user" as const,
|
|
403
|
-
content: "{{outerVar}} value"
|
|
404
|
-
}
|
|
458
|
+
content: "{{outerVar}} value",
|
|
459
|
+
},
|
|
405
460
|
];
|
|
406
461
|
|
|
407
462
|
const processor = customVariables.createProcessor();
|
|
@@ -417,8 +472,8 @@ describe("CustomVariables", () => {
|
|
|
417
472
|
const messages = [
|
|
418
473
|
{
|
|
419
474
|
role: "user" as const,
|
|
420
|
-
content: "Empty: '{{empty}}' Spaces: '{{spaces}}'"
|
|
421
|
-
}
|
|
475
|
+
content: "Empty: '{{empty}}' Spaces: '{{spaces}}'",
|
|
476
|
+
},
|
|
422
477
|
];
|
|
423
478
|
|
|
424
479
|
const processor = customVariables.createProcessor();
|