{"id":44484130,"url":"https://github.com/askmanu/acorn","last_synced_at":"2026-02-24T22:03:57.993Z","repository":{"id":336139971,"uuid":"1148419209","full_name":"askmanu/acorn","owner":"askmanu","description":"LLM framework for long running agents","archived":false,"fork":false,"pushed_at":"2026-02-20T12:51:06.000Z","size":387,"stargazers_count":2,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-20T16:43:43.259Z","etag":null,"topics":["ai","ai-agents","llm-framework"],"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/askmanu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"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":"2026-02-03T00:09:44.000Z","updated_at":"2026-02-20T12:51:10.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/askmanu/acorn","commit_stats":null,"previous_names":["askmanu/acorn"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/askmanu/acorn","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/askmanu%2Facorn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/askmanu%2Facorn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/askmanu%2Facorn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/askmanu%2Facorn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/askmanu","download_url":"https://codeload.github.com/askmanu/acorn/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/askmanu%2Facorn/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29802866,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-24T21:02:39.706Z","status":"ssl_error","status_checked_at":"2026-02-24T21:02:21.834Z","response_time":75,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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","llm-framework"],"created_at":"2026-02-13T01:12:48.156Z","updated_at":"2026-02-24T22:03:57.988Z","avatar_url":"https://github.com/askmanu.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\u003cimg width=\"851\" height=\"190\" alt=\"github\" src=\"https://github.com/user-attachments/assets/3f06caa7-b670-4cfb-8a57-0278f7f946a0\" /\u003e\n\n\n**LLM agent framework with structured I/O**\n\nBuild AI agents with type-safe inputs and outputs, automatic tool calling, and powerful agentic loops.\n\n[![Tests](https://img.shields.io/badge/tests-201%20passing-brightgreen)](tests/)\n[![Coverage](https://img.shields.io/badge/coverage-85%25-brightgreen)](tests/)\n[![Python](https://img.shields.io/badge/python-3.10+-blue)](pyproject.toml)\n[![License](https://img.shields.io/badge/license-MIT-blue)](LICENSE)\n\n---\n\n## ✨ Features\n\n- 🎯 **Structured I/O** - Pydantic models for inputs and outputs\n- 🤖 **Agentic Loops** - Multi-turn execution with tool calling\n- 🛠️ **Auto Tool Schemas** - Generate from type hints and docstrings\n- 🔄 **Dynamic Tools** - Add/remove tools during execution\n- ✅ **Parse Error Recovery** - Automatic retry on validation failures\n- 📊 **Step Callbacks** - Full control over loop behavior\n- 🔌 **LiteLLM Integration** - Works with any LLM provider\n- 🌊 **Streaming Responses** - Real-time output with partial structured updates\n- 💾 **Provider Caching** - Reduce latency and cost with prompt caching\n- 🛡️ **Model Fallbacks** - Automatic provider failover for high availability\n- 🌳 **Branching Workflows** - Spawn sub-agents that extend parent capabilities for parallel analysis and map-reduce patterns\n\n---\n\n## 🚀 Quick Start\n\n### Installation\n\n```bash\npip install acorn\n```\n\nSet your API key:\n\n```bash\n# For Anthropic Claude\nexport ANTHROPIC_API_KEY=\"your-key-here\"\n\n# Or for OpenAI\nexport OPENAI_API_KEY=\"your-key-here\"\n\n# Or any other LiteLLM-supported provider\n```\n\n### Single-Turn Example\n\n```python\nfrom pydantic import BaseModel, Field\nfrom acorn import Module\n\nclass Input(BaseModel):\n    text: str = Field(description=\"The text to summarize\")\n    max_words: int = Field(default=100, description=\"Maximum words in summary\")\n\nclass Output(BaseModel):\n    summary: str = Field(description=\"The concise summary\")\n    word_count: int = Field(description=\"Number of words in summary\")\n\nclass Summarizer(Module):\n    \"\"\"Summarize text concisely.\"\"\"\n\n    initial_input = Input\n    final_output = Output\n    model = \"anthropic/claude-sonnet-4-5-20250514\"\n\n# Use it\nsummarizer = Summarizer()\nresult = summarizer(\n    text=\"Long article text here...\",\n    max_words=50\n)\n\nprint(result.summary)\nprint(f\"Words: {result.word_count}\")\n```\n\n### Multi-Turn Agentic Loop\n\n```python\nfrom pydantic import BaseModel, Field\nfrom acorn import Module, tool\n\nclass Input(BaseModel):\n    topic: str = Field(description=\"Research topic\")\n    depth: str = Field(default=\"shallow\", description=\"Research depth\")\n\nclass Output(BaseModel):\n    findings: str = Field(description=\"Summary of findings\")\n    sources: list[str] = Field(description=\"Sources consulted\")\n\nclass ResearchAgent(Module):\n    \"\"\"Research assistant with tools.\"\"\"\n\n    initial_input = Input\n    max_steps = 5  # Enable agentic loop\n    final_output = Output\n    model = \"anthropic/claude-sonnet-4-5-20250514\"\n\n    @tool\n    def search(self, query: str) -\u003e list:\n        \"\"\"Search for information.\"\"\"\n        # Your search implementation\n        return [\"result1\", \"result2\"]\n\n    @tool\n    def analyze(self, data: str) -\u003e str:\n        \"\"\"Analyze collected data.\"\"\"\n        # Your analysis implementation\n        return f\"Analysis: {data}\"\n\n    def on_step(self, step):\n        \"\"\"Called after each step.\"\"\"\n        print(f\"Step {step.counter}\")\n\n        # Early termination if done\n        if len(step.tool_results) \u003e= 3:\n            step.finish(\n                findings=\"Sufficient data collected\",\n                sources=[\"source1\", \"source2\"]\n            )\n\n        return step\n\n# Use it\nagent = ResearchAgent()\nresult = agent(topic=\"Large Language Models\", depth=\"shallow\")\n```\n\n---\n\n## 📚 Core Concepts\n\n### Module\nBase class for LLM agents. Configure with:\n- `model` - LLM to use (required - no default)\n- `temperature` - Sampling temperature\n- `max_tokens` - Maximum tokens to generate\n- `max_steps` - Max agentic loop iterations (None = single-turn)\n- `initial_input` - Pydantic model for input schema\n- `final_output` - Pydantic model for output schema\n- `tools` - List of available tools\n- `cache` - Enable provider-level prompt caching\n- `model_fallbacks` - List of fallback models for automatic failover\n\n### Tools\nFunctions the LLM can call:\n\n```python\n@tool\ndef search(query: str, limit: int = 10) -\u003e list:\n    \"\"\"Search for information.\n\n    Args:\n        query: The search query\n        limit: Maximum results to return\n    \"\"\"\n    return search_api(query, limit)\n```\n\nSchema is automatically generated from type hints and docstring.\n\n### Step Callback\nControl agentic loop execution:\n\n```python\ndef on_step(self, step):\n    # Access step info\n    print(f\"Step {step.counter}\")\n    print(f\"Tools called: {[tc.name for tc in step.tool_calls]}\")\n\n    # Dynamic tool management\n    step.add_tool(new_tool)\n    step.remove_tool(\"old_tool\")\n\n    # Early termination\n    if condition:\n        step.finish(result=\"Early exit\")\n\n    return step\n```\n\n---\n\n## 🎯 Examples\n\nTry them live on the [Gradio app](https://askmanu-acorn.hf.space) or browse the source in `examples/`:\n\n| Example | Category | Description |\n|---------|----------|-------------|\n| [Simple Q\u0026A](https://askmanu-acorn.hf.space/simple_qa) | Basic | Single-turn question answering with structured output |\n| [HN Production Readiness](https://askmanu-acorn.hf.space/hn_production_check) | Agentic | Checks if a trending HN project is production-ready |\n| [Documentation Coverage](https://askmanu-acorn.hf.space/doc_coverage) | Agentic | Scores documentation coverage of a GitHub repo (0–100) |\n| [Bus Factor Calculator](https://askmanu-acorn.hf.space/bus_factor) | Branching | Calculates the bus factor of a GitHub repository |\n| [License Compatibility](https://askmanu-acorn.hf.space/license_checker) | Agentic | Checks dependency license compatibility for conflicts |\n| [Dependency Bloat Scanner](https://askmanu-acorn.hf.space/dependency_scanner) | Branching | Finds redundant and overlapping libraries in your deps |\n\n---\n\n## 🧪 Testing\n\n```bash\n# Run all tests\npytest\n\n# With coverage\npytest --cov=acorn\n\n# Specific test file\npytest tests/test_agentic_loop.py -v\n```\n\n**Current status:** 201 tests passing, 85% coverage\n\n---\n\n## 📖 Documentation\n\n- [Getting Started](docs/getting-started.md) - Installation and first steps\n- [Module Reference](docs/module.md) - Complete Module API documentation\n\n---\n\n## 🛣️ Roadmap\n\n### ✅ Completed\n- Single-turn execution\n- Multi-turn agentic loops\n- Tool calling with auto-schema generation\n- Parse error recovery\n- Dynamic tool management\n- Step callbacks\n- Streaming responses with partial structured output\n- Forced termination strategies\n- Provider caching\n- Model fallbacks\n- Branching workflows\n\n### 📋 Planned\n- Async support\n\n---\n\n## 🤝 Contributing\n\nContributions welcome! Please:\n\n1. Check open issues for areas to help\n2. Write tests for new features (maintain \u003e80% coverage)\n3. Update documentation\n4. Add examples for new features\n\n---\n\n## 💬 Questions?\n\nCheck out:\n- [Getting Started](docs/getting-started.md) for installation and examples\n- [Module Reference](docs/module.md) for detailed API docs\n- [Examples](examples/) for working code\n- [Tests](tests/) for usage patterns\n\n---\n\n## 🙏 Acknowledgments\nThanks to @rosenbrockc for donating the `acorn` pip package name.\n\n---\n\n## 📄 License\n\n[MIT License](LICENSE)\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faskmanu%2Facorn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faskmanu%2Facorn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faskmanu%2Facorn/lists"}