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,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified AI Provider - Single interface for all OpenAI-compatible APIs
|
|
3
|
+
* Supports: OpenAI, Groq, Mistral, Gemini, OpenRouter, Together, Ollama, LMStudio
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import OpenAI from 'openai';
|
|
7
|
+
import { config } from 'dotenv';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = path.dirname(__filename);
|
|
12
|
+
config({ path: path.resolve(__dirname, '../../../.env') });
|
|
13
|
+
// Provider configurations with their base URLs
|
|
14
|
+
const PROVIDER_CONFIGS = {
|
|
15
|
+
openai: {
|
|
16
|
+
base: 'https://api.openai.com/v1',
|
|
17
|
+
key: process.env.OPENAI_API_KEY,
|
|
18
|
+
models: ['gpt-5', 'gpt-5-mini', 'gpt-5-nano']
|
|
19
|
+
},
|
|
20
|
+
gpt5: {
|
|
21
|
+
base: 'https://api.openai.com/v1', // Uses /responses endpoint internally
|
|
22
|
+
key: process.env.OPENAI_API_KEY,
|
|
23
|
+
models: ['gpt-5', 'gpt-5-mini', 'gpt-5-nano'],
|
|
24
|
+
special: true // Needs special handling
|
|
25
|
+
},
|
|
26
|
+
mistral: {
|
|
27
|
+
base: 'https://api.mistral.ai/v1',
|
|
28
|
+
key: process.env.MISTRAL_API_KEY,
|
|
29
|
+
models: ['mistral-large-latest', 'mistral-small-latest', 'codestral-latest']
|
|
30
|
+
},
|
|
31
|
+
gemini: {
|
|
32
|
+
base: 'https://generativelanguage.googleapis.com/v1beta/',
|
|
33
|
+
key: process.env.GOOGLE_API_KEY,
|
|
34
|
+
models: ['gemini-2.5-flash', 'gemini-2.5-pro', 'gemini-2.5-flash-lite']
|
|
35
|
+
},
|
|
36
|
+
openrouter: {
|
|
37
|
+
base: 'https://openrouter.ai/api/v1',
|
|
38
|
+
key: process.env.OPENROUTER_API_KEY,
|
|
39
|
+
models: ['anthropic/claude-3.5-sonnet', 'meta-llama/llama-3.1-405b', 'google/gemini-pro']
|
|
40
|
+
},
|
|
41
|
+
together: {
|
|
42
|
+
base: 'https://api.together.xyz/v1',
|
|
43
|
+
key: process.env.TOGETHER_API_KEY,
|
|
44
|
+
models: ['Meta-Llama-3.1-405B-Instruct-Turbo', 'Qwen/Qwen2.5-72B-Instruct-Turbo']
|
|
45
|
+
},
|
|
46
|
+
ollama: {
|
|
47
|
+
base: process.env.OLLAMA_BASE_URL || 'http://localhost:11434/v1',
|
|
48
|
+
key: 'ollama', // Ollama doesn't need an API key
|
|
49
|
+
models: ['llama3.3', 'qwen2.5', 'mistral', 'gemma2']
|
|
50
|
+
},
|
|
51
|
+
lmstudio: {
|
|
52
|
+
base: process.env.LMSTUDIO_BASE_URL || 'http://localhost:1234/v1',
|
|
53
|
+
key: 'lmstudio', // LMStudio doesn't need an API key
|
|
54
|
+
models: ['local-model'] // Depends on what's loaded
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Check if a provider is available (has API key configured)
|
|
59
|
+
*/
|
|
60
|
+
export function isProviderAvailable(provider) {
|
|
61
|
+
const config = PROVIDER_CONFIGS[provider];
|
|
62
|
+
if (!config)
|
|
63
|
+
return false;
|
|
64
|
+
// Local providers are always available
|
|
65
|
+
if (provider === 'ollama' || provider === 'lmstudio') {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
return !!config.key;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get available providers
|
|
72
|
+
*/
|
|
73
|
+
export function getAvailableProviders() {
|
|
74
|
+
return Object.keys(PROVIDER_CONFIGS)
|
|
75
|
+
.filter(p => isProviderAvailable(p));
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Unified AI query function
|
|
79
|
+
*/
|
|
80
|
+
export async function queryAI(prompt, options) {
|
|
81
|
+
const config = PROVIDER_CONFIGS[options.provider];
|
|
82
|
+
if (!config) {
|
|
83
|
+
throw new Error(`Unknown provider: ${options.provider}`);
|
|
84
|
+
}
|
|
85
|
+
if (!isProviderAvailable(options.provider)) {
|
|
86
|
+
throw new Error(`Provider ${options.provider} is not configured. Please set the appropriate API key.`);
|
|
87
|
+
}
|
|
88
|
+
// Handle GPT-5 special case
|
|
89
|
+
if (options.provider === 'gpt5' && 'special' in config && config.special) {
|
|
90
|
+
return await handleGPT5(prompt, options);
|
|
91
|
+
}
|
|
92
|
+
// Standard OpenAI-compatible handling
|
|
93
|
+
const client = new OpenAI({
|
|
94
|
+
apiKey: config.key,
|
|
95
|
+
baseURL: config.base
|
|
96
|
+
});
|
|
97
|
+
const model = options.model || config.models[0];
|
|
98
|
+
try {
|
|
99
|
+
const response = await client.chat.completions.create({
|
|
100
|
+
model,
|
|
101
|
+
messages: [
|
|
102
|
+
...(options.systemPrompt ? [{ role: 'system', content: options.systemPrompt }] : []),
|
|
103
|
+
{ role: 'user', content: prompt }
|
|
104
|
+
],
|
|
105
|
+
temperature: options.temperature ?? 0.7,
|
|
106
|
+
max_tokens: options.maxTokens ?? 2000,
|
|
107
|
+
stream: false // Always false for now to avoid streaming complexity
|
|
108
|
+
});
|
|
109
|
+
return response.choices[0]?.message?.content || 'No response generated';
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
113
|
+
console.error(`Error with ${options.provider}:`, errorMessage);
|
|
114
|
+
throw new Error(`${options.provider} API error: ${errorMessage}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Special handling for GPT-5 (uses /responses endpoint)
|
|
119
|
+
*/
|
|
120
|
+
async function handleGPT5(prompt, options) {
|
|
121
|
+
const config = PROVIDER_CONFIGS.gpt5;
|
|
122
|
+
const endpoint = 'https://api.openai.com/v1/responses';
|
|
123
|
+
const model = options.model || 'gpt-5-nano'; // Default to cheapest
|
|
124
|
+
const requestBody = {
|
|
125
|
+
model,
|
|
126
|
+
input: prompt,
|
|
127
|
+
reasoning: {
|
|
128
|
+
effort: model === 'gpt-5' ? 'high' : 'low'
|
|
129
|
+
},
|
|
130
|
+
text: {
|
|
131
|
+
verbosity: 'medium'
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
try {
|
|
135
|
+
const response = await fetch(endpoint, {
|
|
136
|
+
method: 'POST',
|
|
137
|
+
headers: {
|
|
138
|
+
'Content-Type': 'application/json',
|
|
139
|
+
'Authorization': `Bearer ${config.key}`
|
|
140
|
+
},
|
|
141
|
+
body: JSON.stringify(requestBody)
|
|
142
|
+
});
|
|
143
|
+
if (!response.ok) {
|
|
144
|
+
const error = await response.text();
|
|
145
|
+
throw new Error(`GPT-5 API error: ${error}`);
|
|
146
|
+
}
|
|
147
|
+
const data = await response.json();
|
|
148
|
+
return data.output || data.response || 'No response generated';
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
console.error('GPT-5 error:', error);
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Mode-specific wrappers
|
|
157
|
+
*/
|
|
158
|
+
export async function analyzeWithAI(content, provider, analysisType = 'code') {
|
|
159
|
+
const prompts = {
|
|
160
|
+
code: `Analyze this code for quality, bugs, and improvements:\n\n${content}`,
|
|
161
|
+
text: `Analyze this text for clarity, structure, and key points:\n\n${content}`,
|
|
162
|
+
security: `Analyze this code for security vulnerabilities:\n\n${content}`,
|
|
163
|
+
performance: `Analyze this code for performance issues:\n\n${content}`
|
|
164
|
+
};
|
|
165
|
+
return queryAI(prompts[analysisType], {
|
|
166
|
+
provider,
|
|
167
|
+
mode: 'analyze',
|
|
168
|
+
temperature: 0.3 // Lower temperature for analysis
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
export async function generateCode(requirements, provider, language) {
|
|
172
|
+
const prompt = language
|
|
173
|
+
? `Generate ${language} code for: ${requirements}`
|
|
174
|
+
: `Generate code for: ${requirements}`;
|
|
175
|
+
return queryAI(prompt, {
|
|
176
|
+
provider,
|
|
177
|
+
mode: 'code',
|
|
178
|
+
temperature: 0.5,
|
|
179
|
+
systemPrompt: 'You are an expert programmer. Generate clean, efficient, well-commented code.'
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
export function getUnifiedAITools() {
|
|
183
|
+
const availableProviders = getAvailableProviders();
|
|
184
|
+
if (availableProviders.length === 0) {
|
|
185
|
+
console.error('⚠️ No AI providers configured. Please set API keys in .env');
|
|
186
|
+
return [];
|
|
187
|
+
}
|
|
188
|
+
return [
|
|
189
|
+
{
|
|
190
|
+
name: 'ai',
|
|
191
|
+
description: 'Query any AI model',
|
|
192
|
+
parameters: z.object({
|
|
193
|
+
prompt: z.string(),
|
|
194
|
+
provider: z.enum(availableProviders).optional(),
|
|
195
|
+
model: z.string().optional(),
|
|
196
|
+
mode: z.enum(['chat', 'complete', 'reason', 'analyze', 'code']).optional(),
|
|
197
|
+
temperature: z.number().min(0).max(2).optional(),
|
|
198
|
+
maxTokens: z.number().min(1).max(100000).optional()
|
|
199
|
+
}),
|
|
200
|
+
execute: async (args, context) => {
|
|
201
|
+
const typedArgs = args;
|
|
202
|
+
const provider = typedArgs.provider || availableProviders[0];
|
|
203
|
+
return await queryAI(typedArgs.prompt, {
|
|
204
|
+
provider,
|
|
205
|
+
model: typedArgs.model,
|
|
206
|
+
mode: typedArgs.mode,
|
|
207
|
+
temperature: typedArgs.temperature,
|
|
208
|
+
maxTokens: typedArgs.maxTokens
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
name: 'ai_analyze',
|
|
214
|
+
description: 'Analyze code or text',
|
|
215
|
+
parameters: z.object({
|
|
216
|
+
content: z.string(),
|
|
217
|
+
type: z.enum(['code', 'text', 'security', 'performance']),
|
|
218
|
+
provider: z.enum(availableProviders).optional()
|
|
219
|
+
}),
|
|
220
|
+
execute: async (args, context) => {
|
|
221
|
+
const typedArgs = args;
|
|
222
|
+
const provider = typedArgs.provider || availableProviders[0];
|
|
223
|
+
return await analyzeWithAI(typedArgs.content, provider, typedArgs.type);
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
name: 'ai_code',
|
|
228
|
+
description: 'Generate code',
|
|
229
|
+
parameters: z.object({
|
|
230
|
+
requirements: z.string(),
|
|
231
|
+
language: z.string().optional(),
|
|
232
|
+
provider: z.enum(availableProviders).optional()
|
|
233
|
+
}),
|
|
234
|
+
execute: async (args, context) => {
|
|
235
|
+
const typedArgs = args;
|
|
236
|
+
const provider = typedArgs.provider || availableProviders[0];
|
|
237
|
+
return await generateCode(typedArgs.requirements, provider, typedArgs.language);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
];
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* List available models for a provider
|
|
244
|
+
*/
|
|
245
|
+
export function listModels(provider) {
|
|
246
|
+
return PROVIDER_CONFIGS[provider]?.models || [];
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Get provider info
|
|
250
|
+
*/
|
|
251
|
+
export function getProviderInfo() {
|
|
252
|
+
const info = {};
|
|
253
|
+
for (const [provider, config] of Object.entries(PROVIDER_CONFIGS)) {
|
|
254
|
+
info[provider] = {
|
|
255
|
+
available: isProviderAvailable(provider),
|
|
256
|
+
models: config.models
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
return info;
|
|
260
|
+
}
|
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Runner Tool - Execute custom workflows via MCP
|
|
3
|
+
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { workflowEngine } from '../workflows/custom-workflows.js';
|
|
6
|
+
import * as yaml from 'yaml';
|
|
7
|
+
import { isToolEnabled } from '../utils/tool-config.js';
|
|
8
|
+
/**
|
|
9
|
+
* Register workflow tools with the MCP server
|
|
10
|
+
*/
|
|
11
|
+
export function registerWorkflowTools(server) {
|
|
12
|
+
const tools = [];
|
|
13
|
+
// Tool to execute workflows (by name or from file)
|
|
14
|
+
tools.push({
|
|
15
|
+
name: 'workflow',
|
|
16
|
+
description: 'Execute workflows',
|
|
17
|
+
parameters: z.object({
|
|
18
|
+
name: z.string().optional(),
|
|
19
|
+
file: z.string().optional(),
|
|
20
|
+
query: z.string(),
|
|
21
|
+
projectPath: z.string().optional(),
|
|
22
|
+
truncateSteps: z.boolean().optional(),
|
|
23
|
+
maxStepTokens: z.number().optional(),
|
|
24
|
+
}),
|
|
25
|
+
execute: async (args) => {
|
|
26
|
+
try {
|
|
27
|
+
// Validation: must specify exactly one
|
|
28
|
+
if (!args.name && !args.file) {
|
|
29
|
+
return "❌ Error: Must specify either 'name' or 'file' parameter\n\nExamples:\n workflow --name code-review --query 'input'\n workflow --file ./custom.yaml --query 'input'";
|
|
30
|
+
}
|
|
31
|
+
if (args.name && args.file) {
|
|
32
|
+
return "❌ Error: Cannot use both 'name' and 'file' parameters\n\nUse one or the other.";
|
|
33
|
+
}
|
|
34
|
+
let result;
|
|
35
|
+
if (args.file) {
|
|
36
|
+
// File-based execution (ad-hoc)
|
|
37
|
+
console.error(`🚀 Executing workflow from file: ${args.file}`);
|
|
38
|
+
result = await workflowEngine.loadAndExecuteWorkflowFile(args.file, args.query, {
|
|
39
|
+
variables: { query: args.query },
|
|
40
|
+
truncateSteps: args.truncateSteps,
|
|
41
|
+
maxStepTokens: args.maxStepTokens,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
// Named workflow execution (discovery-based)
|
|
46
|
+
console.error(`🚀 Executing named workflow: ${args.name}`);
|
|
47
|
+
result = await workflowEngine.executeWorkflow(args.name, args.query, {
|
|
48
|
+
variables: { query: args.query },
|
|
49
|
+
truncateSteps: args.truncateSteps,
|
|
50
|
+
maxStepTokens: args.maxStepTokens,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
// ALWAYS format as string for Claude Code display
|
|
54
|
+
// Format result for readability
|
|
55
|
+
if (typeof result === 'string') {
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
// Format detailed workflow results
|
|
59
|
+
if (typeof result === 'object' && result !== null && 'steps' in result) {
|
|
60
|
+
const detailed = result;
|
|
61
|
+
// Determine truncation settings
|
|
62
|
+
// Default: truncate enabled, 2500 tokens (~10k chars)
|
|
63
|
+
const truncate = args.truncateSteps ?? true;
|
|
64
|
+
const maxTokens = args.maxStepTokens ?? 2500;
|
|
65
|
+
const maxChars = maxTokens * 4; // 1 token ≈ 4 chars
|
|
66
|
+
let output = `# Workflow: ${detailed.workflow}\n\n`;
|
|
67
|
+
output += `**Duration:** ${(detailed.duration / 1000).toFixed(1)}s\n`;
|
|
68
|
+
output += `**Steps Completed:** ${detailed.steps.length}\n\n`;
|
|
69
|
+
output += `---\n\n`;
|
|
70
|
+
// Format each step's output
|
|
71
|
+
for (let i = 0; i < detailed.steps.length; i++) {
|
|
72
|
+
const step = detailed.steps[i];
|
|
73
|
+
output += `## Step ${i + 1}: ${step.step}\n\n`;
|
|
74
|
+
// Format the step output - keep it clean and readable
|
|
75
|
+
let stepOutput = step.output;
|
|
76
|
+
// Truncate based on settings
|
|
77
|
+
if (truncate && typeof stepOutput === 'string' && stepOutput.length > maxChars) {
|
|
78
|
+
const approxTokens = Math.floor(stepOutput.length / 4);
|
|
79
|
+
output += stepOutput.substring(0, maxChars) +
|
|
80
|
+
'\n\n...(output truncated: ~' + approxTokens + ' tokens, limit: ' + maxTokens + ' tokens. Use truncateSteps=false for full output)...\n\n';
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
output += `${stepOutput}\n\n`;
|
|
84
|
+
}
|
|
85
|
+
output += `---\n\n`;
|
|
86
|
+
}
|
|
87
|
+
// Add final summary footer
|
|
88
|
+
output += `\n**Workflow Complete** ✓\n`;
|
|
89
|
+
return output;
|
|
90
|
+
}
|
|
91
|
+
// Fallback for any other object type
|
|
92
|
+
return JSON.stringify(result, null, 2);
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
return `Workflow execution failed: ${error.message}`;
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
// Tool to list all workflows
|
|
100
|
+
tools.push({
|
|
101
|
+
name: 'list_workflows',
|
|
102
|
+
description: 'List workflows',
|
|
103
|
+
parameters: z.object({
|
|
104
|
+
projectPath: z.string().optional(),
|
|
105
|
+
}),
|
|
106
|
+
execute: async (args) => {
|
|
107
|
+
const workflows = workflowEngine.listWorkflows();
|
|
108
|
+
const errors = workflowEngine.getValidationErrors();
|
|
109
|
+
let output = '';
|
|
110
|
+
// Show successful workflows
|
|
111
|
+
if (workflows.length > 0) {
|
|
112
|
+
const formatted = workflows.map(w => `• ${w.name}: ${w.description || 'No description'} (${w.steps} steps)`).join('\n');
|
|
113
|
+
output += `Available Workflows:\n\n${formatted}\n\nUse 'workflow' tool to execute any of these.\n`;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
output += `No workflows available.\n`;
|
|
117
|
+
}
|
|
118
|
+
// Show validation errors if any
|
|
119
|
+
if (errors.length > 0) {
|
|
120
|
+
output += `\n⚠️ Validation Errors (${errors.length} files failed to load):\n\n`;
|
|
121
|
+
errors.forEach(err => {
|
|
122
|
+
output += `❌ [${err.source}] ${err.file}\n`;
|
|
123
|
+
output += ` Error: ${err.error}\n\n`;
|
|
124
|
+
});
|
|
125
|
+
output += `Fix these files to make them available.\n`;
|
|
126
|
+
}
|
|
127
|
+
return output;
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
// Tool to create a new workflow
|
|
131
|
+
tools.push({
|
|
132
|
+
name: 'create_workflow',
|
|
133
|
+
description: 'Create workflow',
|
|
134
|
+
parameters: z.object({
|
|
135
|
+
name: z.string(),
|
|
136
|
+
type: z.enum(['code-review', 'brainstorm', 'debug', 'research', 'custom']),
|
|
137
|
+
steps: z.string().optional(),
|
|
138
|
+
}),
|
|
139
|
+
execute: async (args) => {
|
|
140
|
+
try {
|
|
141
|
+
let workflow;
|
|
142
|
+
// Create based on template
|
|
143
|
+
switch (args.type) {
|
|
144
|
+
case 'code-review':
|
|
145
|
+
workflow = {
|
|
146
|
+
name: args.name,
|
|
147
|
+
description: 'Custom code review workflow',
|
|
148
|
+
version: '1.0',
|
|
149
|
+
settings: {
|
|
150
|
+
optimization: {
|
|
151
|
+
enabled: true,
|
|
152
|
+
cacheResults: true,
|
|
153
|
+
compressPrompts: true,
|
|
154
|
+
smartRouting: true,
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
steps: [
|
|
158
|
+
{ name: 'analyze', tool: 'gemini_analyze_code', input: { prompt: 'Analyze code' } },
|
|
159
|
+
{ name: 'review', tool: 'grok_code', input: { prompt: 'Review for best practices' } },
|
|
160
|
+
{ name: 'suggest', tool: 'ai', input: { prompt: 'Suggest improvements' }, model: 'openai' },
|
|
161
|
+
],
|
|
162
|
+
};
|
|
163
|
+
break;
|
|
164
|
+
case 'brainstorm':
|
|
165
|
+
workflow = {
|
|
166
|
+
name: args.name,
|
|
167
|
+
description: 'Custom brainstorming workflow',
|
|
168
|
+
version: '1.0',
|
|
169
|
+
settings: {},
|
|
170
|
+
steps: [
|
|
171
|
+
{ name: 'ideate', tool: 'gemini_brainstorm', input: { prompt: 'Generate ideas' } },
|
|
172
|
+
{ name: 'expand', tool: 'openai_brainstorm', input: { prompt: 'Expand on ideas' } },
|
|
173
|
+
{ name: 'research', tool: 'scout', input: { prompt: 'Find evidence' } },
|
|
174
|
+
],
|
|
175
|
+
};
|
|
176
|
+
break;
|
|
177
|
+
case 'debug':
|
|
178
|
+
workflow = {
|
|
179
|
+
name: args.name,
|
|
180
|
+
description: 'Custom debugging workflow',
|
|
181
|
+
version: '1.0',
|
|
182
|
+
settings: {},
|
|
183
|
+
steps: [
|
|
184
|
+
{ name: 'analyze', tool: 'grok_debug', input: { prompt: 'Analyze error' } },
|
|
185
|
+
{ name: 'trace', tool: 'grok_code', input: { prompt: 'Analyze code path' } },
|
|
186
|
+
{ name: 'fix', tool: 'ai_code', input: { prompt: 'Suggest fix' } },
|
|
187
|
+
],
|
|
188
|
+
};
|
|
189
|
+
break;
|
|
190
|
+
case 'research':
|
|
191
|
+
workflow = {
|
|
192
|
+
name: args.name,
|
|
193
|
+
description: 'Custom research workflow',
|
|
194
|
+
version: '1.0',
|
|
195
|
+
settings: {},
|
|
196
|
+
steps: [
|
|
197
|
+
{ name: 'search', tool: 'perplexity_ask', input: { prompt: 'Initial research' } },
|
|
198
|
+
{ name: 'analyze', tool: 'ai_analyze', input: { prompt: 'Analyze findings' } },
|
|
199
|
+
{ name: 'verify', tool: 'verifier', input: { prompt: 'Verify facts' } },
|
|
200
|
+
{ name: 'synthesize', tool: 'focus', input: { prompt: 'Synthesize results' } },
|
|
201
|
+
],
|
|
202
|
+
};
|
|
203
|
+
break;
|
|
204
|
+
case 'custom':
|
|
205
|
+
if (!args.steps) {
|
|
206
|
+
return 'Custom workflow requires steps in YAML or JSON format';
|
|
207
|
+
}
|
|
208
|
+
try {
|
|
209
|
+
const stepsData = args.steps.trim().startsWith('{')
|
|
210
|
+
? JSON.parse(args.steps)
|
|
211
|
+
: yaml.parse(args.steps);
|
|
212
|
+
workflow = {
|
|
213
|
+
name: args.name,
|
|
214
|
+
description: 'Custom workflow',
|
|
215
|
+
version: '1.0',
|
|
216
|
+
settings: {},
|
|
217
|
+
steps: stepsData.steps || stepsData,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
return `Failed to parse custom steps: ${error}`;
|
|
222
|
+
}
|
|
223
|
+
break;
|
|
224
|
+
default:
|
|
225
|
+
return `Unknown workflow type: ${args.type}`;
|
|
226
|
+
}
|
|
227
|
+
// Save the workflow
|
|
228
|
+
await workflowEngine.saveWorkflow(workflow, 'yaml');
|
|
229
|
+
return `✅ Created workflow '${args.name}' successfully!
|
|
230
|
+
|
|
231
|
+
To use it: workflow --name ${args.name} --query "your input"
|
|
232
|
+
|
|
233
|
+
Workflow saved to: .tachi/workflows/${args.name}.yaml`;
|
|
234
|
+
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
return `Failed to create workflow: ${error.message}`;
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
});
|
|
240
|
+
// Tool to visualize workflow
|
|
241
|
+
tools.push({
|
|
242
|
+
name: 'visualize_workflow',
|
|
243
|
+
description: 'Visualize workflow',
|
|
244
|
+
parameters: z.object({
|
|
245
|
+
name: z.string(),
|
|
246
|
+
}),
|
|
247
|
+
execute: async (args) => {
|
|
248
|
+
const workflow = workflowEngine.getWorkflow(args.name);
|
|
249
|
+
if (!workflow) {
|
|
250
|
+
return `Workflow '${args.name}' not found`;
|
|
251
|
+
}
|
|
252
|
+
// Create ASCII visualization
|
|
253
|
+
let viz = `
|
|
254
|
+
┌─────────────────────────────────────┐
|
|
255
|
+
│ Workflow: ${workflow.name.padEnd(25)}│
|
|
256
|
+
└─────────────────────────────────────┘
|
|
257
|
+
|
|
258
|
+
${workflow.description || 'No description'}
|
|
259
|
+
|
|
260
|
+
Settings:
|
|
261
|
+
• Optimization: ${workflow.settings?.optimization?.enabled ? '✅' : '❌'}
|
|
262
|
+
• Smart Routing: ${workflow.settings?.optimization?.smartRouting ? '✅' : '❌'}
|
|
263
|
+
|
|
264
|
+
Steps:
|
|
265
|
+
`;
|
|
266
|
+
for (let i = 0; i < workflow.steps.length; i++) {
|
|
267
|
+
const step = workflow.steps[i];
|
|
268
|
+
const isLast = i === workflow.steps.length - 1;
|
|
269
|
+
const prefix = isLast ? '└──' : '├──';
|
|
270
|
+
const connector = isLast ? ' ' : '│ ';
|
|
271
|
+
viz += `${prefix} ${i + 1}. ${step.name}\n`;
|
|
272
|
+
viz += `${connector} Tool: ${step.tool}\n`;
|
|
273
|
+
if (step.model)
|
|
274
|
+
viz += `${connector} Model: ${step.model}\n`;
|
|
275
|
+
if (step.parallel)
|
|
276
|
+
viz += `${connector} ⚡ Runs in parallel\n`;
|
|
277
|
+
if (step.condition)
|
|
278
|
+
viz += `${connector} ⚠️ Conditional\n`;
|
|
279
|
+
viz += '\n';
|
|
280
|
+
}
|
|
281
|
+
return viz;
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
// Tool to start workflow step-by-step (streaming mode)
|
|
285
|
+
tools.push({
|
|
286
|
+
name: 'workflow_start',
|
|
287
|
+
description: 'Start workflow session',
|
|
288
|
+
parameters: z.object({
|
|
289
|
+
name: z.string(),
|
|
290
|
+
query: z.string(),
|
|
291
|
+
variables: z.record(z.union([z.string(), z.number(), z.boolean()])).optional(),
|
|
292
|
+
}),
|
|
293
|
+
execute: async (args) => {
|
|
294
|
+
try {
|
|
295
|
+
console.error(`🚀 Starting streaming workflow: ${args.name}`);
|
|
296
|
+
const result = await workflowEngine.startWorkflowStepByStep(args.name, args.query, { variables: args.variables });
|
|
297
|
+
const totalSteps = workflowEngine.getWorkflow(args.name)?.steps.length || '?';
|
|
298
|
+
const r = result;
|
|
299
|
+
return `# Workflow Started: ${args.name}
|
|
300
|
+
|
|
301
|
+
**Session ID:** \`${r.sessionId}\`
|
|
302
|
+
|
|
303
|
+
✅ Step ${r.step}/${totalSteps}: **${r.stepName}**
|
|
304
|
+
|
|
305
|
+
${r.output}
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
${r.hasMore ? `⏭️ **Next:** Use \`continue_workflow\` with session ID \`${r.sessionId}\` to execute step ${r.step + 1}` : '✓ Workflow complete!'}`;
|
|
310
|
+
}
|
|
311
|
+
catch (error) {
|
|
312
|
+
return `Failed to start workflow: ${error.message}`;
|
|
313
|
+
}
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
// Tool to continue workflow execution
|
|
317
|
+
tools.push({
|
|
318
|
+
name: 'continue_workflow',
|
|
319
|
+
description: 'Continue workflow',
|
|
320
|
+
parameters: z.object({
|
|
321
|
+
sessionId: z.string(),
|
|
322
|
+
}),
|
|
323
|
+
execute: async (args) => {
|
|
324
|
+
try {
|
|
325
|
+
const result = await workflowEngine.continueWorkflow(args.sessionId);
|
|
326
|
+
// Get workflow info for context
|
|
327
|
+
const session = workflowEngine.sessions?.get(args.sessionId);
|
|
328
|
+
const workflowName = session?.workflowName || 'unknown';
|
|
329
|
+
const totalSteps = session?.workflow?.steps.length || '?';
|
|
330
|
+
const r = result;
|
|
331
|
+
if (!r.hasMore) {
|
|
332
|
+
return `# Workflow Complete: ${workflowName}
|
|
333
|
+
|
|
334
|
+
**Session ID:** \`${r.sessionId}\`
|
|
335
|
+
|
|
336
|
+
✅ All steps completed!
|
|
337
|
+
|
|
338
|
+
Final output from step ${r.step}:
|
|
339
|
+
|
|
340
|
+
${r.output}
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
✓ Workflow finished successfully`;
|
|
345
|
+
}
|
|
346
|
+
return `# Workflow Progress: ${workflowName}
|
|
347
|
+
|
|
348
|
+
**Session ID:** \`${r.sessionId}\`
|
|
349
|
+
|
|
350
|
+
✅ Step ${r.step}/${totalSteps}: **${r.stepName}**
|
|
351
|
+
|
|
352
|
+
${r.output}
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
⏭️ **Next:** Call \`continue_workflow\` with session ID \`${r.sessionId}\` to execute step ${r.step + 1}`;
|
|
357
|
+
}
|
|
358
|
+
catch (error) {
|
|
359
|
+
return `Failed to continue workflow: ${error.message}`;
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
});
|
|
363
|
+
// Tool to check workflow session status
|
|
364
|
+
tools.push({
|
|
365
|
+
name: 'workflow_status',
|
|
366
|
+
description: 'Workflow status',
|
|
367
|
+
parameters: z.object({
|
|
368
|
+
sessionId: z.string(),
|
|
369
|
+
}),
|
|
370
|
+
execute: async (args) => {
|
|
371
|
+
try {
|
|
372
|
+
// Access internal session state (type assertion to access private members)
|
|
373
|
+
const session = workflowEngine.sessions?.get(args.sessionId);
|
|
374
|
+
if (!session) {
|
|
375
|
+
return `❌ Session '${args.sessionId}' not found. It may have completed or expired.`;
|
|
376
|
+
}
|
|
377
|
+
const totalSteps = session.workflow.steps.length;
|
|
378
|
+
const currentStep = session.currentStepIndex + 1;
|
|
379
|
+
const completed = session.currentStepIndex;
|
|
380
|
+
const remaining = totalSteps - completed;
|
|
381
|
+
const duration = ((Date.now() - session.startTime) / 1000).toFixed(1);
|
|
382
|
+
return `# Workflow Session Status
|
|
383
|
+
|
|
384
|
+
**Workflow:** ${session.workflowName}
|
|
385
|
+
**Session ID:** \`${args.sessionId}\`
|
|
386
|
+
**Status:** Running
|
|
387
|
+
|
|
388
|
+
**Progress:** ${completed}/${totalSteps} steps completed
|
|
389
|
+
**Current Step:** ${currentStep} - ${session.workflow.steps[session.currentStepIndex]?.name || 'N/A'}
|
|
390
|
+
**Remaining:** ${remaining} steps
|
|
391
|
+
**Duration:** ${duration}s
|
|
392
|
+
|
|
393
|
+
**Latest Output:**
|
|
394
|
+
${session.previousOutput?.substring(0, 500) || 'No output yet'}${session.previousOutput?.length > 500 ? '...' : ''}
|
|
395
|
+
|
|
396
|
+
Use \`continue_workflow\` to execute the next step.`;
|
|
397
|
+
}
|
|
398
|
+
catch (error) {
|
|
399
|
+
return `Failed to get workflow status: ${error.message}`;
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
});
|
|
403
|
+
// Register tools with server (with profile filtering)
|
|
404
|
+
tools.forEach(tool => {
|
|
405
|
+
try {
|
|
406
|
+
// Check if tool is enabled in profile
|
|
407
|
+
if (!isToolEnabled(tool.name)) {
|
|
408
|
+
return; // Skip disabled tools
|
|
409
|
+
}
|
|
410
|
+
server.addTool(tool);
|
|
411
|
+
}
|
|
412
|
+
catch (error) {
|
|
413
|
+
console.error(`Failed to register tool ${tool.name}:`, error);
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
console.error('✅ Registered workflow tools:');
|
|
417
|
+
console.error(' - workflow: Execute complete workflows (all steps at once)');
|
|
418
|
+
console.error(' - workflow_start: Start streaming workflow (step-by-step mode)');
|
|
419
|
+
console.error(' - continue_workflow: Execute next step in streaming workflow');
|
|
420
|
+
console.error(' - workflow_status: Check progress of streaming workflow');
|
|
421
|
+
console.error(' - list_workflows: List available workflows');
|
|
422
|
+
console.error(' - create_workflow: Create new workflow from template');
|
|
423
|
+
console.error(' - visualize_workflow: Show workflow structure');
|
|
424
|
+
return tools;
|
|
425
|
+
}
|