@sowonai/crewx-cli 0.4.0-dev.1

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 (173) hide show
  1. package/README.md +529 -0
  2. package/dist/ai-provider.service.d.ts +36 -0
  3. package/dist/ai-provider.service.js +191 -0
  4. package/dist/ai-provider.service.js.map +1 -0
  5. package/dist/ai.service.d.ts +57 -0
  6. package/dist/ai.service.js +628 -0
  7. package/dist/ai.service.js.map +1 -0
  8. package/dist/app.module.d.ts +5 -0
  9. package/dist/app.module.js +103 -0
  10. package/dist/app.module.js.map +1 -0
  11. package/dist/cli/agent.handler.d.ts +2 -0
  12. package/dist/cli/agent.handler.js +140 -0
  13. package/dist/cli/agent.handler.js.map +1 -0
  14. package/dist/cli/chat.handler.d.ts +19 -0
  15. package/dist/cli/chat.handler.js +431 -0
  16. package/dist/cli/chat.handler.js.map +1 -0
  17. package/dist/cli/cli.handler.d.ts +4 -0
  18. package/dist/cli/cli.handler.js +97 -0
  19. package/dist/cli/cli.handler.js.map +1 -0
  20. package/dist/cli/doctor.handler.d.ts +36 -0
  21. package/dist/cli/doctor.handler.js +382 -0
  22. package/dist/cli/doctor.handler.js.map +1 -0
  23. package/dist/cli/execute.handler.d.ts +2 -0
  24. package/dist/cli/execute.handler.js +319 -0
  25. package/dist/cli/execute.handler.js.map +1 -0
  26. package/dist/cli/help.handler.d.ts +2 -0
  27. package/dist/cli/help.handler.js +10 -0
  28. package/dist/cli/help.handler.js.map +1 -0
  29. package/dist/cli/init.handler.d.ts +26 -0
  30. package/dist/cli/init.handler.js +450 -0
  31. package/dist/cli/init.handler.js.map +1 -0
  32. package/dist/cli/mcp.handler.d.ts +3 -0
  33. package/dist/cli/mcp.handler.js +121 -0
  34. package/dist/cli/mcp.handler.js.map +1 -0
  35. package/dist/cli/query.handler.d.ts +2 -0
  36. package/dist/cli/query.handler.js +380 -0
  37. package/dist/cli/query.handler.js.map +1 -0
  38. package/dist/cli/templates.handler.d.ts +2 -0
  39. package/dist/cli/templates.handler.js +100 -0
  40. package/dist/cli/templates.handler.js.map +1 -0
  41. package/dist/cli-options.d.ts +29 -0
  42. package/dist/cli-options.js +234 -0
  43. package/dist/cli-options.js.map +1 -0
  44. package/dist/config/timeout.config.d.ts +14 -0
  45. package/dist/config/timeout.config.js +34 -0
  46. package/dist/config/timeout.config.js.map +1 -0
  47. package/dist/conversation/base-conversation-history.provider.d.ts +12 -0
  48. package/dist/conversation/base-conversation-history.provider.js +45 -0
  49. package/dist/conversation/base-conversation-history.provider.js.map +1 -0
  50. package/dist/conversation/cli-conversation-history.provider.d.ts +16 -0
  51. package/dist/conversation/cli-conversation-history.provider.js +111 -0
  52. package/dist/conversation/cli-conversation-history.provider.js.map +1 -0
  53. package/dist/conversation/conversation-provider.factory.d.ts +10 -0
  54. package/dist/conversation/conversation-provider.factory.js +50 -0
  55. package/dist/conversation/conversation-provider.factory.js.map +1 -0
  56. package/dist/conversation/index.d.ts +6 -0
  57. package/dist/conversation/index.js +27 -0
  58. package/dist/conversation/index.js.map +1 -0
  59. package/dist/conversation/slack-conversation-history.provider.d.ts +28 -0
  60. package/dist/conversation/slack-conversation-history.provider.js +278 -0
  61. package/dist/conversation/slack-conversation-history.provider.js.map +1 -0
  62. package/dist/crewx.tool.d.ts +332 -0
  63. package/dist/crewx.tool.js +1461 -0
  64. package/dist/crewx.tool.js.map +1 -0
  65. package/dist/guards/bearer-auth.guard.d.ts +7 -0
  66. package/dist/guards/bearer-auth.guard.js +44 -0
  67. package/dist/guards/bearer-auth.guard.js.map +1 -0
  68. package/dist/health.controller.d.ts +6 -0
  69. package/dist/health.controller.js +32 -0
  70. package/dist/health.controller.js.map +1 -0
  71. package/dist/main.d.ts +1 -0
  72. package/dist/main.js +267 -0
  73. package/dist/main.js.map +1 -0
  74. package/dist/mcp.controller.d.ts +8 -0
  75. package/dist/mcp.controller.js +62 -0
  76. package/dist/mcp.controller.js.map +1 -0
  77. package/dist/project.service.d.ts +44 -0
  78. package/dist/project.service.js +299 -0
  79. package/dist/project.service.js.map +1 -0
  80. package/dist/providers/base-ai.provider.d.ts +50 -0
  81. package/dist/providers/base-ai.provider.js +624 -0
  82. package/dist/providers/base-ai.provider.js.map +1 -0
  83. package/dist/providers/claude.provider.d.ts +25 -0
  84. package/dist/providers/claude.provider.js +362 -0
  85. package/dist/providers/claude.provider.js.map +1 -0
  86. package/dist/providers/codex.provider.d.ts +17 -0
  87. package/dist/providers/codex.provider.js +99 -0
  88. package/dist/providers/codex.provider.js.map +1 -0
  89. package/dist/providers/copilot.provider.d.ts +25 -0
  90. package/dist/providers/copilot.provider.js +266 -0
  91. package/dist/providers/copilot.provider.js.map +1 -0
  92. package/dist/providers/dynamic-provider.factory.d.ts +55 -0
  93. package/dist/providers/dynamic-provider.factory.js +586 -0
  94. package/dist/providers/dynamic-provider.factory.js.map +1 -0
  95. package/dist/providers/gemini.provider.d.ts +22 -0
  96. package/dist/providers/gemini.provider.js +147 -0
  97. package/dist/providers/gemini.provider.js.map +1 -0
  98. package/dist/services/agent-loader.service.d.ts +29 -0
  99. package/dist/services/agent-loader.service.js +370 -0
  100. package/dist/services/agent-loader.service.js.map +1 -0
  101. package/dist/services/auth.service.d.ts +9 -0
  102. package/dist/services/auth.service.js +47 -0
  103. package/dist/services/auth.service.js.map +1 -0
  104. package/dist/services/config-validator.service.d.ts +28 -0
  105. package/dist/services/config-validator.service.js +467 -0
  106. package/dist/services/config-validator.service.js.map +1 -0
  107. package/dist/services/config.service.d.ts +45 -0
  108. package/dist/services/config.service.js +180 -0
  109. package/dist/services/config.service.js.map +1 -0
  110. package/dist/services/context-enhancement.service.d.ts +13 -0
  111. package/dist/services/context-enhancement.service.js +169 -0
  112. package/dist/services/context-enhancement.service.js.map +1 -0
  113. package/dist/services/document-loader.service.d.ts +16 -0
  114. package/dist/services/document-loader.service.js +137 -0
  115. package/dist/services/document-loader.service.js.map +1 -0
  116. package/dist/services/help.service.d.ts +5 -0
  117. package/dist/services/help.service.js +117 -0
  118. package/dist/services/help.service.js.map +1 -0
  119. package/dist/services/intelligent-compression.service.d.ts +20 -0
  120. package/dist/services/intelligent-compression.service.js +179 -0
  121. package/dist/services/intelligent-compression.service.js.map +1 -0
  122. package/dist/services/mcp-client.service.d.ts +26 -0
  123. package/dist/services/mcp-client.service.js +81 -0
  124. package/dist/services/mcp-client.service.js.map +1 -0
  125. package/dist/services/parallel-processing.service.d.ts +108 -0
  126. package/dist/services/parallel-processing.service.js +268 -0
  127. package/dist/services/parallel-processing.service.js.map +1 -0
  128. package/dist/services/remote-agent.service.d.ts +49 -0
  129. package/dist/services/remote-agent.service.js +215 -0
  130. package/dist/services/remote-agent.service.js.map +1 -0
  131. package/dist/services/result-formatter.service.d.ts +27 -0
  132. package/dist/services/result-formatter.service.js +126 -0
  133. package/dist/services/result-formatter.service.js.map +1 -0
  134. package/dist/services/task-management.service.d.ts +63 -0
  135. package/dist/services/task-management.service.js +272 -0
  136. package/dist/services/task-management.service.js.map +1 -0
  137. package/dist/services/template.service.d.ts +36 -0
  138. package/dist/services/template.service.js +195 -0
  139. package/dist/services/template.service.js.map +1 -0
  140. package/dist/services/tool-call.service.d.ts +53 -0
  141. package/dist/services/tool-call.service.js +1061 -0
  142. package/dist/services/tool-call.service.js.map +1 -0
  143. package/dist/slack/formatters/message.formatter.d.ts +25 -0
  144. package/dist/slack/formatters/message.formatter.js +246 -0
  145. package/dist/slack/formatters/message.formatter.js.map +1 -0
  146. package/dist/slack/slack-bot.d.ts +24 -0
  147. package/dist/slack/slack-bot.js +467 -0
  148. package/dist/slack/slack-bot.js.map +1 -0
  149. package/dist/stderr.logger.d.ts +8 -0
  150. package/dist/stderr.logger.js +26 -0
  151. package/dist/stderr.logger.js.map +1 -0
  152. package/dist/utils/config-utils.d.ts +15 -0
  153. package/dist/utils/config-utils.js +69 -0
  154. package/dist/utils/config-utils.js.map +1 -0
  155. package/dist/utils/mcp-installer.d.ts +20 -0
  156. package/dist/utils/mcp-installer.js +199 -0
  157. package/dist/utils/mcp-installer.js.map +1 -0
  158. package/dist/utils/mention-parser.d.ts +18 -0
  159. package/dist/utils/mention-parser.js +136 -0
  160. package/dist/utils/mention-parser.js.map +1 -0
  161. package/dist/utils/simple-security.d.ts +3 -0
  162. package/dist/utils/simple-security.js +20 -0
  163. package/dist/utils/simple-security.js.map +1 -0
  164. package/dist/utils/stdin-utils.d.ts +27 -0
  165. package/dist/utils/stdin-utils.js +130 -0
  166. package/dist/utils/stdin-utils.js.map +1 -0
  167. package/dist/utils/template-processor.d.ts +32 -0
  168. package/dist/utils/template-processor.js +202 -0
  169. package/dist/utils/template-processor.js.map +1 -0
  170. package/dist/version.d.ts +1 -0
  171. package/dist/version.js +17 -0
  172. package/dist/version.js.map +1 -0
  173. package/package.json +122 -0
