Unified Python library for interacting with LLM providers (OpenAI, Gemini, Anthropic Claude). Simple, consistent syntax with stateless design.
Project description
msgmodel
A unified Python library and CLI for interacting with multiple Large Language Model (LLM) providers with a simple, consistent syntax.
Overview
msgmodel provides both a Python library and a command-line interface to interact with major LLM providers:
- OpenAI (GPT models) — Zero Data Retention available via automatic header
- Google Gemini (Paid tier recommended) — Configurable data policies
- Anthropic Claude — Standard API data handling
Core Principle: msgmodel itself is entirely stateless and ephemeral—it never retains your data. Provider-level data handling varies; see the Data Retention section for details on each provider's policies and available options.
Features
- Unified API: Single
query()andstream()functions work with all providers - Library & CLI: Use as a Python module or command-line tool
- Streaming support: Stream responses in real-time
- File attachments: Process images, PDFs, and text files with in-memory BytesIO
- Flexible configuration: Dataclass-based configs with sensible defaults
- Multiple API key sources: Direct parameter, environment variable, or key file
- Exception-based error handling: Clean errors, no
sys.exit()in library code - Type-safe: Full type hints throughout
- Stateless design: msgmodel never retains your data; all processing is ephemeral
Installation
From PyPI (Recommended)
pip install msgmodel
From Source
# Clone the repository
git clone https://github.com/LeoooDias/msgmodel.git
cd msgmodel
# Install the package
pip install -e .
# Or with development dependencies
pip install -e ".[dev]"
Prerequisites
- Python 3.10 or higher
- API keys from the providers you wish to use
Quick Start
As a Library
from msgmodel import query, stream
# Simple query (uses OPENAI_API_KEY env var)
response = query("openai", "What is Python?")
print(response.text)
# With explicit API key
response = query("gemini", "Hello!", api_key="your-api-key")
# Streaming
for chunk in stream("openai", "Tell me a story"):
print(chunk, end="", flush=True)
# With file attachment (in-memory BytesIO only)
import io
file_obj = io.BytesIO(your_binary_data)
response = query("gemini", "Describe this image", file_like=file_obj, filename="photo.jpg")
# With custom configuration
from msgmodel import OpenAIConfig
config = OpenAIConfig(model="gpt-4o-mini", temperature=0.7, max_tokens=2000)
response = query("openai", "Write a poem", config=config)
As a CLI
# Basic usage
python -m msgmodel -p openai "What is Python?"
# Using shorthand provider codes
python -m msgmodel -p g "Hello, Gemini!" # g = gemini
python -m msgmodel -p o "Hello, OpenAI!" # o = openai
python -m msgmodel -p c "Hello, Claude!" # c = claude/anthropic
# With streaming
python -m msgmodel -p openai "Tell me a story" --stream
# From a file
python -m msgmodel -p gemini -f prompt.txt
# With system instruction
python -m msgmodel -p claude "Analyze this" -i "You are a data analyst"
# With file attachment (base64 inline)
python -m msgmodel -p gemini "Describe this" -b image.jpg
# Custom parameters
python -m msgmodel -p openai "Hello" -m gpt-4o-mini -t 500 --temperature 0.7
# Get full JSON response instead of just text
python -m msgmodel -p openai "Hello" --json
# Verbose output (shows model, provider, token usage)
python -m msgmodel -p openai "Hello" -v
API Key Configuration
API keys can be provided in three ways (in order of priority):
- Direct parameter:
query("openai", "Hello", api_key="sk-...") - Environment variable:
OPENAI_API_KEYfor OpenAIGOOGLE_API_KEYfor GeminiANTHROPIC_API_KEYfor Claude/Anthropic
- Key file in current directory:
openai-api.keygemini-api.keyanthropic-api.key
Configuration
Each provider has its own configuration dataclass with sensible defaults:
from msgmodel import OpenAIConfig, GeminiConfig, AnthropicConfig
# OpenAI configuration
openai_config = OpenAIConfig(
model="gpt-4o", # Model to use
temperature=1.0, # Sampling temperature
top_p=1.0, # Nucleus sampling
max_tokens=1000, # Max output tokens
)
# Gemini configuration
gemini_config = GeminiConfig(
model="gemini-2.5-flash",
temperature=1.0,
top_p=0.95,
top_k=40,
safety_threshold="BLOCK_NONE",
)
# Anthropic/Claude configuration
anthropic_config = AnthropicConfig(
model="claude-haiku-4-5-20251001", # Default; also: claude-sonnet-4-20250514
temperature=1.0,
top_p=1.0,
max_tokens=1000,
)
Data Retention & Privacy
msgmodel is designed with statelessness as a core principle—the library itself never retains your data. Provider-level data handling varies, and this section helps you understand your options.
OpenAI (Zero Data Retention by Default)
When using OpenAI:
- Default behavior: The
X-OpenAI-No-Storeheader is automatically sent, opting out of data retention for model training - What this means: OpenAI does not use these interactions for service improvements or model training
- File handling: All files are base64-encoded and embedded inline in prompts—no server-side uploads
Note: OpenAI's API logs may retain minimal metadata (timestamps, API version, token counts) for ~30 days for debugging purposes, but not the actual prompt/response content.
from msgmodel import query
response = query("openai", "Your prompt here")
# Zero Data Retention header is sent automatically
Google Gemini
Google Gemini's data retention policy depends on your service tier:
Paid Services (Google Cloud Billing + Paid Quota)
- Data is NOT used for model training or product improvement
- Prompts and responses may be retained temporarily for abuse detection (typically 24-72 hours)
- Base64-encoded inline file embedding—no persistent storage
Free Tier
- Google may retain data for model training. Review Google's terms if this matters for your use case.
from msgmodel import query
# Gemini request - data handling depends on your account tier
response = query("gemini", "Your prompt here", api_key="your-api-key")
Learn more: Google Gemini API Terms
Anthropic Claude
When using Anthropic Claude:
- Default behavior: Anthropic does not use API data for model training by default
- Data retention: Data may be retained temporarily for safety monitoring and abuse prevention
- File handling: Base64-encoded inline embedding
from msgmodel import query
response = query("claude", "Your prompt here")
# or: query("anthropic", ...) or query("c", ...)
Learn more: Anthropic Privacy Policy
Summary Comparison
| Provider | Training Data Opt-Out | Data Retention | Notes |
|---|---|---|---|
| OpenAI | ✅ Automatic | None (ZDR header) | Metadata ~30 days |
| Gemini (Paid) | ✅ Yes | ~24-72 hours (abuse monitoring) | Requires paid tier |
| Gemini (Free) | ❌ No | Per Google's terms | Review terms |
| Anthropic | ✅ Default | Temporary (safety) | Standard API behavior |
For maximum privacy: Use OpenAI with the default ZDR settings, or Anthropic's API. For Gemini, use the paid tier.
File Uploads
The BytesIO-Only Approach
All file uploads in msgmodel v3.2.0+ use in-memory BytesIO objects with base64 inline encoding:
import io
from msgmodel import query
# Read file into memory
with open("document.pdf", "rb") as f:
file_data = f.read()
# Create BytesIO object
file_obj = io.BytesIO(file_data)
# Query with file
response = query(
"openai",
"Summarize this document",
file_like=file_obj,
filename="document.pdf" # Enables MIME type detection
)
Why BytesIO?
- Stateless operation—each request is completely independent
- No server-side file uploads (Files API not used)
- Files are base64-encoded inline in prompts
File Size Limits
- OpenAI: ~15-20MB practical limit (base64 overhead + token limits)
- Gemini: ~22MB practical limit (base64 overhead + token limits)
- Anthropic: ~20MB practical limit (base64 overhead + token limits)
If API returns a size-related error, the file exceeds practical limits for that provider.
Error Handling
The library uses exceptions instead of sys.exit():
from msgmodel import query, MsgModelError, AuthenticationError, APIError
try:
response = query("openai", "Hello")
except AuthenticationError as e:
print(f"API key issue: {e}")
except APIError as e:
print(f"API call failed: {e}")
print(f"Status code: {e.status_code}")
except MsgModelError as e:
print(f"General error: {e}")
Response Object
The query() function returns an LLMResponse object:
response = query("openai", "Hello")
print(response.text) # The generated text
print(response.model) # Model used (e.g., "gpt-4o")
print(response.provider) # Provider name (e.g., "openai")
print(response.usage) # Token usage dict (if available)
print(response.raw_response) # Complete API response
Project Structure
msgmodel/
├── msgmodel/ # Python package
│ ├── __init__.py # Public API exports
│ ├── __main__.py # CLI entry point
│ ├── core.py # Core query/stream functions
│ ├── config.py # Configuration dataclasses
│ ├── exceptions.py # Custom exceptions
│ ├── py.typed # PEP 561 marker for typed package
│ └── providers/ # Provider implementations
│ ├── __init__.py
│ ├── openai.py
│ └── gemini.py
├── tests/ # Test suite
│ ├── test_config.py
│ ├── test_core.py
│ └── test_exceptions.py
├── pyproject.toml # Package configuration
├── LICENSE # MIT License
├── MANIFEST.in # Distribution manifest
├── requirements.txt # Dependencies
└── README.md
CLI Usage
After installation, the msgmodel command is available:
# Basic usage
msgmodel -p openai "What is Python?"
# Or using python -m
python -m msgmodel -p openai "What is Python?"
# Provider shortcuts: o=openai, g=gemini
msgmodel -p g "Hello, Gemini!"
# With streaming
msgmodel -p openai "Tell me a story" --stream
# From a file
msgmodel -p gemini -f prompt.txt
Running Tests
# Install dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run with coverage
pytest --cov=msgmodel
Building & Publishing
# Install build tools
pip install build twine
# Build the package
python -m build
# Check the distribution
twine check dist/*
# Upload to PyPI (requires PyPI account)
twine upload dist/*
# Upload to TestPyPI first (recommended)
twine upload --repository testpypi dist/*
License
MIT License - see LICENSE for details.
Author
Leo Dias
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 msgmodel-4.1.0.tar.gz.
File metadata
- Download URL: msgmodel-4.1.0.tar.gz
- Upload date:
- Size: 74.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
41c9d7127982a0e161a6304bf1503215b8ad53462d9ea9b075a084bc320f55d3
|
|
| MD5 |
558d9c6102b3dc4d777a28f18d4e0da9
|
|
| BLAKE2b-256 |
92cc746b82918b2a4077e4596617f9f3a85105cc440863e86b310537b8b60cea
|
File details
Details for the file msgmodel-4.1.0-py3-none-any.whl.
File metadata
- Download URL: msgmodel-4.1.0-py3-none-any.whl
- Upload date:
- Size: 47.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f69b6738362b36a384aa1319cf3ba2f72c11f42aa1daeadc3ee56bf80114231e
|
|
| MD5 |
bb15ab4571e1c20adaf903e9e9095bf9
|
|
| BLAKE2b-256 |
64374a4e98f6b6d8c2f3455b564f593a7e8079fbd2a0430e04d7c46819c2fcb8
|