agentic-flow 1.0.7 → 1.1.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/cli/agent-manager.js +451 -0
- package/dist/cli-proxy.js +87 -8
- package/dist/mcp/standalone-stdio.js +175 -2
- package/dist/router/providers/onnx.js +26 -4
- package/dist/utils/agentLoader.js +59 -14
- package/dist/utils/cli.js +118 -18
- package/dist/utils/modelOptimizer.js +398 -0
- package/package.json +1 -1
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Agent Management CLI - Create, list, and manage custom agents
|
|
4
|
+
* Supports both npm package agents and local .claude/agents
|
|
5
|
+
* Includes conflict detection and deduplication
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, statSync } from 'fs';
|
|
8
|
+
import { join, dirname, relative, extname } from 'path';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
import { createInterface } from 'readline';
|
|
11
|
+
// Get package root and default paths
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = dirname(__filename);
|
|
14
|
+
const packageRoot = join(__dirname, '../..');
|
|
15
|
+
const packageAgentsDir = join(packageRoot, '.claude/agents');
|
|
16
|
+
const localAgentsDir = join(process.cwd(), '.claude/agents');
|
|
17
|
+
export class AgentManager {
|
|
18
|
+
/**
|
|
19
|
+
* Find all agent files from both package and local directories
|
|
20
|
+
* Deduplicates by preferring local over package
|
|
21
|
+
*/
|
|
22
|
+
findAllAgents() {
|
|
23
|
+
const agents = new Map();
|
|
24
|
+
// Load package agents first
|
|
25
|
+
if (existsSync(packageAgentsDir)) {
|
|
26
|
+
this.scanAgentsDirectory(packageAgentsDir, 'package', agents);
|
|
27
|
+
}
|
|
28
|
+
// Load local agents (overrides package agents with same relative path)
|
|
29
|
+
if (existsSync(localAgentsDir)) {
|
|
30
|
+
this.scanAgentsDirectory(localAgentsDir, 'local', agents);
|
|
31
|
+
}
|
|
32
|
+
return agents;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Recursively scan directory for agent markdown files
|
|
36
|
+
*/
|
|
37
|
+
scanAgentsDirectory(dir, source, agents) {
|
|
38
|
+
const baseDir = source === 'package' ? packageAgentsDir : localAgentsDir;
|
|
39
|
+
try {
|
|
40
|
+
const entries = readdirSync(dir);
|
|
41
|
+
for (const entry of entries) {
|
|
42
|
+
const fullPath = join(dir, entry);
|
|
43
|
+
const stat = statSync(fullPath);
|
|
44
|
+
if (stat.isDirectory()) {
|
|
45
|
+
this.scanAgentsDirectory(fullPath, source, agents);
|
|
46
|
+
}
|
|
47
|
+
else if (extname(entry) === '.md' && entry !== 'README.md') {
|
|
48
|
+
const relativePath = relative(baseDir, fullPath);
|
|
49
|
+
const agentInfo = this.parseAgentFile(fullPath, source, relativePath);
|
|
50
|
+
if (agentInfo) {
|
|
51
|
+
// Use relative path as key for deduplication
|
|
52
|
+
// Local agents override package agents
|
|
53
|
+
const existingAgent = agents.get(relativePath);
|
|
54
|
+
if (!existingAgent || source === 'local') {
|
|
55
|
+
agents.set(relativePath, agentInfo);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
console.error(`Error scanning directory ${dir}: ${error.message}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Parse agent markdown file and extract metadata
|
|
67
|
+
*/
|
|
68
|
+
parseAgentFile(filePath, source, relativePath) {
|
|
69
|
+
try {
|
|
70
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
71
|
+
// Try frontmatter format first
|
|
72
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
73
|
+
if (frontmatterMatch) {
|
|
74
|
+
const [, frontmatter] = frontmatterMatch;
|
|
75
|
+
const meta = {};
|
|
76
|
+
frontmatter.split('\n').forEach(line => {
|
|
77
|
+
const match = line.match(/^(\w+):\s*(.+)$/);
|
|
78
|
+
if (match) {
|
|
79
|
+
const [, key, value] = match;
|
|
80
|
+
meta[key] = value.replace(/^["']|["']$/g, '');
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
if (meta.name && meta.description) {
|
|
84
|
+
return {
|
|
85
|
+
name: meta.name,
|
|
86
|
+
description: meta.description,
|
|
87
|
+
category: this.getCategoryFromPath(relativePath),
|
|
88
|
+
filePath,
|
|
89
|
+
source,
|
|
90
|
+
relativePath
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Fallback: extract from markdown headers
|
|
95
|
+
const nameMatch = content.match(/^#\s+(.+)$/m);
|
|
96
|
+
const descMatch = content.match(/^##\s+Description\s*\n\s*(.+)$/m);
|
|
97
|
+
if (nameMatch) {
|
|
98
|
+
return {
|
|
99
|
+
name: nameMatch[1].trim(),
|
|
100
|
+
description: descMatch ? descMatch[1].trim() : 'No description available',
|
|
101
|
+
category: this.getCategoryFromPath(relativePath),
|
|
102
|
+
filePath,
|
|
103
|
+
source,
|
|
104
|
+
relativePath
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Get category from file path
|
|
115
|
+
*/
|
|
116
|
+
getCategoryFromPath(relativePath) {
|
|
117
|
+
const parts = relativePath.split('/');
|
|
118
|
+
return parts.length > 1 ? parts[0] : 'custom';
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* List all agents with deduplication
|
|
122
|
+
*/
|
|
123
|
+
list(format = 'summary') {
|
|
124
|
+
const agents = this.findAllAgents();
|
|
125
|
+
if (format === 'json') {
|
|
126
|
+
const agentList = Array.from(agents.values()).map(a => ({
|
|
127
|
+
name: a.name,
|
|
128
|
+
description: a.description,
|
|
129
|
+
category: a.category,
|
|
130
|
+
source: a.source,
|
|
131
|
+
path: a.relativePath
|
|
132
|
+
}));
|
|
133
|
+
console.log(JSON.stringify(agentList, null, 2));
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
// Group by category
|
|
137
|
+
const byCategory = new Map();
|
|
138
|
+
for (const agent of agents.values()) {
|
|
139
|
+
const category = agent.category;
|
|
140
|
+
if (!byCategory.has(category)) {
|
|
141
|
+
byCategory.set(category, []);
|
|
142
|
+
}
|
|
143
|
+
byCategory.get(category).push(agent);
|
|
144
|
+
}
|
|
145
|
+
// Sort categories
|
|
146
|
+
const sortedCategories = Array.from(byCategory.keys()).sort();
|
|
147
|
+
console.log('\n📦 Available Agents:');
|
|
148
|
+
console.log('═'.repeat(80));
|
|
149
|
+
for (const category of sortedCategories) {
|
|
150
|
+
const categoryAgents = byCategory.get(category).sort((a, b) => a.name.localeCompare(b.name));
|
|
151
|
+
console.log(`\n${category.toUpperCase()}:`);
|
|
152
|
+
for (const agent of categoryAgents) {
|
|
153
|
+
const sourceIcon = agent.source === 'local' ? '📝' : '📦';
|
|
154
|
+
if (format === 'detailed') {
|
|
155
|
+
console.log(` ${sourceIcon} ${agent.name}`);
|
|
156
|
+
console.log(` ${agent.description}`);
|
|
157
|
+
console.log(` Source: ${agent.source} (${agent.relativePath})`);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
console.log(` ${sourceIcon} ${agent.name.padEnd(30)} ${agent.description.substring(0, 45)}...`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
console.log(`\n📊 Total: ${agents.size} agents`);
|
|
165
|
+
console.log(` 📝 Local: ${Array.from(agents.values()).filter(a => a.source === 'local').length}`);
|
|
166
|
+
console.log(` 📦 Package: ${Array.from(agents.values()).filter(a => a.source === 'package').length}`);
|
|
167
|
+
console.log('');
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Create a new agent
|
|
171
|
+
*/
|
|
172
|
+
async create(options) {
|
|
173
|
+
let { name, description, category, systemPrompt, tools } = options;
|
|
174
|
+
// Interactive mode
|
|
175
|
+
if (options.interactive) {
|
|
176
|
+
const rl = createInterface({
|
|
177
|
+
input: process.stdin,
|
|
178
|
+
output: process.stdout
|
|
179
|
+
});
|
|
180
|
+
const question = (prompt) => {
|
|
181
|
+
return new Promise(resolve => rl.question(prompt, resolve));
|
|
182
|
+
};
|
|
183
|
+
console.log('\n🤖 Create New Agent');
|
|
184
|
+
console.log('═'.repeat(80));
|
|
185
|
+
name = await question('Agent name (e.g., my-custom-agent): ');
|
|
186
|
+
description = await question('Description: ');
|
|
187
|
+
category = await question('Category (default: custom): ') || 'custom';
|
|
188
|
+
systemPrompt = await question('System prompt: ');
|
|
189
|
+
const toolsInput = await question('Tools (comma-separated, optional): ');
|
|
190
|
+
tools = toolsInput ? toolsInput.split(',').map(t => t.trim()) : [];
|
|
191
|
+
rl.close();
|
|
192
|
+
}
|
|
193
|
+
// Validate required fields
|
|
194
|
+
if (!name || !description || !systemPrompt) {
|
|
195
|
+
throw new Error('Name, description, and system prompt are required');
|
|
196
|
+
}
|
|
197
|
+
// Normalize name to kebab-case
|
|
198
|
+
const kebabName = name.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '');
|
|
199
|
+
// Check for conflicts
|
|
200
|
+
const agents = this.findAllAgents();
|
|
201
|
+
const conflictingAgent = Array.from(agents.values()).find(a => a.name.toLowerCase() === kebabName.toLowerCase());
|
|
202
|
+
if (conflictingAgent) {
|
|
203
|
+
console.log(`\n⚠️ Warning: Agent "${conflictingAgent.name}" already exists`);
|
|
204
|
+
console.log(` Source: ${conflictingAgent.source}`);
|
|
205
|
+
console.log(` Path: ${conflictingAgent.relativePath}`);
|
|
206
|
+
const rl = createInterface({
|
|
207
|
+
input: process.stdin,
|
|
208
|
+
output: process.stdout
|
|
209
|
+
});
|
|
210
|
+
const answer = await new Promise(resolve => {
|
|
211
|
+
rl.question('\nCreate in local .claude/agents anyway? (y/N): ', resolve);
|
|
212
|
+
});
|
|
213
|
+
rl.close();
|
|
214
|
+
if (answer.toLowerCase() !== 'y') {
|
|
215
|
+
console.log('Cancelled.');
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// Create directory structure
|
|
220
|
+
const targetCategory = category || 'custom';
|
|
221
|
+
const targetDir = join(localAgentsDir, targetCategory);
|
|
222
|
+
if (!existsSync(targetDir)) {
|
|
223
|
+
mkdirSync(targetDir, { recursive: true });
|
|
224
|
+
}
|
|
225
|
+
// Generate markdown content
|
|
226
|
+
const markdown = this.generateAgentMarkdown({
|
|
227
|
+
name: kebabName,
|
|
228
|
+
description: description,
|
|
229
|
+
category: targetCategory,
|
|
230
|
+
tools
|
|
231
|
+
}, systemPrompt);
|
|
232
|
+
const filePath = join(targetDir, `${kebabName}.md`);
|
|
233
|
+
if (existsSync(filePath)) {
|
|
234
|
+
throw new Error(`Agent file already exists at ${filePath}`);
|
|
235
|
+
}
|
|
236
|
+
writeFileSync(filePath, markdown, 'utf8');
|
|
237
|
+
console.log(`\n✅ Agent created successfully!`);
|
|
238
|
+
console.log(` Name: ${kebabName}`);
|
|
239
|
+
console.log(` Category: ${targetCategory}`);
|
|
240
|
+
console.log(` Path: ${filePath}`);
|
|
241
|
+
console.log(`\n📝 Usage:`);
|
|
242
|
+
console.log(` npx agentic-flow --agent ${kebabName} --task "Your task"`);
|
|
243
|
+
console.log('');
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Generate agent markdown with frontmatter
|
|
247
|
+
*/
|
|
248
|
+
generateAgentMarkdown(metadata, systemPrompt) {
|
|
249
|
+
const toolsLine = metadata.tools && metadata.tools.length > 0
|
|
250
|
+
? `tools: ${metadata.tools.join(', ')}`
|
|
251
|
+
: '';
|
|
252
|
+
return `---
|
|
253
|
+
name: ${metadata.name}
|
|
254
|
+
description: ${metadata.description}
|
|
255
|
+
${metadata.color ? `color: ${metadata.color}` : ''}
|
|
256
|
+
${toolsLine}
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
${systemPrompt}
|
|
260
|
+
|
|
261
|
+
## Usage
|
|
262
|
+
|
|
263
|
+
\`\`\`bash
|
|
264
|
+
npx agentic-flow --agent ${metadata.name} --task "Your task"
|
|
265
|
+
\`\`\`
|
|
266
|
+
|
|
267
|
+
## Examples
|
|
268
|
+
|
|
269
|
+
### Example 1
|
|
270
|
+
\`\`\`bash
|
|
271
|
+
npx agentic-flow --agent ${metadata.name} --task "Example task description"
|
|
272
|
+
\`\`\`
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
*Created: ${new Date().toISOString()}*
|
|
276
|
+
*Source: local*
|
|
277
|
+
`;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Get information about a specific agent
|
|
281
|
+
*/
|
|
282
|
+
info(name) {
|
|
283
|
+
const agents = this.findAllAgents();
|
|
284
|
+
const agent = Array.from(agents.values()).find(a => a.name.toLowerCase() === name.toLowerCase());
|
|
285
|
+
if (!agent) {
|
|
286
|
+
console.log(`\n❌ Agent "${name}" not found`);
|
|
287
|
+
console.log('\nUse "agentic-flow agent list" to see all available agents\n');
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
console.log('\n📋 Agent Information');
|
|
291
|
+
console.log('═'.repeat(80));
|
|
292
|
+
console.log(`Name: ${agent.name}`);
|
|
293
|
+
console.log(`Description: ${agent.description}`);
|
|
294
|
+
console.log(`Category: ${agent.category}`);
|
|
295
|
+
console.log(`Source: ${agent.source === 'local' ? '📝 Local' : '📦 Package'}`);
|
|
296
|
+
console.log(`Path: ${agent.relativePath}`);
|
|
297
|
+
console.log(`Full Path: ${agent.filePath}`);
|
|
298
|
+
console.log('');
|
|
299
|
+
// Show content preview
|
|
300
|
+
try {
|
|
301
|
+
const content = readFileSync(agent.filePath, 'utf-8');
|
|
302
|
+
console.log('Preview:');
|
|
303
|
+
console.log('─'.repeat(80));
|
|
304
|
+
const lines = content.split('\n').slice(0, 20);
|
|
305
|
+
console.log(lines.join('\n'));
|
|
306
|
+
if (content.split('\n').length > 20) {
|
|
307
|
+
console.log('...');
|
|
308
|
+
}
|
|
309
|
+
console.log('');
|
|
310
|
+
}
|
|
311
|
+
catch (error) {
|
|
312
|
+
console.log('Could not read agent file\n');
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Check for conflicts between package and local agents
|
|
317
|
+
*/
|
|
318
|
+
checkConflicts() {
|
|
319
|
+
console.log('\n🔍 Checking for agent conflicts...');
|
|
320
|
+
console.log('═'.repeat(80));
|
|
321
|
+
const packageAgents = new Map();
|
|
322
|
+
const localAgents = new Map();
|
|
323
|
+
if (existsSync(packageAgentsDir)) {
|
|
324
|
+
this.scanAgentsDirectory(packageAgentsDir, 'package', packageAgents);
|
|
325
|
+
}
|
|
326
|
+
if (existsSync(localAgentsDir)) {
|
|
327
|
+
this.scanAgentsDirectory(localAgentsDir, 'local', localAgents);
|
|
328
|
+
}
|
|
329
|
+
// Find conflicts (same relative path in both)
|
|
330
|
+
const conflicts = [];
|
|
331
|
+
for (const [relativePath, localAgent] of localAgents) {
|
|
332
|
+
const packageAgent = packageAgents.get(relativePath);
|
|
333
|
+
if (packageAgent) {
|
|
334
|
+
conflicts.push({ path: relativePath, package: packageAgent, local: localAgent });
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
if (conflicts.length === 0) {
|
|
338
|
+
console.log('\n✅ No conflicts found!\n');
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
console.log(`\n⚠️ Found ${conflicts.length} conflict(s):\n`);
|
|
342
|
+
for (const conflict of conflicts) {
|
|
343
|
+
console.log(`📁 ${conflict.path}`);
|
|
344
|
+
console.log(` 📦 Package: ${conflict.package.name}`);
|
|
345
|
+
console.log(` ${conflict.package.description}`);
|
|
346
|
+
console.log(` 📝 Local: ${conflict.local.name}`);
|
|
347
|
+
console.log(` ${conflict.local.description}`);
|
|
348
|
+
console.log(` ℹ️ Local version will be used\n`);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* CLI command handler
|
|
354
|
+
*/
|
|
355
|
+
export async function handleAgentCommand(args) {
|
|
356
|
+
const command = args[0];
|
|
357
|
+
const manager = new AgentManager();
|
|
358
|
+
switch (command) {
|
|
359
|
+
case undefined:
|
|
360
|
+
case 'help':
|
|
361
|
+
console.log(`
|
|
362
|
+
🤖 Agent Management CLI
|
|
363
|
+
|
|
364
|
+
USAGE:
|
|
365
|
+
npx agentic-flow agent <command> [options]
|
|
366
|
+
|
|
367
|
+
COMMANDS:
|
|
368
|
+
list [format] List all available agents
|
|
369
|
+
format: summary (default), detailed, json
|
|
370
|
+
|
|
371
|
+
create Create a new agent interactively
|
|
372
|
+
create --name NAME Create agent with CLI arguments
|
|
373
|
+
--description DESC
|
|
374
|
+
--category CAT
|
|
375
|
+
--prompt PROMPT
|
|
376
|
+
[--tools TOOLS]
|
|
377
|
+
|
|
378
|
+
info <name> Show detailed information about an agent
|
|
379
|
+
|
|
380
|
+
conflicts Check for conflicts between package and local agents
|
|
381
|
+
|
|
382
|
+
help Show this help message
|
|
383
|
+
|
|
384
|
+
EXAMPLES:
|
|
385
|
+
# List all agents
|
|
386
|
+
npx agentic-flow agent list
|
|
387
|
+
|
|
388
|
+
# List with details
|
|
389
|
+
npx agentic-flow agent list detailed
|
|
390
|
+
|
|
391
|
+
# Create agent interactively
|
|
392
|
+
npx agentic-flow agent create
|
|
393
|
+
|
|
394
|
+
# Create agent with CLI
|
|
395
|
+
npx agentic-flow agent create --name my-agent --description "My custom agent" --prompt "You are a helpful assistant"
|
|
396
|
+
|
|
397
|
+
# Get agent info
|
|
398
|
+
npx agentic-flow agent info coder
|
|
399
|
+
|
|
400
|
+
# Check conflicts
|
|
401
|
+
npx agentic-flow agent conflicts
|
|
402
|
+
|
|
403
|
+
AGENT LOCATIONS:
|
|
404
|
+
📦 Package: ${packageAgentsDir}
|
|
405
|
+
📝 Local: ${localAgentsDir}
|
|
406
|
+
|
|
407
|
+
Note: Local agents override package agents with the same path.
|
|
408
|
+
`);
|
|
409
|
+
break;
|
|
410
|
+
case 'list':
|
|
411
|
+
const format = args[1] || 'summary';
|
|
412
|
+
manager.list(format);
|
|
413
|
+
break;
|
|
414
|
+
case 'create':
|
|
415
|
+
const nameIdx = args.indexOf('--name');
|
|
416
|
+
const descIdx = args.indexOf('--description');
|
|
417
|
+
const catIdx = args.indexOf('--category');
|
|
418
|
+
const promptIdx = args.indexOf('--prompt');
|
|
419
|
+
const toolsIdx = args.indexOf('--tools');
|
|
420
|
+
if (nameIdx === -1 || descIdx === -1 || promptIdx === -1) {
|
|
421
|
+
// Interactive mode
|
|
422
|
+
await manager.create({ interactive: true });
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
// CLI mode
|
|
426
|
+
await manager.create({
|
|
427
|
+
name: args[nameIdx + 1],
|
|
428
|
+
description: args[descIdx + 1],
|
|
429
|
+
category: catIdx !== -1 ? args[catIdx + 1] : 'custom',
|
|
430
|
+
systemPrompt: args[promptIdx + 1],
|
|
431
|
+
tools: toolsIdx !== -1 ? args[toolsIdx + 1].split(',').map(t => t.trim()) : []
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
break;
|
|
435
|
+
case 'info':
|
|
436
|
+
if (!args[1]) {
|
|
437
|
+
console.log('\n❌ Please specify an agent name\n');
|
|
438
|
+
console.log('Usage: npx agentic-flow agent info <name>\n');
|
|
439
|
+
process.exit(1);
|
|
440
|
+
}
|
|
441
|
+
manager.info(args[1]);
|
|
442
|
+
break;
|
|
443
|
+
case 'conflicts':
|
|
444
|
+
manager.checkConflicts();
|
|
445
|
+
break;
|
|
446
|
+
default:
|
|
447
|
+
console.log(`\n❌ Unknown command: ${command}\n`);
|
|
448
|
+
console.log('Use "npx agentic-flow agent help" for usage information\n');
|
|
449
|
+
process.exit(1);
|
|
450
|
+
}
|
|
451
|
+
}
|
package/dist/cli-proxy.js
CHANGED
|
@@ -10,6 +10,8 @@ import { parseArgs } from "./utils/cli.js";
|
|
|
10
10
|
import { getAgent, listAgents } from "./utils/agentLoader.js";
|
|
11
11
|
import { directApiAgent } from "./agents/directApiAgent.js";
|
|
12
12
|
import { handleConfigCommand } from "./cli/config-wizard.js";
|
|
13
|
+
import { handleAgentCommand } from "./cli/agent-manager.js";
|
|
14
|
+
import { ModelOptimizer } from "./utils/modelOptimizer.js";
|
|
13
15
|
import { readFileSync } from 'fs';
|
|
14
16
|
import { resolve, dirname } from 'path';
|
|
15
17
|
import { fileURLToPath } from 'url';
|
|
@@ -36,6 +38,12 @@ class AgenticFlowCLI {
|
|
|
36
38
|
await handleConfigCommand(configArgs);
|
|
37
39
|
process.exit(0);
|
|
38
40
|
}
|
|
41
|
+
if (options.mode === 'agent-manager') {
|
|
42
|
+
// Handle agent management commands
|
|
43
|
+
const agentArgs = process.argv.slice(3); // Skip 'node', 'cli-proxy.js', 'agent'
|
|
44
|
+
await handleAgentCommand(agentArgs);
|
|
45
|
+
process.exit(0);
|
|
46
|
+
}
|
|
39
47
|
if (options.mode === 'mcp') {
|
|
40
48
|
// Run standalone MCP server directly
|
|
41
49
|
const { spawn } = await import('child_process');
|
|
@@ -55,6 +63,25 @@ class AgenticFlowCLI {
|
|
|
55
63
|
process.on('SIGTERM', () => proc.kill('SIGTERM'));
|
|
56
64
|
return;
|
|
57
65
|
}
|
|
66
|
+
// Apply model optimization if requested
|
|
67
|
+
if (options.optimize && options.agent && options.task) {
|
|
68
|
+
const recommendation = ModelOptimizer.optimize({
|
|
69
|
+
agent: options.agent,
|
|
70
|
+
task: options.task,
|
|
71
|
+
priority: options.optimizePriority || 'balanced',
|
|
72
|
+
maxCostPerTask: options.maxCost
|
|
73
|
+
});
|
|
74
|
+
// Display recommendation
|
|
75
|
+
ModelOptimizer.displayRecommendation(recommendation);
|
|
76
|
+
// Apply recommendation to options
|
|
77
|
+
if (!options.provider || options.optimize) {
|
|
78
|
+
options.provider = recommendation.provider;
|
|
79
|
+
}
|
|
80
|
+
if (!options.model || options.optimize) {
|
|
81
|
+
options.model = recommendation.model;
|
|
82
|
+
}
|
|
83
|
+
console.log(`✅ Using optimized model: ${recommendation.modelName}\n`);
|
|
84
|
+
}
|
|
58
85
|
// Determine if we should use OpenRouter
|
|
59
86
|
const useOpenRouter = this.shouldUseOpenRouter(options);
|
|
60
87
|
try {
|
|
@@ -235,6 +262,7 @@ USAGE:
|
|
|
235
262
|
COMMANDS:
|
|
236
263
|
config [subcommand] Manage environment configuration (interactive wizard)
|
|
237
264
|
mcp <command> [server] Manage MCP servers (start, stop, status, list)
|
|
265
|
+
agent <command> Agent management (list, create, info, conflicts)
|
|
238
266
|
--list, -l List all available agents
|
|
239
267
|
--agent, -a <name> Run specific agent mode
|
|
240
268
|
|
|
@@ -254,12 +282,51 @@ MCP COMMANDS:
|
|
|
254
282
|
|
|
255
283
|
Available servers: claude-flow, flow-nexus, agentic-payments, all (default)
|
|
256
284
|
|
|
285
|
+
AGENT COMMANDS:
|
|
286
|
+
npx agentic-flow agent list [format] List all agents (summary/detailed/json)
|
|
287
|
+
npx agentic-flow agent create Create new custom agent (interactive)
|
|
288
|
+
npx agentic-flow agent info <name> Show detailed agent information
|
|
289
|
+
npx agentic-flow agent conflicts Check for package/local conflicts
|
|
290
|
+
|
|
257
291
|
OPTIONS:
|
|
258
|
-
--task, -t <task>
|
|
259
|
-
--model, -m <model>
|
|
260
|
-
--provider, -p <name>
|
|
261
|
-
--stream, -s
|
|
262
|
-
--help, -h
|
|
292
|
+
--task, -t <task> Task description for agent mode
|
|
293
|
+
--model, -m <model> Model to use (triggers OpenRouter if contains "/")
|
|
294
|
+
--provider, -p <name> Provider to use (anthropic, openrouter, onnx)
|
|
295
|
+
--stream, -s Enable real-time streaming output
|
|
296
|
+
--help, -h Show this help message
|
|
297
|
+
|
|
298
|
+
API CONFIGURATION:
|
|
299
|
+
--anthropic-key <key> Override ANTHROPIC_API_KEY environment variable
|
|
300
|
+
--openrouter-key <key> Override OPENROUTER_API_KEY environment variable
|
|
301
|
+
|
|
302
|
+
AGENT BEHAVIOR:
|
|
303
|
+
--temperature <0.0-1.0> Sampling temperature (creativity control)
|
|
304
|
+
--max-tokens <number> Maximum tokens in response
|
|
305
|
+
|
|
306
|
+
DIRECTORY:
|
|
307
|
+
--agents-dir <path> Custom agents directory (default: .claude/agents)
|
|
308
|
+
|
|
309
|
+
OUTPUT:
|
|
310
|
+
--output <text|json|md> Output format (text/json/markdown)
|
|
311
|
+
--verbose Enable verbose logging for debugging
|
|
312
|
+
|
|
313
|
+
EXECUTION:
|
|
314
|
+
--timeout <ms> Execution timeout in milliseconds
|
|
315
|
+
--retry Auto-retry on transient errors
|
|
316
|
+
|
|
317
|
+
MODEL OPTIMIZATION (NEW!):
|
|
318
|
+
--optimize, -O Auto-select best model for agent/task based on priorities
|
|
319
|
+
--priority <type> Optimization priority:
|
|
320
|
+
• quality - Best results (Claude Sonnet 4.5, GPT-4o)
|
|
321
|
+
• balanced - Mix quality/cost (DeepSeek R1, Gemini 2.5 Flash) [default]
|
|
322
|
+
• cost - Cheapest (DeepSeek Chat V3, Llama 3.1 8B)
|
|
323
|
+
• speed - Fastest responses (Gemini 2.5 Flash)
|
|
324
|
+
• privacy - Local only (ONNX Phi-4, no cloud)
|
|
325
|
+
--max-cost <dollars> Maximum cost per task (e.g., 0.001 = $0.001/task budget cap)
|
|
326
|
+
|
|
327
|
+
Optimization analyzes agent type + task complexity to recommend best model.
|
|
328
|
+
Example savings: DeepSeek R1 costs 85% less than Claude Sonnet 4.5 with similar quality.
|
|
329
|
+
See docs/agentic-flow/benchmarks/MODEL_CAPABILITIES.md for full comparison.
|
|
263
330
|
|
|
264
331
|
EXAMPLES:
|
|
265
332
|
# MCP Server Management
|
|
@@ -274,6 +341,12 @@ EXAMPLES:
|
|
|
274
341
|
npx agentic-flow --agent coder --task "Create REST API" --model "meta-llama/llama-3.1-8b-instruct"
|
|
275
342
|
npx agentic-flow --agent coder --task "Create code" --provider onnx
|
|
276
343
|
|
|
344
|
+
# Model Optimization (Auto-select best model)
|
|
345
|
+
npx agentic-flow --agent coder --task "Build API" --optimize
|
|
346
|
+
npx agentic-flow --agent coder --task "Build API" --optimize --priority cost
|
|
347
|
+
npx agentic-flow --agent reviewer --task "Security audit" --optimize --priority quality
|
|
348
|
+
npx agentic-flow --agent coder --task "Simple function" --optimize --max-cost 0.001
|
|
349
|
+
|
|
277
350
|
ENVIRONMENT VARIABLES:
|
|
278
351
|
ANTHROPIC_API_KEY Anthropic API key (for Claude models)
|
|
279
352
|
OPENROUTER_API_KEY OpenRouter API key (for alternative models)
|
|
@@ -288,11 +361,17 @@ OPENROUTER MODELS:
|
|
|
288
361
|
- google/gemini-2.5-flash-preview (fastest)
|
|
289
362
|
- See https://openrouter.ai/models for full list
|
|
290
363
|
|
|
291
|
-
MCP TOOLS (
|
|
292
|
-
•
|
|
364
|
+
MCP TOOLS (213+ available):
|
|
365
|
+
• agentic-flow: 7 tools (agent execution, creation, management, model optimization)
|
|
293
366
|
• claude-flow: 101 tools (neural networks, GitHub, workflows, DAA)
|
|
294
367
|
• flow-nexus: 96 cloud tools (sandboxes, distributed swarms, templates)
|
|
295
|
-
• agentic-payments:
|
|
368
|
+
• agentic-payments: 6 tools (payment authorization, multi-agent consensus)
|
|
369
|
+
|
|
370
|
+
OPTIMIZATION BENEFITS:
|
|
371
|
+
💰 Cost Savings: 85-98% cheaper models for same quality tasks
|
|
372
|
+
🎯 Smart Selection: Agent-aware (coder needs quality ≥85, researcher flexible)
|
|
373
|
+
📊 10+ Models: Claude, GPT-4o, Gemini, DeepSeek, Llama, ONNX local
|
|
374
|
+
⚡ Zero Overhead: <5ms decision time, no API calls during optimization
|
|
296
375
|
|
|
297
376
|
For more information: https://github.com/ruvnet/agentic-flow
|
|
298
377
|
`);
|