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,270 @@
1
+ /**
2
+ * Scout Helper Functions
3
+ *
4
+ * Pure, composable functions extracted from Scout mode.
5
+ * Used by workflows/system/scout.yaml
6
+ *
7
+ * SOLID Principles:
8
+ * - Single Responsibility: Each function does ONE transformation
9
+ * - Open/Closed: Functions are closed for modification, open for extension
10
+ * - Liskov Substitution: All functions are predictable pure functions
11
+ * - Interface Segregation: Small, focused function signatures
12
+ * - Dependency Inversion: Functions depend on types, not concrete implementations
13
+ */
14
+ // ============================================================================
15
+ // Query Preparation
16
+ // ============================================================================
17
+ /**
18
+ * Prepend current date to query for temporal context
19
+ *
20
+ * @example
21
+ * prepareQuery("What's new in React?", "October 21, 2025")
22
+ * // => "[Current date: October 21, 2025] What's new in React?"
23
+ */
24
+ export const prepareQuery = (query, date) => {
25
+ return `[Current date: ${date}] ${query}`;
26
+ };
27
+ /**
28
+ * Craft targeted probe based on query type detection
29
+ *
30
+ * Identifies question type (latest, technical, comparison) and
31
+ * reformulates query for better search results.
32
+ */
33
+ export const craftTargetedProbe = (query) => {
34
+ const keywords = extractKeywords(query);
35
+ const questionType = identifyQuestionType(query);
36
+ switch (questionType) {
37
+ case 'latest':
38
+ return `Latest information about ${keywords.join(' ')} as of 2025`;
39
+ case 'technical':
40
+ return `Technical documentation and API details for ${keywords.join(' ')}`;
41
+ case 'comparison':
42
+ return `Compare ${keywords.join(' vs ')} with current data`;
43
+ default:
44
+ return query;
45
+ }
46
+ };
47
+ // ============================================================================
48
+ // Fact Extraction & Validation
49
+ // ============================================================================
50
+ /**
51
+ * Extract structured facts from search result text
52
+ *
53
+ * Returns array of fact strings (lines > 20 chars, max 5 facts)
54
+ */
55
+ export const extractFacts = (searchResult) => {
56
+ const lines = searchResult.split('\n');
57
+ const facts = lines
58
+ .filter(line => line.trim().length > 20)
59
+ .slice(0, 5)
60
+ .map(line => line.trim());
61
+ const sources = extractSources(searchResult);
62
+ const reliability = assessReliability(searchResult);
63
+ return {
64
+ facts,
65
+ sources,
66
+ timestamp: new Date().toISOString(),
67
+ reliability
68
+ };
69
+ };
70
+ /**
71
+ * Validate fact quality and reliability
72
+ *
73
+ * Returns true if facts are sufficient for analysis
74
+ */
75
+ export const validateFacts = (facts) => {
76
+ return facts.facts.length > 0 && facts.reliability > 0.5;
77
+ };
78
+ /**
79
+ * Select best facts from quick scan or deep search
80
+ */
81
+ export const selectBestFacts = (quickFacts, deepFacts, valid) => {
82
+ if (valid && quickFacts) {
83
+ return quickFacts;
84
+ }
85
+ return deepFacts;
86
+ };
87
+ /**
88
+ * Verify fact reliability
89
+ */
90
+ export const verifyFacts = (facts) => {
91
+ return {
92
+ verified: true,
93
+ confidence: facts.reliability
94
+ };
95
+ };
96
+ // ============================================================================
97
+ // Context Building
98
+ // ============================================================================
99
+ /**
100
+ * Build context string from facts for model analysis
101
+ */
102
+ export const buildContext = (facts, timestamp) => {
103
+ const ts = timestamp || facts.timestamp;
104
+ const sourceList = facts.sources?.join(', ') || 'Not specified';
105
+ return `Context (${ts}):\n${facts.facts.join('\n')}\n\nSources: ${sourceList}`;
106
+ };
107
+ // ============================================================================
108
+ // Insight Extraction
109
+ // ============================================================================
110
+ /**
111
+ * Extract key insights from model analyses
112
+ *
113
+ * Returns array of AnalysisResult with extracted insights
114
+ */
115
+ export const extractInsights = (analyses) => {
116
+ return analyses.map(({ model, content }) => ({
117
+ model,
118
+ analysis: content,
119
+ insights: extractInsightsFromText(content)
120
+ }));
121
+ };
122
+ /**
123
+ * Extract insight bullet points from text
124
+ */
125
+ const extractInsightsFromText = (text) => {
126
+ const lines = text.split('\n');
127
+ return lines
128
+ .filter(line => line.includes('insight') ||
129
+ line.includes('Key') ||
130
+ line.startsWith('•') ||
131
+ line.startsWith('-'))
132
+ .map(line => line.replace(/^[•\-]\s*/, '').trim())
133
+ .filter(line => line.length > 10)
134
+ .slice(0, 3);
135
+ };
136
+ // ============================================================================
137
+ // Synthesis
138
+ // ============================================================================
139
+ /**
140
+ * Synthesize facts and analyses into readable report
141
+ */
142
+ export const synthesizeScoutReport = (facts, insights) => {
143
+ let synthesis = '';
144
+ // Add facts section
145
+ if (facts && facts.facts.length > 0) {
146
+ synthesis += `Current Information (${facts.timestamp}):\n`;
147
+ facts.facts.slice(0, 3).forEach(fact => {
148
+ synthesis += `• ${fact}\n`;
149
+ });
150
+ synthesis += '\n';
151
+ }
152
+ // Add analysis section
153
+ synthesis += 'Analysis:\n';
154
+ insights.forEach(analysis => {
155
+ synthesis += `${analysis.model}:\n`;
156
+ analysis.insights.slice(0, 2).forEach(insight => {
157
+ synthesis += `• ${insight}\n`;
158
+ });
159
+ });
160
+ return synthesis;
161
+ };
162
+ /**
163
+ * Synthesize waterfall verification results
164
+ */
165
+ export const synthesizeScoutWaterfall = (facts, verification) => {
166
+ return `Verified Information:\n${facts.facts.join('\n')}\n\nReliability: ${facts.reliability}`;
167
+ };
168
+ // ============================================================================
169
+ // Report Formatting
170
+ // ============================================================================
171
+ /**
172
+ * Format final Scout report with metadata
173
+ */
174
+ export const formatScoutReport = (config) => {
175
+ return {
176
+ synthesis: config.synthesis,
177
+ facts: config.facts || undefined,
178
+ analyses_count: config.analyses_count,
179
+ execution_time: config.execution_time,
180
+ warning: config.warning || undefined,
181
+ verification: config.verification
182
+ };
183
+ };
184
+ // ============================================================================
185
+ // Internal Utilities (not exported, used by public functions)
186
+ // ============================================================================
187
+ /**
188
+ * Extract keywords from query (remove stop words)
189
+ */
190
+ const extractKeywords = (query) => {
191
+ const words = query.toLowerCase().split(/\s+/);
192
+ const stopWords = ['what', 'how', 'why', 'when', 'where', 'is', 'are', 'the', 'a', 'an'];
193
+ return words.filter(w => !stopWords.includes(w) && w.length > 2);
194
+ };
195
+ /**
196
+ * Identify question type from query text
197
+ */
198
+ const identifyQuestionType = (query) => {
199
+ const lower = query.toLowerCase();
200
+ if (lower.includes('latest') || lower.includes('current') || lower.includes('new')) {
201
+ return 'latest';
202
+ }
203
+ if (lower.includes('api') || lower.includes('function') || lower.includes('method')) {
204
+ return 'technical';
205
+ }
206
+ if (lower.includes('vs') || lower.includes('compare') || lower.includes('difference')) {
207
+ return 'comparison';
208
+ }
209
+ return 'general';
210
+ };
211
+ /**
212
+ * Extract source citations from text
213
+ */
214
+ const extractSources = (text) => {
215
+ const sourcePattern = /\[(\d+)\]\s*([^\n]+)/g;
216
+ const sources = [];
217
+ let match;
218
+ while ((match = sourcePattern.exec(text)) !== null) {
219
+ sources.push(match[2]);
220
+ }
221
+ return sources;
222
+ };
223
+ /**
224
+ * Assess reliability score based on content indicators
225
+ *
226
+ * Scoring:
227
+ * - Base: 0.5
228
+ * - Has sources/citations: +0.2
229
+ * - Has recent dates (2024/2025): +0.1
230
+ * - Has verification keywords: +0.1
231
+ * - Lengthy content (> 500 chars): +0.1
232
+ * - Max: 1.0
233
+ */
234
+ const assessReliability = (text) => {
235
+ let score = 0.5;
236
+ if (text.includes('source') || text.includes('['))
237
+ score += 0.2;
238
+ if (text.includes('2025') || text.includes('2024'))
239
+ score += 0.1;
240
+ if (text.includes('verified') || text.includes('confirmed'))
241
+ score += 0.1;
242
+ if (text.length > 500)
243
+ score += 0.1;
244
+ return Math.min(score, 1.0);
245
+ };
246
+ // ============================================================================
247
+ // Type Guards
248
+ // ============================================================================
249
+ /**
250
+ * Check if value is a valid FactResult
251
+ */
252
+ export const isFactResult = (value) => {
253
+ if (!value || typeof value !== 'object')
254
+ return false;
255
+ const obj = value;
256
+ return (Array.isArray(obj.facts) &&
257
+ typeof obj.timestamp === 'string' &&
258
+ typeof obj.reliability === 'number');
259
+ };
260
+ /**
261
+ * Check if value is a valid AnalysisResult
262
+ */
263
+ export const isAnalysisResult = (value) => {
264
+ if (!value || typeof value !== 'object')
265
+ return false;
266
+ const obj = value;
267
+ return (typeof obj.model === 'string' &&
268
+ typeof obj.analysis === 'string' &&
269
+ Array.isArray(obj.insights));
270
+ };
@@ -0,0 +1,332 @@
1
+ /**
2
+ * Verifier Helper Functions
3
+ *
4
+ * Pure, composable functions for multi-model verification and consensus analysis.
5
+ * Used by workflows/system/verifier.yaml
6
+ *
7
+ * SOLID Principles:
8
+ * - Single Responsibility: Each function does ONE transformation
9
+ * - Open/Closed: Functions are closed for modification, open for extension
10
+ * - Liskov Substitution: All functions are predictable pure functions
11
+ * - Interface Segregation: Small, focused function signatures
12
+ * - Dependency Inversion: Functions depend on types, not concrete implementations
13
+ */
14
+ // ============================================================================
15
+ // Prompt Building
16
+ // ============================================================================
17
+ /**
18
+ * Build verification prompt with optional source requirements
19
+ */
20
+ export const buildPrompt = (config) => {
21
+ const basePrompt = `Analyze the following query/statement critically and provide your assessment.
22
+
23
+ Query: ${config.query}
24
+
25
+ Please provide:
26
+ 1. Your conclusion (true/false/uncertain/needs-context)
27
+ 2. Key reasoning points
28
+ 3. Confidence level (0-100%)`;
29
+ if (config.include_sources) {
30
+ return basePrompt + `
31
+ 4. Supporting evidence or sources
32
+ 5. Any contradicting information found`;
33
+ }
34
+ return basePrompt;
35
+ };
36
+ // ============================================================================
37
+ // Response Extraction
38
+ // ============================================================================
39
+ /**
40
+ * Extract structured data from raw model responses
41
+ */
42
+ export const extractModelResponses = (config) => {
43
+ return config.raw_responses.map((response, index) => ({
44
+ model: config.models[index] || response.model,
45
+ response: response.content,
46
+ conclusion: extractConclusion(response.content),
47
+ evidence: config.include_sources ? extractEvidence(response.content) : undefined,
48
+ confidence: extractConfidence(response.content),
49
+ tokens: estimateTokens(response.content)
50
+ }));
51
+ };
52
+ /**
53
+ * Extract conclusion from response text
54
+ *
55
+ * Patterns checked (in order):
56
+ * 1. "conclusion: ..." / "answer: ..." / "verdict: ..." / "result: ..."
57
+ * 2. Keywords: "true", "false", "uncertain"
58
+ * 3. Default: "unknown"
59
+ */
60
+ export const extractConclusion = (content) => {
61
+ const patterns = [
62
+ /conclusion:\s*([^\n]+)/i,
63
+ /answer:\s*([^\n]+)/i,
64
+ /verdict:\s*([^\n]+)/i,
65
+ /result:\s*([^\n]+)/i
66
+ ];
67
+ for (const pattern of patterns) {
68
+ const match = content.match(pattern);
69
+ if (match) {
70
+ return match[1].trim().toLowerCase();
71
+ }
72
+ }
73
+ // Fallback keyword detection
74
+ const lower = content.toLowerCase();
75
+ if (lower.includes('true'))
76
+ return 'true';
77
+ if (lower.includes('false'))
78
+ return 'false';
79
+ if (lower.includes('uncertain'))
80
+ return 'uncertain';
81
+ return 'unknown';
82
+ };
83
+ /**
84
+ * Extract evidence/sources from response text
85
+ */
86
+ export const extractEvidence = (content) => {
87
+ const evidence = [];
88
+ const patterns = [
89
+ /evidence:\s*([^\n]+)/gi,
90
+ /source:\s*([^\n]+)/gi,
91
+ /citation:\s*([^\n]+)/gi,
92
+ /\[(\d+)\]\s*([^\n]+)/g
93
+ ];
94
+ for (const pattern of patterns) {
95
+ const matches = content.matchAll(pattern);
96
+ for (const match of matches) {
97
+ evidence.push(match[1] || match[2]);
98
+ }
99
+ }
100
+ return evidence;
101
+ };
102
+ /**
103
+ * Extract confidence score from response text
104
+ *
105
+ * Patterns checked:
106
+ * - "confidence: 80%" / "certainty: 80%"
107
+ * - "80% confident"
108
+ * - Default: 0.5 (50%)
109
+ */
110
+ export const extractConfidence = (content) => {
111
+ const patterns = [
112
+ /confidence:\s*(\d+)%?/i,
113
+ /certainty:\s*(\d+)%?/i,
114
+ /(\d+)%\s*confident/i
115
+ ];
116
+ for (const pattern of patterns) {
117
+ const match = content.match(pattern);
118
+ if (match) {
119
+ return parseInt(match[1]) / 100;
120
+ }
121
+ }
122
+ return 0.5; // Default 50% confidence
123
+ };
124
+ // ============================================================================
125
+ // Consensus Analysis
126
+ // ============================================================================
127
+ /**
128
+ * Calculate consensus by clustering responses by conclusion
129
+ *
130
+ * Returns:
131
+ * - agreement: ratio of models in majority cluster
132
+ * - clusters: Map of conclusion → responses
133
+ * - majorityCluster: conclusion with most models
134
+ * - outlierModels: models not in majority cluster
135
+ */
136
+ export const calculateConsensus = (config) => {
137
+ const clusters = new Map();
138
+ // Cluster responses by conclusion
139
+ for (const response of config.responses) {
140
+ const conclusion = response.conclusion || 'unknown';
141
+ if (!clusters.has(conclusion)) {
142
+ clusters.set(conclusion, []);
143
+ }
144
+ clusters.get(conclusion).push(response);
145
+ }
146
+ // Find majority cluster
147
+ const sortedClusters = Array.from(clusters.entries())
148
+ .sort((a, b) => b[1].length - a[1].length);
149
+ const majorityCluster = sortedClusters[0][0];
150
+ const majorityCount = sortedClusters[0][1].length;
151
+ const agreement = majorityCount / config.responses.length;
152
+ // Identify outliers (models not in majority cluster)
153
+ const outlierModels = sortedClusters
154
+ .slice(1)
155
+ .flatMap(([_, responses]) => responses.map(r => r.model));
156
+ return {
157
+ agreement,
158
+ clusters: new Map(clusters), // Convert to readonly
159
+ majorityCluster,
160
+ outlierModels
161
+ };
162
+ };
163
+ /**
164
+ * Find outlier responses (dissenting views)
165
+ */
166
+ export const findOutliers = (config) => {
167
+ return config.responses.filter(r => config.consensus.outlierModels.includes(r.model));
168
+ };
169
+ /**
170
+ * Calculate overall confidence score
171
+ *
172
+ * Weighted formula:
173
+ * - 50% weight: consensus agreement
174
+ * - 30% weight: average model confidence
175
+ * - 20% weight: number of responses (more models = higher confidence)
176
+ */
177
+ export const calculateConfidence = (config) => {
178
+ const agreementScore = config.consensus.agreement;
179
+ const avgModelConfidence = config.responses
180
+ .map(r => r.confidence || 0.5)
181
+ .reduce((a, b) => a + b, 0) / config.responses.length;
182
+ const responseCount = config.responses.length;
183
+ const responseScore = Math.min(responseCount / 5, 1); // Max at 5 models
184
+ return (agreementScore * 0.5 + avgModelConfidence * 0.3 + responseScore * 0.2);
185
+ };
186
+ // ============================================================================
187
+ // Synthesis
188
+ // ============================================================================
189
+ /**
190
+ * Generate beautiful verification report with table
191
+ */
192
+ export const synthesizeVerifierReport = (config) => {
193
+ const majorityResponses = config.consensus.clusters.get(config.consensus.majorityCluster) || [];
194
+ const outlierCount = config.responses.length - majorityResponses.length;
195
+ const consensusPercent = (config.consensus.agreement * 100).toFixed(1);
196
+ let synthesis = `## 🔍 Multi-Model Verification Report\n\n`;
197
+ // Consensus indicator
198
+ synthesis += `### 📊 Consensus: ${consensusPercent}%\n\n`;
199
+ const consensusBar = Math.round(config.consensus.agreement * 10);
200
+ synthesis += `\`\`\`\n`;
201
+ synthesis += `[${'█'.repeat(consensusBar)}${'░'.repeat(10 - consensusBar)}] ${consensusPercent}% agreement\n`;
202
+ synthesis += `\`\`\`\n\n`;
203
+ // Model responses table
204
+ synthesis += `### 🤖 Model Responses\n\n`;
205
+ synthesis += buildResponseTable(config.responses, majorityResponses);
206
+ // Majority analysis
207
+ synthesis += `### 🎯 Majority View\n\n`;
208
+ synthesis += `**Conclusion:** ${config.consensus.majorityCluster}\n`;
209
+ synthesis += `**Models in agreement:** ${majorityResponses.length}/${config.responses.length}\n\n`;
210
+ if (majorityResponses.length > 0) {
211
+ synthesis += `**Key reasoning points:**\n`;
212
+ const points = extractKeyPoints(majorityResponses);
213
+ if (points.length > 0) {
214
+ points.forEach(point => synthesis += `- ${point}\n`);
215
+ }
216
+ else {
217
+ // Fallback: show first sentence from each response
218
+ majorityResponses.slice(0, 3).forEach(resp => {
219
+ const firstSentence = resp.response.split(/[.!?]/)[0];
220
+ if (firstSentence && firstSentence.length > 10) {
221
+ synthesis += `- ${firstSentence.trim()}.\n`;
222
+ }
223
+ });
224
+ }
225
+ synthesis += `\n`;
226
+ }
227
+ // Dissenting views
228
+ if (outlierCount > 0) {
229
+ synthesis += `### ⚠️ Dissenting Views (${outlierCount})\n\n`;
230
+ config.outliers.forEach(outlier => {
231
+ synthesis += `**${outlier.model}:** "${outlier.conclusion || 'unknown'}"\n`;
232
+ const preview = (outlier.response || '').substring(0, 150).replace(/\n/g, ' ');
233
+ if (preview) {
234
+ synthesis += `> ${preview}${outlier.response.length > 150 ? '...' : ''}\n\n`;
235
+ }
236
+ });
237
+ }
238
+ // Summary
239
+ synthesis += `### 📋 Summary\n\n`;
240
+ synthesis += `\`\`\`\n`;
241
+ synthesis += `Total Models: ${config.responses.length}\n`;
242
+ synthesis += `Consensus: ${consensusPercent}%\n`;
243
+ synthesis += `Majority View: ${config.consensus.majorityCluster}\n`;
244
+ synthesis += `Agreeing Models: ${majorityResponses.length}\n`;
245
+ synthesis += `Dissenting: ${outlierCount}\n`;
246
+ synthesis += `High Confidence: ${config.consensus.agreement >= 0.8 ? 'YES ✓' : 'NO'}\n`;
247
+ synthesis += `\`\`\`\n`;
248
+ return synthesis;
249
+ };
250
+ /**
251
+ * Format final verification result
252
+ */
253
+ export const formatVerifierResult = (config) => {
254
+ return {
255
+ consensus: config.consensus,
256
+ majority: config.majority,
257
+ outliers: config.outliers,
258
+ responses: config.responses,
259
+ synthesis: config.synthesis,
260
+ confidence: config.confidence,
261
+ shouldTerminate: config.should_terminate
262
+ };
263
+ };
264
+ // ============================================================================
265
+ // Internal Utilities
266
+ // ============================================================================
267
+ /**
268
+ * Build response table with status icons
269
+ */
270
+ const buildResponseTable = (responses, majorityResponses) => {
271
+ // Simple table format (without TableBuilder dependency)
272
+ let table = '| Status | Model | Conclusion | Confidence | Preview |\n';
273
+ table += '|:------:|:------|:----------:|-----------:|:--------|\n';
274
+ responses.forEach((resp) => {
275
+ const isMajority = majorityResponses.includes(resp);
276
+ const statusIcon = isMajority ? '✅' : '⚠️';
277
+ const conclusionIcon = resp.conclusion === 'true' ? '✓' :
278
+ resp.conclusion === 'false' ? '✗' :
279
+ resp.conclusion === 'uncertain' ? '❓' : '❔';
280
+ const confidence = resp.confidence ? `${Math.round(resp.confidence * 100)}%` : 'N/A';
281
+ const preview = (resp.response || '').substring(0, 60).replace(/\n/g, ' ').trim();
282
+ const previewText = preview ? `${preview}...` : 'No response';
283
+ table += `| ${statusIcon} | ${resp.model} | ${conclusionIcon} ${resp.conclusion || 'unknown'} | ${confidence} | ${previewText} |\n`;
284
+ });
285
+ table += '\n';
286
+ return table;
287
+ };
288
+ /**
289
+ * Extract key reasoning points from responses
290
+ */
291
+ const extractKeyPoints = (responses) => {
292
+ const points = new Set();
293
+ for (const response of responses) {
294
+ const content = response.response || '';
295
+ const lines = content.split('\n')
296
+ .filter((line) => line.trim().startsWith('-') || line.trim().startsWith('•'))
297
+ .map((line) => line.replace(/^[-•]\s*/, '').trim())
298
+ .filter((line) => line.length > 10 && line.length < 200);
299
+ lines.forEach((line) => points.add(line));
300
+ }
301
+ return Array.from(points).slice(0, 5);
302
+ };
303
+ /**
304
+ * Estimate tokens from text length
305
+ */
306
+ const estimateTokens = (text) => {
307
+ return Math.floor(text.length / 4);
308
+ };
309
+ // ============================================================================
310
+ // Type Guards
311
+ // ============================================================================
312
+ /**
313
+ * Check if value is a valid ModelResponse
314
+ */
315
+ export const isModelResponse = (value) => {
316
+ if (!value || typeof value !== 'object')
317
+ return false;
318
+ const obj = value;
319
+ return (typeof obj.model === 'string' &&
320
+ typeof obj.response === 'string');
321
+ };
322
+ /**
323
+ * Check if value is a valid ConsensusAnalysis
324
+ */
325
+ export const isConsensusAnalysis = (value) => {
326
+ if (!value || typeof value !== 'object')
327
+ return false;
328
+ const obj = value;
329
+ return (typeof obj.agreement === 'number' &&
330
+ typeof obj.majorityCluster === 'string' &&
331
+ Array.isArray(obj.outlierModels));
332
+ };