@@ -0,0 +1,1061 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ToolCallService = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ const fs_1 = require("fs");
15
+ const child_process_1 = require("child_process");
16
+ const path_1 = require("path");
17
+ const agent_loader_service_1 = require("./agent-loader.service");
18
+ const crewx_sdk_1 = require("@sowonai/crewx-sdk");
19
+ let ToolCallService = class ToolCallService {
20
+ constructor(agentLoaderService) {
21
+ this.agentLoaderService = agentLoaderService;
22
+ this.logger = new common_1.Logger('ToolCallService');
23
+ this.tools = new Map();
24
+ this.registerBuiltinTools();
25
+ }
26
+ setCrewXTool(crewXTool) {
27
+ this.crewXTool = crewXTool;
28
+ this.registerMcpTools();
29
+ }
30
+ registerBuiltinTools() {
31
+ this.register({
32
+ name: 'hello',
33
+ description: 'A simple greeting tool that returns a hello message with the provided name',
34
+ input_schema: {
35
+ type: 'object',
36
+ properties: {
37
+ name: {
38
+ type: 'string',
39
+ description: 'The name to greet',
40
+ },
41
+ },
42
+ required: ['name'],
43
+ },
44
+ output_schema: {
45
+ type: 'object',
46
+ properties: {
47
+ message: {
48
+ type: 'string',
49
+ description: 'The greeting message',
50
+ },
51
+ },
52
+ required: ['message'],
53
+ },
54
+ }, {
55
+ execute: async (context) => {
56
+ const startTime = Date.now();
57
+ try {
58
+ const { name } = context.input;
59
+ if (!name || typeof name !== 'string') {
60
+ return {
61
+ success: false,
62
+ error: 'Invalid input: name is required and must be a string',
63
+ metadata: {
64
+ executionTime: Date.now() - startTime,
65
+ toolName: 'hello',
66
+ runId: context.runId,
67
+ },
68
+ };
69
+ }
70
+ const message = `Hello, ${name}! 👋 Welcome to CrewX tool system!`;
71
+ return {
72
+ success: true,
73
+ data: { message },
74
+ metadata: {
75
+ executionTime: Date.now() - startTime,
76
+ toolName: 'hello',
77
+ runId: context.runId,
78
+ },
79
+ };
80
+ }
81
+ catch (error) {
82
+ return {
83
+ success: false,
84
+ error: `Failed to generate greeting: ${error.message}`,
85
+ metadata: {
86
+ executionTime: Date.now() - startTime,
87
+ toolName: 'hello',
88
+ runId: context.runId,
89
+ },
90
+ };
91
+ }
92
+ },
93
+ });
94
+ this.register({
95
+ name: 'run_shell',
96
+ description: 'Execute a shell command in the current workspace directory',
97
+ input_schema: {
98
+ type: 'object',
99
+ properties: {
100
+ command: {
101
+ type: 'string',
102
+ description: 'Shell command to execute (executed via bash -lc)',
103
+ },
104
+ cwd: {
105
+ type: 'string',
106
+ description: 'Optional working directory (relative or absolute)',
107
+ },
108
+ timeout: {
109
+ type: 'number',
110
+ description: 'Optional timeout in milliseconds (default: 120000)',
111
+ },
112
+ },
113
+ required: ['command'],
114
+ },
115
+ output_schema: {
116
+ type: 'object',
117
+ properties: {
118
+ stdout: { type: 'string', description: 'Standard output from the command' },
119
+ stderr: { type: 'string', description: 'Standard error from the command' },
120
+ exitCode: { type: 'number', description: 'Process exit code' },
121
+ timedOut: { type: 'boolean', description: 'Indicates whether the process was terminated due to timeout' },
122
+ },
123
+ },
124
+ }, {
125
+ execute: async (context) => {
126
+ const startTime = Date.now();
127
+ const { command, cwd, timeout } = context.input;
128
+ if (!command || typeof command !== 'string') {
129
+ return {
130
+ success: false,
131
+ error: 'Invalid input: command is required and must be a string',
132
+ metadata: {
133
+ executionTime: Date.now() - startTime,
134
+ toolName: 'run_shell',
135
+ runId: context.runId,
136
+ },
137
+ };
138
+ }
139
+ const workingDir = cwd && typeof cwd === 'string' ? (0, path_1.resolve)(process.cwd(), cwd) : process.cwd();
140
+ const maxTimeout = typeof timeout === 'number' && timeout > 0 ? timeout : 120000;
141
+ return await new Promise((resolveResult) => {
142
+ try {
143
+ const child = (0, child_process_1.spawn)('bash', ['-lc', command], {
144
+ cwd: workingDir,
145
+ env: { ...process.env },
146
+ });
147
+ let stdout = '';
148
+ let stderr = '';
149
+ let timedOut = false;
150
+ child.stdout.on('data', (data) => {
151
+ stdout += data.toString();
152
+ });
153
+ child.stderr.on('data', (data) => {
154
+ stderr += data.toString();
155
+ });
156
+ const timeoutId = setTimeout(() => {
157
+ timedOut = true;
158
+ child.kill('SIGTERM');
159
+ }, maxTimeout);
160
+ child.on('error', (error) => {
161
+ clearTimeout(timeoutId);
162
+ resolveResult({
163
+ success: false,
164
+ error: `Failed to execute command: ${error.message}`,
165
+ metadata: {
166
+ executionTime: Date.now() - startTime,
167
+ toolName: 'run_shell',
168
+ runId: context.runId,
169
+ },
170
+ });
171
+ });
172
+ child.on('close', (code) => {
173
+ clearTimeout(timeoutId);
174
+ const executionTime = Date.now() - startTime;
175
+ if (timedOut) {
176
+ resolveResult({
177
+ success: false,
178
+ error: `Command timed out after ${maxTimeout}ms`,
179
+ metadata: {
180
+ executionTime,
181
+ toolName: 'run_shell',
182
+ runId: context.runId,
183
+ },
184
+ data: {
185
+ stdout,
186
+ stderr,
187
+ exitCode: code ?? -1,
188
+ timedOut: true,
189
+ },
190
+ });
191
+ return;
192
+ }
193
+ if (code === 0) {
194
+ resolveResult({
195
+ success: true,
196
+ data: {
197
+ stdout: stdout.trim(),
198
+ stderr: stderr.trim(),
199
+ exitCode: code ?? 0,
200
+ timedOut: false,
201
+ },
202
+ metadata: {
203
+ executionTime,
204
+ toolName: 'run_shell',
205
+ runId: context.runId,
206
+ },
207
+ });
208
+ }
209
+ else {
210
+ resolveResult({
211
+ success: false,
212
+ error: stderr.trim() || `Command exited with code ${code}`,
213
+ data: {
214
+ stdout: stdout.trim(),
215
+ stderr: stderr.trim(),
216
+ exitCode: code ?? -1,
217
+ timedOut: false,
218
+ },
219
+ metadata: {
220
+ executionTime,
221
+ toolName: 'run_shell',
222
+ runId: context.runId,
223
+ },
224
+ });
225
+ }
226
+ });
227
+ }
228
+ catch (error) {
229
+ resolveResult({
230
+ success: false,
231
+ error: `Failed to execute command: ${error.message}`,
232
+ metadata: {
233
+ executionTime: Date.now() - startTime,
234
+ toolName: 'run_shell',
235
+ runId: context.runId,
236
+ },
237
+ });
238
+ }
239
+ });
240
+ },
241
+ });
242
+ this.register({
243
+ name: 'read_file',
244
+ description: 'Read the contents of a file from the filesystem',
245
+ input_schema: {
246
+ type: 'object',
247
+ properties: {
248
+ path: {
249
+ type: 'string',
250
+ description: 'The path to the file to read',
251
+ },
252
+ },
253
+ required: ['path'],
254
+ },
255
+ output_schema: {
256
+ type: 'object',
257
+ properties: {
258
+ content: {
259
+ type: 'string',
260
+ description: 'The content of the file',
261
+ },
262
+ },
263
+ required: ['content'],
264
+ },
265
+ }, {
266
+ execute: async (context) => {
267
+ const startTime = Date.now();
268
+ try {
269
+ const { path } = context.input;
270
+ if (!path || typeof path !== 'string') {
271
+ return {
272
+ success: false,
273
+ error: 'Invalid input: path is required and must be a string',
274
+ metadata: {
275
+ executionTime: Date.now() - startTime,
276
+ toolName: 'read_file',
277
+ runId: context.runId,
278
+ },
279
+ };
280
+ }
281
+ const content = (0, fs_1.readFileSync)(path, 'utf-8');
282
+ return {
283
+ success: true,
284
+ data: { content },
285
+ metadata: {
286
+ executionTime: Date.now() - startTime,
287
+ toolName: 'read_file',
288
+ runId: context.runId,
289
+ },
290
+ };
291
+ }
292
+ catch (error) {
293
+ return {
294
+ success: false,
295
+ error: `Failed to read file: ${error.message}`,
296
+ metadata: {
297
+ executionTime: Date.now() - startTime,
298
+ toolName: 'read_file',
299
+ runId: context.runId,
300
+ },
301
+ };
302
+ }
303
+ },
304
+ });
305
+ this.register({
306
+ name: 'write_to_file',
307
+ description: 'Write content to a file on the filesystem. Creates the file if it does not exist, or overwrites it if it does.',
308
+ input_schema: {
309
+ type: 'object',
310
+ properties: {
311
+ path: {
312
+ type: 'string',
313
+ description: 'The path to the file to write',
314
+ },
315
+ content: {
316
+ type: 'string',
317
+ description: 'The content to write to the file',
318
+ },
319
+ },
320
+ required: ['path', 'content'],
321
+ },
322
+ output_schema: {
323
+ type: 'object',
324
+ properties: {
325
+ success: {
326
+ type: 'boolean',
327
+ description: 'Whether the write operation succeeded',
328
+ },
329
+ path: {
330
+ type: 'string',
331
+ description: 'The path of the written file',
332
+ },
333
+ bytesWritten: {
334
+ type: 'number',
335
+ description: 'Number of bytes written',
336
+ },
337
+ },
338
+ required: ['success', 'path'],
339
+ },
340
+ }, {
341
+ execute: async (context) => {
342
+ const startTime = Date.now();
343
+ try {
344
+ const { path, content } = context.input;
345
+ if (!path || typeof path !== 'string') {
346
+ return {
347
+ success: false,
348
+ error: 'Invalid input: path is required and must be a string',
349
+ metadata: {
350
+ executionTime: Date.now() - startTime,
351
+ toolName: 'write_to_file',
352
+ runId: context.runId,
353
+ },
354
+ };
355
+ }
356
+ if (content === undefined || content === null) {
357
+ return {
358
+ success: false,
359
+ error: 'Invalid input: content is required',
360
+ metadata: {
361
+ executionTime: Date.now() - startTime,
362
+ toolName: 'write_to_file',
363
+ runId: context.runId,
364
+ },
365
+ };
366
+ }
367
+ const contentStr = String(content);
368
+ (0, fs_1.writeFileSync)(path, contentStr, 'utf-8');
369
+ const bytesWritten = Buffer.byteLength(contentStr, 'utf-8');
370
+ return {
371
+ success: true,
372
+ data: {
373
+ success: true,
374
+ path,
375
+ bytesWritten,
376
+ },
377
+ metadata: {
378
+ executionTime: Date.now() - startTime,
379
+ toolName: 'write_to_file',
380
+ runId: context.runId,
381
+ },
382
+ };
383
+ }
384
+ catch (error) {
385
+ return {
386
+ success: false,
387
+ error: `Failed to write file: ${error.message}`,
388
+ metadata: {
389
+ executionTime: Date.now() - startTime,
390
+ toolName: 'write_to_file',
391
+ runId: context.runId,
392
+ },
393
+ };
394
+ }
395
+ },
396
+ });
397
+ this.register({
398
+ name: 'list_agents',
399
+ description: 'List all available AI agents in the CrewX system. Returns detailed information about each agent including their ID, provider, capabilities, and specialties. Use this tool to discover which agents are available for delegation or collaboration.',
400
+ input_schema: {
401
+ type: 'object',
402
+ properties: {},
403
+ required: [],
404
+ },
405
+ output_schema: {
406
+ type: 'object',
407
+ properties: {
408
+ agents: {
409
+ type: 'array',
410
+ description: 'List of available agents',
411
+ items: {
412
+ type: 'object',
413
+ properties: {
414
+ id: { type: 'string', description: 'Agent unique identifier' },
415
+ name: { type: 'string', description: 'Agent display name' },
416
+ provider: { type: 'string', description: 'AI provider (claude/gemini/copilot)' },
417
+ role: { type: 'string', description: 'Agent role' },
418
+ team: { type: 'string', description: 'Agent team' },
419
+ workingDirectory: { type: 'string', description: 'Working directory path' },
420
+ capabilities: { type: 'array', items: { type: 'string' }, description: 'Agent capabilities' },
421
+ description: { type: 'string', description: 'Agent description' },
422
+ specialties: { type: 'array', items: { type: 'string' }, description: 'Agent specialties' },
423
+ },
424
+ },
425
+ },
426
+ totalCount: {
427
+ type: 'number',
428
+ description: 'Total number of available agents',
429
+ },
430
+ },
431
+ required: ['agents', 'totalCount'],
432
+ },
433
+ }, {
434
+ execute: async (context) => {
435
+ const startTime = Date.now();
436
+ try {
437
+ console.log('Executing list_agents tool');
438
+ const agents = await this.agentLoaderService.getAllAgents();
439
+ const configSource = this.agentLoaderService.getConfigSource();
440
+ this.logger.log(`list_agents tool returned ${agents.length} agents`);
441
+ return {
442
+ success: true,
443
+ data: {
444
+ agents: agents.map(agent => ({
445
+ id: agent.id,
446
+ name: agent.name || agent.id,
447
+ role: agent.role || 'AI Agent',
448
+ team: agent.team || 'AI Team',
449
+ provider: Array.isArray(agent.provider) ? agent.provider[0] : agent.provider,
450
+ workingDirectory: agent.workingDirectory || './',
451
+ capabilities: agent.capabilities || [],
452
+ description: agent.description || `${agent.name || agent.id} agent`,
453
+ specialties: agent.specialties || [],
454
+ })),
455
+ totalCount: agents.length,
456
+ configurationSource: configSource.source,
457
+ },
458
+ metadata: {
459
+ executionTime: Date.now() - startTime,
460
+ toolName: 'list_agents',
461
+ runId: context.runId,
462
+ },
463
+ };
464
+ }
465
+ catch (error) {
466
+ return {
467
+ success: false,
468
+ error: `Failed to list agents: ${error.message}`,
469
+ metadata: {
470
+ executionTime: Date.now() - startTime,
471
+ toolName: 'list_agents',
472
+ runId: context.runId,
473
+ },
474
+ };
475
+ }
476
+ },
477
+ });
478
+ this.register({
479
+ name: 'get_markdown_headings',
480
+ description: 'Extract table of contents (headings) from a markdown file. Use this tool to efficiently understand the structure of large markdown files without reading the entire content.',
481
+ input_schema: {
482
+ type: 'object',
483
+ properties: {
484
+ path: {
485
+ type: 'string',
486
+ description: 'The path to the markdown file',
487
+ },
488
+ maxDepth: {
489
+ type: 'number',
490
+ description: 'Maximum heading depth to include (1-6, default: 3)',
491
+ },
492
+ },
493
+ required: ['path'],
494
+ },
495
+ output_schema: {
496
+ type: 'object',
497
+ properties: {
498
+ headings: {
499
+ type: 'array',
500
+ description: 'Array of heading objects with depth and text',
501
+ items: {
502
+ type: 'object',
503
+ properties: {
504
+ depth: { type: 'number', description: 'Heading depth (1-6)' },
505
+ text: { type: 'string', description: 'Heading text' },
506
+ },
507
+ },
508
+ },
509
+ toc: {
510
+ type: 'string',
511
+ description: 'Table of contents as markdown string',
512
+ },
513
+ fileSize: {
514
+ type: 'number',
515
+ description: 'File size in bytes',
516
+ },
517
+ },
518
+ required: ['headings', 'toc', 'fileSize'],
519
+ },
520
+ }, {
521
+ execute: async (context) => {
522
+ const startTime = Date.now();
523
+ try {
524
+ const { path, maxDepth = 3 } = context.input;
525
+ if (!path || typeof path !== 'string') {
526
+ return {
527
+ success: false,
528
+ error: 'Invalid input: path is required and must be a string',
529
+ metadata: {
530
+ executionTime: Date.now() - startTime,
531
+ toolName: 'get_markdown_headings',
532
+ runId: context.runId,
533
+ },
534
+ };
535
+ }
536
+ const depth = typeof maxDepth === 'number' ? Math.min(Math.max(maxDepth, 1), 6) : 3;
537
+ const content = (0, fs_1.readFileSync)(path, 'utf-8');
538
+ const stats = (0, fs_1.statSync)(path);
539
+ const tocMarkdown = await crewx_sdk_1.DocumentManager.extractToc(content, depth);
540
+ const headings = tocMarkdown.split('\n').filter(line => line.trim()).map(line => {
541
+ const match = line.match(/^(#{1,6})\s+(.+)$/);
542
+ if (match && match[1] && match[2]) {
543
+ return {
544
+ depth: match[1].length,
545
+ text: match[2].trim(),
546
+ };
547
+ }
548
+ return null;
549
+ }).filter((h) => h !== null);
550
+ return {
551
+ success: true,
552
+ data: {
553
+ headings,
554
+ toc: tocMarkdown,
555
+ fileSize: stats.size,
556
+ },
557
+ metadata: {
558
+ executionTime: Date.now() - startTime,
559
+ toolName: 'get_markdown_headings',
560
+ runId: context.runId,
561
+ },
562
+ };
563
+ }
564
+ catch (error) {
565
+ return {
566
+ success: false,
567
+ error: `Failed to extract markdown headings: ${error.message}`,
568
+ metadata: {
569
+ executionTime: Date.now() - startTime,
570
+ toolName: 'get_markdown_headings',
571
+ runId: context.runId,
572
+ },
573
+ };
574
+ }
575
+ },
576
+ });
577
+ this.register({
578
+ name: 'get_markdown_sections',
579
+ description: 'Extract specific sections from a markdown file by heading names. Use this after get_markdown_headings to selectively read only the sections you need.',
580
+ input_schema: {
581
+ type: 'object',
582
+ properties: {
583
+ path: {
584
+ type: 'string',
585
+ description: 'The path to the markdown file',
586
+ },
587
+ headings: {
588
+ type: 'array',
589
+ items: { type: 'string' },
590
+ description: 'Array of heading texts to extract sections for',
591
+ },
592
+ },
593
+ required: ['path', 'headings'],
594
+ },
595
+ output_schema: {
596
+ type: 'object',
597
+ properties: {
598
+ sections: {
599
+ type: 'array',
600
+ description: 'Array of extracted sections',
601
+ items: {
602
+ type: 'object',
603
+ properties: {
604
+ heading: { type: 'string', description: 'Requested heading text' },
605
+ content: { type: 'string', description: 'Section content' },
606
+ found: { type: 'boolean', description: 'Whether the section was found' },
607
+ },
608
+ },
609
+ },
610
+ totalSize: {
611
+ type: 'number',
612
+ description: 'Total size of extracted content in bytes',
613
+ },
614
+ notFound: {
615
+ type: 'array',
616
+ items: { type: 'string' },
617
+ description: 'Headings that were not found',
618
+ },
619
+ },
620
+ required: ['sections', 'totalSize', 'notFound'],
621
+ },
622
+ }, {
623
+ execute: async (context) => {
624
+ const startTime = Date.now();
625
+ try {
626
+ const { path, headings } = context.input;
627
+ if (!path || typeof path !== 'string') {
628
+ return {
629
+ success: false,
630
+ error: 'Invalid input: path is required and must be a string',
631
+ metadata: {
632
+ executionTime: Date.now() - startTime,
633
+ toolName: 'get_markdown_sections',
634
+ runId: context.runId,
635
+ },
636
+ };
637
+ }
638
+ if (!Array.isArray(headings) || headings.length === 0) {
639
+ return {
640
+ success: false,
641
+ error: 'Invalid input: headings is required and must be a non-empty array',
642
+ metadata: {
643
+ executionTime: Date.now() - startTime,
644
+ toolName: 'get_markdown_sections',
645
+ runId: context.runId,
646
+ },
647
+ };
648
+ }
649
+ const content = (0, fs_1.readFileSync)(path, 'utf-8');
650
+ const sections = [];
651
+ const notFound = [];
652
+ let totalSize = 0;
653
+ for (const heading of headings) {
654
+ if (typeof heading !== 'string') {
655
+ sections.push({
656
+ heading: String(heading),
657
+ content: '',
658
+ found: false,
659
+ });
660
+ notFound.push(String(heading));
661
+ continue;
662
+ }
663
+ try {
664
+ const escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
665
+ const headingRegex = new RegExp(`^(#{1,6})\\s+${escapeRegex(heading)}\\s*$`, 'm');
666
+ const match = content.match(headingRegex);
667
+ if (match && match.index !== undefined && match[1]) {
668
+ const startIndex = match.index;
669
+ const headingLevel = match[1].length;
670
+ const nextHeadingRegex = new RegExp(`^#{1,${headingLevel}}\\s+`, 'gm');
671
+ nextHeadingRegex.lastIndex = startIndex + match[0].length;
672
+ const nextMatch = nextHeadingRegex.exec(content);
673
+ const endIndex = nextMatch ? nextMatch.index : content.length;
674
+ const sectionContent = content.substring(startIndex, endIndex).trim();
675
+ sections.push({
676
+ heading,
677
+ content: sectionContent,
678
+ found: true,
679
+ });
680
+ totalSize += sectionContent.length;
681
+ }
682
+ else {
683
+ sections.push({
684
+ heading,
685
+ content: '',
686
+ found: false,
687
+ });
688
+ notFound.push(heading);
689
+ }
690
+ }
691
+ catch (error) {
692
+ sections.push({
693
+ heading,
694
+ content: '',
695
+ found: false,
696
+ });
697
+ notFound.push(heading);
698
+ }
699
+ }
700
+ return {
701
+ success: true,
702
+ data: {
703
+ sections,
704
+ totalSize,
705
+ notFound,
706
+ },
707
+ metadata: {
708
+ executionTime: Date.now() - startTime,
709
+ toolName: 'get_markdown_sections',
710
+ runId: context.runId,
711
+ },
712
+ };
713
+ }
714
+ catch (error) {
715
+ return {
716
+ success: false,
717
+ error: `Failed to extract markdown sections: ${error.message}`,
718
+ metadata: {
719
+ executionTime: Date.now() - startTime,
720
+ toolName: 'get_markdown_sections',
721
+ runId: context.runId,
722
+ },
723
+ };
724
+ }
725
+ },
726
+ });
727
+ this.logger.log('Built-in tools registered: hello, read_file, write_to_file, run_shell, list_agents, get_markdown_headings, get_markdown_sections');
728
+ }
729
+ registerMcpTools() {
730
+ if (!this.crewXTool) {
731
+ this.logger.warn('CrewXTool not available, skipping MCP tools registration');
732
+ return;
733
+ }
734
+ this.register({
735
+ name: 'get_task_logs',
736
+ description: 'Get task execution logs by task ID. Use this to monitor task progress and detailed execution logs for debugging or tracking purposes.',
737
+ input_schema: {
738
+ type: 'object',
739
+ properties: {
740
+ taskId: {
741
+ type: 'string',
742
+ description: 'Task ID to get logs for. If not provided, returns all recent tasks.',
743
+ },
744
+ },
745
+ required: [],
746
+ },
747
+ output_schema: {
748
+ type: 'object',
749
+ properties: {
750
+ logs: {
751
+ type: 'string',
752
+ description: 'Task logs content',
753
+ },
754
+ },
755
+ required: ['logs'],
756
+ },
757
+ }, {
758
+ execute: async (context) => {
759
+ const startTime = Date.now();
760
+ try {
761
+ const result = await this.crewXTool.getTaskLogs({ taskId: context.input.taskId });
762
+ return {
763
+ success: result.isError !== true,
764
+ data: {
765
+ logs: result.content?.[0]?.text || 'No logs available',
766
+ },
767
+ metadata: {
768
+ executionTime: Date.now() - startTime,
769
+ toolName: 'get_task_logs',
770
+ runId: context.runId,
771
+ },
772
+ };
773
+ }
774
+ catch (error) {
775
+ return {
776
+ success: false,
777
+ error: `Failed to get task logs: ${error.message}`,
778
+ metadata: {
779
+ executionTime: Date.now() - startTime,
780
+ toolName: 'get_task_logs',
781
+ runId: context.runId,
782
+ },
783
+ };
784
+ }
785
+ },
786
+ });
787
+ this.register({
788
+ name: 'check_ai_providers',
789
+ description: 'Check the status of available AI CLI tools (Claude, Gemini, GitHub Copilot). Returns information about which providers are installed and ready to use.',
790
+ input_schema: {
791
+ type: 'object',
792
+ properties: {},
793
+ required: [],
794
+ },
795
+ output_schema: {
796
+ type: 'object',
797
+ properties: {
798
+ availableProviders: {
799
+ type: 'array',
800
+ items: { type: 'string' },
801
+ description: 'List of available AI providers',
802
+ },
803
+ installation: {
804
+ type: 'object',
805
+ description: 'Installation status for each provider',
806
+ },
807
+ },
808
+ required: ['availableProviders'],
809
+ },
810
+ }, {
811
+ execute: async (context) => {
812
+ const startTime = Date.now();
813
+ try {
814
+ const result = await this.crewXTool.checkAIProviders();
815
+ return {
816
+ success: result.success !== false,
817
+ data: {
818
+ availableProviders: result.availableProviders || [],
819
+ installation: result.installation || {},
820
+ recommendations: result.recommendations || [],
821
+ },
822
+ metadata: {
823
+ executionTime: Date.now() - startTime,
824
+ toolName: 'check_ai_providers',
825
+ runId: context.runId,
826
+ },
827
+ };
828
+ }
829
+ catch (error) {
830
+ return {
831
+ success: false,
832
+ error: `Failed to check AI providers: ${error.message}`,
833
+ metadata: {
834
+ executionTime: Date.now() - startTime,
835
+ toolName: 'check_ai_providers',
836
+ runId: context.runId,
837
+ },
838
+ };
839
+ }
840
+ },
841
+ });
842
+ this.register({
843
+ name: 'query_agent',
844
+ description: 'Query a specific AI agent in read-only mode. Use this to ask questions, request code analysis, explanations, or reviews. No file modifications will be performed. This is ideal for getting expert opinions or analysis from specialized agents.',
845
+ input_schema: {
846
+ type: 'object',
847
+ properties: {
848
+ agentId: {
849
+ type: 'string',
850
+ description: 'Agent ID to query (e.g., claude, gemini, copilot, or custom agents from agents.yaml). Use list_agents tool to see available agents.',
851
+ },
852
+ query: {
853
+ type: 'string',
854
+ description: 'Question or request to ask the agent',
855
+ },
856
+ context: {
857
+ type: 'string',
858
+ description: 'Additional context or background information (optional)',
859
+ },
860
+ },
861
+ required: ['agentId', 'query'],
862
+ },
863
+ output_schema: {
864
+ type: 'object',
865
+ properties: {
866
+ response: {
867
+ type: 'string',
868
+ description: 'Agent response to the query',
869
+ },
870
+ agent: {
871
+ type: 'string',
872
+ description: 'Agent that responded',
873
+ },
874
+ provider: {
875
+ type: 'string',
876
+ description: 'AI provider used',
877
+ },
878
+ taskId: {
879
+ type: 'string',
880
+ description: 'Task ID for tracking',
881
+ },
882
+ },
883
+ required: ['response', 'agent'],
884
+ },
885
+ }, {
886
+ execute: async (context) => {
887
+ const startTime = Date.now();
888
+ try {
889
+ const result = await this.crewXTool.queryAgent({
890
+ agentId: context.input.agentId,
891
+ query: context.input.query,
892
+ context: context.input.context,
893
+ });
894
+ return {
895
+ success: result.success !== false,
896
+ data: {
897
+ response: result.response || result.content?.[0]?.text || 'No response',
898
+ agent: result.agent,
899
+ provider: result.provider,
900
+ taskId: result.taskId,
901
+ error: result.error,
902
+ },
903
+ metadata: {
904
+ executionTime: Date.now() - startTime,
905
+ toolName: 'query_agent',
906
+ runId: context.runId,
907
+ },
908
+ };
909
+ }
910
+ catch (error) {
911
+ return {
912
+ success: false,
913
+ error: `Failed to query agent: ${error.message}`,
914
+ metadata: {
915
+ executionTime: Date.now() - startTime,
916
+ toolName: 'query_agent',
917
+ runId: context.runId,
918
+ },
919
+ };
920
+ }
921
+ },
922
+ });
923
+ this.register({
924
+ name: 'execute_agent',
925
+ description: 'Execute tasks through a specialist agent. This allows file modifications and implementations. Use this when you need an agent to perform actual work like code generation, file editing, or system changes. Be cautious as this can modify files.',
926
+ input_schema: {
927
+ type: 'object',
928
+ properties: {
929
+ agentId: {
930
+ type: 'string',
931
+ description: 'Agent ID to execute (e.g., claude, gemini, copilot, or custom agents). Use list_agents to see available agents.',
932
+ },
933
+ task: {
934
+ type: 'string',
935
+ description: 'Task or implementation request for the agent to perform',
936
+ },
937
+ context: {
938
+ type: 'string',
939
+ description: 'Additional context or background information (optional)',
940
+ },
941
+ },
942
+ required: ['agentId', 'task'],
943
+ },
944
+ output_schema: {
945
+ type: 'object',
946
+ properties: {
947
+ implementation: {
948
+ type: 'string',
949
+ description: 'Implementation result or guidance',
950
+ },
951
+ agent: {
952
+ type: 'string',
953
+ description: 'Agent that executed the task',
954
+ },
955
+ provider: {
956
+ type: 'string',
957
+ description: 'AI provider used',
958
+ },
959
+ taskId: {
960
+ type: 'string',
961
+ description: 'Task ID for tracking',
962
+ },
963
+ },
964
+ required: ['implementation', 'agent'],
965
+ },
966
+ }, {
967
+ execute: async (context) => {
968
+ const startTime = Date.now();
969
+ try {
970
+ const result = await this.crewXTool.executeAgent({
971
+ agentId: context.input.agentId,
972
+ task: context.input.task,
973
+ context: context.input.context,
974
+ });
975
+ return {
976
+ success: result.success !== false,
977
+ data: {
978
+ implementation: result.implementation || result.content?.[0]?.text || 'No implementation',
979
+ agent: result.agent,
980
+ provider: result.provider,
981
+ taskId: result.taskId,
982
+ error: result.error,
983
+ recommendations: result.recommendations,
984
+ },
985
+ metadata: {
986
+ executionTime: Date.now() - startTime,
987
+ toolName: 'execute_agent',
988
+ runId: context.runId,
989
+ },
990
+ };
991
+ }
992
+ catch (error) {
993
+ return {
994
+ success: false,
995
+ error: `Failed to execute agent: ${error.message}`,
996
+ metadata: {
997
+ executionTime: Date.now() - startTime,
998
+ toolName: 'execute_agent',
999
+ runId: context.runId,
1000
+ },
1001
+ };
1002
+ }
1003
+ },
1004
+ });
1005
+ this.logger.log('MCP tools registered: get_task_logs, check_ai_providers, query_agent, execute_agent');
1006
+ }
1007
+ register(definition, executor) {
1008
+ this.tools.set(definition.name, { definition, executor });
1009
+ this.logger.log(`Tool registered: ${definition.name}`);
1010
+ }
1011
+ list() {
1012
+ return Array.from(this.tools.values()).map(t => t.definition);
1013
+ }
1014
+ async execute(name, input, context) {
1015
+ const tool = this.tools.get(name);
1016
+ if (!tool) {
1017
+ this.logger.error(`Tool not found: ${name}`);
1018
+ return {
1019
+ success: false,
1020
+ error: `Tool not found: ${name}`,
1021
+ };
1022
+ }
1023
+ const executionContext = {
1024
+ input,
1025
+ runId: context?.runId,
1026
+ threadId: context?.threadId,
1027
+ resourceId: context?.resourceId,
1028
+ agentId: context?.agentId,
1029
+ tracingContext: context?.tracingContext,
1030
+ };
1031
+ this.logger.log(`Executing tool: ${name} with input:`, JSON.stringify(input));
1032
+ try {
1033
+ const result = await tool.executor.execute(executionContext);
1034
+ this.logger.log(`Tool ${name} executed successfully`, {
1035
+ success: result.success,
1036
+ runId: executionContext.runId,
1037
+ });
1038
+ return result;
1039
+ }
1040
+ catch (error) {
1041
+ this.logger.error(`Tool ${name} execution failed:`, error.message);
1042
+ return {
1043
+ success: false,
1044
+ error: `Tool execution failed: ${error.message}`,
1045
+ metadata: {
1046
+ toolName: name,
1047
+ runId: executionContext.runId,
1048
+ },
1049
+ };
1050
+ }
1051
+ }
1052
+ has(name) {
1053
+ return this.tools.has(name);
1054
+ }
1055
+ };
1056
+ exports.ToolCallService = ToolCallService;
1057
+ exports.ToolCallService = ToolCallService = __decorate([
1058
+ (0, common_1.Injectable)(),
1059
+ __metadata("design:paramtypes", [agent_loader_service_1.AgentLoaderService])
1060
+ ], ToolCallService);
1061
+ //# sourceMappingURL=tool-call.service.js.map