@tyvm/knowhow 0.0.56 → 0.0.59
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 +3 -3
- package/src/agents/base/base.ts +87 -43
- package/src/agents/tools/execCommand.ts +17 -14
- package/src/agents/tools/googleSearch.ts +1 -0
- package/src/agents/tools/index.ts +1 -0
- package/src/agents/tools/lazy/definitions.ts +63 -0
- package/src/agents/tools/lazy/disableTools.ts +16 -0
- package/src/agents/tools/lazy/enableTools.ts +16 -0
- package/src/agents/tools/lazy/index.ts +3 -0
- package/src/agents/tools/lazy/listAvailableTools.ts +14 -0
- package/src/agents/tools/list.ts +2 -0
- package/src/agents/tools/mcp/connectMcpServer.ts +40 -0
- package/src/agents/tools/mcp/definitions.ts +67 -0
- package/src/agents/tools/mcp/disconnectMcpServer.ts +40 -0
- package/src/agents/tools/mcp/index.ts +3 -0
- package/src/agents/tools/mcp/listAvailableMcpServers.ts +28 -0
- package/src/agents/tools/writeFile.ts +4 -1
- package/src/chat/CliChatService.ts +8 -3
- package/src/chat/modules/AgentModule.ts +74 -296
- package/src/cli.ts +33 -10
- package/src/plugins/GitPlugin.ts +30 -24
- package/src/plugins/language.ts +95 -18
- package/src/processors/ToolResponseCache.ts +98 -79
- package/src/processors/tools/grepToolResponse.ts +99 -0
- package/src/processors/tools/index.ts +21 -0
- package/src/processors/tools/jqToolResponse.ts +124 -0
- package/src/processors/tools/listStoredToolResponses.ts +83 -0
- package/src/processors/tools/tailToolResponse.ts +75 -0
- package/src/services/AgentService.ts +1 -1
- package/src/services/AgentSynchronization.ts +291 -0
- package/src/services/DockerService.ts +37 -1
- package/src/services/EventService.ts +8 -2
- package/src/services/KnowhowClient.ts +141 -1
- package/src/services/LazyToolsService.ts +146 -0
- package/src/services/Mcp.ts +171 -4
- package/src/services/SessionManager.ts +287 -0
- package/src/services/TaskRegistry.ts +108 -0
- package/src/services/Tools.ts +2 -0
- package/src/services/index.ts +7 -0
- package/src/services/script-execution/ScriptExecutor.ts +7 -5
- package/src/types.ts +1 -0
- package/src/utils/InputQueueManager.ts +91 -57
- package/src/utils/errors.ts +0 -0
- package/src/utils/index.ts +11 -0
- package/src/worker.ts +12 -0
- package/tests/compressor/bigstring.test.ts +100 -0
- package/tests/compressor/bigstring.txt +1 -0
- package/tests/plugins/language/languagePlugin-content-triggers.test.ts +13 -5
- package/tests/plugins/language/languagePlugin-integration.test.ts +22 -7
- package/tests/plugins/language/languagePlugin.test.ts +11 -4
- package/tests/processors/ToolResponseCache.test.ts +128 -0
- package/tests/unit/InputQueueManager.test.ts +174 -0
- package/ts_build/package.json +3 -3
- package/ts_build/src/agents/base/base.d.ts +10 -0
- package/ts_build/src/agents/base/base.js +66 -34
- package/ts_build/src/agents/base/base.js.map +1 -1
- package/ts_build/src/agents/tools/execCommand.js +1 -9
- package/ts_build/src/agents/tools/execCommand.js.map +1 -1
- package/ts_build/src/agents/tools/github/index.d.ts +1 -1
- package/ts_build/src/agents/tools/googleSearch.d.ts +1 -0
- package/ts_build/src/agents/tools/googleSearch.js +1 -0
- package/ts_build/src/agents/tools/googleSearch.js.map +1 -1
- package/ts_build/src/agents/tools/index.d.ts +1 -0
- package/ts_build/src/agents/tools/index.js +1 -0
- package/ts_build/src/agents/tools/index.js.map +1 -1
- package/ts_build/src/agents/tools/lazy/definitions.d.ts +5 -0
- package/ts_build/src/agents/tools/lazy/definitions.js +58 -0
- package/ts_build/src/agents/tools/lazy/definitions.js.map +1 -0
- package/ts_build/src/agents/tools/lazy/disableTools.d.ts +9 -0
- package/ts_build/src/agents/tools/lazy/disableTools.js +15 -0
- package/ts_build/src/agents/tools/lazy/disableTools.js.map +1 -0
- package/ts_build/src/agents/tools/lazy/enableTools.d.ts +9 -0
- package/ts_build/src/agents/tools/lazy/enableTools.js +15 -0
- package/ts_build/src/agents/tools/lazy/enableTools.js.map +1 -0
- package/ts_build/src/agents/tools/lazy/index.d.ts +3 -0
- package/ts_build/src/agents/tools/lazy/index.js +20 -0
- package/ts_build/src/agents/tools/lazy/index.js.map +1 -0
- package/ts_build/src/agents/tools/lazy/listAvailableTools.d.ts +11 -0
- package/ts_build/src/agents/tools/lazy/listAvailableTools.js +15 -0
- package/ts_build/src/agents/tools/lazy/listAvailableTools.js.map +1 -0
- package/ts_build/src/agents/tools/list.js +2 -0
- package/ts_build/src/agents/tools/list.js.map +1 -1
- package/ts_build/src/agents/tools/mcp/connectMcpServer.d.ts +5 -0
- package/ts_build/src/agents/tools/mcp/connectMcpServer.js +31 -0
- package/ts_build/src/agents/tools/mcp/connectMcpServer.js.map +1 -0
- package/ts_build/src/agents/tools/mcp/definitions.d.ts +2 -0
- package/ts_build/src/agents/tools/mcp/definitions.js +62 -0
- package/ts_build/src/agents/tools/mcp/definitions.js.map +1 -0
- package/ts_build/src/agents/tools/mcp/disconnectMcpServer.d.ts +5 -0
- package/ts_build/src/agents/tools/mcp/disconnectMcpServer.js +31 -0
- package/ts_build/src/agents/tools/mcp/disconnectMcpServer.js.map +1 -0
- package/ts_build/src/agents/tools/mcp/index.d.ts +3 -0
- package/ts_build/src/agents/tools/mcp/index.js +10 -0
- package/ts_build/src/agents/tools/mcp/index.js.map +1 -0
- package/ts_build/src/agents/tools/mcp/listAvailableMcpServers.d.ts +14 -0
- package/ts_build/src/agents/tools/mcp/listAvailableMcpServers.js +23 -0
- package/ts_build/src/agents/tools/mcp/listAvailableMcpServers.js.map +1 -0
- package/ts_build/src/agents/tools/writeFile.js +4 -1
- package/ts_build/src/agents/tools/writeFile.js.map +1 -1
- package/ts_build/src/chat/CliChatService.js +3 -1
- package/ts_build/src/chat/CliChatService.js.map +1 -1
- package/ts_build/src/chat/modules/AgentModule.d.ts +4 -3
- package/ts_build/src/chat/modules/AgentModule.js +71 -265
- package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
- package/ts_build/src/cli.d.ts +1 -1
- package/ts_build/src/cli.js +17 -4
- package/ts_build/src/cli.js.map +1 -1
- package/ts_build/src/plugins/GitPlugin.d.ts +1 -0
- package/ts_build/src/plugins/GitPlugin.js +26 -19
- package/ts_build/src/plugins/GitPlugin.js.map +1 -1
- package/ts_build/src/plugins/language.d.ts +3 -0
- package/ts_build/src/plugins/language.js +55 -13
- package/ts_build/src/plugins/language.js.map +1 -1
- package/ts_build/src/processors/ToolResponseCache.d.ts +7 -4
- package/ts_build/src/processors/ToolResponseCache.js +47 -88
- package/ts_build/src/processors/ToolResponseCache.js.map +1 -1
- package/ts_build/src/processors/tools/grepToolResponse.d.ts +10 -0
- package/ts_build/src/processors/tools/grepToolResponse.js +71 -0
- package/ts_build/src/processors/tools/grepToolResponse.js.map +1 -0
- package/ts_build/src/processors/tools/index.d.ts +4 -0
- package/ts_build/src/processors/tools/index.js +16 -0
- package/ts_build/src/processors/tools/index.js.map +1 -0
- package/ts_build/src/processors/tools/jqToolResponse.d.ts +3 -0
- package/ts_build/src/processors/tools/jqToolResponse.js +115 -0
- package/ts_build/src/processors/tools/jqToolResponse.js.map +1 -0
- package/ts_build/src/processors/tools/listStoredToolResponses.d.ts +21 -0
- package/ts_build/src/processors/tools/listStoredToolResponses.js +51 -0
- package/ts_build/src/processors/tools/listStoredToolResponses.js.map +1 -0
- package/ts_build/src/processors/tools/tailToolResponse.d.ts +6 -0
- package/ts_build/src/processors/tools/tailToolResponse.js +55 -0
- package/ts_build/src/processors/tools/tailToolResponse.js.map +1 -0
- package/ts_build/src/services/AgentService.d.ts +1 -1
- package/ts_build/src/services/AgentSynchronization.d.ts +27 -0
- package/ts_build/src/services/AgentSynchronization.js +168 -0
- package/ts_build/src/services/AgentSynchronization.js.map +1 -0
- package/ts_build/src/services/DockerService.d.ts +2 -0
- package/ts_build/src/services/DockerService.js +21 -1
- package/ts_build/src/services/DockerService.js.map +1 -1
- package/ts_build/src/services/EventService.d.ts +5 -0
- package/ts_build/src/services/EventService.js +7 -2
- package/ts_build/src/services/EventService.js.map +1 -1
- package/ts_build/src/services/KnowhowClient.d.ts +41 -1
- package/ts_build/src/services/KnowhowClient.js +42 -0
- package/ts_build/src/services/KnowhowClient.js.map +1 -1
- package/ts_build/src/services/LazyToolsService.d.ts +29 -0
- package/ts_build/src/services/LazyToolsService.js +96 -0
- package/ts_build/src/services/LazyToolsService.js.map +1 -0
- package/ts_build/src/services/Mcp.d.ts +18 -1
- package/ts_build/src/services/Mcp.js +119 -4
- package/ts_build/src/services/Mcp.js.map +1 -1
- package/ts_build/src/services/SessionManager.d.ts +15 -0
- package/ts_build/src/services/SessionManager.js +220 -0
- package/ts_build/src/services/SessionManager.js.map +1 -0
- package/ts_build/src/services/TaskRegistry.d.ts +15 -0
- package/ts_build/src/services/TaskRegistry.js +58 -0
- package/ts_build/src/services/TaskRegistry.js.map +1 -0
- package/ts_build/src/services/Tools.d.ts +2 -0
- package/ts_build/src/services/Tools.js.map +1 -1
- package/ts_build/src/services/index.d.ts +4 -0
- package/ts_build/src/services/index.js +4 -0
- package/ts_build/src/services/index.js.map +1 -1
- package/ts_build/src/services/script-execution/ScriptExecutor.js +7 -5
- package/ts_build/src/services/script-execution/ScriptExecutor.js.map +1 -1
- package/ts_build/src/types.d.ts +1 -0
- package/ts_build/src/types.js.map +1 -1
- package/ts_build/src/utils/InputQueueManager.d.ts +9 -2
- package/ts_build/src/utils/InputQueueManager.js +54 -40
- package/ts_build/src/utils/InputQueueManager.js.map +1 -1
- package/ts_build/src/utils/errors.d.ts +0 -0
- package/ts_build/src/utils/errors.js +1 -0
- package/ts_build/src/utils/errors.js.map +1 -0
- package/ts_build/src/utils/index.d.ts +1 -0
- package/ts_build/src/utils/index.js +5 -1
- package/ts_build/src/utils/index.js.map +1 -1
- package/ts_build/src/worker.js +8 -0
- package/ts_build/src/worker.js.map +1 -1
- package/ts_build/tests/compressor/bigstring.test.d.ts +1 -0
- package/ts_build/tests/compressor/bigstring.test.js +66 -0
- package/ts_build/tests/compressor/bigstring.test.js.map +1 -0
- package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.js +6 -5
- package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.js.map +1 -1
- package/ts_build/tests/plugins/language/languagePlugin-integration.test.js +9 -7
- package/ts_build/tests/plugins/language/languagePlugin-integration.test.js.map +1 -1
- package/ts_build/tests/plugins/language/languagePlugin.test.js +7 -4
- package/ts_build/tests/plugins/language/languagePlugin.test.js.map +1 -1
- package/ts_build/tests/processors/ToolResponseCache.test.js +107 -0
- package/ts_build/tests/processors/ToolResponseCache.test.js.map +1 -1
- package/ts_build/tests/unit/InputQueueManager.test.d.ts +1 -0
- package/ts_build/tests/unit/InputQueueManager.test.js +104 -0
- package/ts_build/tests/unit/InputQueueManager.test.js.map +1 -0
|
@@ -119,7 +119,9 @@ describe("LanguagePlugin - Content-Based Triggering", () => {
|
|
|
119
119
|
// Verify that the content-based trigger was activated
|
|
120
120
|
expect(mockEventService.emit).toHaveBeenCalledWith(
|
|
121
121
|
"agent:msg",
|
|
122
|
-
expect.
|
|
122
|
+
expect.stringMatching(
|
|
123
|
+
/<Workflow>[\s\S]*language_context_trigger[\s\S]*<\/Workflow>/
|
|
124
|
+
)
|
|
123
125
|
);
|
|
124
126
|
|
|
125
127
|
const emitCall = mockEventService.emit.mock.calls.find(
|
|
@@ -127,9 +129,11 @@ describe("LanguagePlugin - Content-Based Triggering", () => {
|
|
|
127
129
|
);
|
|
128
130
|
expect(emitCall).toBeDefined();
|
|
129
131
|
|
|
130
|
-
|
|
132
|
+
// Extract JSON from <Workflow> tags
|
|
133
|
+
const workflowContent = emitCall![1].match(/<Workflow>\s*(\{[\s\S]*?\})\s*<\/Workflow>/);
|
|
134
|
+
expect(workflowContent).toBeDefined();
|
|
135
|
+
const eventData = JSON.parse(workflowContent![1]);
|
|
131
136
|
expect(eventData.type).toBe("language_context_trigger");
|
|
132
|
-
expect(eventData.filePath).toBe("src/components/MyComponent.spec.ts");
|
|
133
137
|
expect(eventData.matchingTerms).toContain("test(");
|
|
134
138
|
expect(eventData.contextMessage).toContain("Jest testing best practices");
|
|
135
139
|
});
|
|
@@ -275,7 +279,9 @@ describe("LanguagePlugin - Content-Based Triggering", () => {
|
|
|
275
279
|
// Verify that case-insensitive matching worked
|
|
276
280
|
expect(mockEventService.emit).toHaveBeenCalledWith(
|
|
277
281
|
"agent:msg",
|
|
278
|
-
expect.
|
|
282
|
+
expect.stringMatching(
|
|
283
|
+
/<Workflow>[\s\S]*language_context_trigger[\s\S]*<\/Workflow>/
|
|
284
|
+
)
|
|
279
285
|
);
|
|
280
286
|
});
|
|
281
287
|
|
|
@@ -326,7 +332,9 @@ describe("LanguagePlugin - Content-Based Triggering", () => {
|
|
|
326
332
|
// Verify that edit events also trigger content analysis
|
|
327
333
|
expect(mockEventService.emit).toHaveBeenCalledWith(
|
|
328
334
|
"agent:msg",
|
|
329
|
-
expect.
|
|
335
|
+
expect.stringMatching(
|
|
336
|
+
/<Workflow>[\s\S]*language_context_trigger[\s\S]*<\/Workflow>/
|
|
337
|
+
)
|
|
330
338
|
);
|
|
331
339
|
});
|
|
332
340
|
});
|
|
@@ -146,7 +146,9 @@ test("should calculate sum correctly", () => {
|
|
|
146
146
|
// Verify agent:msg was emitted
|
|
147
147
|
expect(mockEventService.emit).toHaveBeenCalledWith(
|
|
148
148
|
"agent:msg",
|
|
149
|
-
expect.
|
|
149
|
+
expect.stringMatching(
|
|
150
|
+
/<Workflow>[\s\S]*language_context_trigger[\s\S]*<\/Workflow>/
|
|
151
|
+
)
|
|
150
152
|
);
|
|
151
153
|
});
|
|
152
154
|
|
|
@@ -198,7 +200,9 @@ describe('User service', () => {
|
|
|
198
200
|
// Should trigger on 'test(' pattern
|
|
199
201
|
expect(mockEventService.emit).toHaveBeenCalledWith(
|
|
200
202
|
"agent:msg",
|
|
201
|
-
expect.
|
|
203
|
+
expect.stringMatching(
|
|
204
|
+
/<Workflow>[\s\S]*Testing context[\s\S]*<\/Workflow>/
|
|
205
|
+
)
|
|
202
206
|
);
|
|
203
207
|
});
|
|
204
208
|
|
|
@@ -267,7 +271,9 @@ test('should get user data', () => {
|
|
|
267
271
|
// Should now trigger on the edited content
|
|
268
272
|
expect(mockEventService.emit).toHaveBeenCalledWith(
|
|
269
273
|
"agent:msg",
|
|
270
|
-
expect.
|
|
274
|
+
expect.stringMatching(
|
|
275
|
+
/<Workflow>[\s\S]*Testing context[\s\S]*<\/Workflow>/
|
|
276
|
+
)
|
|
271
277
|
);
|
|
272
278
|
});
|
|
273
279
|
|
|
@@ -336,7 +342,9 @@ test('should query database correctly', async () => {
|
|
|
336
342
|
// Should emit agent:msg for the triggered terms
|
|
337
343
|
expect(mockEventService.emit).toHaveBeenCalledWith(
|
|
338
344
|
"agent:msg",
|
|
339
|
-
expect.
|
|
345
|
+
expect.stringMatching(
|
|
346
|
+
/<Workflow>[\s\S]*language_context_trigger[\s\S]*<\/Workflow>/
|
|
347
|
+
)
|
|
340
348
|
);
|
|
341
349
|
|
|
342
350
|
// Check that the emitted message contains both contexts
|
|
@@ -345,7 +353,10 @@ test('should query database correctly', async () => {
|
|
|
345
353
|
);
|
|
346
354
|
expect(emitCalls.length).toBeGreaterThan(0);
|
|
347
355
|
|
|
348
|
-
|
|
356
|
+
// Extract JSON from <Workflow> tags
|
|
357
|
+
const workflowContent = emitCalls[0][1].match(/<Workflow>\s*(\{[\s\S]*?\})\s*<\/Workflow>/);
|
|
358
|
+
expect(workflowContent).toBeDefined();
|
|
359
|
+
const eventData = JSON.parse(workflowContent[1]);
|
|
349
360
|
expect(eventData.matchingTerms).toEqual(
|
|
350
361
|
expect.arrayContaining(["test(", "database"])
|
|
351
362
|
);
|
|
@@ -393,7 +404,9 @@ test('sum function works', () => {
|
|
|
393
404
|
|
|
394
405
|
expect(mockEventService.emit).toHaveBeenCalledWith(
|
|
395
406
|
"agent:msg",
|
|
396
|
-
expect.
|
|
407
|
+
expect.stringMatching(
|
|
408
|
+
/<Workflow>[\s\S]*Testing context[\s\S]*<\/Workflow>/
|
|
409
|
+
)
|
|
397
410
|
);
|
|
398
411
|
|
|
399
412
|
// Clean up
|
|
@@ -447,7 +460,9 @@ test('performance test', () => {
|
|
|
447
460
|
// Should still trigger correctly
|
|
448
461
|
expect(mockEventService.emit).toHaveBeenCalledWith(
|
|
449
462
|
"agent:msg",
|
|
450
|
-
expect.
|
|
463
|
+
expect.stringMatching(
|
|
464
|
+
/<Workflow>[\s\S]*Testing context[\s\S]*<\/Workflow>/
|
|
465
|
+
)
|
|
451
466
|
);
|
|
452
467
|
|
|
453
468
|
// Should process reasonably quickly (less than 1 second)
|
|
@@ -199,9 +199,11 @@ describe("LanguagePlugin", () => {
|
|
|
199
199
|
);
|
|
200
200
|
|
|
201
201
|
expect(emitCall).toBeDefined();
|
|
202
|
-
|
|
202
|
+
// Extract JSON from <Workflow> tags
|
|
203
|
+
const workflowContent = emitCall[1].match(/<Workflow>\s*(\{[\s\S]*?\})\s*<\/Workflow>/);
|
|
204
|
+
expect(workflowContent).toBeDefined();
|
|
205
|
+
const eventData = JSON.parse(workflowContent[1]);
|
|
203
206
|
expect(eventData.type).toBe("language_context_trigger");
|
|
204
|
-
expect(eventData.filePath).toBe("src/components/Button.ts");
|
|
205
207
|
expect(eventData.matchingTerms).toEqual(["**/*.ts"]);
|
|
206
208
|
expect(eventData.eventType).toBe("file:post-edit");
|
|
207
209
|
expect(eventData.resolvedSources).toBeDefined();
|
|
@@ -264,7 +266,10 @@ describe("LanguagePlugin", () => {
|
|
|
264
266
|
const emitCall = mockEventService.emit.mock.calls.find(
|
|
265
267
|
(call) => call[0] === "agent:msg"
|
|
266
268
|
);
|
|
267
|
-
|
|
269
|
+
// Extract JSON from <Workflow> tags
|
|
270
|
+
const workflowContent = emitCall![1].match(/<Workflow>\s*(\{[\s\S]*?\})\s*<\/Workflow>/);
|
|
271
|
+
expect(workflowContent).toBeDefined();
|
|
272
|
+
const eventData = JSON.parse(workflowContent![1]);
|
|
268
273
|
// With minimatch, *.ts doesn't match src/components/Button.ts (needs **/*.ts)
|
|
269
274
|
// Only src/** pattern matches src/components/Button.ts
|
|
270
275
|
expect(eventData.matchingTerms).toContain("src/**");
|
|
@@ -334,7 +339,9 @@ describe("LanguagePlugin", () => {
|
|
|
334
339
|
);
|
|
335
340
|
expect(mockEventService.emit).toHaveBeenCalledWith(
|
|
336
341
|
"agent:msg",
|
|
337
|
-
expect.
|
|
342
|
+
expect.stringMatching(
|
|
343
|
+
/<Workflow>[\s\S]*language_context_trigger[\s\S]*<\/Workflow>/
|
|
344
|
+
)
|
|
338
345
|
);
|
|
339
346
|
});
|
|
340
347
|
});
|
|
@@ -2,6 +2,9 @@ import { Message } from "../../src/clients/types";
|
|
|
2
2
|
import {
|
|
3
3
|
ToolResponseCache,
|
|
4
4
|
jqToolResponseDefinition,
|
|
5
|
+
grepToolResponseDefinition,
|
|
6
|
+
tailToolResponseDefinition,
|
|
7
|
+
listStoredToolResponsesDefinition,
|
|
5
8
|
} from "../../src/processors/ToolResponseCache";
|
|
6
9
|
import { ToolsService } from "../../src/services";
|
|
7
10
|
|
|
@@ -170,9 +173,15 @@ describe("ToolResponseCache", () => {
|
|
|
170
173
|
expect(cache).toBeInstanceOf(ToolResponseCache);
|
|
171
174
|
expect(mockToolsService.addTools).toHaveBeenCalledWith([
|
|
172
175
|
jqToolResponseDefinition,
|
|
176
|
+
grepToolResponseDefinition,
|
|
177
|
+
tailToolResponseDefinition,
|
|
178
|
+
listStoredToolResponsesDefinition,
|
|
173
179
|
]);
|
|
174
180
|
expect(mockToolsService.addFunctions).toHaveBeenCalledWith({
|
|
175
181
|
jqToolResponse: expect.any(Function),
|
|
182
|
+
grepToolResponse: expect.any(Function),
|
|
183
|
+
tailToolResponse: expect.any(Function),
|
|
184
|
+
listStoredToolResponses: expect.any(Function),
|
|
176
185
|
});
|
|
177
186
|
});
|
|
178
187
|
|
|
@@ -549,9 +558,30 @@ describe("ToolResponseCache", () => {
|
|
|
549
558
|
name: "jqToolResponse",
|
|
550
559
|
}),
|
|
551
560
|
},
|
|
561
|
+
{
|
|
562
|
+
type: "function",
|
|
563
|
+
function: expect.objectContaining({
|
|
564
|
+
name: "grepToolResponse",
|
|
565
|
+
}),
|
|
566
|
+
},
|
|
567
|
+
{
|
|
568
|
+
type: "function",
|
|
569
|
+
function: expect.objectContaining({
|
|
570
|
+
name: "tailToolResponse",
|
|
571
|
+
}),
|
|
572
|
+
},
|
|
573
|
+
{
|
|
574
|
+
type: "function",
|
|
575
|
+
function: expect.objectContaining({
|
|
576
|
+
name: "listStoredToolResponses",
|
|
577
|
+
}),
|
|
578
|
+
},
|
|
552
579
|
]);
|
|
553
580
|
expect(mockToolsService.addFunctions).toHaveBeenCalledWith({
|
|
554
581
|
jqToolResponse: expect.any(Function),
|
|
582
|
+
grepToolResponse: expect.any(Function),
|
|
583
|
+
tailToolResponse: expect.any(Function),
|
|
584
|
+
listStoredToolResponses: expect.any(Function),
|
|
555
585
|
});
|
|
556
586
|
});
|
|
557
587
|
|
|
@@ -581,6 +611,104 @@ describe("ToolResponseCache", () => {
|
|
|
581
611
|
});
|
|
582
612
|
});
|
|
583
613
|
|
|
614
|
+
describe("tailToolResponse", () => {
|
|
615
|
+
beforeEach(() => {
|
|
616
|
+
// Store test data with multiple lines
|
|
617
|
+
const multiLineContent = Array(50)
|
|
618
|
+
.fill(0)
|
|
619
|
+
.map((_, i) => `Line ${i + 1}: This is line number ${i + 1}`)
|
|
620
|
+
.join("\n");
|
|
621
|
+
cache.storeToolResponse(multiLineContent, "call_multiline");
|
|
622
|
+
|
|
623
|
+
// Store short content
|
|
624
|
+
cache.storeToolResponse("Line 1\nLine 2\nLine 3", "call_short");
|
|
625
|
+
|
|
626
|
+
// Store single line
|
|
627
|
+
cache.storeToolResponse("Single line content", "call_single");
|
|
628
|
+
|
|
629
|
+
// Store empty content
|
|
630
|
+
cache.storeToolResponse("", "call_empty");
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
it("should return last 10 lines by default", async () => {
|
|
634
|
+
const result = await cache.tailToolResponse("call_multiline");
|
|
635
|
+
const lines = result.split("\n");
|
|
636
|
+
expect(lines).toHaveLength(10);
|
|
637
|
+
expect(lines[0]).toContain("41: Line 41");
|
|
638
|
+
expect(lines[9]).toContain("50: Line 50");
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
it("should return last n lines when specified", async () => {
|
|
642
|
+
const result = await cache.tailToolResponse("call_multiline", {
|
|
643
|
+
lines: 5,
|
|
644
|
+
});
|
|
645
|
+
const lines = result.split("\n");
|
|
646
|
+
expect(lines).toHaveLength(5);
|
|
647
|
+
expect(lines[0]).toContain("46: Line 46");
|
|
648
|
+
expect(lines[4]).toContain("50: Line 50");
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
it("should return all lines if n is greater than total lines", async () => {
|
|
652
|
+
const result = await cache.tailToolResponse("call_short", { lines: 10 });
|
|
653
|
+
const lines = result.split("\n");
|
|
654
|
+
expect(lines).toHaveLength(3);
|
|
655
|
+
expect(lines[0]).toContain("1: Line 1");
|
|
656
|
+
expect(lines[1]).toContain("2: Line 2");
|
|
657
|
+
expect(lines[2]).toContain("3: Line 3");
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
it("should handle single line content", async () => {
|
|
661
|
+
const result = await cache.tailToolResponse("call_single", { lines: 5 });
|
|
662
|
+
expect(result).toBe("1: Single line content");
|
|
663
|
+
});
|
|
664
|
+
|
|
665
|
+
it("should handle empty content", async () => {
|
|
666
|
+
const result = await cache.tailToolResponse("call_empty", { lines: 10 });
|
|
667
|
+
expect(result).toBe("1: ");
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
it("should return last 1 line when lines is 1", async () => {
|
|
671
|
+
const result = await cache.tailToolResponse("call_multiline", {
|
|
672
|
+
lines: 1,
|
|
673
|
+
});
|
|
674
|
+
expect(result).toBe("50: Line 50: This is line number 50");
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
it("should return last 20 lines", async () => {
|
|
678
|
+
const result = await cache.tailToolResponse("call_multiline", {
|
|
679
|
+
lines: 20,
|
|
680
|
+
});
|
|
681
|
+
const lines = result.split("\n");
|
|
682
|
+
expect(lines).toHaveLength(20);
|
|
683
|
+
expect(lines[0]).toContain("31: Line 31");
|
|
684
|
+
expect(lines[19]).toContain("50: Line 50");
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
it("should format line numbers correctly", async () => {
|
|
688
|
+
const result = await cache.tailToolResponse("call_multiline", {
|
|
689
|
+
lines: 3,
|
|
690
|
+
});
|
|
691
|
+
const lines = result.split("\n");
|
|
692
|
+
expect(lines[0]).toMatch(/^48:/);
|
|
693
|
+
expect(lines[1]).toMatch(/^49:/);
|
|
694
|
+
expect(lines[2]).toMatch(/^50:/);
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
it("should return error for missing tool call ID", async () => {
|
|
698
|
+
const result = await cache.tailToolResponse("missing_id");
|
|
699
|
+
expect(result).toContain("Error: No tool response found");
|
|
700
|
+
expect(result).toContain("missing_id");
|
|
701
|
+
expect(result).toContain("Available IDs:");
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
it("should handle lines option of 0", async () => {
|
|
705
|
+
const result = await cache.tailToolResponse("call_multiline", {
|
|
706
|
+
lines: 0,
|
|
707
|
+
});
|
|
708
|
+
expect(result).toBe("");
|
|
709
|
+
});
|
|
710
|
+
});
|
|
711
|
+
|
|
584
712
|
describe("Edge Cases and Error Handling", () => {
|
|
585
713
|
it("should handle very large JSON objects", async () => {
|
|
586
714
|
const largeObject = {
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { InputQueueManager } from "../../src/utils/InputQueueManager";
|
|
2
|
+
|
|
3
|
+
describe("InputQueueManager history ordering", () => {
|
|
4
|
+
test("should use only passed-in history for navigation", () => {
|
|
5
|
+
const manager = new InputQueueManager();
|
|
6
|
+
|
|
7
|
+
// Simulate history passed to ask() (oldest -> newest)
|
|
8
|
+
const history = ["old1", "old2", "old3"];
|
|
9
|
+
|
|
10
|
+
// Access the private getHistory method via reflection for testing
|
|
11
|
+
const getHistory = (manager as any).getHistory.bind(manager);
|
|
12
|
+
|
|
13
|
+
// Simulate having a current question with history
|
|
14
|
+
(manager as any).stack = [{
|
|
15
|
+
question: "test",
|
|
16
|
+
options: [],
|
|
17
|
+
history: history,
|
|
18
|
+
resolve: () => {}
|
|
19
|
+
}];
|
|
20
|
+
|
|
21
|
+
const result = getHistory();
|
|
22
|
+
|
|
23
|
+
// Should return history in oldest->newest order (same as passed in)
|
|
24
|
+
expect(result).toEqual(["old1", "old2", "old3"]);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("should sanitize history entries", () => {
|
|
28
|
+
const manager = new InputQueueManager();
|
|
29
|
+
|
|
30
|
+
// History with entries that need sanitization
|
|
31
|
+
const history = ["normal", "has\nnewline", " spaces ", ""];
|
|
32
|
+
|
|
33
|
+
const getHistory = (manager as any).getHistory.bind(manager);
|
|
34
|
+
|
|
35
|
+
(manager as any).stack = [{
|
|
36
|
+
question: "test",
|
|
37
|
+
options: [],
|
|
38
|
+
history: history,
|
|
39
|
+
resolve: () => {}
|
|
40
|
+
}];
|
|
41
|
+
|
|
42
|
+
const result = getHistory();
|
|
43
|
+
|
|
44
|
+
// Should sanitize: remove newlines, trim whitespace, filter empty
|
|
45
|
+
expect(result).toEqual(["normal", "has newline", "spaces"]);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("should return empty array when no history provided", () => {
|
|
49
|
+
const manager = new InputQueueManager();
|
|
50
|
+
|
|
51
|
+
const getHistory = (manager as any).getHistory.bind(manager);
|
|
52
|
+
|
|
53
|
+
// No history in stack
|
|
54
|
+
(manager as any).stack = [{
|
|
55
|
+
question: "test",
|
|
56
|
+
options: [],
|
|
57
|
+
history: undefined,
|
|
58
|
+
resolve: () => {}
|
|
59
|
+
}];
|
|
60
|
+
|
|
61
|
+
const result = getHistory();
|
|
62
|
+
|
|
63
|
+
expect(result).toEqual([]);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("should return empty array when stack is empty", () => {
|
|
67
|
+
const manager = new InputQueueManager();
|
|
68
|
+
|
|
69
|
+
const getHistory = (manager as any).getHistory.bind(manager);
|
|
70
|
+
|
|
71
|
+
// Empty stack
|
|
72
|
+
(manager as any).stack = [];
|
|
73
|
+
|
|
74
|
+
const result = getHistory();
|
|
75
|
+
|
|
76
|
+
expect(result).toEqual([]);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("Verify historyIndex math for first Up press", () => {
|
|
80
|
+
// History array: ["old1", "old2", "recent"]
|
|
81
|
+
// length = 3
|
|
82
|
+
// First Up: historyIndex becomes 0
|
|
83
|
+
// Index to access: length - 1 - historyIndex = 3 - 1 - 0 = 2
|
|
84
|
+
// history[2] = "recent" ✓
|
|
85
|
+
|
|
86
|
+
const history = ["old1", "old2", "recent"];
|
|
87
|
+
const historyIndex = 0; // After first Up press
|
|
88
|
+
const accessIndex = history.length - 1 - historyIndex;
|
|
89
|
+
|
|
90
|
+
expect(accessIndex).toBe(2);
|
|
91
|
+
expect(history[accessIndex]).toBe("recent");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("Verify historyIndex math for multiple Up presses", () => {
|
|
95
|
+
// History array: ["old1", "old2", "recent"]
|
|
96
|
+
// length = 3
|
|
97
|
+
const history = ["old1", "old2", "recent"];
|
|
98
|
+
|
|
99
|
+
// First Up: historyIndex = 0
|
|
100
|
+
expect(history[history.length - 1 - 0]).toBe("recent");
|
|
101
|
+
|
|
102
|
+
// Second Up: historyIndex = 1
|
|
103
|
+
expect(history[history.length - 1 - 1]).toBe("old2");
|
|
104
|
+
|
|
105
|
+
// Third Up: historyIndex = 2
|
|
106
|
+
expect(history[history.length - 1 - 2]).toBe("old1");
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("onNewEntry callback is called when set", () => {
|
|
110
|
+
const manager = new InputQueueManager();
|
|
111
|
+
const entries: string[] = [];
|
|
112
|
+
|
|
113
|
+
manager.setOnNewEntry((entry) => {
|
|
114
|
+
entries.push(entry);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Verify callback is stored (we can't easily test the actual Enter key behavior without mocking readline)
|
|
118
|
+
expect((manager as any).onNewEntry).toBeDefined();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe("InputQueueManager with CliChatService integration pattern", () => {
|
|
123
|
+
test("new entries should appear in history for next ask() call", () => {
|
|
124
|
+
// This test verifies the pattern used by CliChatService:
|
|
125
|
+
// 1. ask() is called with current inputHistory
|
|
126
|
+
// 2. User types and presses Enter
|
|
127
|
+
// 3. onNewEntry callback adds entry to inputHistory
|
|
128
|
+
// 4. Next ask() call includes the new entry
|
|
129
|
+
|
|
130
|
+
const inputHistory: string[] = ["old1", "old2"];
|
|
131
|
+
const manager = new InputQueueManager();
|
|
132
|
+
|
|
133
|
+
// Set up callback (like CliChatService does)
|
|
134
|
+
manager.setOnNewEntry((entry) => {
|
|
135
|
+
if (!entry.startsWith("/") && entry.trim() !== "") {
|
|
136
|
+
inputHistory.push(entry);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Simulate: first ask() call with current history
|
|
141
|
+
const getHistory = (manager as any).getHistory.bind(manager);
|
|
142
|
+
(manager as any).stack = [{
|
|
143
|
+
question: "test",
|
|
144
|
+
options: [],
|
|
145
|
+
history: [...inputHistory], // snapshot at time of ask()
|
|
146
|
+
resolve: () => {}
|
|
147
|
+
}];
|
|
148
|
+
|
|
149
|
+
let result = getHistory();
|
|
150
|
+
expect(result).toEqual(["old1", "old2"]);
|
|
151
|
+
|
|
152
|
+
// Simulate: user presses Enter with "new message"
|
|
153
|
+
// The callback fires (in real code this happens in the 'line' event)
|
|
154
|
+
(manager as any).onNewEntry("new message");
|
|
155
|
+
|
|
156
|
+
// inputHistory is now updated
|
|
157
|
+
expect(inputHistory).toEqual(["old1", "old2", "new message"]);
|
|
158
|
+
|
|
159
|
+
// Simulate: next ask() call with updated history
|
|
160
|
+
(manager as any).stack = [{
|
|
161
|
+
question: "test2",
|
|
162
|
+
options: [],
|
|
163
|
+
history: [...inputHistory], // new snapshot includes "new message"
|
|
164
|
+
resolve: () => {}
|
|
165
|
+
}];
|
|
166
|
+
|
|
167
|
+
result = getHistory();
|
|
168
|
+
expect(result).toEqual(["old1", "old2", "new message"]);
|
|
169
|
+
|
|
170
|
+
// Press Up: should get "new message" (the most recent)
|
|
171
|
+
const historyIndex = 0;
|
|
172
|
+
expect(result[result.length - 1 - historyIndex]).toBe("new message");
|
|
173
|
+
});
|
|
174
|
+
});
|
package/ts_build/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tyvm/knowhow",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.59",
|
|
4
4
|
"description": "ai cli with plugins and agents",
|
|
5
5
|
"main": "ts_build/src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"test": "jest --testTimeout 300000",
|
|
11
11
|
"test:debug": "node --inspect-brk ../../node_modules/jest/bin/jest.js --detectOpenHandles --forceExit --testTimeout 300000",
|
|
12
12
|
"compile": "tsc",
|
|
13
|
-
"start": "npm run compile && node ts_build/src/server/index.js",
|
|
13
|
+
"start": "npm run compile && node --no-node-snapshot ts_build/src/server/index.js",
|
|
14
14
|
"dataset:diffs:generate": "ts-node src/dataset/diffs/generate.ts",
|
|
15
15
|
"dataset:diffs:jsonl": "ts-node src/dataset/diffs/jsonl.ts",
|
|
16
16
|
"prepublishOnly": "npm run compile",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"jira-client": "^8.2.2",
|
|
63
63
|
"marked": "^10.0.0",
|
|
64
64
|
"marked-terminal": "^6.2.0",
|
|
65
|
-
"minimatch": "^10.
|
|
65
|
+
"minimatch": "^10.1.2",
|
|
66
66
|
"morgan": "^1.10.0",
|
|
67
67
|
"node-fetch": "^3.2.3",
|
|
68
68
|
"node-jq": "^6.0.1",
|
|
@@ -52,10 +52,17 @@ export declare abstract class BaseAgent implements IAgent {
|
|
|
52
52
|
costUpdate: string;
|
|
53
53
|
toolCall: string;
|
|
54
54
|
toolUsed: string;
|
|
55
|
+
notStarted: string;
|
|
56
|
+
inProgress: string;
|
|
55
57
|
done: string;
|
|
56
58
|
pause: string;
|
|
57
59
|
kill: string;
|
|
58
60
|
unpause: string;
|
|
61
|
+
agentMsg: string;
|
|
62
|
+
userSay: string;
|
|
63
|
+
agentSay: string;
|
|
64
|
+
agentNewTask: string;
|
|
65
|
+
agentTaskComplete: string;
|
|
59
66
|
};
|
|
60
67
|
tools: ToolsService;
|
|
61
68
|
events: EventService;
|
|
@@ -108,6 +115,9 @@ export declare abstract class BaseAgent implements IAgent {
|
|
|
108
115
|
unpaused(): Promise<unknown>;
|
|
109
116
|
kill(): Promise<void>;
|
|
110
117
|
call(userInput: string, _messages?: Message[]): any;
|
|
118
|
+
getStatusMessage(): string;
|
|
119
|
+
logStatus(): void;
|
|
120
|
+
addPendingMessage(message: Message): void;
|
|
111
121
|
addPendingUserMessage(message: Message): void;
|
|
112
122
|
getMessagesLength(messages: Message[]): number;
|
|
113
123
|
getTaskBreakdown(messages: Message[]): Promise<string>;
|