tachibot-mcp 2.7.10 → 2.9.0
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/dist/src/application/services/focus/FocusExecutionService.js +359 -0
- package/dist/src/application/services/focus/FocusTool.service.js +52 -13
- package/dist/src/application/services/focus/modes/focus-deep.mode.js +25 -0
- package/dist/src/application/services/focus/types/FocusSession.js +8 -0
- package/dist/src/config/model-constants.js +7 -0
- package/dist/src/focus-deep.js +34 -0
- package/dist/src/modes/challenger.js +40 -1
- package/dist/src/modes/scout.js +23 -1
- package/dist/src/modes/shared/helpers/challenger-helpers.js +14 -1
- package/dist/src/modes/shared/helpers/verifier-helpers.js +16 -1
- package/dist/src/modes/verifier.js +39 -1
- package/dist/src/orchestrators/collaborative/services/tool-execution/ToolExecutionService.js +3 -1
- package/dist/src/orchestrators/collaborative/services/visualization/VisualizationService.js +39 -1
- package/dist/src/profiles/balanced.js +5 -0
- package/dist/src/profiles/code_focus.js +5 -0
- package/dist/src/profiles/full.js +5 -0
- package/dist/src/profiles/heavy_coding.js +7 -2
- package/dist/src/profiles/minimal.js +5 -0
- package/dist/src/profiles/research_power.js +5 -0
- package/dist/src/prompt-engineer-lite.js +58 -10
- package/dist/src/sequential-thinking.js +24 -10
- package/dist/src/server.js +84 -56
- package/dist/src/tools/advanced-modes.js +48 -38
- package/dist/src/tools/claude-integration.js +16 -12
- package/dist/src/tools/gemini-tools.js +208 -67
- package/dist/src/tools/grok-enhanced.js +18 -13
- package/dist/src/tools/grok-tools.js +71 -51
- package/dist/src/tools/lmstudio-tools.js +18 -16
- package/dist/src/tools/openai-tools.js +181 -38
- package/dist/src/tools/openrouter-tools.js +111 -61
- package/dist/src/tools/perplexity-tools.js +43 -49
- package/dist/src/tools/prompt-technique-tools.js +404 -0
- package/dist/src/tools/qwen-wrapper.js +16 -11
- package/dist/src/tools/tachi-tool.js +47 -53
- package/dist/src/tools/workflow-runner.js +52 -75
- package/dist/src/utils/ansi-renderer.js +5 -2
- package/dist/src/utils/format-constants.js +47 -0
- package/dist/src/utils/format-stripper.js +28 -0
- package/dist/src/utils/ink-renderer.js +36 -5
- package/dist/src/utils/input-validator.js +42 -15
- package/dist/src/utils/progress-stream.js +4 -1
- package/dist/src/utils/usage-tracker.js +65 -7
- package/dist/src/workflows/custom-workflows.js +14 -2
- package/dist/src/workflows/tool-mapper.js +24 -21
- package/package.json +1 -1
- package/profiles/balanced.json +7 -2
- package/profiles/code_focus.json +7 -2
- package/profiles/full.json +7 -2
- package/profiles/heavy_coding.json +7 -2
- package/profiles/minimal.json +7 -2
- package/profiles/research_power.json +7 -2
- package/tools.config.json +2 -1
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FocusExecutionService - Manages focus sessions and step execution
|
|
3
|
+
* Enables executeNow mode for focus tool to actually run model calls
|
|
4
|
+
*/
|
|
5
|
+
import { randomBytes } from "crypto";
|
|
6
|
+
import { ToolExecutionService } from "../../../orchestrators/collaborative/services/tool-execution/ToolExecutionService.js";
|
|
7
|
+
import { ReasoningMode } from "../../../reasoning-chain.js";
|
|
8
|
+
import { createFocusDeepPlan, generateFocusDeepVisualization } from "../../../focus-deep.js";
|
|
9
|
+
import { SESSION_TIMEOUT_MS, } from "./types/FocusSession.js";
|
|
10
|
+
/**
|
|
11
|
+
* Generate UUID v4 using randomBytes
|
|
12
|
+
*/
|
|
13
|
+
function generateUUID() {
|
|
14
|
+
const bytes = randomBytes(16);
|
|
15
|
+
// Set version (4) and variant bits
|
|
16
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
|
17
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
18
|
+
const hex = bytes.toString('hex');
|
|
19
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* FocusExecutionService - Session management and step execution for focus modes
|
|
23
|
+
*/
|
|
24
|
+
export class FocusExecutionService {
|
|
25
|
+
constructor(toolExecutionService) {
|
|
26
|
+
this.sessions = new Map();
|
|
27
|
+
this.cleanupInterval = null;
|
|
28
|
+
this.toolExecutionService = toolExecutionService || new ToolExecutionService({ verbose: false });
|
|
29
|
+
// Start cleanup interval
|
|
30
|
+
this.startCleanupInterval();
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Start a new focus session and execute the first step
|
|
34
|
+
*/
|
|
35
|
+
async startFocusSession(params) {
|
|
36
|
+
const { query, mode, domain, rounds = 5, models = [], temperature = 0.7, maxTokensPerRound = 2000, pingPongStyle = "collaborative", tokenEfficient = false, saveSession = true, } = params;
|
|
37
|
+
// Create the focus plan
|
|
38
|
+
const plan = createFocusDeepPlan(query, domain);
|
|
39
|
+
// Create session
|
|
40
|
+
const sessionId = generateUUID();
|
|
41
|
+
const session = {
|
|
42
|
+
sessionId,
|
|
43
|
+
mode,
|
|
44
|
+
query,
|
|
45
|
+
domain,
|
|
46
|
+
currentStepIndex: 0,
|
|
47
|
+
totalSteps: plan.steps.length,
|
|
48
|
+
plan,
|
|
49
|
+
stepOutputs: new Map(),
|
|
50
|
+
status: "running",
|
|
51
|
+
config: {
|
|
52
|
+
rounds,
|
|
53
|
+
models: models.length > 0 ? models : plan.availableModels,
|
|
54
|
+
temperature,
|
|
55
|
+
maxTokensPerRound,
|
|
56
|
+
pingPongStyle,
|
|
57
|
+
tokenEfficient,
|
|
58
|
+
saveSession,
|
|
59
|
+
},
|
|
60
|
+
createdAt: new Date(),
|
|
61
|
+
lastActivityAt: new Date(),
|
|
62
|
+
};
|
|
63
|
+
this.sessions.set(sessionId, session);
|
|
64
|
+
// Execute first step
|
|
65
|
+
return this.executeNextStep(session);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Continue an existing focus session
|
|
69
|
+
*/
|
|
70
|
+
async continueFocus(sessionId) {
|
|
71
|
+
const session = this.sessions.get(sessionId);
|
|
72
|
+
if (!session) {
|
|
73
|
+
return {
|
|
74
|
+
sessionId,
|
|
75
|
+
status: "failed",
|
|
76
|
+
progress: 0,
|
|
77
|
+
output: `Error: Session not found. Session ID: ${sessionId}`,
|
|
78
|
+
hasMoreSteps: false,
|
|
79
|
+
totalSteps: 0,
|
|
80
|
+
currentStep: 0,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
// Check timeout
|
|
84
|
+
if (this.isSessionTimedOut(session)) {
|
|
85
|
+
session.status = "failed";
|
|
86
|
+
session.error = "Session timed out after 30 minutes of inactivity";
|
|
87
|
+
return {
|
|
88
|
+
sessionId,
|
|
89
|
+
status: "failed",
|
|
90
|
+
progress: this.calculateProgress(session),
|
|
91
|
+
output: `Error: ${session.error}`,
|
|
92
|
+
hasMoreSteps: false,
|
|
93
|
+
totalSteps: session.totalSteps,
|
|
94
|
+
currentStep: session.currentStepIndex,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
if (session.status === "completed") {
|
|
98
|
+
return this.buildCompletedResult(session);
|
|
99
|
+
}
|
|
100
|
+
if (session.status === "failed") {
|
|
101
|
+
return {
|
|
102
|
+
sessionId,
|
|
103
|
+
status: "failed",
|
|
104
|
+
progress: this.calculateProgress(session),
|
|
105
|
+
output: `Error: Session failed - ${session.error}`,
|
|
106
|
+
hasMoreSteps: false,
|
|
107
|
+
totalSteps: session.totalSteps,
|
|
108
|
+
currentStep: session.currentStepIndex,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
// Execute next step
|
|
112
|
+
return this.executeNextStep(session);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get session status without executing
|
|
116
|
+
*/
|
|
117
|
+
getSession(sessionId) {
|
|
118
|
+
return this.sessions.get(sessionId);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Execute the next step in the session
|
|
122
|
+
*/
|
|
123
|
+
async executeNextStep(session) {
|
|
124
|
+
const stepIndex = session.currentStepIndex;
|
|
125
|
+
const step = session.plan.steps[stepIndex];
|
|
126
|
+
if (!step) {
|
|
127
|
+
// No more steps - session complete
|
|
128
|
+
session.status = "completed";
|
|
129
|
+
return this.buildCompletedResult(session);
|
|
130
|
+
}
|
|
131
|
+
const startTime = Date.now();
|
|
132
|
+
try {
|
|
133
|
+
// Build context from previous steps
|
|
134
|
+
const context = this.buildStepContext(session, stepIndex);
|
|
135
|
+
// Build the prompt for this step
|
|
136
|
+
const prompt = this.buildStepPrompt(session, step, context);
|
|
137
|
+
// Execute the step using ToolExecutionService
|
|
138
|
+
const output = await this.toolExecutionService.executeRealTool(step.model, prompt, ReasoningMode.DEEP_REASONING);
|
|
139
|
+
const duration = Date.now() - startTime;
|
|
140
|
+
// Store step output
|
|
141
|
+
const stepOutput = {
|
|
142
|
+
stepIndex,
|
|
143
|
+
model: step.model,
|
|
144
|
+
action: step.action,
|
|
145
|
+
output,
|
|
146
|
+
duration,
|
|
147
|
+
timestamp: new Date(),
|
|
148
|
+
};
|
|
149
|
+
session.stepOutputs.set(stepIndex, stepOutput);
|
|
150
|
+
// Move to next step
|
|
151
|
+
session.currentStepIndex++;
|
|
152
|
+
session.lastActivityAt = new Date();
|
|
153
|
+
// Check if we're done
|
|
154
|
+
if (session.currentStepIndex >= session.totalSteps) {
|
|
155
|
+
session.status = "completed";
|
|
156
|
+
return this.buildCompletedResult(session);
|
|
157
|
+
}
|
|
158
|
+
// Return progress result
|
|
159
|
+
return {
|
|
160
|
+
sessionId: session.sessionId,
|
|
161
|
+
status: "running",
|
|
162
|
+
progress: this.calculateProgress(session),
|
|
163
|
+
stepOutput,
|
|
164
|
+
output: this.formatStepOutput(stepOutput, session),
|
|
165
|
+
hasMoreSteps: true,
|
|
166
|
+
totalSteps: session.totalSteps,
|
|
167
|
+
currentStep: session.currentStepIndex,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
172
|
+
const duration = Date.now() - startTime;
|
|
173
|
+
// Store error output
|
|
174
|
+
const stepOutput = {
|
|
175
|
+
stepIndex,
|
|
176
|
+
model: step.model,
|
|
177
|
+
action: step.action,
|
|
178
|
+
output: "",
|
|
179
|
+
duration,
|
|
180
|
+
timestamp: new Date(),
|
|
181
|
+
error: errorMsg,
|
|
182
|
+
};
|
|
183
|
+
session.stepOutputs.set(stepIndex, stepOutput);
|
|
184
|
+
session.status = "failed";
|
|
185
|
+
session.error = `Step ${stepIndex + 1} failed: ${errorMsg}`;
|
|
186
|
+
return {
|
|
187
|
+
sessionId: session.sessionId,
|
|
188
|
+
status: "failed",
|
|
189
|
+
progress: this.calculateProgress(session),
|
|
190
|
+
stepOutput,
|
|
191
|
+
output: `Error executing step ${stepIndex + 1} (${step.model}:${step.action}): ${errorMsg}`,
|
|
192
|
+
hasMoreSteps: false,
|
|
193
|
+
totalSteps: session.totalSteps,
|
|
194
|
+
currentStep: session.currentStepIndex,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Build context from previous step outputs
|
|
200
|
+
*/
|
|
201
|
+
buildStepContext(session, currentStepIndex) {
|
|
202
|
+
if (currentStepIndex === 0) {
|
|
203
|
+
return "";
|
|
204
|
+
}
|
|
205
|
+
const previousOutputs = [];
|
|
206
|
+
for (let i = 0; i < currentStepIndex; i++) {
|
|
207
|
+
const output = session.stepOutputs.get(i);
|
|
208
|
+
if (output && !output.error) {
|
|
209
|
+
const step = session.plan.steps[i];
|
|
210
|
+
previousOutputs.push(`### Step ${i + 1}: ${step.action} (${step.model})\n${output.output}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return previousOutputs.join("\n\n---\n\n");
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Build prompt for a specific step
|
|
217
|
+
*/
|
|
218
|
+
buildStepPrompt(session, step, previousContext) {
|
|
219
|
+
let prompt = `## Objective\n${session.query}\n\n`;
|
|
220
|
+
if (session.domain) {
|
|
221
|
+
prompt += `## Domain\n${session.domain}\n\n`;
|
|
222
|
+
}
|
|
223
|
+
if (previousContext) {
|
|
224
|
+
prompt += `## Previous Analysis\n${previousContext}\n\n---\n\n`;
|
|
225
|
+
}
|
|
226
|
+
prompt += `## Current Task: ${step.action.toUpperCase()}\n`;
|
|
227
|
+
prompt += `${step.prompt}\n\n`;
|
|
228
|
+
if (step.reasoning) {
|
|
229
|
+
prompt += `**Why this step**: ${step.reasoning}\n\n`;
|
|
230
|
+
}
|
|
231
|
+
prompt += `Please provide your ${step.action} analysis.`;
|
|
232
|
+
return prompt;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Format step output for display
|
|
236
|
+
*/
|
|
237
|
+
formatStepOutput(stepOutput, session) {
|
|
238
|
+
const step = session.plan.steps[stepOutput.stepIndex];
|
|
239
|
+
const progress = this.calculateProgress(session);
|
|
240
|
+
let output = `## Step ${stepOutput.stepIndex + 1}/${session.totalSteps}: ${step.action.toUpperCase()}\n`;
|
|
241
|
+
output += `**Model**: ${stepOutput.model}\n`;
|
|
242
|
+
output += `**Duration**: ${stepOutput.duration}ms\n`;
|
|
243
|
+
output += `**Progress**: ${progress.toFixed(0)}%\n\n`;
|
|
244
|
+
if (stepOutput.error) {
|
|
245
|
+
output += `### Error\n${stepOutput.error}\n`;
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
output += `### Output\n${stepOutput.output}\n`;
|
|
249
|
+
}
|
|
250
|
+
output += `\n---\n`;
|
|
251
|
+
output += `Session ID: \`${session.sessionId}\`\n`;
|
|
252
|
+
output += `Use \`continue_focus\` with this session ID to continue.\n`;
|
|
253
|
+
return output;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Build completed session result with summary
|
|
257
|
+
*/
|
|
258
|
+
buildCompletedResult(session) {
|
|
259
|
+
// Collect all outputs
|
|
260
|
+
const allOutputs = [];
|
|
261
|
+
for (let i = 0; i < session.totalSteps; i++) {
|
|
262
|
+
const output = session.stepOutputs.get(i);
|
|
263
|
+
if (output) {
|
|
264
|
+
allOutputs.push(output);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// Build summary output
|
|
268
|
+
let output = `# Focus-Deep Session Complete\n\n`;
|
|
269
|
+
output += `**Objective**: ${session.query}\n`;
|
|
270
|
+
output += `**Mode**: ${session.mode}\n`;
|
|
271
|
+
output += `**Steps Completed**: ${allOutputs.length}/${session.totalSteps}\n\n`;
|
|
272
|
+
// Add each step's output
|
|
273
|
+
output += `## Step-by-Step Analysis\n\n`;
|
|
274
|
+
for (const stepOutput of allOutputs) {
|
|
275
|
+
const step = session.plan.steps[stepOutput.stepIndex];
|
|
276
|
+
output += `### Step ${stepOutput.stepIndex + 1}: ${step.action.toUpperCase()} (${stepOutput.model})\n`;
|
|
277
|
+
output += `*Duration: ${stepOutput.duration}ms*\n\n`;
|
|
278
|
+
if (stepOutput.error) {
|
|
279
|
+
output += `**Error**: ${stepOutput.error}\n\n`;
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
output += `${stepOutput.output}\n\n`;
|
|
283
|
+
}
|
|
284
|
+
output += `---\n\n`;
|
|
285
|
+
}
|
|
286
|
+
// Add final synthesis prompt
|
|
287
|
+
const lastOutput = allOutputs[allOutputs.length - 1];
|
|
288
|
+
if (lastOutput && !lastOutput.error) {
|
|
289
|
+
output += `## Final Synthesis\n\n`;
|
|
290
|
+
output += `The focus-deep analysis has completed. The final step (${session.plan.steps[lastOutput.stepIndex].action}) provides the synthesized conclusion.\n`;
|
|
291
|
+
}
|
|
292
|
+
return {
|
|
293
|
+
sessionId: session.sessionId,
|
|
294
|
+
status: "completed",
|
|
295
|
+
progress: 100,
|
|
296
|
+
output,
|
|
297
|
+
hasMoreSteps: false,
|
|
298
|
+
totalSteps: session.totalSteps,
|
|
299
|
+
currentStep: session.totalSteps,
|
|
300
|
+
allOutputs,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Calculate session progress percentage
|
|
305
|
+
*/
|
|
306
|
+
calculateProgress(session) {
|
|
307
|
+
if (session.totalSteps === 0)
|
|
308
|
+
return 100;
|
|
309
|
+
return (session.currentStepIndex / session.totalSteps) * 100;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Check if session has timed out
|
|
313
|
+
*/
|
|
314
|
+
isSessionTimedOut(session) {
|
|
315
|
+
const now = Date.now();
|
|
316
|
+
const lastActivity = session.lastActivityAt.getTime();
|
|
317
|
+
return now - lastActivity > SESSION_TIMEOUT_MS;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Start interval to clean up timed out sessions
|
|
321
|
+
*/
|
|
322
|
+
startCleanupInterval() {
|
|
323
|
+
// Clean up every 5 minutes
|
|
324
|
+
this.cleanupInterval = setInterval(() => {
|
|
325
|
+
this.cleanupTimedOutSessions();
|
|
326
|
+
}, 5 * 60 * 1000);
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Clean up timed out sessions
|
|
330
|
+
*/
|
|
331
|
+
cleanupTimedOutSessions() {
|
|
332
|
+
const now = Date.now();
|
|
333
|
+
for (const [sessionId, session] of this.sessions) {
|
|
334
|
+
const lastActivity = session.lastActivityAt.getTime();
|
|
335
|
+
if (now - lastActivity > SESSION_TIMEOUT_MS) {
|
|
336
|
+
this.sessions.delete(sessionId);
|
|
337
|
+
console.error(`[FocusExecutionService] Cleaned up timed out session: ${sessionId}`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Stop the cleanup interval (for testing/shutdown)
|
|
343
|
+
*/
|
|
344
|
+
stopCleanup() {
|
|
345
|
+
if (this.cleanupInterval) {
|
|
346
|
+
clearInterval(this.cleanupInterval);
|
|
347
|
+
this.cleanupInterval = null;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Get plan-only visualization (for executeNow: false)
|
|
352
|
+
*/
|
|
353
|
+
getPlanVisualization(query, domain) {
|
|
354
|
+
const plan = createFocusDeepPlan(query, domain);
|
|
355
|
+
return generateFocusDeepVisualization(plan);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
// Export singleton instance
|
|
359
|
+
export const focusExecutionService = new FocusExecutionService();
|
|
@@ -6,29 +6,70 @@
|
|
|
6
6
|
* Architecture:
|
|
7
7
|
* 1. FocusModeRegistry - For complex extracted modes (FocusDeepMode, TachibotStatusMode)
|
|
8
8
|
* 2. Delegate Map - For simple orchestrator calls
|
|
9
|
-
* 3.
|
|
9
|
+
* 3. FocusExecutionService - For executeNow mode (actual model execution)
|
|
10
|
+
* 4. Legacy fallback - For modes with complex conditional logic (handled by server.ts)
|
|
10
11
|
*/
|
|
11
12
|
import { TechnicalDomain } from '../../../reasoning-chain.js';
|
|
12
|
-
import {
|
|
13
|
+
import { stripFormatting } from '../../../utils/format-stripper.js';
|
|
13
14
|
export class FocusToolService {
|
|
14
|
-
constructor(modeRegistry, collaborativeOrchestrator) {
|
|
15
|
+
constructor(modeRegistry, collaborativeOrchestrator, executionService) {
|
|
15
16
|
this.modeRegistry = modeRegistry;
|
|
16
17
|
this.collaborativeOrchestrator = collaborativeOrchestrator;
|
|
17
18
|
this.name = 'focus';
|
|
18
19
|
this.description = 'Multi-model reasoning with various modes';
|
|
20
|
+
this.executionService = null;
|
|
19
21
|
this.delegateHandlers = this.createDelegateHandlers();
|
|
22
|
+
this.executionService = executionService || null;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Set the execution service (for lazy initialization)
|
|
26
|
+
*/
|
|
27
|
+
setExecutionService(service) {
|
|
28
|
+
this.executionService = service;
|
|
20
29
|
}
|
|
21
30
|
async execute(params) {
|
|
22
31
|
const modeName = params.mode || 'simple';
|
|
23
|
-
|
|
24
|
-
|
|
32
|
+
const executeNow = params.executeNow !== false; // Default to true
|
|
33
|
+
// BigText header disabled - plain text only
|
|
34
|
+
const header = '';
|
|
35
|
+
// 0. For focus-deep mode with executeNow, use the execution service
|
|
36
|
+
if (modeName === 'focus-deep' && executeNow && this.executionService) {
|
|
37
|
+
const result = await this.executionService.startFocusSession({
|
|
38
|
+
query: params.query,
|
|
39
|
+
mode: modeName,
|
|
40
|
+
domain: params.domain,
|
|
41
|
+
context: params.context,
|
|
42
|
+
rounds: params.rounds,
|
|
43
|
+
models: params.models,
|
|
44
|
+
temperature: params.temperature,
|
|
45
|
+
maxTokensPerRound: params.maxTokensPerRound,
|
|
46
|
+
pingPongStyle: params.pingPongStyle,
|
|
47
|
+
tokenEfficient: params.tokenEfficient,
|
|
48
|
+
saveSession: params.saveSession,
|
|
49
|
+
});
|
|
50
|
+
return {
|
|
51
|
+
output: stripFormatting(header + result.output),
|
|
52
|
+
metadata: {
|
|
53
|
+
mode: modeName,
|
|
54
|
+
sessionId: result.sessionId,
|
|
55
|
+
status: result.status,
|
|
56
|
+
progress: result.progress,
|
|
57
|
+
hasMoreSteps: result.hasMoreSteps,
|
|
58
|
+
totalSteps: result.totalSteps,
|
|
59
|
+
currentStep: result.currentStep,
|
|
60
|
+
timestamp: Date.now()
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
25
64
|
// 1. Try extracted modes first (Strategy Pattern)
|
|
65
|
+
// For focus-deep with executeNow: false, this returns the plan visualization
|
|
26
66
|
const mode = this.modeRegistry.get(modeName);
|
|
27
67
|
if (mode) {
|
|
28
|
-
|
|
68
|
+
// Pass executeNow to the mode for conditional behavior
|
|
69
|
+
const result = await mode.execute({ ...params, executeNow });
|
|
29
70
|
return {
|
|
30
71
|
...result,
|
|
31
|
-
output: header + result.output
|
|
72
|
+
output: stripFormatting(header + result.output)
|
|
32
73
|
};
|
|
33
74
|
}
|
|
34
75
|
// 2. Try delegate handlers (simple orchestrator calls)
|
|
@@ -36,7 +77,7 @@ export class FocusToolService {
|
|
|
36
77
|
if (handler) {
|
|
37
78
|
const output = await handler(params);
|
|
38
79
|
return {
|
|
39
|
-
output: header + output,
|
|
80
|
+
output: stripFormatting(header + output),
|
|
40
81
|
metadata: {
|
|
41
82
|
mode: modeName,
|
|
42
83
|
timestamp: Date.now()
|
|
@@ -71,22 +112,20 @@ export class FocusToolService {
|
|
|
71
112
|
const query = params.query;
|
|
72
113
|
const domain = parseDomain(params.domain);
|
|
73
114
|
const plan = await this.collaborativeOrchestrator.startDeepReasoning(query, domain);
|
|
74
|
-
|
|
75
|
-
return `${title}\n\n${plan}\n\n🔄 **How it works**: Models collaborate, critique, and build upon each other's ideas to find optimal solutions.`;
|
|
115
|
+
return `🧠 DEEP COLLABORATIVE REASONING\n${'═'.repeat(40)}\n\n${plan}\n\n🔄 How it works: Models collaborate, critique, and build upon each other's ideas to find optimal solutions.`;
|
|
76
116
|
});
|
|
77
117
|
handlers.set('code-brainstorm', async (params) => {
|
|
78
118
|
const query = params.query;
|
|
79
119
|
const domain = parseDomain(params.domain);
|
|
80
120
|
const plan = await this.collaborativeOrchestrator.startDeepReasoning(query, domain);
|
|
81
|
-
|
|
82
|
-
return `${title}\n\n${plan}\n\n🔄 **How it works**: Models collaborate, critique, and build upon each other's ideas to find optimal solutions.`;
|
|
121
|
+
return `💡 CODE BRAINSTORMING SESSION\n${'═'.repeat(40)}\n\n${plan}\n\n🔄 How it works: Models collaborate, critique, and build upon each other's ideas to find optimal solutions.`;
|
|
83
122
|
});
|
|
84
123
|
// Dynamic debate
|
|
85
124
|
handlers.set('dynamic-debate', async (params) => {
|
|
86
125
|
const query = params.query;
|
|
87
126
|
const domain = parseDomain(params.domain);
|
|
88
127
|
const plan = await this.collaborativeOrchestrator.startDynamicDebate(query, domain);
|
|
89
|
-
return `⚔️
|
|
128
|
+
return `⚔️ DYNAMIC DEBATE SESSION\n${'═'.repeat(40)}\n\n${plan}\n\n🥊 How it works: Models take opposing positions, argue their cases, provide rebuttals, and engage in intellectual combat to explore all angles of complex problems.`;
|
|
90
129
|
});
|
|
91
130
|
// Template-based modes
|
|
92
131
|
const templateModes = [
|
|
@@ -2,17 +2,42 @@
|
|
|
2
2
|
* FocusDeep Mode - Ultimate reasoning combining Sequential Thinking + Multi-Model
|
|
3
3
|
* Extracted from server.ts (Phase 2: SOLID refactoring)
|
|
4
4
|
* Wraps existing focus-deep.ts functionality
|
|
5
|
+
*
|
|
6
|
+
* Supports two modes:
|
|
7
|
+
* - executeNow: false - Returns plan visualization (current behavior)
|
|
8
|
+
* - executeNow: true - Actual execution handled by FocusExecutionService in FocusTool.service.ts
|
|
5
9
|
*/
|
|
6
10
|
import { createFocusDeepPlan, generateFocusDeepVisualization } from '../../../../focus-deep.js';
|
|
7
11
|
export class FocusDeepMode {
|
|
8
12
|
constructor() {
|
|
9
13
|
this.modeName = 'focus-deep';
|
|
10
14
|
this.description = 'Ultimate reasoning combining Sequential Thinking + Multi-Model orchestration';
|
|
15
|
+
this.supportsExecution = true;
|
|
11
16
|
}
|
|
12
17
|
async execute(params) {
|
|
13
18
|
const query = params.query;
|
|
14
19
|
const domain = params.domain;
|
|
20
|
+
const executeNow = params.executeNow;
|
|
21
|
+
// Create the plan (needed for both visualization and execution metadata)
|
|
15
22
|
const plan = createFocusDeepPlan(query, domain);
|
|
23
|
+
// If executeNow is explicitly false, return plan visualization only
|
|
24
|
+
// (executeNow: true is handled by FocusExecutionService in FocusTool.service.ts)
|
|
25
|
+
if (executeNow === false) {
|
|
26
|
+
const viz = generateFocusDeepVisualization(plan);
|
|
27
|
+
return {
|
|
28
|
+
output: viz,
|
|
29
|
+
metadata: {
|
|
30
|
+
mode: this.modeName,
|
|
31
|
+
sessionId: plan.sessionId,
|
|
32
|
+
models: plan.availableModels,
|
|
33
|
+
estimatedThoughts: plan.estimatedThoughts,
|
|
34
|
+
executeNow: false
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
// Default: return plan visualization
|
|
39
|
+
// Note: When executeNow is true and FocusExecutionService is available,
|
|
40
|
+
// the request is intercepted by FocusTool.service.ts before reaching here
|
|
16
41
|
const viz = generateFocusDeepVisualization(plan);
|
|
17
42
|
return {
|
|
18
43
|
output: viz,
|
|
@@ -125,6 +125,7 @@ export const CURRENT_MODELS = {
|
|
|
125
125
|
brainstorm: OPENAI_MODELS.DEFAULT, // Creative ideation (gpt-5.2 + effort=medium)
|
|
126
126
|
code: OPENAI_MODELS.DEFAULT, // Code tasks (gpt-5.2 + effort=medium)
|
|
127
127
|
explain: OPENAI_MODELS.DEFAULT, // Explanations (gpt-5.2 + effort=low)
|
|
128
|
+
search: OPENAI_MODELS.DEFAULT, // Web search (gpt-5.2 + web_search tool)
|
|
128
129
|
// Premium option for opt-in (use sparingly - 12x more expensive)
|
|
129
130
|
premium: OPENAI_MODELS.PRO, // Expert mode (gpt-5.2-pro - 88.4% GPQA, $21/$168)
|
|
130
131
|
},
|
|
@@ -175,6 +176,12 @@ export const TOOL_DEFAULTS = {
|
|
|
175
176
|
maxTokens: 1500,
|
|
176
177
|
temperature: 0.7,
|
|
177
178
|
},
|
|
179
|
+
openai_search: {
|
|
180
|
+
model: CURRENT_MODELS.openai.search,
|
|
181
|
+
reasoning_effort: OPENAI_REASONING.LOW,
|
|
182
|
+
maxTokens: 6000,
|
|
183
|
+
temperature: 0.3,
|
|
184
|
+
},
|
|
178
185
|
// Gemini tools
|
|
179
186
|
gemini_brainstorm: {
|
|
180
187
|
model: CURRENT_MODELS.gemini.default,
|
package/dist/src/focus-deep.js
CHANGED
|
@@ -243,3 +243,37 @@ export function canRunFocusDeep() {
|
|
|
243
243
|
quality
|
|
244
244
|
};
|
|
245
245
|
}
|
|
246
|
+
/**
|
|
247
|
+
* Execute a Focus-Deep step with actual tool execution
|
|
248
|
+
* Uses ToolExecutionService for model calls
|
|
249
|
+
*/
|
|
250
|
+
export async function executeFocusDeepStepWithTools(step, context, toolService) {
|
|
251
|
+
const startTime = Date.now();
|
|
252
|
+
// Build the full prompt with context
|
|
253
|
+
let fullPrompt = context;
|
|
254
|
+
if (step.reasoning) {
|
|
255
|
+
fullPrompt += `\n\n**Why this step**: ${step.reasoning}`;
|
|
256
|
+
}
|
|
257
|
+
fullPrompt += `\n\n**Task**: ${step.prompt}`;
|
|
258
|
+
try {
|
|
259
|
+
// Execute using the tool service
|
|
260
|
+
// Import ReasoningMode dynamically to avoid circular dependency
|
|
261
|
+
const { ReasoningMode } = await import("./reasoning-chain.js");
|
|
262
|
+
const output = await toolService.executeRealTool(step.model, fullPrompt, ReasoningMode.DEEP_REASONING);
|
|
263
|
+
const duration = Date.now() - startTime;
|
|
264
|
+
return {
|
|
265
|
+
output,
|
|
266
|
+
model: step.model,
|
|
267
|
+
duration
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
catch (error) {
|
|
271
|
+
const duration = Date.now() - startTime;
|
|
272
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
273
|
+
return {
|
|
274
|
+
output: `[Error executing ${step.model}: ${errorMsg}]`,
|
|
275
|
+
model: step.model,
|
|
276
|
+
duration
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
}
|
|
@@ -21,7 +21,46 @@ import { createProgressStream } from '../utils/progress-stream.js';
|
|
|
21
21
|
import { smartAPIClient } from '../utils/smart-api-client.js';
|
|
22
22
|
import { getSmartTimeout } from '../config/timeout-config.js';
|
|
23
23
|
import { execSync } from 'child_process';
|
|
24
|
-
import {
|
|
24
|
+
// import {
|
|
25
|
+
// renderTable,
|
|
26
|
+
// renderKeyValueTable,
|
|
27
|
+
// renderGradientBorderBox,
|
|
28
|
+
// renderGradientDivider,
|
|
29
|
+
// brailleBar,
|
|
30
|
+
// icons,
|
|
31
|
+
// } from '../utils/ink-renderer.js';
|
|
32
|
+
// Ink disabled - using plain text functions
|
|
33
|
+
const renderTable = (data) => {
|
|
34
|
+
if (data.length === 0)
|
|
35
|
+
return '';
|
|
36
|
+
const keys = Object.keys(data[0]);
|
|
37
|
+
const header = '| ' + keys.join(' | ') + ' |';
|
|
38
|
+
const separator = '|' + keys.map(() => '---').join('|') + '|';
|
|
39
|
+
const rows = data.map(row => '| ' + keys.map(k => row[k] || '').join(' | ') + ' |');
|
|
40
|
+
return [header, separator, ...rows].join('\n');
|
|
41
|
+
};
|
|
42
|
+
const renderKeyValueTable = (data) => {
|
|
43
|
+
return Object.entries(data).map(([k, v]) => `${k}: ${v}`).join('\n');
|
|
44
|
+
};
|
|
45
|
+
const renderGradientBorderBox = (content, _opts) => {
|
|
46
|
+
return `--- ${content} ---`;
|
|
47
|
+
};
|
|
48
|
+
const renderGradientDivider = (width = 50, _preset) => '-'.repeat(width);
|
|
49
|
+
const brailleBar = (value, max, width = 20) => {
|
|
50
|
+
const filled = Math.round((value / max) * width);
|
|
51
|
+
return '[' + '#'.repeat(filled) + '-'.repeat(width - filled) + ']';
|
|
52
|
+
};
|
|
53
|
+
const icons = {
|
|
54
|
+
search: '?',
|
|
55
|
+
brain: '*',
|
|
56
|
+
check: '+',
|
|
57
|
+
alertCircle: '!',
|
|
58
|
+
file: '#',
|
|
59
|
+
folder: '#',
|
|
60
|
+
bot: '@',
|
|
61
|
+
sparkle: '*',
|
|
62
|
+
chartBar: '|',
|
|
63
|
+
};
|
|
25
64
|
// ============================================
|
|
26
65
|
// CONSTANTS
|
|
27
66
|
// ============================================
|
package/dist/src/modes/scout.js
CHANGED
|
@@ -5,7 +5,29 @@ import { createProgressStream } from '../utils/progress-stream.js';
|
|
|
5
5
|
import { providerRouter } from '../utils/provider-router.js';
|
|
6
6
|
import { getSmartTimeout } from '../config/timeout-config.js';
|
|
7
7
|
import { execSync } from 'child_process';
|
|
8
|
-
import {
|
|
8
|
+
// import {
|
|
9
|
+
// renderKeyValueTable,
|
|
10
|
+
// renderGradientBorderBox,
|
|
11
|
+
// renderGradientDivider,
|
|
12
|
+
// icons,
|
|
13
|
+
// } from '../utils/ink-renderer.js';
|
|
14
|
+
// Ink disabled - using plain text functions
|
|
15
|
+
const renderKeyValueTable = (data) => {
|
|
16
|
+
return Object.entries(data)
|
|
17
|
+
.filter(([_, v]) => v !== undefined)
|
|
18
|
+
.map(([k, v]) => `${k}: ${v}`)
|
|
19
|
+
.join('\n');
|
|
20
|
+
};
|
|
21
|
+
const renderGradientBorderBox = (content, _opts) => {
|
|
22
|
+
return `--- ${content} ---`;
|
|
23
|
+
};
|
|
24
|
+
const renderGradientDivider = (width = 50, _preset) => '-'.repeat(width);
|
|
25
|
+
const icons = {
|
|
26
|
+
search: '?',
|
|
27
|
+
brain: '*',
|
|
28
|
+
info: 'i',
|
|
29
|
+
check: '+',
|
|
30
|
+
};
|
|
9
31
|
// Provider name constants
|
|
10
32
|
const PROVIDER_PERPLEXITY = 'perplexity';
|
|
11
33
|
const PROVIDER_GROK = 'grok';
|