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,455 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
/**
|
|
3
|
+
* In-memory message queue implementation
|
|
4
|
+
* Can be replaced with Kafka/RabbitMQ for production
|
|
5
|
+
*/
|
|
6
|
+
export class MessageQueue extends EventEmitter {
|
|
7
|
+
constructor(config = {}) {
|
|
8
|
+
super();
|
|
9
|
+
this.queues = new Map();
|
|
10
|
+
this.processing = new Map();
|
|
11
|
+
this.deadLetterQueue = [];
|
|
12
|
+
this.stats = new Map();
|
|
13
|
+
this.handlers = new Map();
|
|
14
|
+
this.config = {
|
|
15
|
+
maxSize: 10000,
|
|
16
|
+
maxRetries: 3,
|
|
17
|
+
retryDelay: 1000,
|
|
18
|
+
batchSize: 10,
|
|
19
|
+
flushInterval: 100,
|
|
20
|
+
deadLetterQueue: true,
|
|
21
|
+
...config
|
|
22
|
+
};
|
|
23
|
+
this.startFlushTimer();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Send a message to a topic
|
|
27
|
+
*/
|
|
28
|
+
async send(topic, payload, options = {}) {
|
|
29
|
+
const messageId = this.generateMessageId();
|
|
30
|
+
const message = {
|
|
31
|
+
id: messageId,
|
|
32
|
+
topic,
|
|
33
|
+
payload,
|
|
34
|
+
timestamp: Date.now(),
|
|
35
|
+
retryCount: 0,
|
|
36
|
+
maxRetries: options.maxRetries || this.config.maxRetries,
|
|
37
|
+
priority: options.priority || 'normal',
|
|
38
|
+
headers: options.headers
|
|
39
|
+
};
|
|
40
|
+
// Check queue size limit
|
|
41
|
+
const queue = this.getQueue(topic);
|
|
42
|
+
if (queue.length >= this.config.maxSize) {
|
|
43
|
+
throw new Error(`Queue ${topic} is full (max: ${this.config.maxSize})`);
|
|
44
|
+
}
|
|
45
|
+
// Add to queue based on priority
|
|
46
|
+
this.addToQueue(topic, message);
|
|
47
|
+
this.emit('message-sent', { topic, messageId });
|
|
48
|
+
// Update stats
|
|
49
|
+
this.updateStats(topic, 'pending', 1);
|
|
50
|
+
return messageId;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Send a batch of messages
|
|
54
|
+
*/
|
|
55
|
+
async sendBatch(topic, payloads, options = {}) {
|
|
56
|
+
const messageIds = [];
|
|
57
|
+
for (const payload of payloads) {
|
|
58
|
+
const id = await this.send(topic, payload, options);
|
|
59
|
+
messageIds.push(id);
|
|
60
|
+
}
|
|
61
|
+
return messageIds;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Subscribe to a topic
|
|
65
|
+
*/
|
|
66
|
+
subscribe(topic, handler) {
|
|
67
|
+
if (!this.handlers.has(topic)) {
|
|
68
|
+
this.handlers.set(topic, []);
|
|
69
|
+
}
|
|
70
|
+
this.handlers.get(topic).push(handler);
|
|
71
|
+
this.emit('subscription-added', { topic });
|
|
72
|
+
// Process any pending messages
|
|
73
|
+
this.processQueue(topic);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Process messages in a queue
|
|
77
|
+
*/
|
|
78
|
+
async processQueue(topic) {
|
|
79
|
+
const queue = this.getQueue(topic);
|
|
80
|
+
const handlers = this.handlers.get(topic) || [];
|
|
81
|
+
if (queue.length === 0 || handlers.length === 0) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
// Get batch of messages
|
|
85
|
+
const batch = this.getNextBatch(topic);
|
|
86
|
+
for (const message of batch) {
|
|
87
|
+
// Skip if already processing
|
|
88
|
+
if (this.isProcessing(topic, message.id)) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
this.markProcessing(topic, message.id);
|
|
92
|
+
// Process message with all handlers
|
|
93
|
+
this.processMessage(topic, message, handlers);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Process a single message
|
|
98
|
+
*/
|
|
99
|
+
async processMessage(topic, message, handlers) {
|
|
100
|
+
const startTime = Date.now();
|
|
101
|
+
try {
|
|
102
|
+
// Execute all handlers in parallel
|
|
103
|
+
const results = await Promise.allSettled(handlers.map(handler => handler(message)));
|
|
104
|
+
// Check if any handler failed
|
|
105
|
+
const failures = results.filter(r => r.status === 'rejected');
|
|
106
|
+
if (failures.length > 0) {
|
|
107
|
+
throw new Error(`${failures.length} handlers failed`);
|
|
108
|
+
}
|
|
109
|
+
// Success - remove from queue
|
|
110
|
+
this.removeFromQueue(topic, message.id);
|
|
111
|
+
this.markComplete(topic, message.id);
|
|
112
|
+
// Update stats
|
|
113
|
+
const processingTime = Date.now() - startTime;
|
|
114
|
+
this.updateStats(topic, 'completed', 1);
|
|
115
|
+
this.updateProcessingTime(topic, processingTime);
|
|
116
|
+
this.emit('message-processed', { topic, messageId: message.id, processingTime });
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
// Handle failure
|
|
120
|
+
await this.handleFailure(topic, message, error);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Handle message processing failure
|
|
125
|
+
*/
|
|
126
|
+
async handleFailure(topic, message, error) {
|
|
127
|
+
message.retryCount++;
|
|
128
|
+
this.markComplete(topic, message.id); // Remove from processing
|
|
129
|
+
if (message.retryCount < message.maxRetries) {
|
|
130
|
+
// Retry with delay
|
|
131
|
+
setTimeout(() => {
|
|
132
|
+
this.addToQueue(topic, message);
|
|
133
|
+
this.emit('message-retry', {
|
|
134
|
+
topic,
|
|
135
|
+
messageId: message.id,
|
|
136
|
+
retryCount: message.retryCount
|
|
137
|
+
});
|
|
138
|
+
}, this.config.retryDelay * message.retryCount);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
// Move to dead letter queue
|
|
142
|
+
if (this.config.deadLetterQueue) {
|
|
143
|
+
this.deadLetterQueue.push(message);
|
|
144
|
+
this.updateStats(topic, 'deadLetter', 1);
|
|
145
|
+
this.emit('message-dead-letter', {
|
|
146
|
+
topic,
|
|
147
|
+
messageId: message.id,
|
|
148
|
+
error: error.message
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
this.updateStats(topic, 'failed', 1);
|
|
153
|
+
this.emit('message-failed', {
|
|
154
|
+
topic,
|
|
155
|
+
messageId: message.id,
|
|
156
|
+
error: error.message
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
// Remove from queue
|
|
160
|
+
this.removeFromQueue(topic, message.id);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Get next batch of messages to process
|
|
165
|
+
*/
|
|
166
|
+
getNextBatch(topic) {
|
|
167
|
+
const queue = this.getQueue(topic);
|
|
168
|
+
// Sort by priority and timestamp
|
|
169
|
+
const sorted = queue.sort((a, b) => {
|
|
170
|
+
const priorityOrder = { critical: 0, high: 1, normal: 2, low: 3 };
|
|
171
|
+
const priorityDiff = priorityOrder[a.priority] - priorityOrder[b.priority];
|
|
172
|
+
if (priorityDiff !== 0)
|
|
173
|
+
return priorityDiff;
|
|
174
|
+
return a.timestamp - b.timestamp;
|
|
175
|
+
});
|
|
176
|
+
return sorted.slice(0, this.config.batchSize);
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Add message to queue based on priority
|
|
180
|
+
*/
|
|
181
|
+
addToQueue(topic, message) {
|
|
182
|
+
const queue = this.getQueue(topic);
|
|
183
|
+
if (message.priority === 'critical' || message.priority === 'high') {
|
|
184
|
+
// Add to front for high priority
|
|
185
|
+
queue.unshift(message);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
// Add to back for normal/low priority
|
|
189
|
+
queue.push(message);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Remove message from queue
|
|
194
|
+
*/
|
|
195
|
+
removeFromQueue(topic, messageId) {
|
|
196
|
+
const queue = this.getQueue(topic);
|
|
197
|
+
const index = queue.findIndex(m => m.id === messageId);
|
|
198
|
+
if (index >= 0) {
|
|
199
|
+
queue.splice(index, 1);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Get or create queue for topic
|
|
204
|
+
*/
|
|
205
|
+
getQueue(topic) {
|
|
206
|
+
if (!this.queues.has(topic)) {
|
|
207
|
+
this.queues.set(topic, []);
|
|
208
|
+
this.processing.set(topic, new Set());
|
|
209
|
+
this.initStats(topic);
|
|
210
|
+
}
|
|
211
|
+
return this.queues.get(topic);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Check if message is being processed
|
|
215
|
+
*/
|
|
216
|
+
isProcessing(topic, messageId) {
|
|
217
|
+
return this.processing.get(topic)?.has(messageId) || false;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Mark message as processing
|
|
221
|
+
*/
|
|
222
|
+
markProcessing(topic, messageId) {
|
|
223
|
+
if (!this.processing.has(topic)) {
|
|
224
|
+
this.processing.set(topic, new Set());
|
|
225
|
+
}
|
|
226
|
+
this.processing.get(topic).add(messageId);
|
|
227
|
+
this.updateStats(topic, 'processing', 1);
|
|
228
|
+
this.updateStats(topic, 'pending', -1);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Mark message as complete
|
|
232
|
+
*/
|
|
233
|
+
markComplete(topic, messageId) {
|
|
234
|
+
this.processing.get(topic)?.delete(messageId);
|
|
235
|
+
this.updateStats(topic, 'processing', -1);
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Start flush timer to process queues periodically
|
|
239
|
+
*/
|
|
240
|
+
startFlushTimer() {
|
|
241
|
+
this.flushTimer = setInterval(() => {
|
|
242
|
+
for (const topic of this.queues.keys()) {
|
|
243
|
+
this.processQueue(topic);
|
|
244
|
+
}
|
|
245
|
+
}, this.config.flushInterval);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Generate unique message ID
|
|
249
|
+
*/
|
|
250
|
+
generateMessageId() {
|
|
251
|
+
return `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Initialize stats for a topic
|
|
255
|
+
*/
|
|
256
|
+
initStats(topic) {
|
|
257
|
+
this.stats.set(topic, {
|
|
258
|
+
pending: 0,
|
|
259
|
+
processing: 0,
|
|
260
|
+
completed: 0,
|
|
261
|
+
failed: 0,
|
|
262
|
+
deadLetter: 0,
|
|
263
|
+
avgProcessingTime: 0,
|
|
264
|
+
throughput: 0
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Update stats for a topic
|
|
269
|
+
*/
|
|
270
|
+
updateStats(topic, field, delta) {
|
|
271
|
+
const stats = this.stats.get(topic);
|
|
272
|
+
if (stats) {
|
|
273
|
+
stats[field] += delta;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Update processing time stats
|
|
278
|
+
*/
|
|
279
|
+
updateProcessingTime(topic, time) {
|
|
280
|
+
const stats = this.stats.get(topic);
|
|
281
|
+
if (stats) {
|
|
282
|
+
// Calculate moving average
|
|
283
|
+
const alpha = 0.1; // Smoothing factor
|
|
284
|
+
stats.avgProcessingTime = alpha * time + (1 - alpha) * stats.avgProcessingTime;
|
|
285
|
+
// Calculate throughput (messages per second)
|
|
286
|
+
stats.throughput = 1000 / stats.avgProcessingTime;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Get stats for a topic
|
|
291
|
+
*/
|
|
292
|
+
getStats(topic) {
|
|
293
|
+
if (topic) {
|
|
294
|
+
return this.stats.get(topic) || this.initStats(topic) || this.stats.get(topic);
|
|
295
|
+
}
|
|
296
|
+
return new Map(this.stats);
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Get dead letter queue
|
|
300
|
+
*/
|
|
301
|
+
getDeadLetterQueue() {
|
|
302
|
+
return [...this.deadLetterQueue];
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Retry dead letter messages
|
|
306
|
+
*/
|
|
307
|
+
async retryDeadLetters(topic) {
|
|
308
|
+
const messages = topic
|
|
309
|
+
? this.deadLetterQueue.filter(m => m.topic === topic)
|
|
310
|
+
: [...this.deadLetterQueue];
|
|
311
|
+
let retried = 0;
|
|
312
|
+
for (const message of messages) {
|
|
313
|
+
message.retryCount = 0; // Reset retry count
|
|
314
|
+
this.addToQueue(message.topic, message);
|
|
315
|
+
// Remove from dead letter queue
|
|
316
|
+
const index = this.deadLetterQueue.indexOf(message);
|
|
317
|
+
if (index >= 0) {
|
|
318
|
+
this.deadLetterQueue.splice(index, 1);
|
|
319
|
+
}
|
|
320
|
+
retried++;
|
|
321
|
+
}
|
|
322
|
+
this.emit('dead-letters-retried', { count: retried, topic });
|
|
323
|
+
return retried;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Clear a queue
|
|
327
|
+
*/
|
|
328
|
+
clearQueue(topic) {
|
|
329
|
+
this.queues.set(topic, []);
|
|
330
|
+
this.processing.set(topic, new Set());
|
|
331
|
+
this.initStats(topic);
|
|
332
|
+
this.emit('queue-cleared', { topic });
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Cleanup and stop processing
|
|
336
|
+
*/
|
|
337
|
+
cleanup() {
|
|
338
|
+
if (this.flushTimer) {
|
|
339
|
+
clearInterval(this.flushTimer);
|
|
340
|
+
}
|
|
341
|
+
// Clear all queues
|
|
342
|
+
for (const topic of this.queues.keys()) {
|
|
343
|
+
this.clearQueue(topic);
|
|
344
|
+
}
|
|
345
|
+
this.deadLetterQueue = [];
|
|
346
|
+
this.removeAllListeners();
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Message Queue Orchestrator for Claude → Subagent communication
|
|
351
|
+
*/
|
|
352
|
+
export class MessageQueueOrchestrator extends EventEmitter {
|
|
353
|
+
constructor(queueConfig) {
|
|
354
|
+
super();
|
|
355
|
+
this.pendingRequests = new Map();
|
|
356
|
+
this.queue = new MessageQueue(queueConfig);
|
|
357
|
+
this.setupResponseHandler();
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Delegate task to subagent via message queue
|
|
361
|
+
*/
|
|
362
|
+
async delegateToSubagent(request) {
|
|
363
|
+
const timeout = request.timeout || 30000;
|
|
364
|
+
return new Promise((resolve, reject) => {
|
|
365
|
+
// Store pending request
|
|
366
|
+
const timeoutHandle = setTimeout(() => {
|
|
367
|
+
this.pendingRequests.delete(request.id);
|
|
368
|
+
reject(new Error(`Subagent request ${request.id} timed out after ${timeout}ms`));
|
|
369
|
+
}, timeout);
|
|
370
|
+
this.pendingRequests.set(request.id, { resolve, reject, timeout: timeoutHandle });
|
|
371
|
+
// Send to message queue
|
|
372
|
+
this.queue.send('subagent-requests', request, {
|
|
373
|
+
priority: 'normal',
|
|
374
|
+
headers: {
|
|
375
|
+
'request-id': request.id,
|
|
376
|
+
'request-type': request.type,
|
|
377
|
+
'timeout': timeout.toString()
|
|
378
|
+
}
|
|
379
|
+
}).catch(error => {
|
|
380
|
+
this.pendingRequests.delete(request.id);
|
|
381
|
+
clearTimeout(timeoutHandle);
|
|
382
|
+
reject(error);
|
|
383
|
+
});
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Spawn ephemeral subagent
|
|
388
|
+
*/
|
|
389
|
+
async spawnEphemeralSubagent(type, config) {
|
|
390
|
+
const subagentId = `${type}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
391
|
+
const request = {
|
|
392
|
+
id: this.generateRequestId(),
|
|
393
|
+
type: 'spawn-subagent',
|
|
394
|
+
config: {
|
|
395
|
+
subagentId,
|
|
396
|
+
type,
|
|
397
|
+
...config
|
|
398
|
+
},
|
|
399
|
+
payload: {}
|
|
400
|
+
};
|
|
401
|
+
const response = await this.delegateToSubagent(request);
|
|
402
|
+
if (response.error) {
|
|
403
|
+
throw new Error(`Failed to spawn subagent: ${response.error}`);
|
|
404
|
+
}
|
|
405
|
+
return subagentId;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Setup response handler
|
|
409
|
+
*/
|
|
410
|
+
setupResponseHandler() {
|
|
411
|
+
this.queue.subscribe('subagent-responses', async (message) => {
|
|
412
|
+
const response = message.payload;
|
|
413
|
+
const pending = this.pendingRequests.get(response.requestId);
|
|
414
|
+
if (pending) {
|
|
415
|
+
clearTimeout(pending.timeout);
|
|
416
|
+
this.pendingRequests.delete(response.requestId);
|
|
417
|
+
if (response.error) {
|
|
418
|
+
pending.reject(new Error(response.error));
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
pending.resolve(response);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Generate unique request ID
|
|
428
|
+
*/
|
|
429
|
+
generateRequestId() {
|
|
430
|
+
return `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Get queue statistics
|
|
434
|
+
*/
|
|
435
|
+
getStats() {
|
|
436
|
+
return this.queue.getStats();
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Cleanup
|
|
440
|
+
*/
|
|
441
|
+
cleanup() {
|
|
442
|
+
// Clear pending requests
|
|
443
|
+
for (const [id, pending] of this.pendingRequests.entries()) {
|
|
444
|
+
clearTimeout(pending.timeout);
|
|
445
|
+
pending.reject(new Error('Orchestrator shutting down'));
|
|
446
|
+
}
|
|
447
|
+
this.pendingRequests.clear();
|
|
448
|
+
// Cleanup queue
|
|
449
|
+
this.queue.cleanup();
|
|
450
|
+
this.removeAllListeners();
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
// Export singleton instances
|
|
454
|
+
export const messageQueue = new MessageQueue();
|
|
455
|
+
export const mqOrchestrator = new MessageQueueOrchestrator();
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
export class ModelRouter {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.models = new Map([
|
|
4
|
+
['claude-code', {
|
|
5
|
+
id: 'claude-code',
|
|
6
|
+
cost: 0,
|
|
7
|
+
quality: 10,
|
|
8
|
+
speed: 8,
|
|
9
|
+
reasoning: 10,
|
|
10
|
+
useFor: ['primary reasoning', 'code', 'analysis']
|
|
11
|
+
}],
|
|
12
|
+
['gemini-2.5-pro', {
|
|
13
|
+
id: 'gemini-2.5-pro',
|
|
14
|
+
cost: 10,
|
|
15
|
+
quality: 9,
|
|
16
|
+
speed: 7,
|
|
17
|
+
reasoning: 9,
|
|
18
|
+
context: '1M tokens',
|
|
19
|
+
useFor: ['deep reasoning', 'complex analysis', 'when quality matters']
|
|
20
|
+
}],
|
|
21
|
+
['gemini-2.5-flash', {
|
|
22
|
+
id: 'gemini-2.5-flash',
|
|
23
|
+
cost: 2,
|
|
24
|
+
quality: 7,
|
|
25
|
+
speed: 10,
|
|
26
|
+
reasoning: 7,
|
|
27
|
+
context: '1M tokens',
|
|
28
|
+
useFor: ['scout mode', 'quick analysis', 'high-volume tasks']
|
|
29
|
+
}],
|
|
30
|
+
['perplexity-sonar-pro', {
|
|
31
|
+
id: 'perplexity-sonar-pro',
|
|
32
|
+
cost: 6,
|
|
33
|
+
quality: 9,
|
|
34
|
+
speed: 7,
|
|
35
|
+
reasoning: 8,
|
|
36
|
+
useFor: ['web search', 'fact-checking', 'citations']
|
|
37
|
+
}],
|
|
38
|
+
['perplexity-sonar-reasoning', {
|
|
39
|
+
id: 'perplexity-sonar-reasoning',
|
|
40
|
+
cost: 10,
|
|
41
|
+
quality: 10,
|
|
42
|
+
speed: 5,
|
|
43
|
+
reasoning: 10,
|
|
44
|
+
useFor: ['complex reasoning with evidence']
|
|
45
|
+
}],
|
|
46
|
+
['grok-4', {
|
|
47
|
+
id: 'grok-4',
|
|
48
|
+
cost: 9,
|
|
49
|
+
quality: 9,
|
|
50
|
+
speed: 6,
|
|
51
|
+
reasoning: 9,
|
|
52
|
+
useFor: ['first-principles', 'architecture', 'challenging assumptions']
|
|
53
|
+
}],
|
|
54
|
+
['grok-4-heavy', {
|
|
55
|
+
id: 'grok-4-heavy',
|
|
56
|
+
cost: 12,
|
|
57
|
+
quality: 10,
|
|
58
|
+
speed: 4,
|
|
59
|
+
reasoning: 10,
|
|
60
|
+
useFor: ['deep reasoning', 'complex problems']
|
|
61
|
+
}],
|
|
62
|
+
['gpt5', {
|
|
63
|
+
id: 'gpt5',
|
|
64
|
+
cost: 12,
|
|
65
|
+
quality: 10,
|
|
66
|
+
speed: 7,
|
|
67
|
+
reasoning: 10,
|
|
68
|
+
useFor: ['primary reasoning', 'complex analysis', 'critical workflows']
|
|
69
|
+
}],
|
|
70
|
+
['gpt5_mini', {
|
|
71
|
+
id: 'gpt5_mini',
|
|
72
|
+
cost: 8,
|
|
73
|
+
quality: 9,
|
|
74
|
+
speed: 9,
|
|
75
|
+
reasoning: 9,
|
|
76
|
+
useFor: ['fallback reasoning', 'challenger mode', 'cost-aware reasoning']
|
|
77
|
+
}],
|
|
78
|
+
['gpt5_reason', {
|
|
79
|
+
id: 'gpt5_reason',
|
|
80
|
+
cost: 12,
|
|
81
|
+
quality: 10,
|
|
82
|
+
speed: 7,
|
|
83
|
+
reasoning: 10,
|
|
84
|
+
useFor: ['deep research', 'complex reasoning']
|
|
85
|
+
}],
|
|
86
|
+
['qwen3-coder-480b', {
|
|
87
|
+
id: 'qwen3-coder-480b',
|
|
88
|
+
cost: 12,
|
|
89
|
+
quality: 10,
|
|
90
|
+
speed: 4,
|
|
91
|
+
reasoning: 8,
|
|
92
|
+
useFor: ['code generation', 'code analysis', 'refactoring']
|
|
93
|
+
}],
|
|
94
|
+
['qwq-32b', {
|
|
95
|
+
id: 'qwq-32b',
|
|
96
|
+
cost: 10,
|
|
97
|
+
quality: 9,
|
|
98
|
+
speed: 5,
|
|
99
|
+
reasoning: 10,
|
|
100
|
+
useFor: ['mathematical reasoning', 'step-by-step logic']
|
|
101
|
+
}],
|
|
102
|
+
['qwen3-30b', {
|
|
103
|
+
id: 'qwen3-30b',
|
|
104
|
+
cost: 6,
|
|
105
|
+
quality: 8,
|
|
106
|
+
speed: 7,
|
|
107
|
+
reasoning: 8,
|
|
108
|
+
useFor: ['general tasks', 'cheaper alternative']
|
|
109
|
+
}],
|
|
110
|
+
['think', {
|
|
111
|
+
id: 'think',
|
|
112
|
+
cost: 0,
|
|
113
|
+
quality: 6,
|
|
114
|
+
speed: 10,
|
|
115
|
+
reasoning: 6,
|
|
116
|
+
useFor: ['synthesis', 'internal reasoning', 'combining insights']
|
|
117
|
+
}]
|
|
118
|
+
]);
|
|
119
|
+
}
|
|
120
|
+
selectModel(task, constraints = {}) {
|
|
121
|
+
if (task.needsCurrentInfo || task.type === 'facts' || task.type === 'research') {
|
|
122
|
+
return 'perplexity-sonar-pro';
|
|
123
|
+
}
|
|
124
|
+
if (task.complexity > 0.8 && !constraints.budget) {
|
|
125
|
+
return constraints.budget !== undefined && constraints.budget < 10 ? 'gpt5_mini' : 'gpt5';
|
|
126
|
+
}
|
|
127
|
+
if (task.complexity < 0.2 && task.type === 'format') {
|
|
128
|
+
return 'gemini-2.5-flash';
|
|
129
|
+
}
|
|
130
|
+
if (task.type === 'synthesis') {
|
|
131
|
+
return 'think';
|
|
132
|
+
}
|
|
133
|
+
if (constraints.local) {
|
|
134
|
+
return 'lmstudio-local';
|
|
135
|
+
}
|
|
136
|
+
const taskTypeMap = {
|
|
137
|
+
'code': task.complexity > 0.7 ? 'qwen3-coder-480b' : 'gemini-2.5-flash',
|
|
138
|
+
'research': 'perplexity-sonar-pro',
|
|
139
|
+
'reasoning': task.complexity > 0.5 ? 'gpt5' : 'gpt5_mini',
|
|
140
|
+
'scout': 'multi-model',
|
|
141
|
+
'verifier': task.complexity > 0.5 ? 'gpt5' : 'gpt5_mini',
|
|
142
|
+
'challenger': 'gpt5_mini',
|
|
143
|
+
'auditor': 'perplexity-sonar-pro',
|
|
144
|
+
'architect': 'grok-4',
|
|
145
|
+
'commit_guardian': 'gemini-2.5-flash'
|
|
146
|
+
};
|
|
147
|
+
return taskTypeMap[task.type] || this.selectByConstraints(task, constraints);
|
|
148
|
+
}
|
|
149
|
+
selectByConstraints(task, constraints) {
|
|
150
|
+
let candidates = Array.from(this.models.values());
|
|
151
|
+
if (constraints.budget !== undefined) {
|
|
152
|
+
candidates = candidates.filter(m => m.cost <= constraints.budget);
|
|
153
|
+
}
|
|
154
|
+
if (constraints.speed) {
|
|
155
|
+
candidates.sort((a, b) => b.speed - a.speed);
|
|
156
|
+
}
|
|
157
|
+
else if (constraints.quality) {
|
|
158
|
+
candidates.sort((a, b) => b.quality - a.quality);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
candidates.sort((a, b) => {
|
|
162
|
+
const scoreA = (a.quality * 0.4 + a.speed * 0.3 + a.reasoning * 0.3) / a.cost;
|
|
163
|
+
const scoreB = (b.quality * 0.4 + b.speed * 0.3 + b.reasoning * 0.3) / b.cost;
|
|
164
|
+
return scoreB - scoreA;
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
return candidates[0]?.id || 'gpt5_mini';
|
|
168
|
+
}
|
|
169
|
+
getModelInfo(modelId) {
|
|
170
|
+
return this.models.get(modelId);
|
|
171
|
+
}
|
|
172
|
+
estimateCost(modelId, tokens) {
|
|
173
|
+
const model = this.models.get(modelId);
|
|
174
|
+
if (!model)
|
|
175
|
+
return 0;
|
|
176
|
+
const costPerMillion = model.cost;
|
|
177
|
+
return (tokens / 1000000) * costPerMillion;
|
|
178
|
+
}
|
|
179
|
+
selectModelsForVerification(variant) {
|
|
180
|
+
const variants = {
|
|
181
|
+
'quick_verify': ['gpt5_mini', 'gemini-2.5-flash', 'qwen3-30b'],
|
|
182
|
+
'deep_verify': ['gpt5', 'qwq-32b', 'gpt5_reason', 'gemini-2.5-pro', 'qwen3-coder-480b'],
|
|
183
|
+
'fact_check': ['perplexity-sonar-pro', 'gpt5', 'gemini-2.5-pro'],
|
|
184
|
+
'code_verify': ['qwen3-coder-480b', 'gpt5', 'gemini-2.5-pro'],
|
|
185
|
+
'security_verify': ['gpt5', 'qwen3-coder-480b', 'grok-4']
|
|
186
|
+
};
|
|
187
|
+
return variants[variant] || variants['quick_verify'];
|
|
188
|
+
}
|
|
189
|
+
}
|