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.
- package/.env.example +260 -0
- package/CHANGELOG.md +54 -0
- package/CODE_OF_CONDUCT.md +56 -0
- package/CONTRIBUTING.md +54 -0
- package/Dockerfile +36 -0
- package/LICENSE +644 -0
- package/README.md +201 -0
- package/SECURITY.md +95 -0
- package/dist/personality/komaai-expressions.js +12 -0
- package/dist/profiles/balanced.json +33 -0
- package/dist/profiles/code_focus.json +33 -0
- package/dist/profiles/full.json +33 -0
- package/dist/profiles/minimal.json +33 -0
- package/dist/profiles/research_power.json +33 -0
- package/dist/scripts/build-profiles.js +46 -0
- package/dist/src/application/services/focus/FocusModeRegistry.js +46 -0
- package/dist/src/application/services/focus/FocusTool.service.js +109 -0
- package/dist/src/application/services/focus/ModeRegistry.js +46 -0
- package/dist/src/application/services/focus/modes/focus-deep.mode.js +27 -0
- package/dist/src/application/services/focus/modes/status.mode.js +50 -0
- package/dist/src/application/services/focus/modes/tachibot-status.mode.js +50 -0
- package/dist/src/collaborative-orchestrator.js +391 -0
- package/dist/src/config/model-constants.js +188 -0
- package/dist/src/config/model-defaults.js +57 -0
- package/dist/src/config/model-preferences.js +382 -0
- package/dist/src/config/timeout-config.js +130 -0
- package/dist/src/config.js +173 -0
- package/dist/src/domain/interfaces/IFocusMode.js +5 -0
- package/dist/src/domain/interfaces/IProvider.js +6 -0
- package/dist/src/domain/interfaces/ITool.js +5 -0
- package/dist/src/focus-deep.js +245 -0
- package/dist/src/infrastructure/ascii/art/robots.ascii.js +16 -0
- package/dist/src/mcp-client.js +90 -0
- package/dist/src/memory/index.js +17 -0
- package/dist/src/memory/memory-config.js +135 -0
- package/dist/src/memory/memory-interface.js +174 -0
- package/dist/src/memory/memory-manager.js +383 -0
- package/dist/src/memory/providers/devlog-provider.js +385 -0
- package/dist/src/memory/providers/hybrid-provider.js +399 -0
- package/dist/src/memory/providers/local-provider.js +388 -0
- package/dist/src/memory/providers/mem0-provider.js +337 -0
- package/dist/src/modes/architect.js +477 -0
- package/dist/src/modes/auditor.js +362 -0
- package/dist/src/modes/challenger.js +841 -0
- package/dist/src/modes/code-reviewer.js +382 -0
- package/dist/src/modes/commit-guardian.js +424 -0
- package/dist/src/modes/documentation-writer.js +572 -0
- package/dist/src/modes/scout.js +587 -0
- package/dist/src/modes/shared/helpers/challenger-helpers.js +454 -0
- package/dist/src/modes/shared/helpers/index.js +17 -0
- package/dist/src/modes/shared/helpers/scout-helpers.js +270 -0
- package/dist/src/modes/shared/helpers/verifier-helpers.js +332 -0
- package/dist/src/modes/test-architect.js +767 -0
- package/dist/src/modes/verifier.js +378 -0
- package/dist/src/monitoring/performance-monitor.js +435 -0
- package/dist/src/optimization/batch-executor.js +121 -0
- package/dist/src/optimization/context-pruner.js +196 -0
- package/dist/src/optimization/cost-monitor.js +338 -0
- package/dist/src/optimization/index.js +65 -0
- package/dist/src/optimization/model-router.js +264 -0
- package/dist/src/optimization/result-cache.js +114 -0
- package/dist/src/optimization/token-optimizer.js +257 -0
- package/dist/src/optimization/token-tracker.js +118 -0
- package/dist/src/orchestrator-instructions.js +128 -0
- package/dist/src/orchestrator-lite.js +139 -0
- package/dist/src/orchestrator.js +191 -0
- package/dist/src/orchestrators/collaborative/interfaces/IToolExecutionEngine.js +1 -0
- package/dist/src/orchestrators/collaborative/interfaces/IToolExecutionStrategy.js +5 -0
- package/dist/src/orchestrators/collaborative/interfaces/IVisualizationRenderer.js +1 -0
- package/dist/src/orchestrators/collaborative/registries/ModelProviderRegistry.js +95 -0
- package/dist/src/orchestrators/collaborative/registries/ToolAdapterRegistry.js +64 -0
- package/dist/src/orchestrators/collaborative/services/tool-execution/ToolExecutionService.js +502 -0
- package/dist/src/orchestrators/collaborative/services/visualization/VisualizationService.js +206 -0
- package/dist/src/orchestrators/collaborative/types/session-types.js +5 -0
- package/dist/src/profiles/balanced.js +37 -0
- package/dist/src/profiles/code_focus.js +37 -0
- package/dist/src/profiles/debug_intensive.js +59 -0
- package/dist/src/profiles/full.js +37 -0
- package/dist/src/profiles/minimal.js +37 -0
- package/dist/src/profiles/research_code.js +59 -0
- package/dist/src/profiles/research_power.js +37 -0
- package/dist/src/profiles/types.js +5 -0
- package/dist/src/profiles/workflow_builder.js +53 -0
- package/dist/src/prompt-engineer-lite.js +78 -0
- package/dist/src/prompt-engineer.js +399 -0
- package/dist/src/reasoning-chain.js +508 -0
- package/dist/src/sequential-thinking.js +291 -0
- package/dist/src/server-diagnostic.js +74 -0
- package/dist/src/server-raw.js +158 -0
- package/dist/src/server-simple.js +58 -0
- package/dist/src/server.js +514 -0
- package/dist/src/session/session-logger.js +617 -0
- package/dist/src/session/session-manager.js +571 -0
- package/dist/src/session/session-tools.js +400 -0
- package/dist/src/tools/advanced-modes.js +200 -0
- package/dist/src/tools/claude-integration.js +356 -0
- package/dist/src/tools/consolidated/ai-router.js +174 -0
- package/dist/src/tools/consolidated/ai-tool.js +48 -0
- package/dist/src/tools/consolidated/brainstorm-tool.js +87 -0
- package/dist/src/tools/consolidated/environment-detector.js +80 -0
- package/dist/src/tools/consolidated/index.js +50 -0
- package/dist/src/tools/consolidated/search-tool.js +110 -0
- package/dist/src/tools/consolidated/workflow-tool.js +238 -0
- package/dist/src/tools/gemini-tools.js +329 -0
- package/dist/src/tools/grok-enhanced.js +376 -0
- package/dist/src/tools/grok-tools.js +299 -0
- package/dist/src/tools/lmstudio-tools.js +223 -0
- package/dist/src/tools/openai-tools.js +498 -0
- package/dist/src/tools/openrouter-tools.js +317 -0
- package/dist/src/tools/optimized-wrapper.js +204 -0
- package/dist/src/tools/perplexity-tools.js +294 -0
- package/dist/src/tools/pingpong-tool.js +343 -0
- package/dist/src/tools/qwen-wrapper.js +74 -0
- package/dist/src/tools/tool-router.js +444 -0
- package/dist/src/tools/unified-ai-provider.js +260 -0
- package/dist/src/tools/workflow-runner.js +425 -0
- package/dist/src/tools/workflow-validator-tool.js +107 -0
- package/dist/src/types.js +23 -0
- package/dist/src/utils/input-validator.js +130 -0
- package/dist/src/utils/model-router.js +91 -0
- package/dist/src/utils/progress-stream.js +255 -0
- package/dist/src/utils/provider-router.js +88 -0
- package/dist/src/utils/smart-api-client.js +146 -0
- package/dist/src/utils/table-builder.js +218 -0
- package/dist/src/utils/timestamp-formatter.js +134 -0
- package/dist/src/utils/tool-compressor.js +257 -0
- package/dist/src/utils/tool-config.js +201 -0
- package/dist/src/validators/dependency-graph-validator.js +147 -0
- package/dist/src/validators/interpolation-validator.js +222 -0
- package/dist/src/validators/output-usage-validator.js +151 -0
- package/dist/src/validators/syntax-validator.js +102 -0
- package/dist/src/validators/tool-registry-validator.js +123 -0
- package/dist/src/validators/tool-types.js +97 -0
- package/dist/src/validators/types.js +8 -0
- package/dist/src/validators/workflow-validator.js +134 -0
- package/dist/src/visualizer-lite.js +42 -0
- package/dist/src/visualizer.js +179 -0
- package/dist/src/workflows/circuit-breaker.js +199 -0
- package/dist/src/workflows/custom-workflows.js +451 -0
- package/dist/src/workflows/engine/AutoSynthesizer.js +97 -0
- package/dist/src/workflows/engine/StepParameterResolver.js +74 -0
- package/dist/src/workflows/engine/VariableInterpolator.js +123 -0
- package/dist/src/workflows/engine/WorkflowDiscovery.js +125 -0
- package/dist/src/workflows/engine/WorkflowExecutionEngine.js +485 -0
- package/dist/src/workflows/engine/WorkflowExecutor.js +113 -0
- package/dist/src/workflows/engine/WorkflowFileManager.js +244 -0
- package/dist/src/workflows/engine/WorkflowHelpers.js +114 -0
- package/dist/src/workflows/engine/WorkflowOutputFormatter.js +83 -0
- package/dist/src/workflows/engine/events/WorkflowEventBus.js +132 -0
- package/dist/src/workflows/engine/events/interfaces/IEventBus.js +5 -0
- package/dist/src/workflows/engine/handlers/ErrorRecoveryHandler.js +162 -0
- package/dist/src/workflows/engine/handlers/PromptEnhancementHandler.js +115 -0
- package/dist/src/workflows/engine/handlers/SessionPersistenceHandler.js +167 -0
- package/dist/src/workflows/engine/handlers/StepExecutionHandler.js +231 -0
- package/dist/src/workflows/engine/handlers/ToolInvocationHandler.js +46 -0
- package/dist/src/workflows/engine/interfaces/IAutoSynthesizer.js +5 -0
- package/dist/src/workflows/engine/interfaces/IStepParameterResolver.js +5 -0
- package/dist/src/workflows/engine/interfaces/IVariableInterpolator.js +5 -0
- package/dist/src/workflows/engine/interfaces/IWorkflowDiscovery.js +4 -0
- package/dist/src/workflows/engine/interfaces/IWorkflowFileManager.js +5 -0
- package/dist/src/workflows/engine/interfaces/IWorkflowOutputFormatter.js +5 -0
- package/dist/src/workflows/engine/state/WorkflowStateMachine.js +194 -0
- package/dist/src/workflows/engine/state/interfaces/IStateMachine.js +17 -0
- package/dist/src/workflows/fallback-strategies.js +373 -0
- package/dist/src/workflows/message-queue.js +455 -0
- package/dist/src/workflows/model-router.js +189 -0
- package/dist/src/workflows/orchestrator-examples.js +174 -0
- package/dist/src/workflows/orchestrator-integration.js +200 -0
- package/dist/src/workflows/self-healing.js +524 -0
- package/dist/src/workflows/tool-mapper.js +407 -0
- package/dist/src/workflows/tool-orchestrator.js +796 -0
- package/dist/src/workflows/workflow-engine.js +573 -0
- package/dist/src/workflows/workflow-parser.js +283 -0
- package/dist/src/workflows/workflow-types.js +95 -0
- package/dist/src/workflows.js +568 -0
- package/dist/test-workflow-file-output.js +93 -0
- package/docs/API_KEYS.md +570 -0
- package/docs/CLAUDE_CODE_SETUP.md +181 -0
- package/docs/CLAUDE_DESKTOP_MANUAL.md +127 -0
- package/docs/CONFIGURATION.md +745 -0
- package/docs/FOCUS_MODES.md +240 -0
- package/docs/INSTALLATION_BOTH.md +145 -0
- package/docs/TERMS.md +352 -0
- package/docs/TOOLS_REFERENCE.md +1622 -0
- package/docs/TOOL_PARAMETERS.md +496 -0
- package/docs/TOOL_PROFILES.md +236 -0
- package/docs/WORKFLOWS.md +987 -0
- package/docs/WORKFLOW_OUTPUT.md +198 -0
- package/docs/WORKFLOW_PROGRESS_TRACKING.md +305 -0
- package/docs/workflows/design-brainstorm.md +335 -0
- package/package.json +97 -0
- package/profiles/balanced.json +37 -0
- package/profiles/code_focus.json +37 -0
- package/profiles/debug_intensive.json +34 -0
- package/profiles/full.json +37 -0
- package/profiles/minimal.json +37 -0
- package/profiles/research_power.json +37 -0
- package/profiles/workflow_builder.json +37 -0
- package/smithery.yaml +66 -0
- package/start.sh +8 -0
- package/tools.config.json +81 -0
- package/tsconfig.json +18 -0
- package/workflows/accessibility-code-audit.yaml +92 -0
- package/workflows/code-architecture-review.yaml +202 -0
- package/workflows/code-review.yaml +142 -0
- package/workflows/core/iterative-problem-solver.yaml +283 -0
- package/workflows/creative-brainstorm-yaml.yaml +215 -0
- package/workflows/pingpong.yaml +141 -0
- package/workflows/system/README.md +412 -0
- package/workflows/system/challenger.yaml +175 -0
- package/workflows/system/scout.yaml +164 -0
- package/workflows/system/verifier.yaml +133 -0
- package/workflows/ultra-creative-brainstorm.yaml +318 -0
- 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
|
+
}
|