Run any HuggingFace transformers model from a Strands agent. A tool for every task, or the agent's own multimodal brain. Local. No API keys.
5
stars
7
commits
Python
primary language
Jul 23, 2026
updated
Run any HuggingFace transformers model from a Strands agent. A tool for every task, or the agent's own multimodal brain. Local. No API keys.
π Docs Β Β·Β β‘ 60-second hello Β Β·Β ποΈ See it work Β Β·Β π§© Two ways Β Β·Β π MCP Β Β·Β π§ͺ Examples
HuggingFace transformers already runs every model on earth. The missing piece
is a clean, dynamic bridge into an agent loop - without writing per-model glue
every time. This library is that bridge, two ways:
| What it is | You get | |
|---|---|---|
π οΈ use_transformers | one tool exposing every transformers task | discover Β· run a pipeline Β· call any class/method |
π§ TransformerModel | a local model as your Agent(model=β¦) brain | it sees, hears & speaks via content blocks |
Zero hardcoding.
core/registry.pyreads transformers' ownSUPPORTED_TASKStaxonomy at runtime - the day a task or model lands upstream, it works here. No code change. No version bump.
uv pip install strands-transformers # from PyPI
PYTHONPATH=. python examples/smoke.py # verify β "18/18 checks passed"
uv pip install -e . # editable from source
uv pip install -e ".[audio]" # soundfile, librosa (mp3/flac/ogg decode)
uv pip install -e ".[vision]" # torchvision (needed by VLMs!), opencv, av
uv pip install -e ".[training]" # trl, peft, accelerate
uv pip install -e ".[all]" # everything
WAV audio works with no extras. Vision models (SmolVLM, Qwen-VL, β¦) need
[vision]. device="auto" picks cuda β mps β cpu (bf16 on GPU).
A 256M-param vision model, seeing pixels in the standard Strands loop - no key, no server:
import io
from PIL import Image
from strands import Agent
from strands_transformers import TransformerModel
buf = io.BytesIO(); Image.new("RGB", (64, 64), (20, 200, 40)).save(buf, "PNG") # a green square
model = TransformerModel(model_path="HuggingFaceTB/SmolVLM-256M-Instruct")
agent = Agent(model=model, system_prompt="You are concise.")
print(agent([
{"image": {"format": "png", "source": {"bytes": buf.getvalue()}}},
{"text": "Color? One word."},
]))
# β Green.
Swap model_path for any HF VLM and the code is identical.
Every result below is a real model output (CUDA Β· transformers 5.12 Β· torch 2.10):
| You give it | It returns | Example |
|---|---|---|
| πΌοΈ a green image + "Color?" | "Green." | multimodal_agent.py |
| π¬ brightening video frames | "BRIGHTER." | multimodal_advanced.py |
π§° a blue tool screenshot (in toolResult) | "Blue." | multimodal_advanced.py |
| π a text document | recovers BANANA-42 | document_and_audio.py |
| π a 440 Hz tone (Omni) | "It's a pure tone." | omni_audio.py |
| π¬ "say: β¦can speak" (Omni) | π real 24 kHz speech | omni_audio.py |
| π¦Ύ camera + "pick the cube" | actions [1, 30, 6] | molmoact_vla.py |
# πΌοΈ image β "Green." (local VLM brain, content blocks)
import io
from PIL import Image
from strands import Agent
from strands_transformers import TransformerModel
png = io.BytesIO(); Image.new("RGB", (224, 224), (20, 200, 40)).save(png, "PNG")
agent = Agent(model=TransformerModel(model_path="HuggingFaceTB/SmolVLM-256M-Instruct"))
print(agent([
{"image": {"format": "png", "source": {"bytes": png.getvalue()}}},
{"text": "What color is this image? One word."},
])) # β Green.
# π¬ video β "BRIGHTER." (a video content block of brightening frames)
import asyncio, numpy as np
from PIL import Image
from strands_transformers import TransformerModel
model = TransformerModel(model_path="HuggingFaceTB/SmolVLM2-500M-Video-Instruct",
params={"max_tokens": 48, "do_sample": False})
frames = [Image.fromarray(np.full((224, 224, 3), v, np.uint8)) for v in (10,40,80,120,160,200,230,250)]
msgs = [{"role": "user", "content": [
{"video": {"format": "mp4", "fps": 2.0, "source": {"bytes": frames}}},
{"text": "Does this video get brighter or darker? Answer brighter or darker."},
]}]
async def go():
return "".join([e.get("contentBlockDelta",{}).get("delta",{}).get("text","")
async for e in model.stream(msgs)])
print(asyncio.run(go())) # β ...brighter...
# π§° tool screenshot β "Blue." (an image returned inside a toolResult)
import asyncio, io
from PIL import Image
from strands_transformers import TransformerModel
blue = io.BytesIO(); Image.new("RGB", (224, 224), (25, 25, 210)).save(blue, "PNG")
model = TransformerModel(model_path="HuggingFaceTB/SmolVLM-256M-Instruct",
params={"max_tokens": 32, "do_sample": False})
msgs = [
{"role": "user", "content": [{"text": "Capture the screen, then name its color."}]},
{"role": "assistant", "content": [{"toolUse": {"name": "capture", "toolUseId": "t1", "input": {}}}]},
{"role": "user", "content": [{"toolResult": {"toolUseId": "t1", "status": "success", "content": [
{"text": "Here is the captured screen:"},
{"image": {"format": "png", "source": {"bytes": blue.getvalue()}}}]}}]},
{"role": "user", "content": [{"text": "Dominant color of the captured screen? One word."}]},
]
async def go():
return "".join([e.get("contentBlockDelta",{}).get("delta",{}).get("text","")
async for e in model.stream(msgs)])
print(asyncio.run(go())) # β Blue.
# π document β recovers "BANANA-42" (a document content block β text LM prompt)
import asyncio
from strands_transformers import TransformerModel
model = TransformerModel(model_path="Qwen/Qwen3-0.6B", enable_thinking=False,
params={"max_tokens": 64, "do_sample": False})
body = b"The secret passphrase for the vault is BANANA-42. Keep it safe."
msgs = [{"role": "user", "content": [
{"document": {"name": "secret", "format": "txt", "source": {"bytes": body}}},
{"text": "What is the secret passphrase? Answer with just the passphrase."},
]}]
async def go():
return "".join([e.get("contentBlockDelta",{}).get("delta",{}).get("text","")
async for e in model.stream(msgs)])
print(asyncio.run(go())) # β BANANA-42
# π text β speech β text (TTS then ASR, the tool path; the library narrating itself)
from strands_transformers import use_transformers
tts = use_transformers(action="run", task="text-to-audio",
model="facebook/mms-tts-eng",
inputs="the quick brown fox jumps over the lazy dog")
wav = tts["artifacts"][0]
asr = use_transformers(action="run", task="automatic-speech-recognition",
model="openai/whisper-tiny", inputs=wav)
print(asr["content"][0]["text"]) # β "...quick brown fox..."
# π¦Ύ camera + instruction β robot actions [1, 30, 6] (VLA via the `call` path)
import numpy as np
from PIL import Image
from huggingface_hub import hf_hub_download
from strands_transformers import use_transformers
REPO = "allenai/MolmoAct2-SO100_101"
top = Image.open(hf_hub_download(REPO, "assets/sample_realsense_top_rgb.png")).convert("RGB")
side = Image.open(hf_hub_download(REPO, "assets/sample_realsense_side_rgb.png")).convert("RGB")
state = [-0.527, 189.14, 181.41, 60.64, -3.60, 1.097]
use_transformers(action="call", target="AutoProcessor.from_pretrained",
parameters={"pretrained_model_name_or_path": REPO, "trust_remote_code": True}, cache_key="proc")
use_transformers(action="call", target="AutoModelForImageTextToText.from_pretrained",
parameters={"pretrained_model_name_or_path": REPO, "trust_remote_code": True, "dtype": "float32"}, cache_key="vla")
print(use_transformers(action="call", target="cached:vla.predict_action",
parameters={"processor": "cached:proc", "images": [top, side],
"task": "Pick up the lemon and drop it in the red bowl.",
"state": state, "norm_tag": "so100_so101_molmoact2",
"inference_action_mode": "continuous", "num_steps": 10})["content"][0]["text"][:200])
# β MolmoAct2ActionOutput ... actions [1, 30, 6]
Omni audio-in + speech-out needs one bigger model - see
examples/omni_audio.py.
Vision tasks on one COCO photo - detection Β· depth Β· panoptic segmentation:
Β Β
text-to-audio then re-transcribed by whisper (the library narrating itself)use_transformersfrom strands import Agent
from strands_transformers import use_transformers
agent = Agent(tools=[use_transformers])
agent("Transcribe recording.wav") # automatic-speech-recognition
agent("What's in scene.jpg?") # image-text-to-text
agent("Say 'hello from strands' as audio") # text-to-audio
agent("Detect objects in https://.../street.jpg") # object-detection
Discover everything at runtime (action="tasks" | "modalities" | "inspect" | β¦),
run high-level pipelines, or call any class / fn / method for custom models.
β The tool guide
TransformerModelPass image / video / audio / document blocks (and media inside a
toolResult) - the provider auto-detects the model's processor and routes them.
| Content block | Verified output | Example |
|---|---|---|
image | "Green." | multimodal_agent.py |
video (with fps) | "BRIGHTER." | multimodal_advanced.py |
image in toolResult | "Blue." | multimodal_advanced.py |
document | recovers BANANA-42 | document_and_audio.py |
audio (our schema extension) | audio β text | audio_content_block.py |
audio in and speech out | hears + speaks | omni_audio.py |
β Agent brain Β· Content blocks Β· Audio
Two transformers-native layers, both GPU-verified:
run: "the red cube is bottom-left,
move the arm there first."predict_action via call:
MolmoAct2 β [1,30,6];
OpenVLA-7b β 7-DoF (auto 4.xβ5.x shims).π Full agentic loop (robot_reason_act_agent.py):
Cosmos plans over real RealSense frames β MolmoAct acts β perception β plan β
action through one tool. (Lerobot policies like SmolVLA / Ο0 / GR00T run their own
runtimes β pair with use_lerobot.)
β Robotics guide
Use it from Claude Code, Claude Desktop, Cursor, or any MCP client β same tool, over MCP.
No install needed β just uvx:
uvx strands-transformers # stdio (Claude Code / Desktop)
uvx strands-transformers --http --port 8021 # HTTP multi-client
Claude Code: claude mcp add transformers -- uvx strands-transformers
Claude Desktop:
{"mcpServers": {"transformers": {"command": "uvx", "args": ["strands-transformers"]}}}
pip install "strands-transformers[mcp]"
strands-transformers-mcp
Examples use tiny models so they run in seconds. Point the same code at any current
library_name: transformers model - swap the id, the plumbing is identical:
| Modality | Strong open model | How |
|---|---|---|
| Vision-language | Qwen/Qwen3-VL-8B-Instruct Β· google/gemma-3-4b-it | brain or run (image-text-to-text) |
| Speech β text | openai/whisper-large-v3-turbo | run (automatic-speech-recognition) |
| Audio in + speech out | Qwen/Qwen2.5-Omni-3B | brain (speak=True) |
| Multimodal (audio+vision+text) | microsoft/Phi-4-multimodal-instruct | brain |
| Robot actions (VLA) | allenai/MolmoAct2 Β· openvla/openvla-7b | call β predict_action |
| Embodied reasoning | nvidia/Cosmos-Reason2-2B | run (image-text-to-text) |
# swap the tiny demo model for a SOTA one - same code:
model = TransformerModel(model_path="Qwen/Qwen3-VL-8B-Instruct")
strands_transformers/
βββ tools/use_transformers.py # the one @tool: discover Β· run Β· call
βββ models/transformers.py # TransformerModel - local multimodal brain
βββ types/audio.py # audio content-block extension
βββ core/{registry,engine,io,compat}.py # taxonomy Β· load/cache Β· I/O Β· legacy shims
Nothing is hardcoded per task - registry.py reads transformers' SUPPORTED_TASKS
at runtime, so coverage tracks upstream automatically.
β Architecture Β·
API reference
Runnable, GPU-verified examples in examples/ - image, video, audio,
document, Omni speech, VLA, and pipelines. Run any:
PYTHONPATH=. python examples/<name>.py
β Examples & FAQ
MIT - built with the Strands Agents SDK and HuggingFace Transformers.
5 commits
2 commits
Python
100.0%
Run any HuggingFace transformers model from a Strands agent. A tool for every task, or the agent's own multimodal brain. Local. No API keys.
5
stars
7
commits
Python
primary language
Jul 23, 2026
updated
Run any HuggingFace transformers model from a Strands agent. A tool for every task, or the agent's own multimodal brain. Local. No API keys.
π Docs Β Β·Β β‘ 60-second hello Β Β·Β ποΈ See it work Β Β·Β π§© Two ways Β Β·Β π MCP Β Β·Β π§ͺ Examples
HuggingFace transformers already runs every model on earth. The missing piece
is a clean, dynamic bridge into an agent loop - without writing per-model glue
every time. This library is that bridge, two ways:
| What it is | You get | |
|---|---|---|
π οΈ use_transformers | one tool exposing every transformers task | discover Β· run a pipeline Β· call any class/method |
π§ TransformerModel | a local model as your Agent(model=β¦) brain | it sees, hears & speaks via content blocks |
Zero hardcoding.
core/registry.pyreads transformers' ownSUPPORTED_TASKStaxonomy at runtime - the day a task or model lands upstream, it works here. No code change. No version bump.
uv pip install strands-transformers # from PyPI
PYTHONPATH=. python examples/smoke.py # verify β "18/18 checks passed"
uv pip install -e . # editable from source
uv pip install -e ".[audio]" # soundfile, librosa (mp3/flac/ogg decode)
uv pip install -e ".[vision]" # torchvision (needed by VLMs!), opencv, av
uv pip install -e ".[training]" # trl, peft, accelerate
uv pip install -e ".[all]" # everything
WAV audio works with no extras. Vision models (SmolVLM, Qwen-VL, β¦) need
[vision]. device="auto" picks cuda β mps β cpu (bf16 on GPU).
A 256M-param vision model, seeing pixels in the standard Strands loop - no key, no server:
import io
from PIL import Image
from strands import Agent
from strands_transformers import TransformerModel
buf = io.BytesIO(); Image.new("RGB", (64, 64), (20, 200, 40)).save(buf, "PNG") # a green square
model = TransformerModel(model_path="HuggingFaceTB/SmolVLM-256M-Instruct")
agent = Agent(model=model, system_prompt="You are concise.")
print(agent([
{"image": {"format": "png", "source": {"bytes": buf.getvalue()}}},
{"text": "Color? One word."},
]))
# β Green.
Swap model_path for any HF VLM and the code is identical.
Every result below is a real model output (CUDA Β· transformers 5.12 Β· torch 2.10):
| You give it | It returns | Example |
|---|---|---|
| πΌοΈ a green image + "Color?" | "Green." | multimodal_agent.py |
| π¬ brightening video frames | "BRIGHTER." | multimodal_advanced.py |
π§° a blue tool screenshot (in toolResult) | "Blue." | multimodal_advanced.py |
| π a text document | recovers BANANA-42 | document_and_audio.py |
| π a 440 Hz tone (Omni) | "It's a pure tone." | omni_audio.py |
| π¬ "say: β¦can speak" (Omni) | π real 24 kHz speech | omni_audio.py |
| π¦Ύ camera + "pick the cube" | actions [1, 30, 6] | molmoact_vla.py |
# πΌοΈ image β "Green." (local VLM brain, content blocks)
import io
from PIL import Image
from strands import Agent
from strands_transformers import TransformerModel
png = io.BytesIO(); Image.new("RGB", (224, 224), (20, 200, 40)).save(png, "PNG")
agent = Agent(model=TransformerModel(model_path="HuggingFaceTB/SmolVLM-256M-Instruct"))
print(agent([
{"image": {"format": "png", "source": {"bytes": png.getvalue()}}},
{"text": "What color is this image? One word."},
])) # β Green.
# π¬ video β "BRIGHTER." (a video content block of brightening frames)
import asyncio, numpy as np
from PIL import Image
from strands_transformers import TransformerModel
model = TransformerModel(model_path="HuggingFaceTB/SmolVLM2-500M-Video-Instruct",
params={"max_tokens": 48, "do_sample": False})
frames = [Image.fromarray(np.full((224, 224, 3), v, np.uint8)) for v in (10,40,80,120,160,200,230,250)]
msgs = [{"role": "user", "content": [
{"video": {"format": "mp4", "fps": 2.0, "source": {"bytes": frames}}},
{"text": "Does this video get brighter or darker? Answer brighter or darker."},
]}]
async def go():
return "".join([e.get("contentBlockDelta",{}).get("delta",{}).get("text","")
async for e in model.stream(msgs)])
print(asyncio.run(go())) # β ...brighter...
# π§° tool screenshot β "Blue." (an image returned inside a toolResult)
import asyncio, io
from PIL import Image
from strands_transformers import TransformerModel
blue = io.BytesIO(); Image.new("RGB", (224, 224), (25, 25, 210)).save(blue, "PNG")
model = TransformerModel(model_path="HuggingFaceTB/SmolVLM-256M-Instruct",
params={"max_tokens": 32, "do_sample": False})
msgs = [
{"role": "user", "content": [{"text": "Capture the screen, then name its color."}]},
{"role": "assistant", "content": [{"toolUse": {"name": "capture", "toolUseId": "t1", "input": {}}}]},
{"role": "user", "content": [{"toolResult": {"toolUseId": "t1", "status": "success", "content": [
{"text": "Here is the captured screen:"},
{"image": {"format": "png", "source": {"bytes": blue.getvalue()}}}]}}]},
{"role": "user", "content": [{"text": "Dominant color of the captured screen? One word."}]},
]
async def go():
return "".join([e.get("contentBlockDelta",{}).get("delta",{}).get("text","")
async for e in model.stream(msgs)])
print(asyncio.run(go())) # β Blue.
# π document β recovers "BANANA-42" (a document content block β text LM prompt)
import asyncio
from strands_transformers import TransformerModel
model = TransformerModel(model_path="Qwen/Qwen3-0.6B", enable_thinking=False,
params={"max_tokens": 64, "do_sample": False})
body = b"The secret passphrase for the vault is BANANA-42. Keep it safe."
msgs = [{"role": "user", "content": [
{"document": {"name": "secret", "format": "txt", "source": {"bytes": body}}},
{"text": "What is the secret passphrase? Answer with just the passphrase."},
]}]
async def go():
return "".join([e.get("contentBlockDelta",{}).get("delta",{}).get("text","")
async for e in model.stream(msgs)])
print(asyncio.run(go())) # β BANANA-42
# π text β speech β text (TTS then ASR, the tool path; the library narrating itself)
from strands_transformers import use_transformers
tts = use_transformers(action="run", task="text-to-audio",
model="facebook/mms-tts-eng",
inputs="the quick brown fox jumps over the lazy dog")
wav = tts["artifacts"][0]
asr = use_transformers(action="run", task="automatic-speech-recognition",
model="openai/whisper-tiny", inputs=wav)
print(asr["content"][0]["text"]) # β "...quick brown fox..."
# π¦Ύ camera + instruction β robot actions [1, 30, 6] (VLA via the `call` path)
import numpy as np
from PIL import Image
from huggingface_hub import hf_hub_download
from strands_transformers import use_transformers
REPO = "allenai/MolmoAct2-SO100_101"
top = Image.open(hf_hub_download(REPO, "assets/sample_realsense_top_rgb.png")).convert("RGB")
side = Image.open(hf_hub_download(REPO, "assets/sample_realsense_side_rgb.png")).convert("RGB")
state = [-0.527, 189.14, 181.41, 60.64, -3.60, 1.097]
use_transformers(action="call", target="AutoProcessor.from_pretrained",
parameters={"pretrained_model_name_or_path": REPO, "trust_remote_code": True}, cache_key="proc")
use_transformers(action="call", target="AutoModelForImageTextToText.from_pretrained",
parameters={"pretrained_model_name_or_path": REPO, "trust_remote_code": True, "dtype": "float32"}, cache_key="vla")
print(use_transformers(action="call", target="cached:vla.predict_action",
parameters={"processor": "cached:proc", "images": [top, side],
"task": "Pick up the lemon and drop it in the red bowl.",
"state": state, "norm_tag": "so100_so101_molmoact2",
"inference_action_mode": "continuous", "num_steps": 10})["content"][0]["text"][:200])
# β MolmoAct2ActionOutput ... actions [1, 30, 6]
Omni audio-in + speech-out needs one bigger model - see
examples/omni_audio.py.
Vision tasks on one COCO photo - detection Β· depth Β· panoptic segmentation:
Β Β
text-to-audio then re-transcribed by whisper (the library narrating itself)use_transformersfrom strands import Agent
from strands_transformers import use_transformers
agent = Agent(tools=[use_transformers])
agent("Transcribe recording.wav") # automatic-speech-recognition
agent("What's in scene.jpg?") # image-text-to-text
agent("Say 'hello from strands' as audio") # text-to-audio
agent("Detect objects in https://.../street.jpg") # object-detection
Discover everything at runtime (action="tasks" | "modalities" | "inspect" | β¦),
run high-level pipelines, or call any class / fn / method for custom models.
β The tool guide
TransformerModelPass image / video / audio / document blocks (and media inside a
toolResult) - the provider auto-detects the model's processor and routes them.
| Content block | Verified output | Example |
|---|---|---|
image | "Green." | multimodal_agent.py |
video (with fps) | "BRIGHTER." | multimodal_advanced.py |
image in toolResult | "Blue." | multimodal_advanced.py |
document | recovers BANANA-42 | document_and_audio.py |
audio (our schema extension) | audio β text | audio_content_block.py |
audio in and speech out | hears + speaks | omni_audio.py |
β Agent brain Β· Content blocks Β· Audio
Two transformers-native layers, both GPU-verified:
run: "the red cube is bottom-left,
move the arm there first."predict_action via call:
MolmoAct2 β [1,30,6];
OpenVLA-7b β 7-DoF (auto 4.xβ5.x shims).π Full agentic loop (robot_reason_act_agent.py):
Cosmos plans over real RealSense frames β MolmoAct acts β perception β plan β
action through one tool. (Lerobot policies like SmolVLA / Ο0 / GR00T run their own
runtimes β pair with use_lerobot.)
β Robotics guide
Use it from Claude Code, Claude Desktop, Cursor, or any MCP client β same tool, over MCP.
No install needed β just uvx:
uvx strands-transformers # stdio (Claude Code / Desktop)
uvx strands-transformers --http --port 8021 # HTTP multi-client
Claude Code: claude mcp add transformers -- uvx strands-transformers
Claude Desktop:
{"mcpServers": {"transformers": {"command": "uvx", "args": ["strands-transformers"]}}}
pip install "strands-transformers[mcp]"
strands-transformers-mcp
Examples use tiny models so they run in seconds. Point the same code at any current
library_name: transformers model - swap the id, the plumbing is identical:
| Modality | Strong open model | How |
|---|---|---|
| Vision-language | Qwen/Qwen3-VL-8B-Instruct Β· google/gemma-3-4b-it | brain or run (image-text-to-text) |
| Speech β text | openai/whisper-large-v3-turbo | run (automatic-speech-recognition) |
| Audio in + speech out | Qwen/Qwen2.5-Omni-3B | brain (speak=True) |
| Multimodal (audio+vision+text) | microsoft/Phi-4-multimodal-instruct | brain |
| Robot actions (VLA) | allenai/MolmoAct2 Β· openvla/openvla-7b | call β predict_action |
| Embodied reasoning | nvidia/Cosmos-Reason2-2B | run (image-text-to-text) |
# swap the tiny demo model for a SOTA one - same code:
model = TransformerModel(model_path="Qwen/Qwen3-VL-8B-Instruct")
strands_transformers/
βββ tools/use_transformers.py # the one @tool: discover Β· run Β· call
βββ models/transformers.py # TransformerModel - local multimodal brain
βββ types/audio.py # audio content-block extension
βββ core/{registry,engine,io,compat}.py # taxonomy Β· load/cache Β· I/O Β· legacy shims
Nothing is hardcoded per task - registry.py reads transformers' SUPPORTED_TASKS
at runtime, so coverage tracks upstream automatically.
β Architecture Β·
API reference
Runnable, GPU-verified examples in examples/ - image, video, audio,
document, Omni speech, VLA, and pipelines. Run any:
PYTHONPATH=. python examples/<name>.py
β Examples & FAQ
MIT - built with the Strands Agents SDK and HuggingFace Transformers.
5 commits
2 commits
Python
100.0%