agentic-flow 1.1.5 → 1.1.8

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.
@@ -1,73 +1,207 @@
1
- // Generic agent that uses .claude/agents definitions
1
+ // Generic agent that uses .claude/agents definitions with multi-provider SDK routing
2
2
  import { query } from "@anthropic-ai/claude-agent-sdk";
3
3
  import { logger } from "../utils/logger.js";
4
4
  import { withRetry } from "../utils/retry.js";
5
5
  import { claudeFlowSdkServer } from "../mcp/claudeFlowSdkServer.js";
6
+ function getCurrentProvider() {
7
+ // Determine provider from environment
8
+ if (process.env.PROVIDER === 'gemini' || process.env.USE_GEMINI === 'true') {
9
+ return 'gemini';
10
+ }
11
+ if (process.env.PROVIDER === 'openrouter' || process.env.USE_OPENROUTER === 'true') {
12
+ return 'openrouter';
13
+ }
14
+ if (process.env.PROVIDER === 'onnx' || process.env.USE_ONNX === 'true') {
15
+ return 'onnx';
16
+ }
17
+ return 'anthropic'; // Default
18
+ }
19
+ function getModelForProvider(provider) {
20
+ switch (provider) {
21
+ case 'gemini':
22
+ return {
23
+ model: process.env.COMPLETION_MODEL || 'gemini-2.0-flash-exp',
24
+ apiKey: process.env.GOOGLE_GEMINI_API_KEY || process.env.ANTHROPIC_API_KEY || '',
25
+ baseURL: process.env.PROXY_URL || undefined
26
+ };
27
+ case 'openrouter':
28
+ return {
29
+ model: process.env.COMPLETION_MODEL || 'meta-llama/llama-3.1-8b-instruct',
30
+ apiKey: process.env.OPENROUTER_API_KEY || process.env.ANTHROPIC_API_KEY || '',
31
+ baseURL: process.env.PROXY_URL || undefined
32
+ };
33
+ case 'onnx':
34
+ return {
35
+ model: 'onnx-local',
36
+ apiKey: 'local',
37
+ baseURL: process.env.PROXY_URL || undefined
38
+ };
39
+ case 'anthropic':
40
+ default:
41
+ // For anthropic provider, require ANTHROPIC_API_KEY
42
+ const apiKey = process.env.ANTHROPIC_API_KEY;
43
+ if (!apiKey) {
44
+ throw new Error('ANTHROPIC_API_KEY is required but not set for Anthropic provider');
45
+ }
46
+ return {
47
+ model: process.env.COMPLETION_MODEL || 'claude-sonnet-4-5-20250929',
48
+ apiKey,
49
+ // No baseURL for direct Anthropic
50
+ };
51
+ }
52
+ }
6
53
  export async function claudeAgent(agent, input, onStream, modelOverride) {
7
54
  const startTime = Date.now();
8
- logger.info('Starting Claude agent', {
55
+ const provider = getCurrentProvider();
56
+ logger.info('Starting Claude Agent SDK with multi-provider support', {
9
57
  agent: agent.name,
58
+ provider,
10
59
  input: input.substring(0, 100),
11
60
  model: modelOverride || 'default'
12
61
  });
13
62
  return withRetry(async () => {
14
- // Quad MCP server setup: in-SDK + claude-flow + flow-nexus + agentic-payments
15
- const result = query({
16
- prompt: input,
17
- options: {
63
+ // Get model configuration for the selected provider
64
+ const modelConfig = getModelForProvider(provider);
65
+ const finalModel = modelOverride || modelConfig.model;
66
+ // Configure environment for Claude Agent SDK with proxy routing
67
+ // The SDK internally uses Anthropic client which reads ANTHROPIC_BASE_URL and ANTHROPIC_API_KEY
68
+ const envOverrides = {};
69
+ if (provider === 'gemini' && process.env.GOOGLE_GEMINI_API_KEY) {
70
+ // For Gemini: Route through translation proxy
71
+ // Proxy runs on port 3001 and translates Anthropic API → Gemini API
72
+ envOverrides.ANTHROPIC_API_KEY = 'proxy-key'; // Proxy handles real auth
73
+ envOverrides.ANTHROPIC_BASE_URL = process.env.GEMINI_PROXY_URL || 'http://localhost:3001';
74
+ logger.info('Using Gemini proxy', {
75
+ proxyUrl: envOverrides.ANTHROPIC_BASE_URL,
76
+ model: finalModel
77
+ });
78
+ }
79
+ else if (provider === 'openrouter' && process.env.OPENROUTER_API_KEY) {
80
+ // For OpenRouter: Route through translation proxy
81
+ // Proxy runs on port 3000 and translates Anthropic API → OpenRouter API
82
+ envOverrides.ANTHROPIC_API_KEY = 'proxy-key'; // Proxy handles real auth
83
+ envOverrides.ANTHROPIC_BASE_URL = process.env.OPENROUTER_PROXY_URL || 'http://localhost:3000';
84
+ logger.info('Using OpenRouter proxy', {
85
+ proxyUrl: envOverrides.ANTHROPIC_BASE_URL,
86
+ model: finalModel
87
+ });
88
+ }
89
+ else if (provider === 'onnx') {
90
+ // For ONNX: Local inference (TODO: implement ONNX proxy)
91
+ envOverrides.ANTHROPIC_API_KEY = 'local';
92
+ if (modelConfig.baseURL) {
93
+ envOverrides.ANTHROPIC_BASE_URL = modelConfig.baseURL;
94
+ }
95
+ }
96
+ // For Anthropic provider, use existing ANTHROPIC_API_KEY (no proxy needed)
97
+ logger.info('Multi-provider configuration', {
98
+ provider,
99
+ model: finalModel,
100
+ hasApiKey: !!envOverrides.ANTHROPIC_API_KEY || !!process.env.ANTHROPIC_API_KEY,
101
+ hasBaseURL: !!envOverrides.ANTHROPIC_BASE_URL
102
+ });
103
+ try {
104
+ // MCP server setup - enable in-SDK server and optional external servers
105
+ const mcpServers = {};
106
+ // Enable in-SDK MCP server for custom tools
107
+ if (process.env.ENABLE_CLAUDE_FLOW_SDK === 'true') {
108
+ mcpServers['claude-flow-sdk'] = claudeFlowSdkServer;
109
+ }
110
+ // Optional external MCP servers (disabled by default to avoid subprocess failures)
111
+ // Enable by setting ENABLE_CLAUDE_FLOW_MCP=true or ENABLE_FLOW_NEXUS_MCP=true
112
+ if (process.env.ENABLE_CLAUDE_FLOW_MCP === 'true') {
113
+ mcpServers['claude-flow'] = {
114
+ type: 'stdio',
115
+ command: 'npx',
116
+ args: ['claude-flow@alpha', 'mcp', 'start'],
117
+ env: {
118
+ ...process.env,
119
+ MCP_AUTO_START: 'true',
120
+ PROVIDER: provider
121
+ }
122
+ };
123
+ }
124
+ if (process.env.ENABLE_FLOW_NEXUS_MCP === 'true') {
125
+ mcpServers['flow-nexus'] = {
126
+ type: 'stdio',
127
+ command: 'npx',
128
+ args: ['flow-nexus@latest', 'mcp', 'start'],
129
+ env: {
130
+ ...process.env,
131
+ FLOW_NEXUS_AUTO_START: 'true'
132
+ }
133
+ };
134
+ }
135
+ if (process.env.ENABLE_AGENTIC_PAYMENTS_MCP === 'true') {
136
+ mcpServers['agentic-payments'] = {
137
+ type: 'stdio',
138
+ command: 'npx',
139
+ args: ['-y', 'agentic-payments', 'mcp'],
140
+ env: {
141
+ ...process.env,
142
+ AGENTIC_PAYMENTS_AUTO_START: 'true'
143
+ }
144
+ };
145
+ }
146
+ const queryOptions = {
18
147
  systemPrompt: agent.systemPrompt,
19
- model: modelOverride, // Support custom models like OpenRouter
148
+ model: finalModel, // Claude Agent SDK handles model selection
20
149
  permissionMode: 'bypassPermissions', // Auto-approve all tool usage for Docker automation
21
- mcpServers: {
22
- // In-SDK server: 6 basic tools (memory + swarm)
23
- 'claude-flow-sdk': claudeFlowSdkServer,
24
- // Full MCP server: 101 tools via subprocess (neural, analysis, workflow, github, daa, system)
25
- 'claude-flow': {
26
- command: 'npx',
27
- args: ['claude-flow@alpha', 'mcp', 'start'],
28
- env: {
29
- ...process.env,
30
- MCP_AUTO_START: 'true'
31
- }
32
- },
33
- // Flow Nexus MCP server: 96 cloud tools (sandboxes, swarms, neural, workflows)
34
- 'flow-nexus': {
35
- command: 'npx',
36
- args: ['flow-nexus@latest', 'mcp', 'start'],
37
- env: {
38
- ...process.env,
39
- FLOW_NEXUS_AUTO_START: 'true'
40
- }
41
- },
42
- // Agentic Payments MCP server: Payment authorization and multi-agent consensus
43
- 'agentic-payments': {
44
- command: 'npx',
45
- args: ['-y', 'agentic-payments', 'mcp'],
46
- env: {
47
- ...process.env,
48
- AGENTIC_PAYMENTS_AUTO_START: 'true'
49
- }
50
- }
51
- }
52
- // allowedTools: removed to enable ALL tools from all servers
150
+ // Enable all built-in tools by default (Read, Write, Edit, Bash, Glob, Grep, WebFetch, WebSearch)
151
+ // Based on SDK types, allowedTools and disallowedTools control which tools are available
152
+ // If not specified, all tools are enabled by default
153
+ allowedTools: [
154
+ 'Read',
155
+ 'Write',
156
+ 'Edit',
157
+ 'Bash',
158
+ 'Glob',
159
+ 'Grep',
160
+ 'WebFetch',
161
+ 'WebSearch',
162
+ 'NotebookEdit',
163
+ 'TodoWrite'
164
+ ],
165
+ // Add MCP servers if configured
166
+ mcpServers: Object.keys(mcpServers).length > 0 ? mcpServers : undefined
167
+ };
168
+ // Add environment overrides if present
169
+ if (Object.keys(envOverrides).length > 0) {
170
+ queryOptions.env = {
171
+ ...process.env,
172
+ ...envOverrides
173
+ };
53
174
  }
54
- });
55
- let output = '';
56
- for await (const msg of result) {
57
- if (msg.type === 'assistant') {
58
- const chunk = msg.message.content?.map((c) => c.type === 'text' ? c.text : '').join('') || '';
59
- output += chunk;
60
- if (onStream && chunk) {
61
- onStream(chunk);
175
+ const result = query({
176
+ prompt: input,
177
+ options: queryOptions
178
+ });
179
+ let output = '';
180
+ for await (const msg of result) {
181
+ if (msg.type === 'assistant') {
182
+ const chunk = msg.message.content?.map((c) => c.type === 'text' ? c.text : '').join('') || '';
183
+ output += chunk;
184
+ if (onStream && chunk) {
185
+ onStream(chunk);
186
+ }
62
187
  }
63
188
  }
189
+ const duration = Date.now() - startTime;
190
+ logger.info('Claude Agent SDK completed', {
191
+ agent: agent.name,
192
+ provider,
193
+ duration,
194
+ outputLength: output.length
195
+ });
196
+ return { output, agent: agent.name };
197
+ }
198
+ catch (error) {
199
+ logger.error('Claude Agent SDK execution failed', {
200
+ provider,
201
+ model: finalModel,
202
+ error: error.message
203
+ });
204
+ throw error;
64
205
  }
65
- const duration = Date.now() - startTime;
66
- logger.info('Claude agent completed', {
67
- agent: agent.name,
68
- duration,
69
- outputLength: output.length
70
- });
71
- return { output, agent: agent.name };
72
206
  });
73
207
  }
@@ -253,8 +253,7 @@ export async function directApiAgent(agent, input, onStream) {
253
253
  : (process.env.COMPLETION_MODEL || 'meta-llama/llama-3.1-8b-instruct'),
254
254
  messages: messagesWithSystem,
255
255
  maxTokens: 8192,
256
- temperature: 0.7,
257
- provider: provider // Force the router to use this specific provider
256
+ temperature: 0.7
258
257
  };
259
258
  const routerResponse = await routerInstance.chat(params);
260
259
  // Convert router response to Anthropic format
@@ -0,0 +1,151 @@
1
+ // Claude Agent SDK with multi-provider proxy routing
2
+ // Architecture: SDK → Proxy Router → Multi-provider (Anthropic/OpenRouter/Gemini/ONNX)
3
+ import { query } from '@anthropic-ai/claude-agent-sdk';
4
+ import { logger } from '../utils/logger.js';
5
+ import { withRetry } from '../utils/retry.js';
6
+ import { ModelRouter } from '../router/router.js';
7
+ import { claudeFlowSdkServer } from '../mcp/claudeFlowSdkServer.js';
8
+ // Lazy initialize router
9
+ let router = null;
10
+ function getRouter() {
11
+ if (!router) {
12
+ router = new ModelRouter();
13
+ }
14
+ return router;
15
+ }
16
+ function getCurrentProvider() {
17
+ // Determine provider from environment
18
+ if (process.env.PROVIDER === 'gemini' || process.env.USE_GEMINI === 'true') {
19
+ return 'gemini';
20
+ }
21
+ if (process.env.PROVIDER === 'openrouter' || process.env.USE_OPENROUTER === 'true') {
22
+ return 'openrouter';
23
+ }
24
+ if (process.env.PROVIDER === 'onnx' || process.env.USE_ONNX === 'true') {
25
+ return 'onnx';
26
+ }
27
+ return 'anthropic'; // Default
28
+ }
29
+ /**
30
+ * Get model configuration for the specified provider
31
+ * Returns model name, API key, and optional proxy URL for routing
32
+ */
33
+ function getModelForProvider(provider) {
34
+ switch (provider) {
35
+ case 'gemini':
36
+ return {
37
+ model: process.env.COMPLETION_MODEL || 'gemini-2.0-flash-exp',
38
+ apiKey: process.env.GOOGLE_GEMINI_API_KEY || process.env.ANTHROPIC_API_KEY || '',
39
+ baseURL: process.env.PROXY_URL || undefined // Optional: Proxy routes SDK calls to Gemini
40
+ };
41
+ case 'openrouter':
42
+ return {
43
+ model: process.env.COMPLETION_MODEL || 'meta-llama/llama-3.1-8b-instruct',
44
+ apiKey: process.env.OPENROUTER_API_KEY || process.env.ANTHROPIC_API_KEY || '',
45
+ baseURL: process.env.PROXY_URL || undefined // Optional: Proxy routes SDK calls to OpenRouter
46
+ };
47
+ case 'onnx':
48
+ return {
49
+ model: 'onnx-local',
50
+ apiKey: 'local', // Not needed for local inference
51
+ baseURL: process.env.PROXY_URL || undefined // Optional: Proxy routes to ONNX runtime
52
+ };
53
+ case 'anthropic':
54
+ default:
55
+ const apiKey = process.env.ANTHROPIC_API_KEY;
56
+ if (!apiKey) {
57
+ throw new Error('ANTHROPIC_API_KEY is required but not set');
58
+ }
59
+ if (!apiKey.startsWith('sk-ant-')) {
60
+ throw new Error(`Invalid ANTHROPIC_API_KEY format. Expected: sk-ant-...\\n` +
61
+ `Got: ${apiKey.substring(0, 10)}...`);
62
+ }
63
+ return {
64
+ model: process.env.COMPLETION_MODEL || 'claude-sonnet-4-5-20250929',
65
+ apiKey,
66
+ // No baseURL for direct Anthropic - SDK uses official endpoint
67
+ };
68
+ }
69
+ }
70
+ /**
71
+ * Main agent execution using Claude Agent SDK
72
+ * The SDK handles tool calling, streaming, and conversation management
73
+ * The proxy router enables multi-provider support (Anthropic/OpenRouter/Gemini/ONNX)
74
+ */
75
+ export async function sdkAgent(agent, input, onStream) {
76
+ const startTime = Date.now();
77
+ const provider = getCurrentProvider();
78
+ logger.info('Starting Claude Agent SDK with multi-provider routing', {
79
+ agent: agent.name,
80
+ provider,
81
+ input: input.substring(0, 100)
82
+ });
83
+ return withRetry(async () => {
84
+ // Get the model configuration for the selected provider
85
+ const modelConfig = getModelForProvider(provider);
86
+ logger.info('Provider configuration', {
87
+ provider,
88
+ model: modelConfig.model,
89
+ hasProxy: !!modelConfig.baseURL,
90
+ proxyUrl: modelConfig.baseURL
91
+ });
92
+ // Build Claude Agent SDK options
93
+ const queryOptions = {
94
+ systemPrompt: agent.systemPrompt || 'You are a helpful AI assistant.',
95
+ model: modelConfig.model,
96
+ permissionMode: 'bypassPermissions', // Auto-approve tools for automation
97
+ // Configure SDK's Anthropic client
98
+ // If baseURL is set, it acts as a proxy that routes to different providers
99
+ anthropicOptions: {
100
+ apiKey: modelConfig.apiKey,
101
+ ...(modelConfig.baseURL && { baseURL: modelConfig.baseURL })
102
+ },
103
+ // Attach MCP servers for tool access (111 tools from claude-flow)
104
+ mcpServers: {
105
+ // In-SDK server: Basic memory + coordination tools
106
+ 'claude-flow-sdk': claudeFlowSdkServer,
107
+ // Full MCP server: 101 advanced tools
108
+ 'claude-flow': {
109
+ command: 'npx',
110
+ args: ['claude-flow@alpha', 'mcp', 'start'],
111
+ env: {
112
+ ...process.env,
113
+ MCP_AUTO_START: 'true',
114
+ PROVIDER: provider // Pass provider to MCP tools
115
+ }
116
+ }
117
+ }
118
+ };
119
+ // Execute with Claude Agent SDK
120
+ // The SDK handles:
121
+ // - Tool calling loops
122
+ // - Streaming
123
+ // - Error handling
124
+ // - Conversation management
125
+ let output = '';
126
+ const result = query({
127
+ prompt: input,
128
+ options: queryOptions
129
+ });
130
+ for await (const msg of result) {
131
+ if (msg.type === 'assistant') {
132
+ const chunk = msg.message.content
133
+ ?.map((c) => c.type === 'text' ? c.text : '')
134
+ .join('') || '';
135
+ output += chunk;
136
+ if (onStream && chunk) {
137
+ onStream(chunk);
138
+ }
139
+ }
140
+ }
141
+ const duration = Date.now() - startTime;
142
+ logger.info('Claude Agent SDK completed', {
143
+ agent: agent.name,
144
+ provider,
145
+ model: modelConfig.model,
146
+ duration,
147
+ outputLength: output.length
148
+ });
149
+ return { output, agent: agent.name };
150
+ });
151
+ }
package/dist/cli-proxy.js CHANGED
@@ -28,7 +28,7 @@ import { AnthropicToOpenRouterProxy } from "./proxy/anthropic-to-openrouter.js";
28
28
  import { logger } from "./utils/logger.js";
29
29
  import { parseArgs } from "./utils/cli.js";
30
30
  import { getAgent, listAgents } from "./utils/agentLoader.js";
31
- import { directApiAgent } from "./agents/directApiAgent.js";
31
+ import { claudeAgent } from "./agents/claudeAgent.js";
32
32
  import { handleConfigCommand } from "./cli/config-wizard.js";
33
33
  import { handleAgentCommand } from "./cli/agent-manager.js";
34
34
  import { ModelOptimizer } from "./utils/modelOptimizer.js";
@@ -286,8 +286,8 @@ class AgenticFlowCLI {
286
286
  }
287
287
  console.log('⏳ Running...\n');
288
288
  const streamHandler = options.stream ? (chunk) => process.stdout.write(chunk) : undefined;
289
- // Use directApiAgent (works without Claude Code installed) instead of claudeAgent (requires Claude Code)
290
- const result = await directApiAgent(agent, task, streamHandler);
289
+ // Use claudeAgent with Claude Agent SDK - handles multi-provider routing
290
+ const result = await claudeAgent(agent, task, streamHandler);
291
291
  if (!options.stream) {
292
292
  console.log('\n✅ Completed!\n');
293
293
  console.log('═══════════════════════════════════════\n');