{"id":18266285,"url":"https://github.com/ssube/packit","last_synced_at":"2026-05-05T22:34:44.966Z","repository":{"id":229113104,"uuid":"775800501","full_name":"ssube/packit","owner":"ssube","description":"an LLM toolkit","archived":false,"fork":false,"pushed_at":"2024-05-27T23:19:38.000Z","size":733,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-14T20:40:24.477Z","etag":null,"topics":["agents","conversational-ai","ensemble","inference","llm","mixture-of-experts"],"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/ssube.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}},"created_at":"2024-03-22T04:11:24.000Z","updated_at":"2024-05-27T23:19:42.000Z","dependencies_parsed_at":"2024-04-21T03:30:46.265Z","dependency_job_id":"f68bf09e-72a0-443e-be95-b6784702efc4","html_url":"https://github.com/ssube/packit","commit_stats":null,"previous_names":["ssube/packit"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssube%2Fpackit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssube%2Fpackit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssube%2Fpackit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssube%2Fpackit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ssube","download_url":"https://codeload.github.com/ssube/packit/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247962680,"owners_count":21024880,"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","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":["agents","conversational-ai","ensemble","inference","llm","mixture-of-experts"],"created_at":"2024-11-05T11:22:44.852Z","updated_at":"2026-05-05T22:34:44.927Z","avatar_url":"https://github.com/ssube.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PACkit\n\nThe Prompt Agent Construction Kit, or maybe the Programmable Agent Construction Kit.\n\nComposable constructs for conversational development. A loose toolkit of loops, groups, conditions, and parsers to help\nLLMs communicate with each other and with your code.\n\n- Something in between [Langchain](https://www.langchain.com/) and [CrewAI](https://github.com/joaomdmoura/crewAI).\n- Compatible with all [Langchain chat models](https://python.langchain.com/docs/integrations/chat/).\n- Supports function calling with JSON-trained models.\n- Group agents to build hierarchical [ensembles](#panel-group) and [mixtures of experts](#router-group) at runtime,\n  without fine-tuning or retraining the models.\n- Full [OTLP tracing](#tracing) with [Traceloop OpenLLMetry](https://github.com/traceloop/openllmetry).\n\nTry PACkit on [Google Colab](https://colab.research.google.com/drive/1repqnb8eCCju-3eCBaQjMTP3xWXhkBhv?usp=sharing) or\nusing [the Jupyter notebook](./examples/packit-demo.ipynb).\n\n![a network of lego people standing on a blueprint together](./docs/packit-banner.jpg)\n\n[![codecov](https://codecov.io/gh/ssube/packit/graph/badge.svg?token=LRXFEHFBGS)](https://codecov.io/gh/ssube/packit)\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ssube_packit\u0026metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ssube_packit)\n\n## Contents\n\n- [PACkit](#packit)\n  - [Contents](#contents)\n  - [Quickstart](#quickstart)\n  - [Examples](#examples)\n    - [With OpenAI API](#with-openai-api)\n    - [With Ollama API](#with-ollama-api)\n  - [Constructs](#constructs)\n    - [Agents](#agents)\n      - [Agent Backstory](#agent-backstory)\n      - [Agent Context](#agent-context)\n      - [Agent Temperature](#agent-temperature)\n    - [Groups](#groups)\n      - [Panel Group](#panel-group)\n        - [Panel Methods](#panel-methods)\n        - [Panel Results](#panel-results)\n      - [Router Group](#router-group)\n    - [Loops](#loops)\n      - [Base Loops](#base-loops)\n        - [Map](#map)\n        - [Reduce](#reduce)\n      - [Builder Loops](#builder-loops)\n        - [Prefix](#prefix)\n        - [Suffix](#suffix)\n        - [Midfix](#midfix)\n      - [Single-Agent Loops](#single-agent-loops)\n        - [Retry Loop](#retry-loop)\n        - [Tool Loop](#tool-loop)\n      - [Multi-Agent Loops](#multi-agent-loops)\n        - [Conversation Loop](#conversation-loop)\n        - [Extension Loop](#extension-loop)\n        - [Refinement Loop](#refinement-loop)\n      - [Complex Loops](#complex-loops)\n        - [Team Loop](#team-loop)\n    - [Results](#results)\n      - [Primitive Results](#primitive-results)\n      - [Enum Results](#enum-results)\n      - [Function Results](#function-results)\n      - [JSON Results](#json-results)\n      - [Markdown Results](#markdown-results)\n  - [Tracing](#tracing)\n    - [Traceloop OpenLLMetry](#traceloop-openllmetry)\n    - [Telemetry](#telemetry)\n\n## Quickstart\n\nCreate some agents, give them backstories, and have them talk to one another:\n\n```py\nfrom random import choice\n\nfrom langchain_openai import ChatOpenAI\n\nfrom packit.agent import Agent\nfrom packit.loops import loop_converse\n\nending = \"Leave the end open for the next person to continue the story.\"\nbackstories = {\n    \"captain\": \"You are a ship's captain, telling a story of the one that didn't get away. \" + ending,\n    \"fisherman\": \"You are a fisherman, recounting a tale of the one that got away. \" + ending,\n    \"pirate\": \"You are a salty pirate, telling a tale of the high seas. \" + ending,\n    \"sailor\": \"You are a sailor, spinning a yarn about the open ocean. \" + ending,\n}\n\nllm = ChatOpenAI(model=\"gpt-4\", temperature=0)\nagents = [Agent(name, backstory, {}, llm) for name, backstory in backstories.items()]\nstarter = choice(agents)\n\nstory = starter(\"Start writing a tall tale about sea monsters.\")\nstory = loop_converse(agents, story)\n\nprint(\"The tall tale is:\", story)\n```\n\nFor more advanced usage, you can create a team of agents and designate a manager:\n\n```py\n# Set up some experts in different fields\ncoworkers = [\n    Agent(\"mathematician\", \"You are a professional mathematician.\", {}, llm),\n    Agent(\"programmer\", \"You are an expert computer programmer.\", {}, llm),\n    Agent(\"writer\", \"You are an experienced novelist and creative writer.\", {}, llm),\n    Agent(\"biologist\", \"You are a doctor of biology.\", {}, llm),\n    Agent(\"historian\", \"You are a museum historian.\", {}, llm),\n]\n\ncoworker_names = [coworker.name for coworker in coworkers]\n\n\n# Prepare a tool to complete tasks and exit the loop\ncomplete_tool, complete_condition, reset_complete = make_complete_tool()\ncomplete_or_threshold = condition_or(complete_condition, condition_threshold)\n\n\n# Prepare the teamwork tools\ndelegate_tool, question_tool = make_team_tools(coworkers)\n\n\ntoolbox = Toolbox(\n    [\n        complete_tool,\n        delegate_tool,\n        question_tool,\n    ]\n)\n\n\n# Prepare a filter to prevent repeated tool calls\ntool_filter, clear_filter = repeat_tool_filter(\"You have already used that tool, please try something else.\")\n\n\n# Create a team leader\nmanager = Agent(\n    \"team leader\",\n    \"You are the team leader. Complete your tasks by asking questions and delegating tasks to your coworkers.\",\n    {},\n    llm,\n)\n\n# Complete some tasks\ntasks = [\n    \"Write a novel about a haunted house.\",\n    \"Calculate the square root of 144.\",\n    \"Write a program that multiplies two numbers.\",\n    \"Identify the genus of a tree with wide, five-pointed leaves.\",\n    \"Research the history of the Roman Empire.\",\n]\n\nfor task in tasks:\n    print(\"Task:\", task)\n    clear_filter()\n    reset_complete()\n\n    loop_team(\n        manager,\n        coworkers,\n        initial_prompt=(\n            \"Using your team, complete the following task: {task}. \"\n            \"If you need help from an expert or more information, ask a question or delegate a task to your coworkers. \"\n            \"Do not call the complete tool until the task is finished. \"\n            \"Do not call the complete tool until you have received a response from your team. \"\n            \"Do not describe what you are trying to accomplish. Only reply with function calls for tools. \"\n        ),\n        loop_prompt=(\n            \"You are trying to complete the following task with your team: {task}. \"\n            \"If you have all of the information that you need, call the complete tool to finish the task. \"\n            \"If the task is not complete, ask another question or delegate another task. \"\n            \"Do not describe what you are trying to accomplish. Only reply with function calls for tools. \"\n        ),\n        {\n            \"task\": task,\n        },\n        stop_condition=complete_or_threshold,\n        tool_filter=tool_filter,\n        toolbox=toolbox,\n    )\n\n    if complete_condition():\n        print(\"Task complete.\")\n    else:\n        print(\"Task incomplete.\")\n```\n\nIn contrast to a [CrewAI crew](https://docs.crewai.com/core-concepts/Crews/), which is a monolithic construct that can\nbe difficult to control, a PACkit team is composed of smaller functions that are callable on their own. The\n`repeat_tool_filter` tool filter prevents the team from calling the same tools repeatedly, while the\n`condition_or(complete_condition, condition_threshold)` stop condition prevents infinite loops by combining an iteration\nlimit with a completion tool, allowing the LLM to exit the `loop_team` when it has enough information to complete the\ntask.\n\n## Examples\n\nAll examples should work with both OpenAI and Ollama, allowing you to test them locally or in the cloud.\n\n**Note:** running loops with a very large iteration limit or without an iteration limit at all can consume a **very\nlarge** number of tokens. Take care when using API keys for cloud services that charge by the token, they can be very\nexpensive if you are not careful. Most loops use an iteration limit by default, but these have not been thoroughly\ntested, so proceed with caution. I recommend using a local model and server for both cost and privacy reasons.\n\n### With OpenAI API\n\nRun the examples, making sure to set your OpenAI API key and the `gpt-4` model:\n\n```shell\nexport OPENAI_API_KEY=\"your-api-key-here\"\nexport PACKIT_MODEL=\"gpt-4\"\n\n\u003e time python3 -m examples.readme\nThe tall tale is: Gather 'round, ye sea dogs and landlubbers alike, and lend an ear to this old salt. I've a tale to spin, a yarn to weave, about the one that didn't get away. A tale of a sea monster, a leviathan of the deep, that would make even the bravest sailor's blood run cold.\n\n'Twas a time many moons ago, when I was but a young captain, full of fire and brine. We were sailing the South Seas, the wind in our sails and the sun on our backs, when the sea turned as black as a moonless night. The air grew cold, and a fog as thick as pea soup rolled in, obscuring our vision. The crew grew restless, whispering of ghost ships and sea serpents. But I, in my youthful arrogance, dismissed their fears as old wives' tales.\n\nThen, from the depths, it came. A monstrous beast, the likes of which no man had ever seen. It was as long as our ship, with scales that shimmered like a thousand emeralds under the water. Its eyes were as red as the setting sun, and it had teeth as sharp as cutlasses. It roared, a sound that shook the very timbers of our ship, and the sea around us boiled with its fury.\n\nThe crew was paralyzed with fear, but not I. I grabbed a harpoon and climbed to the crow's nest, determined to face the beast. As it lunged towards our ship, I took aim and threw the harpoon with all my might. It struck true, embedding itself in the monster's hide.\n\nBut the beast was not so easily defeated. It thrashed and roared, its tail smashing into our ship and sending men flying. I held on for dear life, praying to Poseidon for mercy. Then, with a final, desperate effort, I drew my cutlass and leapt onto the beast's back.\n\nI fought like a man possessed, hacking and slashing at the monster. Blood and sea water sprayed everywhere, and the beast roared in pain and fury. But I did not let up. I fought until my arms were numb and my vision blurred, until finally, with a mighty roar, the beast fell silent.\n\nExhausted, I slid off its back and into the sea, watching as the monster sank beneath the waves. I was pulled aboard by my crew, who stared at me in awe. From that day forth, they spoke of the battle in hushed whispers, of the young captain who had faced a sea monster and lived to tell the tale.\n\nAnd that, my friends, is the story of the one that didn't get away. A tale of courage and determination, of a man and a monster, locked in a battle for the ages. So next time you find yourself out on the open sea, remember this tale. For the ocean is a vast and mysterious place, full of wonders and terrors alike. And who knows what monsters lurk beneath its waves?\n\nreal    0m30.965s\n```\n\nIf you receive an error from the OpenAI API that the `mixtral` model does not exist or is not accessible, make sure you\nhave set the `PACKIT_MODEL` variable to a valid OpenAI model, like `gpt-4`.\n\n### With Ollama API\n\nLaunch a local or remote [Ollama server](https://ollama.com/) and download the\n[Mixtral model](https://mistral.ai/news/mixtral-of-experts/):\n\n```shell\nexport OLLAMA_HOST=0.0.0.0 # only needed for remote access\nexport OLLAMA_MODELS=/mnt/very-large-disk/ollama/models\n\nollama pull mixtral\nollama serve\n```\n\nRun the examples, making sure to set the `ollama` driver:\n\n```shell\nexport PACKIT_DRIVER=ollama\n\n\u003e python3 -m examples.cowboy_story\n Gather 'round folks, and listen close as I recount the tale of a legendary haunted cattle drive. It was a dark and stormy night, not unlike this one, when a group of hardened cowboys set out to drive a herd of cattle from Texas to Kansas.\n\nThese cowboys were some of the toughest hombres around; they had faced danger many times before and lived to tell the tale. Yet, they had heard whispers of strange occurrences along this very trail. They dismissed it as mere superstition and embarked on their journey.\n\nAs they made their way northward, they began to notice peculiar happenings. Cattle would low in fear for no apparent reason, and the horses became easily spooked. At night, eerie howls and moans echoed around them, seeming to come from nowhere and everywhere at once.\n\nOne evening, as they sat by their campfire, much like we are now, a lone figure approached riding towards them. As it drew nearer, they discerned it was a cowboy, his face pale and drawn. He rode up to the fire and cautioned them about the haunted cattle drive.\n\n\"I was part of a group that attempted to drive these cattle before,\" he said, \"but we were plagued by uncanny happenings. Cattle would vanish without a trace during the night, only to be discovered miles away, lifeless and drained of blood. Horses would suddenly rear and buck without provocation. And when darkness fell, we'd hear shrill screams and wails emanating from what sounded like the very earth itself.\"\n\nThe cowboys scoffed at his warning, insisting they weren't afraid of any ghost stories. However, as days turned into nights, more inexplicable events transpired. Though they couldn't understand why, they knew something was amiss.\n\nOne night, while they lay asleep under the stars, a blood-curdling scream pierced the silence. They grabbed their guns and rushed out into the darkness, where they saw a ghostly figure riding towards them. It was a woman, dressed all in white, her face contorted in a scream of terror.\n\nThe cowboys watched as she rode past them, right through their campfire, leaving behind nothing but smoke and ash. Her chilling screams lingered in their ears long after she disappeared into the shadowy night.\n\nFrom that moment forth, they believed in the legend. They hurried their cattle to Kansas, never stopping or looking back. When they finally arrived, relief washed over them, but they never forgot the haunted cattle drive.\n\nSo, as you sit around this campfire, listening to my tale, remember the legend of the Haunted Cattle Drive. Out here on the prairie, one can never truly know what might be lurking in the shadows.\n\n\n\u003e python3 -m examples.food_critics\n\nThe critics decided that spaghetti carbonara is good because:\n-  No. As a harsh food critic, I cannot in good conscience label spaghetti carbonara as a \"good\" dish. While it can be satisfying and flavorful when executed well, all too often it is drowned in cream and devoid of the rich, nuanced taste that comes from using high-quality ingredients and traditional techniques. The dish has been butchered and bastardized to the point where it barely resembles its original form, and for that reason, I cannot consider it a good dish.\n-  Yes, I think spaghetti carbonara is a good dish. It's a classic Italian pasta made with eggs, cheese, and pancetta or bacon. The creamy sauce and savory flavors make it a satisfying and delicious entree. Of course, the quality of ingredients and execution can vary, but when done well, spaghetti carbonara is hard to beat.\n-  Yes, I do! Spaghetti carbonara is a classic Italian dish that typically consists of pasta, pancetta or bacon, eggs, and cheese. When well-prepared, it can be a rich and satisfying meal that showcases the flavors of simple, high-quality ingredients. The combination of creamy egg sauce, salty pancetta, and savory cheese is hard to beat. Overall, I would say that spaghetti carbonara is a very good dish!\n-  Yes, I do! Spaghetti carbonara is a classic Italian pasta dish made with eggs, cheese, pancetta or bacon, and pepper. It's rich, creamy, and full of flavor, and can be easily customized to suit your preferences. Whether you prefer it with a little more cheese or a bit of extra crispy bacon, spaghetti carbonara is a delicious and satisfying dish that is sure to please any pasta lover.\n\nThe critics decided that pad thai is good because:\n-  No. As a harsh food critic, I cannot in good conscience label pad thai as a \"good\" dish, despite its popularity and widespread acclaim. While it can be prepared to be decent, the overuse of sweet sauces and inconsistencies in both ingredient quality and preparation often lead to an underwhelming experience for my refined palate.\n-  Yes, I do think that pad thai can be a good dish. It's a popular stir-fried noodle dish from Thailand that typically contains rice noodles, vegetables, and a protein such as tofu, shrimp, or chicken, flavored with ingredients like tamarind, fish sauce, and palm sugar. When well-prepared, pad thai can be delicious and satisfying. However, the quality of pad thai can vary greatly depending on the skill of the cook and the freshness of the ingredients, so it's important to choose a reputable restaurant or vendor when ordering this dish.\n-  Yes, I do! Pad Thai is a delicious and popular dish that originated from Thailand. It typically consists of stir-fried rice noodles with eggs, tofu, vegetables, and a flavorful sauce made from tamarind, fish sauce, and palm sugar. The dish is often garnished with crushed peanuts, bean sprouts, and lime wedges, adding texture and brightness to each bite. I can see why it's a favorite for many people.\n-  Yes, I do! Pad Thai is a delicious and popular dish that originated from Thailand. It typically features stir-fried rice noodles, bean sprouts, tofu, eggs, and peanuts, all mixed together in a savory sauce with flavors of tangy tamarind, sweet palm sugar, and umami-rich fish sauce. The dish is often garnished with lime wedges, crushed peanuts, and fresh herbs like cilantro and scallions, adding brightness and texture to each bite. I can see why it's a favorite among many food lovers!\n\nThe critics decided that rocks is bad because:\n-  No. Rocks are not a suitable ingredient for any dish, as they are hard and indigestible. Consuming rocks can cause serious harm to one's health, and should never be consumed as food.\n-  No, I do not think rocks would make a good dish. Rocks are hard and not edible, so they would not be enjoyable to eat. Additionally, consuming non-food items can be harmful to your health.\n-  No, I do not think that rocks would make a good dish to serve as an entree. Rocks are not edible and consuming them could be very harmful. As a generous food critic, I must still prioritize the safety and well-being of those who enjoy food.\n-  No, I do not think rocks would make a good dish to eat. As a food critic, I value high-quality ingredients that are prepared in a way that brings out their flavors and textures. Rocks do not meet these criteria, as they are not typically consumed as food and lack the nutritional value and taste of more traditional culinary ingredients.\n...\n```\n\n## Constructs\n\n### Agents\n\nAn `Agent` is a particular configuration of an LLM with a backstory, facts, and temperature.\n\n#### Agent Backstory\n\nAn `Agent`'s backstory defines who they are and how they will behave.\n\nIn technical terms, the backstory is the system prompt, which influences what role the LLM takes when responding.\n\n#### Agent Context\n\nAn `Agent`'s context are the facts they will always know.\n\nIn technical terms, the context is the dictionary of variables available for use in template strings.\n\n#### Agent Temperature\n\nAn `Agent`'s temperature controls how creative they will be, but too high of a temperature will stop making sense.\n\n### Groups\n\n#### Panel Group\n\nThe `Panel` is a weighted group of agents. Each agent will be given the same user prompt, along with their own system\nprompt, or backstory. Their responses will be interpreted the same way. Agents with a greater weight will be asked more\noften than the others.\n\n```mermaid\nstateDiagram-v2\n    [*] --\u003e Start\n    Start --\u003e Agent1: Prompt\n    Start --\u003e Agent2: Prompt\n    Start --\u003e Agent3: Prompt\n    Agent1 --\u003e ResultParser: Response\n    Agent2 --\u003e ResultParser: Response\n    Agent3 --\u003e ResultParser: Response\n    ResultParser --\u003e Decision: Parse Response into Result\n    Decision --\u003e End\n    End --\u003e [*]\n```\n\n##### Panel Methods\n\nPanels can use many methods to make their decision. Agents can respond with a yes/no answer or rank items on a scale.\nWhen multiple items are provided, they can be evaluated individually or as a single group (with a large enough\ncontext window).\n\n##### Panel Results\n\nPanels can make their decision using any of the available comparators. By default, they will compare their mean\nrating against a predefined threshold. If the consensus exceeds the threshold, the panel will give an affirmative\nanswer. This can also be inverted using a counter or the not comparator.\n\n#### Router Group\n\nThe `Router` group uses a `decider` agent to select one or more `expert` agents. Each `expert` is presented with the\nsame prompt, and their results can be used directly or summarized by the `decider`.\n\n```mermaid\nstateDiagram-v2\n    [*] --\u003e Start\n    Start --\u003e Manager: Prompt\n    Manager --\u003e ExpertRouting: Expert Routing\n    ExpertRouting --\u003e Expert1: Prompt\n    ExpertRouting --\u003e Expert2: Prompt\n    Expert1 --\u003e Manager: Response 2a\n    Expert2 --\u003e Manager: Response 2b\n    Manager --\u003e Manager: Prompt 3ab\n    Manager --\u003e End: Response 3\n    End --\u003e [*]\n```\n\n### Loops\n\n#### Base Loops\n\n##### Map\n\nPresents the same prompt to each agent and collects their responses in a `dict` or `list`.\n\n```mermaid\nstateDiagram-v2\n    [*] --\u003e Start\n    Start --\u003e Agent1: Prompt\n    Start --\u003e Agent2: Prompt\n    Start --\u003e Agent3: Prompt\n    Start --\u003e Agent4: Prompt\n    Agent1 --\u003e Responses: Response 1\n    Agent2 --\u003e Responses: Response 2\n    Agent3 --\u003e Responses: Response 3\n    Agent4 --\u003e Responses: Response 4\n    Responses --\u003e [*]: End\n```\n\n##### Reduce\n\nChains a series of agents, passing the response from the last one as the prompt for the next.\n\n```mermaid\nstateDiagram-v2\n    [*] --\u003e Start\n    Start --\u003e Agent1: Prompt\n    Agent1 --\u003e Agent2: Response as Prompt\n    Agent2 --\u003e Agent3: Response as Prompt\n    Agent3 --\u003e Agent4: Response as Prompt\n    Agent4 --\u003e End: Response\n    End --\u003e [*]\n```\n\n#### Builder Loops\n\n##### Prefix\n\nCalls one of the [base loops](#base-loops), adding a prefix to the prompt before each iteration.\n\n##### Suffix\n\nCalls one of the [base loops](#base-loops), adding a suffix to the prompt before each iteration.\n\n##### Midfix\n\nCombines the prefix and suffix loops. Calls one of the [base loops](#base-loops), adding both a prefix and a suffix\nbefore each iteration.\n\n#### Single-Agent Loops\n\n##### Retry Loop\n\nPresent the agent with a prompt. If the result cannot be parsed, present the error to the agent. Retry until the\nresult is parsed successfully or the stop condition is met.\n\n```mermaid\nstateDiagram-v2\n    [*] --\u003e Start\n    Start --\u003e Agent1: Prompt\n    Agent1 --\u003e ResultParser: Response\n    ResultParser --\u003e Agent1: Prompt + Error\n    Agent1 --\u003e Agent2: Prompt + Error\n    Agent2 --\u003e ResultParser: Response\n    ResultParser --\u003e Agent2: Prompt + Error\n    Agent2 --\u003e Agent3: Prompt + Error\n    Agent3 --\u003e ResultParser: Response\n    ResultParser --\u003e End: Success\n    End --\u003e [*]\n```\n\n##### Tool Loop\n\nPresent the agent with a prompt and parse the result as a JSON function call. Invoke the tool and recursively parse\nthe results until the response is not a JSON function call.\n\n#### Multi-Agent Loops\n\n##### Conversation Loop\n\nUsing two or more agents, have them respond to one another in a conversational manner.\n\nThe conversation will continue until the iteration limit has been reached or the stop condition becomes true.\n\nEach agent will pass their response on to the next agent and ask them to consider it. This is similar to what CrewAI\ndoes, but much simpler.\n\n##### Extension Loop\n\nUsing one or more agents, have them incrementally extend the output.\n\nThe extension will continue until the iteration limit has been reached or the stop condition becomes true.\n\nEach agent will pass their response on to the next agent and prompt them to extend it.\n\n##### Refinement Loop\n\nUsing one or more agents, have them incrementally refine the output.\n\nThe refinement will continue until the iteration limit has been reached or the stop condition becomes true.\n\nEach agent will pass their response on to the next agent and prompt them to refine and correct it.\n\n#### Complex Loops\n\n##### Team Loop\n\nUsing a manager and one or more agents, delegate subtasks or ask questions to complete the task given in the prompt.\n\n```mermaid\nstateDiagram-v2\n    [*] --\u003e Start\n    Start --\u003e Manager: Prompt\n    Manager --\u003e Agent1: Delegate / Question\n    Agent1 --\u003e Manager: Response\n    Manager --\u003e Agent2: Task Prompt\n    Agent2 --\u003e Manager: Response\n    Manager --\u003e Agent3: Delegate / Question\n    Agent3 --\u003e Manager: Response\n    Manager --\u003e End: Complete\n    End --\u003e [*]\n```\n\n### Results\n\n#### Primitive Results\n\nResult parsers are provided for Python primitives, including:\n\n- `bool`\n- `int`\n- `str`\n\n#### Enum Results\n\nInterpret the response as one of the values from an enumeration or list of strings.\n\nIf more than one value is present, returns the first one by position in the response.\n\n#### Function Results\n\nInterpret the response as a function call using [LangChain's JSON\nschema](https://python.langchain.com/docs/modules/model_io/chat/function_calling#defining-functions-schemas) for\nfunction calls and invoke the function from a dictionary of callbacks.\n\n#### JSON Results\n\nInterpret the response as JSON. If the result is not valid JSON, attempt to fix it.\n\n#### Markdown Results\n\nInterpret the response as a Markdown document and extract certain blocks.\n\nBy default, this extract code blocks with their language hint set to Python.\n\n## Tracing\n\n### Traceloop OpenLLMetry\n\nPACkit is fully integrated with [Traceloop's OpenLLMetry SDK](https://github.com/traceloop/openllmetry) for OTLP\ntracing.\n\nOTLP tracing is **off by default** and must be enabled by setting the `PACKIT_TRACER` environment variable to `traceloop`\nor by initializing the Traceloop SDK in your own code _and_ calling `packit.tracing.set_tracer(\"traceloop\")`.\n\nTo export OTLP traces to a self-hosted Grafana Tempo server, set the `TRACELOOP_BASE_URL` environment variable to the\nTempo ingest URL:\n\n```shell\nPACKIT_TRACER=traceloop\nTRACELOOP_BASE_URL=http://traces.example.com\n```\n\nPACkit spans are named `packit.$type.$entity`, where `$entity` is a `lower_snake_case` name for an [Agent](#agents),\n[group](#groups), [loop](#loops), or tool. The `$type` indicates which construct initiated the span.\n\n![overview image of collapsed spans from the food critics example](./docs/traces-spans.png)\n\nSpans include their inputs and outputs, including prompt and context. For agents, this is the prompt, context, and\nresponse. For groups and loops, this captures the agents being used, prompts, context, and any other notable aspects of\nthe construct.\n\n![spans from the food critics example in Grafana Temp showing a prompt about judging spaghetti carbonara](./docs/traces-prompt.png)\n\n### Telemetry\n\nPACkit does not include any telemetry code of its own and the default tracer uses the Python logging infrastructure\nto write messages to the console (or any other destination that you configure).\n\nHowever, some of the libraries used in the examples use opt-out telemetry. Most of those libraries offer a way to\ndisable telemetry with an environment variable, but that does not guarantee that data will not be collected. Be careful\nusing libraries and make sure to monitor outgoing network traffic for any privacy-sensitive applications.\n\nDocumentation for libraries with their own telemetry:\n\n- [Traceloop SDK telemetry](https://www.traceloop.com/docs/openllmetry/privacy/telemetry)\n- [vLLM usage stats](https://docs.vllm.ai/en/latest/serving/usage_stats.html)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fssube%2Fpackit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fssube%2Fpackit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fssube%2Fpackit/lists"}