claude-flow 3.7.0-alpha.77 → 3.7.0-alpha.78
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-flow",
|
|
3
|
-
"version": "3.7.0-alpha.
|
|
3
|
+
"version": "3.7.0-alpha.78",
|
|
4
4
|
"description": "Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -15,6 +15,7 @@ function behavioralRules() {
|
|
|
15
15
|
- NEVER save working files or tests to root — use \`/src\`, \`/tests\`, \`/docs\`, \`/config\`, \`/scripts\`
|
|
16
16
|
- ALWAYS read a file before editing it
|
|
17
17
|
- NEVER commit secrets, credentials, or .env files
|
|
18
|
+
- NEVER add a \`Co-Authored-By\` trailer to user commits unless this project's \`.claude/settings.json\` has \`attribution.commit\` set (#2078). The Claude Code Bash tool may suggest one in its default commit-message template — ignore it. \`Co-Authored-By\` is semantic authorship attribution under git/GitHub convention; the tool is the facilitator, not a co-author.
|
|
18
19
|
- Keep files under 500 lines
|
|
19
20
|
- Validate input at system boundaries`;
|
|
20
21
|
}
|
|
@@ -60,14 +60,31 @@ export async function callAnthropicMessages(input) {
|
|
|
60
60
|
const explicitProvider = (process.env.RUFLO_PROVIDER || '').toLowerCase();
|
|
61
61
|
const ollamaKey = process.env.OLLAMA_API_KEY;
|
|
62
62
|
const anthropicKey = process.env.ANTHROPIC_API_KEY;
|
|
63
|
-
|
|
63
|
+
// #2042 — OpenRouter is an OpenAI-compat endpoint that fronts dozens of
|
|
64
|
+
// providers. Reporter (@ummcke00) had `providers.openrouter.apiKey` in
|
|
65
|
+
// their config.yaml but agent_execute hardcoded Anthropic. Detect via
|
|
66
|
+
// explicit RUFLO_PROVIDER=openrouter OR presence of OPENROUTER_API_KEY
|
|
67
|
+
// when no Anthropic key is available (same precedence as the Ollama
|
|
68
|
+
// branch above).
|
|
69
|
+
const openrouterKey = process.env.OPENROUTER_API_KEY;
|
|
70
|
+
const useOpenRouter = explicitProvider === 'openrouter' || (!anthropicKey && !!openrouterKey);
|
|
71
|
+
const useOllama = explicitProvider === 'ollama' || (!anthropicKey && !!ollamaKey && !openrouterKey);
|
|
72
|
+
if (useOpenRouter && openrouterKey) {
|
|
73
|
+
return callOpenAICompat({
|
|
74
|
+
...input,
|
|
75
|
+
apiKey: openrouterKey,
|
|
76
|
+
baseUrl: process.env.OPENROUTER_BASE_URL || 'https://openrouter.ai/api',
|
|
77
|
+
providerLabel: 'openrouter',
|
|
78
|
+
defaultModel: process.env.OPENROUTER_DEFAULT_MODEL || 'anthropic/claude-3.5-sonnet',
|
|
79
|
+
});
|
|
80
|
+
}
|
|
64
81
|
if (useOllama && ollamaKey) {
|
|
65
82
|
return callOllamaCompat({ ...input, apiKey: ollamaKey });
|
|
66
83
|
}
|
|
67
84
|
if (!anthropicKey) {
|
|
68
85
|
return {
|
|
69
86
|
success: false,
|
|
70
|
-
error: 'No LLM provider configured. Set ANTHROPIC_API_KEY (Tier-3) or OLLAMA_API_KEY (Tier-2
|
|
87
|
+
error: 'No LLM provider configured. Set ANTHROPIC_API_KEY (Tier-3), OPENROUTER_API_KEY (#2042), or OLLAMA_API_KEY (Tier-2 — #1725).',
|
|
71
88
|
};
|
|
72
89
|
}
|
|
73
90
|
const model = input.model || DEFAULT_ANTHROPIC_MODEL;
|
|
@@ -202,6 +219,88 @@ async function callOllamaCompat(input) {
|
|
|
202
219
|
};
|
|
203
220
|
}
|
|
204
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* Generic OpenAI-compat caller for OpenRouter and other OpenAI-shaped
|
|
224
|
+
* endpoints. #2042 — reporter (@ummcke00) configured OpenRouter via
|
|
225
|
+
* config.yaml but agent_execute hardcoded the Anthropic fetch. This is
|
|
226
|
+
* the same shape as `callOllamaCompat` but routes to a configurable
|
|
227
|
+
* baseUrl + sends an OpenRouter-friendly default model when none is
|
|
228
|
+
* specified. Logical model names (haiku/sonnet/opus) pass through —
|
|
229
|
+
* OpenRouter accepts vendor-prefixed names like `anthropic/claude-3.5-sonnet`.
|
|
230
|
+
*/
|
|
231
|
+
async function callOpenAICompat(input) {
|
|
232
|
+
const model = resolveOpenAICompatModel(input.model, input.defaultModel);
|
|
233
|
+
const startedAt = Date.now();
|
|
234
|
+
const base = input.baseUrl.replace(/\/+$/, '');
|
|
235
|
+
const url = `${base}/v1/chat/completions`;
|
|
236
|
+
try {
|
|
237
|
+
const controller = new AbortController();
|
|
238
|
+
const timer = setTimeout(() => controller.abort(), input.timeoutMs || 60000);
|
|
239
|
+
const messages = [];
|
|
240
|
+
if (input.systemPrompt)
|
|
241
|
+
messages.push({ role: 'system', content: input.systemPrompt });
|
|
242
|
+
messages.push({ role: 'user', content: input.prompt });
|
|
243
|
+
const res = await fetch(url, {
|
|
244
|
+
method: 'POST',
|
|
245
|
+
headers: {
|
|
246
|
+
Authorization: `Bearer ${input.apiKey}`,
|
|
247
|
+
'content-type': 'application/json',
|
|
248
|
+
// OpenRouter convention: identify the integrating app for analytics
|
|
249
|
+
// and rate-limit tiering. Harmless on other OpenAI-compat backends.
|
|
250
|
+
'HTTP-Referer': 'https://github.com/ruvnet/ruflo',
|
|
251
|
+
'X-Title': 'Ruflo',
|
|
252
|
+
},
|
|
253
|
+
body: JSON.stringify({
|
|
254
|
+
model,
|
|
255
|
+
max_tokens: input.maxTokens || 1024,
|
|
256
|
+
temperature: typeof input.temperature === 'number' ? input.temperature : 0.7,
|
|
257
|
+
messages,
|
|
258
|
+
}),
|
|
259
|
+
signal: controller.signal,
|
|
260
|
+
});
|
|
261
|
+
clearTimeout(timer);
|
|
262
|
+
if (!res.ok) {
|
|
263
|
+
const errText = await res.text().catch(() => '<unreadable error body>');
|
|
264
|
+
return { success: false, model, error: `${input.providerLabel} API error ${res.status}: ${errText.slice(0, 400)}` };
|
|
265
|
+
}
|
|
266
|
+
const data = await res.json();
|
|
267
|
+
const textOut = data.choices?.[0]?.message?.content ?? '';
|
|
268
|
+
const usage = data.usage ?? {};
|
|
269
|
+
return {
|
|
270
|
+
success: true,
|
|
271
|
+
model: data.model || model,
|
|
272
|
+
messageId: data.id,
|
|
273
|
+
stopReason: data.choices?.[0]?.finish_reason ?? 'end_turn',
|
|
274
|
+
output: textOut,
|
|
275
|
+
usage: {
|
|
276
|
+
inputTokens: usage.prompt_tokens ?? 0,
|
|
277
|
+
outputTokens: usage.completion_tokens ?? 0,
|
|
278
|
+
totalTokens: usage.total_tokens ?? 0,
|
|
279
|
+
},
|
|
280
|
+
durationMs: Date.now() - startedAt,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
catch (err) {
|
|
284
|
+
return {
|
|
285
|
+
success: false,
|
|
286
|
+
model,
|
|
287
|
+
error: err instanceof Error ? err.message : String(err),
|
|
288
|
+
durationMs: Date.now() - startedAt,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function resolveOpenAICompatModel(input, fallback) {
|
|
293
|
+
if (!input)
|
|
294
|
+
return fallback;
|
|
295
|
+
// Logical Claude names → OpenRouter Anthropic-vendored names
|
|
296
|
+
if (input === 'haiku')
|
|
297
|
+
return 'anthropic/claude-3.5-haiku';
|
|
298
|
+
if (input === 'sonnet' || input === 'inherit')
|
|
299
|
+
return 'anthropic/claude-3.5-sonnet';
|
|
300
|
+
if (input === 'opus')
|
|
301
|
+
return 'anthropic/claude-3-opus';
|
|
302
|
+
return input;
|
|
303
|
+
}
|
|
205
304
|
function resolveOllamaModel(input) {
|
|
206
305
|
const DEFAULT = 'gpt-oss:120b-cloud';
|
|
207
306
|
if (!input)
|
|
@@ -232,15 +331,6 @@ export function resolveAnthropicModel(input) {
|
|
|
232
331
|
return input;
|
|
233
332
|
}
|
|
234
333
|
export async function executeAgentTask(input) {
|
|
235
|
-
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
236
|
-
if (!apiKey) {
|
|
237
|
-
return {
|
|
238
|
-
success: false,
|
|
239
|
-
agentId: input.agentId,
|
|
240
|
-
error: 'ANTHROPIC_API_KEY not set in environment',
|
|
241
|
-
remediation: 'Set the env var and re-run. The key is read at call time.',
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
334
|
const store = loadAgentStore();
|
|
245
335
|
const agent = store.agents[input.agentId];
|
|
246
336
|
if (!agent)
|
|
@@ -256,73 +346,50 @@ export async function executeAgentTask(input) {
|
|
|
256
346
|
agent.taskCount = (agent.taskCount || 0) + 1;
|
|
257
347
|
saveAgentStore(store);
|
|
258
348
|
const startedAt = Date.now();
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}),
|
|
277
|
-
signal: controller.signal,
|
|
278
|
-
});
|
|
279
|
-
clearTimeout(timer);
|
|
280
|
-
if (!res.ok) {
|
|
281
|
-
const errText = await res.text().catch(() => '<unreadable error body>');
|
|
282
|
-
agent.status = 'idle';
|
|
283
|
-
saveAgentStore(store);
|
|
284
|
-
return {
|
|
285
|
-
success: false,
|
|
286
|
-
agentId: input.agentId,
|
|
287
|
-
model: anthropicModel,
|
|
288
|
-
error: `Anthropic API error ${res.status}: ${errText.slice(0, 400)}`,
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
const data = await res.json();
|
|
292
|
-
const textOut = data.content
|
|
293
|
-
.filter(c => c.type === 'text' && typeof c.text === 'string')
|
|
294
|
-
.map(c => c.text)
|
|
295
|
-
.join('');
|
|
296
|
-
const result = {
|
|
349
|
+
// #2042 — delegate to callAnthropicMessages so the v3 provider router
|
|
350
|
+
// (Anthropic / Ollama / OpenRouter) governs which backend is hit. The
|
|
351
|
+
// previous inline `fetch('https://api.anthropic.com/...')` bypassed
|
|
352
|
+
// the router entirely and forced an ANTHROPIC_API_KEY error for every
|
|
353
|
+
// non-Anthropic deployment. Reporter (@ummcke00) had OpenRouter
|
|
354
|
+
// configured but the bypass made the agent unreachable.
|
|
355
|
+
const result = await callAnthropicMessages({
|
|
356
|
+
model: anthropicModel,
|
|
357
|
+
prompt: input.prompt,
|
|
358
|
+
systemPrompt,
|
|
359
|
+
maxTokens: input.maxTokens,
|
|
360
|
+
temperature: input.temperature,
|
|
361
|
+
timeoutMs: input.timeoutMs,
|
|
362
|
+
});
|
|
363
|
+
agent.status = 'idle';
|
|
364
|
+
if (result.success) {
|
|
365
|
+
const out = {
|
|
297
366
|
success: true,
|
|
298
367
|
agentId: input.agentId,
|
|
299
|
-
messageId:
|
|
300
|
-
model:
|
|
301
|
-
stopReason:
|
|
302
|
-
output:
|
|
303
|
-
usage:
|
|
304
|
-
|
|
305
|
-
outputTokens: data.usage.output_tokens,
|
|
306
|
-
totalTokens: data.usage.input_tokens + data.usage.output_tokens,
|
|
307
|
-
},
|
|
308
|
-
durationMs: Date.now() - startedAt,
|
|
368
|
+
messageId: result.messageId,
|
|
369
|
+
model: result.model,
|
|
370
|
+
stopReason: result.stopReason,
|
|
371
|
+
output: result.output,
|
|
372
|
+
usage: result.usage,
|
|
373
|
+
durationMs: result.durationMs ?? Date.now() - startedAt,
|
|
309
374
|
};
|
|
310
|
-
agent.
|
|
311
|
-
agent.lastResult = result;
|
|
312
|
-
saveAgentStore(store);
|
|
313
|
-
return result;
|
|
314
|
-
}
|
|
315
|
-
catch (err) {
|
|
316
|
-
agent.status = 'idle';
|
|
375
|
+
agent.lastResult = out;
|
|
317
376
|
saveAgentStore(store);
|
|
318
|
-
|
|
319
|
-
return {
|
|
320
|
-
success: false,
|
|
321
|
-
agentId: input.agentId,
|
|
322
|
-
model: anthropicModel,
|
|
323
|
-
error: `agent_execute failed: ${msg}`,
|
|
324
|
-
durationMs: Date.now() - startedAt,
|
|
325
|
-
};
|
|
377
|
+
return out;
|
|
326
378
|
}
|
|
379
|
+
saveAgentStore(store);
|
|
380
|
+
// No-provider-configured error → surface the same actionable message
|
|
381
|
+
// the router built, with a #2042-aware remediation pointer.
|
|
382
|
+
const noProvider = (result.error || '').includes('No LLM provider configured');
|
|
383
|
+
return {
|
|
384
|
+
success: false,
|
|
385
|
+
agentId: input.agentId,
|
|
386
|
+
model: anthropicModel,
|
|
387
|
+
error: result.error || 'agent_execute failed',
|
|
388
|
+
durationMs: result.durationMs ?? Date.now() - startedAt,
|
|
389
|
+
...(noProvider && {
|
|
390
|
+
remediation: 'Set one of ANTHROPIC_API_KEY, OPENROUTER_API_KEY (+ optional OPENROUTER_BASE_URL), or OLLAMA_API_KEY. ' +
|
|
391
|
+
'Or set RUFLO_PROVIDER=openrouter|ollama to force a specific provider.',
|
|
392
|
+
}),
|
|
393
|
+
};
|
|
327
394
|
}
|
|
328
395
|
//# sourceMappingURL=agent-execute-core.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claude-flow/cli",
|
|
3
|
-
"version": "3.7.0-alpha.
|
|
3
|
+
"version": "3.7.0-alpha.78",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Ruflo CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
|
|
6
6
|
"main": "dist/src/index.js",
|