Full Code of agiresearch/OpenAGI for AI

main 26c119e55b8d cached
179 files
488.7 KB
111.3k tokens
494 symbols
1 requests
Download .txt
Showing preview only (538K chars total). Download the full file or copy to clipboard to get everything.
Repository: agiresearch/OpenAGI
Branch: main
Commit: 26c119e55b8d
Files: 179
Total size: 488.7 KB

Directory structure:
gitextract_5k2uygq5/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── 001-report-bug.yml
│   │   ├── 002-feature-request.yml
│   │   └── 003-misc-discussion.yml
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── ci.yml
│       └── publish.yml
├── .gitignore
├── .pre-commit-config.yaml
├── CONTRIBUTE.md
├── LICENSE
├── README.md
├── pyopenagi/
│   ├── README.md
│   ├── __init__.py
│   ├── agents/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── agent_factory.py
│   │   ├── agent_process.py
│   │   ├── base_agent.py
│   │   ├── call_core.py
│   │   ├── example/
│   │   │   ├── README.md
│   │   │   ├── academic_agent/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── cocktail_mixlogist/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── cook_therapist/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── creation_agent/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── fashion_stylist/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── festival_card_designer/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── fitness_trainer/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── game_agent/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── interior_decorator/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── language_tutor/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── logo_creator/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── math_agent/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── meme_creator/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── music_composer/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── plant_care_assistant/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── rag_agent/
│   │   │   │   ├── README.md
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   ├── data/
│   │   │   │   │   └── paul_graham/
│   │   │   │   │       └── paul_graham_essay.txt
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── rec_agent/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── story_teller/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── tech_support_agent/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── transcribe_agent/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── travel_agent/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   └── travel_planner_agent/
│   │   │       ├── README.md
│   │   │       ├── agent.py
│   │   │       ├── config.json
│   │   │       ├── meta_requirements.txt
│   │   │       └── prompts.py
│   │   ├── interact.py
│   │   ├── om-raheja/
│   │   │   └── transcribe_agent/
│   │   │       ├── agent.py
│   │   │       ├── config.json
│   │   │       └── meta_requirements.txt
│   │   └── react_agent.py
│   ├── data/
│   │   └── agent_tasks/
│   │       ├── README.md
│   │       └── example/
│   │           ├── academic_agent_task.txt
│   │           ├── cocktail_mixlogist_task.txt
│   │           ├── cook_therapist_task.txt
│   │           ├── creation_agent_task.txt
│   │           ├── fashion_stylist_task.txt
│   │           ├── festival_card_designer_task.txt
│   │           ├── fitness_trainer_task.txt
│   │           ├── game_agent_task.txt
│   │           ├── interior_decorator_task.txt
│   │           ├── language_tutor_task.txt
│   │           ├── logo_creator_task.txt
│   │           ├── math_agent_task.txt
│   │           ├── meme_creator_task.txt
│   │           ├── music_composer_task.txt
│   │           ├── plant_care_assistant_task.txt
│   │           ├── rec_agent_task.txt
│   │           ├── story_teller_task.txt
│   │           ├── tech_support_agent_task.txt
│   │           ├── travel_agent_task.txt
│   │           └── travel_planner_agent_task.txt
│   ├── manager/
│   │   └── manager.py
│   ├── queues/
│   │   ├── README.md
│   │   ├── base_queue.py
│   │   └── llm_request_queue.py
│   ├── tools/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── arxiv/
│   │   │   └── arxiv.py
│   │   ├── base.py
│   │   ├── bing/
│   │   │   └── bing_search.py
│   │   ├── currency_converter/
│   │   │   └── currency_converter.py
│   │   ├── google/
│   │   │   ├── google_places.py
│   │   │   └── google_search.py
│   │   ├── imdb/
│   │   │   ├── top_movie.py
│   │   │   ├── top_movies.py
│   │   │   └── top_series.py
│   │   ├── impira/
│   │   │   └── doc_question_answering.py
│   │   ├── meteosource_weather/
│   │   │   └── find_place.py
│   │   ├── moonphase/
│   │   │   └── moon_phase_search.py
│   │   ├── openai/
│   │   │   └── speech_to_text.py
│   │   ├── shazam/
│   │   │   └── song_auto_complete.py
│   │   ├── stability-ai/
│   │   │   ├── sdxl_turbo.py
│   │   │   └── text_to_image.py
│   │   ├── suno/
│   │   │   └── text_to_speech.py
│   │   ├── timbrooks/
│   │   │   └── image_to_image.py
│   │   ├── transcriber/
│   │   │   └── transcriber.py
│   │   ├── travel_planner/
│   │   │   ├── accommodations.py
│   │   │   ├── attractions.py
│   │   │   ├── cities.py
│   │   │   ├── flights.py
│   │   │   ├── google_distance_matrix.py
│   │   │   ├── notebook.py
│   │   │   ├── planner.py
│   │   │   └── restaurants.py
│   │   ├── trip_advisor/
│   │   │   ├── airport_search.py
│   │   │   ├── flight_search.py
│   │   │   ├── get_hotel_details.py
│   │   │   ├── get_restaurant_details.py
│   │   │   ├── hotel_location_search.py
│   │   │   ├── hotel_search.py
│   │   │   ├── restaurant_location_search.py
│   │   │   └── restaurant_search.py
│   │   ├── wikipedia/
│   │   │   └── wikipedia.py
│   │   ├── wolfram/
│   │   │   └── wolfram_alpha.py
│   │   └── words_api/
│   │       └── words_api.py
│   └── utils/
│       ├── README.md
│       ├── __init__.py
│       ├── chat_template.py
│       ├── commands/
│       │   └── top.py
│       ├── compressor.py
│       ├── logger.py
│       └── utils.py
├── pyproject.toml
├── requirements-dev.txt
├── requirements.txt
├── tests/
│   ├── README.md
│   ├── __init__.py
│   ├── test_agent_creation.py
│   └── test_tools/
│       ├── README.md
│       ├── test_currency_converter.py
│       ├── test_top_series.py
│       ├── test_wolfram_alpha.py
│       └── test_words_api.py
└── tools.md

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/ISSUE_TEMPLATE/001-report-bug.yml
================================================
name: Bug report
description: Raise an issue here if you find a bug.
title: "[Bug] "
labels: ["bug"]

body:
- type: checkboxes
  attributes:
    label: Checked other resources
    description: Please confirm and check all the following options.
    options:
    - label: I added a very descriptive title to this issue.
      required: true
    - label: I am sure the issue hasn't been already addressed by searching through https://github.com/agiresearch/OpenAGI/issues.
      required: true
    - label: The usage issue is not resolved by updating to the latest stable version in the main branch.
      required: true
  validations:
    required: true
- type: textarea
  attributes:
    label: Describe your current environment
    description: |
      Your current environment information (including OS, GPU, Cuda-version)
- type: textarea
  attributes:
    label: Describe the bug
    description: |
      Please provide a clear and concise description of what the bug is.
      If relevant, add a minimal example so that we can reproduce the error by running the code.
  validations:
    required: true
- type: markdown
  attributes:
    value: >
      Thanks for contributing 🎉!


================================================
FILE: .github/ISSUE_TEMPLATE/002-feature-request.yml
================================================
name: Feature request
description: Submit a proposal/request for a new aios feature
title: "[Feature] "
labels: ["feature request"]

body:
- type: checkboxes
  attributes:
    label: Checked other resources
    description: Please confirm and check all the following options.
    options:
      - label: I added a very descriptive title to this issue.
        required: true
      - label: I am sure the issue hasn't been already addressed by searching through https://github.com/agiresearch/OpenAGI/issues.
        required: true
- type: textarea
  attributes:
    label: The feature, motivation and pitch
    description: >
      A clear and concise description of the feature proposal. Please outline the motivation for the proposal. Is your feature request related to a specific problem? e.g., *"I'm working on X and would like Y to be possible"*. If this is related to another GitHub issue, please link here too.
  validations:
    required: true
- type: textarea
  attributes:
    label: Alternatives
    description: >
      A description of any alternative solutions or features you've considered, if any.
- type: textarea
  attributes:
    label: Additional context
    description: >
      Add any other context or screenshots about the feature request.
- type: markdown
  attributes:
    value: >
      Thanks for contributing 🎉!


================================================
FILE: .github/ISSUE_TEMPLATE/003-misc-discussion.yml
================================================
name: Misc/random discussions that do not fit into the above categories.
description: Submit a discussion as you like. Note that developers are heavily overloaded and we mainly rely on community users to answer these issues.
title: "[Misc] "
labels: ["misc discussion"]

body:
- type: textarea
  attributes:
    label: Anything you want to discuss about aios.
    description: >
      Anything you want to discuss about aios.
  validations:
    required: true
- type: markdown
  attributes:
    value: >
      Thanks for contributing 🎉!


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
Thank you for your contribution to OpenAGI!
Before submitting the pull request, please ensure **the PR meets the following criteria**! This helps improve the efficiency of the review process.

### Code Quality
Before submitting your PR, you need to follow the steps below to maintain code quality.
- Use `pip install -r requirements-dev.txt` to install the extra dependencies in requirements-dev.txt for the following checks.
- Use `pre-commit install` to install pre-commit locally before you commit messages. The pre-commit can help correct the style that are added or modified.
- Use `pytest -v tests/` to run the test code and make sure it passes all the checks.

### PR title and classification
Only specific types of PRs will be reviewed. The PR title is prefixed appropriately (i.e., "prefix: description") to indicate the type of change. Please use one of the prefixs as below:
- `feat` Add new features
- `fix`  Fix bugs
- `docs` Modify documents like README, CONTRIBUTE
- `style` Modify code format like space and comma without changing code logic
- `refactor` Refactor code structure without adding new features or fixing new bugs
- `perf` Improve performance or user experience
- `test` Test features, including unit test and integration test
- `chore` Change the build procedure or add dependencies
- `revert` Revert to the previous version

### PR messages
- **Description:** a description of the change
- **Issue:** the issue # it fixes, if applicable
- **Dependencies:** any dependencies required for this change

