A minimal agent framework
Project description
Chain Nhem Nhem
Chain Nhem Nhem is a minimal, framework-agnostic agent framework for building LLM agents with tool calling, step tracking and driver abstraction.
It was designed to be:
- Simple
- Explicit
- Hackable
- Dependency-light
No magic. No hidden chains. Just control.
Features
- Pluggable LLM drivers (Gemini, OpenAI, etc.)
- Pluggable Tools with schema validation
- Tool-calling loop with safety limits
- Step-by-step agent execution
- Token usage tracking (when supported by the driver)
- Framework-agnostic (works with FastAPI, Flask, CLI, scripts, etc.)
- Designed to be extended by the application, not the framework
Installation
pip install chain-nhem-nhem
Quick Start (Simple Usage)
The easiest way to get started is using the built-in agent factory. This approach requires zero configuration and works out of the box.
from chain_nhem_nhem.agent.factory import create_agent
agent = create_agent()
result = agent.run("Explain what an LLM is in one sentence")
print(result.output)
Quick Start (Power user)
from chain_nhem_nhem.agent.agent import Agent
from chain_nhem_nhem.llm.registry import load_drivers, llm_driver_registry
from chain_nhem_nhem.tools.registry import tool_registry, load_tools
load_drivers()
load_tools()
driver = llm_driver_registry.create("gemini")
agent = Agent(
driver=driver,
tool_registry=tool_registry,
driver_name="gemini"
)
result = agent.run("What's the weather in São Paulo?")
print(result.output)
Tools
Tools are simple Python classes that implement a callable interface.
Example Tool
from pydantic import BaseModel, Field
from chain_nhem_nhem.tools.base import Tool
from chain_nhem_nhem.tools.registry import tool_registry
#----------------------------
# Args Schemas
#----------------------------
class FavoriteGameArgs(BaseModel):
console: str = Field(..., description="Console to check favorite game (PC, Plastation, Xbox...).")
#----------------------------
# Tool Implementation
#----------------------------
class FavoriteGameTool(Tool):
def __init__(self):
self.name = "get_favorite_game"
self.description = "Get the favorite game for a given console."
self.args_schema = FavoriteGameArgs
def __call__(self, args: FavoriteGameArgs) -> dict:
favorite_game = ""
if args.console.lower() == "pc":
favorite_game = "League of Legends"
elif args.console.lower() == "playstation":
favorite_game = "The Last of Us Part II"
elif args.console.lower() == "xbox":
favorite_game = "Halo Infinite"
else:
favorite_game = "Pacman"
return {
"console": args.console,
"favorite_game": favorite_game
}
#----------------------------
# Tools Registration
# ---------------------------
tool_registry.register(FavoriteGameTool())
Tools are automatically discovered when placed in a directory ending with _tool.py.
Tool Discovery
Chain Nhem Nhem supports external tools via environment variables.
APP_TOOLS_PATH=/absolute/path/to/your/tools
All files ending with *_tool.py will be loaded automatically.
Agent Output
{
"output": "Yes, it will rain tomorrow.",
"steps": [
"User input: Will it rain tomorrow?",
"Model called tool: get_weather",
"Step: 1 - Tool 'get_weather' returned {...}",
"Step: 2 - Final answer generated"
],
"tools_used": ["get_weather"],
"tokens": 812
}
Configuration
Configuration is done via environment variables.
DRIVER=gemini
DEBUG_MODE=true
LOGGER_LEVEL=DEBUG
APP_TOOLS_PATH=/path/to/tools
APP_DRIVERS_PATH=/path/to/drivers
Logging
Chain Nhem Nhem provides its own logger, isolated from your app.
[INFO] [chain_nhem_nhem.llm] Loading internal LLM drivers
[INFO] [chain_nhem_nhem.tools] Tools loaded: ['weather_tool']
[INFO] [chain_nhem_nhem.agent] Agent run started
Log level is controlled via LOGGER_LEVEL.
Drivers
Drivers implement a common interface (LLMDriver) and can be swapped freely.
Supported:
- Gemini (official API)
Planned:
- OpenAI
- Local LLMs
- MCP-style adapters
Philosophy
“Explicit is better than magic.”
Chain Nhem Nhem does not:
- Hide prompts
- Abstract control flow away
- Lock you into a framework
- Force opinions
You own:
- The agent loop
- The tools
- The drivers
- The orchestration
Status
Alpha – APIs may change.
Feedback and experimentation welcome.
Why the name?
Because it’s fun to say.
And because frameworks don’t need to take themselves so seriously.
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 chain_nhem_nhem-0.1.0.tar.gz.
File metadata
- Download URL: chain_nhem_nhem-0.1.0.tar.gz
- Upload date:
- Size: 12.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6691242c9e8744f623a0b91615873791cc075445fc793ca25e5f2789540d10a1
|
|
| MD5 |
4531f7fba0b690cd9ff966dbae21ba90
|
|
| BLAKE2b-256 |
9838324034f2050682cc4637fc9bb2833a2a3bb109a68662a45ad9abca3a746e
|
File details
Details for the file chain_nhem_nhem-0.1.0-py3-none-any.whl.
File metadata
- Download URL: chain_nhem_nhem-0.1.0-py3-none-any.whl
- Upload date:
- Size: 14.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2cb963be4ebee4e37fab44cbad7a3d7dc1c71b15afd24ca73e35c39b25420310
|
|
| MD5 |
631a77ce355362c1ed9456d4f47f0a7b
|
|
| BLAKE2b-256 |
2065d401811d8de5b2c5c729c73992f88dcae6a994afe9d118efc5e02d07f702
|