{"record":{"id":"c15304e57754a571","repo":"ruvnet/ruflo","slug":"provider-call-failed","errorCode":null,"errorMessage":"provider call failed","messagePattern":"provider call failed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/ruvector/agent-wasm.ts","lineNumber":172,"sourceCode":" * Called once at agent-creation time; the provider stays attached for the\n * agent's lifetime.  No-op (returns false) when no provider keys are\n * configured so the echo-fallback path below is preserved for keyless\n * environments.\n */\nasync function attachJsModelProvider(agent: any, config: WasmAgentConfig): Promise<boolean> {\n  const hasAny = !!(process.env.ANTHROPIC_API_KEY || process.env.OPENROUTER_API_KEY || process.env.OLLAMA_API_KEY);\n  if (!hasAny) return false;\n  const mod = await import('@ruvector/rvagent-wasm');\n  const { callAnthropicMessages, resolveAnthropicModel } = await import('../mcp-tools/agent-execute-core.js');\n  const model = resolveAnthropicModel(config.model);\n  const systemPrompt = config.instructions || 'You are a helpful coding assistant running in a Ruflo WASM agent sandbox.';\n\n  const provider = new mod.JsModelProvider(async (messagesJson: string) => {\n    const messages: Array<{ role: string; content: string }> = JSON.parse(messagesJson);\n    const lastUser = [...messages].reverse().find(m => m.role === 'user');\n    const prompt = lastUser?.content ?? messagesJson;\n    const result = await callAnthropicMessages({ prompt, systemPrompt, model, maxTokens: 2048 });\n    if (!result.success) throw new Error(result.error ?? 'provider call failed');\n    return JSON.stringify({ role: 'assistant', content: result.output ?? '' });\n  });\n  agent.set_model_provider(provider);\n  return true;\n}\n\n/**\n * Send a prompt to a WASM agent.\n *\n * ADR-129 P1: JsModelProvider is now wired at creation time so the WASM\n * agent's internal conversation loop (multi-turn state, turn_count,\n * stop conditions) runs against a real LLM.  The echo-stub detection\n * block is kept as a fallback for keyless environments (CI, sandboxed\n * test runners) — behaviour is identical to the pre-P1 path when no\n * provider key is set.\n *\n * Billing note: every wasm_agent_prompt call with a provider key\n * configured makes a billable LLM call.  Use a keyless environment to","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/ruvector/agent-wasm.ts#L154-L190","documentation":"Thrown inside the JsModelProvider callback wired into a WASM agent: callAnthropicMessages() returned success=false, and when its error field was empty this generic message is used. The backing LLM HTTP call failed before producing output — auth, network, model, or quota — so the WASM agent's conversation turn cannot proceed.","triggerScenarios":"ANTHROPIC_API_KEY (or the resolved provider key) set but invalid/expired (401); rate limit or quota exhausted (429); network egress blocked from the sandbox; resolveAnthropicModel(config.model) producing a model id the API rejects.","commonSituations":"Rotated API keys with stale env vars in long-lived shells; CI runners without egress to the provider API; retired model names pinned in config; token quota exhausted mid-run.","solutions":["Verify the key with a minimal authenticated request to the provider and expect 200/400 rather than 401","Check the resolved model: log resolveAnthropicModel(config.model) and confirm it is a currently valid model id","Retry after rate-limit windows and confirm remaining quota in the provider console","Run keyless (unset ANTHROPIC_API_KEY / OPENROUTER_API_KEY / OLLAMA_API_KEY) when the echo stub is sufficient — it makes no provider calls"],"exampleFix":"# before\nexport ANTHROPIC_API_KEY=sk-ant-expired   # promptWasmAgent → 'provider call failed'\n# after\nexport ANTHROPIC_API_KEY=<valid key>\n# or, for cost-free sandboxing:\nunset ANTHROPIC_API_KEY OPENROUTER_API_KEY OLLAMA_API_KEY   # echo stub","handlingStrategy":"fallback","validationCode":"const hasKey = !!(process.env.ANTHROPIC_API_KEY || process.env.OPENROUTER_API_KEY || process.env.OLLAMA_API_KEY);\nif (!hasKey) {\n  // keyless path: agents run on the echo stub, no provider calls are made\n  console.log('no provider key set — echo stub in effect');\n}","typeGuard":"const isProviderCallFailure = (e: unknown): e is Error =>\n  e instanceof Error && /provider call failed/.test(e.message);","tryCatchPattern":"try {\n  return await promptWasmAgent(agentId, input);\n} catch (e) {\n  if (isProviderCallFailure(e)) {\n    await ensureProviderReachable();  // key/network sanity check\n    return `echo: ${input}`;          // fall back to keyless echo-stub behaviour\n  }\n  throw e;\n}","preventionTips":["Validate API keys at startup with a cheap provider call","Unset provider keys in CI when the echo stub is intended","Watch provider status pages for rate limits during bulk runs","Log provider response bodies — this generic message means the underlying error field was empty"],"tags":["llm-provider","api-key","network","wasm-agent"],"backgroundTag":"llm-provider-call-failed","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}