@tyvm/knowhow 0.0.57 → 0.0.60

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 (183) hide show
  1. package/package.json +3 -3
  2. package/src/agents/base/base.ts +87 -43
  3. package/src/agents/tools/execCommand.ts +17 -14
  4. package/src/agents/tools/googleSearch.ts +1 -0
  5. package/src/agents/tools/index.ts +1 -0
  6. package/src/agents/tools/lazy/definitions.ts +65 -0
  7. package/src/agents/tools/lazy/disableTools.ts +16 -0
  8. package/src/agents/tools/lazy/enableTools.ts +16 -0
  9. package/src/agents/tools/lazy/index.ts +3 -0
  10. package/src/agents/tools/lazy/listAvailableTools.ts +14 -0
  11. package/src/agents/tools/list.ts +2 -0
  12. package/src/agents/tools/mcp/connectMcpServer.ts +40 -0
  13. package/src/agents/tools/mcp/definitions.ts +67 -0
  14. package/src/agents/tools/mcp/disconnectMcpServer.ts +40 -0
  15. package/src/agents/tools/mcp/index.ts +3 -0
  16. package/src/agents/tools/mcp/listAvailableMcpServers.ts +28 -0
  17. package/src/agents/tools/writeFile.ts +4 -1
  18. package/src/chat/CliChatService.ts +8 -3
  19. package/src/chat/modules/AgentModule.ts +74 -296
  20. package/src/cli.ts +33 -10
  21. package/src/plugins/GitPlugin.ts +30 -24
  22. package/src/plugins/language.ts +95 -18
  23. package/src/processors/ToolResponseCache.ts +98 -79
  24. package/src/processors/tools/grepToolResponse.ts +99 -0
  25. package/src/processors/tools/index.ts +21 -0
  26. package/src/processors/tools/jqToolResponse.ts +124 -0
  27. package/src/processors/tools/listStoredToolResponses.ts +83 -0
  28. package/src/processors/tools/tailToolResponse.ts +75 -0
  29. package/src/services/AgentService.ts +1 -1
  30. package/src/services/AgentSynchronization.ts +291 -0
  31. package/src/services/EventService.ts +8 -2
  32. package/src/services/KnowhowClient.ts +141 -1
  33. package/src/services/LazyToolsService.ts +142 -0
  34. package/src/services/Mcp.ts +171 -4
  35. package/src/services/SessionManager.ts +287 -0
  36. package/src/services/TaskRegistry.ts +108 -0
  37. package/src/services/Tools.ts +2 -0
  38. package/src/services/index.ts +7 -0
  39. package/src/services/script-execution/ScriptExecutor.ts +7 -5
  40. package/src/types.ts +1 -0
  41. package/src/utils/InputQueueManager.ts +91 -57
  42. package/src/utils/errors.ts +0 -0
  43. package/src/utils/index.ts +11 -0
  44. package/tests/compressor/bigstring.test.ts +100 -0
  45. package/tests/compressor/bigstring.txt +1 -0
  46. package/tests/plugins/language/languagePlugin-content-triggers.test.ts +13 -5
  47. package/tests/plugins/language/languagePlugin-integration.test.ts +22 -7
  48. package/tests/plugins/language/languagePlugin.test.ts +11 -4
  49. package/tests/processors/ToolResponseCache.test.ts +128 -0
  50. package/tests/unit/InputQueueManager.test.ts +174 -0
  51. package/ts_build/package.json +3 -3
  52. package/ts_build/src/agents/base/base.d.ts +10 -0
  53. package/ts_build/src/agents/base/base.js +66 -34
  54. package/ts_build/src/agents/base/base.js.map +1 -1
  55. package/ts_build/src/agents/tools/execCommand.js +1 -9
  56. package/ts_build/src/agents/tools/execCommand.js.map +1 -1
  57. package/ts_build/src/agents/tools/github/index.d.ts +1 -1
  58. package/ts_build/src/agents/tools/googleSearch.d.ts +1 -0
  59. package/ts_build/src/agents/tools/googleSearch.js +1 -0
  60. package/ts_build/src/agents/tools/googleSearch.js.map +1 -1
  61. package/ts_build/src/agents/tools/index.d.ts +1 -0
  62. package/ts_build/src/agents/tools/index.js +1 -0
  63. package/ts_build/src/agents/tools/index.js.map +1 -1
  64. package/ts_build/src/agents/tools/lazy/definitions.d.ts +5 -0
  65. package/ts_build/src/agents/tools/lazy/definitions.js +60 -0
  66. package/ts_build/src/agents/tools/lazy/definitions.js.map +1 -0
  67. package/ts_build/src/agents/tools/lazy/disableTools.d.ts +9 -0
  68. package/ts_build/src/agents/tools/lazy/disableTools.js +15 -0
  69. package/ts_build/src/agents/tools/lazy/disableTools.js.map +1 -0
  70. package/ts_build/src/agents/tools/lazy/enableTools.d.ts +9 -0
  71. package/ts_build/src/agents/tools/lazy/enableTools.js +15 -0
  72. package/ts_build/src/agents/tools/lazy/enableTools.js.map +1 -0
  73. package/ts_build/src/agents/tools/lazy/index.d.ts +3 -0
  74. package/ts_build/src/agents/tools/lazy/index.js +20 -0
  75. package/ts_build/src/agents/tools/lazy/index.js.map +1 -0
  76. package/ts_build/src/agents/tools/lazy/listAvailableTools.d.ts +11 -0
  77. package/ts_build/src/agents/tools/lazy/listAvailableTools.js +15 -0
  78. package/ts_build/src/agents/tools/lazy/listAvailableTools.js.map +1 -0
  79. package/ts_build/src/agents/tools/list.js +2 -0
  80. package/ts_build/src/agents/tools/list.js.map +1 -1
  81. package/ts_build/src/agents/tools/mcp/connectMcpServer.d.ts +5 -0
  82. package/ts_build/src/agents/tools/mcp/connectMcpServer.js +31 -0
  83. package/ts_build/src/agents/tools/mcp/connectMcpServer.js.map +1 -0
  84. package/ts_build/src/agents/tools/mcp/definitions.d.ts +2 -0
  85. package/ts_build/src/agents/tools/mcp/definitions.js +62 -0
  86. package/ts_build/src/agents/tools/mcp/definitions.js.map +1 -0
  87. package/ts_build/src/agents/tools/mcp/disconnectMcpServer.d.ts +5 -0
  88. package/ts_build/src/agents/tools/mcp/disconnectMcpServer.js +31 -0
  89. package/ts_build/src/agents/tools/mcp/disconnectMcpServer.js.map +1 -0
  90. package/ts_build/src/agents/tools/mcp/index.d.ts +3 -0
  91. package/ts_build/src/agents/tools/mcp/index.js +10 -0
  92. package/ts_build/src/agents/tools/mcp/index.js.map +1 -0
  93. package/ts_build/src/agents/tools/mcp/listAvailableMcpServers.d.ts +14 -0
  94. package/ts_build/src/agents/tools/mcp/listAvailableMcpServers.js +23 -0
  95. package/ts_build/src/agents/tools/mcp/listAvailableMcpServers.js.map +1 -0
  96. package/ts_build/src/agents/tools/writeFile.js +4 -1
  97. package/ts_build/src/agents/tools/writeFile.js.map +1 -1
  98. package/ts_build/src/chat/CliChatService.js +3 -1
  99. package/ts_build/src/chat/CliChatService.js.map +1 -1
  100. package/ts_build/src/chat/modules/AgentModule.d.ts +4 -3
  101. package/ts_build/src/chat/modules/AgentModule.js +71 -265
  102. package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
  103. package/ts_build/src/cli.d.ts +1 -1
  104. package/ts_build/src/cli.js +17 -4
  105. package/ts_build/src/cli.js.map +1 -1
  106. package/ts_build/src/plugins/GitPlugin.d.ts +1 -0
  107. package/ts_build/src/plugins/GitPlugin.js +26 -19
  108. package/ts_build/src/plugins/GitPlugin.js.map +1 -1
  109. package/ts_build/src/plugins/language.d.ts +3 -0
  110. package/ts_build/src/plugins/language.js +55 -13
  111. package/ts_build/src/plugins/language.js.map +1 -1
  112. package/ts_build/src/processors/ToolResponseCache.d.ts +7 -4
  113. package/ts_build/src/processors/ToolResponseCache.js +47 -88
  114. package/ts_build/src/processors/ToolResponseCache.js.map +1 -1
  115. package/ts_build/src/processors/tools/grepToolResponse.d.ts +10 -0
  116. package/ts_build/src/processors/tools/grepToolResponse.js +71 -0
  117. package/ts_build/src/processors/tools/grepToolResponse.js.map +1 -0
  118. package/ts_build/src/processors/tools/index.d.ts +4 -0
  119. package/ts_build/src/processors/tools/index.js +16 -0
  120. package/ts_build/src/processors/tools/index.js.map +1 -0
  121. package/ts_build/src/processors/tools/jqToolResponse.d.ts +3 -0
  122. package/ts_build/src/processors/tools/jqToolResponse.js +115 -0
  123. package/ts_build/src/processors/tools/jqToolResponse.js.map +1 -0
  124. package/ts_build/src/processors/tools/listStoredToolResponses.d.ts +21 -0
  125. package/ts_build/src/processors/tools/listStoredToolResponses.js +51 -0
  126. package/ts_build/src/processors/tools/listStoredToolResponses.js.map +1 -0
  127. package/ts_build/src/processors/tools/tailToolResponse.d.ts +6 -0
  128. package/ts_build/src/processors/tools/tailToolResponse.js +55 -0
  129. package/ts_build/src/processors/tools/tailToolResponse.js.map +1 -0
  130. package/ts_build/src/services/AgentService.d.ts +1 -1
  131. package/ts_build/src/services/AgentSynchronization.d.ts +27 -0
  132. package/ts_build/src/services/AgentSynchronization.js +168 -0
  133. package/ts_build/src/services/AgentSynchronization.js.map +1 -0
  134. package/ts_build/src/services/EventService.d.ts +5 -0
  135. package/ts_build/src/services/EventService.js +7 -2
  136. package/ts_build/src/services/EventService.js.map +1 -1
  137. package/ts_build/src/services/KnowhowClient.d.ts +41 -1
  138. package/ts_build/src/services/KnowhowClient.js +42 -0
  139. package/ts_build/src/services/KnowhowClient.js.map +1 -1
  140. package/ts_build/src/services/LazyToolsService.d.ts +29 -0
  141. package/ts_build/src/services/LazyToolsService.js +94 -0
  142. package/ts_build/src/services/LazyToolsService.js.map +1 -0
  143. package/ts_build/src/services/Mcp.d.ts +18 -1
  144. package/ts_build/src/services/Mcp.js +119 -4
  145. package/ts_build/src/services/Mcp.js.map +1 -1
  146. package/ts_build/src/services/SessionManager.d.ts +15 -0
  147. package/ts_build/src/services/SessionManager.js +220 -0
  148. package/ts_build/src/services/SessionManager.js.map +1 -0
  149. package/ts_build/src/services/TaskRegistry.d.ts +15 -0
  150. package/ts_build/src/services/TaskRegistry.js +58 -0
  151. package/ts_build/src/services/TaskRegistry.js.map +1 -0
  152. package/ts_build/src/services/Tools.d.ts +2 -0
  153. package/ts_build/src/services/Tools.js.map +1 -1
  154. package/ts_build/src/services/index.d.ts +4 -0
  155. package/ts_build/src/services/index.js +4 -0
  156. package/ts_build/src/services/index.js.map +1 -1
  157. package/ts_build/src/services/script-execution/ScriptExecutor.js +7 -5
  158. package/ts_build/src/services/script-execution/ScriptExecutor.js.map +1 -1
  159. package/ts_build/src/types.d.ts +1 -0
  160. package/ts_build/src/types.js.map +1 -1
  161. package/ts_build/src/utils/InputQueueManager.d.ts +9 -2
  162. package/ts_build/src/utils/InputQueueManager.js +54 -40
  163. package/ts_build/src/utils/InputQueueManager.js.map +1 -1
  164. package/ts_build/src/utils/errors.d.ts +0 -0
  165. package/ts_build/src/utils/errors.js +1 -0
  166. package/ts_build/src/utils/errors.js.map +1 -0
  167. package/ts_build/src/utils/index.d.ts +1 -0
  168. package/ts_build/src/utils/index.js +5 -1
  169. package/ts_build/src/utils/index.js.map +1 -1
  170. package/ts_build/tests/compressor/bigstring.test.d.ts +1 -0
  171. package/ts_build/tests/compressor/bigstring.test.js +66 -0
  172. package/ts_build/tests/compressor/bigstring.test.js.map +1 -0
  173. package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.js +6 -5
  174. package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.js.map +1 -1
  175. package/ts_build/tests/plugins/language/languagePlugin-integration.test.js +9 -7
  176. package/ts_build/tests/plugins/language/languagePlugin-integration.test.js.map +1 -1
  177. package/ts_build/tests/plugins/language/languagePlugin.test.js +7 -4
  178. package/ts_build/tests/plugins/language/languagePlugin.test.js.map +1 -1
  179. package/ts_build/tests/processors/ToolResponseCache.test.js +107 -0
  180. package/ts_build/tests/processors/ToolResponseCache.test.js.map +1 -1
  181. package/ts_build/tests/unit/InputQueueManager.test.d.ts +1 -0
  182. package/ts_build/tests/unit/InputQueueManager.test.js +104 -0
  183. package/ts_build/tests/unit/InputQueueManager.test.js.map +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tyvm/knowhow",