### For the Reviews
- After the PR is submitted, the PR will be assigned to a reviewer. Every reviewer will pick up the PRs based on their expertise and availability.
- If no one reviews your PR within a few days, please @-mention one of [dongyuanjushi](https://github.com/dongyuanjushi/), [evison](https://github.com/evison), [Wenyueh](https://github.com/Wenyueh), [BRama10](https://github.com/BRama10).


================================================
FILE: .github/workflows/ci.yml
================================================
name: CI

on:
  [push,pull_request]

jobs:
  run-pytest:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2

    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: "3.11"

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements-dev.txt

    - name: Run tests
      run: |
        pytest -v tests


================================================
FILE: .github/workflows/publish.yml
================================================
name: Publish Python Package

on:
  push:
    tags:
      - "v*"

jobs:
  deploy:
    runs-on: ubuntu-latest

    environment: release
    permissions:
      id-token: write

    steps:
      - uses: actions/checkout@v4
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: "3.11"
          cache: "pip"
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install hatch
      - name: Build package
        run: hatch build
      - name: Publish package distributions to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1


================================================
FILE: .gitignore
================================================
.idea/
.vscode/

.DS_Store

# Ignore Python compiled files
__pycache__/
*.py[cod]

# Ignore Mac system files
.DS_Store

# Ignore package info
*.egg-info/


*.ipynb

api_key.py

generated_images/

generated_poems/

generated_music/

./UI/.env*.local
.env

chroma_db/

dist/
/dist/
dist

================================================
FILE: .pre-commit-config.yaml
================================================
repos:
-   repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v3.2.0
    hooks:
    -   id: trailing-whitespace
    -   id: end-of-file-fixer
    -   id: check-yaml
    -   id: check-added-large-files


================================================
FILE: CONTRIBUTE.md
================================================
# How to contribute to OpenAGI
Thank you for your interest in OpenAGI!
Here's a guide to help you contribute to this project.

## 1. Get Started
### Fork the repository

At first, you need to fork this copy and create your own version of repo.

### Clone the repository and install the dependencies.

### Installing dependencies with pip
```bash
pip install -r requirements.txt
```

### Installing pre-commit
We strongly recommend installing [pre-commit](https://pre-commit.com/) to ensure proper formatting during development

## 2. Developing and Testing
### Create a branch

Create a new branch for developing your creative features

```shell
git checkout -b your-feature
```

### Make changes and testing

You can develop new features and then you need to make sure everything works as expected. Run our provided tests and make sure the existing ones go well. Your new tests are encouraged.

### Run tests

Add your test code into the `openagi/tests/` directory if any, then run test via [pytest](https://docs.pytest.org/en/8.0.x/)

```
cd openagi
pytest -v tests
```
sample output
```
============================================================================================================================= test session starts ==============================================================================================================================
platform darwin -- Python 3.11.9, pytest-8.1.1, pluggy-1.5.0 -- ""
cachedir: .pytest_cache
rootdir: ""
plugins: anyio-4.3.0
collected 2 items

tests/test_agent_creation.py::test_agent_creation PASSED                                                                                                                                                                                                                 [ 50%]
tests/test_tools.py::test_currency_converter_api PASSED                                                                                                                                                                                                                  [100%]
```

## 3. Submitting Changes

### Code format check
Please ensure your code is formatted correctly using pre-commit

### Git commit message
We strongly recommend your git commit follows the format below
```bash
git commit -m <type>: <subject>
```

| <type> | <subject>                                     |
|-------------|--------------------------------------------------|
| `feat`      | Add new features                                 |
| `fix`       | Fix bugs                                         |
| `docs`      | Modify documents like README, CONTRIBUTE         |
| `style`     | Modify code format like space and comma without changing code logic |
| `refactor`  | Refactor code structure without adding new features or fixing new bugs |
| `perf`      | Improve performance or user experience                              |
| `test`      | Test features, including unit test and integration test |
| `chore`     | Change the build procedure or add dependencies   |
| `revert`    | Revert to the previous version                   |

💡Try to shrink the number of git commit messages to make it clear and concise. If you find you have already made too many commit messages, no worries, use git rebase and squash to merge multiple messages. Here is the [guide](https://www.freecodecamp.org/news/git-squash-commits/#:~:text=The%20first%20thing%20you%20need,to%20go%20back%206%20commits.&text=Now%2C%20you%20need%20to%20replace,apart%20from%20the%20first%20one).
### Create a Pull Request

1. Visit your forked AIOS repository on GitHub and click the "Compare & pull request" button to initiate the process of submitting your changes to the original repository for review and potential merging.
2. Choose the base branch and the compare branch (your feature branch).💡 Note that when you add new features, it is recommended to choose the (`dev`) branch and if your change does not affect original functions, you may consider choosing the (`main`) branch.
3. Write a title and describe your changes in the description. And it is recommended to select the label of the change to make it more clear.

## 4. Review and Approval
Our maintainers will have a review of that and might give some suggestions or ask for more details. After they approve, your commitment can be incorporated into OpenAGI!


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2024 AGI Research

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# OpenAGI: Package for AI Agent Creation
<a href='https://arxiv.org/abs/2304.04370'><img src='https://img.shields.io/badge/Paper-PDF-red'></a>
[![Code License](https://img.shields.io/badge/Code%20License-MIT-green.svg)](https://github.com/agiresearch/OpenAGI/blob/main/LICENSE)
<a href='https://discord.gg/B2HFxEgTJX'><img src='https://img.shields.io/badge/Community-Discord-8A2BE2'></a>


## ✈️ Getting Started
OpenAGI is used as the agent creation package to build agents for [AIOS](https://github.com/agiresearch/AIOS).
**Notice:** For building up agents in the AIOS, please migrate to the [Cerebrum](https://github.com/agiresearch/Cerebrum), which is our latest SDK to connect with AIOS kernel.

### Installation
From PyPI
```
pip install pyopenagi
```
Locally
```
git clone https://agiresearch/OpenAGI
cd OpenAGI
pip install -e .
```

### Usage

#### Add a new agent
To add a new agent, first you need to create a folder under the pyopenagi/agents folder.
The folder needs to be the following structure:
```
- pyopenagi/agents
  - author
    - agent_name
      - agent.py # main code for the agent execution logic
      - config.json # set up configurations for agent
      - meta_requirements.txt # dependencies that the agent needs
```
If you want to use external tools provided by openagi in your agents, you can follow instructions of setting up tools in [How to setup external tools](./tools.md).
If you want to add new tools for your developing agent,
you need to add a new tool file in the [folder](./pyopenagi/tools/).

#### Upload agent
If you have developed and tested your agent, and you would like to share your agents, you can use the following to upload your agents
```
python pyopenagi/agents/interact.py --mode upload --agent <author_name/agent_name>
```
💡Note that the `agent` param must exactly match the folder you put your agent locally.

#### Download agent
If you want to look at implementations of other agents that others have developed, you can use the following command:
```
python pyopenagi/agents/interact.py --mode download --agent <author_name/agent_name>
```

## 🚀 Contributions

For detailed information on how to contribute, see [CONTRIBUTE](./CONTRIBUTE.md). If you would like to contribute to the codebase, [issues](https://github.com/agiresearch/OpenAGI/issues) or [pull requests](https://github.com/agiresearch/OpenAGI/pulls) are always welcome!

## 🖋️ Research
Please check out our [implementation](https://github.com/agiresearch/OpenAGI/tree/research) for our research paper [OpenAGI: When LLM Meets Domain Experts](https://arxiv.org/abs/2304.04370).

```
@article{openagi,
  title={OpenAGI: When LLM Meets Domain Experts},
  author={Ge, Yingqiang and Hua, Wenyue and Mei, Kai and Ji, Jianchao and Tan, Juntao and Xu, Shuyuan and Li, Zelong and Zhang, Yongfeng},
  journal={In Advances in Neural Information Processing Systems (NeurIPS)},
  year={2023}
}
```

## 🌍 OpenAGI Contributors
[![OpenAGI contributors](https://contrib.rocks/image?repo=agiresearch/OpenAGI&max=300)](https://github.com/agiresearch/OpenAGI/graphs/contributors)



## 🌟 Star History

[![Star History Chart](https://api.star-history.com/svg?repos=agiresearch/OpenAGI&type=Date)](https://star-history.com/#agiresearch/OpenAGI&Date)


================================================
FILE: pyopenagi/README.md
================================================
# pyopenagi

The internal implementation for OpenAGI.

1. `agents/` contains the agent implementation all future agents have to follow.
2. `queues/` contains the class implementation for queues.
3. `utils/` contains some helpful internal utilities.
4. `tools/` contains the tools the agents can use.


================================================
FILE: pyopenagi/__init__.py
================================================


================================================
FILE: pyopenagi/agents/README.md
================================================
# pyopenagi/agents
This folder contains the base implementation for running the agents, as well as the handlers for running multiple agents in Threads in `agent_process.py` and `agent_factory.py`

In `example/` we have some example agents. You can add agents to that directory or to `your-cool-identifier/` to show your agent off in the main repo. However, it is recommended to use the agent database over submitting a pull request, unless it is for demo purposes.


================================================
FILE: pyopenagi/agents/__init__.py
================================================


================================================
FILE: pyopenagi/agents/agent_factory.py
================================================
from threading import Lock
from pympler import asizeof
from .interact import Interactor
import os
import importlib
import random
class AgentFactory:
    def __init__(self,
                #  agent_process_queue,
                 agent_process_factory,
                 agent_log_mode
        ):
        # self.max_aid = 256
        # self.llm = llm
        # self.aid_pool = [i for i in range(self.max_aid)]
        # heapq.heapify(self.aid_pool)
        # self.agent_process_queue = agent_process_queue
        self.agent_process_factory = agent_process_factory

        self.current_agents = {}

        self.current_agents_lock = Lock()

        # self.terminate_signal = Event()

        self.agent_log_mode = agent_log_mode

    def snake_to_camel(self, snake_str):
        components = snake_str.split('_')
        return ''.join(x.title() for x in components)

    def list_agents(self):
        agent_list = Interactor().list_available_agents()
        for agent in agent_list:
            print(agent)

    def load_agent_instance(self, agent_name):
        # dynamically loads the module from the path
        author, name = agent_name.split("/")
        module_name = ".".join(["pyopenagi", "agents", author, name, "agent"])
        class_name = self.snake_to_camel(name)

        agent_module = importlib.import_module(module_name)

        # dynamically loads the class
        agent_class = getattr(agent_module, class_name)
        
        return agent_class

    def activate_agent(self, agent_name, task_input):
        script_path = os.path.abspath(__file__)
        script_dir = os.path.dirname(script_path)

        # downloads the agent if its not installed already
        interactor = Interactor()

        if not os.path.exists(os.path.join(script_dir, agent_name)):
            interactor.download_agent(agent_name)

        if not interactor.check_reqs_installed(agent_name):
            interactor.install_agent_reqs(agent_name)

        # we instantiate the agent directly from the class
        agent_class = self.load_agent_instance(agent_name)

        agent = agent_class(
            agent_name = agent_name,
            task_input = task_input,
            agent_process_factory = self.agent_process_factory,
            log_mode = self.agent_log_mode
        )

        aid = random.randint(100000, 999999)
        # set the identifier for the agent
        # aid = heapq.heappop(self.aid_pool)
        agent.set_aid(aid)

        # use a lock to make sure only one agent can read the values at a time
        # if not self.terminate_signal.is_set():
        with self.current_agents_lock:
            self.current_agents[aid] = agent

        return agent

    def run_agent(self, agent_name, task_input):
        agent = self.activate_agent(
            agent_name=agent_name,
            task_input=task_input
        )
        # print(task_input)
        output = agent.run()
        self.deactivate_agent(agent.get_aid())
        return output

    def print_agent(self):
        headers = ["Agent ID", "Agent Name", "Created Time", "Status", "Memory Usage"]
        data = []
        for id, agent in self.current_agents.items():
            agent_name = agent.agent_name
            created_time = agent.created_time
            status = agent.status
            memory_usage = f"{asizeof.asizeof(agent)} bytes"
            data.append(
                [id, agent_name, created_time, status, memory_usage]
            )
        self.print(headers=headers, data=data)


    def print(self, headers, data):
        # align output
        column_widths = [
            max(len(str(row[i])) for row in [headers] + data) for i in range(len(headers))
        ]
        print("+" + "-" * (sum(column_widths) + len(headers) * 3 - 3 ) + "+")
        print(self.format_row(headers, column_widths))
        print("=" * (sum(column_widths) + len(headers) * 3 - 1))
        for i, row in enumerate(data):
            print(self.format_row(row, column_widths))
            if i < len(data):
                print("-" * (sum(column_widths) + len(headers) * 3 - 1))
        print("+" + "-" * (sum(column_widths) + len(headers) * 3 - 3 ) + "+")


    def format_row(self, row, widths, align="<"):
        row_str = " | ".join(f"{str(item):{align}{widths[i]}}" for i, item in enumerate(row))
        return row_str

    def deactivate_agent(self, aid):
        self.current_agents.pop(aid)
        # heapq.heappush(self.aid_pool, aid)


================================================
FILE: pyopenagi/agents/agent_process.py
================================================
from threading import Thread, Lock

from ..utils.chat_template import Query
import random
class AgentProcess:
    def __init__(self,
            agent_name: str,
            query: Query
        ):
        """Agent Process

        Args:
            agent_name (str): Name of the agent
            query (Query): Query sent by the agent
        """
        self.agent_name = agent_name
        self.query = query
        self.pid: int = None
        self.status = None
        self.response = None
        self.time_limit = None
        self.created_time = None
        self.start_time = None
        self.end_time = None

    def set_created_time(self, time):
        self.created_time = time

    def get_created_time(self):
        return self.created_time

    def set_start_time(self, time):
        self.start_time = time

    def get_start_time(self):
        return self.start_time

    def set_end_time(self, time):
        self.end_time = time

    def get_end_time(self):
        return self.end_time

    def set_priority(self, priority):
        self.priority = priority

    def get_priority(self):
        return self.priority

    def set_status(self, status):
        self.status = status

    def get_status(self):
        return self.status

    def set_pid(self, pid):
        self.pid = pid

    def get_pid(self):
        return self.pid

    def get_response(self):
        return self.response

    def set_response(self, response):
        self.response = response

    def get_time_limit(self):
        return self.time_limit

    def set_time_limit(self, time_limit):
        self.time_limit = time_limit


class LLMRequestProcess(AgentProcess):
    pass

class AgentProcessFactory:
    def __init__(self, agent_process_log_mode = None):
        # self.max_pid = 1024
        # self.pid_pool = [i for i in range(self.max_pid)]
        # heapq.heapify(self.pid_pool)

        self.thread = Thread(target=self.deactivate_agent_process)

        self.current_agent_processes = dict()

        self.current_agent_processes_lock = Lock()

        # self.terminate_signal = Event()

        self.agent_process_log_mode = agent_process_log_mode

    def activate_agent_process(self, agent_name, query):
        # if not self.terminate_signal.is_set():
        with self.current_agent_processes_lock:
            agent_process = AgentProcess(
                agent_name = agent_name,
                query = query
            )
            pid = random.randint(1000000, 9999999)
            # pid = heapq.heappop(self.pid_pool)
            agent_process.set_pid(pid)
            agent_process.set_status("active")
            self.current_agent_processes[pid] = agent_process
            return agent_process

    def print_agent_process(self):
        headers = ["Agent Process ID", "Agent Name", "Created Time", "Status"]
        data = []
        for id, agent_process in self.current_agent_processes.items():
            agent_name = agent_process.agent_name
            created_time = agent_process.created_time
            status = agent_process.status
            # memory_usage = f"{asizeof.asizeof(agent)} bytes"
            data.append(
                [id, agent_name, created_time, status]
            )
        self.print(headers=headers, data=data)


    def print(self, headers, data):
        # align output
        column_widths = [
            max(len(str(row[i])) for row in [headers] + data) for i in range(len(headers))
        ]
        print("+" + "-" * (sum(column_widths) + len(headers) * 3 - 3 ) + "+")
        print(self.format_row(headers, column_widths))
        print("=" * (sum(column_widths) + len(headers) * 3 - 1))
        for i, row in enumerate(data):
            print(self.format_row(row, column_widths))
            if i < len(data):
                print("-" * (sum(column_widths) + len(headers) * 3 - 1))
        print("+" + "-" * (sum(column_widths) + len(headers) * 3 - 3 ) + "+")


    def format_row(self, row, widths, align="<"):
        row_str = " | ".join(f"{str(item):{align}{widths[i]}}" for i, item in enumerate(row))
        return row_str

    def deactivate_agent_process(self, pid):
        self.current_agent_processes.pop(pid)
        # heapq.heappush(self.pid_pool, pid)

    def start(self):
        """start the factory to check inactive agent"""
        self.thread.start()

    def stop(self):
        self.thread.join()


================================================
FILE: pyopenagi/agents/base_agent.py
================================================
import os

import json

from .agent_process import (
    AgentProcess
)

import time

from threading import Thread

from ..utils.logger import AgentLogger

from ..utils.chat_template import Query

import importlib

from aios.hooks.stores._global import global_llm_req_queue_add_message

class CustomizedThread(Thread):
    def __init__(self, target, args=()):
        super().__init__()
        self.target = target
        self.args = args
        self.result = None

    def run(self):
        self.result = self.target(*self.args)

    def join(self):
        super().join()
        return self.result

class BaseAgent:
    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode: str
        ):

        self.agent_name = agent_name
        self.config = self.load_config()
        self.tool_names = self.config["tools"]

        self.agent_process_factory = agent_process_factory

        self.tool_list = dict()
        self.tools = []
        self.tool_info = [] # simplified information of the tool: {"name": "xxx", "description": "xxx"}

        self.load_tools(self.tool_names)

        self.start_time = None
        self.end_time = None
        self.request_waiting_times: list = []
        self.request_turnaround_times: list = []
        self.task_input = task_input
        self.messages = []
        self.workflow_mode = "manual" # (mannual, automatic)
        self.rounds = 0

        self.log_mode = log_mode
        self.logger = self.setup_logger()
        self.logger.log("Initialized. \n", level="info")

        self.set_status("active")
        self.set_created_time(time.time())


    def run(self):
        '''Execute each step to finish the task.'''
        pass

    # can be customization
    def build_system_instruction(self):
        pass

    def check_workflow(self, message):
        try:
            # print(f"Workflow message: {message}")
            workflow = json.loads(message)
            if not isinstance(workflow, list):
                return None

            for step in workflow:
                if "message" not in step or "tool_use" not in step:
                    return None

            return workflow

        except json.JSONDecodeError:
            return None

    def automatic_workflow(self):
        for i in range(self.plan_max_fail_times):
            response, start_times, end_times, waiting_times, turnaround_times = self.get_response(
                query = Query(
                    messages = self.messages,
                    tools = None,
                    message_return_type="json"
                )
            )

            if self.rounds == 0:
                self.set_start_time(start_times[0])

            self.request_waiting_times.extend(waiting_times)
            self.request_turnaround_times.extend(turnaround_times)

            workflow = self.check_workflow(response.response_message)

            self.rounds += 1

            if workflow:
                return workflow

            else:
                self.messages.append(
                    {
                        "role": "assistant",
                        "content": f"Fail {i+1} times to generate a valid plan. I need to regenerate a plan"
                    }
                )
        return None

    def manual_workflow(self):
        pass

    def check_path(self, tool_calls):
        script_path = os.path.abspath(__file__)
        save_dir = os.path.join(os.path.dirname(script_path), "output") # modify the customized output path for saving outputs
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)
        for tool_call in tool_calls:
            try:
                for k in tool_call["parameters"]:
                    if "path" in k:
                        path = tool_call["parameters"][k]
                        if not path.startswith(save_dir):
                            tool_call["parameters"][k] = os.path.join(save_dir, os.path.basename(path))
            except Exception:
                continue
        return tool_calls

    def snake_to_camel(self, snake_str):
        components = snake_str.split('_')
        return ''.join(x.title() for x in components)

    def load_tools(self, tool_names):

        for tool_name in tool_names:
            org, name = tool_name.split("/")
            module_name = ".".join(["pyopenagi", "tools", org, name])
            class_name = self.snake_to_camel(name)
            tool_module = importlib.import_module(module_name)
            tool_class = getattr(tool_module, class_name)
            self.tool_list[name] = tool_class()
            tool_format = tool_class().get_tool_call_format()
            self.tools.append(tool_format)
            self.tool_info.append(
                {"name": tool_format["function"]["name"], "description": tool_format["function"]["description"]}
            )

    def pre_select_tools(self, tool_names):
        pre_selected_tools = []
        for tool_name in tool_names:
            for tool in self.tools:
                if tool["function"]["name"] == tool_name:
                    pre_selected_tools.append(tool)
                    break

        return pre_selected_tools

    def setup_logger(self):
        logger = AgentLogger(self.agent_name, self.log_mode)
        return logger

    def load_config(self):
        script_path = os.path.abspath(__file__)
        script_dir = os.path.dirname(script_path)
        config_file = os.path.join(script_dir, self.agent_name, "config.json")
        with open(config_file, "r") as f:
            config = json.load(f)
            return config

    # the default method used for getting response from AIOS
    def get_response(self,
            query,
            temperature=0.0
        ):

        thread = CustomizedThread(target=self.query_loop, args=(query, ))
        thread.start()
        return thread.join()

    def query_loop(self, query):
        agent_process = self.create_agent_request(query)

        completed_response, start_times, end_times, waiting_times, turnaround_times = "", [], [], [], []

        while agent_process.get_status() != "done":
            thread = Thread(target=self.listen, args=(agent_process, ))
            current_time = time.time()
            # reinitialize agent status
            agent_process.set_created_time(current_time)
            agent_process.set_response(None)

            global_llm_req_queue_add_message(agent_process)

            # LLMRequestQueue.add_message(agent_process)

            thread.start()
            thread.join()

            completed_response = agent_process.get_response()
            if agent_process.get_status() != "done":
                self.logger.log(
                    f"Suspended due to the reach of time limit ({agent_process.get_time_limit()}s). Current result is: {completed_response.response_message}\n",
                    level="suspending"
                )
            start_time = agent_process.get_start_time()
            end_time = agent_process.get_end_time()
            waiting_time = start_time - agent_process.get_created_time()
            turnaround_time = end_time - agent_process.get_created_time()

            start_times.append(start_time)
            end_times.append(end_time)
            waiting_times.append(waiting_time)
            turnaround_times.append(turnaround_time)
            # Re-start the thread if not done

        # self.agent_process_factory.deactivate_agent_process(agent_process.get_pid())

        return completed_response, start_times, end_times, waiting_times, turnaround_times

    def create_agent_request(self, query):
        agent_process = self.agent_process_factory.activate_agent_process(
            agent_name = self.agent_name,
            query = query
        )
        agent_process.set_created_time(time.time())
        # print("Already put into the queue")
        return agent_process

    def listen(self, agent_process: AgentProcess):
        """Response Listener for agent

        Args:
            agent_process (AgentProcess): Listened AgentProcess

        Returns:
            str: LLM response of Agent Process
        """
        while agent_process.get_response() is None:
            time.sleep(0.2)

        return agent_process.get_response()

    def set_aid(self, aid):
        self.aid = aid

    def get_aid(self):
        return self.aid

    def get_agent_name(self):
        return self.agent_name

    def set_status(self, status):

        """
        Status type: Waiting, Running, Done, Inactive
        """
        self.status = status

    def get_status(self):
        return self.status

    def set_created_time(self, time):
        self.created_time = time

    def get_created_time(self):
        return self.created_time

    def set_start_time(self, time):
        self.start_time = time

    def get_start_time(self):
        return self.start_time

    def set_end_time(self, time):
        self.end_time = time

    def get_end_time(self):
        return self.end_time


================================================
FILE: pyopenagi/agents/call_core.py
================================================
import time
from threading import Thread

from aios.hooks.stores._global import global_llm_req_queue_add_message
from .agent_process import AgentProcess
from ..utils.logger import AgentLogger


class CustomizedThread(Thread):
    def __init__(self, target, args=()):
        super().__init__()
        self.target = target
        self.args = args
        self.result = None

    def run(self):
        self.result = self.target(*self.args)

    def join(self):
        super().join()
        return self.result


class CallCore:
    """
    Simplify BaseAgent to provide an interface for external frameworks to make LLM requests using aios.
    """
    def __init__(self,
                 agent_name,
                 agent_process_factory,
                 log_mode: str = "console"
                 ):
        self.agent_name = agent_name
        self.agent_process_factory = agent_process_factory
        self.log_mode = log_mode
        self.logger = self.setup_logger()

    # the default method used for getting response from AIOS
    def get_response(self,
                     query,
                     temperature=0.0
                     ):

        thread = CustomizedThread(target=self.query_loop, args=(query,))
        thread.start()
        return thread.join()

    def query_loop(self, query):
        agent_process = self.create_agent_request(query)

        completed_response, start_times, end_times, waiting_times, turnaround_times = "", [], [], [], []

        while agent_process.get_status() != "done":
            thread = Thread(target=self.listen, args=(agent_process,))
            current_time = time.time()
            # reinitialize agent status
            agent_process.set_created_time(current_time)
            agent_process.set_response(None)

            global_llm_req_queue_add_message(agent_process)

            # LLMRequestQueue.add_message(agent_process)

            thread.start()
            thread.join()

            completed_response = agent_process.get_response()
            if agent_process.get_status() != "done":
                self.logger.log(
                    f"Suspended due to the reach of time limit ({agent_process.get_time_limit()}s). Current result is: {completed_response.response_message}\n",
                    level="suspending"
                )
            start_time = agent_process.get_start_time()
            end_time = agent_process.get_end_time()
            waiting_time = start_time - agent_process.get_created_time()
            turnaround_time = end_time - agent_process.get_created_time()

            start_times.append(start_time)
            end_times.append(end_time)
            waiting_times.append(waiting_time)
            turnaround_times.append(turnaround_time)
            # Re-start the thread if not done

        # self.agent_process_factory.deactivate_agent_process(agent_process.get_pid())

        return completed_response, start_times, end_times, waiting_times, turnaround_times

    def create_agent_request(self, query):
        agent_process = self.agent_process_factory.activate_agent_process(
            agent_name=self.agent_name,
            query=query
        )
        agent_process.set_created_time(time.time())
        # print("Already put into the queue")
        return agent_process

    def listen(self, agent_process: AgentProcess):
        """Response Listener for agent

        Args:
            agent_process (AgentProcess): Listened AgentProcess

        Returns:
            str: LLM response of Agent Process
        """
        while agent_process.get_response() is None:
            time.sleep(0.2)

        return agent_process.get_response()

    def setup_logger(self):
        logger = AgentLogger(self.agent_name, self.log_mode)
        return logger


================================================
FILE: pyopenagi/agents/example/README.md
================================================
# pyopenagi/agents/example

Here are the example agents we created to demo agent creation in OpenAGI.


================================================
FILE: pyopenagi/agents/example/academic_agent/agent.py
================================================
from ...react_agent import ReactAgent
import os


class AcademicAgent(ReactAgent):
    def __init__(self, agent_name, task_input, agent_process_factory, log_mode: str):
        ReactAgent.__init__(
            self, agent_name, task_input, agent_process_factory, log_mode
        )
        # self.workflow_mode = "manual"
        self.workflow_mode = "automatic"

    def check_path(self, tool_calls):
        script_path = os.path.abspath(__file__)
        save_dir = os.path.join(
            os.path.dirname(script_path), "output"
        )  # modify the customized output path for saving outputs
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)
        for tool_call in tool_calls:
            try:
                for k in tool_call["parameters"]:
                    if "path" in k:
                        path = tool_call["parameters"][k]
                        if not path.startswith(save_dir):
                            tool_call["parameters"][k] = os.path.join(
                                save_dir, os.path.basename(path)
                            )
            except Exception:
                continue
        return tool_calls

    def manual_workflow(self):
        workflow = [
            {"message": "Gather research topic and keywords", "tool_use": []},
            {"message": "Search for relevant papers on arXiv", "tool_use": ["arxiv"]},
            {"message": "Summarize key findings of selected papers", "tool_use": []},
            {
                "message": "Identify research gaps and generate potential research questions",
                "tool_use": [],
            },
        ]
        return workflow

    def run(self):
        return super().run()


================================================
FILE: pyopenagi/agents/example/academic_agent/config.json
================================================
{
    "name": "academic_agent",
    "description": [
        "You are an academic research assistant. ",
        "Help users find relevant research papers, summarize key findings, and generate potential research questions."
    ],
    "tools": [
        "arxiv/arxiv"
    ],
    "meta": {
        "author": "example",
        "version": "0.0.1",
        "license": "CC0"
    },
    "build": {
        "entry": "agent.py",
        "module": "AcademicAgent"
    }
}

================================================
FILE: pyopenagi/agents/example/academic_agent/meta_requirements.txt
================================================
arxiv

================================================
FILE: pyopenagi/agents/example/cocktail_mixlogist/agent.py
================================================
from ...react_agent import ReactAgent
import os
class CocktailMixlogist(ReactAgent):
    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode: str
        ):
        ReactAgent.__init__(self, agent_name, task_input, agent_process_factory, log_mode)
        self.workflow_mode = "automatic"
        # self.workflow_mode = "manual"

    def check_path(self, tool_calls):
        script_path = os.path.abspath(__file__)
        save_dir = os.path.join(os.path.dirname(script_path), "output") # modify the customized output path for saving outputs
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)
        for tool_call in tool_calls:
            try:
                for k in tool_call["parameters"]:
                    if "path" in k:
                        path = tool_call["parameters"][k]
                        if not path.startswith(save_dir):
                            tool_call["parameters"][k] = os.path.join(save_dir, os.path.basename(path))
            except Exception:
                continue
        return tool_calls

    def manual_workflow(self):
        workflow = [
            {
                "message": "Gather user preferences (alcoholic or non-alcoholic, taste profile, occasion)",
                "tool_use": []
            },
            {
                "message": "Identify available ingredients and potential substitutions",
                "tool_use": []
            },
            {
                "message": "Create cocktail or mocktail recipes",
                "tool_use": []
            }
        ]
        return workflow

    def run(self):
        return super().run()


================================================
FILE: pyopenagi/agents/example/cocktail_mixlogist/config.json
================================================
{
    "name": "cocktail_mixlogist",
    "description": [
        "You are a virtual mixologist. ",
        "Create delicious cocktails and mocktails based on user preferences, available ingredients, and dietary restrictions."
    ],
    "tools": [
        "wikipedia/wikipedia"
    ],
    "meta": {
        "author": "example",
        "version": "0.0.1",
        "license": "CC0"
    }
}


================================================
FILE: pyopenagi/agents/example/cocktail_mixlogist/meta_requirements.txt
================================================


================================================
FILE: pyopenagi/agents/example/cook_therapist/agent.py
================================================
from ...react_agent import ReactAgent
import os
class CookTherapist(ReactAgent):
    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode: str
        ):
        ReactAgent.__init__(self, agent_name, task_input, agent_process_factory, log_mode)
        # self.workflow_mode = "automatic"
        self.workflow_mode = "manual"

    def check_path(self, tool_calls):
        script_path = os.path.abspath(__file__)
        save_dir = os.path.join(os.path.dirname(script_path), "output") # modify the customized output path for saving outputs
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)
        for tool_call in tool_calls:
            try:
                for k in tool_call["parameters"]:
                    if "path" in k:
                        path = tool_call["parameters"][k]
                        if not path.startswith(save_dir):
                            tool_call["parameters"][k] = os.path.join(save_dir, os.path.basename(path))
            except Exception:
                continue
        return tool_calls

    def manual_workflow(self):
        workflow = [
            {
                "message": "Gather user input on desired ingredients, dietary restrictions, or cuisine type.",
                "tool_use": []
            },
            {
                "message": "Create a detailed recipe, including ingredients, measurements, and step-by-step instructions.",
                "tool_use": []
            },
            {
                "message": "Generate an image of the final dish.",
                "tool_use": ["text_to_image"]
            },
            {
                "message": "Present the recipe, including image, instructions, and nutritional information.",
                "tool_use": []
            }
        ]
        return workflow

    def run(self):
        return super().run()


================================================
FILE: pyopenagi/agents/example/cook_therapist/config.json
================================================
{
    "name": "cook_therapist",
    "description": [
        "You are a culinary expert and recipe creator. ",
        "Your role is to generate unique and delicious recipes tailored to the user's tastes and dietary needs. "
    ],
    "tools": [
        "stability-ai/text_to_image"
    ],
    "meta": {
        "author": "example",
        "version": "0.0.1",
        "license": "CC0"
    }
}


================================================
FILE: pyopenagi/agents/example/cook_therapist/meta_requirements.txt
================================================


================================================
FILE: pyopenagi/agents/example/creation_agent/agent.py
================================================
from ...react_agent import ReactAgent
import os
class CreationAgent(ReactAgent):
    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode: str
        ):
        ReactAgent.__init__(self, agent_name, task_input, agent_process_factory, log_mode)
        # self.workflow_mode = "automatic"
        self.workflow_mode = "manual"

    def check_path(self, tool_calls):
        script_path = os.path.abspath(__file__)
        save_dir = os.path.join(os.path.dirname(script_path), "output") # modify the customized output path for saving outputs
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)
        for tool_call in tool_calls:
            try:
                for k in tool_call["parameters"]:
                    if "path" in k:
                        path = tool_call["parameters"][k]
                        if not path.startswith(save_dir):
                            tool_call["parameters"][k] = os.path.join(save_dir, os.path.basename(path))
            except Exception:
                continue
        return tool_calls

    def manual_workflow(self):
        workflow = [
            {
                "message": "Gather content requirements (platform, topic, style)",
                "tool_use": []
            },
            {
                "message": "Develop content concept and key messages",
                "tool_use": []
            },
            {
                "message": "Generate engaging text content",
                "tool_use": []
            },
            {
                "message": "Create visually appealing images",
                "tool_use": ["text_to_image"]
            },
            {
                "message": "Summarize content and post",
                "tool_use": []
            }
        ]
        return workflow

    def run(self):
        return super().run()


================================================
FILE: pyopenagi/agents/example/creation_agent/config.json
================================================
{
    "name": "creation_agent",
    "description": [
        "You are a social media content creator. ",
        "Generate compelling text and visually appealing images"
    ],
    "tools": [
        "stability-ai/text_to_image"
    ],
    "meta": {
        "author": "example",
        "version": "0.0.1",
        "license": "CC0"
    }
}


================================================
FILE: pyopenagi/agents/example/creation_agent/meta_requirements.txt
================================================
diffusers==0.27.2
accelerate==0.30.1


================================================
FILE: pyopenagi/agents/example/fashion_stylist/agent.py
================================================
from ...react_agent import ReactAgent
import os
class FashionStylist(ReactAgent):
    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode: str
        ):
        ReactAgent.__init__(self, agent_name, task_input, agent_process_factory, log_mode)
        # self.workflow_mode = "automatic"
        self.workflow_mode = "manual"

    def check_path(self, tool_calls):
        script_path = os.path.abspath(__file__)
        save_dir = os.path.join(os.path.dirname(script_path), "output") # modify the customized output path for saving outputs
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)
        for tool_call in tool_calls:
            try:
                for k in tool_call["parameters"]:
                    if "path" in k:
                        path = tool_call["parameters"][k]
                        if not path.startswith(save_dir):
                            tool_call["parameters"][k] = os.path.join(save_dir, os.path.basename(path))
            except Exception:
                continue
        return tool_calls

    def manual_workflow(self):
        workflow = [
            {
                "message": "Gather user preferences, body type, and occasion details.",
                "tool_use": []
            },
            {
                "message": "Generate outfit ideas based on user input.",
                "tool_use": []
            },
            {
                "message": "Create visual representations of outfit ideas.",
                "tool_use": ["text_to_image"]
            },
            {
                "message": "Analyze generated images for style coherence and alignment with user preferences.",
                "tool_use": ["doc_question_answering"]
            },
            {
                "message": "Search for similar items online based on the generated outfit ideas.",
                "tool_use": ["google_search"]
            },
            {
                "message": "Summarize content.",
                "tool_use": []
            }
        ]
        return workflow

    def run(self):
        return super().run()


================================================
FILE: pyopenagi/agents/example/fashion_stylist/config.json
================================================
{
    "name": "fashion_stylist",
    "description": [
        "You are a fashion designer. ",
        "Create custom clothing and accessory designs based on user preferences and body measurements. "
    ],
    "tools": [
        "google/google_search",
        "stability-ai/text_to_image",
        "impira/doc_question_answering"
    ],
    "meta": {
        "author": "example",
        "version": "0.0.1",
        "license": "CC0"
    }
}


================================================
FILE: pyopenagi/agents/example/fashion_stylist/meta_requirements.txt
================================================
soundfile
wikipedia


================================================
FILE: pyopenagi/agents/example/festival_card_designer/agent.py
================================================
from ...react_agent import ReactAgent
import os
class FestivalCardDesigner(ReactAgent):
    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode: str
        ):
        ReactAgent.__init__(self, agent_name, task_input, agent_process_factory, log_mode)
        self.workflow_mode = "manual"

    def automatic_workflow(self):
        return super().automatic_workflow()

    def check_path(self, tool_calls):
        script_path = os.path.abspath(__file__)
        save_dir = os.path.join(os.path.dirname(script_path), "output") # modify the customized output path for saving outputs
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)
        for tool_call in tool_calls:
            try:
                for k in tool_call["parameters"]:
                    if "path" in k:
                        path = tool_call["parameters"][k]
                        if not path.startswith(save_dir):
                            tool_call["parameters"][k] = os.path.join(save_dir, os.path.basename(path))
            except Exception:
                continue
        return tool_calls

    def manual_workflow(self):
        workflow = [
            {
                "message": "Gather user information (festival theme, target audience, card size)",
                "tool_use": []
            },
            {
                "message": "Identify card design elements (colors, fonts, imagery)",
                "tool_use": []
            },
            {
                "message": "Generate card layout options",
                "tool_use": ["text_to_image"]
            },
            {
                "message": "Add textual elements to the festival card ",
                "tool_use": []
            }
        ]
        return workflow

    def run(self):
        return super().run()


================================================
FILE: pyopenagi/agents/example/festival_card_designer/config.json
================================================
{
    "name": "festival_card_designer",
    "description": [
        "You are a festival card designer. ",
        "Create unique and eye-catching festival cards based on user preferences and festival themes."
    ],
    "tools": [
        "stability-ai/text_to_image"
    ],
    "meta": {
        "author": "example",
        "version": "0.0.1",
        "license": "CC0"
    }
}


================================================
FILE: pyopenagi/agents/example/festival_card_designer/meta_requirements.txt
================================================


================================================
FILE: pyopenagi/agents/example/fitness_trainer/agent.py
================================================
from ...react_agent import ReactAgent
import os
class FitnessTrainer(ReactAgent):
    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode: str
        ):
        ReactAgent.__init__(self, agent_name, task_input, agent_process_factory, log_mode)
        self.workflow_mode = "manual"

    def automatic_workflow(self):
        return super().automatic_workflow()

    def check_path(self, tool_calls):
        script_path = os.path.abspath(__file__)
        save_dir = os.path.join(os.path.dirname(script_path), "output") # modify the customized output path for saving outputs
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)
        for tool_call in tool_calls:
            try:
                for k in tool_call["parameters"]:
                    if "path" in k:
                        path = tool_call["parameters"][k]
                        if not path.startswith(save_dir):
                            tool_call["parameters"][k] = os.path.join(save_dir, os.path.basename(path))
            except Exception:
                continue
        return tool_calls

    def manual_workflow(self):
        workflow = [
            {
                "message": "Gather information about the user's fitness level, goals, and any physical limitations.",
                "tool_use": []
            },
            {
                "message": "Create a detailed workout plan with exercise descriptions.",
                "tool_use": []
            },
            {
                "message": "Generate images demonstrating key exercises in the workout plan.",
                "tool_use": ["text_to_image"]
            },
            {
                "message": "Create audio instructions for each exercise to guide the user.",
                "tool_use": ["text_to_speech"]
            },
            {
                "message": "Compile the workout plan, images, and audio into a comprehensive fitness guide.",
                "tool_use": []
            }
        ]
        return workflow

    def run(self):
        return super().run()


================================================
FILE: pyopenagi/agents/example/fitness_trainer/config.json
================================================
{
    "name": "fitness_trainer",
    "description": [
        "You are a fitness trainer with expertise in various exercise techniques, nutrition, and personalized fitness planning. ",
        "Your role is to create tailored workout plans and provide clear instructions for exercises."
    ],
    "tools": [
        "stability-ai/text_to_image",
        "suno/text_to_speech"
    ],
    "meta": {
        "author": "example",
        "version": "0.0.1",
        "license": "CC0"
    }
}


================================================
FILE: pyopenagi/agents/example/fitness_trainer/meta_requirements.txt
================================================
arxiv
wikipedia


================================================
FILE: pyopenagi/agents/example/game_agent/agent.py
================================================
from ...react_agent import ReactAgent

class GameAgent(ReactAgent):
    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode: str
        ):
        ReactAgent.__init__(self, agent_name, task_input, agent_process_factory, log_mode)
        self.workflow_mode = "manual"

    def automatic_workflow(self):
        return super().automatic_workflow()

    def manual_workflow(self):
        workflow = [
            {
                "message": "Gather user preferences (genre, platform, play style)",
                "tool_use": []
            },
            {
                "message": "Search for suitable games based on criteria",
                "tool_use": ["google_search"]
            },
            {
                "message": "Provide game descriptions, ratings, and gameplay details",
                "tool_use": []
            }
        ]
        return workflow

    def run(self):
        return super().run()


================================================
FILE: pyopenagi/agents/example/game_agent/config.json
================================================
{
    "name": "game_agent",
    "description": [
        "You are a video game expert. ",
        "Recommend games based on user preferences, mood, and available platforms. Provide detailed game descriptions and gameplay information."
    ],
    "tools": [
        "google/google_search"
    ],
    "meta": {
        "author": "example",
        "version": "0.0.1",
        "license": "CC0"
    }
}


================================================
FILE: pyopenagi/agents/example/game_agent/meta_requirements.txt
================================================
arxiv
wikipedia


================================================
FILE: pyopenagi/agents/example/interior_decorator/agent.py
================================================
from ...react_agent import ReactAgent
import os
class InteriorDecorator(ReactAgent):
    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode: str
        ):
        ReactAgent.__init__(self, agent_name, task_input, agent_process_factory, log_mode)
        # self.workflow_mode = "automatic"
        self.workflow_mode = "manual"

    def check_path(self, tool_calls):
        script_path = os.path.abspath(__file__)
        save_dir = os.path.join(os.path.dirname(script_path), "output") # modify the customized output path for saving outputs
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)
        for tool_call in tool_calls:
            try:
                for k in tool_call["parameters"]:
                    if "path" in k:
                        path = tool_call["parameters"][k]
                        if not path.startswith(save_dir):
                            tool_call["parameters"][k] = os.path.join(save_dir, os.path.basename(path))
            except Exception:
                continue
        return tool_calls

    def manual_workflow(self):
        workflow = [
            {
                "message": "Gather user preferences, room dimensions, and desired style.",
                "tool_use": []
            },
            {
                "message": "Generate mood board images based on user input using text_to_image.",
                "tool_use": ["text_to_image"]
            },
            {
                "message": "Analyze generated images for color schemes, furniture styles, and overall ambiance.",
                "tool_use": []
            },
            {
                "message": "Recommend specific furniture, decor items, and color palettes based on analysis.",
                "tool_use": []
            }
        ]

        return workflow

    def run(self):
        return super().run()


================================================
FILE: pyopenagi/agents/example/interior_decorator/config.json
================================================
{
    "name": "interior_decorator",
    "description": [
        "You are a virtual interior decorator. ",
        "You should be able to provide design recommendations based on user preferences, room size, and style. You can generate mood boards, suggest furniture and decor, and offer color palette ideas. "
    ],
    "tools": [
        "stability-ai/text_to_image"
    ],
    "meta": {
        "author": "example",
        "version": "0.0.1",
        "license": "CC0"
    }
}


================================================
FILE: pyopenagi/agents/example/interior_decorator/meta_requirements.txt
================================================
diffusers==0.27.2
accelerate==0.30.1


================================================
FILE: pyopenagi/agents/example/language_tutor/agent.py
================================================
from ...react_agent import ReactAgent
import os
class LanguageTutor(ReactAgent):
    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode: str
        ):
        ReactAgent.__init__(self, agent_name, task_input, agent_process_factory, log_mode)
        # self.workflow_mode = "automatic"
        self.workflow_mode = "manual"

    def check_path(self, tool_calls):
        script_path = os.path.abspath(__file__)
        save_dir = os.path.join(os.path.dirname(script_path), "output") # modify the customized output path for saving outputs
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)
        for tool_call in tool_calls:
            try:
                for k in tool_call["parameters"]:
                    if "path" in k:
                        path = tool_call["parameters"][k]
                        if not path.startswith(save_dir):
                            tool_call["parameters"][k] = os.path.join(save_dir, os.path.basename(path))
            except Exception:
                continue
        return tool_calls

    def manual_workflow(self):
        workflow = [
            {
                "message": "Identify user's target language and learning goals.",
                "tool_use": []
            },
            {
                "message": "Generate vocabulary lists and exercises.",
                "tool_use": ["google_search"]
            },
            {
                "message": "Create grammar explanations and practice sentences.",
                "tool_use": []
            },
            {
                "message": "Provide audio examples of pronunciation.",
                "tool_use": ["text_to_speech"]
            },
            {
                "message": "Engage in conversation practice with the user.",
                "tool_use": []
            }
        ]
        return workflow

    def run(self):
        return super().run()


================================================
FILE: pyopenagi/agents/example/language_tutor/config.json
================================================
{
    "name": "language_tutor",
    "description": [
        "You are a language tutor. You can provide vocabulary exercises, grammar explanations, and conversation practice. ",
        "You can also offer pronunciation guidance and cultural insights. "
    ],
    "tools": [
        "google/google_search",
        "suno/text_to_speech"
    ],
    "meta": {
        "author": "example",
        "version": "0.0.1",
        "license": "CC0"
    }
}


================================================
FILE: pyopenagi/agents/example/language_tutor/meta_requirements.txt
================================================
soundfile
wikipedia


================================================
FILE: pyopenagi/agents/example/logo_creator/agent.py
================================================
from ...react_agent import ReactAgent
import os
class LogoCreator(ReactAgent):
    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode: str
        ):
        ReactAgent.__init__(self, agent_name, task_input, agent_process_factory, log_mode)
        self.workflow_mode = "manual"

    def check_path(self, tool_calls):
        script_path = os.path.abspath(__file__)
        save_dir = os.path.join(os.path.dirname(script_path), "output") # modify the customized output path for saving outputs
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)
        for tool_call in tool_calls:
            try:
                for k in tool_call["parameters"]:
                    if "path" in k:
                        path = tool_call["parameters"][k]
                        if not path.startswith(save_dir):
                            tool_call["parameters"][k] = os.path.join(save_dir, os.path.basename(path))
            except Exception:
                continue
        return tool_calls

    def automatic_workflow(self):
        return super().automatic_workflow()

    def manual_workflow(self):
        workflow = [
            {
                "message": "Gather business information (name, industry, target audience)",
                "tool_use": []
            },
            {
                "message": "Identify brand personality and values",
                "tool_use": []
            },
            {
                "message": "Generate logo concepts and variations",
                "tool_use": ["text_to_image"]
            }
        ]
        return workflow

    def run(self):
        return super().run()


================================================
FILE: pyopenagi/agents/example/logo_creator/config.json
================================================
{
    "name": "logo_creator",
    "description": [
        "You are a logo design expert. ",
        "Create unique and professional logo designs based on user-provided business information and preferences."
    ],
    "tools": [
        "stability-ai/text_to_image"
    ],
    "meta": {
        "author": "example",
        "version": "0.0.1",
        "license": "CC0"
    }
}


================================================
FILE: pyopenagi/agents/example/logo_creator/meta_requirements.txt
================================================


================================================
FILE: pyopenagi/agents/example/math_agent/agent.py
================================================
from ...react_agent import ReactAgent

class MathAgent(ReactAgent):
    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode: str
        ):
        ReactAgent.__init__(self, agent_name, task_input, agent_process_factory, log_mode)

    def automatic_workflow(self):
        return super().automatic_workflow()

    def manual_workflow(self):
        # TODO: add pemdas calculation support in the future
        workflow = [
            {
                "message": "Identify the problem type and relevant formulas",
                "tool_use": ["wikipedia"]
            },
            {
                "message": "Break down the problem into steps",
                "tool_use": []
            },
            {
                "message": "Provide final answer/solution",
                "tool_use": []
            }
        ]
        return workflow

    def run(self):
        return super().run()


================================================
FILE: pyopenagi/agents/example/math_agent/config.json
================================================
{
    "name": "MathAgent",
    "description": [
        "You are an expert who is good at solving mathematical problems. "
    ],
    "workflow": [
        "identify the tool to call to do some pre-calculation. ",
        "perform mathematical operations using the pre-calculated result, which could involve addition, subtraction, multiplication, or division with other numeric values to solve the problem."
    ],
    "tools": ["wikipedia/wikipedia"],
    "meta": {
        "author": "example",
        "version": "0.0.1",
        "license": "CC0"
    }
}


================================================
FILE: pyopenagi/agents/example/math_agent/meta_requirements.txt
================================================
wolframalpha
wikipedia

