@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.
Files changed (30) hide show
  1. package/package.json +1 -1
  2. package/src/agents/base/base.ts +9 -1
  3. package/src/chat/modules/AgentModule.ts +22 -3
  4. package/src/embeddings.ts +2 -4
  5. package/src/processors/CustomVariables.ts +48 -70
  6. package/src/processors/TokenCompressor.ts +5 -4
  7. package/src/processors/ToolResponseCache.ts +6 -9
  8. package/tests/processors/CustomVariables.test.ts +110 -55
  9. package/tests/processors/TokenCompressor.test.ts +48 -49
  10. package/tests/processors/ToolResponseCache.test.ts +309 -261
  11. package/ts_build/package.json +1 -1
  12. package/ts_build/src/agents/base/base.d.ts +5 -0
  13. package/ts_build/src/agents/base/base.js +3 -1
  14. package/ts_build/src/agents/base/base.js.map +1 -1
  15. package/ts_build/src/chat/modules/AgentModule.js +9 -1
  16. package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
  17. package/ts_build/src/embeddings.js +2 -4
  18. package/ts_build/src/embeddings.js.map +1 -1
  19. package/ts_build/src/processors/CustomVariables.js +36 -47
  20. package/ts_build/src/processors/CustomVariables.js.map +1 -1
  21. package/ts_build/src/processors/TokenCompressor.js +2 -2
  22. package/ts_build/src/processors/TokenCompressor.js.map +1 -1
  23. package/ts_build/src/processors/ToolResponseCache.js +6 -8
  24. package/ts_build/src/processors/ToolResponseCache.js.map +1 -1
  25. package/ts_build/tests/processors/CustomVariables.test.js +41 -38
  26. package/ts_build/tests/processors/CustomVariables.test.js.map +1 -1
  27. package/ts_build/tests/processors/TokenCompressor.test.js +4 -5
  28. package/ts_build/tests/processors/TokenCompressor.test.js.map +1 -1
  29. package/ts_build/tests/processors/ToolResponseCache.test.js +89 -78
  30. package/ts_build/tests/processors/ToolResponseCache.test.js.map +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tyvm/knowhow",
3
- "version": "0.0.48",
3
+ "version": "0.0.49",
4
4
  "description": "ai cli with plugins and agents",
5
5
  "main": "ts_build/src/index.js",
6
6
  "bin": {
@@ -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
- toolUsed: "tool_used",
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(agent.eventTypes.toolUsed, (responseMsg) => {
724
- console.log(` 🔨 Tool used: ${JSON.stringify(responseMsg, null, 2)}`);
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(`Found ${inputs.length} files`);
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.map(name => {
110
- const value = this.variables[name];
111
- const preview = typeof value === "string"
112
- ? (value.length > 50 ? value.substring(0, 50) + "..." : value)
113
- : JSON.stringify(value).substring(0, 50) + (JSON.stringify(value).length > 50 ? "..." : "");
114
- return `- ${name}: ${preview}`;
115
- }).join("\n");
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
- if (!toolsService.getTool(this.setVariableToolName)) {
255
- toolsService.addTool(setVariableToolDefinition);
256
- toolsService.addFunctions({
257
- [this.setVariableToolName]: (name: string, contents: any) => {
258
- return this.setVariable(name, contents);
259
- },
260
- });
261
- }
262
-
263
- // Register getVariable tool
264
- if (!toolsService.getTool(this.getVariableToolName)) {
265
- toolsService.addTool(getVariableToolDefinition);
266
- toolsService.addFunctions({
267
- [this.getVariableToolName]: (varName: string) => {
268
- return this.getVariable(varName);
269
- },
270
- });
271
- }
272
-
273
- // Register storeToolCallToVariable tool
274
- if (!toolsService.getTool(this.storeToolCallToolName)) {
275
- toolsService.addTool(storeToolCallToVariableDefinition);
276
- toolsService.addFunctions({
277
- [this.storeToolCallToolName]: async (
278
- varName: string,
279
- toolName: string,
280
- toolArgs: string
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 = path === "" ? this.compressionThreshold : this.maxTokens;
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 && !toolsService.getTool(this.toolName)) {
324
- toolsService.addTool(expandTokensDefinition);
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
- if (!toolsService.getTool(this.toolName)) {
211
- toolsService.addTool(jqToolResponseDefinition);
212
- toolsService.addFunctions({
213
- [this.toolName]: async (toolCallId: string, jqQuery: string) => {
214
- return await this.queryToolResponse(toolCallId, jqQuery);
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
- addTool: jest.fn(),
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.addTool).toHaveBeenCalledTimes(5);
27
- expect(mockToolsService.addFunctions).toHaveBeenCalledTimes(5);
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.addTool.mock.calls;
31
- const toolNames = addToolCalls.map(call => call[0].function.name);
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 not register tools if they already exist", () => {
41
- mockToolsService.getTool.mockReturnValue({ type: "function", function: { name: "setVariable" } } as any);
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 only from the first instance (5 times)
45
- expect(mockToolsService.addTool).toHaveBeenCalledTimes(5);
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(call => call[0].setVariable);
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(call => call[0].setVariable);
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(call => call[0].setVariable);
126
- const getVariableCall = addFunctionsCalls.find(call => call[0].getVariable);
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(call => call[0].setVariable);
170
- const listVariablesCall = addFunctionsCalls.find(call => call[0].listVariables);
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(call => call[0].setVariable);
208
- const deleteVariableCall = addFunctionsCalls.find(call => call[0].deleteVariable);
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('Variable "testVar" has been deleted successfully');
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: (varName: string, toolName: string, toolArgs: string) => Promise<string>;
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(call => call[0].storeToolCallToVariable);
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("resultVar", "testTool", '{"param1": "value1"}');
277
+ const result = await storeToolCallFunction(
278
+ "resultVar",
279
+ "testTool",
280
+ '{"param1": "value1"}'
281
+ );
251
282
 
252
- expect(result).toContain('Tool call result for "testTool" has been stored in variable "resultVar"');
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("resultVar", "testTool", "invalid json");
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("invalid-name", "testTool", "{}");
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(new Error("Tool execution failed"));
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("Error storing tool call result: Tool execution failed");
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(call => call[0].setVariable);
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("Hello Alice, how are you today?");
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('Configuration: {"api":"v1","timeout":5000}');
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('{{ERROR: Variable "undefinedVar" is not defined}}');
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('value and {{ERROR: Variable "undefined" is not defined}}');
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();