{"id":35159439,"url":"https://github.com/paulomtts/py-ai-toolkit","last_synced_at":"2026-03-02T21:36:46.784Z","repository":{"id":312934940,"uuid":"1049337703","full_name":"paulomtts/py-ai-toolkit","owner":"paulomtts","description":"Bundling tools for building with AI.","archived":false,"fork":false,"pushed_at":"2026-02-08T20:38:03.000Z","size":1245,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-09T01:54:04.935Z","etag":null,"topics":["ai","grafo","instructor","jinja2","pydantic"],"latest_commit_sha":null,"homepage":"https://paulomtts.github.io/py-ai-toolkit/","language":"HTML","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/paulomtts.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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":"2025-09-02T20:37:35.000Z","updated_at":"2026-02-08T20:38:05.000Z","dependencies_parsed_at":"2025-09-03T03:19:17.594Z","dependency_job_id":null,"html_url":"https://github.com/paulomtts/py-ai-toolkit","commit_stats":null,"previous_names":["paulomtts/ait","paulomtts/grafo-ai-tools","paulomtts/py-ai-toolkit"],"tags_count":32,"template":false,"template_full_name":null,"purl":"pkg:github/paulomtts/py-ai-toolkit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulomtts%2Fpy-ai-toolkit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulomtts%2Fpy-ai-toolkit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulomtts%2Fpy-ai-toolkit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulomtts%2Fpy-ai-toolkit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/paulomtts","download_url":"https://codeload.github.com/paulomtts/py-ai-toolkit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulomtts%2Fpy-ai-toolkit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30020724,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-02T20:56:45.032Z","status":"ssl_error","status_checked_at":"2026-03-02T20:51:18.182Z","response_time":60,"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","grafo","instructor","jinja2","pydantic"],"created_at":"2025-12-28T17:53:43.710Z","updated_at":"2026-03-02T21:36:46.715Z","avatar_url":"https://github.com/paulomtts.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Install\n```\nuv add py-ai-toolkit\n```\n\n# WHAT\nA set of tools for easily interacting with LLMs.\n\n# WHY\nBuilding AI-driven software leans upon a number of utilities, such as prompt building and LLM calling via HTTP requests. Additionally, writing agents and workflows can prove particularly challenging using conventional code structures.\n\n# HOW\nThis simple library offers a set of predefined functions for:\n- Easy prompting - you need only provide a path or a template\n- Calling LLMs - instructor takes care of that for us\n- Modifying response models - we use Pydantic (duh)\n\nAdditionally, we provide `grafo` out of the box for convenient workflow building.\n\n## About Grafo\nGrafo (see Recommended Docs below) is a library for building executable DAGs where each node contains a coroutine. Since the DAG abstraction fits particularly well into AI-driven building, we have provided the `BaseWorkflow` class with the following methods:\n- `task` for LLM calling\n- `redirect` to help you manage redirections in your `grafo` workflows\n\n# Examples\n### Simple text:\n```python\nfrom py_ai_toolkit import AIT\n\nait = AIT(\"gpt-5\")\ntemplate = \"./prompt.md\"\nresponse = ait.chat(template)\nprint(response.completion)\nprint(response.content)\n```\n\n### Structured response:\n```python\nfrom py_ai_toolkit import AIT\nfrom pydantic import BaseModel\n\nclass Purchase(BaseModel):\n    product: str\n    quantity: int\n\nait = AIT(\"gpt-5\")\ntemplate = \"./prompt.md\" # PROMPT: {{ message }}\nmessage = \"I want to buy 5 apples\"\nresponse = ait.asend(response_model=Fruit, template=template, message=message)\n```\n\n### Structured response with model type injection:\n```python\nfrom py_ai_toolkit import AIT\nfrom pydantic import BaseModel\n\nclass Purchase(BaseModel):\n    product: str\n    quantity: int\n\nait = AIT(\"gpt-5\")\ntemplate = \"./prompt.md\" # PROMPT: {{ message }}\nmessage = \"I want to buy 5 apples\"\navailable_fruits = [\"apple\", \"banana\", \"orange\"]\nFruitModel = ait.inject_types(Purchase, [\n    (\"product\", Literal[tuple(available_fruits)])\n])\nresponse = ait.asend(response_model=Purchase, template=template, message=message)\n```\n\n### Using run_task with validation:\n```python\nfrom py_ai_toolkit import PyAIToolkit\nfrom py_ai_toolkit.core.domain.interfaces import (\n    LLMConfig,\n    SingleShotValidationConfig,\n)\nfrom pydantic import BaseModel\n\nclass Purchase(BaseModel):\n    product: str\n    quantity: int\n\nai_toolkit = PyAIToolkit(main_model_config=LLMConfig())\n\nresult = await ai_toolkit.run_task(\n    template=\"\"\"\n        You will extract a purchase from the following message:\n        {{ message }}\n    \"\"\".strip(),\n    response_model=Purchase,\n    kwargs=dict(message=\"I want to buy 5 apples.\"),\n    config=SingleShotValidationConfig(\n        issues=[\"The identified purchase matches the user's request.\"],\n    ),\n)\n\nprint(result.product)  # \"apple\"\nprint(result.quantity)  # 5\n```\n\n### Simple workflow:\n```python\nfrom py_ai_toolkit import AIT, BaseWorkflow, BaseValidation, Node, TreeExecutor\nfrom pydantic import BaseModel\nfrom typing import Literal\n\nclass Purchase(BaseModel):\n    product: str\n    quantity: int\n\nait = AIT(\"gpt-5\")\nprompts_path = \"./\"\nmessage = \"I want to buy 5 apples\"\navailable_fruits = [\"apple\", \"banana\", \"orange\"]\nFruitModel = ait.inject_types(Purchase, [\n    (\"product\", Literal[tuple(available_fruits)])\n])\n\nclass PurchaseWorkflow(BaseWorkflow):\n    def __init__(...):\n        ...\n\n    async def run(self, message) -\u003e Purchase:\n        purchase_node = Node[FruitModel](\n            uuid=\"fruit purchase node\",\n            coroutine=self.task,\n            kwargs=dict(\n                template=f\"{prompts_path}/purchase.md\",\n                response_model=FruitModel,\n                message=message,\n            )\n        )\n        validation_node = self.create_validation_node(\n            input=message,\n            output=purchase_node.output,\n            issues=[\"The identified purchase matches the user's request.\"],\n            source_node=purchase_node,\n        )\n\n        await purchase_node.connect(validation_node)\n        executor = TreeExecutor(uuid=\"Purchase Workflow\", roots=[purchase_node])\n        await executor.run()\n\n        if not purchase_node.output or not validation_node.output:\n            raise ValueError(\"Purchase validation failed.\")\n\n        if not validation_node.output.valid:\n            raise ValueError(\"Purchase failed validation.\")\n\n        return purchase_node.output\n```\n\n## Validation Modes\n\nThe `run_task` method supports three validation modes that control how the LLM output is validated:\n\n### SingleShotValidationConfig\n- **Count**: 1 validation attempt\n- **Required Ahead**: 1 (needs 1 more success than failure)\n- **Max Retries**: 3\n- **Use Case**: Simple validation for straightforward tasks where a single validation check is sufficient\n\n```python\nfrom py_ai_toolkit.core.domain.interfaces import SingleShotValidationConfig\n\nconfig = SingleShotValidationConfig(\n    issues=[\"The identified purchase matches the user's request.\"],\n)\n```\n\n### ThresholdVotingValidationConfig\n- **Count**: 3 validation attempts (default)\n- **Required Ahead**: 1 (needs 1 more success than failure)\n- **Use Case**: Moderate confidence validation where multiple checks provide better reliability\n\n```python\nfrom py_ai_toolkit.core.domain.interfaces import ThresholdVotingValidationConfig\n\nconfig = ThresholdVotingValidationConfig(\n    issues=[\"The identified purchase matches the user's request.\"],\n)\n```\n\n### KAheadVotingValidationConfig\n- **Count**: 5 validation attempts (default)\n- **Required Ahead**: 3 (needs 3 more successes than failures)\n- **Use Case**: High-stakes validation where you need strong consensus across multiple validation checks\n\n```python\nfrom py_ai_toolkit.core.domain.interfaces import KAheadVotingValidationConfig\n\nconfig = KAheadVotingValidationConfig(\n    issues=[\"The identified purchase matches the user's request.\"],\n)\n```\n\nAll validation configs accept an `issues` parameter, which is a list of validation criteria that will be checked against the task output. Each issue is evaluated independently, and the validation passes only if all issues pass according to the configured mode.\n\n## Recommended Docs\n- `instructor` https://python.useinstructor.com/\n- `jinja2` https://jinja.palletsprojects.com/en/stable/\n- `pydantic` https://docs.pydantic.dev/latest/\n- `grafo` https://github.com/paulomtts/grafo","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaulomtts%2Fpy-ai-toolkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpaulomtts%2Fpy-ai-toolkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaulomtts%2Fpy-ai-toolkit/lists"}