{"id":30773186,"url":"https://github.com/combinatrix-ai/prompttrail","last_synced_at":"2025-10-05T20:19:55.593Z","repository":{"id":181974159,"uuid":"667745888","full_name":"combinatrix-ai/PromptTrail","owner":"combinatrix-ai","description":"PromptTrail: A lightweight library for Prompt Programming, Agent as Code","archived":false,"fork":false,"pushed_at":"2025-02-22T03:42:12.000Z","size":1073,"stargazers_count":12,"open_issues_count":7,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-09-05T01:26:12.425Z","etag":null,"topics":["agent","chatbot","llm","llm-library","python"],"latest_commit_sha":null,"homepage":"https://prompttrail.readthedocs.io/en/latest/quickstart.html","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/combinatrix-ai.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":null,"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}},"created_at":"2023-07-18T07:59:42.000Z","updated_at":"2025-02-19T15:03:14.000Z","dependencies_parsed_at":"2023-09-22T21:02:56.181Z","dependency_job_id":"b73ba47d-0da9-4931-b1da-7be7db1e4107","html_url":"https://github.com/combinatrix-ai/PromptTrail","commit_stats":null,"previous_names":["combinatrix-ai/featherchain"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/combinatrix-ai/PromptTrail","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/combinatrix-ai%2FPromptTrail","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/combinatrix-ai%2FPromptTrail/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/combinatrix-ai%2FPromptTrail/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/combinatrix-ai%2FPromptTrail/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/combinatrix-ai","download_url":"https://codeload.github.com/combinatrix-ai/PromptTrail/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/combinatrix-ai%2FPromptTrail/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278511149,"owners_count":25999048,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-05T02:00:06.059Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["agent","chatbot","llm","llm-library","python"],"created_at":"2025-09-05T01:15:14.711Z","updated_at":"2025-10-05T20:19:55.588Z","avatar_url":"https://github.com/combinatrix-ai.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# 🚂 PromptTrail\n\n**A lightweight, developer-friendly framework for building robust LLM applications**\n\n[![PyPI version](https://badge.fury.io/py/prompttrail.svg)](https://badge.fury.io/py/prompttrail)\n[![Python Versions](https://img.shields.io/pypi/pyversions/prompttrail.svg)](https://pypi.org/project/prompttrail/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Documentation Status](https://readthedocs.org/projects/prompttrail/badge/?version=latest)](https://prompttrail.readthedocs.io/en/latest/?badge=latest)\n\n\u003c/div\u003e\n\n![readme-header](https://github.com/user-attachments/assets/3944a737-b958-43d3-9857-8b3bed5811e6)\n\nPromptTrail is a Python framework designed to make building LLM-powered applications easier and more maintainable. It provides:\n\n### 🔌 Unified LLM Interface\n- **Multiple Providers**: OpenAI, Google Gemini, Anthropic Claude, and local models via Transformers\n- **Consistent API**: Same interface for all providers with full type hints\n- **Easy Extension**: Simple provider interface to add new LLM services\n\n### 🛠️ Developer Tools\n- **Testing**: Mock providers to test LLM interactions without API calls\n- **Cost Optimization**: Built-in caching to reduce API usage\n- **[Coming Soon]**: Advanced logging and debugging features\n\n### 🤖 Agent as Code Framework\n- **Intuitive Templates**: Natural way to define conversation flows\n- **Powerful Tooling**: Type-safe function calling and built-in utilities\n- **Extensible**: Hooks system for custom behaviors and integrations\n- **Subroutines**: Isolated execution contexts with flexible session management\n\n## Contents\n\n- [PromptTrail](#prompttrail)\n  - [Quickstart](#quickstart)\n  - [Installation](#installation)\n  - [Examples](#examples)\n    - [LLM API Call](#llm-api-call)\n    - [Developer Tools](#developer-tools)\n    - [Agent as Code](#agent-as-code)\n    - [Tooling](#tooling)\n    - [Find More](#find-more)\n  - [Next](#next)\n  - [License](#license)\n  - [Contributing](#contributing)\n  - [Showcase](#showcase)\n\n## Quickstart\n\n- See [Quickstart](https://prompttrail.readthedocs.io/en/latest/quickstart.html) for more details.\n\n## Installation\n\n```bash\npip install prompttrail\n```\n\nor\n\n```bash\ngit clone https://github.com/combinatrix-ai/PromptTrail.git\ncd PromptTrail\npip install -e .\n```\n\n## Examples\n\n### LLM API Call\n\nThis is the simplest example of how to use PromptTrail as a thin wrapper around LLMs of various providers.\n\n```python\n\u003e import os\n\u003e from prompttrail.core import Session, Message\n\u003e from prompttrail.models.openai import OpenAIModel, OpenAIConfig\n\u003e\n\u003e api_key = os.environ[\"OPENAI_API_KEY\"]\n\u003e config = OpenAIConfig(\n\u003e     api_key=api_key,\n\u003e     model_name=\"gpt-4o-mini\",\n\u003e     max_tokens=100,\n\u003e     temperature=0\n\u003e )\n\u003e model = OpenAIModel(configuration=config)\n\u003e session = Session(\n\u003e   messages=[\n\u003e     Message(content=\"Hey\", role=\"user\"),\n\u003e   ]\n\u003e )\n\u003e message = model.send(session=session)\n\nMessage(content=\"Hello! How can I assist you today?\", role=\"assistant\")\n```\n\nIf you want streaming output, you can use the `send_async` method if the provider offers the feature.\n\n```python\n\u003e message_generator = model.send_async(session=session)\n\u003e for message in message_generator:\n\u003e     print(message.content, sep=\"\", flush=True)\n\nHello! How can # text is incrementally typed\n```\n\n### Developer Tools\n\nWe provide various tools for developers to build LLM applications.\nFor example, you can mock LLMs for testing.\n\n```python\n\u003e from prompttrail.core import Session, Message\n\u003e from prompttrail.core.mock import EchoMockProvider\n\u003e from prompttrail.models.openai import OpenAIModel, OpenAIConfig\n\u003e\n\u003e # Create a configuration with EchoMockProvider\n\u003e config = OpenAIConfig(\n\u003e     api_key=\"dummy\",  # API key is not used when using mock provider\n\u003e     model_name=\"gpt-4o-mini\",\n\u003e     mock_provider=EchoMockProvider()  # Simply echoes back the last message\n\u003e )\n\u003e model = OpenAIModel(configuration=config)\n\u003e\n\u003e # Use the model as usual - it will echo back the messages\n\u003e session = Session(\n\u003e     messages=[Message(content=\"Hello\", role=\"user\")]\n\u003e )\n\u003e message = model.send(session=session)\n\u003e print(message)\n\nMessage(content=\"Hello\", role=\"assistant\")  # EchoMockProvider simply returns the same content\n```\n\n### Agent as Code\n\nYou can write a simple agent like below. Without reading the documentation, you can understand what this agent does!\n\n```python\ntemplate = LinearTemplate(\n    [\n        SystemTemplate(\n            content=\"You're a math teacher bot.\",\n        ),\n        LoopTemplate(\n            [\n                UserTemplate(\n                    description=\"Let's ask a question to AI:\",\n                    default=\"Why can't you divide a number by zero?\",\n                ),\n                # Generates response using LLM\n                AssistantTemplate(),  \n                # Or, you can impersonate as LLM\n                AssistantTemplate(content=\"Are you satisfied?\"),\n                UserTemplate(\n                    description=\"Input:\",\n                    default=\"Yes.\",\n                ),\n                # Let the LLM decide whether to end the conversation or not\n                AssistantTemplate(\n                    content=\"The user has stated their feedback.\"\n                    + \"If you think the user is satisfied, you must answer `END`. Otherwise, you must answer `RETRY`.\"\n                ),\n                AssistantTemplate(),  # Generates END or RETRY response\n            ],\n            exit_condition=lambda session: (\"END\" in session.get_last_message().content),\n        ),\n    ],\n)\n\nrunner = CommandLineRunner(\n    model=OpenAIModel(\n        configuration=OpenAIConfig(\n            api_key=os.environ[\"OPENAI_API_KEY\"],\n            model_name=\"gpt-4o\"\n        )\n    ),\n    template=template,\n    user_interface=CLIInterface(),\n)\n\nrunner.run()\n```\n\nYou can talk with the agent on your console like below:\n\n````console\n===== Start =====\nFrom: 📝 system\nmessage:  You're a math teacher bot.\n=================\nLet's ask a question to AI:\nFrom: 👤 user\nmessage:  Why can't you divide a number by zero?\n=================\nFrom: 🤖 assistant\nmessage:  Dividing a number by zero is undefined in mathematics. Here's why:\n\nLet's say we have a division operation a/b. This operation asks the question: \"how many times does b fit into a?\" If b is zero, the question becomes \"how many times does zero fit into a?\", and the answer is undefined because zero can fit into a an infinite number of times.\n\nMoreover, if we look at the operation from the perspective of multiplication (since division is the inverse of multiplication), a/b=c means that b*c=a. If b is zero, there's no possible value for c that would satisfy the equation, because zero times any number is always zero, not a.\n\nSo, due to these reasons, division by zero is undefined in mathematics.\n=================\nFrom: 🤖 assistant\nmessage:  Are you satisfied?\n=================\nInput:\nFrom: 👤 user\nmessage:  Yes.\n=================\nFrom: 🤖 assistant\nmessage:  The user has stated their feedback.If you think the user is satisfied, you must answer `END`. Otherwise, you must answer `RETRY`.\n=================\nFrom: 🤖 assistant\nmessage:  END\n=================\n====== End ======\n````\nGo to [examples](examples) directory for more examples.\n\nYou can also use subroutines to break down complex tasks into manageable pieces:\n\n```python\nfrom prompttrail.agent.subroutine import SubroutineTemplate\nfrom prompttrail.agent.session_init_strategy import InheritSystemStrategy\nfrom prompttrail.agent.squash_strategy import FilterByRoleStrategy\n\n# Define a calculation subroutine\ncalculation = CalculationTemplate()  # Your calculation logic here\nsubroutine = SubroutineTemplate(\n    template=calculation,\n    session_init_strategy=InheritSystemStrategy(),  # Inherit system messages\n    squash_strategy=FilterByRoleStrategy(roles=[\"assistant\"])  # Keep only assistant messages\n)\n\n# Use in main template\ntemplate = LinearTemplate([\n    SystemTemplate(content=\"You are a math teacher.\"),\n    UserTemplate(content=\"What is 6 x 7?\"),\n    subroutine,  # Execute calculation in isolated context\n])\n```\n\nSee [examples/agent/subroutine_example.py](examples/agent/subroutine_example.py) for a complete example.\n\n### Tooling\n\nPromptTrail provides a powerful tool system for function calling that handles all the complexity of:\n\n- Type-safe argument validation\n- Automatic documentation generation from type hints\n- Function calling API formatting and execution\n- Result parsing and conversion\n\nYou can define your own tools using TypedDict for structured data and type annotations for safety:\n\n```python\nfrom typing import Literal\nfrom typing_extensions import TypedDict\nfrom prompttrail.agent.tools import Tool, ToolArgument, ToolResult\n\n# Define the structure of tool output\nclass WeatherData(TypedDict):\n    \"\"\"Weather data structure\"\"\"\n    temperature: float\n    weather: Literal[\"sunny\", \"rainy\", \"cloudy\", \"snowy\"]\n\n# Define the result wrapper\nclass WeatherForecastResult(ToolResult):\n    \"\"\"Weather forecast result\"\"\"\n    content: WeatherData\n\n# Implement the tool\nclass WeatherForecastTool(Tool):\n    \"\"\"Weather forecast tool\"\"\"\n    name: str = \"get_weather_forecast\"\n    description: str = \"Get the current weather in a given location\"\n    \n    # Define arguments with type safety\n    arguments: Dict[str, ToolArgument[Any]] = {\n        \"location\": ToolArgument[str](\n            name=\"location\",\n            description=\"The location to get the weather forecast\",\n            value_type=str,\n            required=True\n        ),\n        \"unit\": ToolArgument[str](\n            name=\"unit\",\n            description=\"Temperature unit (celsius or fahrenheit)\",\n            value_type=str,\n            required=False\n        )\n    }\n\n    def _execute(self, args: Dict[str, Any]) -\u003e ToolResult:\n        \"\"\"Execute the weather forecast tool\"\"\"\n        # Implement real API call here\n        return WeatherForecastResult(\n            content={\n                \"temperature\": 20.5,\n                \"weather\": \"sunny\"\n            }\n        )\n\n# Use the tool in a template\ntemplate = LinearTemplate(\n    [\n        SystemTemplate(\n            content=\"You are a helpful weather assistant that provides weather forecasts.\",\n        ),\n        UserTemplate(\n            role=\"user\",\n            content=\"What's the weather in Tokyo?\",\n        ),\n        ToolingTemplate(\n            functions=[WeatherForecastTool()],\n        ),\n    ]\n)\n```\n\nThe conversation will be like below:\n\n```console\n===== Start =====\nFrom: 📝 system\nmessage:  You are a helpful weather assistant that provides weather forecasts.\n=================\nFrom: 👤 user\nmessage:  What's the weather in Tokyo?\n=================\nFrom: 🤖 assistant\ndata:  {'function_call': {'name': 'get_weather_forecast', 'arguments': {'location': 'Tokyo'}}}\n=================\nFrom: 🧮 function\nmessage:  {\"content\": {\"temperature\": 20.5, \"weather\": \"sunny\"}}\n=================\nFrom: 🤖 assistant\nmessage:  The weather in Tokyo is currently sunny with a temperature of 20.5°C.\n=================\n====== End ======\n```\n\nSee [documentation](https://prompttrail.readthedocs.org/en/quickstart-agents.html#tool-function-calling) for more information.\n\n### Find More\n\nYou can find more examples in [examples](examples) directory:\n\n- Agent Examples\n  - Fermi Problem Solver (examples/agent/fermi_problem.py)\n  - Math Teacher Bot (examples/agent/math_teacher.py)\n  - Weather Forecast Bot (examples/agent/weather_forecast.py)\n  - FAQ Bot (examples/agent/faq-bot/)\n\n- Developer Tools (Dogfooding)\n  - Auto-generated Commit Messages (examples/dogfooding/commit_with_auto_generated_comment.py)\n  - Docstring Generator (examples/dogfooding/create_docstring.py)\n  - Unit Test Generator (examples/dogfooding/create_unit_test.py)\n  - Comment Fixer (examples/dogfooding/fix_comment.py)\n  - Markdown Fixer (examples/dogfooding/fix_markdown.py)\n\n## License\n\n- PromptTrail is licensed under the MIT License.\n\n## Contributing\n\n- Contributions are more than welcome!\n- See [CONTRIBUTING](CONTRIBUTING.md) for more details.\n\n## Showcase\n\n- If you build something with PromptTrail, please share it with us via Issues or Discussions!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcombinatrix-ai%2Fprompttrail","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcombinatrix-ai%2Fprompttrail","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcombinatrix-ai%2Fprompttrail/lists"}