Load, unload, and swap any number of local LLMs (LM Studio, Ollama, llama.cpp, ...) with full client-side control — plus unified streaming for local and cloud backends and an MCP server so agents can manage your VRAM.
Project description
promptchain
Load, unload, and swap any number of local LLMs on one GPU — with full, explicit control. A small library for driving LM Studio, Ollama, and any OpenAI-compatible server from Python, plus unified streaming across local and cloud backends, and an MCP server so agents can manage your VRAM for you.
Servers already handle the automatic case — LM Studio auto-evicts, Ollama's keep_alive expires, llama-swap proxies swapping for the servers it manages. What none of them give you is one client that spans LM Studio + Ollama + any OpenAI-compatible endpoint with a policy engine on top: pin a model so it's never evicted, pre-warm the next one before you need it, swap a whole working set in one call, cap residency by count or VRAM budget — and hand all of that to your agent over MCP.
pip install promptchain
Quickstart
from promptchain import ModelManager, Endpoint
# One GPU, one model resident at a time; evict after 5 min idle.
mgr = ModelManager(policy="auto", max_resident=1, idle_unload=300)
mgr.register("drafter", Endpoint("lmstudio", "gemma-4-4b"))
mgr.register("coder", Endpoint("ollama", "qwen3-coder:30b"), priority=10)
mgr.register("reviewer", Endpoint("anthropic", "claude-sonnet-5")) # cloud: never counts against VRAM
with mgr.use("coder") as m: # evicts 'drafter' first if needed, loads 'coder'
for token in m.stream(user_message="write fizzbuzz in rust"):
print(token, end="", flush=True)
mgr.resident() # -> ["coder"]
Full control over the GPU
mgr.load("coder", wait=True) # pre-warm, block until the server reports it ready
mgr.preload("critic") # pre-warm in the background
mgr.swap("drafter", "coder") # atomic unload -> load in one call
mgr.pin("coder"); mgr.unpin("coder")# pinned models are never auto-evicted
mgr.group("review", ["critic", "fixer"])
mgr.activate("review") # swap a whole working set in; evict everything else
mgr.unload_all()
mgr.refresh_residency() # reconcile belief with the server (Ollama /api/ps, LM Studio REST)
mgr.stats() # per-model loads, evictions, tokens, est. cost
policy="auto"evicts other models as needed before a load — lowestpriorityfirst, least-recently-used as the tiebreak — undermax_residentand/orvram_budget.policy="manual"never loads or unloads implicitly; you drive every lifecycle change yourself.- Cloud and
custombackends stream normally but never count against VRAM and are never evicted.
Unified streaming
One stream() across every backend, returning a handle you iterate for tokens:
from promptchain import stream
resp = stream(backend="ollama", model="qwen3:8b", base_url="http://localhost:11434",
user_message="explain async/await")
text = resp.consume()
resp.usage # {"input_tokens": ..., "output_tokens": ...} (cloud backends)
resp.reasoning # hidden <think>...</think> reasoning, stripped from the visible text
resp.tool_calls # parsed tool calls when tools= was passed
Reasoning models (DeepSeek-R1 / Qwen3 / GLM) have their <think> blocks stripped automatically; Hermes-format <tool_call> tags are parsed out for local tool calling.
Backends
| Backend | Load / unload / ps |
Streaming | Usage reporting |
|---|---|---|---|
lmstudio |
✅ | ✅ | — |
ollama |
✅ | ✅ | — |
custom (llama.cpp, vLLM, llama-swap, Jan, and any OpenAI-compatible cloud) |
— | ✅ | ✅ (when keyed) |
openai |
n/a | ✅ | ✅ |
gemini |
n/a | ✅ | ✅ |
anthropic |
n/a | ✅ | ✅ |
API keys for the named clouds are read from OPENAI_API_KEY / ANTHROPIC_API_KEY / GEMINI_API_KEY. Install Anthropic support with pip install "promptchain[anthropic]" (OpenAI/Gemini need no extra — they're OpenAI-compatible).
Any OpenAI-compatible provider
Point the custom backend at any OpenAI-compatible endpoint and pass a key — DeepSeek, Groq, Together, Fireworks, OpenRouter, Mistral, DeepInfra, an authenticated vLLM, whatever:
Endpoint("custom", "deepseek-chat", base_url="https://api.deepseek.com", api_key="sk-...")
Endpoint("custom", "llama-3.3-70b", base_url="https://api.groq.com/openai", api_key="gsk-...")
Endpoint("custom", "anthropic/claude-sonnet-4", base_url="https://openrouter.ai/api", api_key="sk-or-...")
Set base_url to the part before /v1 — the library appends /v1/chat/completions. Token usage is reported whenever a key is present.
Let an agent manage your GPU (MCP)
pip install "promptchain[mcp]"
promptchain-mcp # stdio MCP server
Wire it into Hermes Agent, Claude Code, or Claude Desktop and it can ps your GPU, load/unload/swap models, and generate through them — in plain language. Models are configured in an endpoints.toml (auto-created on first run). See the agent setup guide.
The app built on this
The same repo ships the PromptChain app — a two-model Streamlit pipeline with a human review gate: a small local model drafts your prompt, you fix it, then the big (local or cloud) model writes the code. It's the flagship consumer of this library; clone the repo to run it.
Links
- Source, the app, examples, and full docs: https://github.com/atharva557/Prompt-Chaining
- Requires Python ≥ 3.10. MIT licensed.
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 promptchain-0.1.1.tar.gz.
File metadata
- Download URL: promptchain-0.1.1.tar.gz
- Upload date:
- Size: 35.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
35b621da758594a474f1c51840ea867194b45a6c08ee4786a235c767737dd7a1
|
|
| MD5 |
38117e332407108ea2a8d0fe5ab594d7
|
|
| BLAKE2b-256 |
05f8ece2b0771d8d773e62b527864d5e4adb27ddd31458608d0bb893bf06b207
|
File details
Details for the file promptchain-0.1.1-py3-none-any.whl.
File metadata
- Download URL: promptchain-0.1.1-py3-none-any.whl
- Upload date:
- Size: 38.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b3a94d73a164e9920629ea8c8efcf83fa901f9e4fba213bec918ca858ada484f
|
|
| MD5 |
9a156c98e6ea2863e77e089f8509b1c5
|
|
| BLAKE2b-256 |
61e534575b424c4b6f59f6aaa0f74004c51beb31219ae6deeb1b5b56ac0cb030
|