Observed since 21 Oct, 09:18 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Universal Generative AI provider interface — switch providers without changing code.
⚠️ Alpha Release - This is the debut release of agnosmodel2. While functional, the API may change in future versions.
Universal Generative AI Provider Interface - Switch between any GenAI provider (OpenAI, Anthropic, local models) without changing your code. Define providers once, switch seamlessly at runtime.
Part of the Agnosweaver™ project suite.
Tired of AI vendor lock-in? Frustrated with rewriting code every time you want to try a different model? agnosmodel2 solves this by providing a unified interface across all GenAI providers.
# Define once, switch anytime
manager = GenManager()
manager.add_provider('gpt', 'openai', {'model': 'gpt-4', 'api_key': '...'})
manager.add_provider('claude', 'anthropic', {'model': 'claude-3', 'api_key': '...'})
response = manager.generate("Hello world") # Uses current provider
manager.switch_provider('claude')
response = manager.generate("Hello world") # Now uses Claude - same code!
# PyPI
pip install agnosmodel2
# GitHub
pip install git+https://github.com/agnosweaver/agnosmodel2.git
Requirements: Python 3.11 or higher
from agnosmodel2 import GenManager, ProviderRegistry, BaseGenProvider
# Create manager
manager = GenManager()
Since agnosmodel2 provides the core interface, you need to implement providers for your specific needs:
class OpenAIProvider(BaseGenProvider):
def generate(self, prompt: str, **kwargs):
# Your OpenAI implementation
response = self.call_openai_api(prompt)
return GenResponse(
content=response.text,
provider=self.name,
model=self.model,
timestamp=datetime.now().isoformat(),
content_type="text/plain"
)
async def agenerate(self, prompt: str, **kwargs):
# Your async OpenAI implementation
pass
def validate(self):
return 'api_key' in self.config
# Register your provider
ProviderRegistry.register('openai', OpenAIProvider)
# Add providers
manager.add_provider('gpt4', 'openai', {
'model': 'gpt-4',
'api_key': 'your-key'
})
manager.add_provider('claude', 'anthropic', {
'model': 'claude-3-sonnet',
'api_key': 'your-key'
})
# Generate responses
response = manager.generate("Explain quantum computing")
print(f"Response from {response.provider}: {response.content}")
# Switch providers seamlessly
manager.switch_provider('claude')
response = manager.generate("Explain quantum computing") # Same call, different provider!
# Test different models with the same prompt
results = {}
for provider in ['gpt4', 'claude', 'local-llama']:
manager.switch_provider(provider)
response = manager.generate("Write a haiku about AI")
results[provider] = response.content
def generate_with_fallback(prompt):
providers = ['premium-model', 'standard-model', 'local-backup']
for provider in providers:
try:
manager.switch_provider(provider)
return manager.generate(prompt)
except Exception as e:
print(f"{provider} failed: {e}")
continue
raise Exception("All providers failed")
# Route simple queries to cheaper models
def smart_generate(prompt):
if len(prompt) < 100:
manager.switch_provider('gpt-3.5')
else:
manager.switch_provider('gpt-4')
return manager.generate(prompt)
# Stream from any provider that supports it
for chunk in manager.generate_stream("Tell me a long story"):
print(chunk.content, end='', flush=True)
if chunk.is_final:
break
# Stream from any provider that supports it
for chunk in manager.generate_stream("Tell me a long story"):
print(chunk.content, end='', flush=True)
if chunk.is_final:
break
# Handle different data types seamlessly
audio_response = manager.generate("Say hello", output_type="audio")
video_response = manager.generate("Create a short clip", output_type="video")
# Content can be any type: str, bytes, custom objects
if isinstance(audio_response.content, bytes):
with open("output.wav", "wb") as f:
f.write(audio_response.content)
GenManagerMain interface for managing and switching between providers.
Methods:
add_provider(name, provider_type, config) - Add a new providerswitch_provider(name) - Switch to a different providergenerate(prompt, **kwargs) - Generate content synchronouslyagenerate(prompt, **kwargs) - Generate content asynchronouslygenerate_stream(prompt, **kwargs) - Stream content synchronouslyagenerate_stream(prompt, **kwargs) - Stream content asynchronouslyBaseGenProviderAbstract base class for all providers.
Must Implement:
generate(prompt, **kwargs) - Sync generationagenerate(prompt, **kwargs) - Async generationvalidate() - Configuration validationOptional Override:
generate_stream(prompt, **kwargs) - Sync streamingagenerate_stream(prompt, **kwargs) - Async streamingProviderRegistryRegistry for provider discovery and instantiation.
Methods:
register(provider_type, provider_class) - Register a provider classcreate(provider_type, name, config) - Create provider instancelist_types() - List registered provider typesGenResponse@dataclass
class GenResponse:
content: Union[str, bytes, Any]
provider: str
model: str
timestamp: str
content_type: Optional[str] = None
metadata: Optional[Dict[str, Any]] = None
GenStreamChunk@dataclass
class GenStreamChunk:
content: Union[str, bytes, Any]
provider: str
model: str
timestamp: str
content_type: Optional[str] = None
metadata: Optional[Dict[str, Any]] = None
is_final: bool = False
agnosmodel2 follows a clean, extensible architecture:
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ GenManager │────│ ProviderRegistry │────│ BaseGenProvider │
│ (Router) │ │ (Discovery) │ │ (Implementation)│
└─────────────────┘ └──────────────────┘ └─────────────────┘
│ │ │
│ ┌────────┴────────┐ │
│ │ │ │
▼ ▼ ▼ ▼
┌─────────────────┐ ┌──────────┐ ┌──────────────┐ ┌──────────────┐
│ Your App Code │ │ OpenAI │ │ Anthropic │ │ Local Model │
│ │ │ Provider │ │ Provider │ │ Provider │
└─────────────────┘ └──────────┘ └──────────────┘ └──────────────┘
Key Principles:
class HTTPTransport(BaseModelTransport):
def send(self, request_data, **kwargs):
# Custom HTTP implementation
pass
class gRPCTransport(BaseModelTransport):
def send(self, request_data, **kwargs):
# Custom gRPC implementation
pass
class JSONResponseParser(BaseResponseParser):
def parse_response(self, raw_response):
return json.loads(raw_response)['content']
def get_content_type(self, raw_response):
return "application/json"
Coming Soon: A dedicated repository for community contributions and ideas is being set up. Stay tuned!
For now, if you have suggestions or find issues, please reach out via email.
Licensed under the PolyForm Noncommercial License 1.0.0.
⚠️ Important: This license prohibits commercial use. If you need to use agnosmodel2 in a commercial project, please contact agnosweaver@gmail.com for a commercial license.
Built for developers who hate being boxed in.
Pick, switch, and combine GenAI providers freely.
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.0.1a0 | 12 Sept 2025 | 3 |
This describes our collected data; it is not a security assessment.
Observed since 21 Oct, 09:18 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:176c378fc9cd5df4dd42c890cfc1695fded32d167556664dbfd3d5d74bc261c6