Fuse multiple AI models and judge the best answer for coding
Project description
Fuse Fable
๐ Languages: English ยท เนเธเธข (Thai)
Fan out a coding prompt to many AI models in parallel, then let a judge pick the single best answer โ total latency โ x2 (slowest model + one judge pass), not x7โx15.
Works three ways: as a CLI, as an MCP server (connect Cursor / VS Code / Claude), and as a subagent / pipe (callable by other tools and scripts).
Install
pip install fusefable # core
pip install "fusefable[mcp]" # if you want the MCP server
From source:
git clone https://github.com/proultrax9/fusefable.git
cd fusefable
pip install -e ".[mcp]"
Setup (first run)
fusefable config
- Choose AI Gateway โ one key for everything, then it asks "how many models?" and
prompts for each one.
- Known gateways (base URL auto-filled):
openrouter,groq,together,fireworks,deepinfra,novita,hyperbolic,aimlapi,portkey,deepseek,openaiโ any other works too, just type its base URL.
- Known gateways (base URL auto-filled):
- Or Single providers โ it asks how many, then the API kind of each:
openai_compatโ any OpenAI-compatible endpoint (you provide the base URL)anthropicโ Anthropic native (/v1/messages, base URL auto-filled)googleโ Google Gemini native (generateContent, base URL auto-filled)
Set your API key as an environment variable named as the wizard asks:
export OPENROUTER_API_KEY=sk-... # macOS/Linux
setx OPENROUTER_API_KEY "sk-..." # Windows (open a new terminal afterwards)
Config is stored at ~/.fusefable/config.yaml.
1) Use as a CLI
fusefable ask "Write a quicksort function in Python"
fusefable ask --show-all "..." # show every answer + judge reason
fusefable ask --models gpt-5,qwen3-coder "..." # restrict to specific models
fusefable ask --cheap "..." # use cheap_models from config
ff ask "..." # short alias
2) Use as a subagent / in a pipe
fusefable ask --quiet "..." # print only the answer (no headers)
echo "Explain this code" | fusefable ask --quiet # read the prompt from stdin
cat bug.py | fusefable ask -q "Find the bug in this code"
fusefable ask --json "..." # JSON output: answer, chosen_model, reason, cost, candidates
--json is ideal for scripts/agents that parse the result; --quiet is ideal for piping.
3) Use as an MCP server (Cursor / VS Code / Claude / other agents)
Run as an MCP server over stdio:
fusefable mcp
Exposes a tool fuse_ask(question, models?, cheap?) for any MCP client.
Cursor
~/.cursor/mcp.json (or Settings โ MCP):
{
"mcpServers": {
"fusefable": {
"command": "fusefable",
"args": ["mcp"],
"env": { "OPENROUTER_API_KEY": "sk-..." }
}
}
}
VS Code (Copilot / MCP-compatible extension)
.vscode/mcp.json in your project:
{
"servers": {
"fusefable": {
"command": "fusefable",
"args": ["mcp"],
"env": { "OPENROUTER_API_KEY": "sk-..." }
}
}
}
Claude Desktop
claude_desktop_config.json:
{
"mcpServers": {
"fusefable": {
"command": "fusefable",
"args": ["mcp"],
"env": { "OPENROUTER_API_KEY": "sk-..." }
}
}
}
Requires
pip install "fusefable[mcp]"and a completedfusefable config. Iffusefableisn't on the app's PATH, use a full path such aspython -m fusefable.cli.
Prompt compression (save tokens)
Reduce token usage while keeping answer quality โ useful when you pay per-provider
directly. Two tiers, opt-in via --compress:
fusefable ask --compress "<long prompt or pasted code>"
# [compressed: 5200โ1800 chars, ~65% saved via llm]
- Tier 1 (lossless): trims trailing whitespace, collapses blank lines, strips zero-width chars โ keeps indentation and inner spacing intact (safe for code).
- Tier 2 (LLM): for prompts above
compress_min_chars(default 2000), a cheap model compresses semantically โ once, then the compressed prompt is sent to all models, so you savetokens ร number-of-models. - Quality guards: prompts under the threshold skip the LLM; if the compressed result is empty, longer, or under 30% of the original, it falls back to the lossless text. The judge always sees the original question.
Config (~/.fusefable/config.yaml): compress, compress_min_chars, compress_model
(empty = reuse the judge model).
Architecture
ENTRYPOINTS (one shared core)
โโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโ
โ CLI โ pipe / subagent โ MCP server โ
โ fusefable โ stdin ยท --quiet โ fusefable mcp โ
โ ask "..." โ ยท --json โ tool: fuse_ask() โ
โโโโโโโโฌโโโโโโโดโโโโโโโโโฌโโโโโโโโโโดโโโโโโโโโโโฌโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโ ~/.fusefable/config.yaml
โ core.fuse() โโโโโโ (gateway | single providers,
โโโโโโโโโโโฌโโโโโโโโโโ models, judge, timeout)
โ
โผ
โโโโโโโโโโโโโโโโโโโโโ
โ routing โ build (provider, model) routes
โ + provider โ via factory โ pick adapter by kind
โ factory โ
โโโโโโโโโโโฌโโโโโโโโโโ
โผ
โโโโโโโโโโโโโโโ FAN-OUT (asyncio.gather) โโโโโโโโโโโโโโโ
โ เธเธธเธเธเธฑเธงเธขเธดเธเธเธฃเนเธญเธกเธเธฑเธ ยท per-model timeout ยท เธเธฑเธงเธเธฑเธ = เธเธฑเธเธเธดเนเธ โ
โ โ
โผ โผ โผ โผ โผ
โโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโ
โ openai_ โ โ anthropicโ โ google โ โ openai_ โ โ ... โ
โ compat โ โ native โ โ native โ โ compat โ โ โ
โ(gateway)โ โ/v1/msgs โ โgenerateContโ โ โ โ โ
โโโโโโฌโโโโโ โโโโโโฌโโโโโโ โโโโโโโฌโโโโโโโ โโโโโโฌโโโโโโ โโโโโฌโโโโโ
โโโโโโโโโโโโโดโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโดโโโโโโโโโโโโ
โ Completion[] (เธชเธณเนเธฃเนเธเนเธเนเธฒเธเธฑเนเธ)
โผ
โโโโโโโโโโโโโโโโโโโโโ
โ judge โ เธเธเธเธดเธเธเธทเนเธญ โ Answer A/B/C...
โ (anonymized) โ เนเธซเน judge model เนเธฅเธทเธญเธเธเธฑเธงเธเธตเธชเธธเธ
โโโโโโโโโโโฌโโโโโโโโโโ (เธเธฑเธ โ fallback เธเธฑเธงเนเธฃเธ)
โผ
โโโโโโโโโโโโโโโโโโโโโ
โ FinalAnswer โ text ยท chosen_model ยท reason
โ (+ cost estimate)โ ยท cost_usd ยท candidates
โโโโโโโโโโโโโโโโโโโโโ
Request lifecycle
- Entrypoint โ CLI, a pipe/subagent call, or the MCP tool
fuse_ask()โ all funnel into one core functioncore.fuse(). - Routing โ config (gateway or single providers) is turned into
(provider, model)routes; a provider factory picks the right adapter perkind(openai_compat/anthropic/google). - Fan-out โ every model is called concurrently via
asyncio.gather(total time = slowest model). Each call has its own timeout; any model that times out or errors is dropped and never slows the run. - Judge โ model names are anonymized (Answer A/B/C...) so the judge picks on quality alone, not by brand; if the judge fails it falls back to the first answer.
- Result โ returns the best answer with the chosen model, the judge's reason, an estimated cost, and all candidates.
Components (fusefable/)
| File | Responsibility |
|---|---|
cli.py |
Typer CLI (ask / config / mcp), output modes |
mcp_server.py |
MCP server exposing the fuse_ask tool |
core.py |
shared fuse() entrypoint + model selection |
config.py |
load/save config.yaml |
wizard.py |
interactive setup (gateway vs single, API kind) |
routing.py |
config โ (provider, model) routes |
providers/factory.py |
pick adapter by kind |
providers/openai_compat.py ยท anthropic.py ยท google.py |
provider adapters |
fanout.py |
parallel fan-out (drops failures) |
judge.py |
anonymized judging |
fusion.py |
orchestrator: fan-out โ judge โ FinalAnswer |
cost.py |
token-based cost estimate |
models.py |
dataclasses: Completion, FinalAnswer, ProviderConfig |
Development
pip install -e ".[dev,mcp]"
pytest -q
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fusefable-0.2.0.tar.gz.
File metadata
- Download URL: fusefable-0.2.0.tar.gz
- Upload date:
- Size: 26.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7b58d1171a7b36b369b02c552b3158047a1cef852ad99a4cd5dd57d80d890cfe
|
|
| MD5 |
de133e354a36d6d36bd664bca2c7d058
|
|
| BLAKE2b-256 |
cd4f79c2c1808484edc0a06f0d3eee59ed22631237745cec1351e3cbab78e0b2
|
File details
Details for the file fusefable-0.2.0-py3-none-any.whl.
File metadata
- Download URL: fusefable-0.2.0-py3-none-any.whl
- Upload date:
- Size: 23.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
18562a60b12c26fa6c9627c60fe3b7dc89790ab25b509f76b87f5414843bfe41
|
|
| MD5 |
66b995b6635b4c5d1354d04031298d37
|
|
| BLAKE2b-256 |
fcc08c33eb3302ce3f2c8796c71420d3f48cb12e15ef8f85f3633b52fb58c1e8
|