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,378 @@
1
+ import { ModelRouter } from '../workflows/model-router.js';
2
+ import { getVerifierModels } from '../config/model-defaults.js';
3
+ import { createMultiModelReporter } from '../utils/progress-stream.js';
4
+ import { TableBuilder } from '../utils/table-builder.js';
5
+ import { smartAPIClient } from '../utils/smart-api-client.js';
6
+ import { getSmartTimeout } from '../config/timeout-config.js';
7
+ export class Verifier {
8
+ constructor() {
9
+ this.modelRouter = new ModelRouter();
10
+ // Load model configurations
11
+ const verifierModels = getVerifierModels();
12
+ this.variants = {
13
+ 'quick_verify': {
14
+ models: verifierModels.quick,
15
+ maxTokens: 2000,
16
+ timeout: 10000
17
+ },
18
+ 'deep_verify': {
19
+ models: verifierModels.deep,
20
+ maxTokens: 6000,
21
+ timeout: 30000
22
+ },
23
+ 'fact_check': {
24
+ models: verifierModels.standard,
25
+ maxTokens: 3000,
26
+ timeout: 15000,
27
+ includeSources: true
28
+ },
29
+ 'code_verify': {
30
+ models: verifierModels.standard,
31
+ maxTokens: 4000,
32
+ timeout: 20000
33
+ },
34
+ 'security_verify': {
35
+ models: verifierModels.standard,
36
+ maxTokens: 4000,
37
+ timeout: 20000
38
+ }
39
+ };
40
+ }
41
+ async verify(query, options = {}) {
42
+ const variant = this.getVariant(options.variant || 'quick_verify');
43
+ const models = options.model ?
44
+ (Array.isArray(options.model) ? options.model : [options.model]) :
45
+ variant.models;
46
+ const maxTokens = options.maxTokens || variant.maxTokens;
47
+ const timeout = options.timeout || variant.timeout;
48
+ // Create progress reporter
49
+ const reporter = createMultiModelReporter(models, `Verifier (${options.variant || 'quick_verify'})`);
50
+ const responses = await this.gatherResponses(query, models, maxTokens, timeout, options.includeSources || variant.includeSources, reporter);
51
+ const consensus = this.calculateTrueConsensus(responses);
52
+ const synthesis = await this.synthesizeVerified(responses, consensus);
53
+ // Complete progress reporting
54
+ reporter.complete(`Verification complete: ${(consensus.agreement * 100).toFixed(0)}% consensus`);
55
+ return {
56
+ consensus: consensus.agreement,
57
+ majority: consensus.majorityCluster,
58
+ outliers: consensus.outlierModels.map(m => responses.find(r => r.model === m)).filter(Boolean),
59
+ responses,
60
+ synthesis,
61
+ confidence: this.calculateConfidence(consensus, responses),
62
+ shouldTerminate: consensus.agreement >= 0.8
63
+ };
64
+ }
65
+ async gatherResponses(query, models, maxTokens, timeout, includeSources, reporter) {
66
+ // Determine priority based on timeout (lower timeout = interactive)
67
+ const priority = timeout <= 15000 ? 'interactive' : 'batch';
68
+ const responsePromises = models.map(async (model) => {
69
+ if (reporter) {
70
+ reporter.modelStarted(model);
71
+ }
72
+ try {
73
+ // Determine provider from model name
74
+ const provider = this.getProviderFromModel(model);
75
+ const timeoutConfig = getSmartTimeout(provider, priority);
76
+ // Use SmartAPIClient with retry logic
77
+ const result = await smartAPIClient.callWithRetries(() => this.queryModel(model, query, maxTokens, includeSources), {
78
+ provider,
79
+ priority,
80
+ baseTimeoutMs: timeoutConfig.base,
81
+ maxTimeoutMs: timeoutConfig.max,
82
+ maxRetries: timeoutConfig.retries
83
+ });
84
+ if (reporter) {
85
+ reporter.modelCompleted(model, result.response?.substring(0, 200) || 'No response');
86
+ }
87
+ return { status: 'fulfilled', value: result };
88
+ }
89
+ catch (error) {
90
+ if (reporter) {
91
+ reporter.modelFailed(model, error instanceof Error ? error.message : String(error));
92
+ }
93
+ return { status: 'rejected', reason: error };
94
+ }
95
+ });
96
+ const responses = await Promise.all(responsePromises);
97
+ return responses
98
+ .filter((r) => r.status === 'fulfilled')
99
+ .map(r => r.value);
100
+ }
101
+ /**
102
+ * Determine provider name from model identifier
103
+ */
104
+ getProviderFromModel(model) {
105
+ const lowerModel = model.toLowerCase();
106
+ if (lowerModel.includes('gpt') || lowerModel.includes('openai'))
107
+ return 'openai';
108
+ if (lowerModel.includes('claude') || lowerModel.includes('anthropic'))
109
+ return 'anthropic';
110
+ if (lowerModel.includes('gemini') || lowerModel.includes('google'))
111
+ return 'google';
112
+ if (lowerModel.includes('grok'))
113
+ return 'grok';
114
+ if (lowerModel.includes('sonar') || lowerModel.includes('perplexity'))
115
+ return 'perplexity';
116
+ return 'openai'; // Default fallback
117
+ }
118
+ async queryModel(model, query, maxTokens, includeSources) {
119
+ const prompt = this.buildVerificationPrompt(query, includeSources);
120
+ try {
121
+ const response = await this.executeModelQuery(model, prompt, maxTokens);
122
+ return {
123
+ model,
124
+ response: response.content,
125
+ conclusion: this.extractConclusion(response.content),
126
+ evidence: includeSources ? this.extractEvidence(response.content) : undefined,
127
+ confidence: this.extractConfidence(response.content),
128
+ tokens: response.tokens
129
+ };
130
+ }
131
+ catch (error) {
132
+ console.error(`Error querying ${model}:`, error);
133
+ throw error;
134
+ }
135
+ }
136
+ buildVerificationPrompt(query, includeSources) {
137
+ const basePrompt = `Analyze the following query/statement critically and provide your assessment.
138
+
139
+ Query: ${query}
140
+
141
+ Please provide:
142
+ 1. Your conclusion (true/false/uncertain/needs-context)
143
+ 2. Key reasoning points
144
+ 3. Confidence level (0-100%)`;
145
+ if (includeSources) {
146
+ return basePrompt + `
147
+ 4. Supporting evidence or sources
148
+ 5. Any contradicting information found`;
149
+ }
150
+ return basePrompt;
151
+ }
152
+ async executeModelQuery(model, prompt, maxTokens) {
153
+ try {
154
+ const { modelRouter } = await import('../utils/model-router.js');
155
+ const response = await modelRouter.callModel({
156
+ model,
157
+ prompt,
158
+ maxTokens,
159
+ temperature: 0.7
160
+ });
161
+ return {
162
+ content: response.content,
163
+ tokens: response.tokens || Math.floor(response.content.length / 4)
164
+ };
165
+ }
166
+ catch (error) {
167
+ console.error(`Error querying ${model}:`, error);
168
+ throw new Error(`Failed to query ${model}: ${error.message}`);
169
+ }
170
+ }
171
+ calculateTrueConsensus(responses) {
172
+ const clusters = new Map();
173
+ for (const response of responses) {
174
+ const conclusion = response.conclusion || 'unknown';
175
+ if (!clusters.has(conclusion)) {
176
+ clusters.set(conclusion, []);
177
+ }
178
+ clusters.get(conclusion).push(response);
179
+ }
180
+ const sortedClusters = Array.from(clusters.entries())
181
+ .sort((a, b) => b[1].length - a[1].length);
182
+ const majorityCluster = sortedClusters[0][0];
183
+ const majorityCount = sortedClusters[0][1].length;
184
+ const agreement = majorityCount / responses.length;
185
+ const outlierModels = sortedClusters
186
+ .slice(1)
187
+ .flatMap(([_, responses]) => responses.map(r => r.model));
188
+ return {
189
+ agreement,
190
+ clusters,
191
+ majorityCluster,
192
+ outlierModels
193
+ };
194
+ }
195
+ findOutliers(responses) {
196
+ const consensus = this.calculateTrueConsensus(responses);
197
+ return responses.filter(r => consensus.outlierModels.includes(r.model));
198
+ }
199
+ async synthesizeVerified(responses, consensus) {
200
+ const majorityResponses = consensus.clusters.get(consensus.majorityCluster) || [];
201
+ const outlierCount = responses.length - majorityResponses.length;
202
+ const consensusPercent = (consensus.agreement * 100).toFixed(1);
203
+ let synthesis = `## 🔍 Multi-Model Verification Report\n\n`;
204
+ // Consensus indicator
205
+ synthesis += `### 📊 Consensus: ${consensusPercent}%\n\n`;
206
+ const consensusBar = Math.round(consensus.agreement * 10);
207
+ synthesis += `\`\`\`\n`;
208
+ synthesis += `[${'█'.repeat(consensusBar)}${'░'.repeat(10 - consensusBar)}] ${consensusPercent}% agreement\n`;
209
+ synthesis += `\`\`\`\n\n`;
210
+ // Show all model responses in a beautiful table
211
+ synthesis += `### 🤖 Model Responses\n`;
212
+ const tableBuilder = new TableBuilder()
213
+ .withHeaders(['Status', 'Model', 'Conclusion', 'Confidence', 'Preview'])
214
+ .withAlignments(['center', 'left', 'center', 'right', 'left']);
215
+ responses.forEach((resp) => {
216
+ const isMajority = majorityResponses.includes(resp);
217
+ const statusIcon = isMajority ? '✅' : '⚠️';
218
+ const conclusionIcon = resp.conclusion === 'true' ? '✓' :
219
+ resp.conclusion === 'false' ? '✗' :
220
+ resp.conclusion === 'uncertain' ? '❓' : '❔';
221
+ const confidence = resp.confidence ? `${Math.round(resp.confidence * 100)}%` : 'N/A';
222
+ // Clean up response preview - remove markdown, newlines, and increase length
223
+ const cleanResponse = (resp.response || '')
224
+ .replace(/\*+/g, '') // Remove asterisks
225
+ .replace(/#+/g, '') // Remove headers
226
+ .replace(/\n/g, ' ') // Replace newlines with spaces
227
+ .replace(/\s+/g, ' ') // Collapse multiple spaces
228
+ .trim();
229
+ const preview = cleanResponse.substring(0, 120); // Increased from 60 to 120
230
+ const previewText = preview ? `${preview}${cleanResponse.length > 120 ? '...' : ''}` : 'No response';
231
+ // Clean conclusion display
232
+ const cleanConclusion = (resp.conclusion || 'unknown').replace(/\*+/g, '').trim();
233
+ tableBuilder.addRow([
234
+ statusIcon,
235
+ resp.model,
236
+ `${conclusionIcon} ${cleanConclusion}`,
237
+ confidence,
238
+ previewText
239
+ ]);
240
+ });
241
+ synthesis += tableBuilder.build();
242
+ synthesis += `\n`;
243
+ // DETAILED MODEL RESPONSES - Full text from each model
244
+ synthesis += `### 📝 Detailed Model Responses\n\n`;
245
+ responses.forEach((resp, index) => {
246
+ const isMajority = majorityResponses.includes(resp);
247
+ const statusBadge = isMajority ? '✅ Majority' : '⚠️ Dissenting';
248
+ synthesis += `#### ${index + 1}. ${resp.model} ${statusBadge}\n\n`;
249
+ synthesis += `**Conclusion:** ${(resp.conclusion || 'unknown').replace(/\*+/g, '').trim()}\n`;
250
+ synthesis += `**Confidence:** ${resp.confidence ? `${Math.round(resp.confidence * 100)}%` : 'N/A'}\n\n`;
251
+ synthesis += `**Analysis:**\n`;
252
+ synthesis += `${resp.response || 'No response provided'}\n\n`;
253
+ synthesis += `---\n\n`;
254
+ });
255
+ // Majority analysis
256
+ synthesis += `### 🎯 Majority View\n\n`;
257
+ // Clean up markdown artifacts from conclusion
258
+ const cleanMajorityConclusion = (consensus.majorityCluster || 'unknown').replace(/\*+/g, '').trim();
259
+ synthesis += `**Conclusion:** ${cleanMajorityConclusion}\n`;
260
+ synthesis += `**Models in agreement:** ${majorityResponses.length}/${responses.length}\n\n`;
261
+ if (majorityResponses.length > 0) {
262
+ synthesis += `**Key reasoning points:**\n`;
263
+ const points = this.extractKeyPoints(majorityResponses);
264
+ if (points.length > 0) {
265
+ points.forEach(point => synthesis += `- ${point}\n`);
266
+ }
267
+ else {
268
+ // If no bullet points found, show first sentence from each majority response
269
+ majorityResponses.slice(0, 3).forEach(resp => {
270
+ const firstSentence = resp.response.split(/[.!?]/)[0];
271
+ if (firstSentence && firstSentence.length > 10) {
272
+ synthesis += `- ${firstSentence.trim()}.\n`;
273
+ }
274
+ });
275
+ }
276
+ synthesis += `\n`;
277
+ }
278
+ // Dissenting views
279
+ if (outlierCount > 0) {
280
+ synthesis += `### ⚠️ Dissenting Views (${outlierCount})\n\n`;
281
+ const outliers = this.findOutliers(responses);
282
+ outliers.forEach(outlier => {
283
+ synthesis += `**${outlier.model}:** "${outlier.conclusion || 'unknown'}"\n`;
284
+ const preview = (outlier.response || '').substring(0, 150).replace(/\n/g, ' ');
285
+ if (preview) {
286
+ synthesis += `> ${preview}${outlier.response.length > 150 ? '...' : ''}\n\n`;
287
+ }
288
+ });
289
+ }
290
+ // Summary
291
+ synthesis += `### 📋 Summary\n\n`;
292
+ synthesis += `\`\`\`\n`;
293
+ synthesis += `Total Models: ${responses.length}\n`;
294
+ synthesis += `Consensus: ${consensusPercent}%\n`;
295
+ synthesis += `Majority View: ${consensus.majorityCluster}\n`;
296
+ synthesis += `Agreeing Models: ${majorityResponses.length}\n`;
297
+ synthesis += `Dissenting: ${outlierCount}\n`;
298
+ synthesis += `High Confidence: ${consensus.agreement >= 0.8 ? 'YES ✓' : 'NO'}\n`;
299
+ synthesis += `\`\`\`\n`;
300
+ return synthesis;
301
+ }
302
+ extractConclusion(content) {
303
+ const patterns = [
304
+ /conclusion:\s*([^\n]+)/i,
305
+ /answer:\s*([^\n]+)/i,
306
+ /verdict:\s*([^\n]+)/i,
307
+ /result:\s*([^\n]+)/i
308
+ ];
309
+ for (const pattern of patterns) {
310
+ const match = content.match(pattern);
311
+ if (match) {
312
+ // Clean up markdown artifacts and extra asterisks
313
+ return match[1].trim().toLowerCase().replace(/\*+/g, '').trim();
314
+ }
315
+ }
316
+ if (content.toLowerCase().includes('true'))
317
+ return 'true';
318
+ if (content.toLowerCase().includes('false'))
319
+ return 'false';
320
+ if (content.toLowerCase().includes('uncertain'))
321
+ return 'uncertain';
322
+ return 'unknown';
323
+ }
324
+ extractEvidence(content) {
325
+ const evidence = [];
326
+ const patterns = [
327
+ /evidence:\s*([^\n]+)/gi,
328
+ /source:\s*([^\n]+)/gi,
329
+ /citation:\s*([^\n]+)/gi,
330
+ /\[(\d+)\]\s*([^\n]+)/g
331
+ ];
332
+ for (const pattern of patterns) {
333
+ const matches = content.matchAll(pattern);
334
+ for (const match of matches) {
335
+ evidence.push(match[1] || match[2]);
336
+ }
337
+ }
338
+ return evidence;
339
+ }
340
+ extractConfidence(content) {
341
+ const patterns = [
342
+ /confidence:\s*(\d+)%?/i,
343
+ /certainty:\s*(\d+)%?/i,
344
+ /(\d+)%\s*confident/i
345
+ ];
346
+ for (const pattern of patterns) {
347
+ const match = content.match(pattern);
348
+ if (match) {
349
+ return parseInt(match[1]) / 100;
350
+ }
351
+ }
352
+ return 0.5;
353
+ }
354
+ extractKeyPoints(responses) {
355
+ const points = new Set();
356
+ for (const response of responses) {
357
+ const content = response.response || '';
358
+ const lines = content.split('\n')
359
+ .filter((line) => line.trim().startsWith('-') || line.trim().startsWith('•'))
360
+ .map((line) => line.replace(/^[-•]\s*/, '').trim())
361
+ .filter((line) => line.length > 10 && line.length < 200);
362
+ lines.forEach((line) => points.add(line));
363
+ }
364
+ return Array.from(points).slice(0, 5);
365
+ }
366
+ calculateConfidence(consensus, responses) {
367
+ const agreementScore = consensus.agreement;
368
+ const avgModelConfidence = responses
369
+ .map(r => r.confidence || 0.5)
370
+ .reduce((a, b) => a + b, 0) / responses.length;
371
+ const responseCount = responses.length;
372
+ const responseScore = Math.min(responseCount / 5, 1);
373
+ return (agreementScore * 0.5 + avgModelConfidence * 0.3 + responseScore * 0.2);
374
+ }
375
+ getVariant(name) {
376
+ return this.variants[name] || this.variants['quick_verify'];
377
+ }
378
+ }