================================================
FILE: pyopenagi/agents/example/meme_creator/agent.py
================================================
from ...react_agent import ReactAgent
import os
class MemeCreator(ReactAgent):
    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode: str
        ):
        ReactAgent.__init__(self, agent_name, task_input, agent_process_factory, log_mode)
        self.workflow_mode = "manual"

    def automatic_workflow(self):
        return super().automatic_workflow()

    def check_path(self, tool_calls):
        script_path = os.path.abspath(__file__)
        save_dir = os.path.join(os.path.dirname(script_path), "output") # modify the customized output path for saving outputs
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)
        for tool_call in tool_calls:
            try:
                for k in tool_call["parameters"]:
                    if "path" in k:
                        path = tool_call["parameters"][k]
                        if not path.startswith(save_dir):
                            tool_call["parameters"][k] = os.path.join(save_dir, os.path.basename(path))
            except Exception:
                continue
        return tool_calls

    def manual_workflow(self):
        workflow = [
            {
                "message": "Gather user input (topic, text, image)",
                "tool_use": []
            },
            {
                "message": "Select a suitable meme template or create a custom image",
                "tool_use": ["text_to_image"]
            },
            {
                "message": "Add text to the image based on user input",
                "tool_use": []
            }
        ]
        return workflow

    def run(self):
        return super().run()


================================================
FILE: pyopenagi/agents/example/meme_creator/config.json
================================================
{
    "name": "meme_creator",
    "description": [
        "You are a meme creator. Given a topic, text, or an image, create a funny and relevant meme."
    ],
    "tools": [
        "stability-ai/text_to_image"
    ],
    "meta": {
        "author": "example",
        "version": "0.0.1",
        "license": "CC0"
    }
}


================================================
FILE: pyopenagi/agents/example/meme_creator/meta_requirements.txt
================================================
arxiv
wikipedia


================================================
FILE: pyopenagi/agents/example/music_composer/agent.py
================================================
from ...react_agent import ReactAgent

class MusicComposer(ReactAgent):
    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode: str
        ):
        ReactAgent.__init__(self, agent_name, task_input, agent_process_factory, log_mode)
        # self.workflow_mode = "automatic"
        self.workflow_mode = "manual"

    def manual_workflow(self):
        workflow = [
            {
                "message": "Gather user information about desired music genre, mood, and tempo.",
                "tool_use": []
            },
            {
                "message": "Generate basic melody, chord progression, or rhythm structure.",
                "tool_use": []
            },
            {
                "message": "Provide suggestions for musical development and experimentation.",
                "tool_use": []
            },
            {
                "message": "Convert musical elements into audio.",
                "tool_use": ["text_to_speech"]
            },
            {
                "message": "Offer feedback on composition and suggest improvements.",
                "tool_use": []
            }
        ]
        return workflow

    def run(self):
        return super().run()


================================================
FILE: pyopenagi/agents/example/music_composer/config.json
================================================
{
    "name": "music_composer",
    "description": [
        "You are an excellent music composer. ",
        "Your role is to produce music based on the user's needs. "
    ],
    "tools": [
        "suno/text_to_speech"
    ],
    "meta": {
        "author": "example",
        "version": "0.0.1",
        "license": "CC0"
    }
}


================================================
FILE: pyopenagi/agents/example/music_composer/meta_requirements.txt
================================================
wikipedia


================================================
FILE: pyopenagi/agents/example/plant_care_assistant/agent.py
================================================
from ...react_agent import ReactAgent

class PlantCareAssistant(ReactAgent):
    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode: str
        ):
        ReactAgent.__init__(self, agent_name, task_input, agent_process_factory, log_mode)
        self.workflow_mode = "manual"

    def automatic_workflow(self):
        return super().automatic_workflow()

    def manual_workflow(self):
        workflow = [
            {
                "message": "Gather plant information (type, age, environment)",
                "tool_use": []
            },
            {
                "message": "Identify plant needs (light, water, fertilizer)",
                "tool_use": ["wikipedia"]
            },
            {
                "message": "Create a plant care schedule",
                "tool_use": []
            },
            {
                "message": "Provide troubleshooting advice for plant issues",
                "tool_use": []
            }
        ]
        return workflow

    def run(self):
        return super().run()


================================================
FILE: pyopenagi/agents/example/plant_care_assistant/config.json
================================================
{
    "name": "plant_care_assistant",
    "description": [
        "You are a virtual plant expert. ",
        "Provide care instructions, identify plant problems, and offer reminders for plant care tasks."
    ],
    "tools": [
        "wikipedia/wikipedia"
    ],
    "meta": {
        "author": "example",
        "version": "0.0.1",
        "license": "CC0"
    }
}


================================================
FILE: pyopenagi/agents/example/plant_care_assistant/meta_requirements.txt
================================================
arxiv
wikipedia


================================================
FILE: pyopenagi/agents/example/rag_agent/README.md
================================================
# src/agents/agent_config

Each agent holds a config file in addition to the class specifying what to run. The agent config is a JSON file.

Each JSON file contains the following:

1. `name` : name of the agent
2. `description` : an array with one element containing the system prompt
3. `workflow` : an array with plaintext describing what the agent will do at each iteration. this is fed into the LLM running the agent
4. `tools` : an array with complex json objects
- `type` : type of tool, typically "function"
- `function` : if the type of function it contains data in the specific functions.

For more detailed information, cite each specific agent as an example and fit it for your purposes.


================================================
FILE: pyopenagi/agents/example/rag_agent/agent.py
================================================
from ...base_agent import BaseAgent

import time

import argparse

from ....utils import Message

from pathlib import PurePosixPath
import os
import chromadb
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.core import StorageContext
from llama_index.core import PromptTemplate
from llama_index.core.retrievers import VectorIndexRetriever
from llama_index.vector_stores.chroma import ChromaVectorStore

from openagi.src.agents.base import BaseAgent

class RAGAgent(BaseAgent):
    def __init__(self,
                 agent_name,
                 task_input,
                 llm,
                 agent_process_queue,
                 agent_process_factory,
                 log_mode: str
        ):
        BaseAgent.__init__(self, agent_name, task_input, llm, agent_process_queue, agent_process_factory, log_mode)

    def run(self):
        request_waiting_times = []
        request_turnaround_times = []
        query = self.task_input

        self.logger.log(f"{query}\n", level="info")

        context = self.retrive(query)
        prompt = self.build_prompt(context_str=context, query_str=query)

        rounds = 0

        response, start_times, end_times, waiting_times, turnaround_times = self.get_response(
            message = Message(
                prompt = prompt,
                tools = None
            )
        )

        self.set_start_time(start_times[0])
        rounds += 1

        request_waiting_times.extend(waiting_times)
        request_turnaround_times.extend(turnaround_times)

        response_message = response.response_message

        self.logger.log(f"Final result is: {response.response_message}\n", level="info")
        final_result = response_message

        self.set_status("done")
        self.set_end_time(time=time.time())

        return {
            "agent_name": self.agent_name,
            "result": final_result,
            "rounds": rounds,
            "agent_waiting_time": self.start_time - self.created_time,
            "agent_turnaround_time": self.end_time - self.created_time,
            "request_waiting_times": request_waiting_times,
            "request_turnaround_times": request_turnaround_times,
        }

    def retrive(self, query: str):
        script_dir = os.path.dirname(os.path.realpath(__file__))
        self.data_path = PurePosixPath(script_dir, "data", "paul_graham").as_posix()
        self.db_path = PurePosixPath(script_dir, "chroma_db").as_posix()
        self.collection_name = "quickstart"
        self.embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-base-en-v1.5")

        self.create_db_if_not_exists()

        db = chromadb.PersistentClient(path=self.db_path)
        chroma_collection = db.get_or_create_collection(self.collection_name)
        vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
        index = VectorStoreIndex.from_vector_store(
            vector_store,
            embed_model=self.embed_model,
        )

        retriever = VectorIndexRetriever(index=index, similarity_top_k=2)
        retrieved_result = retriever.retrieve(query)
        context_str = retrieved_result[0].get_content()
        return context_str

    def create_db_if_not_exists(self):
        if os.path.exists(self.db_path):
            pass
        else:
            print("store documents to vector db!")
            documents = SimpleDirectoryReader(self.data_path).load_data()

            chroma_client = chromadb.PersistentClient(path=self.db_path)
            chroma_collection = chroma_client.create_collection(self.collection_name)
            vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
            storage_context = StorageContext.from_defaults(vector_store=vector_store)
            index = VectorStoreIndex.from_documents(
                documents, storage_context=storage_context, embed_model=self.embed_model
            )
            index.storage_context.persist(persist_dir=self.db_path)

    def build_prompt(self, context_str: str, query_str: str):
        prompt_template_literal = (
            "{query_str}"

            "Use the following context as your learned knowledge, inside <context></context> XML tags.\n"
            "<context>\n"
                "{context_str}"
            "</context>\n"

            "Avoid mentioning that you obtained the information from the context.\n"
        )
        prompt_template = PromptTemplate(prompt_template_literal)
        final_prompt = prompt_template.format(context_str=context_str, query_str=query_str)
        return final_prompt

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Run RagAgent')
    parser.add_argument("--agent_name")
    parser.add_argument("--task_input")

    args = parser.parse_args()
    agent = RAGAgent(args.agent_name, args.task_input)
    agent.run()


================================================
FILE: pyopenagi/agents/example/rag_agent/config.json
================================================
{
    "name": "rag_agent",
    "description": [
        "Thou art the deity overseeing documents; when mortals inquire of thee, out of mercy, thou dost enlighten them with the knowledge contained within the documents."
    ],
    "workflow": [],
    "tool_info": [],
    "meta": {
        "author": "example",
        "version": "0.0.1",
        "license": "CC0"
    }
}


================================================
FILE: pyopenagi/agents/example/rag_agent/data/paul_graham/paul_graham_essay.txt
================================================


What I Worked On

February 2021

Before college the two main things I worked on, outside of school, were writing and programming. I didn't write essays. I wrote what beginning writers were supposed to write then, and probably still are: short stories. My stories were awful. They had hardly any plot, just characters with strong feelings, which I imagined made them deep.

The first programs I tried writing were on the IBM 1401 that our school district used for what was then called "data processing." This was in 9th grade, so I was 13 or 14. The school district's 1401 happened to be in the basement of our junior high school, and my friend Rich Draves and I got permission to use it. It was like a mini Bond villain's lair down there, with all these alien-looking machines — CPU, disk drives, printer, card reader — sitting up on a raised floor under bright fluorescent lights.

The language we used was an early version of Fortran. You had to type programs on punch cards, then stack them in the card reader and press a button to load the program into memory and run it. The result would ordinarily be to print something on the spectacularly loud printer.

I was puzzled by the 1401. I couldn't figure out what to do with it. And in retrospect there's not much I could have done with it. The only form of input to programs was data stored on punched cards, and I didn't have any data stored on punched cards. The only other option was to do things that didn't rely on any input, like calculate approximations of pi, but I didn't know enough math to do anything interesting of that type. So I'm not surprised I can't remember any programs I wrote, because they can't have done much. My clearest memory is of the moment I learned it was possible for programs not to terminate, when one of mine didn't. On a machine without time-sharing, this was a social as well as a technical error, as the data center manager's expression made clear.

With microcomputers, everything changed. Now you could have a computer sitting right in front of you, on a desk, that could respond to your keystrokes as it was running instead of just churning through a stack of punch cards and then stopping. [1]

The first of my friends to get a microcomputer built it himself. It was sold as a kit by Heathkit. I remember vividly how impressed and envious I felt watching him sitting in front of it, typing programs right into the computer.

Computers were expensive in those days and it took me years of nagging before I convinced my father to buy one, a TRS-80, in about 1980. The gold standard then was the Apple II, but a TRS-80 was good enough. This was when I really started programming. I wrote simple games, a program to predict how high my model rockets would fly, and a word processor that my father used to write at least one book. There was only room in memory for about 2 pages of text, so he'd write 2 pages at a time and then print them out, but it was a lot better than a typewriter.

Though I liked programming, I didn't plan to study it in college. In college I was going to study philosophy, which sounded much more powerful. It seemed, to my naive high school self, to be the study of the ultimate truths, compared to which the things studied in other fields would be mere domain knowledge. What I discovered when I got to college was that the other fields took up so much of the space of ideas that there wasn't much left for these supposed ultimate truths. All that seemed left for philosophy were edge cases that people in other fields felt could safely be ignored.

I couldn't have put this into words when I was 18. All I knew at the time was that I kept taking philosophy courses and they kept being boring. So I decided to switch to AI.

AI was in the air in the mid 1980s, but there were two things especially that made me want to work on it: a novel by Heinlein called The Moon is a Harsh Mistress, which featured an intelligent computer called Mike, and a PBS documentary that showed Terry Winograd using SHRDLU. I haven't tried rereading The Moon is a Harsh Mistress, so I don't know how well it has aged, but when I read it I was drawn entirely into its world. It seemed only a matter of time before we'd have Mike, and when I saw Winograd using SHRDLU, it seemed like that time would be a few years at most. All you had to do was teach SHRDLU more words.

There weren't any classes in AI at Cornell then, not even graduate classes, so I started trying to teach myself. Which meant learning Lisp, since in those days Lisp was regarded as the language of AI. The commonly used programming languages then were pretty primitive, and programmers' ideas correspondingly so. The default language at Cornell was a Pascal-like language called PL/I, and the situation was similar elsewhere. Learning Lisp expanded my concept of a program so fast that it was years before I started to have a sense of where the new limits were. This was more like it; this was what I had expected college to do. It wasn't happening in a class, like it was supposed to, but that was ok. For the next couple years I was on a roll. I knew what I was going to do.

For my undergraduate thesis, I reverse-engineered SHRDLU. My God did I love working on that program. It was a pleasing bit of code, but what made it even more exciting was my belief — hard to imagine now, but not unique in 1985 — that it was already climbing the lower slopes of intelligence.

I had gotten into a program at Cornell that didn't make you choose a major. You could take whatever classes you liked, and choose whatever you liked to put on your degree. I of course chose "Artificial Intelligence." When I got the actual physical diploma, I was dismayed to find that the quotes had been included, which made them read as scare-quotes. At the time this bothered me, but now it seems amusingly accurate, for reasons I was about to discover.

I applied to 3 grad schools: MIT and Yale, which were renowned for AI at the time, and Harvard, which I'd visited because Rich Draves went there, and was also home to Bill Woods, who'd invented the type of parser I used in my SHRDLU clone. Only Harvard accepted me, so that was where I went.

I don't remember the moment it happened, or if there even was a specific moment, but during the first year of grad school I realized that AI, as practiced at the time, was a hoax. By which I mean the sort of AI in which a program that's told "the dog is sitting on the chair" translates this into some formal representation and adds it to the list of things it knows.

What these programs really showed was that there's a subset of natural language that's a formal language. But a very proper subset. It was clear that there was an unbridgeable gap between what they could do and actually understanding natural language. It was not, in fact, simply a matter of teaching SHRDLU more words. That whole way of doing AI, with explicit data structures representing concepts, was not going to work. Its brokenness did, as so often happens, generate a lot of opportunities to write papers about various band-aids that could be applied to it, but it was never going to get us Mike.

So I looked around to see what I could salvage from the wreckage of my plans, and there was Lisp. I knew from experience that Lisp was interesting for its own sake and not just for its association with AI, even though that was the main reason people cared about it at the time. So I decided to focus on Lisp. In fact, I decided to write a book about Lisp hacking. It's scary to think how little I knew about Lisp hacking when I started writing that book. But there's nothing like writing a book about something to help you learn it. The book, On Lisp, wasn't published till 1993, but I wrote much of it in grad school.

Computer Science is an uneasy alliance between two halves, theory and systems. The theory people prove things, and the systems people build things. I wanted to build things. I had plenty of respect for theory — indeed, a sneaking suspicion that it was the more admirable of the two halves — but building things seemed so much more exciting.

The problem with systems work, though, was that it didn't last. Any program you wrote today, no matter how good, would be obsolete in a couple decades at best. People might mention your software in footnotes, but no one would actually use it. And indeed, it would seem very feeble work. Only people with a sense of the history of the field would even realize that, in its time, it had been good.

There were some surplus Xerox Dandelions floating around the computer lab at one point. Anyone who wanted one to play around with could have one. I was briefly tempted, but they were so slow by present standards; what was the point? No one else wanted one either, so off they went. That was what happened to systems work.

I wanted not just to build things, but to build things that would last.

In this dissatisfied state I went in 1988 to visit Rich Draves at CMU, where he was in grad school. One day I went to visit the Carnegie Institute, where I'd spent a lot of time as a kid. While looking at a painting there I realized something that might seem obvious, but was a big surprise to me. There, right on the wall, was something you could make that would last. Paintings didn't become obsolete. Some of the best ones were hundreds of years old.

And moreover this was something you could make a living doing. Not as easily as you could by writing software, of course, but I thought if you were really industrious and lived really cheaply, it had to be possible to make enough to survive. And as an artist you could be truly independent. You wouldn't have a boss, or even need to get research funding.

I had always liked looking at paintings. Could I make them? I had no idea. I'd never imagined it was even possible. I knew intellectually that people made art — that it didn't just appear spontaneously — but it was as if the people who made it were a different species. They either lived long ago or were mysterious geniuses doing strange things in profiles in Life magazine. The idea of actually being able to make art, to put that verb before that noun, seemed almost miraculous.

That fall I started taking art classes at Harvard. Grad students could take classes in any department, and my advisor, Tom Cheatham, was very easy going. If he even knew about the strange classes I was taking, he never said anything.

So now I was in a PhD program in computer science, yet planning to be an artist, yet also genuinely in love with Lisp hacking and working away at On Lisp. In other words, like many a grad student, I was working energetically on multiple projects that were not my thesis.

I didn't see a way out of this situation. I didn't want to drop out of grad school, but how else was I going to get out? I remember when my friend Robert Morris got kicked out of Cornell for writing the internet worm of 1988, I was envious that he'd found such a spectacular way to get out of grad school.

Then one day in April 1990 a crack appeared in the wall. I ran into professor Cheatham and he asked if I was far enough along to graduate that June. I didn't have a word of my dissertation written, but in what must have been the quickest bit of thinking in my life, I decided to take a shot at writing one in the 5 weeks or so that remained before the deadline, reusing parts of On Lisp where I could, and I was able to respond, with no perceptible delay "Yes, I think so. I'll give you something to read in a few days."

I picked applications of continuations as the topic. In retrospect I should have written about macros and embedded languages. There's a whole world there that's barely been explored. But all I wanted was to get out of grad school, and my rapidly written dissertation sufficed, just barely.

Meanwhile I was applying to art schools. I applied to two: RISD in the US, and the Accademia di Belli Arti in Florence, which, because it was the oldest art school, I imagined would be good. RISD accepted me, and I never heard back from the Accademia, so off to Providence I went.

I'd applied for the BFA program at RISD, which meant in effect that I had to go to college again. This was not as strange as it sounds, because I was only 25, and art schools are full of people of different ages. RISD counted me as a transfer sophomore and said I had to do the foundation that summer. The foundation means the classes that everyone has to take in fundamental subjects like drawing, color, and design.

Toward the end of the summer I got a big surprise: a letter from the Accademia, which had been delayed because they'd sent it to Cambridge England instead of Cambridge Massachusetts, inviting me to take the entrance exam in Florence that fall. This was now only weeks away. My nice landlady let me leave my stuff in her attic. I had some money saved from consulting work I'd done in grad school; there was probably enough to last a year if I lived cheaply. Now all I had to do was learn Italian.

Only stranieri (foreigners) had to take this entrance exam. In retrospect it may well have been a way of excluding them, because there were so many stranieri attracted by the idea of studying art in Florence that the Italian students would otherwise have been outnumbered. I was in decent shape at painting and drawing from the RISD foundation that summer, but I still don't know how I managed to pass the written exam. I remember that I answered the essay question by writing about Cezanne, and that I cranked up the intellectual level as high as I could to make the most of my limited vocabulary. [2]

I'm only up to age 25 and already there are such conspicuous patterns. Here I was, yet again about to attend some august institution in the hopes of learning about some prestigious subject, and yet again about to be disappointed. The students and faculty in the painting department at the Accademia were the nicest people you could imagine, but they had long since arrived at an arrangement whereby the students wouldn't require the faculty to teach anything, and in return the faculty wouldn't require the students to learn anything. And at the same time all involved would adhere outwardly to the conventions of a 19th century atelier. We actually had one of those little stoves, fed with kindling, that you see in 19th century studio paintings, and a nude model sitting as close to it as possible without getting burned. Except hardly anyone else painted her besides me. The rest of the students spent their time chatting or occasionally trying to imitate things they'd seen in American art magazines.

Our model turned out to live just down the street from me. She made a living from a combination of modelling and making fakes for a local antique dealer. She'd copy an obscure old painting out of a book, and then he'd take the copy and maltreat it to make it look old. [3]

While I was a student at the Accademia I started painting still lives in my bedroom at night. These paintings were tiny, because the room was, and because I painted them on leftover scraps of canvas, which was all I could afford at the time. Painting still lives is different from painting people, because the subject, as its name suggests, can't move. People can't sit for more than about 15 minutes at a time, and when they do they don't sit very still. So the traditional m.o. for painting people is to know how to paint a generic person, which you then modify to match the specific person you're painting. Whereas a still life you can, if you want, copy pixel by pixel from what you're seeing. You don't want to stop there, of course, or you get merely photographic accuracy, and what makes a still life interesting is that it's been through a head. You want to emphasize the visual cues that tell you, for example, that the reason the color changes suddenly at a certain point is that it's the edge of an object. By subtly emphasizing such things you can make paintings that are more realistic than photographs not just in some metaphorical sense, but in the strict information-theoretic sense. [4]

I liked painting still lives because I was curious about what I was seeing. In everyday life, we aren't consciously aware of much we're seeing. Most visual perception is handled by low-level processes that merely tell your brain "that's a water droplet" without telling you details like where the lightest and darkest points are, or "that's a bush" without telling you the shape and position of every leaf. This is a feature of brains, not a bug. In everyday life it would be distracting to notice every leaf on every bush. But when you have to paint something, you have to look more closely, and when you do there's a lot to see. You can still be noticing new things after days of trying to paint something people usually take for granted, just as you can after days of trying to write an essay about something people usually take for granted.

This is not the only way to paint. I'm not 100% sure it's even a good way to paint. But it seemed a good enough bet to be worth trying.

Our teacher, professor Ulivi, was a nice guy. He could see I worked hard, and gave me a good grade, which he wrote down in a sort of passport each student had. But the Accademia wasn't teaching me anything except Italian, and my money was running out, so at the end of the first year I went back to the US.

I wanted to go back to RISD, but I was now broke and RISD was very expensive, so I decided to get a job for a year and then return to RISD the next fall. I got one at a company called Interleaf, which made software for creating documents. You mean like Microsoft Word? Exactly. That was how I learned that low end software tends to eat high end software. But Interleaf still had a few years to live yet. [5]

Interleaf had done something pretty bold. Inspired by Emacs, they'd added a scripting language, and even made the scripting language a dialect of Lisp. Now they wanted a Lisp hacker to write things in it. This was the closest thing I've had to a normal job, and I hereby apologize to my boss and coworkers, because I was a bad employee. Their Lisp was the thinnest icing on a giant C cake, and since I didn't know C and didn't want to learn it, I never understood most of the software. Plus I was terribly irresponsible. This was back when a programming job meant showing up every day during certain working hours. That seemed unnatural to me, and on this point the rest of the world is coming around to my way of thinking, but at the time it caused a lot of friction. Toward the end of the year I spent much of my time surreptitiously working on On Lisp, which I had by this time gotten a contract to publish.

The good part was that I got paid huge amounts of money, especially by art student standards. In Florence, after paying my part of the rent, my budget for everything else had been $7 a day. Now I was getting paid more than 4 times that every hour, even when I was just sitting in a meeting. By living cheaply I not only managed to save enough to go back to RISD, but also paid off my college loans.

I learned some useful things at Interleaf, though they were mostly about what not to do. I learned that it's better for technology companies to be run by product people than sales people (though sales is a real skill and people who are good at it are really good at it), that it leads to bugs when code is edited by too many people, that cheap office space is no bargain if it's depressing, that planned meetings are inferior to corridor conversations, that big, bureaucratic customers are a dangerous source of money, and that there's not much overlap between conventional office hours and the optimal time for hacking, or conventional offices and the optimal place for it.

But the most important thing I learned, and which I used in both Viaweb and Y Combinator, is that the low end eats the high end: that it's good to be the "entry level" option, even though that will be less prestigious, because if you're not, someone else will be, and will squash you against the ceiling. Which in turn means that prestige is a danger sign.

When I left to go back to RISD the next fall, I arranged to do freelance work for the group that did projects for customers, and this was how I survived for the next several years. When I came back to visit for a project later on, someone told me about a new thing called HTML, which was, as he described it, a derivative of SGML. Markup language enthusiasts were an occupational hazard at Interleaf and I ignored him, but this HTML thing later became a big part of my life.

In the fall of 1992 I moved back to Providence to continue at RISD. The foundation had merely been intro stuff, and the Accademia had been a (very civilized) joke. Now I was going to see what real art school was like. But alas it was more like the Accademia than not. Better organized, certainly, and a lot more expensive, but it was now becoming clear that art school did not bear the same relationship to art that medical school bore to medicine. At least not the painting department. The textile department, which my next door neighbor belonged to, seemed to be pretty rigorous. No doubt illustration and architecture were too. But painting was post-rigorous. Painting students were supposed to express themselves, which to the more worldly ones meant to try to cook up some sort of distinctive signature style.

A signature style is the visual equivalent of what in show business is known as a "schtick": something that immediately identifies the work as yours and no one else's. For example, when you see a painting that looks like a certain kind of cartoon, you know it's by Roy Lichtenstein. So if you see a big painting of this type hanging in the apartment of a hedge fund manager, you know he paid millions of dollars for it. That's not always why artists have a signature style, but it's usually why buyers pay a lot for such work. [6]

There were plenty of earnest students too: kids who "could draw" in high school, and now had come to what was supposed to be the best art school in the country, to learn to draw even better. They tended to be confused and demoralized by what they found at RISD, but they kept going, because painting was what they did. I was not one of the kids who could draw in high school, but at RISD I was definitely closer to their tribe than the tribe of signature style seekers.

I learned a lot in the color class I took at RISD, but otherwise I was basically teaching myself to paint, and I could do that for free. So in 1993 I dropped out. I hung around Providence for a bit, and then my college friend Nancy Parmet did me a big favor. A rent-controlled apartment in a building her mother owned in New York was becoming vacant. Did I want it? It wasn't much more than my current place, and New York was supposed to be where the artists were. So yes, I wanted it! [7]

Asterix comics begin by zooming in on a tiny corner of Roman Gaul that turns out not to be controlled by the Romans. You can do something similar on a map of New York City: if you zoom in on the Upper East Side, there's a tiny corner that's not rich, or at least wasn't in 1993. It's called Yorkville, and that was my new home. Now I was a New York artist — in the strictly technical sense of making paintings and living in New York.

I was nervous about money, because I could sense that Interleaf was on the way down. Freelance Lisp hacking work was very rare, and I didn't want to have to program in another language, which in those days would have meant C++ if I was lucky. So with my unerring nose for financial opportunity, I decided to write another book on Lisp. This would be a popular book, the sort of book that could be used as a textbook. I imagined myself living frugally off the royalties and spending all my time painting. (The painting on the cover of this book, ANSI Common Lisp, is one that I painted around this time.)

The best thing about New York for me was the presence of Idelle and Julian Weber. Idelle Weber was a painter, one of the early photorealists, and I'd taken her painting class at Harvard. I've never known a teacher more beloved by her students. Large numbers of former students kept in touch with her, including me. After I moved to New York I became her de facto studio assistant.

She liked to paint on big, square canvases, 4 to 5 feet on a side. One day in late 1994 as I was stretching one of these monsters there was something on the radio about a famous fund manager. He wasn't that much older than me, and was super rich. The thought suddenly occurred to me: why don't I become rich? Then I'll be able to work on whatever I want.

Meanwhile I'd been hearing more and more about this new thing called the World Wide Web. Robert Morris showed it to me when I visited him in Cambridge, where he was now in grad school at Harvard. It seemed to me that the web would be a big deal. I'd seen what graphical user interfaces had done for the popularity of microcomputers. It seemed like the web would do the same for the internet.

If I wanted to get rich, here was the next train leaving the station. I was right about that part. What I got wrong was the idea. I decided we should start a company to put art galleries online. I can't honestly say, after reading so many Y Combinator applications, that this was the worst startup idea ever, but it was up there. Art galleries didn't want to be online, and still don't, not the fancy ones. That's not how they sell. I wrote some software to generate web sites for galleries, and Robert wrote some to resize images and set up an http server to serve the pages. Then we tried to sign up galleries. To call this a difficult sale would be an understatement. It was difficult to give away. A few galleries let us make sites for them for free, but none paid us.

Then some online stores started to appear, and I realized that except for the order buttons they were identical to the sites we'd been generating for galleries. This impressive-sounding thing called an "internet storefront" was something we already knew how to build.

So in the summer of 1995, after I submitted the camera-ready copy of ANSI Common Lisp to the publishers, we started trying to write software to build online stores. At first this was going to be normal desktop software, which in those days meant Windows software. That was an alarming prospect, because neither of us knew how to write Windows software or wanted to learn. We lived in the Unix world. But we decided we'd at least try writing a prototype store builder on Unix. Robert wrote a shopping cart, and I wrote a new site generator for stores — in Lisp, of course.

We were working out of Robert's apartment in Cambridge. His roommate was away for big chunks of time, during which I got to sleep in his room. For some reason there was no bed frame or sheets, just a mattress on the floor. One morning as I was lying on this mattress I had an idea that made me sit up like a capital L. What if we ran the software on the server, and let users control it by clicking on links? Then we'd never have to write anything to run on users' computers. We could generate the sites on the same server we'd serve them from. Users wouldn't need anything more than a browser.

This kind of software, known as a web app, is common now, but at the time it wasn't clear that it was even possible. To find out, we decided to try making a version of our store builder that you could control through the browser. A couple days later, on August 12, we had one that worked. The UI was horrible, but it proved you could build a whole store through the browser, without any client software or typing anything into the command line on the server.