3
- "version": "0.0.57",
3
+ "version": "0.0.60",
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.0.3",
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",
@@ -41,7 +41,7 @@ export abstract class BaseAgent implements IAgent {
41
41
  abstract name: string;
42
42
  abstract description: string;
43
43
 
44
- private status = "in_progress";
44
+ private status = "not_started";
45
45
  private lastHealthCheckTime: number = 0;
46
46
  protected provider = "openai";
47
47
  protected modelName: string = Models.openai.GPT_4o;
@@ -70,11 +70,19 @@ export abstract class BaseAgent implements IAgent {
70
70
  costUpdate: "cost_update",
71
71
  toolCall: "tool:pre_call",
72
72
  toolUsed: "tool:post_call",
73
+ notStarted: "not_started",
74
+ inProgress: "in_progress",
73
75
  done: "done",
74
76
  pause: "pause",
75
77
  kill: "kill",
76
78
  unpause: "unpause",
79
+ agentMsg: "agent:msg",
80
+ userSay: "user:say",
81
+ agentSay: "agent:say",
82
+ agentNewTask: "agent:newTask",
83
+ agentTaskComplete: "agent:taskComplete",
77
84
  };
85
+
78
86
  public tools: ToolsService;
79
87
  public events: EventService;
80
88
  public messageProcessor: MessageProcessor;
@@ -97,12 +105,17 @@ export abstract class BaseAgent implements IAgent {
97
105
  }
98
106
 
99
107
  // Subscribe to "agent:msg" events for dynamic context loading
100
- this.events.on("agent:msg", (eventData: any) => {
101
- const message = {
102
- role: "user",
103
- content: JSON.stringify(eventData),
104
- } as Message;
105
- this.addPendingUserMessage(message);
108
+ this.events.on(this.eventTypes.agentMsg, (eventData: any) => {
109
+ if (
110
+ this.status === this.eventTypes.inProgress ||
111
+ this.status === this.eventTypes.pause
112
+ ) {
113
+ const message = {
114
+ role: "user",
115
+ content: JSON.stringify(eventData),
116
+ } as Message;
117
+ this.addPendingMessage(message);
118
+ }
106
119
  });
107
120
  }
108
121
 
@@ -124,14 +137,14 @@ export abstract class BaseAgent implements IAgent {
124
137
  this.taskBreakdown = "";
125
138
  this.summaries = [];
126
139
  this.totalCostUsd = 0;
127
- this.status = "in_progress";
140
+ this.status = this.eventTypes.inProgress;
128
141
  this.turnCount = 0;
129
142
  this.startTimeMs = Date.now();
130
143
  this.currentTaskId = taskId || this.startTimeMs.toString();
131
144
 
132
145
  // Emit event for plugin integration
133
146
  const id = taskId || this.startTimeMs.toString();
134
- this.events.emit("agent:newTask", {
147
+ this.events.emit(this.eventTypes.agentNewTask, {
135
148
  taskId: id,
136
149
  });
137
150
  }
@@ -319,6 +332,9 @@ export abstract class BaseAgent implements IAgent {
319
332
  logMessages(messages: Message[]) {
320
333
  for (const message of messages) {
321
334
  if (message.role === "assistant" && message.content) {
335
+ this.agentEvents.emit(this.eventTypes.agentSay, {
336
+ message: message.content,
337
+ });
322
338
  console.log("\n", "💬 " + message.content, "\n");
323
339
  }
324
340
  }
@@ -429,7 +445,7 @@ export abstract class BaseAgent implements IAgent {
429
445
  unpause() {
430
446
  console.log("Unpausing agent");
431
447
  this.agentEvents.emit(this.eventTypes.unpause, this);
432
- this.status = "in_progress";
448
+ this.status = this.eventTypes.inProgress;
433
449
  }
434
450
 
435
451
  async unpaused() {
@@ -457,6 +473,10 @@ export abstract class BaseAgent implements IAgent {
457
473
  }
458
474
 
459
475
  async call(userInput: string, _messages?: Message[]) {
476
+ if (this.status === this.eventTypes.notStarted) {
477
+ this.status = this.eventTypes.inProgress;
478
+ }
479
+
460
480
  if (this.status === this.eventTypes.pause) {
461
481
  await this.unpaused();
462
482
  }
@@ -560,6 +580,8 @@ export abstract class BaseAgent implements IAgent {
560
580
  "pre_tools"
561
581
  );
562
582
 
583
+ this.updateCurrentThread(messages);
584
+
563
585
  for (const toolCall of toolCalls) {
564
586
  const toolMessages = await this.processToolMessages(toolCall);
565
587
  // Add the tool responses to the thread
@@ -576,7 +598,7 @@ export abstract class BaseAgent implements IAgent {
576
598
 
577
599
  if (finalMessage) {
578
600
  // Emit task completion event for plugins (like GitPlugin)
579
- this.events.emit("agent:taskComplete", {
601
+ this.events.emit(this.eventTypes.agentTaskComplete, {
580
602
  taskId:
581
603
  this.currentTaskId ||
582
604
  this.startTimeMs?.toString() ||
@@ -654,41 +676,13 @@ export abstract class BaseAgent implements IAgent {
654
676
 
655
677
  if (["assistant", "tool"].includes(messages[messages.length - 1].role)) {
656
678
  // sometimes the agent just says a message and doesn't call a tool, or compression ends on a tool message
657
- console.log(
658
- "Agent continuing to the next iteration, reminding agent how to terminate"
659
- );
660
-
661
- const remainingTime =
662
- this.maxRunTimeMs && this.startTimeMs
663
- ? this.maxRunTimeMs - (Date.now() - this.startTimeMs)
664
- : null;
665
-
666
- const remainingTurns = this.maxTurns
667
- ? this.maxTurns - this.turnCount
668
- : null;
669
-
670
- const timeRemainsingMsg = remainingTime
671
- ? `You have approximately ${Math.floor(
672
- remainingTime / 1000
673
- )} seconds remaining for this task. `
674
- : "";
675
-
676
- const turnsRemainingMsg = remainingTurns
677
- ? `You have ${remainingTurns} turns remaining. `
678
- : "";
679
679
 
680
- const remainingBudget = this.maxSpend
681
- ? this.maxSpend - this.totalCostUsd
682
- : null;
683
- const budgetRemainingMsg = remainingBudget
684
- ? `You have $${remainingBudget.toFixed(4)} remaining in your budget.`
685
- : "";
680
+ const statusMessage = this.getStatusMessage();
681
+ this.logStatus();
686
682
 
687
683
  const continuation = `<Workflow>
688
684
  workflow continues until you call one of ${this.requiredToolNames}.\n
689
- ${timeRemainsingMsg}
690
- ${turnsRemainingMsg}
691
- ${budgetRemainingMsg}
685
+ ${statusMessage}
692
686
  </Workflow>`;
693
687
 
694
688
  messages.push({
@@ -719,14 +713,64 @@ export abstract class BaseAgent implements IAgent {
719
713
  }
720
714
  }
721
715
 
722
- addPendingUserMessage(message: Message) {
716
+ getStatusMessage() {
717
+ const remainingTime =
718
+ this.maxRunTimeMs && this.startTimeMs
719
+ ? this.maxRunTimeMs - (Date.now() - this.startTimeMs)
720
+ : null;
721
+
722
+ const remainingTurns = this.maxTurns
723
+ ? this.maxTurns - this.turnCount
724
+ : null;
725
+
726
+ const timeRemainingMsg = remainingTime
727
+ ? `You have approximately ${Math.floor(
728
+ remainingTime / 1000
729
+ )} seconds remaining for this task. `
730
+ : "";
731
+
732
+ const turnsRemainingMsg = remainingTurns
733
+ ? `You have ${remainingTurns} turns remaining. `
734
+ : "";
735
+
736
+ const remainingBudget = this.maxSpend
737
+ ? this.maxSpend - this.totalCostUsd
738
+ : null;
739
+ const budgetRemainingMsg = remainingBudget
740
+ ? `You have $${remainingBudget.toFixed(4)} remaining in your budget.`
741
+ : "";
742
+
743
+ const statusMessage = `${timeRemainingMsg}\n${turnsRemainingMsg}\n${budgetRemainingMsg}`;
744
+ return statusMessage;
745
+ }
746
+
747
+ logStatus() {
748
+ const statusMessage = this.getStatusMessage();
749
+ console.log(
750
+ `\n● ${this.name} status: $${this.getTotalCostUsd().toPrecision(
751
+ 3
752
+ )}\n${statusMessage}`
753
+ );
754
+ }
755
+
756
+ addPendingMessage(message: Message) {
723
757
  if (this.status === this.eventTypes.done) {
724
758
  console.warn("Agent is done, cannot take more messages");
725
759
  } else {
760
+ const pendingMessages = this.pendingUserMessages.map((m) => m.content);
761
+ if (pendingMessages.includes(message.content)) {
762
+ // Ignore messages we already have queue'd up
763
+ return;
764
+ }
726
765
  this.pendingUserMessages.push(message);
727
766
  }
728
767
  }
729
768
 
769
+ addPendingUserMessage(message: Message) {
770
+ this.addPendingMessage(message);
771
+ this.events.emit(this.eventTypes.userSay, message.content);
772
+ }
773
+
730
774
  getMessagesLength(messages: Message[]) {
731
775
  return JSON.stringify(messages).split(" ").length;
732
776
  }
@@ -42,19 +42,19 @@ function commandNameFrom(cmd: string) {
42
42
 
43
43
  function makeLogPath(cmd: string, customFileName?: string) {
44
44
  // Use custom filename if provided, otherwise derive from command
45
- let baseName = customFileName
45
+ let baseName = customFileName
46
46
  ? customFileName.replace(/[^\w.-]+/g, "_")
47
47
  : commandNameFrom(cmd);
48
-
48
+
49
49
  let logPath = path.join(PROCESSES_DIR, `${baseName}.txt`);
50
-
50
+
51
51
  // If file already exists, append epoch seconds to ensure uniqueness
52
52
  if (fs.existsSync(logPath)) {
53
53
  const epochSeconds = Math.floor(Date.now() / 1000);
54
54
  baseName = `${baseName}_${epochSeconds}`;
55
55
  logPath = path.join(PROCESSES_DIR, `${baseName}.txt`);
56
56
  }
57
-
57
+
58
58
  return logPath;
59
59
  }
60
60
 
@@ -282,15 +282,18 @@ export const execCommand = async (
282
282
  : "";
283
283
 
284
284
  const lines = output.split("\n");
285
- const maxLines = 1000;
286
- const maxChars = 40000;
287
- const trimmed = (lines.length > maxLines ? lines.slice(0, maxLines) : lines)
288
- .join("\n")
289
- .slice(0, maxChars);
290
- const trimmedMsg =
291
- lines.length > maxLines
292
- ? ` (${lines.length - maxLines} results trimmed)`
293
- : "";
285
+ /*
286
+ *const maxLines = 1000;
287
+ *const maxChars = 40000;
288
+ *const trimmed = (lines.length > maxLines ? lines.slice(0, maxLines) : lines)
289
+ * .join("\n")
290
+ * .slice(0, maxChars);
291
+ *const trimmedMsg =
292
+ * lines.length > maxLines
293
+ * ? ` (${lines.length - maxLines} results trimmed)`
294
+ * : "";
295
+ */
294
296
 
295
- return `$ ${command}${statusMsg}\n${trimmed}${trimmedMsg}`;
297
+ // return `$ ${command}${statusMsg}\n${trimmed}${trimmedMsg}`;
298
+ return `$ ${command}${statusMsg}\n${output}`;
296
299
  };
@@ -154,6 +154,7 @@ function transformGoogleSearchResponseForLLM(
154
154
  searchQuery,
155
155
  totalResults,
156
156
  results: relevantItems,
157
+ usd_cost: 0.005,
157
158
  };
158
159
  }
159
160
 
@@ -27,3 +27,4 @@ export * from "./executeScript";
27
27
  export * from "./ast";
28
28
  export * from "./startAgentTask";
29
29
  export * from "./ycmd";
30
+ export * from "./mcp";
@@ -0,0 +1,65 @@
1
+ import { Tool } from "../../../clients/types";
2
+
3
+ export const listAvailableToolsDefinition: Tool = {
4
+ type: "function",
5
+ function: {
6
+ name: "listAvailableTools",
7
+ description:
8
+ "List all available tools in the system, showing which are currently enabled and disabled. Use this to discover what tools exist before enabling them.",
9
+ parameters: {
10
+ type: "object",
11
+ positional: true,
12
+ properties: {},
13
+ required: [],
14
+ },
15
+ },
16
+ };
17
+
18
+ export const enableToolsDefinition: Tool = {
19
+ type: "function",
20
+ function: {
21
+ name: "enableTools",
22
+ description:
23
+ "Enable tools matching glob patterns. Examples: ['read*'] enables all tools starting with 'read', ['mcp_*_browser_*'] enables all browser MCP tools, ['*File'] enables all tools ending with 'File'. Pass an array of pattern strings.",
24
+ parameters: {
25
+ type: "object",
26
+ positional: true,
27
+ properties: {
28
+ patterns: {
29
+ type: "array",
30
+ items: { type: "string" },
31
+ description:
32
+ "Array of glob patterns to match tool names.",
33
+ },
34
+ },
35
+ required: ["patterns"],
36
+ },
37
+ },
38
+ };
39
+
40
+ export const disableToolsDefinition: Tool = {
41
+ type: "function",
42
+ function: {
43
+ name: "disableTools",
44
+ description:
45
+ "Disable tools matching glob patterns. This removes tools from the available tool list to stay within provider limits. Pass an array of pattern strings.",
46
+ parameters: {
47
+ type: "object",
48
+ positional: true,
49
+ properties: {
50
+ patterns: {
51
+ type: "array",
52
+ items: { type: "string" },
53
+ description: "Array of glob patterns to match tool names for disabling.",
54
+ },
55
+ },
56
+ required: ["patterns"],
57
+ },
58
+ },
59
+ };
60
+
61
+ export const definitions = [
62
+ listAvailableToolsDefinition,
63
+ enableToolsDefinition,
64
+ disableToolsDefinition,
65
+ ];
@@ -0,0 +1,16 @@
1
+ import { LazyToolsService } from "../../../services/LazyToolsService";
2
+ import { ToolsService } from "../../../services/Tools";
3
+
4
+ export async function disableTools(
5
+ this: ToolsService,
6
+ patterns: string[]
7
+ ) {
8
+ if (!(this instanceof LazyToolsService)) {
9
+ return {
10
+ error: "This tool requires LazyToolsService",
11
+ message: "disableTools is only available when using LazyToolsService",
12
+ };
13
+ }
14
+
15
+ return this.disableTools(patterns);
16
+ }
@@ -0,0 +1,16 @@
1
+ import { LazyToolsService } from "../../../services/LazyToolsService";
2
+ import { ToolsService } from "../../../services/Tools";
3
+
4
+ export async function enableTools(
5
+ this: ToolsService,
6
+ patterns: string[]
7
+ ) {
8
+ if (!(this instanceof LazyToolsService)) {
9
+ return {
10
+ error: "This tool requires LazyToolsService",
11
+ message: "enableTools is only available when using LazyToolsService",
12
+ };
13
+ }
14
+
15
+ return this.enableTools(patterns);
16
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./listAvailableTools";
2
+ export * from "./enableTools";
3
+ export * from "./disableTools";
@@ -0,0 +1,14 @@
1
+ import { LazyToolsService } from "../../../services/LazyToolsService";
2
+ import { ToolsService } from "../../../services/Tools";
3
+
4
+ export async function listAvailableTools(this: ToolsService) {
5
+ if (!(this instanceof LazyToolsService)) {
6
+ return {
7
+ error: "This tool requires LazyToolsService",
8
+ message:
9
+ "listAvailableTools is only available when using LazyToolsService",
10
+ };
11
+ }
12
+
13
+ return this.listAvailableTools();
14
+ }
@@ -6,6 +6,7 @@ import * as github from "./github/definitions";
6
6
  import * as asana from "./asana/definitions";
7
7
  import * as ycmd from "./ycmd/definitions";
8
8
  import * as language from "./language/definitions";
9
+ import * as mcp from "./mcp/definitions";
9
10
  import { googleSearchDefinition } from "./googleSearch";
10
11
  import { executeScriptDefinition } from "./executeScript/definition";
11
12
  import { startAgentTaskDefinition } from "./startAgentTask";
@@ -795,4 +796,5 @@ export const includedTools = [
795
796
  ...ycmd.definitions,
796
797
  ...github.definitions,
797
798
  ...language.definitions,
799
+ ...mcp.definitions,
798
800
  ] as Tool[];
@@ -0,0 +1,40 @@
1
+ import { services } from "../../../services";
2
+ import { McpService } from "../../../services/Mcp";
3
+ import { ToolsService } from "../../../services/Tools";
4
+
5
+ export async function connectMcpServer(
6
+ serverName: string,
7
+ timeout: number = 30000
8
+ ) {
9
+ const toolService = (
10
+ this instanceof ToolsService ? this : services().Tools
11
+ ) as ToolsService;
12
+
13
+ const context = toolService.getContext();
14
+ const Mcp = context.Mcp;
15
+
16
+ if (!Mcp) {
17
+ return {
18
+ success: false,
19
+ error: "MCP service not available in context",
20
+ toolsAdded: [],
21
+ };
22
+ }
23
+
24
+ if (!serverName) {
25
+ return {
26
+ success: false,
27
+ error: "serverName parameter is required",
28
+ toolsAdded: [],
29
+ };
30
+ }
31
+
32
+ const result = await Mcp.connectSingle(serverName, timeout);
33
+
34
+ // If connection was successful and tools were added, register them with the ToolsService
35
+ if (result.success && result.toolsAdded.length > 0) {
36
+ await Mcp.addTools(toolService);
37
+ }
38
+
39
+ return result;
40
+ }
@@ -0,0 +1,67 @@
1
+ import { Tool } from "../../../clients/types";
2
+
3
+ const listAvailableMcpServersDefinition: Tool = {
4
+ type: "function",
5
+ function: {
6
+ name: "listAvailableMcpServers",
7
+ description:
8
+ "List all configured MCP servers and their connection status. Shows which servers are connected, which are disconnected, and how many tools each provides.",
9
+ parameters: {
10
+ type: "object",
11
+ positional: true,
12
+ properties: {},
13
+ required: [],
14
+ },
15
+ },
16
+ };
17
+
18
+ const connectMcpServerDefinition: Tool = {
19
+ type: "function",
20
+ function: {
21
+ name: "connectMcpServer",
22
+ description:
23
+ "Connect to a specific MCP server on-demand. This is useful for servers configured with autoConnect: false, or to reconnect a disconnected server. Once connected, the server's tools will be available for use.",
24
+ parameters: {
25
+ type: "object",
26
+ positional: true,
27
+ properties: {
28
+ serverName: {
29
+ type: "string",
30
+ description: "The name of the MCP server to connect to",
31
+ },
32
+ timeout: {
33
+ type: "number",
34
+ description:
35
+ "Connection timeout in milliseconds (optional, default: 30000)",
36
+ },
37
+ },
38
+ required: ["serverName"],
39
+ },
40
+ },
41
+ };
42
+
43
+ const disconnectMcpServerDefinition: Tool = {
44
+ type: "function",
45
+ function: {
46
+ name: "disconnectMcpServer",
47
+ description:
48
+ "Disconnect from a specific MCP server. This will close the connection and remove the server's tools from the available tools list.",
49
+ parameters: {
50
+ type: "object",
51
+ positional: true,
52
+ properties: {
53
+ serverName: {
54
+ type: "string",
55
+ description: "The name of the MCP server to disconnect from",
56
+ },
57
+ },
58
+ required: ["serverName"],
59
+ },
60
+ },
61
+ };
62
+
63
+ export const definitions = [
64
+ listAvailableMcpServersDefinition,
65
+ connectMcpServerDefinition,
66
+ disconnectMcpServerDefinition,
67
+ ];
@@ -0,0 +1,40 @@
1
+ import { services } from "../../../services";
2
+ import { McpService } from "../../../services/Mcp";
3
+ import { ToolsService } from "../../../services/Tools";
4
+
5
+ export async function disconnectMcpServer(serverName: string) {
6
+ const toolService = (
7
+ this instanceof ToolsService ? this : services().Tools
8
+ ) as ToolsService;
9
+
10
+ const context = toolService.getContext();
11
+ const Mcp = context.Mcp;
12
+
13
+ if (!Mcp) {
14
+ return {
15
+ success: false,
16
+ error: "MCP service not available in context",
17
+ toolsRemoved: [],
18
+ };
19
+ }
20
+
21
+ if (!serverName) {
22
+ return {
23
+ success: false,
24
+ error: "serverName parameter is required",
25
+ toolsRemoved: [],
26
+ };
27
+ }
28
+
29
+ const result = await Mcp.disconnectSingle(serverName);
30
+
31
+ // If disconnection was successful and tools were removed, update the ToolsService
32
+ if (result.success && result.toolsRemoved.length > 0) {
33
+ // Remove tools from the current ToolsService instance
34
+ toolService.tools = toolService.tools.filter(
35
+ (tool) => !result.toolsRemoved.includes(tool.function.name)
36
+ );
37
+ }
38
+
39
+ return result;
40
+ }
@@ -0,0 +1,3 @@
1
+ export { listAvailableMcpServers } from "./listAvailableMcpServers";
2
+ export { connectMcpServer } from "./connectMcpServer";
3
+ export { disconnectMcpServer } from "./disconnectMcpServer";
@@ -0,0 +1,28 @@
1
+ import { services } from "../../../services";
2
+ import { McpService } from "../../../services/Mcp";
3
+ import { ToolsService } from "../../../services/Tools";
4
+
5
+ export async function listAvailableMcpServers() {
6
+ const toolService = (
7
+ this instanceof ToolsService ? this : services().Tools
8
+ ) as ToolsService;
9
+
10
+ const context = toolService.getContext();
11
+ const Mcp = context.Mcp;
12
+
13
+ if (!Mcp) {
14
+ return {
15
+ error: "MCP service not available in context",
16
+ servers: [],
17
+ };
18
+ }
19
+
20
+ const servers = Mcp.getAvailableServers();
21
+
22
+ return {
23
+ servers,
24
+ summary: `Found ${servers.length} configured MCP server(s). ${
25
+ servers.filter((s) => s.connected).length
26
+ } connected, ${servers.filter((s) => !s.connected).length} disconnected.`,
27
+ };
28
+ }
@@ -25,7 +25,10 @@ export async function writeFileChunk(
25
25
 
26
26
  if (!filePath || content === undefined) {
27
27
  throw new Error(
28
- "File path and content are both required. Make sure you write small chunks of content, otherwise you may hit output limits."
28
+ `File path and content are both required. We received: ${JSON.stringify({
29
+ filePath,
30
+ content,
31
+ })}. Make sure you write small chunks of content, otherwise you will hit output limits, resulting in content being empty.`
29
32
  );
30
33
  }
31
34