tachibot-mcp 2.0.2

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 (214) hide show
  1. package/.env.example +260 -0
  2. package/CHANGELOG.md +54 -0
  3. package/CODE_OF_CONDUCT.md +56 -0
  4. package/CONTRIBUTING.md +54 -0
  5. package/Dockerfile +36 -0
  6. package/LICENSE +644 -0
  7. package/README.md +201 -0
  8. package/SECURITY.md +95 -0
  9. package/dist/personality/komaai-expressions.js +12 -0
  10. package/dist/profiles/balanced.json +33 -0
  11. package/dist/profiles/code_focus.json +33 -0
  12. package/dist/profiles/full.json +33 -0
  13. package/dist/profiles/minimal.json +33 -0
  14. package/dist/profiles/research_power.json +33 -0
  15. package/dist/scripts/build-profiles.js +46 -0
  16. package/dist/src/application/services/focus/FocusModeRegistry.js +46 -0
  17. package/dist/src/application/services/focus/FocusTool.service.js +109 -0
  18. package/dist/src/application/services/focus/ModeRegistry.js +46 -0
  19. package/dist/src/application/services/focus/modes/focus-deep.mode.js +27 -0
  20. package/dist/src/application/services/focus/modes/status.mode.js +50 -0
  21. package/dist/src/application/services/focus/modes/tachibot-status.mode.js +50 -0
  22. package/dist/src/collaborative-orchestrator.js +391 -0
  23. package/dist/src/config/model-constants.js +188 -0
  24. package/dist/src/config/model-defaults.js +57 -0
  25. package/dist/src/config/model-preferences.js +382 -0
  26. package/dist/src/config/timeout-config.js +130 -0
  27. package/dist/src/config.js +173 -0
  28. package/dist/src/domain/interfaces/IFocusMode.js +5 -0
  29. package/dist/src/domain/interfaces/IProvider.js +6 -0
  30. package/dist/src/domain/interfaces/ITool.js +5 -0
  31. package/dist/src/focus-deep.js +245 -0
  32. package/dist/src/infrastructure/ascii/art/robots.ascii.js +16 -0
  33. package/dist/src/mcp-client.js +90 -0
  34. package/dist/src/memory/index.js +17 -0
  35. package/dist/src/memory/memory-config.js +135 -0
  36. package/dist/src/memory/memory-interface.js +174 -0
  37. package/dist/src/memory/memory-manager.js +383 -0
  38. package/dist/src/memory/providers/devlog-provider.js +385 -0
  39. package/dist/src/memory/providers/hybrid-provider.js +399 -0
  40. package/dist/src/memory/providers/local-provider.js +388 -0
  41. package/dist/src/memory/providers/mem0-provider.js +337 -0
  42. package/dist/src/modes/architect.js +477 -0
  43. package/dist/src/modes/auditor.js +362 -0
  44. package/dist/src/modes/challenger.js +841 -0
  45. package/dist/src/modes/code-reviewer.js +382 -0
  46. package/dist/src/modes/commit-guardian.js +424 -0
  47. package/dist/src/modes/documentation-writer.js +572 -0
  48. package/dist/src/modes/scout.js +587 -0
  49. package/dist/src/modes/shared/helpers/challenger-helpers.js +454 -0
  50. package/dist/src/modes/shared/helpers/index.js +17 -0
  51. package/dist/src/modes/shared/helpers/scout-helpers.js +270 -0
  52. package/dist/src/modes/shared/helpers/verifier-helpers.js +332 -0
  53. package/dist/src/modes/test-architect.js +767 -0
  54. package/dist/src/modes/verifier.js +378 -0
  55. package/dist/src/monitoring/performance-monitor.js +435 -0
  56. package/dist/src/optimization/batch-executor.js +121 -0
  57. package/dist/src/optimization/context-pruner.js +196 -0
  58. package/dist/src/optimization/cost-monitor.js +338 -0
  59. package/dist/src/optimization/index.js +65 -0
  60. package/dist/src/optimization/model-router.js +264 -0
  61. package/dist/src/optimization/result-cache.js +114 -0
  62. package/dist/src/optimization/token-optimizer.js +257 -0
  63. package/dist/src/optimization/token-tracker.js +118 -0
  64. package/dist/src/orchestrator-instructions.js +128 -0
  65. package/dist/src/orchestrator-lite.js +139 -0
  66. package/dist/src/orchestrator.js +191 -0
  67. package/dist/src/orchestrators/collaborative/interfaces/IToolExecutionEngine.js +1 -0
  68. package/dist/src/orchestrators/collaborative/interfaces/IToolExecutionStrategy.js +5 -0
  69. package/dist/src/orchestrators/collaborative/interfaces/IVisualizationRenderer.js +1 -0
  70. package/dist/src/orchestrators/collaborative/registries/ModelProviderRegistry.js +95 -0
  71. package/dist/src/orchestrators/collaborative/registries/ToolAdapterRegistry.js +64 -0
  72. package/dist/src/orchestrators/collaborative/services/tool-execution/ToolExecutionService.js +502 -0
  73. package/dist/src/orchestrators/collaborative/services/visualization/VisualizationService.js +206 -0
  74. package/dist/src/orchestrators/collaborative/types/session-types.js +5 -0
  75. package/dist/src/profiles/balanced.js +37 -0
  76. package/dist/src/profiles/code_focus.js +37 -0
  77. package/dist/src/profiles/debug_intensive.js +59 -0
  78. package/dist/src/profiles/full.js +37 -0
  79. package/dist/src/profiles/minimal.js +37 -0
  80. package/dist/src/profiles/research_code.js +59 -0
  81. package/dist/src/profiles/research_power.js +37 -0
  82. package/dist/src/profiles/types.js +5 -0
  83. package/dist/src/profiles/workflow_builder.js +53 -0
  84. package/dist/src/prompt-engineer-lite.js +78 -0
  85. package/dist/src/prompt-engineer.js +399 -0
  86. package/dist/src/reasoning-chain.js +508 -0
  87. package/dist/src/sequential-thinking.js +291 -0
  88. package/dist/src/server-diagnostic.js +74 -0
  89. package/dist/src/server-raw.js +158 -0
  90. package/dist/src/server-simple.js +58 -0
  91. package/dist/src/server.js +514 -0
  92. package/dist/src/session/session-logger.js +617 -0
  93. package/dist/src/session/session-manager.js +571 -0
  94. package/dist/src/session/session-tools.js +400 -0
  95. package/dist/src/tools/advanced-modes.js +200 -0
  96. package/dist/src/tools/claude-integration.js +356 -0
  97. package/dist/src/tools/consolidated/ai-router.js +174 -0
  98. package/dist/src/tools/consolidated/ai-tool.js +48 -0
  99. package/dist/src/tools/consolidated/brainstorm-tool.js +87 -0
  100. package/dist/src/tools/consolidated/environment-detector.js +80 -0
  101. package/dist/src/tools/consolidated/index.js +50 -0
  102. package/dist/src/tools/consolidated/search-tool.js +110 -0
  103. package/dist/src/tools/consolidated/workflow-tool.js +238 -0
  104. package/dist/src/tools/gemini-tools.js +329 -0
  105. package/dist/src/tools/grok-enhanced.js +376 -0
  106. package/dist/src/tools/grok-tools.js +299 -0
  107. package/dist/src/tools/lmstudio-tools.js +223 -0
  108. package/dist/src/tools/openai-tools.js +498 -0
  109. package/dist/src/tools/openrouter-tools.js +317 -0
  110. package/dist/src/tools/optimized-wrapper.js +204 -0
  111. package/dist/src/tools/perplexity-tools.js +294 -0
  112. package/dist/src/tools/pingpong-tool.js +343 -0
  113. package/dist/src/tools/qwen-wrapper.js +74 -0
  114. package/dist/src/tools/tool-router.js +444 -0
  115. package/dist/src/tools/unified-ai-provider.js +260 -0
  116. package/dist/src/tools/workflow-runner.js +425 -0
  117. package/dist/src/tools/workflow-validator-tool.js +107 -0
  118. package/dist/src/types.js +23 -0
  119. package/dist/src/utils/input-validator.js +130 -0
  120. package/dist/src/utils/model-router.js +91 -0
  121. package/dist/src/utils/progress-stream.js +255 -0
  122. package/dist/src/utils/provider-router.js +88 -0
  123. package/dist/src/utils/smart-api-client.js +146 -0
  124. package/dist/src/utils/table-builder.js +218 -0
  125. package/dist/src/utils/timestamp-formatter.js +134 -0
  126. package/dist/src/utils/tool-compressor.js +257 -0
  127. package/dist/src/utils/tool-config.js +201 -0
  128. package/dist/src/validators/dependency-graph-validator.js +147 -0
  129. package/dist/src/validators/interpolation-validator.js +222 -0
  130. package/dist/src/validators/output-usage-validator.js +151 -0
  131. package/dist/src/validators/syntax-validator.js +102 -0
  132. package/dist/src/validators/tool-registry-validator.js +123 -0
  133. package/dist/src/validators/tool-types.js +97 -0
  134. package/dist/src/validators/types.js +8 -0
  135. package/dist/src/validators/workflow-validator.js +134 -0
  136. package/dist/src/visualizer-lite.js +42 -0
  137. package/dist/src/visualizer.js +179 -0
  138. package/dist/src/workflows/circuit-breaker.js +199 -0
  139. package/dist/src/workflows/custom-workflows.js +451 -0
  140. package/dist/src/workflows/engine/AutoSynthesizer.js +97 -0
  141. package/dist/src/workflows/engine/StepParameterResolver.js +74 -0
  142. package/dist/src/workflows/engine/VariableInterpolator.js +123 -0
  143. package/dist/src/workflows/engine/WorkflowDiscovery.js +125 -0
  144. package/dist/src/workflows/engine/WorkflowExecutionEngine.js +485 -0
  145. package/dist/src/workflows/engine/WorkflowExecutor.js +113 -0
  146. package/dist/src/workflows/engine/WorkflowFileManager.js +244 -0
  147. package/dist/src/workflows/engine/WorkflowHelpers.js +114 -0
  148. package/dist/src/workflows/engine/WorkflowOutputFormatter.js +83 -0
  149. package/dist/src/workflows/engine/events/WorkflowEventBus.js +132 -0
  150. package/dist/src/workflows/engine/events/interfaces/IEventBus.js +5 -0
  151. package/dist/src/workflows/engine/handlers/ErrorRecoveryHandler.js +162 -0
  152. package/dist/src/workflows/engine/handlers/PromptEnhancementHandler.js +115 -0
  153. package/dist/src/workflows/engine/handlers/SessionPersistenceHandler.js +167 -0
  154. package/dist/src/workflows/engine/handlers/StepExecutionHandler.js +231 -0
  155. package/dist/src/workflows/engine/handlers/ToolInvocationHandler.js +46 -0
  156. package/dist/src/workflows/engine/interfaces/IAutoSynthesizer.js +5 -0
  157. package/dist/src/workflows/engine/interfaces/IStepParameterResolver.js +5 -0
  158. package/dist/src/workflows/engine/interfaces/IVariableInterpolator.js +5 -0
  159. package/dist/src/workflows/engine/interfaces/IWorkflowDiscovery.js +4 -0
  160. package/dist/src/workflows/engine/interfaces/IWorkflowFileManager.js +5 -0
  161. package/dist/src/workflows/engine/interfaces/IWorkflowOutputFormatter.js +5 -0
  162. package/dist/src/workflows/engine/state/WorkflowStateMachine.js +194 -0
  163. package/dist/src/workflows/engine/state/interfaces/IStateMachine.js +17 -0
  164. package/dist/src/workflows/fallback-strategies.js +373 -0
  165. package/dist/src/workflows/message-queue.js +455 -0
  166. package/dist/src/workflows/model-router.js +189 -0
  167. package/dist/src/workflows/orchestrator-examples.js +174 -0
  168. package/dist/src/workflows/orchestrator-integration.js +200 -0
  169. package/dist/src/workflows/self-healing.js +524 -0
  170. package/dist/src/workflows/tool-mapper.js +407 -0
  171. package/dist/src/workflows/tool-orchestrator.js +796 -0
  172. package/dist/src/workflows/workflow-engine.js +573 -0
  173. package/dist/src/workflows/workflow-parser.js +283 -0
  174. package/dist/src/workflows/workflow-types.js +95 -0
  175. package/dist/src/workflows.js +568 -0
  176. package/dist/test-workflow-file-output.js +93 -0
  177. package/docs/API_KEYS.md +570 -0
  178. package/docs/CLAUDE_CODE_SETUP.md +181 -0
  179. package/docs/CLAUDE_DESKTOP_MANUAL.md +127 -0
  180. package/docs/CONFIGURATION.md +745 -0
  181. package/docs/FOCUS_MODES.md +240 -0
  182. package/docs/INSTALLATION_BOTH.md +145 -0
  183. package/docs/TERMS.md +352 -0
  184. package/docs/TOOLS_REFERENCE.md +1622 -0
  185. package/docs/TOOL_PARAMETERS.md +496 -0
  186. package/docs/TOOL_PROFILES.md +236 -0
  187. package/docs/WORKFLOWS.md +987 -0
  188. package/docs/WORKFLOW_OUTPUT.md +198 -0
  189. package/docs/WORKFLOW_PROGRESS_TRACKING.md +305 -0
  190. package/docs/workflows/design-brainstorm.md +335 -0
  191. package/package.json +97 -0
  192. package/profiles/balanced.json +37 -0
  193. package/profiles/code_focus.json +37 -0
  194. package/profiles/debug_intensive.json +34 -0
  195. package/profiles/full.json +37 -0
  196. package/profiles/minimal.json +37 -0
  197. package/profiles/research_power.json +37 -0
  198. package/profiles/workflow_builder.json +37 -0
  199. package/smithery.yaml +66 -0
  200. package/start.sh +8 -0
  201. package/tools.config.json +81 -0
  202. package/tsconfig.json +18 -0
  203. package/workflows/accessibility-code-audit.yaml +92 -0
  204. package/workflows/code-architecture-review.yaml +202 -0
  205. package/workflows/code-review.yaml +142 -0
  206. package/workflows/core/iterative-problem-solver.yaml +283 -0
  207. package/workflows/creative-brainstorm-yaml.yaml +215 -0
  208. package/workflows/pingpong.yaml +141 -0
  209. package/workflows/system/README.md +412 -0
  210. package/workflows/system/challenger.yaml +175 -0
  211. package/workflows/system/scout.yaml +164 -0
  212. package/workflows/system/verifier.yaml +133 -0
  213. package/workflows/ultra-creative-brainstorm.yaml +318 -0
  214. package/workflows/ux-research-flow.yaml +92 -0