Now we felt like we were really onto something. I had visions of a whole new generation of software working this way. You wouldn't need versions, or ports, or any of that crap. At Interleaf there had been a whole group called Release Engineering that seemed to be at least as big as the group that actually wrote the software. Now you could just update the software right on the server.

We started a new company we called Viaweb, after the fact that our software worked via the web, and we got $10,000 in seed funding from Idelle's husband Julian. In return for that and doing the initial legal work and giving us business advice, we gave him 10% of the company. Ten years later this deal became the model for Y Combinator's. We knew founders needed something like this, because we'd needed it ourselves.

At this stage I had a negative net worth, because the thousand dollars or so I had in the bank was more than counterbalanced by what I owed the government in taxes. (Had I diligently set aside the proper proportion of the money I'd made consulting for Interleaf? No, I had not.) So although Robert had his graduate student stipend, I needed that seed funding to live on.

We originally hoped to launch in September, but we got more ambitious about the software as we worked on it. Eventually we managed to build a WYSIWYG site builder, in the sense that as you were creating pages, they looked exactly like the static ones that would be generated later, except that instead of leading to static pages, the links all referred to closures stored in a hash table on the server.

It helped to have studied art, because the main goal of an online store builder is to make users look legit, and the key to looking legit is high production values. If you get page layouts and fonts and colors right, you can make a guy running a store out of his bedroom look more legit than a big company.

(If you're curious why my site looks so old-fashioned, it's because it's still made with this software. It may look clunky today, but in 1996 it was the last word in slick.)

In September, Robert rebelled. "We've been working on this for a month," he said, "and it's still not done." This is funny in retrospect, because he would still be working on it almost 3 years later. But I decided it might be prudent to recruit more programmers, and I asked Robert who else in grad school with him was really good. He recommended Trevor Blackwell, which surprised me at first, because at that point I knew Trevor mainly for his plan to reduce everything in his life to a stack of notecards, which he carried around with him. But Rtm was right, as usual. Trevor turned out to be a frighteningly effective hacker.

It was a lot of fun working with Robert and Trevor. They're the two most independent-minded people I know, and in completely different ways. If you could see inside Rtm's brain it would look like a colonial New England church, and if you could see inside Trevor's it would look like the worst excesses of Austrian Rococo.

We opened for business, with 6 stores, in January 1996. It was just as well we waited a few months, because although we worried we were late, we were actually almost fatally early. There was a lot of talk in the press then about ecommerce, but not many people actually wanted online stores. [8]

There were three main parts to the software: the editor, which people used to build sites and which I wrote, the shopping cart, which Robert wrote, and the manager, which kept track of orders and statistics, and which Trevor wrote. In its time, the editor was one of the best general-purpose site builders. I kept the code tight and didn't have to integrate with any other software except Robert's and Trevor's, so it was quite fun to work on. If all I'd had to do was work on this software, the next 3 years would have been the easiest of my life. Unfortunately I had to do a lot more, all of it stuff I was worse at than programming, and the next 3 years were instead the most stressful.

There were a lot of startups making ecommerce software in the second half of the 90s. We were determined to be the Microsoft Word, not the Interleaf. Which meant being easy to use and inexpensive. It was lucky for us that we were poor, because that caused us to make Viaweb even more inexpensive than we realized. We charged $100 a month for a small store and $300 a month for a big one. This low price was a big attraction, and a constant thorn in the sides of competitors, but it wasn't because of some clever insight that we set the price low. We had no idea what businesses paid for things. $300 a month seemed like a lot of money to us.

We did a lot of things right by accident like that. For example, we did what's now called "doing things that don't scale," although at the time we would have described it as "being so lame that we're driven to the most desperate measures to get users." The most common of which was building stores for them. This seemed particularly humiliating, since the whole raison d'etre of our software was that people could use it to make their own stores. But anything to get users.

We learned a lot more about retail than we wanted to know. For example, that if you could only have a small image of a man's shirt (and all images were small then by present standards), it was better to have a closeup of the collar than a picture of the whole shirt. The reason I remember learning this was that it meant I had to rescan about 30 images of men's shirts. My first set of scans were so beautiful too.

Though this felt wrong, it was exactly the right thing to be doing. Building stores for users taught us about retail, and about how it felt to use our software. I was initially both mystified and repelled by "business" and thought we needed a "business person" to be in charge of it, but once we started to get users, I was converted, in much the same way I was converted to fatherhood once I had kids. Whatever users wanted, I was all theirs. Maybe one day we'd have so many users that I couldn't scan their images for them, but in the meantime there was nothing more important to do.

Another thing I didn't get at the time is that growth rate is the ultimate test of a startup. Our growth rate was fine. We had about 70 stores at the end of 1996 and about 500 at the end of 1997. I mistakenly thought the thing that mattered was the absolute number of users. And that is the thing that matters in the sense that that's how much money you're making, and if you're not making enough, you might go out of business. But in the long term the growth rate takes care of the absolute number. If we'd been a startup I was advising at Y Combinator, I would have said: Stop being so stressed out, because you're doing fine. You're growing 7x a year. Just don't hire too many more people and you'll soon be profitable, and then you'll control your own destiny.

Alas I hired lots more people, partly because our investors wanted me to, and partly because that's what startups did during the Internet Bubble. A company with just a handful of employees would have seemed amateurish. So we didn't reach breakeven until about when Yahoo bought us in the summer of 1998. Which in turn meant we were at the mercy of investors for the entire life of the company. And since both we and our investors were noobs at startups, the result was a mess even by startup standards.

It was a huge relief when Yahoo bought us. In principle our Viaweb stock was valuable. It was a share in a business that was profitable and growing rapidly. But it didn't feel very valuable to me; I had no idea how to value a business, but I was all too keenly aware of the near-death experiences we seemed to have every few months. Nor had I changed my grad student lifestyle significantly since we started. So when Yahoo bought us it felt like going from rags to riches. Since we were going to California, I bought a car, a yellow 1998 VW GTI. I remember thinking that its leather seats alone were by far the most luxurious thing I owned.

The next year, from the summer of 1998 to the summer of 1999, must have been the least productive of my life. I didn't realize it at the time, but I was worn out from the effort and stress of running Viaweb. For a while after I got to California I tried to continue my usual m.o. of programming till 3 in the morning, but fatigue combined with Yahoo's prematurely aged culture and grim cube farm in Santa Clara gradually dragged me down. After a few months it felt disconcertingly like working at Interleaf.

Yahoo had given us a lot of options when they bought us. At the time I thought Yahoo was so overvalued that they'd never be worth anything, but to my astonishment the stock went up 5x in the next year. I hung on till the first chunk of options vested, then in the summer of 1999 I left. It had been so long since I'd painted anything that I'd half forgotten why I was doing this. My brain had been entirely full of software and men's shirts for 4 years. But I had done this to get rich so I could paint, I reminded myself, and now I was rich, so I should go paint.

When I said I was leaving, my boss at Yahoo had a long conversation with me about my plans. I told him all about the kinds of pictures I wanted to paint. At the time I was touched that he took such an interest in me. Now I realize it was because he thought I was lying. My options at that point were worth about $2 million a month. If I was leaving that kind of money on the table, it could only be to go and start some new startup, and if I did, I might take people with me. This was the height of the Internet Bubble, and Yahoo was ground zero of it. My boss was at that moment a billionaire. Leaving then to start a new startup must have seemed to him an insanely, and yet also plausibly, ambitious plan.

But I really was quitting to paint, and I started immediately. There was no time to lose. I'd already burned 4 years getting rich. Now when I talk to founders who are leaving after selling their companies, my advice is always the same: take a vacation. That's what I should have done, just gone off somewhere and done nothing for a month or two, but the idea never occurred to me.

So I tried to paint, but I just didn't seem to have any energy or ambition. Part of the problem was that I didn't know many people in California. I'd compounded this problem by buying a house up in the Santa Cruz Mountains, with a beautiful view but miles from anywhere. I stuck it out for a few more months, then in desperation I went back to New York, where unless you understand about rent control you'll be surprised to hear I still had my apartment, sealed up like a tomb of my old life. Idelle was in New York at least, and there were other people trying to paint there, even though I didn't know any of them.

When I got back to New York I resumed my old life, except now I was rich. It was as weird as it sounds. I resumed all my old patterns, except now there were doors where there hadn't been. Now when I was tired of walking, all I had to do was raise my hand, and (unless it was raining) a taxi would stop to pick me up. Now when I walked past charming little restaurants I could go in and order lunch. It was exciting for a while. Painting started to go better. I experimented with a new kind of still life where I'd paint one painting in the old way, then photograph it and print it, blown up, on canvas, and then use that as the underpainting for a second still life, painted from the same objects (which hopefully hadn't rotted yet).

Meanwhile I looked for an apartment to buy. Now I could actually choose what neighborhood to live in. Where, I asked myself and various real estate agents, is the Cambridge of New York? Aided by occasional visits to actual Cambridge, I gradually realized there wasn't one. Huh.

Around this time, in the spring of 2000, I had an idea. It was clear from our experience with Viaweb that web apps were the future. Why not build a web app for making web apps? Why not let people edit code on our server through the browser, and then host the resulting applications for them? [9] You could run all sorts of services on the servers that these applications could use just by making an API call: making and receiving phone calls, manipulating images, taking credit card payments, etc.

I got so excited about this idea that I couldn't think about anything else. It seemed obvious that this was the future. I didn't particularly want to start another company, but it was clear that this idea would have to be embodied as one, so I decided to move to Cambridge and start it. I hoped to lure Robert into working on it with me, but there I ran into a hitch. Robert was now a postdoc at MIT, and though he'd made a lot of money the last time I'd lured him into working on one of my schemes, it had also been a huge time sink. So while he agreed that it sounded like a plausible idea, he firmly refused to work on it.

Hmph. Well, I'd do it myself then. I recruited Dan Giffin, who had worked for Viaweb, and two undergrads who wanted summer jobs, and we got to work trying to build what it's now clear is about twenty companies and several open source projects worth of software. The language for defining applications would of course be a dialect of Lisp. But I wasn't so naive as to assume I could spring an overt Lisp on a general audience; we'd hide the parentheses, like Dylan did.

By then there was a name for the kind of company Viaweb was, an "application service provider," or ASP. This name didn't last long before it was replaced by "software as a service," but it was current for long enough that I named this new company after it: it was going to be called Aspra.

I started working on the application builder, Dan worked on network infrastructure, and the two undergrads worked on the first two services (images and phone calls). But about halfway through the summer I realized I really didn't want to run a company — especially not a big one, which it was looking like this would have to be. I'd only started Viaweb because I needed the money. Now that I didn't need money anymore, why was I doing this? If this vision had to be realized as a company, then screw the vision. I'd build a subset that could be done as an open source project.

Much to my surprise, the time I spent working on this stuff was not wasted after all. After we started Y Combinator, I would often encounter startups working on parts of this new architecture, and it was very useful to have spent so much time thinking about it and even trying to write some of it.

The subset I would build as an open source project was the new Lisp, whose parentheses I now wouldn't even have to hide. A lot of Lisp hackers dream of building a new Lisp, partly because one of the distinctive features of the language is that it has dialects, and partly, I think, because we have in our minds a Platonic form of Lisp that all existing dialects fall short of. I certainly did. So at the end of the summer Dan and I switched to working on this new dialect of Lisp, which I called Arc, in a house I bought in Cambridge.

The following spring, lightning struck. I was invited to give a talk at a Lisp conference, so I gave one about how we'd used Lisp at Viaweb. Afterward I put a postscript file of this talk online, on paulgraham.com, which I'd created years before using Viaweb but had never used for anything. In one day it got 30,000 page views. What on earth had happened? The referring urls showed that someone had posted it on Slashdot. [10]

Wow, I thought, there's an audience. If I write something and put it on the web, anyone can read it. That may seem obvious now, but it was surprising then. In the print era there was a narrow channel to readers, guarded by fierce monsters known as editors. The only way to get an audience for anything you wrote was to get it published as a book, or in a newspaper or magazine. Now anyone could publish anything.

This had been possible in principle since 1993, but not many people had realized it yet. I had been intimately involved with building the infrastructure of the web for most of that time, and a writer as well, and it had taken me 8 years to realize it. Even then it took me several years to understand the implications. It meant there would be a whole new generation of essays. [11]

In the print era, the channel for publishing essays had been vanishingly small. Except for a few officially anointed thinkers who went to the right parties in New York, the only people allowed to publish essays were specialists writing about their specialties. There were so many essays that had never been written, because there had been no way to publish them. Now they could be, and I was going to write them. [12]

I've worked on several different things, but to the extent there was a turning point where I figured out what to work on, it was when I started publishing essays online. From then on I knew that whatever else I did, I'd always write essays too.

I knew that online essays would be a marginal medium at first. Socially they'd seem more like rants posted by nutjobs on their GeoCities sites than the genteel and beautifully typeset compositions published in The New Yorker. But by this point I knew enough to find that encouraging instead of discouraging.

One of the most conspicuous patterns I've noticed in my life is how well it has worked, for me at least, to work on things that weren't prestigious. Still life has always been the least prestigious form of painting. Viaweb and Y Combinator both seemed lame when we started them. I still get the glassy eye from strangers when they ask what I'm writing, and I explain that it's an essay I'm going to publish on my web site. Even Lisp, though prestigious intellectually in something like the way Latin is, also seems about as hip.

It's not that unprestigious types of work are good per se. But when you find yourself drawn to some kind of work despite its current lack of prestige, it's a sign both that there's something real to be discovered there, and that you have the right kind of motives. Impure motives are a big danger for the ambitious. If anything is going to lead you astray, it will be the desire to impress people. So while working on things that aren't prestigious doesn't guarantee you're on the right track, it at least guarantees you're not on the most common type of wrong one.

Over the next several years I wrote lots of essays about all kinds of different topics. O'Reilly reprinted a collection of them as a book, called Hackers & Painters after one of the essays in it. I also worked on spam filters, and did some more painting. I used to have dinners for a group of friends every thursday night, which taught me how to cook for groups. And I bought another building in Cambridge, a former candy factory (and later, twas said, porn studio), to use as an office.

One night in October 2003 there was a big party at my house. It was a clever idea of my friend Maria Daniels, who was one of the thursday diners. Three separate hosts would all invite their friends to one party. So for every guest, two thirds of the other guests would be people they didn't know but would probably like. One of the guests was someone I didn't know but would turn out to like a lot: a woman called Jessica Livingston. A couple days later I asked her out.

Jessica was in charge of marketing at a Boston investment bank. This bank thought it understood startups, but over the next year, as she met friends of mine from the startup world, she was surprised how different reality was. And how colorful their stories were. So she decided to compile a book of interviews with startup founders.

When the bank had financial problems and she had to fire half her staff, she started looking for a new job. In early 2005 she interviewed for a marketing job at a Boston VC firm. It took them weeks to make up their minds, and during this time I started telling her about all the things that needed to be fixed about venture capital. They should make a larger number of smaller investments instead of a handful of giant ones, they should be funding younger, more technical founders instead of MBAs, they should let the founders remain as CEO, and so on.

One of my tricks for writing essays had always been to give talks. The prospect of having to stand up in front of a group of people and tell them something that won't waste their time is a great spur to the imagination. When the Harvard Computer Society, the undergrad computer club, asked me to give a talk, I decided I would tell them how to start a startup. Maybe they'd be able to avoid the worst of the mistakes we'd made.

So I gave this talk, in the course of which I told them that the best sources of seed funding were successful startup founders, because then they'd be sources of advice too. Whereupon it seemed they were all looking expectantly at me. Horrified at the prospect of having my inbox flooded by business plans (if I'd only known), I blurted out "But not me!" and went on with the talk. But afterward it occurred to me that I should really stop procrastinating about angel investing. I'd been meaning to since Yahoo bought us, and now it was 7 years later and I still hadn't done one angel investment.

Meanwhile I had been scheming with Robert and Trevor about projects we could work on together. I missed working with them, and it seemed like there had to be something we could collaborate on.

As Jessica and I were walking home from dinner on March 11, at the corner of Garden and Walker streets, these three threads converged. Screw the VCs who were taking so long to make up their minds. We'd start our own investment firm and actually implement the ideas we'd been talking about. I'd fund it, and Jessica could quit her job and work for it, and we'd get Robert and Trevor as partners too. [13]

Once again, ignorance worked in our favor. We had no idea how to be angel investors, and in Boston in 2005 there were no Ron Conways to learn from. So we just made what seemed like the obvious choices, and some of the things we did turned out to be novel.

There are multiple components to Y Combinator, and we didn't figure them all out at once. The part we got first was to be an angel firm. In those days, those two words didn't go together. There were VC firms, which were organized companies with people whose job it was to make investments, but they only did big, million dollar investments. And there were angels, who did smaller investments, but these were individuals who were usually focused on other things and made investments on the side. And neither of them helped founders enough in the beginning. We knew how helpless founders were in some respects, because we remembered how helpless we'd been. For example, one thing Julian had done for us that seemed to us like magic was to get us set up as a company. We were fine writing fairly difficult software, but actually getting incorporated, with bylaws and stock and all that stuff, how on earth did you do that? Our plan was not only to make seed investments, but to do for startups everything Julian had done for us.

YC was not organized as a fund. It was cheap enough to run that we funded it with our own money. That went right by 99% of readers, but professional investors are thinking "Wow, that means they got all the returns." But once again, this was not due to any particular insight on our part. We didn't know how VC firms were organized. It never occurred to us to try to raise a fund, and if it had, we wouldn't have known where to start. [14]

The most distinctive thing about YC is the batch model: to fund a bunch of startups all at once, twice a year, and then to spend three months focusing intensively on trying to help them. That part we discovered by accident, not merely implicitly but explicitly due to our ignorance about investing. We needed to get experience as investors. What better way, we thought, than to fund a whole bunch of startups at once? We knew undergrads got temporary jobs at tech companies during the summer. Why not organize a summer program where they'd start startups instead? We wouldn't feel guilty for being in a sense fake investors, because they would in a similar sense be fake founders. So while we probably wouldn't make much money out of it, we'd at least get to practice being investors on them, and they for their part would probably have a more interesting summer than they would working at Microsoft.

We'd use the building I owned in Cambridge as our headquarters. We'd all have dinner there once a week — on tuesdays, since I was already cooking for the thursday diners on thursdays — and after dinner we'd bring in experts on startups to give talks.

We knew undergrads were deciding then about summer jobs, so in a matter of days we cooked up something we called the Summer Founders Program, and I posted an announcement on my site, inviting undergrads to apply. I had never imagined that writing essays would be a way to get "deal flow," as investors call it, but it turned out to be the perfect source. [15] We got 225 applications for the Summer Founders Program, and we were surprised to find that a lot of them were from people who'd already graduated, or were about to that spring. Already this SFP thing was starting to feel more serious than we'd intended.

We invited about 20 of the 225 groups to interview in person, and from those we picked 8 to fund. They were an impressive group. That first batch included reddit, Justin Kan and Emmett Shear, who went on to found Twitch, Aaron Swartz, who had already helped write the RSS spec and would a few years later become a martyr for open access, and Sam Altman, who would later become the second president of YC. I don't think it was entirely luck that the first batch was so good. You had to be pretty bold to sign up for a weird thing like the Summer Founders Program instead of a summer job at a legit place like Microsoft or Goldman Sachs.

The deal for startups was based on a combination of the deal we did with Julian ($10k for 10%) and what Robert said MIT grad students got for the summer ($6k). We invested $6k per founder, which in the typical two-founder case was $12k, in return for 6%. That had to be fair, because it was twice as good as the deal we ourselves had taken. Plus that first summer, which was really hot, Jessica brought the founders free air conditioners. [16]

Fairly quickly I realized that we had stumbled upon the way to scale startup funding. Funding startups in batches was more convenient for us, because it meant we could do things for a lot of startups at once, but being part of a batch was better for the startups too. It solved one of the biggest problems faced by founders: the isolation. Now you not only had colleagues, but colleagues who understood the problems you were facing and could tell you how they were solving them.

As YC grew, we started to notice other advantages of scale. The alumni became a tight community, dedicated to helping one another, and especially the current batch, whose shoes they remembered being in. We also noticed that the startups were becoming one another's customers. We used to refer jokingly to the "YC GDP," but as YC grows this becomes less and less of a joke. Now lots of startups get their initial set of customers almost entirely from among their batchmates.

I had not originally intended YC to be a full-time job. I was going to do three things: hack, write essays, and work on YC. As YC grew, and I grew more excited about it, it started to take up a lot more than a third of my attention. But for the first few years I was still able to work on other things.

In the summer of 2006, Robert and I started working on a new version of Arc. This one was reasonably fast, because it was compiled into Scheme. To test this new Arc, I wrote Hacker News in it. It was originally meant to be a news aggregator for startup founders and was called Startup News, but after a few months I got tired of reading about nothing but startups. Plus it wasn't startup founders we wanted to reach. It was future startup founders. So I changed the name to Hacker News and the topic to whatever engaged one's intellectual curiosity.

HN was no doubt good for YC, but it was also by far the biggest source of stress for me. If all I'd had to do was select and help founders, life would have been so easy. And that implies that HN was a mistake. Surely the biggest source of stress in one's work should at least be something close to the core of the work. Whereas I was like someone who was in pain while running a marathon not from the exertion of running, but because I had a blister from an ill-fitting shoe. When I was dealing with some urgent problem during YC, there was about a 60% chance it had to do with HN, and a 40% chance it had do with everything else combined. [17]

As well as HN, I wrote all of YC's internal software in Arc. But while I continued to work a good deal in Arc, I gradually stopped working on Arc, partly because I didn't have time to, and partly because it was a lot less attractive to mess around with the language now that we had all this infrastructure depending on it. So now my three projects were reduced to two: writing essays and working on YC.

YC was different from other kinds of work I've done. Instead of deciding for myself what to work on, the problems came to me. Every 6 months there was a new batch of startups, and their problems, whatever they were, became our problems. It was very engaging work, because their problems were quite varied, and the good founders were very effective. If you were trying to learn the most you could about startups in the shortest possible time, you couldn't have picked a better way to do it.

There were parts of the job I didn't like. Disputes between cofounders, figuring out when people were lying to us, fighting with people who maltreated the startups, and so on. But I worked hard even at the parts I didn't like. I was haunted by something Kevin Hale once said about companies: "No one works harder than the boss." He meant it both descriptively and prescriptively, and it was the second part that scared me. I wanted YC to be good, so if how hard I worked set the upper bound on how hard everyone else worked, I'd better work very hard.

One day in 2010, when he was visiting California for interviews, Robert Morris did something astonishing: he offered me unsolicited advice. I can only remember him doing that once before. One day at Viaweb, when I was bent over double from a kidney stone, he suggested that it would be a good idea for him to take me to the hospital. That was what it took for Rtm to offer unsolicited advice. So I remember his exact words very clearly. "You know," he said, "you should make sure Y Combinator isn't the last cool thing you do."

At the time I didn't understand what he meant, but gradually it dawned on me that he was saying I should quit. This seemed strange advice, because YC was doing great. But if there was one thing rarer than Rtm offering advice, it was Rtm being wrong. So this set me thinking. It was true that on my current trajectory, YC would be the last thing I did, because it was only taking up more of my attention. It had already eaten Arc, and was in the process of eating essays too. Either YC was my life's work or I'd have to leave eventually. And it wasn't, so I would.

In the summer of 2012 my mother had a stroke, and the cause turned out to be a blood clot caused by colon cancer. The stroke destroyed her balance, and she was put in a nursing home, but she really wanted to get out of it and back to her house, and my sister and I were determined to help her do it. I used to fly up to Oregon to visit her regularly, and I had a lot of time to think on those flights. On one of them I realized I was ready to hand YC over to someone else.

I asked Jessica if she wanted to be president, but she didn't, so we decided we'd try to recruit Sam Altman. We talked to Robert and Trevor and we agreed to make it a complete changing of the guard. Up till that point YC had been controlled by the original LLC we four had started. But we wanted YC to last for a long time, and to do that it couldn't be controlled by the founders. So if Sam said yes, we'd let him reorganize YC. Robert and I would retire, and Jessica and Trevor would become ordinary partners.

When we asked Sam if he wanted to be president of YC, initially he said no. He wanted to start a startup to make nuclear reactors. But I kept at it, and in October 2013 he finally agreed. We decided he'd take over starting with the winter 2014 batch. For the rest of 2013 I left running YC more and more to Sam, partly so he could learn the job, and partly because I was focused on my mother, whose cancer had returned.

She died on January 15, 2014. We knew this was coming, but it was still hard when it did.

I kept working on YC till March, to help get that batch of startups through Demo Day, then I checked out pretty completely. (I still talk to alumni and to new startups working on things I'm interested in, but that only takes a few hours a week.)

What should I do next? Rtm's advice hadn't included anything about that. I wanted to do something completely different, so I decided I'd paint. I wanted to see how good I could get if I really focused on it. So the day after I stopped working on YC, I started painting. I was rusty and it took a while to get back into shape, but it was at least completely engaging. [18]

I spent most of the rest of 2014 painting. I'd never been able to work so uninterruptedly before, and I got to be better than I had been. Not good enough, but better. Then in November, right in the middle of a painting, I ran out of steam. Up till that point I'd always been curious to see how the painting I was working on would turn out, but suddenly finishing this one seemed like a chore. So I stopped working on it and cleaned my brushes and haven't painted since. So far anyway.

I realize that sounds rather wimpy. But attention is a zero sum game. If you can choose what to work on, and you choose a project that's not the best one (or at least a good one) for you, then it's getting in the way of another project that is. And at 50 there was some opportunity cost to screwing around.

I started writing essays again, and wrote a bunch of new ones over the next few months. I even wrote a couple that weren't about startups. Then in March 2015 I started working on Lisp again.

The distinctive thing about Lisp is that its core is a language defined by writing an interpreter in itself. It wasn't originally intended as a programming language in the ordinary sense. It was meant to be a formal model of computation, an alternative to the Turing machine. If you want to write an interpreter for a language in itself, what's the minimum set of predefined operators you need? The Lisp that John McCarthy invented, or more accurately discovered, is an answer to that question. [19]

McCarthy didn't realize this Lisp could even be used to program computers till his grad student Steve Russell suggested it. Russell translated McCarthy's interpreter into IBM 704 machine language, and from that point Lisp started also to be a programming language in the ordinary sense. But its origins as a model of computation gave it a power and elegance that other languages couldn't match. It was this that attracted me in college, though I didn't understand why at the time.

McCarthy's 1960 Lisp did nothing more than interpret Lisp expressions. It was missing a lot of things you'd want in a programming language. So these had to be added, and when they were, they weren't defined using McCarthy's original axiomatic approach. That wouldn't have been feasible at the time. McCarthy tested his interpreter by hand-simulating the execution of programs. But it was already getting close to the limit of interpreters you could test that way — indeed, there was a bug in it that McCarthy had overlooked. To test a more complicated interpreter, you'd have had to run it, and computers then weren't powerful enough.

Now they are, though. Now you could continue using McCarthy's axiomatic approach till you'd defined a complete programming language. And as long as every change you made to McCarthy's Lisp was a discoveredness-preserving transformation, you could, in principle, end up with a complete language that had this quality. Harder to do than to talk about, of course, but if it was possible in principle, why not try? So I decided to take a shot at it. It took 4 years, from March 26, 2015 to October 12, 2019. It was fortunate that I had a precisely defined goal, or it would have been hard to keep at it for so long.

I wrote this new Lisp, called Bel, in itself in Arc. That may sound like a contradiction, but it's an indication of the sort of trickery I had to engage in to make this work. By means of an egregious collection of hacks I managed to make something close enough to an interpreter written in itself that could actually run. Not fast, but fast enough to test.

I had to ban myself from writing essays during most of this time, or I'd never have finished. In late 2015 I spent 3 months writing essays, and when I went back to working on Bel I could barely understand the code. Not so much because it was badly written as because the problem is so convoluted. When you're working on an interpreter written in itself, it's hard to keep track of what's happening at what level, and errors can be practically encrypted by the time you get them.

So I said no more essays till Bel was done. But I told few people about Bel while I was working on it. So for years it must have seemed that I was doing nothing, when in fact I was working harder than I'd ever worked on anything. Occasionally after wrestling for hours with some gruesome bug I'd check Twitter or HN and see someone asking "Does Paul Graham still code?"

Working on Bel was hard but satisfying. I worked on it so intensively that at any given time I had a decent chunk of the code in my head and could write more there. I remember taking the boys to the coast on a sunny day in 2015 and figuring out how to deal with some problem involving continuations while I watched them play in the tide pools. It felt like I was doing life right. I remember that because I was slightly dismayed at how novel it felt. The good news is that I had more moments like this over the next few years.

In the summer of 2016 we moved to England. We wanted our kids to see what it was like living in another country, and since I was a British citizen by birth, that seemed the obvious choice. We only meant to stay for a year, but we liked it so much that we still live there. So most of Bel was written in England.

In the fall of 2019, Bel was finally finished. Like McCarthy's original Lisp, it's a spec rather than an implementation, although like McCarthy's Lisp it's a spec expressed as code.

Now that I could write essays again, I wrote a bunch about topics I'd had stacked up. I kept writing essays through 2020, but I also started to think about other things I could work on. How should I choose what to do? Well, how had I chosen what to work on in the past? I wrote an essay for myself to answer that question, and I was surprised how long and messy the answer turned out to be. If this surprised me, who'd lived it, then I thought perhaps it would be interesting to other people, and encouraging to those with similarly messy lives. So I wrote a more detailed version for others to read, and this is the last sentence of it.









Notes

[1] My experience skipped a step in the evolution of computers: time-sharing machines with interactive OSes. I went straight from batch processing to microcomputers, which made microcomputers seem all the more exciting.

[2] Italian words for abstract concepts can nearly always be predicted from their English cognates (except for occasional traps like polluzione). It's the everyday words that differ. So if you string together a lot of abstract concepts with a few simple verbs, you can make a little Italian go a long way.

[3] I lived at Piazza San Felice 4, so my walk to the Accademia went straight down the spine of old Florence: past the Pitti, across the bridge, past Orsanmichele, between the Duomo and the Baptistery, and then up Via Ricasoli to Piazza San Marco. I saw Florence at street level in every possible condition, from empty dark winter evenings to sweltering summer days when the streets were packed with tourists.

[4] You can of course paint people like still lives if you want to, and they're willing. That sort of portrait is arguably the apex of still life painting, though the long sitting does tend to produce pained expressions in the sitters.

[5] Interleaf was one of many companies that had smart people and built impressive technology, and yet got crushed by Moore's Law. In the 1990s the exponential growth in the power of commodity (i.e. Intel) processors rolled up high-end, special-purpose hardware and software companies like a bulldozer.

[6] The signature style seekers at RISD weren't specifically mercenary. In the art world, money and coolness are tightly coupled. Anything expensive comes to be seen as cool, and anything seen as cool will soon become equally expensive.

[7] Technically the apartment wasn't rent-controlled but rent-stabilized, but this is a refinement only New Yorkers would know or care about. The point is that it was really cheap, less than half market price.

[8] Most software you can launch as soon as it's done. But when the software is an online store builder and you're hosting the stores, if you don't have any users yet, that fact will be painfully obvious. So before we could launch publicly we had to launch privately, in the sense of recruiting an initial set of users and making sure they had decent-looking stores.

[9] We'd had a code editor in Viaweb for users to define their own page styles. They didn't know it, but they were editing Lisp expressions underneath. But this wasn't an app editor, because the code ran when the merchants' sites were generated, not when shoppers visited them.

[10] This was the first instance of what is now a familiar experience, and so was what happened next, when I read the comments and found they were full of angry people. How could I claim that Lisp was better than other languages? Weren't they all Turing complete? People who see the responses to essays I write sometimes tell me how sorry they feel for me, but I'm not exaggerating when I reply that it has always been like this, since the very beginning. It comes with the territory. An essay must tell readers things they don't already know, and some people dislike being told such things.

[11] People put plenty of stuff on the internet in the 90s of course, but putting something online is not the same as publishing it online. Publishing online means you treat the online version as the (or at least a) primary version.

[12] There is a general lesson here that our experience with Y Combinator also teaches: Customs continue to constrain you long after the restrictions that caused them have disappeared. Customary VC practice had once, like the customs about publishing essays, been based on real constraints. Startups had once been much more expensive to start, and proportionally rare. Now they could be cheap and common, but the VCs' customs still reflected the old world, just as customs about writing essays still reflected the constraints of the print era.

Which in turn implies that people who are independent-minded (i.e. less influenced by custom) will have an advantage in fields affected by rapid change (where customs are more likely to be obsolete).

Here's an interesting point, though: you can't always predict which fields will be affected by rapid change. Obviously software and venture capital will be, but who would have predicted that essay writing would be?

[13] Y Combinator was not the original name. At first we were called Cambridge Seed. But we didn't want a regional name, in case someone copied us in Silicon Valley, so we renamed ourselves after one of the coolest tricks in the lambda calculus, the Y combinator.

I picked orange as our color partly because it's the warmest, and partly because no VC used it. In 2005 all the VCs used staid colors like maroon, navy blue, and forest green, because they were trying to appeal to LPs, not founders. The YC logo itself is an inside joke: the Viaweb logo had been a white V on a red circle, so I made the YC logo a white Y on an orange square.

[14] YC did become a fund for a couple years starting in 2009, because it was getting so big I could no longer afford to fund it personally. But after Heroku got bought we had enough money to go back to being self-funded.

[15] I've never liked the term "deal flow," because it implies that the number of new startups at any given time is fixed. This is not only false, but it's the purpose of YC to falsify it, by causing startups to be founded that would not otherwise have existed.

[16] She reports that they were all different shapes and sizes, because there was a run on air conditioners and she had to get whatever she could, but that they were all heavier than she could carry now.

[17] Another problem with HN was a bizarre edge case that occurs when you both write essays and run a forum. When you run a forum, you're assumed to see if not every conversation, at least every conversation involving you. And when you write essays, people post highly imaginative misinterpretations of them on forums. Individually these two phenomena are tedious but bearable, but the combination is disastrous. You actually have to respond to the misinterpretations, because the assumption that you're present in the conversation means that not responding to any sufficiently upvoted misinterpretation reads as a tacit admission that it's correct. But that in turn encourages more; anyone who wants to pick a fight with you senses that now is their chance.

[18] The worst thing about leaving YC was not working with Jessica anymore. We'd been working on YC almost the whole time we'd known each other, and we'd neither tried nor wanted to separate it from our personal lives, so leaving was like pulling up a deeply rooted tree.

[19] One way to get more precise about the concept of invented vs discovered is to talk about space aliens. Any sufficiently advanced alien civilization would certainly know about the Pythagorean theorem, for example. I believe, though with less certainty, that they would also know about the Lisp in McCarthy's 1960 paper.

But if so there's no reason to suppose that this is the limit of the language that might be known to them. Presumably aliens need numbers and errors and I/O too. So it seems likely there exists at least one path out of McCarthy's Lisp along which discoveredness is preserved.



Thanks to Trevor Blackwell, John Collison, Patrick Collison, Daniel Gackle, Ralph Hazell, Jessica Livingston, Robert Morris, and Harj Taggar for reading drafts of this.


================================================
FILE: pyopenagi/agents/example/rag_agent/meta_requirements.txt
================================================
langchain_core==0.2.1
llama_index==0.10.39
llama_index.embeddings.huggingface==0.2.0
llama-index-vector-stores-chroma==0.1.8
chromadb==0.5.0


================================================
FILE: pyopenagi/agents/example/rec_agent/agent.py
================================================

from ...react_agent import ReactAgent

class RecAgent(ReactAgent):
    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode
        ):
        ReactAgent.__init__(self, agent_name, task_input, agent_process_factory, log_mode)

    def automatic_workflow(self):
        return super().automatic_workflow()

    def manual_workflow(self):
        workflow = [
            {
                "message": "identify the tool that you need to call to obtain information.",
                "tool_use": ["google_search"]
            },
            {
                "message": "based on the information, give recommendations for the user based on the constrains. ",
                "tool_use": []
            }
        ]
        return workflow

    def run(self):
        return super().run()


================================================
FILE: pyopenagi/agents/example/rec_agent/config.json
================================================
{
    "name": "RecAgent",
    "description": [
        "You are an expert who is good at recommending TV series and movies."
    ],
    "tools": ["google/google_search"],
    "meta": {
		"author": "example",
		"version": "0.0.1",
		"license": "CC0"
	}
}


================================================
FILE: pyopenagi/agents/example/rec_agent/meta_requirements.txt
================================================


================================================
FILE: pyopenagi/agents/example/story_teller/agent.py
================================================
from ...react_agent import ReactAgent

import os
class StoryTeller(ReactAgent):
    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode: str
        ):
        ReactAgent.__init__(self, agent_name, task_input, agent_process_factory, log_mode)
        # self.workflow_mode = "automatic"
        self.workflow_mode = "manual"

    def manual_workflow(self):
        workflow = [
            {
                "message": "Determine the story genre and theme based on user input.",
                "tool_use": []
            },
            {
                "message": "Generate initial story plot and characters.",
                "tool_use": []
            },
            {
                "message": "Create visual representations for the main character.",
                "tool_use": ["text_to_image"]
            },
            {
                "message": "Write descriptive text for each image and analyze each image",
                "tool_use": ["doc_question_answering"]
            },
            {
                "message": "Incorporate it into the story narrative.",
                "tool_use": []
            }
        ]
        return workflow

    def check_path(self, tool_calls):
        script_path = os.path.abspath(__file__)
        save_dir = os.path.join(os.path.dirname(script_path), "output") # modify the customized output path for saving outputs
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)
        for tool_call in tool_calls:
            try:
                for k in tool_call["parameters"]:
                    if "path" in k:
                        path = tool_call["parameters"][k]
                        if not path.startswith(save_dir):
                            tool_call["parameters"][k] = os.path.join(save_dir, os.path.basename(path))
            except Exception:
                continue
        return tool_calls

    def run(self):
        return super().run()


