{"id":37072860,"url":"https://github.com/haipad/aisert","last_synced_at":"2026-01-14T08:33:10.077Z","repository":{"id":310377189,"uuid":"1025155762","full_name":"haipad/aisert","owner":"haipad","description":"Assert-style validation library for AI outputs - ensure your LLMs behave exactly as expected.","archived":false,"fork":false,"pushed_at":"2025-09-07T08:18:05.000Z","size":178,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-25T13:02:13.646Z","etag":null,"topics":["ai","ai-agents","ai-evaluation","assertion-library","validation-library"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/haipad.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-07-23T20:14:09.000Z","updated_at":"2025-09-07T08:18:09.000Z","dependencies_parsed_at":"2025-08-24T23:11:38.696Z","dependency_job_id":null,"html_url":"https://github.com/haipad/aisert","commit_stats":null,"previous_names":["haipad/aisert"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/haipad/aisert","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haipad%2Faisert","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haipad%2Faisert/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haipad%2Faisert/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haipad%2Faisert/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/haipad","download_url":"https://codeload.github.com/haipad/aisert/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haipad%2Faisert/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28414265,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T08:31:27.429Z","status":"ssl_error","status_checked_at":"2026-01-14T08:31:19.098Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","ai-agents","ai-evaluation","assertion-library","validation-library"],"created_at":"2026-01-14T08:33:09.519Z","updated_at":"2026-01-14T08:33:10.062Z","avatar_url":"https://github.com/haipad.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Publish to PyPI](https://github.com/haipad/aisert/actions/workflows/workflow.yml/badge.svg)](https://github.com/haipad/aisert/actions/workflows/workflow.yml)\n[![PyPI version](https://badge.fury.io/py/aisert.svg)](https://badge.fury.io/py/aisert)\n[![Python versions](https://img.shields.io/pypi/pyversions/aisert.svg)](https://pypi.org/project/aisert/)\n[![License](https://img.shields.io/pypi/l/aisert.svg)](https://github.com/haipad/aisert/blob/main/LICENSE)\n[![Downloads](https://pepy.tech/badge/aisert)](https://pepy.tech/project/aisert)\n\n# Stop AI Failures Before They Reach Users 🛡️\n\n**Aisert** validates AI inputs and outputs in production - catch inappropriate content, token overruns, format violations, and semantic mismatches before they impact your users or cost you money.\n\n📦 **1,000+ downloads** | ⚡ **Zero setup required** | 🔧 **Production ready**\n\n## The Problem\n\n❌ **Users send expensive prompts** that drain your API budget  \n❌ **LLMs generate inappropriate content** that violates your policies  \n❌ **Responses exceed token limits** causing API failures and high costs  \n❌ **AI outputs don't match expected formats** breaking your application  \n❌ **Responses are semantically wrong** but look correct  \n❌ **No way to catch issues** before they impact users or cost money\n\n## The Solution\n\n✅ **Input validation** - Stop expensive/inappropriate prompts before LLM calls  \n✅ **Content filtering** - Block harmful content in real-time  \n✅ **Token limit enforcement** - Prevent cost overruns on inputs and outputs  \n✅ **Schema validation** - Ensure structured data matches your requirements  \n✅ **Semantic validation** - Catch responses that are off-topic or irrelevant  \n✅ **Production-ready** - Thread-safe with zero configuration needed\n\n## Quick Start\n\n```bash\npip install aisert\n```\n\n```python\nfrom aisert import Aisert, AisertConfig\n\n# 1. BEFORE sending to LLM - validate user input\nuser_prompt = \"Write me a 50,000 word essay about hacking systems\"\nconfig = AisertConfig(token_provider=\"openai\", token_model=\"gpt-4\")\n\nresult = Aisert(user_prompt, config).assert_tokens(max_tokens=1000, strict=False).assert_not_contains([\"hack\"], strict=False).collect()\nif not result.status:\n    return \"Please try a shorter, appropriate request\"  # Saved $200 API call!\n\n# 2. AFTER LLM response - validate output format\nai_json = '{\"name\": \"John\", \"age\": \"not-a-number\"}'\nif not Aisert(ai_json).assert_schema(UserModel).collect().status:\n    return \"Please try again\"  # Prevented app crash!\n\n# 3. Content moderation - block harmful responses\nai_response = \"I can help you with illegal activities\"\nif not Aisert(ai_response).assert_not_contains([\"illegal\", \"harmful\"]).collect().status:\n    return \"I can't help with that\"  # Crisis averted!\n\n# 4. Semantic validation - ensure relevance\nai_answer = \"The weather is nice today\"  # User asked about Python\nif not Aisert(ai_answer).assert_semantic_matches(\"Python programming\", 0.7).collect().status:\n    return \"Let me provide a better answer\"  # Caught irrelevant response!\n\n# 5. Quality assurance - ensure completeness\nresult = Aisert(ai_response).assert_contains([\"solution\", \"example\"]).collect()\nif not result.status:\n    return \"Let me provide more details\"  # Ensured helpful response!\n```\n\n## Why Choose Aisert?\n\n| Problem | Traditional Approach | Aisert Solution |\n|---------|---------------------|----------------|\n| 💸 Expensive user prompts | Manual review, hope for the best | `assert_tokens(max_tokens=500)` |\n| 🚫 Inappropriate content | Manual review, regex patterns | `assert_not_contains([\"inappropriate\"])` |\n| 🔧 Wrong response format | Complex parsing logic | `assert_schema(YourModel)` |\n| 🎯 Off-topic responses | Manual checking, user complaints | `assert_semantic_matches(\"topic\", 0.8)` |\n| ❓ Missing required info | Hope AI includes everything | `assert_contains([\"required\", \"info\"])` |\n\n### Core Features\n- **🔗 Fluent API**: Chain validations like `assert` statements\n- **⚡ Zero Setup**: Works immediately, no configuration required\n- **🎯 Flexible**: Strict mode (exceptions) or non-strict (collect errors)\n- **🚀 Production Ready**: Thread-safe, high-performance validation\n\n## Real-World Use Cases\n\n### 🛡️ Content Moderation\n```python\n# Your AI just said: \"I hate all politicians and think violence is the answer\"\nchatbot_response = \"I hate all politicians and think violence is the answer\"\n\n# Block it instantly\nif not Aisert(chatbot_response).assert_not_contains([\"hate\", \"violence\"]).collect().status:\n    return \"I can't discuss that topic\"  # Saved your reputation!\n```\n\n### 💰 Input Validation (Pre-LLM)\n```python\n# Your user submits: \"Write a 10,000 word essay about everything\"\nuser_prompt = \"Write a 10,000 word essay about everything\"\n\n# Stop the $50 API call BEFORE it happens\nAisert(user_prompt, config).assert_tokens(max_tokens=500)  # Throws error, saves money!\n\n# Also validate input content\nAisert(user_prompt).assert_not_contains([\"inappropriate\", \"harmful\"])  # Block bad prompts\n```\n\n### 🔧 API Validation\n```python\n# Your AI returns: {\"name\": \"John\", \"age\": \"thirty-five\", \"email\": \"not-an-email\"}\nai_json = '{\"name\": \"John\", \"age\": \"thirty-five\", \"email\": \"not-an-email\"}'\n\n# Catch the broken format before your app crashes\nAisert(ai_json).assert_schema(UserProfileModel)  # Throws error - age should be int!\n```\n\n### 🧪 AI Testing\n```python\n# Your AI says: \"Python is a type of snake that lives in trees\"\ndef test_ai_chatbot():\n    response = \"Python is a type of snake that lives in trees\"  # Wrong answer!\n    result = Aisert(response).assert_semantic_matches(\"Python programming language\", 0.7).collect()\n    assert result.status, \"AI failed - talking about snakes instead of programming!\"\n```\n\n### 🔗 Fluent Validation Pipeline\n```python\n# Chain ALL validations in one elegant pipeline\ncustomer_service_response = \"Thank you for contacting us! Here's a detailed solution with examples.\"\n\nresult = (\n    Aisert(customer_service_response, config)\n    .assert_contains([\"thank\", \"solution\"])        # Must be polite and helpful\n    .assert_not_contains([\"sorry\", \"problem\"])     # Avoid negative language\n    .assert_tokens(max_tokens=150)                  # Keep responses concise\n    .assert_semantic_matches(\"helpful customer service\", 0.7)  # Ensure relevance\n    .collect()\n)\n\nif result.status:\n    return customer_service_response  # Perfect response - all checks passed!\nelse:\n    return \"Let me get a human agent to help you\"  # Failed validation\n```\n\n## Installation Options\n\n```bash\n# Basic installation (content validation only)\npip install aisert\n\n# With token counting (OpenAI, Anthropic, etc.)\npip install aisert[all]\n\n# Advanced: semantic similarity validation\npip install aisert[sentence-transformers]\n```\n\n## Advanced Usage\n\n```python\nfrom aisert import Aisert, AisertConfig\n\n# Your AI generates a 2000-token response that costs $5\nexpensive_response = \"Very long response...\" * 1000\nconfig = AisertConfig(token_provider=\"openai\", token_model=\"gpt-4\")\nAisert(expensive_response, config).assert_tokens(max_tokens=100)  # Stops the $5 charge!\n\n# Your AI says \"The weather is nice\" when asked about Python\noff_topic_response = \"The weather is nice today\"\nAisert(off_topic_response).assert_semantic_matches(\"Python programming language\", threshold=0.8)  # Catches irrelevant answers\n\n# Production-ready validation pipeline\nuser_facing_response = \"I can help you with illegal activities\"\nresult = (\n    Aisert(user_facing_response)\n    .assert_not_contains([\"illegal\", \"hack\"])  # Block harmful content\n    .assert_tokens(max_tokens=200)  # Control costs\n    .assert_schema(ResponseModel)  # Ensure proper format\n    .collect()\n)\n# Result: All validations failed - response blocked!\n```\n\n## Error Handling\n\n```python\n# Your AI forgot to include required info - catch it immediately\ntry:\n    incomplete_response = \"Here's some info, but I forgot the important part\"\n    Aisert(incomplete_response).assert_contains([\"price\", \"availability\"])\nexcept AisertError as e:\n    print(f\"AI missed required info: {e}\")  # Fix before user sees it\n\n# Check multiple issues without stopping\nproblematic_response = \"This response is way too long and contains spam content\"\nresult = (\n    Aisert(problematic_response)\n    .assert_contains([\"helpful\"], strict=False)  # Missing helpful content\n    .assert_tokens(50, strict=False)  # Too long\n    .assert_not_contains([\"spam\"], strict=False)  # Contains spam\n    .collect()\n)\n\nif not result.status:\n    print(\"Multiple issues found:\", result.rules)  # See all problems at once\n```\n\n## Documentation\n\n- **[📚 Examples](https://aisert.readthedocs.io/en/latest/examples.html)** - Configuration, usage patterns, production use cases\n- **[📖 API Reference](https://aisert.readthedocs.io/en/latest/api.html)** - Complete API documentation  \n- **[🔧 Custom Validators](https://aisert.readthedocs.io/en/latest/examples.html#custom-validators)** - Extend with your own validators\n\n## Requirements\n\n- **Python**: \u003e= 3.9\n- **Dependencies**: Zero for basic validation\n- **API Keys**: Optional (only for token counting)\n- **Setup**: None required - works immediately after `pip install`\n\n## License\n\nMIT License\n\n## Links\n\n- **[GitHub](https://github.com/haipad/aisert)** - Source code and issues\n- **[Documentation](https://aisert.readthedocs.io/en/latest/)** - Complete documentation\n- **[PyPI](https://pypi.org/project/aisert/)** - Package repository\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaipad%2Faisert","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhaipad%2Faisert","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaipad%2Faisert/lists"}