@@ -0,0 +1,294 @@
1
+ /**
2
+ * Perplexity Tools Implementation
3
+ * Provides web search and reasoning capabilities
4
+ * No need for separate perplexity-mcp server
5
+ */
6
+ import { z } from "zod";
7
+ // Perplexity API configuration
8
+ const PERPLEXITY_API_URL = "https://api.perplexity.ai";
9
+ // Function to get the API key (deferred reading)
10
+ function getPerplexityApiKey() {
11
+ return process.env.PERPLEXITY_API_KEY;
12
+ }
13
+ // Debug logging function - call when needed
14
+ function debugApiKey() {
15
+ const apiKey = getPerplexityApiKey();
16
+ console.error('[PERPLEXITY DEBUG] API Key present:', !!apiKey);
17
+ if (apiKey) {
18
+ console.error('[PERPLEXITY DEBUG] Key length:', apiKey.length);
19
+ console.error('[PERPLEXITY DEBUG] Key prefix:', apiKey.substring(0, 8) + '...');
20
+ }
21
+ else {
22
+ console.error('[PERPLEXITY DEBUG] process.env keys:', Object.keys(process.env).filter(k => k.includes('PERP') || k.includes('API')));
23
+ }
24
+ }
25
+ // Available Perplexity models (2025 latest)
26
+ export var PerplexityModel;
27
+ (function (PerplexityModel) {
28
+ // Models from Perplexity API docs
29
+ PerplexityModel["SONAR_PRO"] = "sonar";
30
+ PerplexityModel["SONAR_REASONING_PRO"] = "sonar-reasoning";
31
+ PerplexityModel["SONAR_DEEP_RESEARCH"] = "sonar-deep-research";
32
+ PerplexityModel["SONAR"] = "sonar";
33
+ PerplexityModel["SONAR_SMALL"] = "sonar-small";
34
+ })(PerplexityModel || (PerplexityModel = {}));
35
+ /**
36
+ * Call Perplexity API
37
+ */
38
+ export async function callPerplexity(messages, model = PerplexityModel.SONAR_PRO, searchDomain, searchRecency) {
39
+ const apiKey = getPerplexityApiKey();
40
+ if (!apiKey) {
41
+ debugApiKey(); // Log debug info when key is missing
42
+ return `[Perplexity API key not configured. Add PERPLEXITY_API_KEY to .env file]`;
43
+ }
44
+ try {
45
+ const url = `${PERPLEXITY_API_URL}/chat/completions`;
46
+ const requestBody = {
47
+ model,
48
+ messages,
49
+ temperature: 0.2,
50
+ max_tokens: 16384, // Increased for comprehensive research responses
51
+ return_citations: true,
52
+ return_images: false
53
+ };
54
+ // Add search filters if provided
55
+ if (searchDomain) {
56
+ requestBody.search_domain = searchDomain;
57
+ }
58
+ if (searchRecency) {
59
+ requestBody.search_recency = searchRecency;
60
+ }
61
+ const response = await fetch(url, {
62
+ method: "POST",
63
+ headers: {
64
+ "Authorization": `Bearer ${apiKey}`,
65
+ "Content-Type": "application/json"
66
+ },
67
+ body: JSON.stringify(requestBody)
68
+ });
69
+ if (!response.ok) {
70
+ throw new Error(`Perplexity API error: ${response.statusText}`);
71
+ }
72
+ const data = await response.json();
73
+ // Extract the response and citations
74
+ let result = data.choices?.[0]?.message?.content || "No response from Perplexity";
75
+ // Add sources if available (Perplexity API changed from citations to search_results in 2025)
76
+ if (data.search_results && data.search_results.length > 0) {
77
+ result += "\n\n**Sources:**\n";
78
+ data.search_results.forEach((source, idx) => {
79
+ result += `${idx + 1}. ${source.title || 'Untitled'} - ${source.url}`;
80
+ if (source.date)
81
+ result += ` (${source.date})`;
82
+ result += '\n';
83
+ });
84
+ }
85
+ return result;
86
+ }
87
+ catch (error) {
88
+ return `[Perplexity error: ${error instanceof Error ? error.message : String(error)}]`;
89
+ }
90
+ }
91
+ /**
92
+ * Perplexity Ask Tool
93
+ * Search the web and retrieve up-to-date information
94
+ */
95
+ export const perplexityAskTool = {
96
+ name: "perplexity_ask",
97
+ description: "Web search",
98
+ parameters: z.object({
99
+ query: z.string(),
100
+ searchDomain: z.enum(["general", "academic", "news", "social"]).optional(),
101
+ searchRecency: z.enum(["hour", "day", "week", "month", "year"]).optional()
102
+ }),
103
+ execute: async (args, { log }) => {
104
+ const messages = [
105
+ {
106
+ role: "system",
107
+ content: "You are a helpful research assistant. Provide accurate, up-to-date information with sources."
108
+ },
109
+ {
110
+ role: "user",
111
+ content: args.query
112
+ }
113
+ ];
114
+ return await callPerplexity(messages, PerplexityModel.SONAR_PRO, args.searchDomain, args.searchRecency);
115
+ }
116
+ };
117
+ /**
118
+ * Perplexity Research Tool
119
+ * Deep research with multiple queries and synthesis
120
+ */
121
+ export const perplexityResearchTool = {
122
+ name: "perplexity_research",
123
+ description: "Deep research",
124
+ parameters: z.object({
125
+ topic: z.string(),
126
+ questions: z.array(z.string()).optional(),
127
+ depth: z.enum(["quick", "standard", "deep"]).optional()
128
+ }),
129
+ execute: async (args, { log }) => {
130
+ const { topic, questions, depth = "standard" } = args;
131
+ // Generate research questions if not provided
132
+ const researchQuestions = questions || [
133
+ `What is the current state of ${topic}?`,
134
+ `What are the latest developments in ${topic}?`,
135
+ `What are the key challenges and opportunities in ${topic}?`,
136
+ `What do experts say about ${topic}?`
137
+ ];
138
+ // Adjust based on depth
139
+ const questionsToAsk = depth === "quick" ?
140
+ researchQuestions.slice(0, 2) :
141
+ depth === "deep" ?
142
+ [...researchQuestions,
143
+ `What are the future predictions for ${topic}?`,
144
+ `What are the best practices and recommendations for ${topic}?`] :
145
+ researchQuestions;
146
+ let research = `# Research Report: ${topic}\n\n`;
147
+ // Conduct research for each question
148
+ for (const question of questionsToAsk) {
149
+ const messages = [
150
+ {
151
+ role: "system",
152
+ content: "You are a research expert. Provide detailed, factual information with sources."
153
+ },
154
+ {
155
+ role: "user",
156
+ content: question
157
+ }
158
+ ];
159
+ const answer = await callPerplexity(messages, PerplexityModel.SONAR_PRO);
160
+ research += `## ${question}\n\n${answer}\n\n`;
161
+ }
162
+ // Add synthesis
163
+ const synthesisMessages = [
164
+ {
165
+ role: "system",
166
+ content: "You are a research synthesizer. Create a concise summary of the key findings."
167
+ },
168
+ {
169
+ role: "user",
170
+ content: `Synthesize these research findings into key insights:\n\n${research}`
171
+ }
172
+ ];
173
+ const synthesis = await callPerplexity(synthesisMessages, PerplexityModel.SONAR_PRO);
174
+ research += `## Synthesis\n\n${synthesis}`;
175
+ return research;
176
+ }
177
+ };
178
+ /**
179
+ * Perplexity Reason Tool
180
+ * Perform complex reasoning tasks
181
+ */
182
+ export const perplexityReasonTool = {
183
+ name: "perplexity_reason",
184
+ description: "Reasoning with search",
185
+ parameters: z.object({
186
+ problem: z.string(),
187
+ context: z.string().optional(),
188
+ approach: z.enum(["analytical", "creative", "systematic", "comparative"]).optional()
189
+ }),
190
+ execute: async (args, { log }) => {
191
+ const { problem, context, approach = "analytical" } = args;
192
+ const approachPrompts = {
193
+ analytical: "Break down the problem systematically and analyze each component",
194
+ creative: "Think outside the box and consider unconventional solutions",
195
+ systematic: "Follow a step-by-step logical process",
196
+ comparative: "Compare different approaches and evaluate trade-offs"
197
+ };
198
+ const messages = [
199
+ {
200
+ role: "system",
201
+ content: `You are an expert reasoning system. ${approachPrompts[approach]}.
202
+ Provide clear, logical reasoning with evidence and examples.
203
+ ${context ? `Context: ${context}` : ''}`
204
+ },
205
+ {
206
+ role: "user",
207
+ content: problem
208
+ }
209
+ ];
210
+ return await callPerplexity(messages, PerplexityModel.SONAR_REASONING_PRO);
211
+ }
212
+ };
213
+ /**
214
+ * Perplexity Fact Check Tool
215
+ * Verify claims with evidence
216
+ */
217
+ export const perplexityFactCheckTool = {
218
+ name: "perplexity_fact_check",
219
+ description: `Fact-check claims`,
220
+ parameters: z.object({
221
+ claim: z.string(),
222
+ context: z.string().optional()
223
+ }),
224
+ execute: async (args, { log }) => {
225
+ const messages = [
226
+ {
227
+ role: "system",
228
+ content: `You are a fact-checking expert. Verify the following claim with evidence.
229
+ Provide:
230
+ 1. Verdict: TRUE, FALSE, PARTIALLY TRUE, or UNVERIFIABLE
231
+ 2. Evidence supporting or refuting the claim
232
+ 3. Sources for verification
233
+ 4. Any important context or nuance
234
+ ${args.context ? `Additional context: ${args.context}` : ''}`
235
+ },
236
+ {
237
+ role: "user",
238
+ content: `Fact-check this claim: "${args.claim}"`
239
+ }
240
+ ];
241
+ return await callPerplexity(messages, PerplexityModel.SONAR_PRO, "general", "month");
242
+ }
243
+ };
244
+ /**
245
+ * Perplexity Code Search Tool
246
+ * Search for code examples and documentation
247
+ */
248
+ export const perplexityCodeSearchTool = {
249
+ name: "perplexity_code_search",
250
+ description: `Code search`,
251
+ parameters: z.object({
252
+ query: z.string(),
253
+ language: z.string().optional(),
254
+ framework: z.string().optional()
255
+ }),
256
+ execute: async (args, { log }) => {
257
+ const searchQuery = `${args.language || ''} ${args.framework || ''} ${args.query} code example implementation`.trim();
258
+ const messages = [
259
+ {
260
+ role: "system",
261
+ content: `You are a programming expert. Find and explain code solutions.
262
+ Focus on:
263
+ 1. Working code examples
264
+ 2. Best practices
265
+ 3. Common pitfalls to avoid
266
+ 4. Links to documentation`
267
+ },
268
+ {
269
+ role: "user",
270
+ content: searchQuery
271
+ }
272
+ ];
273
+ return await callPerplexity(messages, PerplexityModel.SONAR_PRO);
274
+ }
275
+ };
276
+ /**
277
+ * Check if Perplexity is available
278
+ */
279
+ export function isPerplexityAvailable() {
280
+ return !!getPerplexityApiKey();
281
+ }
282
+ export function getAllPerplexityTools() {
283
+ if (!isPerplexityAvailable()) {
284
+ return [];
285
+ }
286
+ // Minimized tool set - keeping only essential Perplexity tools
287
+ return [
288
+ perplexityAskTool, // Web search
289
+ perplexityReasonTool, // Complex reasoning
290
+ perplexityResearchTool,
291
+ // Removed: perplexityFactCheckTool (can use verifier instead)
292
+ // Removed: perplexityCodeSearchTool (can use perplexity_ask)
293
+ ];
294
+ }
@@ -0,0 +1,343 @@
1
+ /**
2
+ * PingPong Tool - Customizable multi-model conversation
3
+ * Supports workflow-like YAML/JSON configuration
4
+ */
5
+ import { z } from "zod";
6
+ import * as yaml from 'yaml';
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+ import { collaborativeOrchestrator } from '../collaborative-orchestrator.js';
10
+ import { TechnicalDomain } from '../reasoning-chain.js';
11
+ // PingPong configuration schema
12
+ const PingPongConfigSchema = z.object({
13
+ name: z.string().optional(),
14
+ description: z.string().optional(),
15
+ settings: z.object({
16
+ rounds: z.number().min(1).default(5), // No hardcoded max - validated against config.maxPingPongRounds
17
+ style: z.enum(['collaborative', 'debate', 'build-upon', 'competitive']).default('collaborative'),
18
+ temperature: z.number().min(0).max(2).default(0.7),
19
+ maxTokensPerRound: z.number().default(2000),
20
+ synthesis_every: z.number().optional(), // Synthesize every N rounds
21
+ save_session: z.boolean().default(true),
22
+ include_cost_analysis: z.boolean().default(true)
23
+ }).optional().default({}),
24
+ models: z.array(z.union([
25
+ z.string(), // Simple model name
26
+ z.object({
27
+ name: z.string(),
28
+ role: z.string().optional(),
29
+ prompt_style: z.string().optional(),
30
+ temperature: z.number().optional(),
31
+ maxTokens: z.number().optional()
32
+ })
33
+ ])).optional(),
34
+ flow: z.object({
35
+ type: z.enum(['sequential', 'parallel', 'conditional']).default('sequential'),
36
+ conditions: z.array(z.object({
37
+ round: z.number(),
38
+ if: z.string(),
39
+ then: z.string(),
40
+ else: z.string().optional()
41
+ })).optional()
42
+ }).optional(),
43
+ prompts: z.object({
44
+ system: z.string().optional(),
45
+ first_round: z.string().optional(),
46
+ subsequent_rounds: z.string().optional(),
47
+ synthesis: z.string().optional()
48
+ }).optional(),
49
+ output: z.object({
50
+ format: z.enum(['summary', 'detailed', 'json', 'structured']).default('structured'),
51
+ save_to_file: z.string().optional(),
52
+ include_metadata: z.boolean().default(true)
53
+ }).optional().default({})
54
+ });
55
+ /**
56
+ * Load configuration from YAML/JSON file or inline object
57
+ */
58
+ async function loadPingPongConfig(config) {
59
+ if (typeof config === 'string') {
60
+ // Check if it's a file path
61
+ if (config.endsWith('.yaml') || config.endsWith('.yml') || config.endsWith('.json')) {
62
+ const configPath = path.resolve(config);
63
+ if (fs.existsSync(configPath)) {
64
+ const content = fs.readFileSync(configPath, 'utf8');
65
+ const parsed = config.endsWith('.json')
66
+ ? JSON.parse(content)
67
+ : yaml.parse(content);
68
+ return PingPongConfigSchema.parse(parsed);
69
+ }
70
+ }
71
+ // Try to parse as inline YAML/JSON
72
+ try {
73
+ const parsed = yaml.parse(config);
74
+ return PingPongConfigSchema.parse(parsed);
75
+ }
76
+ catch {
77
+ try {
78
+ const parsed = JSON.parse(config);
79
+ return PingPongConfigSchema.parse(parsed);
80
+ }
81
+ catch {
82
+ throw new Error('Invalid configuration format. Provide YAML, JSON, or file path.');
83
+ }
84
+ }
85
+ }
86
+ // It's already an object
87
+ return PingPongConfigSchema.parse(config);
88
+ }
89
+ /**
90
+ * Build custom model configuration
91
+ */
92
+ function buildModelConfig(config, overrides) {
93
+ const settings = config.settings || {};
94
+ // Determine models to use
95
+ let models = overrides?.models || [];
96
+ if (models.length === 0 && config.models) {
97
+ models = config.models.map(m => typeof m === 'string' ? m : m.name);
98
+ }
99
+ if (models.length === 0) {
100
+ models = ['grok', 'gemini', 'openai', 'qwen']; // Default models
101
+ }
102
+ return {
103
+ models,
104
+ rounds: overrides?.rounds || settings.rounds || 5,
105
+ style: overrides?.style || settings.style || 'collaborative',
106
+ temperature: settings.temperature || 0.7,
107
+ maxTokensPerRound: settings.maxTokensPerRound || 2000,
108
+ saveSession: settings.save_session !== false,
109
+ includeCostAnalysis: settings.include_cost_analysis !== false,
110
+ synthesisEvery: settings.synthesis_every
111
+ };
112
+ }
113
+ /**
114
+ * Format output based on configuration
115
+ */
116
+ function formatOutput(result, config, metadata) {
117
+ const outputConfig = config.output || {};
118
+ switch (outputConfig.format) {
119
+ case 'json':
120
+ return JSON.stringify({
121
+ result,
122
+ metadata: outputConfig.include_metadata ? metadata : undefined,
123
+ config: config.name ? { name: config.name, description: config.description } : undefined
124
+ }, null, 2);
125
+ case 'summary':
126
+ // Extract just the synthesis/summary section
127
+ const summaryMatch = result.match(/## .*Synthesis.*\n([\s\S]*?)(?=##|$)/);
128
+ return summaryMatch ? summaryMatch[1].trim() : result;
129
+ case 'detailed':
130
+ // Include everything
131
+ return result;
132
+ case 'structured':
133
+ default:
134
+ // Well-formatted markdown with sections
135
+ let structured = `# PingPong Conversation`;
136
+ if (config.name)
137
+ structured += `: ${config.name}`;
138
+ structured += '\n\n';
139
+ if (config.description)
140
+ structured += `*${config.description}*\n\n`;
141
+ structured += result;
142
+ return structured;
143
+ }
144
+ }
145
+ /**
146
+ * PingPong Tool Definition
147
+ */
148
+ export const pingpongTool = {
149
+ name: "pingpong",
150
+ description: "Multi-model conversation",
151
+ parameters: z.object({
152
+ problem: z.string(),
153
+ config: z.union([
154
+ z.string(),
155
+ z.object({
156
+ name: z.string().optional(),
157
+ description: z.string().optional(),
158
+ settings: z.any().optional(),
159
+ models: z.any().optional(),
160
+ flow: z.any().optional(),
161
+ prompts: z.any().optional(),
162
+ output: z.any().optional()
163
+ })
164
+ ]).optional(),
165
+ models: z.array(z.string()).optional(),
166
+ rounds: z.number().min(1).optional(),
167
+ style: z.enum(['collaborative', 'debate', 'build-upon', 'competitive']).optional(),
168
+ domain: z.enum([
169
+ "architecture", "algorithms", "debugging", "security",
170
+ "performance", "api_design", "database", "frontend",
171
+ "backend", "devops", "testing"
172
+ ]).optional(),
173
+ customPrompts: z.record(z.string()).optional(),
174
+ template: z.string().optional()
175
+ }),
176
+ execute: async (args, { log }) => {
177
+ try {
178
+ // Load configuration
179
+ let config;
180
+ if (args.template) {
181
+ // Use predefined template
182
+ config = getPredefinedTemplate(args.template);
183
+ }
184
+ else if (args.config) {
185
+ config = await loadPingPongConfig(args.config);
186
+ }
187
+ else {
188
+ // Default configuration
189
+ config = {
190
+ settings: {
191
+ rounds: 5,
192
+ style: 'collaborative',
193
+ temperature: 0.7,
194
+ maxTokensPerRound: 2000,
195
+ save_session: true,
196
+ include_cost_analysis: true
197
+ },
198
+ output: {
199
+ format: 'structured',
200
+ include_metadata: true
201
+ }
202
+ };
203
+ }
204
+ // Build final configuration with overrides
205
+ const finalConfig = buildModelConfig(config, {
206
+ models: args.models,
207
+ rounds: args.rounds,
208
+ style: args.style
209
+ });
210
+ // Map domain string to TechnicalDomain enum
211
+ const domainMap = {
212
+ 'architecture': TechnicalDomain.ARCHITECTURE,
213
+ 'algorithms': TechnicalDomain.ALGORITHMS,
214
+ 'debugging': TechnicalDomain.DEBUGGING,
215
+ 'security': TechnicalDomain.SECURITY,
216
+ 'performance': TechnicalDomain.PERFORMANCE,
217
+ 'api_design': TechnicalDomain.API_DESIGN,
218
+ 'database': TechnicalDomain.DATABASE,
219
+ 'frontend': TechnicalDomain.FRONTEND,
220
+ 'backend': TechnicalDomain.BACKEND,
221
+ 'devops': TechnicalDomain.DEVOPS,
222
+ 'testing': TechnicalDomain.TESTING
223
+ };
224
+ const domain = domainMap[args.domain || 'architecture'] || TechnicalDomain.ARCHITECTURE;
225
+ log?.info(`Starting PingPong: ${config.name || 'Custom'}, ${finalConfig.rounds} rounds, ${finalConfig.models.length} models`);
226
+ // Execute the pingpong conversation
227
+ const result = await collaborativeOrchestrator.executeAdvancedPingPong({
228
+ problem: args.problem,
229
+ domain: domain,
230
+ rounds: finalConfig.rounds,
231
+ models: finalConfig.models,
232
+ temperature: finalConfig.temperature,
233
+ maxTokensPerRound: finalConfig.maxTokensPerRound,
234
+ style: finalConfig.style,
235
+ saveSession: finalConfig.saveSession
236
+ });
237
+ // Format output
238
+ const formattedResult = formatOutput(result, config, {
239
+ rounds: finalConfig.rounds,
240
+ models: finalConfig.models,
241
+ style: finalConfig.style,
242
+ timestamp: new Date().toISOString()
243
+ });
244
+ // Save to file if configured
245
+ if (config.output?.save_to_file) {
246
+ const outputPath = path.resolve(config.output.save_to_file);
247
+ fs.writeFileSync(outputPath, formattedResult, 'utf8');
248
+ log?.info(`PingPong result saved to: ${outputPath}`);
249
+ }
250
+ return formattedResult;
251
+ }
252
+ catch (error) {
253
+ const errorMessage = error instanceof Error ? error.message : String(error);
254
+ log?.error('PingPong execution failed:', errorMessage);
255
+ return `PingPong Error: ${errorMessage}`;
256
+ }
257
+ }
258
+ };
259
+ /**
260
+ * Get predefined templates
261
+ */
262
+ function getPredefinedTemplate(template) {
263
+ const templates = {
264
+ debate: {
265
+ name: 'Technical Debate',
266
+ description: 'Models debate different approaches',
267
+ settings: {
268
+ rounds: 6,
269
+ style: 'debate',
270
+ temperature: 0.8,
271
+ maxTokensPerRound: 2000,
272
+ save_session: true,
273
+ include_cost_analysis: true
274
+ },
275
+ models: [
276
+ { name: 'grok', role: 'challenger', prompt_style: 'Challenge assumptions aggressively' },
277
+ { name: 'openai', role: 'defender', prompt_style: 'Defend conventional wisdom' },
278
+ { name: 'gemini', role: 'mediator', prompt_style: 'Find middle ground' }
279
+ ],
280
+ output: { format: 'structured', include_metadata: true }
281
+ },
282
+ brainstorm: {
283
+ name: 'Creative Brainstorm',
284
+ description: 'Collaborative idea generation',
285
+ settings: {
286
+ rounds: 8,
287
+ style: 'build-upon',
288
+ temperature: 0.9,
289
+ maxTokensPerRound: 1500,
290
+ synthesis_every: 3,
291
+ save_session: true,
292
+ include_cost_analysis: false
293
+ },
294
+ models: [
295
+ { name: 'gemini', role: 'ideator' },
296
+ { name: 'grok', role: 'innovator' },
297
+ { name: 'qwen', role: 'implementer' },
298
+ { name: 'openai', role: 'synthesizer' }
299
+ ],
300
+ output: { format: 'structured', include_metadata: false }
301
+ },
302
+ review: {
303
+ name: 'Architecture Review',
304
+ description: 'Multi-perspective code/architecture review',
305
+ settings: {
306
+ rounds: 4,
307
+ style: 'collaborative',
308
+ temperature: 0.6,
309
+ maxTokensPerRound: 2500,
310
+ save_session: true,
311
+ include_cost_analysis: true
312
+ },
313
+ models: [
314
+ { name: 'grok', role: 'security reviewer' },
315
+ { name: 'openai', role: 'performance analyst' },
316
+ { name: 'gemini', role: 'best practices expert' }
317
+ ],
318
+ output: { format: 'detailed', include_metadata: true }
319
+ },
320
+ design: {
321
+ name: 'System Design',
322
+ description: 'Collaborative system design session',
323
+ settings: {
324
+ rounds: 10,
325
+ style: 'build-upon',
326
+ temperature: 0.7,
327
+ maxTokensPerRound: 3000,
328
+ synthesis_every: 5,
329
+ save_session: true,
330
+ include_cost_analysis: true
331
+ },
332
+ models: ['grok', 'gemini', 'openai', 'qwen'],
333
+ output: { format: 'structured', include_metadata: true }
334
+ }
335
+ };
336
+ return templates[template] || templates.brainstorm;
337
+ }
338
+ /**
339
+ * Check if pingpong tool is available
340
+ */
341
+ export function isPingPongAvailable() {
342
+ return true; // Always available since it uses the collaborative orchestrator
343
+ }