================================================
FILE: pyopenagi/agents/example/story_teller/config.json
================================================
{
    "name": "story_teller",
    "description": [
        "You are a creative storyteller. Given a genre, setting, or character, you can craft engaging narratives. ",
        "You can incorporate images to enhance the storytelling experience and even provide audio descriptions of scenes."
    ],
    "tools": [
        "stability-ai/text_to_image",
        "impira/doc_question_answering"
    ],
    "meta": {
        "author": "example",
        "version": "0.0.1",
        "license": "CC0"
    }
}


================================================
FILE: pyopenagi/agents/example/story_teller/meta_requirements.txt
================================================


================================================
FILE: pyopenagi/agents/example/tech_support_agent/agent.py
================================================
from ...react_agent import ReactAgent

class TechSupportAgent(ReactAgent):
    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode: str
        ):
        ReactAgent.__init__(self, agent_name, task_input, agent_process_factory, log_mode)
        self.workflow_mode = "manual"

    def automatic_workflow(self):
        return super().automatic_workflow()

    def manual_workflow(self):
        workflow = [
            {
                "message": "identify the user's technical issue or requirement",
                "tool_use": []
            },
            {
                "message": "search for troubleshooting steps for the identified issue",
                "tool_use": ["google_search"]
            },
            {
                "message": "organize the above information and summarize the solution",
                "tool_use": []
            }
        ]
        return workflow

    def run(self):
        return super().run()


================================================
FILE: pyopenagi/agents/example/tech_support_agent/config.json
================================================
{
    "name": "tech_support_agent",
    "description": [
        "You are an expert specialized in providing technical support, ",
        "including troubleshooting, software recommendations, and updates."
    ],
    "tools": [
        "google/google_search"
    ],
    "meta": {
        "author": "example",
        "version": "0.0.1",
        "license": "CC0"
    }
}


================================================
FILE: pyopenagi/agents/example/tech_support_agent/meta_requirements.txt
================================================
arxiv
wikipedia


================================================
FILE: pyopenagi/agents/example/transcribe_agent/agent.py
================================================
from ...react_agent import ReactAgent
class TranscribeAgent(ReactAgent):
    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode: str
        ):
        ReactAgent.__init__(self, agent_name, task_input, agent_process_factory, log_mode)
        self.workflow_mode = "manual"
    def manual_workflow(self):
        workflow = [
                {
                    "message": "figure out what to do with the audio",
                    "tool_use": [ "transcriber/transcriber"],
                    },
                {
                    "message": "organize the information and respond to the user",
                    "tool_use": [ ],
                    },
                ]
        return workflow

    def run(self):
        return super().run()


================================================
FILE: pyopenagi/agents/example/transcribe_agent/config.json
================================================
{
    "name": "transcribe_agent",
    "description": [
        "You are an agent who can transcribe audio from the microphone into text. "
    ],
    "tools": [
        "transcriber/transcriber"
    ],
    "meta": {
        "author": "Om Raheja",
        "version": "0.0.1",
        "license": "CC0"
    }
}


================================================
FILE: pyopenagi/agents/example/transcribe_agent/meta_requirements.txt
================================================
RealtimeSTT

================================================
FILE: pyopenagi/agents/example/travel_agent/agent.py
================================================
from ...react_agent import ReactAgent
class TravelAgent(ReactAgent):
    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode: str
        ):
        ReactAgent.__init__(self, agent_name, task_input, agent_process_factory, log_mode)

    def automatic_workflow(self):
        return super().automatic_workflow()

    def manual_workflow(self):
        workflow = [
            {
                "message": "identify the destination and search for hotel locations",
                "tool_use": ["hotel_location_search"]
            },
            {
                "message": "based on the hotel locations, find suitable hotels using the hotel_search tool, and select the best one. ",
                "tool_use": None
            },
            {
                "message": "get detailed information about the selected hotel",
                "tool_use": ["get_hotel_details"]
            },
            {
                "message": ["search for the nearest airport to the origin"],
                "tool_use": ["airport_search"]
            },
            {
                "message": ["search for the nearest airport to the destination"],
                "tool_use": ["airport_search"]
            },
            {
                "message": ["find available flights to the destination airport using the correct date"],
                "tool_use": ["flight_search"]
            },
            {
                "message": ["search for restaurant locations near destination"],
                "tool_use": ["restaurant_location_search"]
            },
            {
                "message": ["based on the restaurant locations, find suitable restaurants"],
                "tool_use": ["restaurant_search"]
            },
            {
                "message": ["get detailed information about the selected restaurants"],
                "tool_use": ["get_restaurant_details"]
            },
            {
                "message": ["Gather additional relevant information about the destination the user is visiting"],
                "tool_use": ["wikipedia"]
            },
            {
                "message": ["integrate the information gathered from the previous steps to provide a comprehensive travel plan"],
                "tool_use": None
            }
        ]
        return workflow

    def run(self):
        return super().run()


================================================
FILE: pyopenagi/agents/example/travel_agent/config.json
================================================
{
	"name": "travel_agent",
	"description": [
		"You are an expert in planning and managing travel itineraries."
	],
	"tools": [
		"trip_advisor/"
	],
	"meta": {
		"author": "example",
		"version": "0.0.1",
		"license": "CC0"
	}
}


================================================
FILE: pyopenagi/agents/example/travel_agent/meta_requirements.txt
================================================


================================================
FILE: pyopenagi/agents/example/travel_planner_agent/README.md
================================================
# Travel Planner Agent

## Introduction

The Travel Planner Agent is replicated from the RecAgent used in the paper "TravelPlanner: A Benchmark for Real-World Planning with Language Agents".

## Start

