agentic-flow 1.1.12 → 1.1.13
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/README.md
CHANGED
|
@@ -70,7 +70,7 @@ npx agentic-flow --list
|
|
|
70
70
|
Access 213 MCP tools for memory, swarms, GitHub, neural networks, and cloud sandboxes:
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
|
-
# Start all MCP servers (213 tools)
|
|
73
|
+
# Start all MCP servers (213 tools) - stdio transport
|
|
74
74
|
npx agentic-flow mcp start
|
|
75
75
|
|
|
76
76
|
# List all available tools
|
|
@@ -84,7 +84,24 @@ export ENABLE_CLAUDE_FLOW_SDK=true
|
|
|
84
84
|
npx agentic-flow --agent coder --task "Store config in memory using memory_store"
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
+
**MCP Transports:**
|
|
88
|
+
- **stdio** (default): Standard input/output for Claude Desktop integration
|
|
89
|
+
- **HTTP/SSE** (new): HTTP server with Server-Sent Events for web apps
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# Start HTTP/SSE server on port 8080
|
|
93
|
+
npm run mcp:http
|
|
94
|
+
# Endpoints:
|
|
95
|
+
# - HTTP: http://localhost:8080/mcp
|
|
96
|
+
# - SSE: http://localhost:8080/sse
|
|
97
|
+
# - Health: http://localhost:8080/health
|
|
98
|
+
|
|
99
|
+
# Start stdio server (default)
|
|
100
|
+
npm run mcp:stdio
|
|
101
|
+
```
|
|
102
|
+
|
|
87
103
|
**MCP Tool Categories:**
|
|
104
|
+
- **Agentic Flow** (6 tools): Agent execution, creation, optimization, model selection
|
|
88
105
|
- **Claude Flow SDK** (6 tools): In-process memory and swarm coordination
|
|
89
106
|
- **Claude Flow** (101 tools): Neural networks, GitHub, workflows, performance, DAA
|
|
90
107
|
- **Flow Nexus** (96 tools): E2B sandboxes, distributed swarms, templates, storage
|
|
@@ -286,6 +303,7 @@ MCP (Model Context Protocol) tools extend agent capabilities beyond text generat
|
|
|
286
303
|
|
|
287
304
|
### Starting MCP Servers
|
|
288
305
|
|
|
306
|
+
**stdio Transport (default for Claude Desktop):**
|
|
289
307
|
```bash
|
|
290
308
|
# Start all 213 tools (4 servers)
|
|
291
309
|
npx agentic-flow mcp start
|
|
@@ -305,6 +323,24 @@ npx agentic-flow mcp status
|
|
|
305
323
|
npx agentic-flow mcp stop
|
|
306
324
|
```
|
|
307
325
|
|
|
326
|
+
**HTTP/SSE Transport (new for web applications):**
|
|
327
|
+
```bash
|
|
328
|
+
# Start HTTP/SSE MCP server on port 8080
|
|
329
|
+
npm run mcp:http
|
|
330
|
+
|
|
331
|
+
# Or manually:
|
|
332
|
+
node dist/mcp/fastmcp/servers/http-sse.js
|
|
333
|
+
|
|
334
|
+
# Server provides 3 endpoints:
|
|
335
|
+
# - http://localhost:8080/mcp (MCP protocol)
|
|
336
|
+
# - http://localhost:8080/sse (Server-Sent Events)
|
|
337
|
+
# - http://localhost:8080/health (health check)
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**When to use each transport:**
|
|
341
|
+
- **stdio**: Claude Desktop, Cursor IDE, command-line tools
|
|
342
|
+
- **HTTP/SSE**: Web apps, browser extensions, REST APIs, mobile apps
|
|
343
|
+
|
|
308
344
|
### Using MCP Tools in Agents
|
|
309
345
|
|
|
310
346
|
**Automatic (Recommended):**
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// FastMCP server with HTTP/SSE transport - All agentic-flow tools
|
|
3
|
+
// Accessible via HTTP at http://localhost:8080/mcp
|
|
4
|
+
// SSE endpoint at http://localhost:8080/sse
|
|
5
|
+
import { FastMCP } from 'fastmcp';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { execSync } from 'child_process';
|
|
8
|
+
console.error('🚀 Starting Agentic-Flow MCP Server (HTTP/SSE transport)...');
|
|
9
|
+
console.error('📦 Loading agentic-flow tools');
|
|
10
|
+
const server = new FastMCP({
|
|
11
|
+
name: 'agentic-flow-http',
|
|
12
|
+
version: '1.1.12'
|
|
13
|
+
});
|
|
14
|
+
// Tool: Run agentic-flow agent
|
|
15
|
+
server.addTool({
|
|
16
|
+
name: 'agentic_flow_agent',
|
|
17
|
+
description: 'Execute an agentic-flow agent with a specific task. Supports multiple providers (Anthropic, Gemini, OpenRouter, ONNX) and comprehensive configuration options.',
|
|
18
|
+
parameters: z.object({
|
|
19
|
+
agent: z.string().describe('Agent type (coder, researcher, analyst, etc.) - Use agentic_flow_list_agents to see all 66+ available agents'),
|
|
20
|
+
task: z.string().describe('Task description for the agent to execute'),
|
|
21
|
+
// Provider Configuration
|
|
22
|
+
model: z.string().optional().describe('Model to use (e.g., "claude-sonnet-4-5-20250929" for Anthropic, "meta-llama/llama-3.1-8b-instruct" for OpenRouter, or "Xenova/gpt2" for ONNX local models)'),
|
|
23
|
+
provider: z.enum(['anthropic', 'openrouter', 'onnx', 'gemini']).optional().describe('LLM provider: "anthropic" (default, highest quality, requires ANTHROPIC_API_KEY), "gemini" (free tier, requires GOOGLE_GEMINI_API_KEY), "openrouter" (99% cost savings, requires OPENROUTER_API_KEY), "onnx" (free local inference, no API key needed)'),
|
|
24
|
+
// API Configuration
|
|
25
|
+
anthropicApiKey: z.string().optional().describe('Anthropic API key (sk-ant-...) - overrides ANTHROPIC_API_KEY environment variable'),
|
|
26
|
+
openrouterApiKey: z.string().optional().describe('OpenRouter API key (sk-or-...) - overrides OPENROUTER_API_KEY environment variable'),
|
|
27
|
+
// Agent Behavior
|
|
28
|
+
stream: z.boolean().optional().default(false).describe('Enable streaming output (real-time response chunks)'),
|
|
29
|
+
temperature: z.number().min(0).max(1).optional().describe('Sampling temperature (0.0-1.0): lower = more focused/deterministic, higher = more creative/random. Default varies by agent.'),
|
|
30
|
+
maxTokens: z.number().positive().optional().describe('Maximum tokens in response (default: 4096). Controls output length.'),
|
|
31
|
+
// Directory Configuration
|
|
32
|
+
agentsDir: z.string().optional().describe('Custom agents directory path (default: .claude/agents) - for using custom agent definitions'),
|
|
33
|
+
// Output Options
|
|
34
|
+
outputFormat: z.enum(['text', 'json', 'markdown']).optional().describe('Output format: "text" (default, human-readable), "json" (structured data), "markdown" (formatted docs)'),
|
|
35
|
+
verbose: z.boolean().optional().default(false).describe('Enable verbose logging for debugging'),
|
|
36
|
+
// Execution Control
|
|
37
|
+
timeout: z.number().positive().optional().describe('Execution timeout in milliseconds (default: 300000 = 5 minutes)'),
|
|
38
|
+
retryOnError: z.boolean().optional().default(false).describe('Automatically retry on transient errors (rate limits, network issues)')
|
|
39
|
+
}),
|
|
40
|
+
execute: async ({ agent, task, model, provider, anthropicApiKey, openrouterApiKey, stream, temperature, maxTokens, agentsDir, outputFormat, verbose, timeout, retryOnError }) => {
|
|
41
|
+
try {
|
|
42
|
+
// Build command with all parameters
|
|
43
|
+
let cmd = `npx --yes agentic-flow --agent "${agent}" --task "${task}"`;
|
|
44
|
+
// Provider & Model
|
|
45
|
+
if (model)
|
|
46
|
+
cmd += ` --model "${model}"`;
|
|
47
|
+
if (provider)
|
|
48
|
+
cmd += ` --provider ${provider}`;
|
|
49
|
+
// API Keys (set as env vars)
|
|
50
|
+
const env = { ...process.env };
|
|
51
|
+
if (anthropicApiKey)
|
|
52
|
+
env.ANTHROPIC_API_KEY = anthropicApiKey;
|
|
53
|
+
if (openrouterApiKey)
|
|
54
|
+
env.OPENROUTER_API_KEY = openrouterApiKey;
|
|
55
|
+
// Agent Behavior
|
|
56
|
+
if (stream)
|
|
57
|
+
cmd += ' --stream';
|
|
58
|
+
if (temperature !== undefined)
|
|
59
|
+
cmd += ` --temperature ${temperature}`;
|
|
60
|
+
if (maxTokens)
|
|
61
|
+
cmd += ` --max-tokens ${maxTokens}`;
|
|
62
|
+
// Directories
|
|
63
|
+
if (agentsDir)
|
|
64
|
+
cmd += ` --agents-dir "${agentsDir}"`;
|
|
65
|
+
// Output
|
|
66
|
+
if (outputFormat)
|
|
67
|
+
cmd += ` --output ${outputFormat}`;
|
|
68
|
+
if (verbose)
|
|
69
|
+
cmd += ' --verbose';
|
|
70
|
+
// Execution
|
|
71
|
+
if (timeout)
|
|
72
|
+
cmd += ` --timeout ${timeout}`;
|
|
73
|
+
if (retryOnError)
|
|
74
|
+
cmd += ' --retry';
|
|
75
|
+
const result = execSync(cmd, {
|
|
76
|
+
encoding: 'utf-8',
|
|
77
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
78
|
+
timeout: timeout || 300000,
|
|
79
|
+
env
|
|
80
|
+
});
|
|
81
|
+
return {
|
|
82
|
+
content: [{
|
|
83
|
+
type: 'text',
|
|
84
|
+
text: JSON.stringify({
|
|
85
|
+
success: true,
|
|
86
|
+
agent,
|
|
87
|
+
provider: provider || 'anthropic',
|
|
88
|
+
output: result,
|
|
89
|
+
timestamp: new Date().toISOString()
|
|
90
|
+
}, null, 2)
|
|
91
|
+
}]
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
return {
|
|
96
|
+
content: [{
|
|
97
|
+
type: 'text',
|
|
98
|
+
text: JSON.stringify({
|
|
99
|
+
success: false,
|
|
100
|
+
agent,
|
|
101
|
+
error: error.message,
|
|
102
|
+
stderr: error.stderr?.toString(),
|
|
103
|
+
timestamp: new Date().toISOString()
|
|
104
|
+
}, null, 2)
|
|
105
|
+
}],
|
|
106
|
+
isError: true
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
// Tool: List all agents
|
|
112
|
+
server.addTool({
|
|
113
|
+
name: 'agentic_flow_list_agents',
|
|
114
|
+
description: 'List all available agentic-flow agents (66+ total)',
|
|
115
|
+
parameters: z.object({
|
|
116
|
+
format: z.enum(['summary', 'detailed', 'json']).optional().default('summary')
|
|
117
|
+
}),
|
|
118
|
+
execute: async ({ format }) => {
|
|
119
|
+
try {
|
|
120
|
+
const result = execSync('npx --yes agentic-flow --list', {
|
|
121
|
+
encoding: 'utf-8',
|
|
122
|
+
maxBuffer: 5 * 1024 * 1024,
|
|
123
|
+
timeout: 30000
|
|
124
|
+
});
|
|
125
|
+
if (format === 'detailed') {
|
|
126
|
+
return {
|
|
127
|
+
content: [{
|
|
128
|
+
type: 'text',
|
|
129
|
+
text: result
|
|
130
|
+
}]
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
// Parse agent list
|
|
134
|
+
const agents = [];
|
|
135
|
+
const lines = result.split('\n');
|
|
136
|
+
let currentCategory = '';
|
|
137
|
+
for (const line of lines) {
|
|
138
|
+
if (line.includes(':') && line.trim().endsWith(':')) {
|
|
139
|
+
currentCategory = line.replace(':', '').trim();
|
|
140
|
+
}
|
|
141
|
+
else if (line.trim().startsWith('•') || /^\s{2,}\w/.test(line)) {
|
|
142
|
+
const match = line.match(/^\s*[•\s]*(\S+)\s+(.+)$/);
|
|
143
|
+
if (match) {
|
|
144
|
+
agents.push({
|
|
145
|
+
name: match[1],
|
|
146
|
+
description: match[2].trim(),
|
|
147
|
+
category: currentCategory
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
content: [{
|
|
154
|
+
type: 'text',
|
|
155
|
+
text: JSON.stringify({
|
|
156
|
+
success: true,
|
|
157
|
+
count: agents.length,
|
|
158
|
+
agents: format === 'json' ? agents : agents.map(a => a.name),
|
|
159
|
+
timestamp: new Date().toISOString()
|
|
160
|
+
}, null, 2)
|
|
161
|
+
}]
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
return {
|
|
166
|
+
content: [{
|
|
167
|
+
type: 'text',
|
|
168
|
+
text: JSON.stringify({
|
|
169
|
+
success: false,
|
|
170
|
+
error: error.message,
|
|
171
|
+
timestamp: new Date().toISOString()
|
|
172
|
+
}, null, 2)
|
|
173
|
+
}],
|
|
174
|
+
isError: true
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
// Tool: Create custom agent
|
|
180
|
+
server.addTool({
|
|
181
|
+
name: 'agentic_flow_create_agent',
|
|
182
|
+
description: 'Create a new custom agent with specified name, description, and system prompt',
|
|
183
|
+
parameters: z.object({
|
|
184
|
+
name: z.string().describe('Agent name (will be converted to kebab-case, e.g., my-custom-agent)'),
|
|
185
|
+
description: z.string().describe('Agent description (what this agent does)'),
|
|
186
|
+
systemPrompt: z.string().describe('System prompt that defines the agent behavior and personality'),
|
|
187
|
+
category: z.string().optional().default('custom').describe('Category/folder to organize the agent (default: custom)'),
|
|
188
|
+
tools: z.array(z.string()).optional().describe('Optional list of tools this agent can use (e.g., ["web-search", "code-execution"])')
|
|
189
|
+
}),
|
|
190
|
+
execute: async ({ name, description, systemPrompt, category, tools }) => {
|
|
191
|
+
try {
|
|
192
|
+
const { writeFileSync, existsSync, mkdirSync } = await import('fs');
|
|
193
|
+
const { join } = await import('path');
|
|
194
|
+
// Convert to kebab-case
|
|
195
|
+
const agentName = name.toLowerCase().replace(/\s+/g, '-');
|
|
196
|
+
const agentsDir = join(process.cwd(), '.claude', 'agents', category || 'custom');
|
|
197
|
+
if (!existsSync(agentsDir)) {
|
|
198
|
+
mkdirSync(agentsDir, { recursive: true });
|
|
199
|
+
}
|
|
200
|
+
const markdown = `# ${name}
|
|
201
|
+
|
|
202
|
+
## Description
|
|
203
|
+
${description}
|
|
204
|
+
|
|
205
|
+
## System Prompt
|
|
206
|
+
${systemPrompt}
|
|
207
|
+
|
|
208
|
+
${tools && tools.length > 0 ? `## Tools\n${tools.map(t => `- ${t}`).join('\n')}\n` : ''}
|
|
209
|
+
|
|
210
|
+
## Usage
|
|
211
|
+
\`\`\`bash
|
|
212
|
+
npx agentic-flow --agent ${agentName} --task "Your task"
|
|
213
|
+
\`\`\`
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
*Created: ${new Date().toISOString()}*
|
|
217
|
+
`;
|
|
218
|
+
const filePath = join(agentsDir, `${agentName}.md`);
|
|
219
|
+
if (existsSync(filePath)) {
|
|
220
|
+
throw new Error(`Agent '${agentName}' already exists at ${filePath}`);
|
|
221
|
+
}
|
|
222
|
+
writeFileSync(filePath, markdown, 'utf8');
|
|
223
|
+
return {
|
|
224
|
+
content: [{
|
|
225
|
+
type: 'text',
|
|
226
|
+
text: JSON.stringify({
|
|
227
|
+
success: true,
|
|
228
|
+
agent: agentName,
|
|
229
|
+
category: category || 'custom',
|
|
230
|
+
filePath,
|
|
231
|
+
message: `Agent '${agentName}' created successfully`,
|
|
232
|
+
timestamp: new Date().toISOString()
|
|
233
|
+
}, null, 2)
|
|
234
|
+
}]
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
return {
|
|
239
|
+
content: [{
|
|
240
|
+
type: 'text',
|
|
241
|
+
text: JSON.stringify({
|
|
242
|
+
success: false,
|
|
243
|
+
error: error.message,
|
|
244
|
+
timestamp: new Date().toISOString()
|
|
245
|
+
}, null, 2)
|
|
246
|
+
}],
|
|
247
|
+
isError: true
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
// Tool: Get agent info
|
|
253
|
+
server.addTool({
|
|
254
|
+
name: 'agentic_flow_agent_info',
|
|
255
|
+
description: 'Get detailed information about a specific agent including source, description, and system prompt preview',
|
|
256
|
+
parameters: z.object({
|
|
257
|
+
name: z.string().describe('Agent name to get information about')
|
|
258
|
+
}),
|
|
259
|
+
execute: async ({ name }) => {
|
|
260
|
+
try {
|
|
261
|
+
const result = execSync(`npx --yes agentic-flow agent info ${name}`, {
|
|
262
|
+
encoding: 'utf-8',
|
|
263
|
+
maxBuffer: 5 * 1024 * 1024,
|
|
264
|
+
timeout: 30000
|
|
265
|
+
});
|
|
266
|
+
return {
|
|
267
|
+
content: [{
|
|
268
|
+
type: 'text',
|
|
269
|
+
text: result
|
|
270
|
+
}]
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
return {
|
|
275
|
+
content: [{
|
|
276
|
+
type: 'text',
|
|
277
|
+
text: JSON.stringify({
|
|
278
|
+
success: false,
|
|
279
|
+
error: error.message,
|
|
280
|
+
timestamp: new Date().toISOString()
|
|
281
|
+
}, null, 2)
|
|
282
|
+
}],
|
|
283
|
+
isError: true
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
// Tool: Check for agent conflicts
|
|
289
|
+
server.addTool({
|
|
290
|
+
name: 'agentic_flow_check_conflicts',
|
|
291
|
+
description: 'Check for conflicts between package agents and local custom agents',
|
|
292
|
+
parameters: z.object({}),
|
|
293
|
+
execute: async () => {
|
|
294
|
+
try {
|
|
295
|
+
const result = execSync('npx --yes agentic-flow agent conflicts', {
|
|
296
|
+
encoding: 'utf-8',
|
|
297
|
+
maxBuffer: 5 * 1024 * 1024,
|
|
298
|
+
timeout: 30000
|
|
299
|
+
});
|
|
300
|
+
return {
|
|
301
|
+
content: [{
|
|
302
|
+
type: 'text',
|
|
303
|
+
text: result
|
|
304
|
+
}]
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
catch (error) {
|
|
308
|
+
return {
|
|
309
|
+
content: [{
|
|
310
|
+
type: 'text',
|
|
311
|
+
text: JSON.stringify({
|
|
312
|
+
success: false,
|
|
313
|
+
error: error.message,
|
|
314
|
+
timestamp: new Date().toISOString()
|
|
315
|
+
}, null, 2)
|
|
316
|
+
}],
|
|
317
|
+
isError: true
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
// Tool: Optimize model selection
|
|
323
|
+
server.addTool({
|
|
324
|
+
name: 'agentic_flow_optimize_model',
|
|
325
|
+
description: 'Automatically select the optimal model for an agent and task based on priorities (quality, cost, speed, privacy)',
|
|
326
|
+
parameters: z.object({
|
|
327
|
+
agent: z.string().describe('Agent type (e.g., coder, researcher, reviewer)'),
|
|
328
|
+
task: z.string().describe('Task description'),
|
|
329
|
+
priority: z.enum(['quality', 'balanced', 'cost', 'speed', 'privacy']).optional().default('balanced')
|
|
330
|
+
.describe('Optimization priority: quality (best results), balanced (cost/quality), cost (cheapest), speed (fastest), privacy (local only)'),
|
|
331
|
+
max_cost: z.number().positive().optional().describe('Maximum cost per task in dollars (optional budget cap)')
|
|
332
|
+
}),
|
|
333
|
+
execute: async ({ agent, task, priority, max_cost }) => {
|
|
334
|
+
try {
|
|
335
|
+
let cmd = `npx --yes agentic-flow --agent ${agent} --task "${task}" --optimize --priority ${priority}`;
|
|
336
|
+
if (max_cost)
|
|
337
|
+
cmd += ` --max-cost ${max_cost}`;
|
|
338
|
+
const result = execSync(cmd, {
|
|
339
|
+
encoding: 'utf-8',
|
|
340
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
341
|
+
timeout: 60000
|
|
342
|
+
});
|
|
343
|
+
return {
|
|
344
|
+
content: [{
|
|
345
|
+
type: 'text',
|
|
346
|
+
text: result
|
|
347
|
+
}]
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
catch (error) {
|
|
351
|
+
return {
|
|
352
|
+
content: [{
|
|
353
|
+
type: 'text',
|
|
354
|
+
text: JSON.stringify({
|
|
355
|
+
success: false,
|
|
356
|
+
error: error.message,
|
|
357
|
+
timestamp: new Date().toISOString()
|
|
358
|
+
}, null, 2)
|
|
359
|
+
}],
|
|
360
|
+
isError: true
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
console.error('✅ Registered 6 tools successfully');
|
|
366
|
+
console.error('🌐 Starting HTTP/SSE transport...');
|
|
367
|
+
// Start with HTTP/SSE transport
|
|
368
|
+
server.start({
|
|
369
|
+
transportType: 'httpStream',
|
|
370
|
+
httpStream: {
|
|
371
|
+
port: 8080
|
|
372
|
+
}
|
|
373
|
+
}).then(() => {
|
|
374
|
+
console.error('✅ Agentic-Flow MCP Server running!');
|
|
375
|
+
console.error('📡 HTTP endpoint: http://localhost:8080/mcp');
|
|
376
|
+
console.error('📡 SSE endpoint: http://localhost:8080/sse');
|
|
377
|
+
console.error('💊 Health check: http://localhost:8080/health');
|
|
378
|
+
}).catch((error) => {
|
|
379
|
+
console.error('❌ Failed to start HTTP/SSE server:', error);
|
|
380
|
+
process.exit(1);
|
|
381
|
+
});
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Converts Anthropic API format to OpenRouter format
|
|
3
3
|
import express from 'express';
|
|
4
4
|
import { logger } from '../utils/logger.js';
|
|
5
|
-
import { getInstructionsForModel, formatInstructions } from './provider-instructions.js';
|
|
5
|
+
import { getInstructionsForModel, formatInstructions, taskRequiresFileOps, getMaxTokensForModel } from './provider-instructions.js';
|
|
6
6
|
export class AnthropicToOpenRouterProxy {
|
|
7
7
|
app;
|
|
8
8
|
openrouterApiKey;
|
|
@@ -127,8 +127,11 @@ export class AnthropicToOpenRouterProxy {
|
|
|
127
127
|
const modelId = anthropicReq.model || this.defaultModel;
|
|
128
128
|
const provider = this.extractProvider(modelId);
|
|
129
129
|
const instructions = getInstructionsForModel(modelId, provider);
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
// Check if task requires file operations
|
|
131
|
+
const needsFileOps = taskRequiresFileOps(anthropicReq.system || '', anthropicReq.messages);
|
|
132
|
+
// Only include XML instructions if task needs file/tool operations
|
|
133
|
+
const toolInstructions = formatInstructions(instructions, needsFileOps);
|
|
134
|
+
// Add system message with context-aware tool instructions
|
|
132
135
|
let systemContent = toolInstructions;
|
|
133
136
|
if (anthropicReq.system) {
|
|
134
137
|
systemContent += '\n\n' + anthropicReq.system;
|
|
@@ -162,10 +165,12 @@ export class AnthropicToOpenRouterProxy {
|
|
|
162
165
|
content
|
|
163
166
|
});
|
|
164
167
|
}
|
|
168
|
+
// Get appropriate max_tokens for this model
|
|
169
|
+
const maxTokens = getMaxTokensForModel(finalModel, anthropicReq.max_tokens);
|
|
165
170
|
const openaiReq = {
|
|
166
171
|
model: finalModel,
|
|
167
172
|
messages,
|
|
168
|
-
max_tokens:
|
|
173
|
+
max_tokens: maxTokens,
|
|
169
174
|
temperature: anthropicReq.temperature,
|
|
170
175
|
stream: anthropicReq.stream
|
|
171
176
|
};
|
|
@@ -181,11 +181,27 @@ export function getInstructionsForModel(modelId, provider) {
|
|
|
181
181
|
// Default to base instructions
|
|
182
182
|
return BASE_INSTRUCTIONS;
|
|
183
183
|
}
|
|
184
|
+
// Check if task requires file/tool operations based on prompt content
|
|
185
|
+
export function taskRequiresFileOps(systemPrompt, userMessages) {
|
|
186
|
+
const combined = (systemPrompt + ' ' + JSON.stringify(userMessages)).toLowerCase();
|
|
187
|
+
// Keywords that suggest file operations are needed
|
|
188
|
+
const fileKeywords = [
|
|
189
|
+
'create file', 'write file', 'save to', 'create a file',
|
|
190
|
+
'write to disk', 'save code to', 'create script',
|
|
191
|
+
'bash', 'shell', 'command', 'execute', 'run command'
|
|
192
|
+
];
|
|
193
|
+
return fileKeywords.some(keyword => combined.includes(keyword));
|
|
194
|
+
}
|
|
184
195
|
// Generate formatted instruction string for injection
|
|
185
|
-
|
|
196
|
+
// Only include XML instructions if task actually requires file operations
|
|
197
|
+
export function formatInstructions(instructions, includeXmlInstructions = true) {
|
|
186
198
|
if (instructions.format === 'native') {
|
|
187
199
|
return `${instructions.emphasis}\n\n${instructions.commands.write}\n${instructions.commands.read}\n${instructions.commands.bash}`;
|
|
188
200
|
}
|
|
201
|
+
// For simple code generation without file ops, skip XML instructions
|
|
202
|
+
if (!includeXmlInstructions) {
|
|
203
|
+
return 'Provide clean, well-formatted code in your response. Use markdown code blocks for code.';
|
|
204
|
+
}
|
|
189
205
|
let formatted = `${instructions.emphasis}\n\n`;
|
|
190
206
|
formatted += `Available commands:\n`;
|
|
191
207
|
formatted += `${instructions.commands.write}\n`;
|
|
@@ -196,3 +212,25 @@ export function formatInstructions(instructions) {
|
|
|
196
212
|
}
|
|
197
213
|
return formatted;
|
|
198
214
|
}
|
|
215
|
+
// Get appropriate max_tokens for model
|
|
216
|
+
export function getMaxTokensForModel(modelId, requestedMaxTokens) {
|
|
217
|
+
const normalizedModel = modelId.toLowerCase();
|
|
218
|
+
// If user requested specific max_tokens, use it
|
|
219
|
+
if (requestedMaxTokens) {
|
|
220
|
+
return requestedMaxTokens;
|
|
221
|
+
}
|
|
222
|
+
// DeepSeek needs higher max_tokens
|
|
223
|
+
if (normalizedModel.includes('deepseek')) {
|
|
224
|
+
return 8000;
|
|
225
|
+
}
|
|
226
|
+
// Llama 3.1/3.3 - moderate
|
|
227
|
+
if (normalizedModel.includes('llama')) {
|
|
228
|
+
return 4096;
|
|
229
|
+
}
|
|
230
|
+
// GPT models - standard
|
|
231
|
+
if (normalizedModel.includes('gpt')) {
|
|
232
|
+
return 4096;
|
|
233
|
+
}
|
|
234
|
+
// Default
|
|
235
|
+
return 4096;
|
|
236
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentic-flow",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"description": "Production-ready AI agent orchestration platform with 66 specialized agents, 111 MCP tools, and autonomous multi-agent swarms. Built by @ruvnet with Claude Agent SDK, neural networks, memory persistence, GitHub integration, and distributed consensus protocols. v1.1.
|
|
3
|
+
"version": "1.1.13",
|
|
4
|
+
"description": "Production-ready AI agent orchestration platform with 66 specialized agents, 111 MCP tools, and autonomous multi-agent swarms. Built by @ruvnet with Claude Agent SDK, neural networks, memory persistence, GitHub integration, and distributed consensus protocols. v1.1.13: Context-aware OpenRouter proxy with 100% success rate across GPT, DeepSeek, and Llama models!",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
@@ -18,12 +18,15 @@
|
|
|
18
18
|
"validate": "tsx validation/quick-wins/validate-all.ts",
|
|
19
19
|
"validate:sdk": "tsx validation/sdk-validation.ts",
|
|
20
20
|
"validate:health": "bash validation/quick-wins/test-health.sh",
|
|
21
|
+
"validate:openrouter": "tsx validation/test-openrouter-fixes.ts",
|
|
21
22
|
"validate:claude-flow": "npm run test:memory && npm run test:coordination && npm run test:hybrid",
|
|
22
23
|
"test:memory": "tsx validation/claude-flow/test-memory.ts",
|
|
23
24
|
"test:coordination": "tsx validation/claude-flow/test-coordination.ts",
|
|
24
25
|
"test:hybrid": "tsx validation/claude-flow/test-hybrid.ts",
|
|
25
26
|
"test:fastmcp": "bash scripts/test-fastmcp-poc.sh",
|
|
26
27
|
"mcp:fastmcp-poc": "node dist/mcp/fastmcp/servers/poc-stdio.js",
|
|
28
|
+
"mcp:http": "node dist/mcp/fastmcp/servers/http-sse.js",
|
|
29
|
+
"mcp:stdio": "node dist/mcp/standalone-stdio.js",
|
|
27
30
|
"example:goal-planner": "tsx src/examples/use-goal-planner.ts",
|
|
28
31
|
"example:multi-agent": "tsx src/examples/multi-agent-orchestration.ts",
|
|
29
32
|
"proxy": "node dist/proxy/anthropic-to-openrouter.js",
|