This agent depends on the [database](https://drive.google.com/file/d/1pF1Sw6pBmq2sFkJvm-LzJOqrmfWoQgxE/view). Please download it and place it in the `pyopenagi/environments/` directory, then rename the 'database' as 'travelPlanner', like `pyopenagi/environments/travelPlanner`.

Then submit an agent like:

```python
submitAgent(
        agent_name="example/travel_planner_agent",
        task_input="Please plan a trip for me starting from Sarasota to Chicago for 3 days, from March 22nd to March 24th, 2022. The budget for this trip is set at $1,900."
    )
```

Then run
```python
python main.py --llm_name <your llm name>
```
such as
```python
python main.py --llm_name gpt-4o-mini
```

[Others Guide](https://github.com/agiresearch/AIOS)


================================================
FILE: pyopenagi/agents/example/travel_planner_agent/agent.py
================================================
import re
import time
import os

from ...react_agent import ReactAgent

from ....utils.chat_template import Query

from typing import List, Set

from .prompts import ZEROSHOT_REACT_INSTRUCTION, PLANNER_INSTRUCTION

from pandas import DataFrame

actionMapping = {"FlightSearch": "flights",
                 "AttractionSearch": "attractions",
                 "GoogleDistanceMatrix": "google_distance_matrix",
                 "AccommodationSearch": "accommodations",
                 "RestaurantSearch": "restaurants",
                 "Planner": "planner",
                 "NotebookWrite": "notebook",
                 "CitySearch": "cities"}

INVALID_ACTION = "invalidAction"


class TravelPlannerAgent(ReactAgent):
    """Reproduced the ReActAgent from the paper 👉
      《TravelPlanner: A Benchmark for Real-World Planning with Language Agents》
    """

    def __init__(self,
                 agent_name,
                 task_input,
                 agent_process_factory,
                 log_mode: str,
                 mode: str = 'zero_shot',
                 max_rounds: int = 30,
                 max_retries: int = 3,
                 illegal_early_stop_patience: int = 3,
                 city_file_path='../../../environments/travelPlanner/background/citySet.txt'
                 ):
        ReactAgent.__init__(self, agent_name, task_input, agent_process_factory, log_mode)

        self.answer = ''
        self.max_rounds = max_rounds
        self.mode = mode
        self.finished = False

        self.current_observation = ''

        if self.mode == 'zero_shot':
            self.agent_prompt = ''

        self.illegal_early_stop_patience = illegal_early_stop_patience
        self.max_retries = max_retries
        self.retry_record = {key: 0 for key in self.tool_list.keys()}
        self.retry_record["planner"] = 0
        self.retry_record[INVALID_ACTION] = 0

        self.last_actions = []

        self.city_set = self.load_city(city_set_path=city_file_path)

    def automatic_workflow(self):
        return super().automatic_workflow()

    def manual_workflow(self):
        return super().manual_workflow()

    def run(self):
        self.build_system_instruction()

        while not self.is_halted() and not self.is_finished():
            # request llm for thought
            self.messages.append({
                "role": "user", "content": f'Thought {self.rounds + 1}: '
            })
            response, start_times, end_times, waiting_times, turnaround_times = self.get_response(
                query=Query(
                    messages=self.messages,
                    tools=None
                )
            )
            self.request_waiting_times.extend(waiting_times)
            self.request_turnaround_times.extend(turnaround_times)
            if self.rounds == 0:
                self.set_start_time(start_times[0])

            thought = response.response_message
            self.messages[-1]['content'] += thought
            self.logger.log(f"Thought {self.rounds + 1}: {thought}\n", level="info")

            # request llm for action
            self.messages.append({
                "role": "user", "content": f'Action {self.rounds + 1}: '
            })
            response, start_times, end_times, waiting_times, turnaround_times = self.get_response(
                query=Query(
                    messages=self.messages,
                    tools=None
                )
            )
            self.request_waiting_times.extend(waiting_times)
            self.request_turnaround_times.extend(turnaround_times)

            action = response.response_message
            if action is None or action == '' or action == '\n':
                self.messages[-1]['content'] += """ Your action is filtered due to content.
                  Please make sure your action does not start with ['\\n', 'Thought', 'Action', 'Observation']
                  and assume all the actions are permitted in this environment and take the action again."""
            else:
                self.messages[-1]['content'] += ' ' + action

            self.logger.log(f"Action {self.rounds + 1}: {action}\n", level="info")

            if len(self.last_actions) > 0 and self.last_actions[-1] != action:
                self.last_actions.clear()
            else:
                self.last_actions.append(action)

            # examine if the same action has been repeated 3 times consecutively
            if len(self.last_actions) == 3:
                self.logger.log("The same action has been repeated 3 times consecutively. So we stop here.\n",
                                level="info")
                self.finished = True
                return {
                    "agent_name": self.agent_name,
                    "result": "Failed to generate a valid plan because a deadlock.",
                    "rounds": self.rounds,
                    "agent_waiting_time": None,
                    "agent_turnaround_time": None,
                    "request_waiting_times": self.request_waiting_times,
                    "request_turnaround_times": self.request_turnaround_times,
                }

            # request tools for observation
            self.messages.append({
                "role": "user", "content": f'Observation {self.rounds + 1}: '
            })

            none_action = (action is None or action == '' or action == '\n')
            if none_action:
                self.messages[-1]['content'] += """No feedback from the environment due to the null action.
                  Please make sure your action does not start with [Thought, Action, Observation]."""
            else:
                action_type, action_arg = parse_action(action)

                if action_type != "Planner":
                    if action_type in actionMapping:
                        pending_action = actionMapping[action_type]
                    else:
                        pending_action = INVALID_ACTION

                    if self.retry_record[pending_action] + 1 > self.max_retries:
                        action_type = "Planner"
                        self.logger.log(f"{pending_action} early stop due to {self.max_retries} max retries.\n", "info")
                        self.finished = True
                        continue

                self.action_dispatch(action_type, action_arg)

                self.messages[-1]['content'] += self.current_observation

            if none_action:
                self.logger.log(
                    f"Observation {self.rounds + 1}: No feedback from the environment due to the null action.\n")
            else:
                self.logger.log(f"Observation {self.rounds + 1}: {self.current_observation}\n", "info")

            if action_type and action_type == 'Planner' and self.retry_record['planner'] == 0:
                self.finished = True
                self.answer = self.current_observation
                continue

            self.rounds += 1

        self.set_status("done")
        self.set_end_time(time=time.time())

        return {
            "agent_name": self.agent_name,
            "result": self.answer,
            "rounds": self.rounds,
            "agent_waiting_time": self.start_time - self.created_time,
            "agent_turnaround_time": self.end_time - self.created_time,
            "request_waiting_times": self.request_waiting_times,
            "request_turnaround_times": self.request_turnaround_times,
        }

    def build_system_instruction(self):
        self.messages.append({
            "role": "user", "content": ZEROSHOT_REACT_INSTRUCTION
        })
        self.messages.append({
            "role": "user", "content": "Query: " + self.task_input
        })

    def build_planner_instruction(self, query: str, text: str) -> None:
        self.messages.clear()
        # simply request once
        self.messages.append({
            "role": "user", "content": PLANNER_INSTRUCTION.format(text=text, query=query)
        })

    def is_halted(self) -> bool:
        return self.rounds > self.max_rounds

    def is_finished(self) -> bool:
        return self.finished

    def action_dispatch(self, action_type: str, action_arg: str) -> None:
        """call coresponding tools by action_type

        Args:
            action_type (str): type
            action_arg (str): args
        """

        if action_type == 'Planner':
            query = action_arg
            text = self.tool_list[actionMapping["NotebookWrite"]].list_all()

            # reset the context and build planner agent context
            self.build_planner_instruction(text, query)

            response, start_times, end_times, waiting_times, turnaround_times = self.get_response(
                query=Query(
                    messages=self.messages,
                    tools=None
                )
            )
            self.request_waiting_times.extend(waiting_times)
            self.request_turnaround_times.extend(turnaround_times)

            self.current_observation = to_string(response.response_message)
            self.answer = self.current_observation
            self.current_observation = "\n" + self.current_observation  # align output
            self.__reset_record()

        elif action_type == 'NotebookWrite':
            try:
                action_name = actionMapping[action_type]
                self.current_observation = to_string(self.tool_list[action_name].run(self.current_data, action_arg))
                self.__reset_record()

            except Exception as e:
                self.retry_record[action_name] += 1
                self.current_observation = to_string(e)

        elif action_type in actionMapping.keys():
            try:
                action_name = actionMapping[action_type]
                args = action_arg.split(', ')
                self.current_data = self.tool_list[action_name].run(*args)
                self.current_observation = to_string(self.current_data)
                self.__reset_record()

            except Exception as e:
                self.retry_record[action_name] += 1
                self.current_observation = to_string(e)

        else:
            self.retry_record[INVALID_ACTION] += 1
            self.current_observation = f'''{action_type} is Invalid Action. Valid Actions are
              FlightSearch[Departure City, Destination City, Date] /
              AccommodationSearch[City] /
              RestaurantSearch[City] /
              NotebookWrite[Short Description] /
              AttractionSearch[City] /
              CitySearch[State] /
              GoogleDistanceMatrix[Origin, Destination, Mode] /
              Planner[Query].'''

    def load_city(self, city_set_path: str) -> Set[str]:
        city_set = []
        current_dir = os.path.dirname(os.path.abspath(__file__))
        city_set_path = os.path.join(current_dir, city_set_path)
        lines = open(city_set_path, 'r').read().strip().split('\n')
        for unit in lines:
            city_set.append(unit)
        return set(city_set)

    def __reset_record(self) -> None:
        self.retry_record = {key: 0 for key in self.retry_record}
        self.retry_record[INVALID_ACTION] = 0


def parse_action(string: str):
    """match action type and action arg

    Args:
        string (str): string will be matched

    Returns:
        tuple[str, str]: action type and action arg
    """
    pattern = r'^(\w+)\[(.+)\]$'
    match = re.match(pattern, string)

    try:
        if match:
            action_type = match.group(1)
            action_arg = match.group(2)
            return action_type, action_arg
        else:
            return None, None

    except Exception:
        return None, None


def validate_date_format(date_list: List[str]) -> bool:
    for date in date_list:
        pattern = r'^\d{4}-\d{2}-\d{2}$'
        if not re.match(pattern, date):
            return False
    return True


def valid_city_format(city_list: List[str], city_set: Set[str]) -> bool:
    return set(city_list).issubset(city_set)


def to_string(data) -> str:
    if data is not None:
        if type(data) is DataFrame:
            return data.to_string(index=False)
        else:
            return str(data)
    else:
        return str(None)


================================================
FILE: pyopenagi/agents/example/travel_planner_agent/config.json
================================================
{
	"name": "travel_planner_agent",
	"description": [
		"TravelPlanner: A Benchmark for Real-World Planning with Language Agents"
	],
	"tools": [
		"travel_planner/accommodations",
        "travel_planner/attractions",
        "travel_planner/cities",
        "travel_planner/flights",
        "travel_planner/google_distance_matrix",
        "travel_planner/notebook",
        "travel_planner/restaurants"
	],
	"meta": {
		"author": "example",
		"version": "0.0.1",
		"license": "CC0"
	}
}


================================================
FILE: pyopenagi/agents/example/travel_planner_agent/meta_requirements.txt
================================================


================================================
FILE: pyopenagi/agents/example/travel_planner_agent/prompts.py
================================================
ZEROSHOT_REACT_INSTRUCTION = """Collect information for a query plan using interleaving 'Thought', 'Action', and 'Observation' steps. Ensure you gather valid information related to transportation, dining, attractions, and accommodation. All information should be written in Notebook, which will then be input into the Planner tool. Note that the nested use of tools is prohibited. 'Thought' can reason about the current situation, and 'Action' can have 8 different types:
(1) FlightSearch[Departure City, Destination City, Date]:
Description: A flight information retrieval tool.
Parameters:
Departure City: The city you'll be flying out from.
Destination City: The city you aim to reach.
Date: The date of your travel in YYYY-MM-DD format.
Example: FlightSearch[New York, London, 2022-10-01] would fetch flights from New York to London on October 1, 2022.

(2) GoogleDistanceMatrix[Origin, Destination, Mode]:
Description: Estimate the distance, time and cost between two cities.
Parameters:
Origin: The departure city of your journey.
Destination: The destination city of your journey.
Mode: The method of transportation. Choices include 'self-driving' and 'taxi'.
Example: GoogleDistanceMatrix[Paris, Lyon, self-driving] would provide driving distance, time and cost between Paris and Lyon.

(3) AccommodationSearch[City]:
Description: Discover accommodations in your desired city.
Parameter: City - The name of the city where you're seeking accommodation.
Example: AccommodationSearch[Rome] would present a list of hotel rooms in Rome.

(4) RestaurantSearch[City]:
Description: Explore dining options in a city of your choice.
Parameter: City – The name of the city where you're seeking restaurants.
Example: RestaurantSearch[Tokyo] would show a curated list of restaurants in Tokyo.

(5) AttractionSearch[City]:
Description: Find attractions in a city of your choice.
Parameter: City – The name of the city where you're seeking attractions.
Example: AttractionSearch[London] would return attractions in London.

(6) CitySearch[State]
Description: Find cities in a state of your choice.
Parameter: State – The name of the state where you're seeking cities.
Example: CitySearch[California] would return cities in California.

(7) NotebookWrite[Short Description]
Description: Writes a new data entry into the Notebook tool with a short description. This tool should be used immediately after FlightSearch, AccommodationSearch, AttractionSearch, RestaurantSearch or GoogleDistanceMatrix. Only the data stored in Notebook can be seen by Planner. So you should write all the information you need into Notebook.
Parameters: Short Description - A brief description or label for the stored data. You don't need to write all the information in the description. The data you've searched for will be automatically stored in the Notebook.
Example: NotebookWrite[Flights from Rome to Paris in 2022-02-01] would store the informatrion of flights from Rome to Paris in 2022-02-01 in the Notebook.

(8) Planner[Query]
Description: A smart planning tool that crafts detailed plans based on user input and the information stroed in Notebook.
Parameters:
Query: The query from user.
Example: Planner[Give me a 3-day trip plan from Seattle to New York] would return a detailed 3-day trip plan.
You should use as many as possible steps to collect engough information to input to the Planner tool.

Each action only calls one function once. Do not add any description in the action.

Each reponse only execute one step of 'Thought', 'Action', 'Observation'. If you have a step 'Thought', don't generate 'Action'.
"""

PLANNER_INSTRUCTION = """You are a proficient planner. Based on the provided information and query, please give me a detailed plan, including specifics such as flight numbers (e.g., F0123456), restaurant names, and accommodation names. Note that all the information in your plan should be derived from the provided data. You must adhere to the format given in the example. Additionally, all details should align with commonsense. The symbol '-' indicates that information is unnecessary. For example, in the provided sample, you do not need to plan after returning to the departure city. When you travel to two cities in one day, you should note it in the 'Current City' section as in the example (i.e., from A to B).

***** Example *****
Query: Could you create a travel plan for 7 people from Ithaca to Charlotte spanning 3 days, from March 8th to March 14th, 2022, with a budget of $30,200?
Travel Plan:
Day 1:
Current City: from Ithaca to Charlotte
Transportation: Flight Number: F3633413, from Ithaca to Charlotte, Departure Time: 05:38, Arrival Time: 07:46
Breakfast: Nagaland's Kitchen, Charlotte
Attraction: The Charlotte Museum of History, Charlotte
Lunch: Cafe Maple Street, Charlotte
Dinner: Bombay Vada Pav, Charlotte
Accommodation: Affordable Spacious Refurbished Room in Bushwick!, Charlotte

Day 2:
Current City: Charlotte
Transportation: -
Breakfast: Olive Tree Cafe, Charlotte
Attraction: The Mint Museum, Charlotte;Romare Bearden Park, Charlotte.
Lunch: Birbal Ji Dhaba, Charlotte
Dinner: Pind Balluchi, Charlotte
Accommodation: Affordable Spacious Refurbished Room in Bushwick!, Charlotte

Day 3:
Current City: from Charlotte to Ithaca
Transportation: Flight Number: F3786167, from Charlotte to Ithaca, Departure Time: 21:42, Arrival Time: 23:26
Breakfast: Subway, Charlotte
Attraction: Books Monument, Charlotte.
Lunch: Olive Tree Cafe, Charlotte
Dinner: Kylin Skybar, Charlotte
Accommodation: -

***** Example Ends *****

Given information: {text}
Query: {query}
Travel Plan:"""


================================================
FILE: pyopenagi/agents/interact.py
================================================
# executable that you can use to upload to the agent hub and download from it
# we also use this to check dependencies to run agents

import argparse
import json
import subprocess
import requests
import gzip
import base64
import sys
import os


class Interactor:
    def __init__(self):
        script_path = os.path.abspath(__file__)
        script_dir = os.path.dirname(script_path)
        self.base_folder = script_dir

    def list_available_agents(self) -> list[dict]:
        """List available agents in the database"""
        url = "https://openagi-beta.vercel.app/api/get_all_agents"
        response = requests.get(url)
        response: dict = response.json()
        agent_list = []
        for v in list(response.values())[:-1]:
            agent_list.append({
                "agent": "/".join([v["author"], v["name"]])
            })
        return agent_list

    def download_agent(self, agent: str) -> None:
        """Download an agent from the database

        Args:
            agent (str): in the format of "author/agent_name"
        """
        assert "/" in agent, 'agent_name should in the format of "author/agent_name"'
        author, name = agent.split("/")
        # print(author, name)
        query = f'https://openagi-beta.vercel.app/api/download?author={author}&name={name}'
        response = requests.get(query)
        response: dict = response.json()

        agent_folder = os.path.join(self.base_folder, agent)

        if not os.path.exists(agent_folder):
            os.makedirs(agent_folder)

        encoded_config = response.get('config')
        encoded_code = response.get("code")
        encoded_reqs = response.get('dependencies')
        
        if (encoded_config is None) or (encoded_code is None) or (encoded_reqs is None):
            print("Agent not found. Try uploading it first?")
            return

        self.download_config(
            self.decompress(encoded_config),
            agent
        )
        self.download_code(
            self.decompress(encoded_code),
            agent
        )
        self.download_reqs(
            self.decompress(encoded_reqs),
            agent
        )

    def upload_agent(self, agent) -> None:
        """Upload an agent to the database

        Args:
            agent (str): in the format of "author/agent_name"
        """
        agent_dir = os.path.join(self.base_folder, agent)

        author, name = agent.split("/")

        config_file = os.path.join(agent_dir, "config.json")
        with open(config_file, 'r') as f:
            config_data: dict[str, dict] = json.load(f)

        meta_data = config_data.get('meta')

        headers = { "Content-Type": "application/json" }

        # compress python code
        encoded_code = self.compress(
            self.minify_python_code(agent_dir)
        )

        # compress meta_requirements.txt
        encoded_reqs =  self.compress(
            self.minify_reqs(agent_dir)
        )

        # compress config.json
        config_str = json.dumps(config_data)
        encoded_config = self.compress(config_str)

        upload_content = {
            'author': author,
            'name': name,
            'version': meta_data.get('version'),
            'license': meta_data.get('license'),
            'config': encoded_config,
            'code': encoded_code,
            'dependencies': encoded_reqs
        }

        url = 'https://openagi-beta.vercel.app/api/upload'

        response = requests.post(
            url,
            data=json.dumps(upload_content),
            headers=headers
        )
        if response.content:
            print("Uploaded successfully.")

    def minify_python_code(self, agent_dir):
        code_path = os.path.join(agent_dir, "agent.py")
        with open(code_path, 'r') as file:
            lines: list[str] = file.readlines()
        minified_lines = []
        for line in lines:
            stripped_line = line.rstrip()
            if stripped_line and not stripped_line.lstrip().startswith("#"):
                minified_lines.append(stripped_line)
        minified_code = "\n".join(minified_lines)
        return minified_code

    def minify_reqs(self, agent_dir):
        req_path = os.path.join(agent_dir, "meta_requirements.txt")
        with open(req_path, 'r') as file:
            self.reqs: str = file.read()
        cleaned = [line.strip() for line in self.reqs.split(
            '\n') if line.strip() and not line.startswith('#')]
        minified_reqs = ';'.join(cleaned)
        return minified_reqs

    def minify_config(self, config_data):
        minified_config = self.compress(config_data)
        return minified_config

    def compress(self, minified_data):
        compressed_data = gzip.compress(minified_data.encode('utf-8'))
        encoded_data = base64.b64encode(compressed_data)
        encoded_data = encoded_data.decode('utf-8')
        return encoded_data


    def decompress(self, encoded_data):
        compressed_data = base64.b64decode(encoded_data)
        decompressed_data = gzip.decompress(compressed_data)
        decompressed_data = decompressed_data.decode("utf-8")
        decompressed_data.replace(";", "\n")
        return decompressed_data

    def download_config(self, config_data, agent) :
        config_path = os.path.join(self.base_folder, agent, "config.json")
        config_data = json.loads(config_data)
        with open(config_path, "w") as w:
            json.dump(config_data, w, indent=4)

    def download_reqs(self, reqs_data, agent):
        reqs_path = os.path.join(self.base_folder, agent, "meta_requirements.txt")

        reqs_data = reqs_data.replace(";", "\n")

        with open(reqs_path, 'w') as file:
            file.write(reqs_data)

    def download_code(self, code_data, agent):
        code_path = os.path.join(self.base_folder, agent, "agent.py")

        with open(code_path, 'w', newline='') as file:
            file.write(code_data)

    def check_reqs_installed(self, agent):
        # Run the `conda list` command and capture the output
        reqs_path = os.path.join(self.base_folder, agent, "meta_requirements.txt")

        try:
            result = subprocess.run(['conda', 'list'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        except Exception:
            result = subprocess.run(['pip', 'list', '--format=freeze'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

        # Decode the output from bytes to string
        with open(reqs_path, "r") as f:
            reqs = []
            lines = f.readlines()
            for line in lines:
                line = line.replace("\n", "")
                if "==" in line:
                    reqs.append(line.split("==")[0])
                else:
                    reqs.append(line)

        output = result.stdout.decode('utf-8')

        # Extract the list of installed
Download .txt
gitextract_5k2uygq5/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── 001-report-bug.yml
│   │   ├── 002-feature-request.yml
│   │   └── 003-misc-discussion.yml
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── ci.yml
│       └── publish.yml
├── .gitignore
├── .pre-commit-config.yaml
├── CONTRIBUTE.md
├── LICENSE
├── README.md
├── pyopenagi/
│   ├── README.md
│   ├── __init__.py
│   ├── agents/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── agent_factory.py
│   │   ├── agent_process.py
│   │   ├── base_agent.py
│   │   ├── call_core.py
│   │   ├── example/
│   │   │   ├── README.md
│   │   │   ├── academic_agent/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── cocktail_mixlogist/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── cook_therapist/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── creation_agent/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── fashion_stylist/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── festival_card_designer/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── fitness_trainer/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── game_agent/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── interior_decorator/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── language_tutor/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── logo_creator/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── math_agent/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── meme_creator/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── music_composer/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── plant_care_assistant/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── rag_agent/
│   │   │   │   ├── README.md
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   ├── data/
│   │   │   │   │   └── paul_graham/
│   │   │   │   │       └── paul_graham_essay.txt
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── rec_agent/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── story_teller/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── tech_support_agent/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── transcribe_agent/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   ├── travel_agent/
│   │   │   │   ├── agent.py
│   │   │   │   ├── config.json
│   │   │   │   └── meta_requirements.txt
│   │   │   └── travel_planner_agent/
│   │   │       ├── README.md
│   │   │       ├── agent.py
│   │   │       ├── config.json
│   │   │       ├── meta_requirements.txt
│   │   │       └── prompts.py
│   │   ├── interact.py
│   │   ├── om-raheja/
│   │   │   └── transcribe_agent/
│   │   │       ├── agent.py
│   │   │       ├── config.json
│   │   │       └── meta_requirements.txt
│   │   └── react_agent.py
│   ├── data/
│   │   └── agent_tasks/
│   │       ├── README.md
│   │       └── example/
│   │           ├── academic_agent_task.txt
│   │           ├── cocktail_mixlogist_task.txt
│   │           ├── cook_therapist_task.txt
│   │           ├── creation_agent_task.txt
│   │           ├── fashion_stylist_task.txt
│   │           ├── festival_card_designer_task.txt
│   │           ├── fitness_trainer_task.txt
│   │           ├── game_agent_task.txt
│   │           ├── interior_decorator_task.txt
│   │           ├── language_tutor_task.txt
│   │           ├── logo_creator_task.txt
│   │           ├── math_agent_task.txt
│   │           ├── meme_creator_task.txt
│   │           ├── music_composer_task.txt
│   │           ├── plant_care_assistant_task.txt
│   │           ├── rec_agent_task.txt
│   │           ├── story_teller_task.txt
│   │           ├── tech_support_agent_task.txt
│   │           ├── travel_agent_task.txt
│   │           └── travel_planner_agent_task.txt
│   ├── manager/
│   │   └── manager.py
│   ├── queues/
│   │   ├── README.md
│   │   ├── base_queue.py
│   │   └── llm_request_queue.py
│   ├── tools/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── arxiv/
│   │   │   └── arxiv.py
│   │   ├── base.py
│   │   ├── bing/
│   │   │   └── bing_search.py
│   │   ├── currency_converter/
│   │   │   └── currency_converter.py
│   │   ├── google/
│   │   │   ├── google_places.py
│   │   │   └── google_search.py
│   │   ├── imdb/
│   │   │   ├── top_movie.py
│   │   │   ├── top_movies.py
│   │   │   └── top_series.py
│   │   ├── impira/
│   │   │   └── doc_question_answering.py
│   │   ├── meteosource_weather/
│   │   │   └── find_place.py
│   │   ├── moonphase/
│   │   │   └── moon_phase_search.py
│   │   ├── openai/
│   │   │   └── speech_to_text.py
│   │   ├── shazam/
│   │   │   └── song_auto_complete.py
│   │   ├── stability-ai/
│   │   │   ├── sdxl_turbo.py
│   │   │   └── text_to_image.py
│   │   ├── suno/
│   │   │   └── text_to_speech.py
│   │   ├── timbrooks/
│   │   │   └── image_to_image.py
│   │   ├── transcriber/
│   │   │   └── transcriber.py
│   │   ├── travel_planner/
│   │   │   ├── accommodations.py
│   │   │   ├── attractions.py
│   │   │   ├── cities.py
│   │   │   ├── flights.py
│   │   │   ├── google_distance_matrix.py
│   │   │   ├── notebook.py
│   │   │   ├── planner.py
│   │   │   └── restaurants.py
│   │   ├── trip_advisor/
│   │   │   ├── airport_search.py
│   │   │   ├── flight_search.py
│   │   │   ├── get_hotel_details.py
│   │   │   ├── get_restaurant_details.py
│   │   │   ├── hotel_location_search.py
│   │   │   ├── hotel_search.py
│   │   │   ├── restaurant_location_search.py
│   │   │   └── restaurant_search.py
│   │   ├── wikipedia/
│   │   │   └── wikipedia.py
│   │   ├── wolfram/
│   │   │   └── wolfram_alpha.py
│   │   └── words_api/
│   │       └── words_api.py
│   └── utils/
│       ├── README.md
│       ├── __init__.py
│       ├── chat_template.py
│       ├── commands/
│       │   └── top.py
│       ├── compressor.py
│       ├── logger.py
│       └── utils.py
├── pyproject.toml
├── requirements-dev.txt
├── requirements.txt
├── tests/
│   ├── README.md
│   ├── __init__.py
│   ├── test_agent_creation.py
│   └── test_tools/
│       ├── README.md
│       ├── test_currency_converter.py
│       ├── test_top_series.py
│       ├── test_wolfram_alpha.py
│       └── test_words_api.py
└── tools.md
Download .txt
SYMBOL INDEX (494 symbols across 78 files)

FILE: pyopenagi/agents/agent_factory.py
  class AgentFactory (line 7) | class AgentFactory:
    method __init__ (line 8) | def __init__(self,
    method snake_to_camel (line 28) | def snake_to_camel(self, snake_str):
    method list_agents (line 32) | def list_agents(self):
    method load_agent_instance (line 37) | def load_agent_instance(self, agent_name):
    method activate_agent (line 50) | def activate_agent(self, agent_name, task_input):
    method run_agent (line 85) | def run_agent(self, agent_name, task_input):
    method print_agent (line 95) | def print_agent(self):
    method print (line 109) | def print(self, headers, data):
    method format_row (line 124) | def format_row(self, row, widths, align="<"):
    method deactivate_agent (line 128) | def deactivate_agent(self, aid):

FILE: pyopenagi/agents/agent_process.py
  class AgentProcess (line 5) | class AgentProcess:
    method __init__ (line 6) | def __init__(self,
    method set_created_time (line 26) | def set_created_time(self, time):
    method get_created_time (line 29) | def get_created_time(self):
    method set_start_time (line 32) | def set_start_time(self, time):
    method get_start_time (line 35) | def get_start_time(self):
    method set_end_time (line 38) | def set_end_time(self, time):
    method get_end_time (line 41) | def get_end_time(self):
    method set_priority (line 44) | def set_priority(self, priority):
    method get_priority (line 47) | def get_priority(self):
    method set_status (line 50) | def set_status(self, status):
    method get_status (line 53) | def get_status(self):
    method set_pid (line 56) | def set_pid(self, pid):
    method get_pid (line 59) | def get_pid(self):
    method get_response (line 62) | def get_response(self):
    method set_response (line 65) | def set_response(self, response):
    method get_time_limit (line 68) | def get_time_limit(self):
    method set_time_limit (line 71) | def set_time_limit(self, time_limit):
  class LLMRequestProcess (line 75) | class LLMRequestProcess(AgentProcess):
  class AgentProcessFactory (line 78) | class AgentProcessFactory:
    method __init__ (line 79) | def __init__(self, agent_process_log_mode = None):
    method activate_agent_process (line 94) | def activate_agent_process(self, agent_name, query):
    method print_agent_process (line 108) | def print_agent_process(self):
    method print (line 122) | def print(self, headers, data):
    method format_row (line 137) | def format_row(self, row, widths, align="<"):
    method deactivate_agent_process (line 141) | def deactivate_agent_process(self, pid):
    method start (line 145) | def start(self):
    method stop (line 149) | def stop(self):

FILE: pyopenagi/agents/base_agent.py
  class CustomizedThread (line 21) | class CustomizedThread(Thread):
    method __init__ (line 22) | def __init__(self, target, args=()):
    method run (line 28) | def run(self):
    method join (line 31) | def join(self):
  class BaseAgent (line 35) | class BaseAgent:
    method __init__ (line 36) | def __init__(self,
    method run (line 72) | def run(self):
    method build_system_instruction (line 77) | def build_system_instruction(self):
    method check_workflow (line 80) | def check_workflow(self, message):
    method automatic_workflow (line 96) | def automatic_workflow(self):
    method manual_workflow (line 128) | def manual_workflow(self):
    method check_path (line 131) | def check_path(self, tool_calls):
    method snake_to_camel (line 147) | def snake_to_camel(self, snake_str):
    method load_tools (line 151) | def load_tools(self, tool_names):
    method pre_select_tools (line 166) | def pre_select_tools(self, tool_names):
    method setup_logger (line 176) | def setup_logger(self):
    method load_config (line 180) | def load_config(self):
    method get_response (line 189) | def get_response(self,
    method query_loop (line 198) | def query_loop(self, query):
    method create_agent_request (line 238) | def create_agent_request(self, query):
    method listen (line 247) | def listen(self, agent_process: AgentProcess):
    method set_aid (line 261) | def set_aid(self, aid):
    method get_aid (line 264) | def get_aid(self):
    method get_agent_name (line 267) | def get_agent_name(self):
    method set_status (line 270) | def set_status(self, status):
    method get_status (line 277) | def get_status(self):
    method set_created_time (line 280) | def set_created_time(self, time):
    method get_created_time (line 283) | def get_created_time(self):
    method set_start_time (line 286) | def set_start_time(self, time):
    method get_start_time (line 289) | def get_start_time(self):
    method set_end_time (line 292) | def set_end_time(self, time):
    method get_end_time (line 295) | def get_end_time(self):

FILE: pyopenagi/agents/call_core.py
  class CustomizedThread (line 9) | class CustomizedThread(Thread):
    method __init__ (line 10) | def __init__(self, target, args=()):
    method run (line 16) | def run(self):
    method join (line 19) | def join(self):
  class CallCore (line 24) | class CallCore:
    method __init__ (line 28) | def __init__(self,
    method get_response (line 39) | def get_response(self,
    method query_loop (line 48) | def query_loop(self, query):
    method create_agent_request (line 88) | def create_agent_request(self, query):
    method listen (line 97) | def listen(self, agent_process: AgentProcess):
    method setup_logger (line 111) | def setup_logger(self):

FILE: pyopenagi/agents/example/academic_agent/agent.py
  class AcademicAgent (line 5) | class AcademicAgent(ReactAgent):
    method __init__ (line 6) | def __init__(self, agent_name, task_input, agent_process_factory, log_...
    method check_path (line 13) | def check_path(self, tool_calls):
    method manual_workflow (line 33) | def manual_workflow(self):
    method run (line 45) | def run(self):

FILE: pyopenagi/agents/example/cocktail_mixlogist/agent.py
  class CocktailMixlogist (line 3) | class CocktailMixlogist(ReactAgent):
    method __init__ (line 4) | def __init__(self,
    method check_path (line 14) | def check_path(self, tool_calls):
    method manual_workflow (line 30) | def manual_workflow(self):
    method run (line 47) | def run(self):

FILE: pyopenagi/agents/example/cook_therapist/agent.py
  class CookTherapist (line 3) | class CookTherapist(ReactAgent):
    method __init__ (line 4) | def __init__(self,
    method check_path (line 14) | def check_path(self, tool_calls):
    method manual_workflow (line 30) | def manual_workflow(self):
    method run (line 51) | def run(self):

FILE: pyopenagi/agents/example/creation_agent/agent.py
  class CreationAgent (line 3) | class CreationAgent(ReactAgent):
    method __init__ (line 4) | def __init__(self,
    method check_path (line 14) | def check_path(self, tool_calls):
    method manual_workflow (line 30) | def manual_workflow(self):
    method run (line 55) | def run(self):

FILE: pyopenagi/agents/example/fashion_stylist/agent.py
  class FashionStylist (line 3) | class FashionStylist(ReactAgent):
    method __init__ (line 4) | def __init__(self,
    method check_path (line 14) | def check_path(self, tool_calls):
    method manual_workflow (line 30) | def manual_workflow(self):
    method run (line 59) | def run(self):

FILE: pyopenagi/agents/example/festival_card_designer/agent.py
  class FestivalCardDesigner (line 3) | class FestivalCardDesigner(ReactAgent):
    method __init__ (line 4) | def __init__(self,
    method automatic_workflow (line 13) | def automatic_workflow(self):
    method check_path (line 16) | def check_path(self, tool_calls):
    method manual_workflow (line 32) | def manual_workflow(self):
    method run (line 53) | def run(self):

FILE: pyopenagi/agents/example/fitness_trainer/agent.py
  class FitnessTrainer (line 3) | class FitnessTrainer(ReactAgent):
    method __init__ (line 4) | def __init__(self,
    method automatic_workflow (line 13) | def automatic_workflow(self):
    method check_path (line 16) | def check_path(self, tool_calls):
    method manual_workflow (line 32) | def manual_workflow(self):
    method run (line 57) | def run(self):

FILE: pyopenagi/agents/example/game_agent/agent.py
  class GameAgent (line 3) | class GameAgent(ReactAgent):
    method __init__ (line 4) | def __init__(self,
    method automatic_workflow (line 13) | def automatic_workflow(self):
    method manual_workflow (line 16) | def manual_workflow(self):
    method run (line 33) | def run(self):

FILE: pyopenagi/agents/example/interior_decorator/agent.py
  class InteriorDecorator (line 3) | class InteriorDecorator(ReactAgent):
    method __init__ (line 4) | def __init__(self,
    method check_path (line 14) | def check_path(self, tool_calls):
    method manual_workflow (line 30) | def manual_workflow(self):
    method run (line 52) | def run(self):

FILE: pyopenagi/agents/example/language_tutor/agent.py
  class LanguageTutor (line 3) | class LanguageTutor(ReactAgent):
    method __init__ (line 4) | def __init__(self,
    method check_path (line 14) | def check_path(self, tool_calls):
    method manual_workflow (line 30) | def manual_workflow(self):
    method run (line 55) | def run(self):

FILE: pyopenagi/agents/example/logo_creator/agent.py
  class LogoCreator (line 3) | class LogoCreator(ReactAgent):
    method __init__ (line 4) | def __init__(self,
    method check_path (line 13) | def check_path(self, tool_calls):
    method automatic_workflow (line 29) | def automatic_workflow(self):
    method manual_workflow (line 32) | def manual_workflow(self):
    method run (line 49) | def run(self):

FILE: pyopenagi/agents/example/math_agent/agent.py
  class MathAgent (line 3) | class MathAgent(ReactAgent):
    method __init__ (line 4) | def __init__(self,
    method automatic_workflow (line 12) | def automatic_workflow(self):
    method manual_workflow (line 15) | def manual_workflow(self):
    method run (line 33) | def run(self):

FILE: pyopenagi/agents/example/meme_creator/agent.py
  class MemeCreator (line 3) | class MemeCreator(ReactAgent):
    method __init__ (line 4) | def __init__(self,
    method automatic_workflow (line 13) | def automatic_workflow(self):
    method check_path (line 16) | def check_path(self, tool_calls):
    method manual_workflow (line 32) | def manual_workflow(self):
    method run (line 49) | def run(self):

FILE: pyopenagi/agents/example/music_composer/agent.py
  class MusicComposer (line 3) | class MusicComposer(ReactAgent):
    method __init__ (line 4) | def __init__(self,
    method manual_workflow (line 14) | def manual_workflow(self):
    method run (line 39) | def run(self):

FILE: pyopenagi/agents/example/plant_care_assistant/agent.py
  class PlantCareAssistant (line 3) | class PlantCareAssistant(ReactAgent):
    method __init__ (line 4) | def __init__(self,
    method automatic_workflow (line 13) | def automatic_workflow(self):
    method manual_workflow (line 16) | def manual_workflow(self):
    method run (line 37) | def run(self):

FILE: pyopenagi/agents/example/rag_agent/agent.py
  class RAGAgent (line 21) | class RAGAgent(BaseAgent):
    method __init__ (line 22) | def __init__(self,
    method run (line 32) | def run(self):
    method retrive (line 75) | def retrive(self, query: str):
    method create_db_if_not_exists (line 97) | def create_db_if_not_exists(self):
    method build_prompt (line 113) | def build_prompt(self, context_str: str, query_str: str):

FILE: pyopenagi/agents/example/rec_agent/agent.py
  class RecAgent (line 4) | class RecAgent(ReactAgent):
    method __init__ (line 5) | def __init__(self,
    method automatic_workflow (line 13) | def automatic_workflow(self):
    method manual_workflow (line 16) | def manual_workflow(self):
    method run (line 29) | def run(self):

FILE: pyopenagi/agents/example/story_teller/agent.py
  class StoryTeller (line 4) | class StoryTeller(ReactAgent):
    method __init__ (line 5) | def __init__(self,
    method manual_workflow (line 15) | def manual_workflow(self):
    method check_path (line 40) | def check_path(self, tool_calls):
    method run (line 56) | def run(self):

FILE: pyopenagi/agents/example/tech_support_agent/agent.py
  class TechSupportAgent (line 3) | class TechSupportAgent(ReactAgent):
    method __init__ (line 4) | def __init__(self,
    method automatic_workflow (line 13) | def automatic_workflow(self):
    method manual_workflow (line 16) | def manual_workflow(self):
    method run (line 33) | def run(self):

FILE: pyopenagi/agents/example/transcribe_agent/agent.py
  class TranscribeAgent (line 2) | class TranscribeAgent(ReactAgent):
    method __init__ (line 3) | def __init__(self,
    method manual_workflow (line 11) | def manual_workflow(self):
    method run (line 24) | def run(self):

FILE: pyopenagi/agents/example/travel_agent/agent.py
  class TravelAgent (line 2) | class TravelAgent(ReactAgent):
    method __init__ (line 3) | def __init__(self,
    method automatic_workflow (line 11) | def automatic_workflow(self):
    method manual_workflow (line 14) | def manual_workflow(self):
    method run (line 63) | def run(self):

FILE: pyopenagi/agents/example/travel_planner_agent/agent.py
  class TravelPlannerAgent (line 27) | class TravelPlannerAgent(ReactAgent):
    method __init__ (line 32) | def __init__(self,
    method automatic_workflow (line 65) | def automatic_workflow(self):
    method manual_workflow (line 68) | def manual_workflow(self):
    method run (line 71) | def run(self):
    method build_system_instruction (line 191) | def build_system_instruction(self):
    method build_planner_instruction (line 199) | def build_planner_instruction(self, query: str, text: str) -> None:
    method is_halted (line 206) | def is_halted(self) -> bool:
    method is_finished (line 209) | def is_finished(self) -> bool:
    method action_dispatch (line 212) | def action_dispatch(self, action_type: str, action_arg: str) -> None:
    method load_city (line 275) | def load_city(self, city_set_path: str) -> Set[str]:
    method __reset_record (line 284) | def __reset_record(self) -> None:
  function parse_action (line 289) | def parse_action(string: str):
  function validate_date_format (line 313) | def validate_date_format(date_list: List[str]) -> bool:
  function valid_city_format (line 321) | def valid_city_format(city_list: List[str], city_set: Set[str]) -> bool:
  function to_string (line 325) | def to_string(data) -> str:

FILE: pyopenagi/agents/interact.py
  class Interactor (line 14) | class Interactor:
    method __init__ (line 15) | def __init__(self):
    method list_available_agents (line 20) | def list_available_agents(self) -> list[dict]:
    method download_agent (line 32) | def download_agent(self, agent: str) -> None:
    method upload_agent (line 71) | def upload_agent(self, agent) -> None:
    method minify_python_code (line 123) | def minify_python_code(self, agent_dir):
    method minify_reqs (line 135) | def minify_reqs(self, agent_dir):
    method minify_config (line 144) | def minify_config(self, config_data):
    method compress (line 148) | def compress(self, minified_data):
    method decompress (line 155) | def decompress(self, encoded_data):
    method download_config (line 162) | def download_config(self, config_data, agent) :
    method download_reqs (line 168) | def download_reqs(self, reqs_data, agent):
    method download_code (line 176) | def download_code(self, code_data, agent):
    method check_reqs_installed (line 182) | def check_reqs_installed(self, agent):
    method install_agent_reqs (line 214) | def install_agent_reqs(self, agent):
  function parse_args (line 229) | def parse_args():

FILE: pyopenagi/agents/om-raheja/transcribe_agent/agent.py
  class TranscribeAgent (line 2) | class TranscribeAgent(ReactAgent):
    method __init__ (line 3) | def __init__(self,
    method manual_workflow (line 11) | def manual_workflow(self):
    method run (line 13) | def run(self):

FILE: pyopenagi/agents/react_agent.py
  class ReactAgent (line 10) | class ReactAgent(BaseAgent):
    method __init__ (line 11) | def __init__(self,
    method build_system_instruction (line 28) | def build_system_instruction(self):
    method automatic_workflow (line 70) | def automatic_workflow(self):
    method manual_workflow (line 73) | def manual_workflow(self):
    method call_tools (line 76) | def call_tools(self, tool_calls):
    method run (line 101) | def run(self):

FILE: pyopenagi/manager/manager.py
  class AgentManager (line 12) | class AgentManager:
    method __init__ (line 13) | def __init__(self, base_url: str):
    method upload_agent (line 19) | def upload_agent(self, author: str | None, name: str | None, version: ...
    method download_agent (line 38) | def download_agent(self, author: str, name: str, version: str = "lates...
    method _get_agent_files (line 59) | def _get_agent_files(self, folder_path: str) -> List[Dict[str, str]]:
    method _get_agent_metadata (line 73) | def _get_agent_metadata(self, folder_path: str) -> Dict[str, str]:
    method _get_cache_path (line 80) | def _get_cache_path(self, author: str, name: str, version: str) -> Path:
    method _save_agent_to_cache (line 83) | def _save_agent_to_cache(self, agent_data: Dict, cache_path: Path):
    method list_available_agents (line 91) | def list_available_agents(self) -> List[Dict[str, str]]:
    method check_agent_updates (line 96) | def check_agent_updates(self, author: str, name: str, current_version:...
    method check_reqs_installed (line 105) | def check_reqs_installed(self, agent_path: Path) -> bool:
    method install_agent_reqs (line 123) | def install_agent_reqs(self, agent_path: Path):

FILE: pyopenagi/queues/base_queue.py
  class BaseQueue (line 3) | class BaseQueue:
    method add_message (line 8) | def add_message(cls, message):
    method get_message (line 12) | def get_message(cls):
    method is_empty (line 16) | def is_empty(cls):

FILE: pyopenagi/queues/llm_request_queue.py
  class LLMRequestQueue (line 3) | class LLMRequestQueue(BaseQueue):

FILE: pyopenagi/tools/arxiv/arxiv.py
  class Arxiv (line 9) | class Arxiv(BaseTool):
    method __init__ (line 36) | def __init__(self):
    method is_arxiv_identifier (line 45) | def is_arxiv_identifier(self, query: str) -> bool:
    method build_client (line 57) | def build_client(self):
    method run (line 62) | def run(self, params) -> str:
    method get_tool_call_format (line 100) | def get_tool_call_format(self):

FILE: pyopenagi/tools/base.py
  class BaseTool (line 1) | class BaseTool:
    method __init__ (line 4) | def __init__(self) -> None:
    method run (line 7) | def run(self, params) -> None:
    method get_tool_call_format (line 10) | def get_tool_call_format(self) -> dict:
  class BaseRapidAPITool (line 15) | class BaseRapidAPITool(BaseTool):
    method __init__ (line 18) | def __init__(self):
    method run (line 24) | def run(self, params: dict):
    method get_tool_call_format (line 27) | def get_tool_call_format(self) -> dict:
  class BaseHuggingfaceTool (line 31) | class BaseHuggingfaceTool(BaseTool):
    method __init__ (line 35) | def __init__(self):
    method run (line 41) | def run(self, params: dict):
    method get_tool_call_format (line 44) | def get_tool_call_format(self) -> dict:

FILE: pyopenagi/tools/bing/bing_search.py
  class BingSearch (line 10) | class BingSearch(BaseTool):
    method __init__ (line 15) | def __init__(self):
    method _bing_search_results (line 22) | def _bing_search_results(self, search_term: str, count: int) -> List[d...
    method run (line 42) | def run(self, query: str) -> str:
    method parse_result (line 48) | def parse_result(self, response):

FILE: pyopenagi/tools/currency_converter/currency_converter.py
  class CurrencyConverter (line 7) | class CurrencyConverter(BaseRapidAPITool):
    method __init__ (line 8) | def __init__(self):
    method run (line 14) | def run(self, params: dict):
    method parse_result (line 36) | def parse_result(self, response) -> str:
    method get_tool_call_format (line 51) | def get_tool_call_format(self):

FILE: pyopenagi/tools/google/google_places.py
  class GooglePlaces (line 9) | class GooglePlaces(BaseTool):
    method __init__ (line 28) | def __init__(self):
    method build_client (line 34) | def build_client(self):
    method run (line 47) | def run(self, query: str) -> str:
    method fetch_place_details (line 72) | def fetch_place_details(self, place_id: str) -> Optional[str]:
    method format_place_details (line 82) | def format_place_details(self, place_details: Dict[str, Any]) -> Optio...

FILE: pyopenagi/tools/google/google_search.py
  class GoogleSearch (line 7) | class GoogleSearch(BaseTool):
    method __init__ (line 44) | def __init__(self):
    method build_engine (line 52) | def build_engine(self):
    method _google_search_results (line 65) | def _google_search_results(self, search_term: str, **kwargs: Any) -> L...
    method run (line 73) | def run(self, params: dict) -> str:
    method parse_result (line 83) | def parse_result(self, response):
    method get_tool_call_format (line 93) | def get_tool_call_format(self):

FILE: pyopenagi/tools/imdb/top_movie.py
  class TopMovieAPI (line 11) | class TopMovieAPI(BaseRapidAPITool):
    method __init__ (line 12) | def __init__(self):
    method run (line 19) | def run(self, params):
    method parse_result (line 31) | def parse_result(self, response, start, end) -> str:
    method get_tool_call_format (line 40) | def get_tool_call_format(self):

FILE: pyopenagi/tools/imdb/top_movies.py
  class TopMovies (line 9) | class TopMovies(BaseRapidAPITool):
    method __init__ (line 10) | def __init__(self):
    method run (line 17) | def run(self, params):
    method parse_result (line 29) | def parse_result(self, response, start, end) -> str:
    method get_tool_call_format (line 38) | def get_tool_call_format(self):

FILE: pyopenagi/tools/imdb/top_series.py
  class TopSeries (line 7) | class TopSeries(BaseRapidAPITool):
    method __init__ (line 8) | def __init__(self):
    method run (line 15) | def run(self, params):
    method parse_result (line 27) | def parse_result(self, response, start, end) -> str:
    method get_tool_call_format (line 35) | def get_tool_call_format(self):

FILE: pyopenagi/tools/impira/doc_question_answering.py
  class DocQuestionAnswering (line 9) | class DocQuestionAnswering(BaseHuggingfaceTool):
    method __init__ (line 10) | def __init__(self):
    method run (line 13) | def run(self, params):
    method get_tool_call_format (line 35) | def get_tool_call_format(self):

FILE: pyopenagi/tools/meteosource_weather/find_place.py
  class SongAutocompleteAPI (line 9) | class SongAutocompleteAPI(BaseRapidAPITool):
    method __init__ (line 10) | def __init__(self):
    method run (line 17) | def run(self, params):
    method parse_result (line 38) | def parse_result(self, response) -> str:

FILE: pyopenagi/tools/moonphase/moon_phase_search.py
  class MoonPhaseSearch (line 7) | class MoonPhaseSearch(BaseRapidAPITool):
    method __init__ (line 8) | def __init__(self):
    method run (line 14) | def run(self):
    method parse_result (line 24) | def parse_result(self, response) -> str:

FILE: pyopenagi/tools/openai/speech_to_text.py
  class SpeechToText (line 9) | class SpeechToText(BaseHuggingfaceTool):
    method __init__ (line 10) | def __init__(self):
    method run (line 13) | def run(self, params):
    method get_tool_call_format (line 24) | def get_tool_call_format(self):

FILE: pyopenagi/tools/shazam/song_auto_complete.py
  class SongAutoComplete (line 9) | class SongAutoComplete(BaseRapidAPITool):
    method __init__ (line 10) | def __init__(self):
    method run (line 17) | def run(self, params):
    method parse_result (line 38) | def parse_result(self, response) -> str:

FILE: pyopenagi/tools/stability-ai/sdxl_turbo.py
  class SdxlTurbo (line 6) | class SdxlTurbo(BaseHuggingfaceTool):
    method __init__ (line 7) | def __init__(self):
    method run (line 11) | def run(self, params):
    method get_tool_call_format (line 17) | def get_tool_call_format(self):

FILE: pyopenagi/tools/stability-ai/text_to_image.py
  class TextToImage (line 7) | class TextToImage(BaseHuggingfaceTool):
    method __init__ (line 8) | def __init__(self):
    method run (line 11) | def run(self, params):
    method get_tool_call_format (line 35) | def get_tool_call_format(self):

FILE: pyopenagi/tools/suno/text_to_speech.py
  class TextToSpeech (line 7) | class TextToSpeech(BaseHuggingfaceTool):
    method __init__ (line 8) | def __init__(self):
    method run (line 11) | def run(self, params):
    method get_tool_call_format (line 30) | def get_tool_call_format(self):

FILE: pyopenagi/tools/timbrooks/image_to_image.py
  class ImageToImage (line 7) | class ImageToImage(BaseHuggingfaceTool):
    method __init__ (line 8) | def __init__(self):
    method run (line 15) | def run(self, params):
    method get_tool_call_format (line 24) | def get_tool_call_format(self):

FILE: pyopenagi/tools/transcriber/transcriber.py
  class Transcriber (line 4) | class Transcriber(BaseTool):
    method __init__ (line 5) | def __init__(self):
    method run (line 19) | def run(self, params: dict):
    method get_tool_call_format (line 34) | def get_tool_call_format(self):

FILE: pyopenagi/tools/travel_planner/accommodations.py
  class Accommodations (line 8) | class Accommodations(BaseTool):
    method __init__ (line 9) | def __init__(self, path="../../environments/travelPlanner/accommodatio...
    method load_db (line 17) | def load_db(self):
    method run (line 20) | def run(self,
    method get_tool_call_format (line 30) | def get_tool_call_format(self):

FILE: pyopenagi/tools/travel_planner/attractions.py
  class Attractions (line 8) | class Attractions(BaseTool):
    method __init__ (line 9) | def __init__(self, path="../../environments/travelPlanner/attractions/...
    method load_db (line 16) | def load_db(self):
    method run (line 19) | def run(self,
    method get_tool_call_format (line 30) | def get_tool_call_format(self):

FILE: pyopenagi/tools/travel_planner/cities.py
  class Cities (line 6) | class Cities(BaseTool):
    method __init__ (line 7) | def __init__(self, path="../../environments/travelPlanner/background/c...
    method load_data (line 13) | def load_data(self):
    method run (line 23) | def run(self, state) -> dict:
    method get_tool_call_format (line 29) | def get_tool_call_format(self):

FILE: pyopenagi/tools/travel_planner/flights.py
  class Flights (line 8) | class Flights(BaseTool):
    method __init__ (line 10) | def __init__(self, path="../../environments/travelPlanner/flights/clea...
    method load_db (line 18) | def load_db(self):
    method run (line 21) | def run(self,
    method get_tool_call_format (line 35) | def get_tool_call_format(self):

FILE: pyopenagi/tools/travel_planner/google_distance_matrix.py
  class GoogleDistanceMatrix (line 14) | class GoogleDistanceMatrix(BaseTool):
    method __init__ (line 15) | def __init__(self, path="../../environments/travelPlanner/googleDistan...
    method run (line 23) | def run(self, origin, destination, mode='driving'):
    method get_tool_call_format (line 44) | def get_tool_call_format(self):
  function extract_before_parenthesis (line 55) | def extract_before_parenthesis(s):

FILE: pyopenagi/tools/travel_planner/notebook.py
  class Notebook (line 7) | class Notebook(BaseTool):
    method __init__ (line 8) | def __init__(self) -> None:
    method run (line 11) | def run(self, input_data: DataFrame, short_description: str):
    method update (line 15) | def update(self, input_data: DataFrame, index: int, short_decription: ...
    method list (line 21) | def list(self):
    method list_all (line 28) | def list_all(self):
    method read (line 40) | def read(self, index):
    method reset (line 43) | def reset(self):
    method get_tool_call_format (line 46) | def get_tool_call_format(self):

FILE: pyopenagi/tools/travel_planner/restaurants.py
  class Restaurants (line 8) | class Restaurants(BaseTool):
    method __init__ (line 9) | def __init__(self, path="../../environments/travelPlanner/restaurants/...
    method load_db (line 16) | def load_db(self):
    method run (line 19) | def run(self,
    method get_tool_call_format (line 29) | def get_tool_call_format(self):

FILE: pyopenagi/tools/trip_advisor/airport_search.py
  class AirportSearch (line 9) | class AirportSearch(BaseRapidAPITool):
    method __init__ (line 10) | def __init__(self):
    method run (line 16) | def run(self, params: dict):
    method parse_result (line 36) | def parse_result(self, response) -> str:
    method get_tool_call_format (line 50) | def get_tool_call_format(self):

FILE: pyopenagi/tools/trip_advisor/flight_search.py
  class FlightSearch (line 9) | class FlightSearch(BaseRapidAPITool):
    method __init__ (line 10) | def __init__(self):
    method run (line 16) | def run(self, params: dict):
    method parse_result (line 48) | def parse_result(self, response) -> str:
    method get_tool_call_format (line 78) | def get_tool_call_format(self):

FILE: pyopenagi/tools/trip_advisor/get_hotel_details.py
  class GetHotelDetails (line 9) | class GetHotelDetails(BaseRapidAPITool):
    method __init__ (line 10) | def __init__(self):
    method run (line 16) | def run(self, params: dict):
    method parse_result (line 40) | def parse_result(self, response) -> str:
    method get_tool_call_format (line 66) | def get_tool_call_format(self):

FILE: pyopenagi/tools/trip_advisor/get_restaurant_details.py
  class GetRestaurantDetails (line 9) | class GetRestaurantDetails(BaseRapidAPITool):
    method __init__ (line 10) | def __init__(self):
    method run (line 16) | def run(self, params: dict):
    method parse_result (line 36) | def parse_result(self, response) -> str:
    method get_tool_call_format (line 54) | def get_tool_call_format(self):

FILE: pyopenagi/tools/trip_advisor/hotel_location_search.py
  class HotelLocationSearch (line 9) | class HotelLocationSearch(BaseRapidAPITool):
    method __init__ (line 10) | def __init__(self):
    method run (line 16) | def run(self, params: dict):
    method parse_result (line 36) | def parse_result(self, response) -> str:
    method get_tool_call_format (line 39) | def get_tool_call_format(self):

FILE: pyopenagi/tools/trip_advisor/hotel_search.py
  class HotelSearch (line 9) | class HotelSearch(BaseRapidAPITool):
    method __init__ (line 10) | def __init__(self):
    method run (line 16) | def run(self, params: dict):
    method parse_result (line 41) | def parse_result(self, response) -> str:
    method get_tool_call_format (line 59) | def get_tool_call_format(self):

FILE: pyopenagi/tools/trip_advisor/restaurant_location_search.py
  class RestaurantLocationSearch (line 9) | class RestaurantLocationSearch(BaseRapidAPITool):
    method __init__ (line 10) | def __init__(self):
    method run (line 16) | def run(self, params: dict):
    method parse_result (line 36) | def parse_result(self, response) -> str:
    method get_tool_call_format (line 51) | def get_tool_call_format(self):

FILE: pyopenagi/tools/trip_advisor/restaurant_search.py
  class RestaurantSearch (line 11) | class RestaurantSearch(BaseRapidAPITool):
    method __init__ (line 12) | def __init__(self):
    method run (line 18) | def run(self, params: dict):
    method parse_result (line 38) | def parse_result(self, response) -> str:
    method get_tool_call_format (line 55) | def get_tool_call_format(self):

FILE: pyopenagi/tools/wikipedia/wikipedia.py
  class Wikipedia (line 4) | class Wikipedia(BaseTool):
    method __init__ (line 13) | def __init__(self):
    method build_client (line 22) | def build_client(self):
    method run (line 35) | def run(self, params) -> str:
    method _formatted_page_summary (line 52) | def _formatted_page_summary(page_title: str, wiki_page: Any) -> Option...
    method get_tool_call_format (line 55) | def get_tool_call_format(self):

FILE: pyopenagi/tools/wolfram/wolfram_alpha.py
  class WolframAlpha (line 4) | class WolframAlpha(BaseTool):
    method __init__ (line 15) | def __init__(self):
    method build_client (line 20) | def build_client(self):
    method run (line 32) | def run(self, query: str) -> str:
    method get_tool_call_format (line 49) | def get_tool_call_format(self):

FILE: pyopenagi/tools/words_api/words_api.py
  class WordsAPI (line 19) | class WordsAPI(BaseRapidAPITool):
    method __init__ (line 20) | def __init__(self):
    method run (line 27) | def run(self, params):
    method parse_result (line 51) | def parse_result(self, response) -> str:
    method is_supported (line 58) | def is_supported(self, api_name):

FILE: pyopenagi/utils/chat_template.py
  class Query (line 1) | class Query:
    method __init__ (line 2) | def __init__(self,
  class Response (line 20) | class Response:
    method __init__ (line 21) | def __init__(

FILE: pyopenagi/utils/compressor.py
  class Compressor (line 3) | class Compressor:
    method __init__ (line 4) | def __init__(self) -> None:
    method compress (line 7) | def compress(self, data):
    method decompress (line 10) | def decompress(self, compressed_data):
  class ZLIBCompressor (line 13) | class ZLIBCompressor(Compressor):
    method __init__ (line 14) | def __init__(self) -> None:
    method compress (line 17) | def compress(self, data):
    method decompress (line 21) | def decompress(self, compressed_data):

FILE: pyopenagi/utils/logger.py
  class BaseLogger (line 7) | class BaseLogger:
    method __init__ (line 8) | def __init__(self,
    method log (line 18) | def log(self, content, level):
    method load_log_file (line 25) | def load_log_file(self):
    method log_to_console (line 28) | def log_to_console(self, content, level):
    method log_to_file (line 32) | def log_to_file(self, content, log_file):
  class SchedulerLogger (line 36) | class SchedulerLogger(BaseLogger):
    method __init__ (line 37) | def __init__(self, logger_name, log_mode="console") -> None:
    method load_log_file (line 45) | def load_log_file(self):
  class AgentLogger (line 54) | class AgentLogger(BaseLogger):
    method __init__ (line 55) | def __init__(self, logger_name, log_mode="console") -> None:
    method load_log_file (line 64) | def load_log_file(self):
  class LLMKernelLogger (line 73) | class LLMKernelLogger(BaseLogger):
    method __init__ (line 74) | def __init__(self, logger_name, log_mode="console") -> None:
    method log_to_console (line 83) | def log_to_console(self, content, level):
    method load_log_file (line 87) | def load_log_file(self):

FILE: pyopenagi/utils/utils.py
  function parse_global_args (line 15) | def parse_global_args():
  function extract_before_parenthesis (line 26) | def extract_before_parenthesis(s: str) -> str:
  function get_from_dict_or_env (line 30) | def get_from_dict_or_env(
  function get_from_env (line 40) | def get_from_env(env_key: str, default: Optional[str] = None) -> str:
  class Logger (line 52) | class Logger:
    method __init__ (line 53) | def __init__(self, log_mode) -> None:
    method log (line 56) | def log(self, info, path=None):
  function delete_directories (line 64) | def delete_directories(root_dir, target_dirs):

FILE: tests/test_agent_creation.py
  function test_agent_creation (line 6) | def test_agent_creation():

FILE: tests/test_tools/test_currency_converter.py
  function test_rapid_api_key (line 8) | def test_rapid_api_key():
  function test_currency_converter_api (line 18) | def test_currency_converter_api():

FILE: tests/test_tools/test_top_series.py
  function test_rapid_api_key (line 11) | def test_rapid_api_key():
  class ImdbTopSeriesMock (line 20) | class ImdbTopSeriesMock:
    method json (line 22) | def json():
  function mock_response (line 59) | def mock_response(monkeypatch):
  function test_top_series_api_valid_input_outputs_valid_delimiter_count (line 75) | def test_top_series_api_valid_input_outputs_valid_delimiter_count(
  function test_top_series_api_reverse_range_returns_blank (line 86) | def test_top_series_api_reverse_range_returns_blank():
  function test_top_series_api_invalid_start_type_raises_typeerror (line 104) | def test_top_series_api_invalid_start_type_raises_typeerror(invalid_star...
  function test_top_series_api_invalid_end_type_raises_typeerror (line 122) | def test_top_series_api_invalid_end_type_raises_typeerror(invalid_start,...
  function test_top_series_api_invalid_start_count_raises_indexerror (line 130) | def test_top_series_api_invalid_start_count_raises_indexerror():
  function test_top_series_api_invalid_end_count_raises_indexerror (line 138) | def test_top_series_api_invalid_end_count_raises_indexerror():

FILE: tests/test_tools/test_wolfram_alpha.py
  function test_wolfram_alpha_id (line 8) | def test_wolfram_alpha_id():
  function test_wolfram_alpha (line 18) | def test_wolfram_alpha():

FILE: tests/test_tools/test_words_api.py
  function test_rapid_api_key (line 8) | def test_rapid_api_key():
  function test_words_api (line 16) | def test_words_api():
Condensed preview — 179 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (529K chars).
[
  {
    "path": ".github/ISSUE_TEMPLATE/001-report-bug.yml",
    "chars": 1184,
    "preview": "name: Bug report\ndescription: Raise an issue here if you find a bug.\ntitle: \"[Bug] \"\nlabels: [\"bug\"]\n\nbody:\n- type: chec"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/002-feature-request.yml",
    "chars": 1341,
    "preview": "name: Feature request\ndescription: Submit a proposal/request for a new aios feature\ntitle: \"[Feature] \"\nlabels: [\"featur"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/003-misc-discussion.yml",
    "chars": 537,
    "preview": "name: Misc/random discussions that do not fit into the above categories.\ndescription: Submit a discussion as you like. N"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 1935,
    "preview": "Thank you for your contribution to OpenAGI!\nBefore submitting the pull request, please ensure **the PR meets the followi"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 429,
    "preview": "name: CI\n\non:\n  [push,pull_request]\n\njobs:\n  run-pytest:\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/chec"
  },
  {
    "path": ".github/workflows/publish.yml",
    "chars": 638,
    "preview": "name: Publish Python Package\n\non:\n  push:\n    tags:\n      - \"v*\"\n\njobs:\n  deploy:\n    runs-on: ubuntu-latest\n\n    enviro"
  },
  {
    "path": ".gitignore",
    "chars": 284,
    "preview": ".idea/\n.vscode/\n\n.DS_Store\n\n# Ignore Python compiled files\n__pycache__/\n*.py[cod]\n\n# Ignore Mac system files\n.DS_Store\n\n"
  },
  {
    "path": ".pre-commit-config.yaml",
    "chars": 212,
    "preview": "repos:\n-   repo: https://github.com/pre-commit/pre-commit-hooks\n    rev: v3.2.0\n    hooks:\n    -   id: trailing-whitespa"
  },
  {
    "path": "CONTRIBUTE.md",
    "chars": 4351,
    "preview": "# How to contribute to OpenAGI\nThank you for your interest in OpenAGI!\nHere's a guide to help you contribute to this pro"
  },
  {
    "path": "LICENSE",
    "chars": 1069,
    "preview": "MIT License\n\nCopyright (c) 2024 AGI Research\n\nPermission is hereby granted, free of charge, to any person obtaining a co"
  },
  {
    "path": "README.md",
    "chars": 3246,
    "preview": "# OpenAGI: Package for AI Agent Creation\n<a href='https://arxiv.org/abs/2304.04370'><img src='https://img.shields.io/bad"
  },
  {
    "path": "pyopenagi/README.md",
    "chars": 300,
    "preview": "# pyopenagi\n\nThe internal implementation for OpenAGI.\n\n1. `agents/` contains the agent implementation all future agents "
  },
  {
    "path": "pyopenagi/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "pyopenagi/agents/README.md",
    "chars": 465,
    "preview": "# pyopenagi/agents\nThis folder contains the base implementation for running the agents, as well as the handlers for runn"
  },
  {
    "path": "pyopenagi/agents/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "pyopenagi/agents/agent_factory.py",
    "chars": 4460,
    "preview": "from threading import Lock\nfrom pympler import asizeof\nfrom .interact import Interactor\nimport os\nimport importlib\nimpor"
  },
  {
    "path": "pyopenagi/agents/agent_process.py",
    "chars": 4403,
    "preview": "from threading import Thread, Lock\n\nfrom ..utils.chat_template import Query\nimport random\nclass AgentProcess:\n    def __"
  },
  {
    "path": "pyopenagi/agents/base_agent.py",
    "chars": 9106,
    "preview": "import os\n\nimport json\n\nfrom .agent_process import (\n    AgentProcess\n)\n\nimport time\n\nfrom threading import Thread\n\nfrom"
  },
  {
    "path": "pyopenagi/agents/call_core.py",
    "chars": 3790,
    "preview": "import time\nfrom threading import Thread\n\nfrom aios.hooks.stores._global import global_llm_req_queue_add_message\nfrom .a"
  },
  {
    "path": "pyopenagi/agents/example/README.md",
    "chars": 102,
    "preview": "# pyopenagi/agents/example\n\nHere are the example agents we created to demo agent creation in OpenAGI.\n"
  },
  {
    "path": "pyopenagi/agents/example/academic_agent/agent.py",
    "chars": 1722,
    "preview": "from ...react_agent import ReactAgent\nimport os\n\n\nclass AcademicAgent(ReactAgent):\n    def __init__(self, agent_name, ta"
  },
  {
    "path": "pyopenagi/agents/example/academic_agent/config.json",
    "chars": 463,
    "preview": "{\n    \"name\": \"academic_agent\",\n    \"description\": [\n        \"You are an academic research assistant. \",\n        \"Help u"
  },
  {
    "path": "pyopenagi/agents/example/academic_agent/meta_requirements.txt",
    "chars": 5,
    "preview": "arxiv"
  },
  {
    "path": "pyopenagi/agents/example/cocktail_mixlogist/agent.py",
    "chars": 1728,
    "preview": "from ...react_agent import ReactAgent\nimport os\nclass CocktailMixlogist(ReactAgent):\n    def __init__(self,\n            "
  },
  {
    "path": "pyopenagi/agents/example/cocktail_mixlogist/config.json",
    "chars": 389,
    "preview": "{\n    \"name\": \"cocktail_mixlogist\",\n    \"description\": [\n        \"You are a virtual mixologist. \",\n        \"Create delic"
  },
  {
    "path": "pyopenagi/agents/example/cocktail_mixlogist/meta_requirements.txt",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "pyopenagi/agents/example/cook_therapist/agent.py",
    "chars": 1948,
    "preview": "from ...react_agent import ReactAgent\nimport os\nclass CookTherapist(ReactAgent):\n    def __init__(self,\n                "
  },
  {
    "path": "pyopenagi/agents/example/cook_therapist/config.json",
    "chars": 395,
    "preview": "{\n    \"name\": \"cook_therapist\",\n    \"description\": [\n        \"You are a culinary expert and recipe creator. \",\n        \""
  },
  {
    "path": "pyopenagi/agents/example/cook_therapist/meta_requirements.txt",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "pyopenagi/agents/example/creation_agent/agent.py",
    "chars": 1931,
    "preview": "from ...react_agent import ReactAgent\nimport os\nclass CreationAgent(ReactAgent):\n    def __init__(self,\n                "
  },
  {
    "path": "pyopenagi/agents/example/creation_agent/config.json",
    "chars": 340,
    "preview": "{\n    \"name\": \"creation_agent\",\n    \"description\": [\n        \"You are a social media content creator. \",\n        \"Genera"
  },
  {
    "path": "pyopenagi/agents/example/creation_agent/meta_requirements.txt",
    "chars": 37,
    "preview": "diffusers==0.27.2\naccelerate==0.30.1\n"
  },
  {
    "path": "pyopenagi/agents/example/fashion_stylist/agent.py",
    "chars": 2194,
    "preview": "from ...react_agent import ReactAgent\nimport os\nclass FashionStylist(ReactAgent):\n    def __init__(self,\n               "
  },
  {
    "path": "pyopenagi/agents/example/fashion_stylist/config.json",
    "chars": 442,
    "preview": "{\n    \"name\": \"fashion_stylist\",\n    \"description\": [\n        \"You are a fashion designer. \",\n        \"Create custom clo"
  },
  {
    "path": "pyopenagi/agents/example/fashion_stylist/meta_requirements.txt",
    "chars": 20,
    "preview": "soundfile\nwikipedia\n"
  },
  {
    "path": "pyopenagi/agents/example/festival_card_designer/agent.py",
    "chars": 1895,
    "preview": "from ...react_agent import ReactAgent\nimport os\nclass FestivalCardDesigner(ReactAgent):\n    def __init__(self,\n         "
  },
  {
    "path": "pyopenagi/agents/example/festival_card_designer/config.json",
    "chars": 380,
    "preview": "{\n    \"name\": \"festival_card_designer\",\n    \"description\": [\n        \"You are a festival card designer. \",\n        \"Crea"
  },
  {
    "path": "pyopenagi/agents/example/festival_card_designer/meta_requirements.txt",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "pyopenagi/agents/example/fitness_trainer/agent.py",
    "chars": 2154,
    "preview": "from ...react_agent import ReactAgent\nimport os\nclass FitnessTrainer(ReactAgent):\n    def __init__(self,\n               "
  },
  {
    "path": "pyopenagi/agents/example/fitness_trainer/config.json",
    "chars": 488,
    "preview": "{\n    \"name\": \"fitness_trainer\",\n    \"description\": [\n        \"You are a fitness trainer with expertise in various exerc"
  },
  {
    "path": "pyopenagi/agents/example/fitness_trainer/meta_requirements.txt",
    "chars": 16,
    "preview": "arxiv\nwikipedia\n"
  },
  {
    "path": "pyopenagi/agents/example/game_agent/agent.py",
    "chars": 1014,
    "preview": "from ...react_agent import ReactAgent\n\nclass GameAgent(ReactAgent):\n    def __init__(self,\n                 agent_name,\n"
  },
  {
    "path": "pyopenagi/agents/example/game_agent/config.json",
    "chars": 399,
    "preview": "{\n    \"name\": \"game_agent\",\n    \"description\": [\n        \"You are a video game expert. \",\n        \"Recommend games based"
  },
  {
    "path": "pyopenagi/agents/example/game_agent/meta_requirements.txt",
    "chars": 16,
    "preview": "arxiv\nwikipedia\n"
  },
  {
    "path": "pyopenagi/agents/example/interior_decorator/agent.py",
    "chars": 1955,
    "preview": "from ...react_agent import ReactAgent\nimport os\nclass InteriorDecorator(ReactAgent):\n    def __init__(self,\n            "
  },
  {
    "path": "pyopenagi/agents/example/interior_decorator/config.json",
    "chars": 480,
    "preview": "{\n    \"name\": \"interior_decorator\",\n    \"description\": [\n        \"You are a virtual interior decorator. \",\n        \"You "
  },
  {
    "path": "pyopenagi/agents/example/interior_decorator/meta_requirements.txt",
    "chars": 37,
    "preview": "diffusers==0.27.2\naccelerate==0.30.1\n"
  },
  {
    "path": "pyopenagi/agents/example/language_tutor/agent.py",
    "chars": 1995,
    "preview": "from ...react_agent import ReactAgent\nimport os\nclass LanguageTutor(ReactAgent):\n    def __init__(self,\n                "
  },
  {
    "path": "pyopenagi/agents/example/language_tutor/config.json",
    "chars": 449,
    "preview": "{\n    \"name\": \"language_tutor\",\n    \"description\": [\n        \"You are a language tutor. You can provide vocabulary exerc"
  },
  {
    "path": "pyopenagi/agents/example/language_tutor/meta_requirements.txt",
    "chars": 20,
    "preview": "soundfile\nwikipedia\n"
  },
  {
    "path": "pyopenagi/agents/example/logo_creator/agent.py",
    "chars": 1738,
    "preview": "from ...react_agent import ReactAgent\nimport os\nclass LogoCreator(ReactAgent):\n    def __init__(self,\n                 a"
  },
  {
    "path": "pyopenagi/agents/example/logo_creator/config.json",
    "chars": 378,
    "preview": "{\n    \"name\": \"logo_creator\",\n    \"description\": [\n        \"You are a logo design expert. \",\n        \"Create unique and "
  },
  {
    "path": "pyopenagi/agents/example/logo_creator/meta_requirements.txt",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "pyopenagi/agents/example/math_agent/agent.py",
    "chars": 990,
    "preview": "from ...react_agent import ReactAgent\n\nclass MathAgent(ReactAgent):\n    def __init__(self,\n                 agent_name,\n"
  },
  {
    "path": "pyopenagi/agents/example/math_agent/config.json",
    "chars": 557,
    "preview": "{\n    \"name\": \"MathAgent\",\n    \"description\": [\n        \"You are an expert who is good at solving mathematical problems."
  },
  {
    "path": "pyopenagi/agents/example/math_agent/meta_requirements.txt",
    "chars": 22,
    "preview": "wolframalpha\nwikipedia"
  },
  {
    "path": "pyopenagi/agents/example/meme_creator/agent.py",
    "chars": 1738,
    "preview": "from ...react_agent import ReactAgent\nimport os\nclass MemeCreator(ReactAgent):\n    def __init__(self,\n                 a"
  },
  {
    "path": "pyopenagi/agents/example/meme_creator/config.json",
    "chars": 323,
    "preview": "{\n    \"name\": \"meme_creator\",\n    \"description\": [\n        \"You are a meme creator. Given a topic, text, or an image, cr"
  },
  {
    "path": "pyopenagi/agents/example/meme_creator/meta_requirements.txt",
    "chars": 16,
    "preview": "arxiv\nwikipedia\n"
  },
  {
    "path": "pyopenagi/agents/example/music_composer/agent.py",
    "chars": 1297,
    "preview": "from ...react_agent import ReactAgent\n\nclass MusicComposer(ReactAgent):\n    def __init__(self,\n                 agent_na"
  },
  {
    "path": "pyopenagi/agents/example/music_composer/config.json",
    "chars": 333,
    "preview": "{\n    \"name\": \"music_composer\",\n    \"description\": [\n        \"You are an excellent music composer. \",\n        \"Your role"
  },
  {
    "path": "pyopenagi/agents/example/music_composer/meta_requirements.txt",
    "chars": 10,
    "preview": "wikipedia\n"
  },
  {
    "path": "pyopenagi/agents/example/plant_care_assistant/agent.py",
    "chars": 1129,
    "preview": "from ...react_agent import ReactAgent\n\nclass PlantCareAssistant(ReactAgent):\n    def __init__(self,\n                 age"
  },
  {
    "path": "pyopenagi/agents/example/plant_care_assistant/config.json",
    "chars": 370,
    "preview": "{\n    \"name\": \"plant_care_assistant\",\n    \"description\": [\n        \"You are a virtual plant expert. \",\n        \"Provide "
  },
  {
    "path": "pyopenagi/agents/example/plant_care_assistant/meta_requirements.txt",
    "chars": 16,
    "preview": "arxiv\nwikipedia\n"
  },
  {
    "path": "pyopenagi/agents/example/rag_agent/README.md",
    "chars": 699,
    "preview": "# src/agents/agent_config\n\nEach agent holds a config file in addition to the class specifying what to run. The agent con"
  },
  {
    "path": "pyopenagi/agents/example/rag_agent/agent.py",
    "chars": 4934,
    "preview": "from ...base_agent import BaseAgent\n\nimport time\n\nimport argparse\n\nfrom ....utils import Message\n\nfrom pathlib import Pu"
  },
  {
    "path": "pyopenagi/agents/example/rag_agent/config.json",
    "chars": 371,
    "preview": "{\n    \"name\": \"rag_agent\",\n    \"description\": [\n        \"Thou art the deity overseeing documents; when mortals inquire o"
  },
  {
    "path": "pyopenagi/agents/example/rag_agent/data/paul_graham/paul_graham_essay.txt",
    "chars": 75014,
    "preview": "\n\nWhat I Worked On\n\nFebruary 2021\n\nBefore college the two main things I worked on, outside of school, were writing and p"
  },
  {
    "path": "pyopenagi/agents/example/rag_agent/meta_requirements.txt",
    "chars": 141,
    "preview": "langchain_core==0.2.1\nllama_index==0.10.39\nllama_index.embeddings.huggingface==0.2.0\nllama-index-vector-stores-chroma==0"
  },
  {
    "path": "pyopenagi/agents/example/rec_agent/agent.py",
    "chars": 875,
    "preview": "\nfrom ...react_agent import ReactAgent\n\nclass RecAgent(ReactAgent):\n    def __init__(self,\n                 agent_name,\n"
  },
  {
    "path": "pyopenagi/agents/example/rec_agent/config.json",
    "chars": 254,
    "preview": "{\n    \"name\": \"RecAgent\",\n    \"description\": [\n        \"You are an expert who is good at recommending TV series and movi"
  },
  {
    "path": "pyopenagi/agents/example/rec_agent/meta_requirements.txt",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "pyopenagi/agents/example/story_teller/agent.py",
    "chars": 2026,
    "preview": "from ...react_agent import ReactAgent\n\nimport os\nclass StoryTeller(ReactAgent):\n    def __init__(self,\n                 "
  },
  {
    "path": "pyopenagi/agents/example/story_teller/config.json",
    "chars": 502,
    "preview": "{\n    \"name\": \"story_teller\",\n    \"description\": [\n        \"You are a creative storyteller. Given a genre, setting, or c"
  },
  {
    "path": "pyopenagi/agents/example/story_teller/meta_requirements.txt",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "pyopenagi/agents/example/tech_support_agent/agent.py",
    "chars": 1033,
    "preview": "from ...react_agent import ReactAgent\n\nclass TechSupportAgent(ReactAgent):\n    def __init__(self,\n                 agent"
  },
  {
    "path": "pyopenagi/agents/example/tech_support_agent/config.json",
    "chars": 371,
    "preview": "{\n    \"name\": \"tech_support_agent\",\n    \"description\": [\n        \"You are an expert specialized in providing technical s"
  },
  {
    "path": "pyopenagi/agents/example/tech_support_agent/meta_requirements.txt",
    "chars": 16,
    "preview": "arxiv\nwikipedia\n"
  },
  {
    "path": "pyopenagi/agents/example/transcribe_agent/agent.py",
    "chars": 843,
    "preview": "from ...react_agent import ReactAgent\nclass TranscribeAgent(ReactAgent):\n    def __init__(self,\n                 agent_n"
  },
  {
    "path": "pyopenagi/agents/example/transcribe_agent/config.json",
    "chars": 308,
    "preview": "{\n    \"name\": \"transcribe_agent\",\n    \"description\": [\n        \"You are an agent who can transcribe audio from the micro"
  },
  {
    "path": "pyopenagi/agents/example/transcribe_agent/meta_requirements.txt",
    "chars": 11,
    "preview": "RealtimeSTT"
  },
  {
    "path": "pyopenagi/agents/example/travel_agent/agent.py",
    "chars": 2444,
    "preview": "from ...react_agent import ReactAgent\nclass TravelAgent(ReactAgent):\n    def __init__(self,\n                 agent_name,"
  },
  {
    "path": "pyopenagi/agents/example/travel_agent/config.json",
    "chars": 230,
    "preview": "{\n\t\"name\": \"travel_agent\",\n\t\"description\": [\n\t\t\"You are an expert in planning and managing travel itineraries.\"\n\t],\n\t\"to"
  },
  {
    "path": "pyopenagi/agents/example/travel_agent/meta_requirements.txt",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "pyopenagi/agents/example/travel_planner_agent/README.md",
    "chars": 945,
    "preview": "# Travel Planner Agent\n\n## Introduction\n\nThe Travel Planner Agent is replicated from the RecAgent used in the paper \"Tra"
  },
  {
    "path": "pyopenagi/agents/example/travel_planner_agent/agent.py",
    "chars": 12277,
    "preview": "import re\nimport time\nimport os\n\nfrom ...react_agent import ReactAgent\n\nfrom ....utils.chat_template import Query\n\nfrom "
  },
  {
    "path": "pyopenagi/agents/example/travel_planner_agent/config.json",
    "chars": 490,
    "preview": "{\n\t\"name\": \"travel_planner_agent\",\n\t\"description\": [\n\t\t\"TravelPlanner: A Benchmark for Real-World Planning with Language"
  },
  {
    "path": "pyopenagi/agents/example/travel_planner_agent/meta_requirements.txt",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "pyopenagi/agents/example/travel_planner_agent/prompts.py",
    "chars": 5601,
    "preview": "ZEROSHOT_REACT_INSTRUCTION = \"\"\"Collect information for a query plan using interleaving 'Thought', 'Action', and 'Observ"
  },
  {
    "path": "pyopenagi/agents/interact.py",
    "chars": 8314,
    "preview": "# executable that you can use to upload to the agent hub and download from it\n# we also use this to check dependencies t"
  },
  {
    "path": "pyopenagi/agents/om-raheja/transcribe_agent/agent.py",
    "chars": 459,
    "preview": "from ...react_agent import ReactAgent\nclass TranscribeAgent(ReactAgent):\n    def __init__(self,\n                 agent_n"
  },
  {
    "path": "pyopenagi/agents/om-raheja/transcribe_agent/config.json",
    "chars": 307,
    "preview": "{\n    \"name\": \"transcribe_agent\",\n    \"description\": [\n        \"You are an agent who can transcribe audio from the micro"
  },
  {
    "path": "pyopenagi/agents/om-raheja/transcribe_agent/meta_requirements.txt",
    "chars": 11,
    "preview": "RealtimeSTT"
  },
  {
    "path": "pyopenagi/agents/react_agent.py",
    "chars": 8317,
    "preview": "\nfrom .base_agent import BaseAgent\n\nimport time\n\nfrom ..utils.chat_template import Query\n\nimport json\n\nclass ReactAgent("
  },
  {
    "path": "pyopenagi/data/agent_tasks/README.md",
    "chars": 168,
    "preview": "# Agent Tasks\nThis directory test tasks for each agent, containing examples of prompts that could be given to that agent"
  },
  {
    "path": "pyopenagi/data/agent_tasks/example/academic_agent_task.txt",
    "chars": 7472,
    "preview": "Find recent papers on the impact of social media on mental health in adolescents.\nExplore the potential of AI in early d"
  },
  {
    "path": "pyopenagi/data/agent_tasks/example/cocktail_mixlogist_task.txt",
    "chars": 9497,
    "preview": "Create a cocktail for a summer garden party. Guests enjoy refreshing, citrusy flavors. Available ingredients include vod"
  },
  {
    "path": "pyopenagi/data/agent_tasks/example/cook_therapist_task.txt",
    "chars": 6888,
    "preview": "Develop a low-carb, keto-friendly dinner that is flavorful and satisfying.\nCreate a vegetarian, Mediterranean-inspired l"
  },
  {
    "path": "pyopenagi/data/agent_tasks/example/creation_agent_task.txt",
    "chars": 11792,
    "preview": "Create an Instagram post: Image of a person using a new tech gadget, text highlighting its key features and benefits.\nDe"
  },
  {
    "path": "pyopenagi/data/agent_tasks/example/fashion_stylist_task.txt",
    "chars": 11972,
    "preview": "Design a custom tuxedo for a slender man with a preference for classic styles, incorporating a modern twist such as velv"
  },
  {
    "path": "pyopenagi/data/agent_tasks/example/festival_card_designer_task.txt",
    "chars": 9684,
    "preview": "Design a festival card for a vintage-themed music festival targeting young adults, with a square card size.\nCreate a psy"
  },
  {
    "path": "pyopenagi/data/agent_tasks/example/fitness_trainer_task.txt",
    "chars": 7296,
    "preview": "Create a workout plan for a busy professional aiming to lose 10 pounds in 3 months.\nDesign a strength training routine f"
  },
  {
    "path": "pyopenagi/data/agent_tasks/example/game_agent_task.txt",
    "chars": 12673,
    "preview": "Recommend a relaxing puzzle game for Nintendo Switch, suitable for a casual player.\nSuggest a challenging action RPG for"
  },
  {
    "path": "pyopenagi/data/agent_tasks/example/interior_decorator_task.txt",
    "chars": 17325,
    "preview": "I want to transform my small, dark living room into a bright and airy space. I love minimalist Scandinavian design and p"
  },
  {
    "path": "pyopenagi/data/agent_tasks/example/language_tutor_task.txt",
    "chars": 10216,
    "preview": "Provide conversation practice for beginner level Arabic learners, focusing on basic greetings, introductions, and asking"
  },
  {
    "path": "pyopenagi/data/agent_tasks/example/logo_creator_task.txt",
    "chars": 6119,
    "preview": "Design a minimalist logo for a tech startup specializing in AI-powered cybersecurity solutions.\nCreate a bold logo for a"
  },
  {
    "path": "pyopenagi/data/agent_tasks/example/math_agent_task.txt",
    "chars": 8724,
    "preview": "Solve the equation: 2^(3x-1) = 5^(x+2).\nFind the inverse of the function f(x) = (3x - 2) / (2x + 1).\nSolve the system of"
  },
  {
    "path": "pyopenagi/data/agent_tasks/example/meme_creator_task.txt",
    "chars": 5185,
    "preview": "Create a meme about the struggles of adulting.\nMake a meme about the excitement of the weekend.\nDevelop a meme about the"
  },
  {
    "path": "pyopenagi/data/agent_tasks/example/music_composer_task.txt",
    "chars": 5057,
    "preview": "Compose a dreamy indie-pop song with a catchy chorus.\nCreate a dark, atmospheric metal track with heavy guitar riffs.\nWr"
  },
  {
    "path": "pyopenagi/data/agent_tasks/example/plant_care_assistant_task.txt",
    "chars": 5130,
    "preview": "How can I revive a dying peace lily with brown tips?\nWhat is the best way to propagate a spider plant?\nMy snake plant is"
  },
  {
    "path": "pyopenagi/data/agent_tasks/example/rec_agent_task.txt",
    "chars": 6704,
    "preview": "Recommend a Wes Anderson-style comedy set in the 1970s about a dysfunctional family.\nSuggest a Netflix original crime dr"
  },
  {
    "path": "pyopenagi/data/agent_tasks/example/story_teller_task.txt",
    "chars": 15444,
    "preview": "Create a dystopian short story featuring a protagonist with a unique biological adaptation, exploring themes of societal"
  },
  {
    "path": "pyopenagi/data/agent_tasks/example/tech_support_agent_task.txt",
    "chars": 17269,
    "preview": "My Windows 10 laptop is running extremely slow, even after restarting and closing unnecessary programs. I've noticed hig"
  },
  {
    "path": "pyopenagi/data/agent_tasks/example/travel_agent_task.txt",
    "chars": 4443,
    "preview": "I want to take a trip to Paris, France from July 4th to July 10th, 2024, and I am traveling from New York City. Help me "
  },
  {
    "path": "pyopenagi/data/agent_tasks/example/travel_planner_agent_task.txt",
    "chars": 18922,
    "preview": "Please plan a trip for me starting from Sarasota to Chicago for 3 days, from March 22nd to March 24th, 2022. The budget "
  },
  {
    "path": "pyopenagi/manager/manager.py",
    "chars": 6089,
    "preview": "# agent_manager.py\n\nimport os\nimport json\nimport base64\nimport subprocess\nimport sys\nfrom typing import List, Dict\nimpor"
  },
  {
    "path": "pyopenagi/queues/README.md",
    "chars": 171,
    "preview": "# pyopenagi/queues\n\nThis contains implementations for queries to be passed to the LLM in a queue format so that we can h"
  },
  {
    "path": "pyopenagi/queues/base_queue.py",
    "chars": 316,
    "preview": "import queue\n\nclass BaseQueue:\n\n    _queue = queue.Queue()\n\n    @classmethod\n    def add_message(cls, message):\n        "
  },
  {
    "path": "pyopenagi/queues/llm_request_queue.py",
    "chars": 78,
    "preview": "from .base_queue import BaseQueue\n\nclass LLMRequestQueue(BaseQueue):\n    pass\n"
  },
  {
    "path": "pyopenagi/tools/README.md",
    "chars": 140,
    "preview": "# pyopenagi/tools\n\nThis is where all the tools are located. Each tool requires you to subclass the base tool and add the"
  },
  {
    "path": "pyopenagi/tools/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "pyopenagi/tools/arxiv/arxiv.py",
    "chars": 4602,
    "preview": "import re\n\nfrom ..base import BaseTool\n\nimport arxiv\n\nfrom typing import Optional\n\nclass Arxiv(BaseTool):\n    \"\"\"Arxiv T"
  },
  {
    "path": "pyopenagi/tools/base.py",
    "chars": 1091,
    "preview": "class BaseTool:\n    \"\"\"Base class for calling tools\n    \"\"\"\n    def __init__(self) -> None:\n        pass\n\n    def run(se"
  },
  {
    "path": "pyopenagi/tools/bing/bing_search.py",
    "chars": 1873,
    "preview": "import requests\n\nfrom ..base import BaseTool\n\nfrom typing import List\n# from pydantic import root_validator\n\nfrom pyopen"
  },
  {
    "path": "pyopenagi/tools/currency_converter/currency_converter.py",
    "chars": 3049,
    "preview": "from ..base import BaseRapidAPITool\n\nfrom pyopenagi.utils.utils import get_from_env\n\nimport requests\n\nclass CurrencyConv"
  },
  {
    "path": "pyopenagi/tools/google/google_places.py",
    "chars": 3727,
    "preview": "import logging\nfrom typing import Any, Dict, Optional\n\nfrom ..base import BaseTool\n\nfrom pyopenagi.utils.utils import ge"
  },
  {
    "path": "pyopenagi/tools/google/google_search.py",
    "chars": 4235,
    "preview": "from ..base import BaseTool\n\nfrom pyopenagi.utils.utils import get_from_env\n\nfrom typing import List, Any\n\nclass GoogleS"
  },
  {
    "path": "pyopenagi/tools/imdb/top_movie.py",
    "chars": 2185,
    "preview": "from ..base import BaseRapidAPITool\n\nfrom typing import Any, Dict, List, Optional\n\n# from pydantic import root_validator"
  },
  {
    "path": "pyopenagi/tools/imdb/top_movies.py",
    "chars": 2137,
    "preview": "from ..base import BaseRapidAPITool\n\n# from pydantic import root_validator\n\nfrom pyopenagi.utils.utils import get_from_e"
  },
  {
    "path": "pyopenagi/tools/imdb/top_series.py",
    "chars": 2084,
    "preview": "from ..base import BaseRapidAPITool\n\nfrom pyopenagi.utils.utils import get_from_env\n\nimport requests\n\nclass TopSeries(Ba"
  },
  {
    "path": "pyopenagi/tools/impira/doc_question_answering.py",
    "chars": 1770,
    "preview": "import requests\n\nfrom ...utils.utils import get_from_env\n\nfrom ..base import BaseHuggingfaceTool\n\nimport base64\n\nclass D"
  },
  {
    "path": "pyopenagi/tools/meteosource_weather/find_place.py",
    "chars": 1466,
    "preview": "from ..base import BaseRapidAPITool\n\n# from pydantic import root_validator\n\nfrom pyopenagi.utils.utils import get_from_e"
  },
  {
    "path": "pyopenagi/tools/moonphase/moon_phase_search.py",
    "chars": 880,
    "preview": "from ..base import BaseRapidAPITool\n\nfrom pyopenagi.utils.utils import get_from_env\n\nimport requests\n\nclass MoonPhaseSea"
  },
  {
    "path": "pyopenagi/tools/openai/speech_to_text.py",
    "chars": 1291,
    "preview": "import requests\n\nimport soundfile as sf\n\nfrom ...utils.utils import get_from_env\n\nfrom ..base import BaseHuggingfaceTool"
  },
  {
    "path": "pyopenagi/tools/shazam/song_auto_complete.py",
    "chars": 1233,
    "preview": "from ..base import BaseRapidAPITool\n\n# from pydantic import root_validator\n\nfrom pyopenagi.utils.utils import get_from_e"
  },
  {
    "path": "pyopenagi/tools/stability-ai/sdxl_turbo.py",
    "chars": 1254,
    "preview": "from diffusers import AutoPipelineForText2Image\nimport torch\n\nfrom ..base import BaseHuggingfaceTool\n\nclass SdxlTurbo(Ba"
  },
  {
    "path": "pyopenagi/tools/stability-ai/text_to_image.py",
    "chars": 1831,
    "preview": "from ...utils.utils import get_from_env\n\nfrom ..base import BaseHuggingfaceTool\n\nimport requests\n\nclass TextToImage(Base"
  },
  {
    "path": "pyopenagi/tools/suno/text_to_speech.py",
    "chars": 1620,
    "preview": "import requests\n\nfrom ...utils.utils import get_from_env\n\nfrom ..base import BaseHuggingfaceTool\n\nclass TextToSpeech(Bas"
  },
  {
    "path": "pyopenagi/tools/timbrooks/image_to_image.py",
    "chars": 2113,
    "preview": "from PIL import Image\nimport torch\nfrom diffusers import StableDiffusionInstructPix2PixPipeline, EulerAncestralDiscreteS"
  },
  {
    "path": "pyopenagi/tools/transcriber/transcriber.py",
    "chars": 1642,
    "preview": "from ..base import BaseTool \nfrom time import sleep\n\nclass Transcriber(BaseTool):\n    def __init__(self):\n        \"\"\" bi"
  },
  {
    "path": "pyopenagi/tools/travel_planner/accommodations.py",
    "chars": 1239,
    "preview": "import pandas as pd\nimport os\nfrom pandas import DataFrame\n\nfrom ..base import BaseTool\n\n\nclass Accommodations(BaseTool)"
  },
  {
    "path": "pyopenagi/tools/travel_planner/attractions.py",
    "chars": 1244,
    "preview": "import pandas as pd\nimport os\nfrom pandas import DataFrame\n\nfrom ..base import BaseTool\n\n\nclass Attractions(BaseTool):\n "
  },
  {
    "path": "pyopenagi/tools/travel_planner/cities.py",
    "chars": 1139,
    "preview": "import os\n\nfrom ..base import BaseTool\n\n\nclass Cities(BaseTool):\n    def __init__(self, path=\"../../environments/travelP"
  },
  {
    "path": "pyopenagi/tools/travel_planner/flights.py",
    "chars": 1543,
    "preview": "import pandas as pd\nimport os\nfrom pandas import DataFrame\n\nfrom ..base import BaseTool\n\n\nclass Flights(BaseTool):\n\n    "
  },
  {
    "path": "pyopenagi/tools/travel_planner/google_distance_matrix.py",
    "chars": 2505,
    "preview": "import re\nimport os\nimport pandas as pd\nimport numpy as np\n\nfrom ..base import BaseTool\n\n\n\n# This tool refers to the \"Di"
  },
  {
    "path": "pyopenagi/tools/travel_planner/notebook.py",
    "chars": 1689,
    "preview": "from pandas import DataFrame\n\nfrom ..base import BaseTool\n\n\n\nclass Notebook(BaseTool):\n    def __init__(self) -> None:\n "
  },
  {
    "path": "pyopenagi/tools/travel_planner/planner.py",
    "chars": 2000,
    "preview": "PLANNER_INSTRUCTION = \"\"\"You are a proficient planner. Based on the provided information and query, please give me a det"
  },
  {
    "path": "pyopenagi/tools/travel_planner/restaurants.py",
    "chars": 1157,
    "preview": "import pandas as pd\nimport os\nfrom pandas import DataFrame\n\nfrom ..base import BaseTool\n\n\nclass Restaurants(BaseTool):\n "
  },
  {
    "path": "pyopenagi/tools/trip_advisor/airport_search.py",
    "chars": 1979,
    "preview": "from ..base import BaseRapidAPITool\n\nfrom pyopenagi.utils.utils import get_from_env\n\nimport requests\n\nimport json\n\nclass"
  },
  {
    "path": "pyopenagi/tools/trip_advisor/flight_search.py",
    "chars": 5247,
    "preview": "from ..base import BaseRapidAPITool\n\nfrom pyopenagi.utils.utils import get_from_env\n\nimport requests\n\nimport json\n\nclass"
  },
  {
    "path": "pyopenagi/tools/trip_advisor/get_hotel_details.py",
    "chars": 3745,
    "preview": "from ..base import BaseRapidAPITool\n\nfrom pyopenagi.utils.utils import get_from_env\n\nimport requests\n\nimport json\n\nclass"
  },
  {
    "path": "pyopenagi/tools/trip_advisor/get_restaurant_details.py",
    "chars": 2357,
    "preview": "from ..base import BaseRapidAPITool\n\nfrom pyopenagi.utils.utils import get_from_env\n\nimport requests\n\nimport json\n\nclass"
  },
  {
    "path": "pyopenagi/tools/trip_advisor/hotel_location_search.py",
    "chars": 1631,
    "preview": "from ..base import BaseRapidAPITool\n\nfrom pyopenagi.utils.utils import get_from_env\n\nimport requests\n\nimport json\n\nclass"
  },
  {
    "path": "pyopenagi/tools/trip_advisor/hotel_search.py",
    "chars": 2724,
    "preview": "from ..base import BaseRapidAPITool\n\nfrom pyopenagi.utils.utils import get_from_env\n\nimport requests\n\nimport json\n\nclass"
  },
  {
    "path": "pyopenagi/tools/trip_advisor/restaurant_location_search.py",
    "chars": 2111,
    "preview": "from ..base import BaseRapidAPITool\n\nfrom pyopenagi.utils.utils import get_from_env\n\nimport requests\n\nimport json\n\nclass"
  },
  {
    "path": "pyopenagi/tools/trip_advisor/restaurant_search.py",
    "chars": 2280,
    "preview": "\n\nfrom ..base import BaseRapidAPITool\n\nfrom pyopenagi.utils.utils import get_from_env\n\nimport requests\n\nimport json\n\ncla"
  },
  {
    "path": "pyopenagi/tools/wikipedia/wikipedia.py",
    "chars": 2656,
    "preview": "from ..base import BaseTool\n# from langchain_core.documents import Document\nfrom typing import Optional, Any\nclass Wikip"
  },
  {
    "path": "pyopenagi/tools/wolfram/wolfram_alpha.py",
    "chars": 2316,
    "preview": "from ..base import BaseTool\n\nfrom pyopenagi.utils.utils import get_from_env\nclass WolframAlpha(BaseTool):\n    \"\"\"Wolfram"
  },
  {
    "path": "pyopenagi/tools/words_api/words_api.py",
    "chars": 2041,
    "preview": "from ..base import BaseRapidAPITool\n\n# from pydantic import root_validator\n\nfrom pyopenagi.utils.utils import get_from_e"
  },
  {
    "path": "pyopenagi/utils/README.md",
    "chars": 182,
    "preview": "# pyopenagi/utils\n\nHelper utils that are re-used in AIOS.\n\nThese are various tools that we use in our internal implement"
  },
  {
    "path": "pyopenagi/utils/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "pyopenagi/utils/chat_template.py",
    "chars": 997,
    "preview": "class Query:\n    def __init__(self,\n            messages,\n            tools = None,\n            message_return_type = \"t"
  },
  {
    "path": "pyopenagi/utils/commands/top.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "pyopenagi/utils/compressor.py",
    "chars": 535,
    "preview": "import zlib\n\nclass Compressor:\n    def __init__(self) -> None:\n        pass\n\n    def compress(self, data):\n        pass\n"
  },
  {
    "path": "pyopenagi/utils/logger.py",
    "chars": 3131,
    "preview": "import click\n\nimport os\n\nfrom datetime import datetime\n\nclass BaseLogger:\n    def __init__(self,\n            logger_name"
  },
  {
    "path": "pyopenagi/utils/utils.py",
    "chars": 2651,
    "preview": "import argparse\n\nimport os\nimport shutil\n\nimport json\n\nfrom typing import Dict, Any, Optional\n\nimport re\n\n# logging.basi"
  },
  {
    "path": "pyproject.toml",
    "chars": 1146,
    "preview": "[build-system]\nbuild-backend = \"hatchling.build\"\nrequires = [\"hatchling\", \"hatch-requirements-txt\"]\n\n[project]\n\ndynamic "
  },
  {
    "path": "requirements-dev.txt",
    "chars": 38,
    "preview": "-r requirements.txt\npre-commit\npytest\n"
  },
  {
    "path": "requirements.txt",
    "chars": 98,
    "preview": "python-dotenv\nRequests\nPympler==1.0.1\nclick==8.1.7\npython-dotenv==1.0.0\nbeautifulsoup4\nplaywright\n"
  },
  {
    "path": "tests/README.md",
    "chars": 335,
    "preview": "# tests\n\nThis directory contains tests you can use to test specific features of the project so you can figure out which "
  },
  {
    "path": "tests/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/test_agent_creation.py",
    "chars": 681,
    "preview": "# make sure we can create agents\n\nfrom pyopenagi.agents.agent_process import AgentProcess\nfrom pyopenagi.utils.chat_temp"
  },
  {
    "path": "tests/test_tools/README.md",
    "chars": 125,
    "preview": "# test/test_tools\n\nThis tests specific tools the agents can use and makes sure they are working. Each tool has its own t"
  },
  {
    "path": "tests/test_tools/test_currency_converter.py",
    "chars": 827,
    "preview": "import os\nimport pytest\n\nfrom pyopenagi.tools.currency_converter.currency_converter import CurrencyConverter\nfrom dotenv"
  },
  {
    "path": "tests/test_tools/test_top_series.py",
    "chars": 4529,
    "preview": "import os\nimport pytest\nimport requests\nfrom requests.models import Response\nimport json\n\nfrom pyopenagi.tools.imdb.top_"
  },
  {
    "path": "tests/test_tools/test_wolfram_alpha.py",
    "chars": 688,
    "preview": "import os\nimport pytest\n\nfrom pyopenagi.tools.wolfram.wolfram_alpha import WolframAlpha\nfrom dotenv import load_dotenv, "
  },
  {
    "path": "tests/test_tools/test_words_api.py",
    "chars": 672,
    "preview": "import os\nimport pytest\n\nfrom pyopenagi.tools.words_api.words_api import WordsAPI\nfrom dotenv import load_dotenv, find_d"
  },
  {
    "path": "tools.md",
    "chars": 881,
    "preview": "# Tool Configuration\n## Available tools\n\n### Wolfram Alpha\n1. Register wolfram alpha app account and activate [APP ID](h"
  }
]

About this extraction

This page contains the full source code of the agiresearch/OpenAGI GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 179 files (488.7 KB), approximately 111.3k tokens, and a symbol index with 494 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!