[
  {
    "path": ".do/app.yaml",
    "content": "alerts:\n  - rule: DEPLOYMENT_FAILED\n  - rule: DOMAIN_FAILED\ndatabases:\n  - engine: PG\n    name: super-agi-main\n    num_nodes: 1\n    size: basic-xs\n    version: \"12\"\ningress:\n  rules:\n    - component:\n        name: superagi-backend\n      match:\n        path:\n          prefix: /api\nname: superagi\nservices:\n  - dockerfile_path: DockerfileRedis\n    github: \n      branch: main\n      deploy_on_push: true\n      repo: TransformerOptimus/SuperAGI\n    internal_ports: \n    - 6379\n    instance_count: 1\n    instance_size_slug: basic-xs\n    source_dir: /\n    name: superagi-redis\n  - dockerfile_path: Dockerfile\n    envs:\n      - key: REDIS_URL\n        scope: RUN_TIME\n        value: superagi-redis:6379\n      - key: DB_URL\n        scope: RUN_TIME\n        value: ${super-agi-main.DATABASE_URL}\n    github:\n      branch: main\n      deploy_on_push: true\n      repo: TransformerOptimus/SuperAGI\n    http_port: 8001\n    instance_count: 1\n    instance_size_slug: basic-xs\n    run_command: /app/entrypoint.sh\n    source_dir: /\n    name: superagi-backend\n  - dockerfile_path: ./gui/DockerfileProd\n    github:\n      branch: main\n      deploy_on_push: true\n      repo: TransformerOptimus/SuperAGI\n    http_port: 3000\n    instance_count: 1\n    instance_size_slug: basic-xs\n    source_dir: ./gui\n    name: superagi-gui\nworkers:\n  - dockerfile_path: Dockerfile\n    envs:\n      - key: REDIS_URL\n        scope: RUN_TIME\n        value: superagi-redis:6379\n      - key: DB_URL\n        scope: RUN_TIME\n        value: ${super-agi-main.DATABASE_URL}\n    github:\n      branch: main\n      deploy_on_push: true\n      repo: TransformerOptimus/SuperAGI\n    instance_count: 1\n    instance_size_slug: basic-xs\n    run_command: celery -A superagi.worker worker --beat --loglevel=info\n    source_dir: /\n    name: superagi-celery\n  \n"
  },
  {
    "path": ".do/deploy.template.yaml",
    "content": "spec:\n  alerts:\n    - rule: DEPLOYMENT_FAILED\n    - rule: DOMAIN_FAILED\n  databases:\n    - engine: PG\n      name: super-agi-main\n      num_nodes: 1\n      size: basic-xs\n      version: \"12\"\n  ingress:\n    rules:\n      - component:\n          name: superagi-backend\n        match:\n          path:\n            prefix: /api\n  name: superagi\n  services:\n    - dockerfile_path: DockerfileRedis\n      git:\n        branch: main\n        repo_clone_url: https://github.com/TransformerOptimus/SuperAGI.git\n      internal_ports: \n      - 6379\n      instance_count: 1\n      instance_size_slug: basic-xs\n      source_dir: /\n      name: superagi-redis\n    - dockerfile_path: Dockerfile\n      envs:\n        - key: REDIS_URL\n          scope: RUN_TIME\n          value: superagi-redis:6379\n        - key: DB_URL\n          scope: RUN_TIME\n          value: ${super-agi-main.DATABASE_URL}\n      git:\n        branch: main\n        repo_clone_url: https://github.com/TransformerOptimus/SuperAGI.git\n      http_port: 8001\n      instance_count: 1\n      instance_size_slug: basic-xs\n      run_command: /app/entrypoint.sh\n      source_dir: /\n      name: superagi-backend\n    - dockerfile_path: ./gui/DockerfileProd\n      git:\n        branch: main\n        repo_clone_url: https://github.com/TransformerOptimus/SuperAGI.git\n      http_port: 3000\n      instance_count: 1\n      instance_size_slug: basic-xs\n      source_dir: ./gui\n      name: superagi-gui\n  workers:\n    - dockerfile_path: Dockerfile\n      envs:\n        - key: REDIS_URL\n          scope: RUN_TIME\n          value: superagi-redis:6379\n        - key: DB_URL\n          scope: RUN_TIME\n          value: ${super-agi-main.DATABASE_URL}\n      git:\n        branch: main\n        repo_clone_url: https://github.com/TransformerOptimus/SuperAGI.git\n      instance_count: 1\n      instance_size_slug: basic-xs\n      run_command: celery -A superagi.worker worker --beat --loglevel=info\n      source_dir: /\n      name: superagi-celery\n    \n"
  },
  {
    "path": ".dockerignore",
    "content": "# Ignore everything\n**\n\n# Allow files and directories\n!/migrations\n!/nginx\n!/superagi\n!/tgwui\n!/tools\n!/workspace\n!/main.py\n!/requirements.txt\n!/entrypoint.sh\n!/entrypoint_celery.sh\n!/wait-for-it.sh\n!/tools.json\n!/install_tool_dependencies.sh\n!/alembic.ini"
  },
  {
    "path": ".gitattributes",
    "content": "*.sh text eol=lf\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/1.BUG_REPORT.yml",
    "content": "name: Bug report \ndescription: Create a bug report for SuperAGI.\nlabels: ['status: needs triage']\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        ### ⚠️ Issue Creation Guideline\n        * Check out our [roadmap] and join our [discord] to discuss what's going on\n        * If you need help, you can ask in the [#general] section or in [#support]\n        * **Thoroughly search the [existing issues] before creating a new one**\n        * Read through our docs:\n        [roadmap]: https://github.com/users/TransformerOptimus/projects/5\n        [discord]: https://discord.gg/dXbRe5BHJC\n        [#general]: https://discord.com/channels/1107593006032355359/1107642413993959505\n        [#support]: https://discord.com/channels/1107593006032355359/1107645922797703198\n        [existing issues]: https://github.com/TransformerOptimus/SuperAGI/issues\n  - type: checkboxes\n    attributes:\n      label: ⚠️ Check for existing issues before proceeding. ⚠️\n      description: >\n        Please [search the history](https://github.com/TransformerOptimus/SuperAGI/issues)\n        to see if an issue already exists for the same problem.\n      options:\n        - label: I have searched the existing issues, and there is no existing issue for my problem\n          required: true\n\n  - type: markdown\n    attributes:\n      value: |\n        Please confirm that the issue you have is described well and precise in the title above ⬆️.\n        Think like this: What would you type if you were searching for the issue?\n        \n        For example:\n        ❌ - my SuperAGI agent keeps looping\n        ✅ - After performing Write Tool, SuperAGI goes into a loop where it keeps trying to write the file.\n        \n        Please help us help you by following these steps:\n        - Search for existing issues, adding a comment when you have the same or similar issue is tidier than \"new issue\" and \n          newer issues will not be reviewed earlier, this is dependent on the current priorities set by our wonderful team\n        - Ask on our Discord if your issue is known when you are unsure (https://discord.gg/dXbRe5BHJC)\n        - Provide relevant info:\n          - Provide Docker Logs(docker compose logs) whenever possible.\n          - If it's a pip/packages issue, mention this in the title and provide pip version, python version.\n  - type: dropdown\n    attributes:\n      label: Where are you using SuperAGI?\n      description: >\n        Please select the operating system you were using to run SuperAGI when this problem occurred.\n      options:\n        - Windows\n        - Linux\n        - MacOS\n        - Codespaces\n        - Web Version\n        - Other\n    validations:\n      required: true\n      nested_fields:\n        - type: text\n          attributes:\n            label: Specify the system\n            description: Please specify the system you are working on.\n\n  - type: dropdown\n    attributes:\n      label: Which branch of SuperAGI are you using?\n      description: |\n        Please select which version of SuperAGI you were using when this issue occurred.\n        If installed with git you can run `git branch` to see which version of Auto-GPT you are running.\n      options:\n        - Main\n        - Dev (branch)\n    validations:\n      required: true\n\n  - type: dropdown\n    attributes:\n      label: Do you use OpenAI GPT-3.5 or GPT-4?\n      description: >\n        If you are using SuperAGI with GPT-3.5, your problems may be caused by\n        the limitations of GPT-3.5 like incorrect Tool selection thus causing looping in the agent feed.\n      options:\n        - GPT-3.5\n        - GPT-3.5(16k)\n        - GPT-4\n        - GPT-4(32k)\n    validations:\n      required: true\n\n  - type: dropdown\n    attributes:\n      label: Which area covers your issue best?\n      description: >\n        Select the area related to the issue you are reporting.\n      options:\n        - Installation and setup\n        - Resource Manager\n        - Action Console\n        - Performance\n        - Marketplace\n        - Prompt\n        - Tools\n        - Agents\n        - Documentation\n        - Logging\n        - Other\n    validations:\n      required: true\n      autolabels: true\n      nested_fields:\n        - type: text\n          attributes:\n            label: Specify the area\n            description: Please specify the area you think is best related to the issue.\n\n  - type: textarea\n    attributes:\n      label: Describe your issue.\n      description: Describe the problem you are experiencing. Try to describe only the issue and phrase it short but clear. ⚠️ Provide NO other data in this field  \n    validations:\n      required: true\n\n  - type: textarea\n    attributes:\n     label: How to replicate your Issue?\n     description: |\n      Mention Agent Name, Agent Description and Agent Goals, along with Model selected. \n      Provide any other data which might be relevant for us to replicate this issue.\n      ⚠️ Provide NO other data in this field  \n    validations:\n     required: false\n\n  - type: markdown\n    attributes:\n      value: |\n        ⚠️ Please keep in mind that the log files may contain personal information such as credentials. Make sure you hide them before copy/pasting it! ⚠️        \n  - type: input\n    attributes:\n      label: Upload Error Log Content\n      description: |\n        Upload the error log content, this can help us understand the issue better. \n        To do this, you can simply copy the logs from the terminal with which you did 'docker compose up' or in a new terminal, \n        enter 'docker compose logs' and copy/paste the error contents to this field. \n        ⚠️ The activity log may contain personal data given to SuperAGI by you in prompt or input as well as \n        any personal information that SuperAGI collected out of files during last run. Please hide them before sharing. ⚠️\n    validations:\n      required: True\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!-- Thank you for submitting this PR! :) -->\n<!-- Provide a general summary of your changes in the Title above ^, end with (close #<issue-no>) or (fix #<issue-no>) -->\n\n### Description\n<!-- The title might not be enough to convey how this change affects the user. -->\n<!-- Describe the changes from a user's perspective -->\n\n\n<!-- Changelog Section End -->\n\n### Related Issues\n<!-- Please make sure you have an issue associated with this Pull Request -->\n<!-- And then add `(close #<issue-no>)` to the pull request title -->\n<!-- Add the issue number below (e.g. #234) -->\n\n### Solution and Design\n<!-- How is this issue solved/fixed? What is the design? -->\n<!-- It's better if we elaborate -->\n\n### Test Plan\n<!-- Describe how you tested this functionality. Include steps to reproduce, relevant test cases, and any other pertinent information. -->\n\n### Type of change\n- [ ] Bug fix (non-breaking change which fixes an issue)\n- [ ] New feature (non-breaking change which adds functionality)\n- [ ] Breaking change (fix or feature that would cause existing functionality to change)\n- [ ] Docs update\n\n\n### Checklist\n- [ ] My pull request is atomic and focuses on a single change.\n- [ ] I have read the contributing guide and my code conforms to the guidelines.\n- [ ] I have documented my changes clearly and comprehensively.\n- [ ] I have added the required tests.\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "# This workflow will install Python dependencies, run tests and lint with a single version of Python\n# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python\n\nname: Python CI\n\non:\n  push:\n    branches: [ \"main\", \"dev\" ]\n  pull_request:\n    branches: [ \"main\", \"dev\" ]\n\npermissions:\n  contents: read\n\njobs:\n  lint:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v3\n      with:\n        fetch-depth: 0\n        ref: ${{ github.event.pull_request.head.ref }}\n        repository: ${{ github.event.pull_request.head.repo.full_name }}\n\n    - name: Set up Python 3.9\n      uses: actions/setup-python@v3\n      with:\n        python-version: \"3.9\"\n\n    - name: Cache Python dependencies\n      uses: actions/cache@v2\n      with:\n          path: ~/.cache/pip\n          key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}\n          restore-keys: |\n            ${{ runner.os }}-pip-\n\n    - name: Install dependencies\n      run: |\n        python -m pip install --upgrade pip\n        pip install flake8 pytest\n        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi\n    - name: Lint with flake8\n      run: |\n        # stop the build if there are Python syntax errors or undefined names\n        flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics\n        # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide\n        flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics\n \n  test:\n\n    permissions:\n      # Gives the action the necessary permissions for publishing new\n      # comments in pull requests.\n      pull-requests: write\n      # Gives the action the necessary permissions for pushing data to the\n      # python-coverage-comment-action branch, and for editing existing\n      # comments (to avoid publishing multiple comments in the same PR)\n      contents: write\n\n    runs-on: ubuntu-latest\n    timeout-minutes: 30\n    strategy:\n      matrix:\n        python-version: [\"3.9\"]\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v3\n        with:\n          fetch-depth: 0\n          ref: ${{ github.event.pull_request.head.ref }}\n          repository: ${{ github.event.pull_request.head.repo.full_name }}\n          submodules: true\n\n      - name: Configure git user SuperAGI-Bot\n        run: |\n          git config --global user.name \"SuperAGI-Bot\"\n          git config --global user.email \"github-bot@superagi.com\"\n          \n      - name: Set up Python 3.9\n        uses: actions/setup-python@v3\n        with:\n          python-version: \"3.9\"\n\n      - name: Cache dependencies\n        uses: actions/cache@v2\n        with:\n            path: ~/.cache/pip\n            key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}\n            restore-keys: |\n              ${{ runner.os }}-pip-\n\n      - name: Install dependencies\n        run: |\n          python -m pip install --upgrade pip\n          pip install flake8 pytest\n          if [ -f requirements.txt ]; then pip install -r requirements.txt; fi\n          \n      - name: Test with pytest\n        run: |\n          pytest --cov=superagi --cov-branch --cov-report term-missing --cov-report xml \\\n            tests/unit_tests -s\n        env:\n          CI: true\n          ENV: DEV\n          PLAIN_OUTPUT: True\n          REDIS_URL: \"localhost:6379\"\n          IS_TESTING: True\n          ENCRYPTION_KEY: \"abcdefghijklmnopqrstuvwxyz123456\"\n\n      - name: Upload coverage reports to Codecov\n        uses: codecov/codecov-action@v3\n"
  },
  {
    "path": ".github/workflows/codeql.yml",
    "content": "name: \"CodeQL\"\n\non:\n  push:\n    branches: [ 'main', 'dev' ]\n  pull_request:\n    # The branches below must be a subset of the branches above\n    branches: [ 'main' ]\n  schedule:\n    - cron: '48 0 * * 2'\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n\n    strategy:\n      fail-fast: false\n      matrix:\n        language: [ 'javascript', 'python' ]\n        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]\n        # Use only 'java' to analyze code written in Java, Kotlin or both\n        # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both\n        # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v3\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v2\n      with:\n        languages: ${{ matrix.language }}\n        # If you wish to specify custom queries, you can do so here or in a config file.\n        # By default, queries listed here will override any specified in a config file.\n        # Prefix the list here with \"+\" to use these queries and those in the config file.\n\n        # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs\n        # queries: security-extended,security-and-quality\n\n\n    # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).\n    # If this step fails, then you should remove it and run the build manually (see below)\n    - name: Autobuild\n      uses: github/codeql-action/autobuild@v2\n\n    # ℹ️ Command-line programs to run using the OS shell.\n    # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun\n\n    #   If the Autobuild fails above, remove it and uncomment the following three lines.\n    #   modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.\n\n    # - run: |\n    #     echo \"Run, Build Application using script\"\n    #     ./location_of_script_within_repo/buildscript.sh\n\n    - name: Perform CodeQL Analysis\n      uses: github/codeql-action/analyze@v2\n      with:\n        category: \"/language:${{matrix.language}}\"\n"
  },
  {
    "path": ".gitignore",
    "content": ".idea\n**/.env\n**/.venv\nconfig.yaml\n__pycache__\nsuperagi/models/__pycache__\nsuperagi/controllers/__pycache__\n**agent_dictvenv\n**/__gitpycache__/\ngui/node_modules\nnode_modules\ngui/.next\n.DS_Store\n.DS_Store?\nvenv\nworkspace/output\nworkspace/input\ncelerybeat-schedule\n../bfg-report*\nsuperagi/tools/marketplace_tools/\nsuperagi/tools/external_tools/\ntests/unit_tests/resource_manager/test_path\n/tools.json"
  },
  {
    "path": ".pre-commit-config.yaml",
    "content": "repos:\n  -   repo: local\n      hooks:\n        -   id: pylint\n            name: pylint\n            entry: pylint\n            language: system\n            types: [python]"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, religion, or sexual identity\nand orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the\n  overall community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or\n  advances of any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email\n  address, without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at\n.\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series\nof actions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or\npermanent ban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior,  harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within\nthe community.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.0, available at\nhttps://www.contributor-covenant.org/version/2/0/code_of_conduct.html.\n\nCommunity Impact Guidelines were inspired by [Mozilla's code of conduct\nenforcement ladder](https://github.com/mozilla/diversity).\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see the FAQ at\nhttps://www.contributor-covenant.org/faq. Translations are available at\nhttps://www.contributor-covenant.org/translations.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "#  ⚡ Contributing to SuperAGI\n<p align=\"center\">\n  <a href=\"https://superagi.com//#gh-light-mode-only\">\n    <img src=\"https://superagi.com/wp-content/uploads/2023/05/Logo-dark.svg\" width=\"318px\" alt=\"SuperAGI logo\" />\n  </a>\n  <a href=\"https://superagi.com//#gh-dark-mode-only\">\n    <img src=\"https://superagi.com/wp-content/uploads/2023/05/Logo-light.svg\" width=\"318px\" alt=\"SuperAGI logo\" />\n  </a>\n</p>\n\nFirst of all, thank you for taking the time to contribute to this project. We truly appreciate your contributions, whether it's bug reports, feature suggestions, or pull requests. Your time and effort are highly valued in this project. 🚀\n\nThis document provides guidelines and best practices to help you to contribute effectively. These are meant to serve as guidelines, not strict rules. We encourage you to use your best judgment and feel comfortable proposing changes to this document through a pull request.\n\nFor all contributions, a CLA (Contributor License Agreement) needs to be signed\n[here](https://cla-assistant.io/TransformerOptimus/SuperAGI) before (or after) the pull request has been submitted.\n\n**********************************Table of Content:********************************** \n1. [Code of conduct](https://github.com/TransformerOptimus/SuperAGI/blob/CONTRIBUTING.md#code-of-conduct) \n2. [Quick Start](https://github.com/TransformerOptimus/SuperAGI/blob/CONTRIBUTING.md#quick-start)\n3. [Contributing Guidelines](https://github.com/TransformerOptimus/SuperAGI/blob/CONTRIBUTING.md#contributing-guidelines)\n    1. [Reporting Bugs](https://github.com/TransformerOptimus/SuperAGI/blob/CONTRIBUTING.md#reporting-bugs)\n    2. [New Feature or Suggesting Enhancements](https://github.com/TransformerOptimus/SuperAGI/blob/CONTRIBUTING.md#new-feature-or-suggesting-enhancements)\n4. [Testing](https://github.com/TransformerOptimus/SuperAGI/blob/CONTRIBUTING.md#testing-changes)\n5. [Pull Requests](https://github.com/TransformerOptimus/SuperAGI/blob/CONTRIBUTING.md#pull-requests)\n\n## ✔️ Code of Conduct:\n\nPlease read our [Code of Conduct](https://github.com/TransformerOptimus/SuperAGI/blob/main/CODE_OF_CONDUCT.md) to understand the expectations we have for all contributors participating in this project. By participating, you agree to abide by our Code of Conduct.\n\n## 🚀 Quick Start\n\nYou can quickly get started with contributing by searching for issues with the labels **\"Good First Issue\"** or **\"Help Needed\"** in the [Issues Section](https://github.com/TransformerOptimus/SuperAGI/Issues). If you think you can contribute, comment on the issue and we will assign it to you.  \n\nTo set up your development environment, please follow the steps mentioned below : \n\n1. Fork the repository and create a clone of the fork\n2. Create a branch for a feature or a bug you are working on in your fork\n3. Once you've created your branch, follow the instructions in the [README.MD](https://github.com/TransformerOptimus/SuperAGI/README.MD)\n\n## Contributing Guidelines \n \n### 🔍 Reporting Bugs\n\nYou can start working on an existing bug that has been reported and labeled as **\"Bug\"** in the Issues Section, and you can report your bugs in the following manner :\n\n1. Title describing the issue clearly and concisely with relevant labels\n2. Provide a detailed description of the problem and the necessary steps to reproduce the issue.\n3. Include any relevant logs, screenshots, or other helpful information supporting the issue.\n\n### :bulb: New Feature or Suggesting Enhancements\n\nThis section guides you through working on an enhancement **Including a completely New Feature** & **Enhancements to an existing functionality**. \n\nBefore getting started, Perform a search on Issues to see if the enhancement or feature has already been suggested and picked up. If the feature or enhancement is suggested and not picked up, comment on the issue and assign yourself to it. \n\nIf the feature or enhancement is not in the issues, find out whether your idea fits with the scope and aims of the project by looking at the [Roadmap](https://github.com/users/TransformerOptimus/projects/5/). If yes, raise an issue with the label **\"Feature Request\"** in the following manner: \n\n1. Title describing the feature or enhancement in a clear and concise manner\n2. Clearly describe the proposed enhancement, highlighting its benefits and potential drawbacks.\n3. Provide examples and supporting information.\n\nOnce you have raised the issue and have gotten yourself assigned, you can start working on the feature or enhancement. Please make sure the feature or enhancement you're working on is placed on the Roadmap.\n\n## Testing your Changes\n\nEach method or the function of the code should have a unit test with the maximum coverage possible and on each Pull Request, we have GitHub Actions triggered, which\nruns all the unit tests where all the tests should pass for merging the Pull Request. \n\n## Pull Request\n\nNow that you have worked on your code and tested it thoroughly, you can now go ahead and raise the pull request. Please make sure that the Pull Request adheres to the following guidelines: \n\n1.  The pull request is atomic and focuses on a single change.\n2.  You have read the contributing guide and your code conforms to the guidelines.\n3.  You have documented your changes clearly and comprehensively.\n4.  You have added the required tests.\n\n\n"
  },
  {
    "path": "Dockerfile",
    "content": "# Stage 1: Compile image\nFROM python:3.10-slim-bullseye AS compile-image\nWORKDIR /app\n\nRUN apt-get update && \\\n    apt-get install --no-install-recommends -y wget libpq-dev gcc g++ && \\\n    apt-get clean && \\\n    rm -rf /var/lib/apt/lists/*\n\nRUN python -m venv /opt/venv\nENV PATH=\"/opt/venv/bin:$PATH\"\n\nCOPY requirements.txt .\nRUN pip install --upgrade pip && \\\n    pip install --no-cache-dir -r requirements.txt\n\nRUN python3.10 -c \"import nltk; nltk.download('punkt')\" && \\\n  python3.10 -c \"import nltk; nltk.download('averaged_perceptron_tagger')\"\n\nCOPY . .\n\nRUN chmod +x ./entrypoint.sh ./wait-for-it.sh ./install_tool_dependencies.sh ./entrypoint_celery.sh\n\n# Stage 2: Build image\nFROM python:3.10-slim-bullseye AS build-image\nWORKDIR /app\n\nRUN apt-get update && \\\n    apt-get install --no-install-recommends -y libpq-dev && \\\n    apt-get clean && \\\n    rm -rf /var/lib/apt/lists/*\n\nCOPY --from=compile-image /opt/venv /opt/venv\nCOPY --from=compile-image /app /app\nCOPY --from=compile-image /root/nltk_data /root/nltk_data\n\nENV PATH=\"/opt/venv/bin:$PATH\"\n\nEXPOSE 8001"
  },
  {
    "path": "Dockerfile-gpu",
    "content": "# Define the CUDA SDK version you need\nARG CUDA_IMAGE=\"12.1.1-devel-ubuntu22.04\"\nFROM nvidia/cuda:${CUDA_IMAGE}\n\nENV DEBIAN_FRONTEND=noninteractive\n\nWORKDIR /app\n\nRUN apt-get update && apt-get upgrade -y \\\n    && apt-get install -y git build-essential \\\n    python3 python3-pip python3.10-venv  libpq-dev gcc wget \\\n    ocl-icd-opencl-dev opencl-headers clinfo \\\n    libclblast-dev libopenblas-dev \\\n    && mkdir -p /etc/OpenCL/vendors && echo \"libnvidia-opencl.so.1\" > /etc/OpenCL/vendors/nvidia.icd\n\n# Create a virtual environment and activate it\nRUN python3 -m venv /opt/venv\nENV PATH=\"/opt/venv/bin:$PATH\"\n\n# Install Python dependencies from requirements.txt\nCOPY requirements.txt .\nRUN pip install --upgrade pip && \\\n    pip install --no-cache-dir -r requirements.txt\n\n# Running nltk setup as you mentioned\nRUN python3.10 -c \"import nltk; nltk.download('punkt')\" && \\\n    python3.10 -c \"import nltk; nltk.download('averaged_perceptron_tagger')\"\n\n# Copy the application code\nCOPY . .\n\nENV CUDA_DOCKER_ARCH=all\nENV LLAMA_CUBLAS=1\n\nRUN CMAKE_ARGS=\"-DLLAMA_CUBLAS=on\" pip install llama-cpp-python==0.2.7 --force-reinstall --upgrade --no-cache-dir\n\n# Make necessary scripts executable\nRUN chmod +x ./entrypoint.sh ./wait-for-it.sh ./install_tool_dependencies.sh ./entrypoint_celery.sh\n\n# Set environment variable to point to the custom libllama.so\n# ENV LLAMA_CPP_LIB=/app/llama.cpp/libllama.so\n\nEXPOSE 8001\n\nCMD [\"./entrypoint.sh\"]"
  },
  {
    "path": "DockerfileCelery",
    "content": "FROM python:3.9\n\nWORKDIR /app\n\n#RUN apt-get update && apt-get install --no-install-recommends -y git wget libpq-dev gcc python3-dev && pip install psycopg2\nRUN pip install --upgrade pip\n\nCOPY requirements.txt .\nRUN pip install --no-cache-dir -r requirements.txt\n\nCOPY . .\n\n# Downloads the tools\nRUN python superagi/tool_manager.py\n\n# Set executable permissions for install_tool_dependencies.sh\nRUN chmod +x install_tool_dependencies.sh\n\n# Install dependencies\nRUN ./install_tool_dependencies.sh\n\n# Downloads the tools\nRUN python superagi/tool_manager.py\n\n# Set executable permissions for install_tool_dependencies.sh\nRUN chmod +x install_tool_dependencies.sh\n\n# Install dependencies\nRUN ./install_tool_dependencies.sh\n\n\nCMD [\"celery\", \"-A\", \"superagi.worker\", \"worker\", \"--beat\",\"--loglevel=info\"]\n"
  },
  {
    "path": "DockerfileRedis",
    "content": "FROM redis/redis-stack-server:latest"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2023 TransformerOptimus\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.MD",
    "content": "<p align=\"center\">\n  <a href=\"https://superagi.com//#gh-light-mode-only\">\n    <img src=\"https://superagi.com/wp-content/uploads/2023/05/Logo-dark.svg\" width=\"318px\" alt=\"SuperAGI logo\" />\n  </a>\n  <a href=\"https://superagi.com//#gh-dark-mode-only\">\n    <img src=\"https://superagi.com/wp-content/uploads/2023/05/Logo-light.svg\" width=\"318px\" alt=\"SuperAGI logo\" />\n  </a>\n\n</p>\n\n<p align=\"center\"><i>Open-source framework to build, manage and run useful Autonomous AI Agents</i></p>\n    \n\n<p align=\"center\">\n<a href=\"https://superagi.com\"> <img src=\"https://superagi.com/wp-content/uploads/2023/08/Website.svg\"></a>\n<a href=\"https://app.superagi.com\"> <img src=\"https://superagi.com/wp-content/uploads/2023/07/Cloud.svg\"></a>\n<a href=\"https://marketplace.superagi.com/\"> <img src=\"https://superagi.com/wp-content/uploads/2023/08/Marketplace.svg\"></a>\n<a href=\"https://superagi.com/docs/\"> <img src=\"https://superagi.com/wp-content/uploads/2023/08/Docs.svg\"></a>\n<a href=\"https://documenter.getpostman.com/view/28438662/2s9Xy6rqP5\"> <img src=\"https://superagi.com/wp-content/uploads/2023/08/APIs.svg\"></a>\n</p>\n\n<p align=\"center\">\n<a href=\"https://github.com/TransformerOptimus/SuperAGI/fork\" target=\"blank\">\n<img src=\"https://img.shields.io/github/forks/TransformerOptimus/SuperAGI?style=for-the-badge\" alt=\"SuperAGI forks\"/>\n</a>\n\n<a href=\"https://github.com/TransformerOptimus/SuperAGI/stargazers\" target=\"blank\">\n<img src=\"https://img.shields.io/github/stars/TransformerOptimus/SuperAGI?style=for-the-badge\" alt=\"SuperAGI stars\"/>\n</a>\n<a href='https://github.com/TransformerOptimus/SuperAGI/releases'>\n<img src='https://img.shields.io/github/release/TransformerOptimus/SuperAGI?&label=Latest&style=for-the-badge'>\n</a>\n\n<a href=\"https://github.com/TransformerOptimus/SuperAGI/commits\" target=\"blank\">\n<img src=\"https://img.shields.io/github/commits-since/TransformerOptimus/SuperAGI/v0.0.11.svg?style=for-the-badge\" alt=\"SuperAGI Commits\"/>\n</a>\n</p>\n\n<p align=\"center\"><b>Follow SuperAGI </b></p>\n\n<p align=\"center\">\n<a href=\"https://twitter.com/_superAGI\" target=\"blank\">\n<img src=\"https://img.shields.io/twitter/follow/_superAGI?label=Follow: _superAGI&style=social\" alt=\"Follow _superAGI\"/>\n</a>\n<a href=\"https://www.reddit.com/r/Super_AGI\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/url?label=/r/Super_AGI&logo=reddit&style=social&url=https://github.com/TransformerOptimus/SuperAGI\"/></a>\n\n<a href=\"https://discord.gg/dXbRe5BHJC\" target=\"blank\">\n<img src=\"https://img.shields.io/discord/1107593006032355359?label=Join%20SuperAGI&logo=discord&style=social\" alt=\"Join SuperAGI Discord Community\"/>\n</a>\n<a href=\"https://www.youtube.com/@_superagi\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/url?label=Youtube&logo=youtube&style=social&url=https://github.com/TransformerOptimus/SuperAGI\"/></a>\n</p>\n\n<p align=\"center\"><b>Connect with the Creator </b></p>\n\n<p align=\"center\">\n<a href=\"https://twitter.com/ishaanbhola\" target=\"blank\">\n<img src=\"https://img.shields.io/twitter/follow/ishaanbhola?label=Follow: ishaanbhola&style=social\" alt=\"Follow ishaanbhola\"/>\n</a>\n</p>\n\n<p align=\"center\"><b>Share SuperAGI Repository</b></p>\n\n<p align=\"center\">\n\n<a href=\"https://twitter.com/intent/tweet?text=Check%20this%20GitHub%20repository%20out.%20SuperAGI%20-%20Let%27s%20you%20easily%20build,%20manage%20and%20run%20useful%20autonomous%20AI%20agents.&url=https://github.com/TransformerOptimus/SuperAGI&hashtags=SuperAGI,AGI,Autonomics,future\" target=\"blank\">\n<img src=\"https://img.shields.io/twitter/follow/_superAGI?label=Share Repo on Twitter&style=social\" alt=\"Follow _superAGI\"/></a> \n<a href=\"https://t.me/share/url?text=Check%20this%20GitHub%20repository%20out.%20SuperAGI%20-%20Let%27s%20you%20easily%20build,%20manage%20and%20run%20useful%20autonomous%20AI%20agents.&url=https://github.com/TransformerOptimus/SuperAGI\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/url?label=Telegram&logo=Telegram&style=social&url=https://github.com/TransformerOptimus/SuperAGI\" alt=\"Share on Telegram\"/></a>\n<a href=\"https://api.whatsapp.com/send?text=Check%20this%20GitHub%20repository%20out.%20SuperAGI%20-%20Let's%20you%20easily%20build,%20manage%20and%20run%20useful%20autonomous%20AI%20agents.%20https://github.com/TransformerOptimus/SuperAGI\"><img src=\"https://img.shields.io/twitter/url?label=whatsapp&logo=whatsapp&style=social&url=https://github.com/TransformerOptimus/SuperAGI\" /></a> <a href=\"https://www.reddit.com/submit?url=https://github.com/TransformerOptimus/SuperAGI&title=Check%20this%20GitHub%20repository%20out.%20SuperAGI%20-%20Let's%20you%20easily%20build,%20manage%20and%20run%20useful%20autonomous%20AI%20agents.\n\" target=\"blank\">\n<img src=\"https://img.shields.io/twitter/url?label=Reddit&logo=Reddit&style=social&url=https://github.com/TransformerOptimus/SuperAGI\" alt=\"Share on Reddit\"/>\n</a> <a href=\"mailto:?subject=Check%20this%20GitHub%20repository%20out.&body=SuperAGI%20-%20Let%27s%20you%20easily%20build,%20manage%20and%20run%20useful%20autonomous%20AI%20agents.%3A%0Ahttps://github.com/TransformerOptimus/SuperAGI\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/url?label=Gmail&logo=Gmail&style=social&url=https://github.com/TransformerOptimus/SuperAGI\"/></a> <a href=\"https://www.buymeacoffee.com/superagi\" target=\"_blank\"><img src=\"https://cdn.buymeacoffee.com/buttons/default-orange.png\" alt=\"Buy Me A Coffee\" height=\"23\" width=\"100\" style=\"border-radius:1px\"></a>\n\n</p>\n\n<hr>\n\n## What are we ?\n\nA dev-first open source autonomous AI agent framework enabling developers to build, manage & run useful autonomous agents. You can run concurrent agents seamlessly, extend agent capabilities with tools. The agents efficiently perform a variety of tasks and continually improve their performance with each subsequent run.\n\n\n### 💡 Features\n\n- <b>Provision, Spawn & Deploy Autonomous AI Agents</b> - Create production-ready & scalable autonomous agents.\n- <b>Extend Agent Capabilities with Toolkits</b> - Add Toolkits from our marketplace to your agent workflows.\n- <b>Graphical User Interface</b> - Access your agents through a graphical user interface.\n- <b>Action Console</b> - Interact with agents by giving them input and permissions.\n- <b>Multiple Vector DBs</b> - Connect to multiple Vector DBs to enhance your agent’s performance.\n- <b>Performance Telemetry</b> - Get insights into your agent’s performance and optimize accordingly.\n- <b>Optimized Token Usage</b> - Control token usage to manage costs effectively.\n- <b>Agent Memory Storage</b> - Enable your agents to learn and adapt by storing their memory.\n- <b>Models</b> - Custom fine tuned models for business specific usecases.\n- <b>Workflows</b> - Automate tasks with ease using ReAct LLM's predefined steps.\n\n### 🛠 Toolkits\nToolkits allow SuperAGI Agents to interact with external systems and third-party plugins.\n\n<a href=\"https://marketplace.superagi.com/\" target=\"_blank\"><img src=https://superagi.com/wp-content/uploads/2023/08/Twitter.png height=50px width=50px alt=\"Twitter\" valign=\"middle\" title=\"Twitter\"></a> <a href=\"https://marketplace.superagi.com/\" target=\"_blank\"><img src=https://superagi.com/wp-content/uploads/2023/08/Coding.png height=50px width=50px alt=\"Coding Tool\" valign=\"middle\" title=\"Coding Tool\"></a> <a href=\"https://marketplace.superagi.com/\" target=\"_blank\"><img src=https://superagi.com/wp-content/uploads/2023/08/Insta.png height=50px width=50px alt=\"Instagram\" valign=\"middle\" title=\"Instagram\"></a> <a href=\"https://marketplace.superagi.com/\" target=\"_blank\"><img src=https://superagi.com/wp-content/uploads/2023/08/Knowledge_tool.png height=50px width=50px alt=\"Knowledge Search\" valign=\"middle\" title=\"Knowledge Search\"></a> <a href=\"https://marketplace.superagi.com/\" target=\"_blank\"><img src=https://superagi.com/wp-content/uploads/2023/05/Group-113612.png height=50px width=50px alt=\"Email\"  valign=\"middle\" title=\"Email\"></a> <a href=\"https://marketplace.superagi.com/\" target=\"_blank\"><img src=https://superagi.com/wp-content/uploads/2023/05/Group-113610.png height=50px width=50px alt=\"Jira\" valign=\"middle\" title=\"Jira\"></a> <a href=\"https://marketplace.superagi.com/\" target=\"_blank\"><img src=https://superagi.com/wp-content/uploads/2023/05/Group-113611.png height=50px width=50px alt=\"File Manager\" valign=\"middle\" title=\"File Manager\"></a> <a href=\"https://marketplace.superagi.com/\" target=\"_blank\"><img src=https://superagi.com/wp-content/uploads/2023/05/Group-113613.png height=50px width=50px alt=\"Google Search\" valign=\"middle\" title=\"Google Search\"></a> <a href=\"https://marketplace.superagi.com/\" target=\"_blank\"><img src=https://superagi.com/wp-content/uploads/2023/05/Group-113615.png height=50px width=50px alt=\"Dall-E\" valign=\"middle\" title=\"Dall-E\"></a> <a href=\"https://marketplace.superagi.com/\" target=\"_blank\"><img src=https://superagi.com/wp-content/uploads/2023/05/Group-113614.png height=50px width=50px alt=\"Github\" valign=\"middle\" title=\"Github\"></a> <a href=\"https://marketplace.superagi.com/\" target=\"_blank\"><img src=https://superagi.com/wp-content/uploads/2023/05/Group-113616.png height=50px width=50px alt=\"Web Interaction\" valign=\"middle\" title=\"Web Interaction\"></a> <a href=\"https://marketplace.superagi.com/\" target=\"_blank\"><img src=https://superagi.com/wp-content/uploads/2023/05/Group-113622.png height=50px width=50px alt=\"Duckduckgo\" valign=\"middle\" title=\"Duckduckgo\"></a> <a href=\"https://marketplace.superagi.com/\" target=\"_blank\"><img src=https://superagi.com/wp-content/uploads/2023/08/Calendar_tool.png height=50px width=50px alt=\"Google Calendar\" valign=\"middle\" title=\"Google Calendar\"></a> <a href=\"https://marketplace.superagi.com/\" target=\"_blank\"><img src=https://superagi.com/wp-content/uploads/2023/08/Search_tool.png height=50px width=50px alt=\"Google Calendar\" valign=\"middle\" title=\"Google Search\"></a> <a href=\"https://marketplace.superagi.com/\" target=\"_blank\"><img src=https://superagi.com/wp-content/uploads/2023/08/Serp.png height=50px width=50px alt=\"Serp API\" valign=\"middle\" title=\"Serp API\"></a> <a href=\"https://marketplace.superagi.com/\" target=\"_blank\"><img src=https://superagi.com/wp-content/uploads/2023/08/Searx.png height=50px width=50px alt=\"Searx\" valign=\"middle\" title=\"Searx \"></a> <a href=\"https://marketplace.superagi.com/\" target=\"_blank\"><img src=https://superagi.com/wp-content/uploads/2023/08/Web_scraper_logo.png height=50px width=50px alt=\"Web Scraper\" valign=\"middle\" title=\"Web Scraper\"></a> <a href=\"https://marketplace.superagi.com/\" target=\"_blank\"><img src=https://superagi.com/wp-content/uploads/2023/08/Notion_logo.png height=50px width=50px alt=\"Notion\" valign=\"middle\" title=\"Notion\"></a> <a href=\"https://marketplace.superagi.com/\" target=\"_blank\"><img src=https://superagi.com/wp-content/uploads/2023/08/Apollo_logo.png height=50px width=50px alt=\"Apollo\" valign=\"middle\" title=\"Apollo\"></a>\n\n### ⚙️ Installation\n\nYou can install superAGI using one of the following three approaches.\n\n#### ☁️ SuperAGI cloud\n\nTo quickly start experimenting with agents without the hassle of setting up the system, try [Superagi Cloud](https://app.superagi.com/)\n\n1. Visit [Superagi Cloud](https://app.superagi.com/) and log in using your github account.\n\n2. In your account settings, go to \"Model Providers\" and add your API key.\n\nYou're all set! Start running your agents effortlessly.\n\n#### 🖥️ Local\n\n1. Open your terminal and clone the SuperAGI repository.\n```\ngit clone https://github.com/TransformerOptimus/SuperAGI.git \n```\n\n2. Navigate to the cloned repository directory using the command:\n```\ncd SuperAGI\n```\n3. Create a copy of config_template.yaml, and name it config.yaml.\n\n4. Ensure that Docker is installed on your system. You can download and install it from [here](https://docs.docker.com/get-docker/).\n\n5. Once you have Docker Desktop running, run the following command in the SuperAGI directory:\n\n   a. For regular usage:\n      ```\n      docker compose -f docker-compose.yaml up --build\n      ```\n\n   b. If you want to use SuperAGI with Local LLMs and have GPU, run the following command:\n      ```\n      docker compose -f docker-compose-gpu.yml up --build\n      ```\n\n\n6. Open your web browser and navigate to http://localhost:3000 to access SuperAGI.\n\n#### 🌀 Digital Ocean\n\n<p align=\"left\">\n<a href=\"https://cloud.digitalocean.com/apps/new?repo=https://github.com/TransformerOptimus/SuperAGI/tree/main\"> <img src=\"https://www.deploytodo.com/do-btn-blue.svg\"></a><br>Deploy SuperAGI to DigitalOcean with one click.\n</p>\n\n<a id=\"architecture\">\n\n### 🌐 Architecture\n</a>\n<details>\n<summary>SuperAGI Architecture</summary>\n\n![SuperAGI Architecture](https://superagi.com/wp-content/uploads/2023/09/SuperAGI-Architecture.png)\n</details>\n\n<details>\n<summary>Agent Architecture</summary>\n\n![Agent Architecture](https://superagi.com/wp-content/uploads/2023/06/Agent-Architecture.png)\n</details>\n\n<details>\n<summary>Agent Workflow Architecture</summary>\n\n![Agent Workflow Architecture](https://superagi.com/wp-content/uploads/2023/09/Workflow-Architecture.png)\n</details>\n\n<details>\n<summary>Tools Architecture</summary>\n\n![Tools Architecture](https://superagi.com/wp-content/uploads/2023/09/Tools-Architecture.png)\n</details>\n\n<details>\n<summary>ER Diagram</summary>\n\n![ER Diagram](https://superagi.com/wp-content/uploads/2023/09/ER-Diagram.png)\n</details>\n\n### 📚 Resources\n\n* [Documentation](https://superagi.com/docs/)\n* [YouTube Channel](https://www.youtube.com/@_SuperAGI/videos)\n\n\n### 📖 Need Help?\n\nJoin our [Discord community](https://discord.gg/dXbRe5BHJC) for support and discussions.\n\n[![Join us on Discord](https://invidget.switchblade.xyz/uJ3XUGsY2R)](https://discord.gg/uJ3XUGsY2R)\n\nIf you have questions or encounter issues, please don't hesitate to [create a new issue](https://github.com/TransformerOptimus/SuperAGI/issues/new/choose) to get support.\n\n### 💻 Contribution\nWe ❤️ our contributors. We’re committed to fostering an open, welcoming, and safe environment in the community.\n\nIf you'd like to contribute, start by reading our [Contribution Guide](https://github.com/TransformerOptimus/SuperAGI/blob/main/CONTRIBUTING.md).\n\nWe expect everyone participating in the community to abide by our [Code of Conduct](https://github.com/TransformerOptimus/SuperAGI/blob/main/CODE_OF_CONDUCT.md).\n\nTo get more idea on where we are heading, checkout our roadmap [here](https://github.com/users/TransformerOptimus/projects/5/views/1).\n\nExplore some [good first issues](https://github.com/TransformerOptimus/SuperAGI/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) to start contributing.\n\n### 👩‍💻 Contributors\n[![TransformerOptimus](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/133493246?v=4&w=50&h=50&mask=circle)](https://github.com/TransformerOptimus) [![Cptsnowcrasher](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/133322218?v=4&w=50&h=50&mask=circle)](https://github.com/Cptsnowcrasher) [![vectorcrow](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/133646556?v=4&w=50&h=50&mask=circle)](https://github.com/vectorcrow) [![Akki-jain](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/92881074?v=4&w=50&h=50&mask=circle)](https://github.com/Akki-jain) [![Autocop-Agent](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/129729746?v=4&w=50&h=50&mask=circle)](https://github.com/Autocop-Agent)[![COLONAYUSH](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/60507126?v=4&w=50&h=50&mask=circle)](https://github.com/COLONAYUSH)[![luciferlinx101](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/129729795?v=4&w=50&h=50&mask=circle)](https://github.com/luciferlinx101)[![mukundans89](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/101278493?v=4&w=50&h=50&mask=circle)](https://github.com/mukundans89)[![Fluder-Paradyne](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/121793617?v=4&w=50&h=50&mask=circle)](https://github.com/Fluder-Paradyne)[![nborthy](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/101320057?v=4&w=50&h=50&mask=circle)](https://github.com/nborthy)[![nihirr](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/122777244?v=4&w=50&h=50&mask=circle)](https://github.com/nihirr)[![Tarraann](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/97586318?v=4&w=50&h=50&mask=circle)](https://github.com/Tarraann)[![neelayan7](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/43145646?v=4&w=50&h=50&mask=circle)](https://github.com/neelayan7)[![Arkajit-Datta](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/61142632?v=4&w=50&h=50&mask=circle)](https://github.com/Arkajit-Datta)[![guangchen811](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/103159823?v=4&w=50&h=50&mask=circle)](https://github.com/guangchen811)[![juanfpo96](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/14787156?v=4&w=50&h=50&mask=circle)](https://github.com/juanfpo96)[![iskandarreza](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/32027019?v=4&w=50&h=50&mask=circle)](https://github.com/iskandarreza)[![jpenalbae](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/8380459?v=4&w=50&h=50&mask=circle)](https://github.com/jpenalbae)[![pallasite99](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/26508636?v=4&w=50&h=50&mask=circle)](https://github.com/pallasite99)[![xutpuu](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/11964505?v=4&w=50&h=50&mask=circle)](https://github.com/xutpuu)[![alexkreidler](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/11166947?v=4&w=50&h=50&mask=circle)](https://github.com/alexkreidler)[![hanhyalex123](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/100895608?v=4&w=50&h=50&mask=circle)](https://github.com/hanhyalex123)[![ps4vs](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/91535358?v=4&w=50&h=50&mask=circle)](https://github.com/ps4vs)[![eltociear](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/22633385?v=4&w=50&h=50&mask=circle)](https://github.com/eltociear)\n[![shaiss](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/113060?v=4&w=50&h=50&mask=circle)](https://github.com/shaiss)\n[![AdityaRajSingh1992](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/105219157?v=4&w=50&h=50&mask=circle)](https://github.com/AdityaRajSingh1992)\n[![namansleeps2](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/134390870?v=4&w=50&h=50&mask=circle)](https://github.com/namansleeps22)\n[![sirajperson](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/396941?v=4&w=50&h=50&mask=circle)](https://github.com/sirajperson)\n[![hsm207](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/2398765?v=4&w=50&h=50&mask=circle)](https://github.com/hsm207)\n[![unkn-wn](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/43097991?v=4&w=50&h=50&mask=circle)](https://github.com/unkn-wn)\n[![DMTarmey](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/590474?v=4&w=50&h=50&mask=circle)](https://github.com/DMTarmey)\n[![Parth2506](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/122429822?v=4&w=50&h=50&mask=circle)](https://github.com/Parth2506)\n[![platinaCoder](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/47349795?v=4&w=50&h=50&mask=circle)](https://github.com/platinaCoder)\n[![anisha1607](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/60440541?v=4&w=50&h=50&mask=circle)](https://github.com/anisha1607)\n[![jorgectf](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/46056498?v=4&w=50&h=50&mask=circle)](https://github.com/jorgectf)\n[![PaulRBerg](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/8782666?v=4&w=50&h=50&mask=circle)](https://github.com/PaulRBerg)\n[![boundless-asura](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/122777244?v=4&w=50&h=50&mask=circle)](https://github.com/boundless-asura)\n[![JPDucky](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/34105363?v=4&w=50&h=50&mask=circle)](https://github.com/JPDucky)\n[![Vibhusha22](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/128478691?v=4&w=50&h=50&mask=circle)](https://github.com/Vibhusha22)\n[![ai-akuma](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/7444521?v=4&w=50&h=50&mask=circle)](https://github.com/ai-akuma)\n[![rounak610](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/81288115?v=4&w=50&h=50&mask=circle)](https://github.com/rounak610)\n[![AdarshJha619](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/53672264?v=4&w=50&h=50&mask=circle)](https://github.com/AdarshJha619)\n[![ResoluteStoic](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/105219157?v=4&w=50&h=50&mask=circle)](https://github.com/ResoluteStoic)\n[![JohnHunt999](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/137149331?v=4&w=50&h=50&mask=circle)](https://github.com/JohnHunt999)\n[![Maverick-F35](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/138012351?v=4&w=50&h=50&mask=circle)](https://github.com/Maverick-F359)\n[![jorgectf](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/46056498?v=4&w=50&h=50&mask=circle)](https://github.com/jorgectf)\n[![AdityaSharma13064](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/138581531?v=4&w=50&h=50&mask=circle)](https://github.com/AdityaSharma13064)\n[![lalitlj](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/138583454?v=4&w=50&h=50&mask=circle)](https://github.com/lalitlj)\n[![andrew-kelly-neutralaiz](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/128111428?v=4&w=50&h=50&mask=circle)](https://github.com/andrew-kelly-neutralaiz)\n[![sayan1101](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/139119661?v=4&w=50&h=50&mask=circle)](https://github.com/sayan1101)\n\n\n<p align=\"center\"><a href=\"https://github.com/TransformerOptimus/SuperAGI#\"><img src=\"https://superagi.com/wp-content/uploads/2023/05/backToTopButton.png\" alt=\"Back to top\" height=\"29\"/></a></p>\n\n### ⚠️ Under Development!\nThis project is under active development and may still have issues. We appreciate your understanding and patience. If you encounter any problems, please check the open issues first. If your issue is not listed, kindly create a new issue detailing the error or problem you experienced. Thank you for your support!\n"
  },
  {
    "path": "alembic.ini",
    "content": "# A generic, single database configuration.\n\n[alembic]\n# path to migration scripts\nscript_location = migrations\n\n# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s\n# Uncomment the line below if you want the files to be prepended with date and time\n# see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file\n# for all available tokens\n# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s\n\n# sys.path path, will be prepended to sys.path if present.\n# defaults to the current working directory.\nprepend_sys_path = .\n\n# timezone to use when rendering the date within the migration file\n# as well as the filename.\n# If specified, requires the python-dateutil library that can be\n# installed by adding `alembic[tz]` to the pip requirements\n# string value is passed to dateutil.tz.gettz()\n# leave blank for localtime\n# timezone =\n\n# max length of characters to apply to the\n# \"slug\" field\n# truncate_slug_length = 40\n\n# set to 'true' to run the environment during\n# the 'revision' command, regardless of autogenerate\n# revision_environment = false\n\n# set to 'true' to allow .pyc and .pyo files without\n# a source .py file to be detected as revisions in the\n# versions/ directory\n# sourceless = false\n\n# version location specification; This defaults\n# to migrations/versions.  When using multiple version\n# directories, initial revisions must be specified with --version-path.\n# The path separator used here should be the separator specified by \"version_path_separator\" below.\n# version_locations = %(here)s/bar:%(here)s/bat:migrations/versions\n\n# version path separator; As mentioned above, this is the character used to split\n# version_locations. The default within new alembic.ini files is \"os\", which uses os.pathsep.\n# If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas.\n# Valid values for version_path_separator are:\n#\n# version_path_separator = :\n# version_path_separator = ;\n# version_path_separator = space\nversion_path_separator = os  # Use os.pathsep. Default configuration used for new projects.\n\n# set to 'true' to search source files recursively\n# in each \"version_locations\" directory\n# new in Alembic version 1.10\n# recursive_version_locations = false\n\n# the output encoding used when revision files\n# are written from script.py.mako\n# output_encoding = utf-8\n\nsqlalchemy.url = postgresql://superagi:password@super__postgres:5432/super_agi_main\n\n[post_write_hooks]\n# post_write_hooks defines scripts or Python functions that are run\n# on newly generated revision scripts.  See the documentation for further\n# detail and examples\n\n# format using \"black\" - use the console_scripts runner, against the \"black\" entrypoint\n# hooks = black\n# black.type = console_scripts\n# black.entrypoint = black\n# black.options = -l 79 REVISION_SCRIPT_FILENAME\n\n# Logging configuration\n[loggers]\nkeys = root,sqlalchemy,alembic\n\n[handlers]\nkeys = console\n\n[formatters]\nkeys = generic\n\n[logger_root]\nlevel = WARN\nhandlers = console\nqualname =\n\n[logger_sqlalchemy]\nlevel = WARN\nhandlers =\nqualname = sqlalchemy.engine\n\n[logger_alembic]\nlevel = INFO\nhandlers =\nqualname = alembic\n\n[handler_console]\nclass = StreamHandler\nargs = (sys.stderr,)\nlevel = NOTSET\nformatter = generic\n\n[formatter_generic]\nformat = %(levelname)-5.5s [%(name)s] %(message)s\ndatefmt = %H:%M:%S\n"
  },
  {
    "path": "cli2.py",
    "content": "import os\r\nimport sys\r\nimport subprocess\r\nfrom time import sleep\r\nimport shutil\r\nfrom sys import platform\r\nfrom multiprocessing import Process\r\nfrom superagi.lib.logger import logger\r\n\r\n\r\ndef check_command(command, message):\r\n    if not shutil.which(command):\r\n        logger.info(message)\r\n        sys.exit(1)\r\n\r\n\r\ndef run_npm_commands(shell=False):\r\n    os.chdir(\"gui\")\r\n    try:\r\n        subprocess.run([\"npm\", \"install\"], check=True, shell=shell)\r\n    except subprocess.CalledProcessError:\r\n        logger.error(f\"Error during '{' '.join(sys.exc_info()[1].cmd)}'. Exiting.\")\r\n        sys.exit(1)\r\n    os.chdir(\"..\")\r\n\r\n\r\ndef run_server(shell=False,a_name=None,a_description=None,goals=None):\r\n    tgwui_process = Process(target=subprocess.run, args=([\"python\", \"test.py\",\"--name\",a_name,\"--description\",a_description,\"--goals\"]+goals,), kwargs={\"shell\": shell})\r\n    api_process = Process(target=subprocess.run, args=([\"uvicorn\", \"main:app\", \"--host\", \"0.0.0.0\", \"--port\", \"8000\"],), kwargs={\"shell\": shell})\r\n    celery_process = Process(target=subprocess.run, args=([\"celery\", \"-A\", \"celery_app\", \"worker\", \"--loglevel=info\"],), kwargs={\"shell\": shell})\r\n    ui_process = Process(target=subprocess.run, args=([\"python\", \"test.py\",\"--name\",a_name,\"--description\",a_description,\"--goals\"]+goals,), kwargs={\"shell\": shell})\r\n    api_process.start()\r\n    celery_process.start()\r\n    ui_process.start()\r\n\r\n    return api_process, ui_process, celery_process\r\n\r\n\r\ndef cleanup(api_process, ui_process, celery_process):\r\n    logger.info(\"Shutting down processes...\")\r\n    api_process.terminate()\r\n    ui_process.terminate()\r\n    celery_process.terminate()\r\n    logger.info(\"Processes terminated. Exiting.\")\r\n    sys.exit(1)\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    check_command(\"node\", \"Node.js is not installed. Please install it and try again.\")\r\n    check_command(\"npm\", \"npm is not installed. Please install npm to proceed.\")\r\n    check_command(\"uvicorn\", \"uvicorn is not installed. Please install uvicorn to proceed.\")\r\n\r\n    agent_name = input(\"Enter an agent name: \")\r\n    agent_description = input(\"Enter an agent description: \")\r\n    goals = []\r\n    while True:\r\n        goal = input(\"Enter a goal (or 'q' to quit): \")\r\n        if goal == 'q':\r\n            break\r\n        goals.append(goal)\r\n    isWindows = False\r\n    if platform == \"win32\" or platform == \"cygwin\":\r\n        isWindows = True\r\n    run_npm_commands(shell=isWindows)\r\n\r\n    try:\r\n        api_process, ui_process, celery_process = run_server(isWindows, agent_name, agent_description, goals)\r\n        while True:\r\n            try:\r\n                sleep(30)\r\n            except KeyboardInterrupt:\r\n                cleanup(api_process, ui_process, celery_process)\r\n    except Exception as e:\r\n        cleanup(api_process, ui_process, celery_process)"
  },
  {
    "path": "config_template.yaml",
    "content": "#####################------------------SYSTEM KEYS-------------------------########################\nPINECONE_API_KEY: YOUR_PINECONE_API_KEY\nPINECONE_ENVIRONMENT: YOUR_PINECONE_ENVIRONMENT\n\nOPENAI_API_KEY: YOUR_OPEN_API_KEY\nPALM_API_KEY: YOUR_PALM_API_KEY\nREPLICATE_API_TOKEN: YOUR_REPLICATE_API_TOKEN\nHUGGING_API_TOKEN: YOUR_HUGGING_FACE_API_TOKEN\n\n# For locally hosted LLMs comment out the next line and uncomment the one after\n# to configure a local llm point your browser to 127.0.0.1:7860 and click on the model tab in text generation web ui.\nOPENAI_API_BASE: https://api.openai.com/v1\n#OPENAI_API_BASE: \"http://super__tgwui:5001/v1\"\n\n# \"gpt-3.5-turbo-0301\": 4032, \"gpt-4-0314\": 8092, \"gpt-3.5-turbo\": 4032, \"gpt-4\": 8092, \"gpt-4-32k\": 32768, \"gpt-4-32k-0314\": 32768, \"llama\":2048, \"mpt-7b-storywriter\":45000\nMODEL_NAME: \"gpt-3.5-turbo-0301\"\n# \"gpt-3.5-turbo\", , \"gpt-4\", \"models/chat-bison-001\"\nRESOURCES_SUMMARY_MODEL_NAME: \"gpt-3.5-turbo\"\nMAX_TOOL_TOKEN_LIMIT: 800\nMAX_MODEL_TOKEN_LIMIT: 4032 # set to 2048 for llama\n\n#DATABASE INFO\n# redis details\nDB_NAME: super_agi_main\nDB_HOST: super__postgres\nDB_USERNAME: superagi\nDB_PASSWORD: password\nDB_URL: postgresql://superagi:password@super__postgres:5432/super_agi_main\nREDIS_URL: \"super__redis:6379\"\n\n#STORAGE TYPE (\"FILE\" or \"S3\")\nSTORAGE_TYPE: \"FILE\"\n\n#TOOLS\nTOOLS_DIR: \"superagi/tools\"\n\n#STORAGE INFO FOR FILES\nRESOURCES_INPUT_ROOT_DIR: workspace/input/{agent_id}\nRESOURCES_OUTPUT_ROOT_DIR: workspace/output/{agent_id}/{agent_execution_id} # For keeping resources at agent execution level\n#RESOURCES_OUTPUT_ROOT_DIR: workspace/output/{agent_id}  # For keeping resources at agent level\n\n#S3 RELATED DETAILS ONLY WHEN STORAGE_TYPE IS \"S3\"\nBUCKET_NAME:\nINSTAGRAM_TOOL_BUCKET_NAME:                                   #Public read bucket, Images generated by stable diffusion are put in this bucket and the public url of the same is generated.\nAWS_ACCESS_KEY_ID:\nAWS_SECRET_ACCESS_KEY:\n\n#AUTH\nENV: 'DEV' #DEV,PROD, to use GITHUB OAUTH set to PROD\nJWT_SECRET_KEY: 'secret'\nexpiry_time_hours: 1\n\n#GITHUB OAUTH:\nGITHUB_CLIENT_ID:\nGITHUB_CLIENT_SECRET:\nFRONTEND_URL: \"http://localhost:3000\"\n\n#ENCRYPTION KEY, Replace this with your own key for production\nENCRYPTION_KEY: abcdefghijklmnopqrstuvwxyz123456\n\n#WEAVIATE\n\n# If you are using docker or web hosted uncomment the next two lines and comment the third one\n# WEAVIATE_URL: YOUR_WEAVIATE_URL\n# WEAVIATE_API_KEY: YOUR_WEAVIATE_API_KEY\nWEAVIATE_USE_EMBEDDED: true\n\n\n#####################------------------TOOLS KEY-------------------------########################\n#If you have google api key and CSE key, use this\nGOOGLE_API_KEY: YOUR_GOOGLE_API_KEY\nSEARCH_ENGINE_ID: YOUR_SEARCH_ENIGNE_ID\n\n# IF YOU DONT HAVE GOOGLE SEARCH KEY, YOU CAN USE SERPER.DEV KEYS\nSERP_API_KEY: YOUR_SERPER_API_KEY\n\n#ENTER YOUR EMAIL CREDENTIALS TO ACCESS EMAIL TOOL\nEMAIL_ADDRESS: YOUR_EMAIL_ADDRESS\nEMAIL_PASSWORD: YOUR_EMAIL_APP_PASSWORD #get the app password from (https://myaccount.google.com/apppasswords)\nEMAIL_SMTP_HOST: smtp.gmail.com #Change the SMTP host if not using Gmail\nEMAIL_SMTP_PORT: 587 #Change the SMTP port if not using Gmail\nEMAIL_IMAP_SERVER: imap.gmail.com #Change the IMAP Host if not using Gmail\nEMAIL_SIGNATURE: Email sent by SuperAGI\nEMAIL_DRAFT_MODE_WITH_FOLDER: YOUR_DRAFTS_FOLDER\nEMAIL_ATTACHMENT_BASE_PATH: YOUR_DIRECTORY_FOR_EMAIL_ATTACHMENTS\n\n# GITHUB\nGITHUB_USERNAME: YOUR_GITHUB_USERNAME\nGITHUB_ACCESS_TOKEN: YOUR_GITHUB_ACCESS_TOKEN\n\n#JIRA\nJIRA_INSTANCE_URL: YOUR_JIRA_INSTANCE_URL\nJIRA_USERNAME: YOUR_JIRA_EMAIL\nJIRA_API_TOKEN: YOUR_JIRA_API_TOKEN\n\n#SLACK\nSLACK_BOT_TOKEN: YOUR_SLACK_BOT_TOKEN\n\n# For running stable diffusion\nSTABILITY_API_KEY: YOUR_STABILITY_API_KEY\n#Engine IDs that can be used: 'stable-diffusion-v1', 'stable-diffusion-v1-5','stable-diffusion-512-v2-0', 'stable-diffusion-768-v2-0','stable-diffusion-512-v2-1','stable-diffusion-768-v2-1','stable-diffusion-xl-beta-v2-2-2'\nENGINE_ID: \"stable-diffusion-xl-beta-v2-2-2\"\n\n## To config a vector store for resources manager uncomment config below\n## based on the vector store you want to use\n\n## RESOURCE_VECTOR_STORE can be REDIS, PINECONE, CHROMA, QDRANT\n#RESOURCE_VECTOR_STORE: YOUR_RESOURCE_VECTOR_STORE\n#RESOURCE_VECTOR_STORE_INDEX_NAME: YOUR_RESOURCE_VECTOR_STORE_INDEX_NAME\n\n## To use a custom redis\n#REDIS_VECTOR_STORE_URL: YOUR_REDIS_VECTOR_STORE_URL\n\n## To use qdrant for vector store in resources manager\n#QDRANT_PORT: YOUR_QDRANT_PORT\n#QDRANT_HOST_NAME: YOUR_QDRANT_HOST_NAME\n\n## To use chroma for vector store in resources manager\n#CHROMA_HOST_NAME: YOUR_CHROMA_HOST_NAME\n#CHROMA_PORT: YOUR_CHROMA_PORT\n\n## To use Qdrant for vector store\n#QDRANT_HOST_NAME: YOUR_QDRANT_HOST_NAME\n#QDRANT_PORT: YOUR_QDRANT_PORT\n#GPU_LAYERS: GPU LAYERS THAT YOU WANT TO OFFLOAD TO THE GPU WHILE USING LOCAL LLMS\n"
  },
  {
    "path": "docker-compose-dev.yaml",
    "content": "version: '3.8'\nservices:\n  backend:\n    volumes:\n      - \"./:/app\"\n    build: .\n    depends_on:\n      - super__redis\n      - super__postgres\n    networks:\n      - super_network\n    command: [\"/app/wait-for-it.sh\", \"super__postgres:5432\",\"-t\",\"60\",\"--\",\"/app/entrypoint.sh\"]\n  celery:\n    volumes:\n      - \"./:/app\"\n      - \"${EXTERNAL_RESOURCE_DIR:-./workspace}:/app/ext\"\n    build: .\n    depends_on:\n      - super__redis\n      - super__postgres\n    networks:\n      - super_network\n    command: [\"/app/entrypoint_celery.sh\"]\n  gui:\n    build:\n      context: ./gui\n      args:\n        NEXT_PUBLIC_API_BASE_URL: \"/api\"\n    networks:\n      - super_network\n#    volumes:\n#      - ./gui:/app\n#      - /app/node_modules/\n#      - /app/.next/\n  super__redis:\n    image: \"redis/redis-stack-server:latest\"\n    networks:\n      - super_network\n#    uncomment to expose redis port to host\n#    ports:\n#      - \"6379:6379\"\n    volumes:\n      - redis_data:/data\n\n  super__postgres:\n    image: \"docker.io/library/postgres:latest\"\n    environment:\n      - POSTGRES_USER=superagi\n      - POSTGRES_PASSWORD=password\n      - POSTGRES_DB=super_agi_main\n    volumes:\n      - superagi_postgres_data:/var/lib/postgresql/data/\n    networks:\n      - super_network\n#    uncomment to expose postgres port to host\n#    ports:\n#      - \"5432:5432\"\n\n  proxy:\n    image: nginx:stable-alpine\n    ports:\n      - \"3000:80\"\n    networks:\n      - super_network\n    depends_on:\n      - backend\n      - gui\n    volumes:\n      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf\n\nnetworks:\n  super_network:\n    driver: bridge\nvolumes:\n  superagi_postgres_data:\n  redis_data:\n"
  },
  {
    "path": "docker-compose-gpu.yml",
    "content": "version: '3.8'\nservices:\n  backend:\n    volumes:\n      - \"./:/app\"\n    build:\n      context: .\n      dockerfile: Dockerfile-gpu \n    depends_on:\n      - super__redis\n      - super__postgres\n    networks:\n      - super_network\n    command: [\"/app/wait-for-it.sh\", \"super__postgres:5432\",\"-t\",\"60\",\"--\",\"/app/entrypoint.sh\"]\n    deploy:\n      resources:\n        reservations:\n          devices:\n            - driver: nvidia\n              count: all\n              capabilities: [gpu]\n\n  celery:\n    volumes:\n      - \"./:/app\"\n      - \"${EXTERNAL_RESOURCE_DIR:-./workspace}:/app/ext\"\n    build:\n      context: .\n      dockerfile: Dockerfile-gpu \n    depends_on:\n      - super__redis\n      - super__postgres\n    networks:\n      - super_network\n    command: [\"/app/entrypoint_celery.sh\"]\n    deploy:\n      resources:\n        reservations:\n          devices:\n            - driver: nvidia\n              count: all\n              capabilities: [gpu]\n  gui:\n    build:\n      context: ./gui\n      args:\n        NEXT_PUBLIC_API_BASE_URL: \"/api\"\n    networks:\n      - super_network\n#    volumes:\n#      - ./gui:/app\n#      - /app/node_modules/\n#      - /app/.next/\n  super__redis:\n    image: \"redis/redis-stack-server:latest\"\n    networks:\n      - super_network\n#    uncomment to expose redis port to host\n#    ports:\n#      - \"6379:6379\"\n    volumes:\n      - redis_data:/data\n\n  super__postgres:\n    image: \"docker.io/library/postgres:15\"\n    environment:\n      - POSTGRES_USER=superagi\n      - POSTGRES_PASSWORD=password\n      - POSTGRES_DB=super_agi_main\n    volumes:\n      - superagi_postgres_data:/var/lib/postgresql/data/\n    networks:\n      - super_network\n#    uncomment to expose postgres port to host\n#    ports:\n#      - \"5432:5432\"\n\n  proxy:\n    image: nginx:stable-alpine\n    ports:\n      - \"3000:80\"\n    networks:\n      - super_network\n    depends_on:\n      - backend\n      - gui\n    volumes:\n      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf\n\nnetworks:\n  super_network:\n    driver: bridge\nvolumes:\n  superagi_postgres_data:\n  redis_data:\n"
  },
  {
    "path": "docker-compose.image.example.yaml",
    "content": "version: '3.8'\nservices:\n  backend:\n    image: \"superagidev/superagi:main\"\n    depends_on:\n      - super__redis\n      - super__postgres\n    networks:\n      - super_network\n    env_file:\n      - config.yaml\n    command: [\"/app/wait-for-it.sh\", \"super__postgres:5432\",\"-t\",\"60\",\"--\",\"/app/entrypoint.sh\"]\n\n  celery:\n    image: \"superagidev/superagi:main\"\n    depends_on:\n      - super__redis\n      - super__postgres\n    networks:\n      - super_network\n    env_file:\n      - config.yaml\n    command: [\"/app/entrypoint_celery.sh\"]\n    volumes:\n      - \"./workspace:/app/workspace\"\n\n  gui:\n    image: \"superagidev/superagi-frontend:main\"\n    environment:\n      - NEXT_PUBLIC_API_BASE_URL=/api\n    networks:\n      - super_network\n\n  super__redis:\n    image: \"redis/redis-stack-server:latest\"\n    networks:\n      - super_network\n#    uncomment to expose redis port to host\n#    ports:\n#      - \"6379:6379\"\n    volumes:\n      - redis_data:/data\n\n  super__postgres:\n    image: \"docker.io/library/postgres:latest\"\n    environment:\n      - POSTGRES_USER=superagi\n      - POSTGRES_PASSWORD=password\n      - POSTGRES_DB=super_agi_main\n    volumes:\n      - superagi_postgres_data:/var/lib/postgresql/data/\n    networks:\n      - super_network\n#    uncomment to expose postgres port to host\n#    ports:\n#      - \"5432:5432\"\n\n  proxy:\n    image: nginx:stable-alpine\n    ports:\n      - \"3000:80\"\n    networks:\n      - super_network\n    depends_on:\n      - backend\n      - gui\n    volumes:\n      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf\n\nnetworks:\n  super_network:\n    driver: bridge\nvolumes:\n  superagi_postgres_data:\n  redis_data:\n"
  },
  {
    "path": "docker-compose.yaml",
    "content": "version: '3.8'\nservices:\n  backend:\n    volumes:\n      - \"./:/app\"\n    build: .\n    depends_on:\n      - super__redis\n      - super__postgres\n    networks:\n      - super_network\n    command: [\"/app/wait-for-it.sh\", \"super__postgres:5432\",\"-t\",\"60\",\"--\",\"/app/entrypoint.sh\"]\n  celery:\n    volumes:\n      - \"./:/app\"\n      - \"${EXTERNAL_RESOURCE_DIR:-./workspace}:/app/ext\"\n    build: .\n    depends_on:\n      - super__redis\n      - super__postgres\n    networks:\n      - super_network\n    command: [\"/app/entrypoint_celery.sh\"]\n  gui:\n    build:\n      context: ./gui\n      args:\n        NEXT_PUBLIC_API_BASE_URL: \"/api\"\n    networks:\n      - super_network\n#    volumes:\n#      - ./gui:/app\n#      - /app/node_modules/\n#      - /app/.next/\n  super__redis:\n    image: \"redis/redis-stack-server:latest\"\n    networks:\n      - super_network\n#    uncomment to expose redis port to host\n#    ports:\n#      - \"6379:6379\"\n    volumes:\n      - redis_data:/data\n\n  super__postgres:\n    image: \"docker.io/library/postgres:15\"\n    environment:\n      - POSTGRES_USER=superagi\n      - POSTGRES_PASSWORD=password\n      - POSTGRES_DB=super_agi_main\n    volumes:\n      - superagi_postgres_data:/var/lib/postgresql/data/\n    networks:\n      - super_network\n#    uncomment to expose postgres port to host\n#    ports:\n#      - \"5432:5432\"\n\n  proxy:\n    image: nginx:stable-alpine\n    ports:\n      - \"3000:80\"\n    networks:\n      - super_network\n    depends_on:\n      - backend\n      - gui\n    volumes:\n      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf\n\nnetworks:\n  super_network:\n    driver: bridge\nvolumes:\n  superagi_postgres_data:\n  redis_data:"
  },
  {
    "path": "entrypoint.sh",
    "content": "#!/bin/bash\n\n# Downloads the tools from marketplace and external tool repositories\npython superagi/tool_manager.py\n\n# Install dependencies\n./install_tool_dependencies.sh\n\n# Run Alembic migrations\nalembic upgrade head\n\n# Start the app\nexec uvicorn main:app --host 0.0.0.0 --port 8001 --reload\n"
  },
  {
    "path": "entrypoint_celery.sh",
    "content": "#!/bin/bash\n\n# Downloads the tools\npython superagi/tool_manager.py\n\n# Install dependencies\n./install_tool_dependencies.sh\n\nexec celery -A superagi.worker worker --beat --loglevel=info"
  },
  {
    "path": "gui/.dockerignore",
    "content": "# Ignore everything\n**\n\n# Allow files and directories\n!app\n!pages\n!public\n!utils\n!package.json\n!next.config.js\n!package-lock.json\n!.eslintrc.json\n!jsconfig.json"
  },
  {
    "path": "gui/.eslintrc.json",
    "content": "{\n  \"extends\": \"next/core-web-vitals\"\n}\n"
  },
  {
    "path": "gui/Dockerfile",
    "content": "FROM node:18-alpine AS deps\nRUN apk add --no-cache libc6-compat\nWORKDIR /app\nCOPY package.json package-lock.json ./\nRUN npm ci\n\n# Rebuild the source code only when needed\nFROM node:18-alpine AS builder\n\nWORKDIR /app\n\nCOPY --from=deps /app/node_modules ./node_modules\n\nCOPY . .\nARG NEXT_PUBLIC_API_BASE_URL=/api\nENV NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL\nARG NEXT_PUBLIC_MIXPANEL_AUTH_ID\nENV NEXT_PUBLIC_MIXPANEL_AUTH_ID=$NEXT_PUBLIC_MIXPANEL_AUTH_ID\nEXPOSE 3000\n\nCMD [\"npm\", \"run\", \"dev\"]"
  },
  {
    "path": "gui/DockerfileProd",
    "content": "FROM node:18-alpine AS deps\nRUN apk add --no-cache libc6-compat\nWORKDIR /app\nCOPY package.json package-lock.json ./\nRUN npm ci --only=production\n\n# Rebuild the source code only when needed\nFROM node:18-alpine AS builder\n\nWORKDIR /app\n\nCOPY --from=deps /app/node_modules ./node_modules\n\nCOPY . .\nARG NEXT_PUBLIC_API_BASE_URL=/api\nENV NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL\n\nRUN npm run build\n\n# Production image, copy all the files and run next\nFROM node:18-alpine AS runner\nWORKDIR /app\n\nENV NODE_ENV production\n\nRUN addgroup --system --gid 1001 supergroup\nRUN adduser --system --uid 1001 superuser\n\nCOPY --from=builder /app/public ./public\nCOPY --from=builder /app/package.json ./package.json\n\n# Automatically leverage output traces to reduce image size\n# https://nextjs.org/docs/advanced-features/output-file-tracing\nCOPY --from=builder --chown=superuser:supergroup /app/.next/standalone ./\nCOPY --from=builder --chown=superuser:supergroup /app/.next/static ./.next/static\n\nUSER superuser\n\nEXPOSE 3000\n\nENV PORT 3000\n\nCMD [\"node\", \"server.js\"]"
  },
  {
    "path": "gui/README.md",
    "content": "This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).\n\n## Getting Started\n\nFirst, run the development server:\n\n```bash\nnpm run dev\n# or\nyarn dev\n# or\npnpm dev\n```\n\nOpen [http://localhost:3000](http://localhost:3000) with your browser to see the result.\n\nYou can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file.\n\nThis project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.\n\n## Learn More\n\nTo learn more about Next.js, take a look at the following resources:\n\n- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.\n- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.\n\nYou can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!\n\n## Deploy on Vercel\n\nThe easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.\n\nCheck out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.\n"
  },
  {
    "path": "gui/app/globals.css",
    "content": ":root {\n  --max-width: 1100px;\n  --border-radius: 12px;\n  --font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono',\n    'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro',\n    'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace;\n\n  --foreground-rgb: 0, 0, 0;\n  --background-start-rgb: 214, 219, 220;\n  --background-end-rgb: 255, 255, 255;\n\n  --primary-glow: conic-gradient(\n    from 180deg at 50% 50%,\n    #16abff33 0deg,\n    #0885ff33 55deg,\n    #54d6ff33 120deg,\n    #0071ff33 160deg,\n    transparent 360deg\n  );\n  --secondary-glow: radial-gradient(\n    rgba(255, 255, 255, 1),\n    rgba(255, 255, 255, 0)\n  );\n\n  --tile-start-rgb: 239, 245, 249;\n  --tile-end-rgb: 228, 232, 233;\n  --tile-border: conic-gradient(\n    #00000080,\n    #00000040,\n    #00000030,\n    #00000020,\n    #00000010,\n    #00000010,\n    #00000080\n  );\n\n  --callout-rgb: 238, 240, 241;\n  --callout-border-rgb: 172, 175, 176;\n  --card-rgb: 180, 185, 188;\n  --card-border-rgb: 131, 134, 135;\n}\n\n@media (prefers-color-scheme: dark) {\n  :root {\n    --foreground-rgb: 255, 255, 255;\n    --background-start-rgb: 0, 0, 0;\n    --background-end-rgb: 0, 0, 0;\n\n    --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0));\n    --secondary-glow: linear-gradient(\n      to bottom right,\n      rgba(1, 65, 255, 0),\n      rgba(1, 65, 255, 0),\n      rgba(1, 65, 255, 0.3)\n    );\n\n    --tile-start-rgb: 2, 13, 46;\n    --tile-end-rgb: 2, 5, 19;\n    --tile-border: conic-gradient(\n      #ffffff80,\n      #ffffff40,\n      #ffffff30,\n      #ffffff20,\n      #ffffff10,\n      #ffffff10,\n      #ffffff80\n    );\n\n    --callout-rgb: 20, 20, 20;\n    --callout-border-rgb: 108, 108, 108;\n    --card-rgb: 100, 100, 100;\n    --card-border-rgb: 200, 200, 200;\n  }\n}\n\n* {\n  box-sizing: border-box;\n  padding: 0;\n  margin: 0;\n}\n\nhtml,\nbody {\n  max-width: 100vw;\n  overflow-x: hidden;\n}\n\nbody {\n  color: rgb(var(--foreground-rgb));\n  background: linear-gradient(\n      to bottom,\n      transparent,\n      rgb(var(--background-end-rgb))\n    )\n    rgb(var(--background-start-rgb));\n}\n\na {\n  color: inherit;\n  text-decoration: none;\n}\n\n@media (prefers-color-scheme: dark) {\n  html {\n    color-scheme: dark;\n  }\n}"
  },
  {
    "path": "gui/app/layout.js",
    "content": "import './globals.css'\n\nexport const metadata = {\n  title: 'Super AGI',\n  description: 'Generated by create next app',\n}\n\nexport default function RootLayout({ children }) {\n  return (\n    <html lang=\"en\">\n      <body>{children}</body>\n    </html>\n  )\n}\n"
  },
  {
    "path": "gui/jsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"paths\": {\n      \"@/*\": [\"./*\"]\n    }\n  }\n}\n"
  },
  {
    "path": "gui/next.config.js",
    "content": "/** @type {import('next').NextConfig} */\nconst nextConfig = {\n  assetPrefix: process.env.NODE_ENV === \"production\" ? \"/\" : \"./\",\n  output: 'standalone'\n};\n\nmodule.exports = nextConfig;\n"
  },
  {
    "path": "gui/package.json",
    "content": "{\n  \"name\": \"super-agi\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"build\": \"next build\",\n    \"start\": \"next start\",\n    \"lint\": \"next lint\",\n    \"export\": \"next export\"\n  },\n  \"dependencies\": {\n    \"axios\": \"^1.4.0\",\n    \"bootstrap\": \"^5.2.3\",\n    \"date-fns\": \"^2.30.0\",\n    \"date-fns-tz\": \"^2.0.0\",\n    \"echarts\": \"^5.4.2\",\n    \"echarts-for-react\": \"^3.0.2\",\n    \"eslint\": \"8.40.0\",\n    \"eslint-config-next\": \"13.4.2\",\n    \"js-cookie\": \"^3.0.5\",\n    \"jszip\": \"^3.10.1\",\n    \"mitt\": \"^3.0.0\",\n    \"mixpanel-browser\": \"^2.47.0\",\n    \"moment\": \"^2.29.4\",\n    \"moment-timezone\": \"^0.5.43\",\n    \"next\": \"13.4.2\",\n    \"react\": \"18.2.0\",\n    \"react-datetime\": \"^3.2.0\",\n    \"react-dom\": \"18.2.0\",\n    \"react-draggable\": \"^4.4.5\",\n    \"react-grid-layout\": \"^1.3.4\",\n    \"react-markdown\": \"^8.0.7\",\n    \"react-spinners\": \"^0.13.8\",\n    \"react-tippy\": \"^1.4.0\",\n    \"react-toastify\": \"^9.1.3\"\n  }\n}\n"
  },
  {
    "path": "gui/pages/Content/APM/Apm.module.css",
    "content": ".apm_dashboard_container {\n    display: flex;\n    flex-direction: column;\n}\n\n.apm_dashboard {\n    margin-top: 16px;\n    height: calc(100vh - 16vh);\n    overflow-y: auto;\n}"
  },
  {
    "path": "gui/pages/Content/APM/ApmDashboard.js",
    "content": "import React, {useState, useEffect, useCallback, useRef} from 'react';\nimport Image from \"next/image\";\nimport style from \"./Apm.module.css\";\nimport 'react-toastify/dist/ReactToastify.css';\nimport {getActiveRuns, getAgentRuns, getAllAgents, getToolsUsage, getMetrics} from \"@/pages/api/DashboardService\";\nimport {formatNumber, formatTime, returnToolkitIcon} from \"@/utils/utils\";\nimport {BarGraph} from \"./BarGraph.js\";\nimport {WidthProvider, Responsive} from 'react-grid-layout';\nimport 'react-grid-layout/css/styles.css';\nimport 'react-resizable/css/styles.css';\nimport { Tooltip } from 'react-tippy';\n\nconst ResponsiveGridLayout = WidthProvider(Responsive);\n\nexport default function ApmDashboard() {\n  const [agentDetails, setAgentDetails] = useState([]);\n  const [tokenDetails, setTokenDetails] = useState([]);\n  const [runDetails, setRunDetails] = useState(0);\n  const [allAgents, setAllAgents] = useState([]);\n  const [dropdown1, setDropDown1] = useState(false);\n  const [dropdown2, setDropDown2] = useState(false);\n  const [dropdown3, setDropDown3] = useState(false);\n  const [selectedAgent, setSelectedAgent] = useState('Select an Agent');\n  const [selectedAgentIndex, setSelectedAgentIndex] = useState(-1);\n  const [selectedAgentRun, setSelectedAgentRun] = useState([]);\n  const [activeRuns, setActiveRuns] = useState([]);\n  const [selectedAgentDetails, setSelectedAgentDetails] = useState(null);\n  const [toolsUsed, setToolsUsed] = useState([]);\n  const [showToolTip, setShowToolTip] = useState(false);\n  const [toolTipIndex, setToolTipIndex] = useState(-1);\n  const initialLayout = [\n    {i: 'total_agents', x: 0, y: 0, w: 3, h: 1.5},\n    {i: 'total_tokens', x: 3, y: 0, w: 3, h: 1.5},\n    {i: 'total_runs', x: 6, y: 0, w: 3, h: 1.5},\n    {i: 'active_runs', x: 9, y: 0, w: 3, h: 2},\n    {i: 'most_used_tools', x: 9, y: 1, w: 3, h: 2},\n    {i: 'models_by_agents', x: 0, y: 1, w: 3, h: 2.5},\n    {i: 'runs_by_model', x: 3, y: 1, w: 3, h: 2.5},\n    {i: 'tokens_by_model', x: 6, y: 1, w: 3, h: 2.5},\n    {i: 'agent_details', x: 0, y: 2, w: 12, h: 2.5},\n    {i: 'total_tokens_consumed', x: 0, y: 3, w: 4, h: 2},\n    {i: 'total_calls_made', x: 4, y: 3, w: 4, h: 2},\n    {i: 'tokens_consumed_per_call', x: 8, y: 3, w: 4, h: 2},\n  ];\n  const storedLayout = localStorage.getItem('myLayoutKey');\n  const [layout, setLayout] = useState(storedLayout !== null ? JSON.parse(storedLayout) : initialLayout);\n  const firstUpdate = useRef(true);\n\n  const onLayoutChange = (currentLayout) => {\n    setLayout(currentLayout);\n  };\n\n  const onClickLayoutChange = () => {\n    localStorage.setItem('myLayoutKey', JSON.stringify(initialLayout));\n    setLayout(initialLayout);\n  }\n\n  useEffect(() => {\n    if (!firstUpdate.current) {\n      localStorage.setItem('myLayoutKey', JSON.stringify(layout));\n    } else {\n      firstUpdate.current = false;\n    }\n  }, [layout]);\n\n  const assignDefaultDataPerModel = (data, modelList) => {\n    const modelsInData = data.map(item => item.name);\n    modelList.forEach((model) => {\n      if (!modelsInData.includes(model)) {\n        data.push({name: model, value: 0});\n      }\n    });\n  };\n\n  useEffect(() => {\n    const fetchData = async () => {\n      try {\n        const [metricsResponse, agentsResponse, activeRunsResponse, toolsUsageResponse] = await Promise.all([getMetrics(), getAllAgents(), getActiveRuns(), getToolsUsage()]);\n        const models = ['gpt-4', 'gpt-3.5-turbo', 'gpt-3.5-turbo-16k', 'gpt-4-32k', 'google-palm-bison-001', 'replicate-llama13b-v2-chat'];\n\n        assignDefaultDataPerModel(metricsResponse.data.agent_details.model_metrics, models);\n        assignDefaultDataPerModel(metricsResponse.data.tokens_details.model_metrics, models);\n        assignDefaultDataPerModel(metricsResponse.data.run_details.model_metrics, models);\n\n        setAgentDetails(metricsResponse.data.agent_details);\n        setTokenDetails(metricsResponse.data.tokens_details);\n        setRunDetails(metricsResponse.data.run_details);\n        setAllAgents(agentsResponse.data.agent_details);\n        setActiveRuns(activeRunsResponse.data);\n        setToolsUsed(toolsUsageResponse.data);\n      } catch (error) {\n        console.log(`Error in fetching data: ${error}`);\n      }\n    }\n\n    fetchData();\n    const interval = setInterval(fetchData, 10000);\n    return () => clearInterval(interval);\n  }, []);\n\n  useEffect(() => {\n    console.log(toolsUsed)\n  }, [toolsUsed]);\n\n  const handleSelectedAgent = useCallback((index, name) => {\n    setDropDown1(false)\n    setDropDown2(false)\n    setDropDown3(false)\n    setSelectedAgent(name)\n    setSelectedAgentIndex(index)\n    const agentDetails = allAgents.find(agent => agent.agent_id === index);\n    setSelectedAgentDetails(agentDetails);\n\n    getAgentRuns(index).then((response) => {\n      const data = response.data;\n      setSelectedAgentRun(data);\n    }).catch((error) => console.error(`Error in fetching agent runs: ${error}`));\n  }, [allAgents]);\n\n  useEffect(() => handleSelectedAgent(selectedAgentIndex, selectedAgent), [allAgents]);\n\n  useEffect(() => {\n    if (allAgents.length > 0 && selectedAgent === 'Select an Agent') {\n      const lastAgent = allAgents[allAgents.length - 1];\n      handleSelectedAgent(lastAgent.agent_id, lastAgent.name);\n    }\n  }, [allAgents, selectedAgent, handleSelectedAgent]);\n\n  const setToolTipState = (state, index) => {\n    setShowToolTip(state)\n    setToolTipIndex(index)\n  }\n\n  return (\n    <div className={style.apm_dashboard_container}>\n      <div id=\"apm_dashboard\" className={style.apm_dashboard}>\n        <div className=\"horizontal_space_between w_100 align_center padding_0_8\">\n          <span className=\"text_14 mt_6 ml_6\">Agent Performance Monitoring</span>\n          {/*<button onClick={onClickLayoutChange} className=\"primary_button\">Reset</button>*/}\n        </div>\n        <ResponsiveGridLayout\n          className=\"layout\"\n          layouts={{lg: layout}}\n          onLayoutChange={onLayoutChange}\n          breakpoints={{lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0}}\n          cols={{lg: 12, md: 12, sm: 12, xs: 12, xxs: 12}}>\n          <div key=\"total_agents\" className=\"display_column_container\">\n            <span className=\"text_14 mb_8\">Total Agents</span>\n            <div\n              className=\"text_60_bold display_flex justify_center align_center w_100 h_100 mb_24 mt_24\">{formatNumber(agentDetails.total_agents)}</div>\n          </div>\n          <div key=\"total_tokens\" className=\"display_column_container\">\n            <span className=\"text_14 mb_8\">Total tokens consumed</span>\n            <div\n              className=\"text_60_bold display_flex justify_center align_center w_100 h_100 mb_24 mt_24\">{formatNumber(tokenDetails.total_tokens)}</div>\n          </div>\n          <div key=\"total_runs\" className=\"display_column_container\">\n            <span className=\"text_14 mb_8\">Total runs</span>\n            <div\n              className=\"text_60_bold display_flex justify_center align_center w_100 h_100 mb_24 mt_24\">{formatNumber(runDetails.total_runs)}</div>\n          </div>\n\n          <div key=\"models_by_agents\" className=\"display_column_container\">\n            <span className=\"text_14 mb_8\">Number of Agents per model</span>\n            {agentDetails.model_metrics && agentDetails.model_metrics.length > 0\n              ? <><BarGraph data={agentDetails.model_metrics} type=\"value\" color=\"#3C7EFF\"/>\n                <div className=\"horizontal_container mt_10\">\n                  <span className=\"bar_label_dot\" style={{backgroundColor: '#3C7EFF'}}></span>\n                  <span className=\"bar_label_text\">Models</span>\n                </div>\n              </>\n              : <div className=\"vertical_container align_center mt_80 w_100\">\n                <img src=\"/images/no_permissions.svg\" width={190} height={74} alt=\"No Data\"/>\n                <span className=\"text_12 color_white mt_6\">No Agents Found</span>\n              </div>}\n          </div>\n\n          <div key=\"runs_by_model\" className=\"display_column_container\">\n            <span className=\"text_14 mb_8\">Number of Runs per Model</span>\n            {runDetails.model_metrics && runDetails.model_metrics.length > 0\n              ? <><BarGraph data={runDetails.model_metrics} type=\"value\" color=\"#3C7EFF\"/>\n                <div className=\"horizontal_container mt_10\">\n                  <span className=\"bar_label_dot\" style={{backgroundColor: '#3C7EFF'}}></span>\n                  <span className=\"bar_label_text\">Models</span>\n                </div>\n              </>\n              : <div className=\"vertical_container align_center mt_80 w_100\">\n                <img src=\"/images/no_permissions.svg\" width={190} height={74} alt=\"No Data\"/>\n                <span className=\"text_12 color_white mt_6\">No Agents Found</span>\n              </div>}\n          </div>\n\n          <div key=\"tokens_by_model\" className=\"display_column_container\">\n            <span className=\"text_14 mb_8\">Total Tokens consumed by models</span>\n            {tokenDetails.model_metrics && tokenDetails.model_metrics.length > 0\n              ? <><BarGraph data={tokenDetails.model_metrics} type=\"value\" color=\"#3C7EFF\"/>\n                <div className=\"horizontal_container mt_10\">\n                  <span className=\"bar_label_dot\" style={{backgroundColor: '#3C7EFF'}}></span>\n                  <span className=\"bar_label_text\">Models</span>\n                </div>\n              </>\n              : <div className=\"vertical_container align_center mt_80 w_100\">\n                <img src=\"/images/no_permissions.svg\" width={190} height={74} alt=\"No Data\"/>\n                <span className=\"text_12 color_white mt_6\">No Agents Found</span>\n              </div>}\n          </div>\n\n          <div key=\"most_used_tools\" className=\"display_column_container\">\n            <span className=\"text_14 mb_8\">Most used tools</span>\n            {toolsUsed.length === 0 ?\n              <div className=\"vertical_container align_center mt_70 w_100\">\n                <img src=\"/images/no_permissions.svg\" width={190} height={74} alt=\"No Data\"/>\n                <span className=\"text_12 color_white mt_6\">No Used Tools Found</span>\n              </div> : <div className=\"scrollable_container\">\n                <table className=\"table_css margin_0 padding_0\">\n                  <thead>\n                  <tr style={{borderTop: 'none'}}>\n                    <th className=\"table_header w_56\">Tool</th>\n                    <th className=\"table_header text_align_right w_22\">Agents</th>\n                    <th className=\"table_header text_align_right w_22\">Calls</th>\n                  </tr>\n                  </thead>\n                </table>\n\n                <div className=\"overflow_auto w_100\">\n                  <table className=\"table_css margin_0\">\n                    <tbody>\n                    {toolsUsed.map((tool, index) => (\n                      <tr key={index}>\n                        <td className=\"table_data\" style={{width: '100%', display: 'flex', alignItems: 'center'}}>\n                          <Image className=\"image_class bg_black\" width={20} height={20}\n                                 src={returnToolkitIcon(tool.toolkit)} alt=\"tool-icon\"/>\n                          <span>{tool.tool_name}</span>\n                        </td>\n                        <td className=\"table_data text_align_right w_22 br_left_grey\">{tool.unique_agents}</td>\n                        <td className=\"table_data text_align_right w_22 br_left_grey\">{tool.total_usage}</td>\n                      </tr>\n                    ))}\n                    </tbody>\n                  </table>\n                </div>\n              </div>}\n          </div>\n\n          <div key=\"agent_details\" className=\"display_column_container\">\n            <span className=\"text_14 mb_8\">Agent Overview</span>\n            {allAgents.length === 0 ?\n              <div className=\"vertical_container align_center mt_50 w_100\">\n                <img src=\"/images/no_permissions.svg\" width={300} height={120} alt=\"No Data\"/>\n                <span\n                  className=\"text_12 color_white mt_6\">{selectedAgent === 'Select an Agent' ? 'Please Select an Agent' :\n                  <React.Fragment>No Runs found for <b>{selectedAgent}</b></React.Fragment>}</span>\n              </div> : <div className=\"scrollable_container mt_16\">\n                <table className=\"table_css margin_0 padding_0\">\n                  <thead>\n                  <tr style={{borderTop: 'none'}}>\n                    <th className=\"table_header w_20\">Agent Name</th>\n                    <th className=\"table_header text_align_right w_10\">Model</th>\n                    <th className=\"table_header text_align_right w_12\">Tokens Consumed</th>\n                    <th className=\"table_header text_align_right w_6\">Runs</th>\n                    <th className=\"table_header text_align_right w_12\">Avg tokens per run</th>\n                    <th className=\"table_header text_align_right w_20\">Tools</th>\n                    <th className=\"table_header text_align_right w_10\">Calls</th>\n                    <th className=\"table_header text_align_right w_10\">Avg Run Time</th>\n                  </tr>\n                  </thead>\n                </table>\n\n                <div className=\"overflow_auto w_100\">\n                  <table className=\"table_css margin_0\">\n                    <tbody>\n                    {allAgents.map((run, i) => (\n                      <tr key={i}>\n                        <td className=\"table_data w_20\">{run.name}</td>\n                        <td className=\"table_data text_align_right w_10 br_left_grey\">{run.model_name}</td>\n                        <td className=\"table_data text_align_right w_12 br_left_grey\">{formatNumber(run.total_tokens)}</td>\n                        <td className=\"table_data text_align_right w_6 br_left_grey\">{run.runs_completed}</td>\n                        <td className=\"table_data text_align_right w_12 br_left_grey\">\n                          {run.runs_completed ? formatNumber((run.total_tokens / run.runs_completed).toFixed(1)) : '-'}\n                        </td>\n                        <td className=\"table_data text_align_right br_left_grey\" style={{width: '20%'}}>\n                          {run.tools_used && run.tools_used.slice(0, 3).map((tool, index) => (\n                              <div key={index} className=\"tools_used\">{tool}</div>\n                          ))}\n                          {run.tools_used && run.tools_used.length > 3 &&\n                              <div style={{display:'inline-flex'}}>\n                                <Tooltip\n                                    position=\"top-start\"\n                                    trigger=\"mouseenter\"\n                                    arrow={true}\n                                    html={\n                                      <>\n                                        <div className=\"bg_primary br_8 padding_5\">\n                                        {run.tools_used.slice(3).map((tool,index) =>\n                                            <div className=\"tools_used\" key={index}>{tool}</div>\n                                        )}\n                                        </div>\n                                      </>\n                                    }\n                                >\n                                  <div className=\"tools_used cursor_pointer\">\n                                    +{run.tools_used.length - 3}\n                                  </div>\n                                </Tooltip>\n                              </div>\n                          }\n                        </td>\n                        <td className=\"table_data text_align_right w_10 br_left_grey\">{run.total_calls}</td>\n                        <td className=\"table_data text_align_right w_10 br_left_grey\">\n                          {run.avg_run_time === 0 ? '-' : `${parseFloat((run.avg_run_time / 60).toFixed(1))} mins`}\n                        </td>\n                      </tr>))}\n                    </tbody>\n                  </table>\n                </div>\n              </div>}\n          </div>\n          <div key=\"active_runs\" className=\"display_column_container\">\n            <span className=\"text_14 mb_8\">Active Runs</span>\n            <div className=\"scrollable_container gap_8\">\n              {activeRuns.length === 0 ?\n                <div className=\"vertical_container align_center mt_24\">\n                  <img src=\"/images/no_permissions.svg\" width={190} height={74} alt=\"No Data\"/>\n                  <span className=\"text_12 color_white mt_6\">No active runs found</span>\n                </div> : activeRuns.map((run, index) => (\n                  <div key={index} className=\"active_runs\">\n                    <span className=\"text_14\">{run.name}</span>\n                    <div style={{display: 'inline-flex', alignItems: 'center'}}>\n                      <span className=\"text_12 mt_6\">{run.agent_name} ·  <Image width={12} height={12} src=\"/images/schedule.svg\" alt=\"schedule-icon\"/>\n                        {formatTime(run.created_at)}</span>\n                    </div>\n                  </div>\n                ))}\n            </div>\n          </div>\n          <div key=\"total_tokens_consumed\" className=\"display_column_container\">\n            <div className=\"horizontal_space_between w_100\">\n              <span className=\"text_14 mb_8\">Tokens Consumed by Runs</span>\n              <div style={{position: 'relative', display: 'flex', flexDirection: 'column'}}>\n                {allAgents.length > 0 && <div>\n                  <div className=\"text_14 mb_8 cursor_pointer\" onClick={() => setDropDown2(!dropdown2)}>{selectedAgent}<img width={18} height={16}\n                                                                                    src=\"/images/expand_more.svg\"/></div>\n                  {dropdown2 &&\n                    <div className=\"custom_select_options padding_8 position_absolute r_0\">\n                      {allAgents.map((agent, index) => (\n                        <div key={index} className=\"custom_select_option padding_8\" onClick={() => handleSelectedAgent(agent.agent_id, agent.name)}>{agent.name}</div>))}\n                    </div>}\n                </div>}\n              </div>\n            </div>\n            {selectedAgentRun.length > 0\n              ? <><BarGraph data={selectedAgentRun} type=\"tokens_consumed\" color=\"#3DFF7F\"/>\n                <div className=\"horizontal_container mt_10\">\n                  <span className=\"bar_label_dot\" style={{backgroundColor: '#3DFF7F'}}></span>\n                  <span className=\"bar_label_text\">Runs</span>\n                </div>\n              </>\n              : <div className=\"vertical_container align_center mt_80 w_100\">\n                <img src=\"/images/no_permissions.svg\" width={190} height={74} alt=\"No Data\"/>\n                <span className=\"text_12 color_white mt_6\">No Runs Found</span>\n              </div>}\n          </div>\n\n          <div key=\"total_calls_made\" className=\"display_column_container\">\n            <div className=\"horizontal_space_between w_100\">\n              <span className=\"text_14 mb_8\">Calls Made by Runs</span>\n              <div className=\"vertical_containers position_relative\">\n                {allAgents.length > 0 && <div>\n                  <div className=\"text_14 mb_8 cursor_pointer\"\n                       onClick={() => setDropDown1(!dropdown1)}>{selectedAgent}<img width={18} height={16} src=\"/images/expand_more.svg\"/>\n                  </div>\n                  {dropdown1 &&\n                    <div className=\"custom_select_options padding_8 position_absolute r_0\">\n                      {allAgents.map((agent, index) => (\n                        <div key={index} className=\"custom_select_option padding_8\" onClick={() => handleSelectedAgent(agent.agent_id, agent.name)}>{agent.name}</div>))}\n                    </div>}\n                </div>}\n              </div>\n            </div>\n            {selectedAgentRun.length > 0\n              ? <><BarGraph data={selectedAgentRun} type=\"calls\" color=\"#3DFF7F\"/>\n                <div className=\"horizontal_container mt_10\">\n                  <span className=\"bar_label_dot\" style={{backgroundColor: '#3DFF7F'}}></span>\n                  <span className=\"bar_label_text\">Runs</span>\n                </div>\n              </>\n              : <div className=\"vertical_container align_center mt_80 w_100\">\n                <img src=\"/images/no_permissions.svg\" width={190} height={74} alt=\"No Data\"/>\n                <span className=\"text_12 color_white mt_6\">No Runs Found</span>\n              </div>}\n          </div>\n          <div key=\"tokens_consumed_per_call\" className=\"display_column_container\">\n            <div className=\"horizontal_space_between w_100\">\n              <span className=\"text_14 mb_8\">Average Tokens consumed in all calls per run </span>\n              <div className=\"vertical_containers position_relative\">\n                {allAgents.length > 0 && <div>\n                  <div className=\"text_14 mb_8 cursor_pointer\"\n                       onClick={() => setDropDown3(!dropdown3)}>{selectedAgent}<img width={18} height={16} src=\"/images/expand_more.svg\"/>\n                  </div>\n                  {dropdown3 &&\n                    <div className=\"custom_select_options padding_8 position_absolute r_0\">\n                      {allAgents.map((agent, index) => (\n                        <div key={index} className=\"custom_select_option padding_8\"\n                             onClick={() => handleSelectedAgent(agent.agent_id, agent.name)}>{agent.name}</div>))}\n                    </div>}\n                </div>}\n              </div>\n            </div>\n            {selectedAgentRun.length > 0\n              ? <><BarGraph data={selectedAgentRun} type=\"tokens_per_call\" color=\"#3DFF7F\"/>\n                <div className=\"horizontal_container mt_10\">\n                  <span className=\"bar_label_dot\" style={{backgroundColor: '#3DFF7F'}}></span>\n                  <span className=\"bar_label_text\">Runs</span>\n                </div>\n              </>\n              : <div className=\"vertical_container align_center mt_80 w_100\">\n                <img src=\"/images/no_permissions.svg\" width={190} height={74} alt=\"No Data\"/>\n                <span className=\"text_12 color_white mt_6\">No Runs Found</span>\n              </div>}\n          </div>\n        </ResponsiveGridLayout>\n      </div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "gui/pages/Content/APM/BarGraph.js",
    "content": "import React, {useEffect, useRef} from \"react\";\nimport * as echarts from 'echarts';\n\nexport const BarGraph = ({data, type, color}) => {\n  const chartRef = useRef(null);\n  const containerRef = useRef(null);\n\n  useEffect(() => {\n    const chartInstance = echarts.getInstanceByDom(chartRef.current);\n    const chart = chartInstance ? chartInstance : echarts.init(chartRef.current);\n\n    const option = {\n      color: color,\n      tooltip: {\n        trigger: 'axis',\n        axisPointer: {\n          type: 'shadow'\n        }\n      },\n      xAxis: {\n        type: 'category',\n        data: data.map(item => item.name),\n        axisLabel: {\n          interval: 0,\n          rotate: 45,\n          color: '#888'\n        }\n      },\n      yAxis: {\n        type: 'value',\n        axisLabel: {\n          formatter: function (value) {\n            if (value >= 1000) {\n              return `${value / 1000}k`;\n            } else {\n              return value;\n            }\n          }\n        },\n        splitLine: {\n          lineStyle: {\n            color: 'rgba(255, 255, 255, 0.08)'\n          }\n        }\n      },\n      series: [{\n        data: data.map(item => type === 'tokens_per_call' ? (item.tokens_consumed / item.calls) : item[type]),\n        type: 'bar'\n      }],\n      responsive: true\n    };\n\n    chart.setOption(option);\n\n    const resizeObserver = new ResizeObserver(entries => {\n      entries.forEach(entry => {\n        chart.resize();\n      });\n    });\n\n    resizeObserver.observe(containerRef.current);\n\n    return () => resizeObserver.disconnect();\n  }, [data, type]);\n\n  return (\n    <div ref={containerRef} style={{width: '100%', height: '100%'}}>\n      <div ref={chartRef} style={{width: '100%', height: '100%'}}></div>\n    </div>\n  );\n}\n\nexport default BarGraph;"
  },
  {
    "path": "gui/pages/Content/Agents/ActionConsole.js",
    "content": "import React, {useState, useEffect} from 'react';\nimport styles from './Agents.module.css';\nimport Image from 'next/image';\nimport {updatePermissions} from '@/pages/api/DashboardService';\nimport {formatTimeDifference} from '@/utils/utils';\n\nfunction ActionBox({action, index, denied, reasons, handleDeny, handleSelection, setReasons}) {\n  const isDenied = denied[index];\n\n  return (\n    <div key={action.id} className={styles.history_box}\n         style={{background: '#272335', padding: '16px', cursor: 'default'}}>\n      <div style={{display: 'flex', flexDirection: 'column'}}>\n        {action.question && (<div className={styles.feed_title}>{action.question}</div>)}\n        {!action.question && (<div>Tool <b>{action.tool_name}</b> is seeking for Permissions</div>)}\n\n        {isDenied && (\n          <div style={{marginTop: '26px'}}>\n            <div>Provide Feedback <span style={{color: '#888888'}}>(Optional)</span></div>\n            <input style={{marginTop: '6px'}} type=\"text\" value={reasons[index]} placeholder=\"Enter your input here\"\n                   className=\"input_medium\"\n                   onChange={(e) => {\n                     const newReasons = [...reasons];\n                     newReasons[index] = e.target.value;\n                     setReasons(newReasons);\n                   }}/>\n          </div>\n        )}\n        {isDenied ? (\n          <div style={{display: 'inline-flex', gap: '8px'}}>\n            <button onClick={() => handleDeny(index)} className=\"secondary_button mt_16\" style={{paddingLeft: '10px'}}>\n              <Image width={12} height={12} src=\"/images/undo.svg\" alt=\"check-icon\"/>\n              <span className={styles.text_12_n}>Go Back</span>\n            </button>\n            <button onClick={() => handleSelection(index, false, action.id)} className=\"secondary_button mt_16\"\n                    style={{background: 'transparent', border: 'none'}}>\n              <span className={styles.text_12_n}>Proceed to Deny</span>\n            </button>\n          </div>\n        ) : (\n          <div style={{display: 'inline-flex', gap: '8px'}}>\n            <button onClick={() => handleSelection(index, true, action.id)} className=\"secondary_button mt_16\"\n                    style={{paddingLeft: '10px'}}>\n              <Image width={12} height={12} src=\"/images/check.svg\" alt=\"check-icon\"/>\n              <span className={styles.text_12_n}>Approve</span>\n            </button>\n            <button onClick={() => handleDeny(index)} className=\"secondary_button mt_16\"\n                    style={{background: 'transparent', border: 'none'}}>\n              <Image width={16} height={16} src=\"/images/close.svg\" alt=\"close-icon\"/>\n              <span className={styles.text_12_n}>Deny</span>\n            </button>\n          </div>\n        )}\n      </div>\n      <div style={{display: 'flex', alignItems: 'center', paddingLeft: '0', paddingBottom: '0'}}\n           className={styles.tab_text}>\n        <div>\n          <Image width={12} height={12} src=\"/images/schedule.svg\" alt=\"schedule-icon\"/>\n        </div>\n        <div className={styles.history_info}>{formatTimeDifference(action.time_difference)}</div>\n      </div>\n    </div>\n  );\n}\n\nfunction HistoryBox({action}) {\n  return (\n    <div key={action.id} className={styles.history_box}\n         style={{background: '#272335', padding: '16px', cursor: 'default'}}>\n      <div style={{display: 'flex', flexDirection: 'column'}}>\n        <div>Permissions for <b>{action.tool_name}</b> was::</div>\n        {action.status && action.status === 'APPROVED' ? (\n          <button className=\"history_permission mt_16\">\n            <Image width={12} height={12} src=\"/images/check.svg\" alt=\"check-icon\"/>\n            <span className={styles.text_12_n}>Approved</span>\n          </button>\n        ) : (\n          <button className=\"history_permission mt_16\">\n            <Image width={14} height={14} src=\"/images/close.svg\" alt=\"close-icon\"/>\n            <span className={styles.text_12_n}>Denied</span>\n          </button>\n        )}\n        {action.user_feedback != null &&\n          <div style={{display: 'flex', flexDirection: 'column'}}>\n            <div className=\"mt_16\" style={{color: '#888888'}}>FeedBack</div>\n            <div className=\"mt_6 mb_8\">{action.user_feedback}</div>\n          </div>\n        }\n        <div style={{display: 'flex', alignItems: 'center', paddingLeft: '0', paddingBottom: '0'}}\n             className={styles.tab_text}>\n          <div>\n            <Image width={12} height={12} src=\"/images/schedule.svg\" alt=\"schedule-icon\"/>\n          </div>\n          <div className={styles.history_info}>{formatTimeDifference(action.time_difference)}</div>\n        </div>\n      </div>\n    </div>\n  )\n}\n\nexport default function ActionConsole({actions, pendingPermission, setPendingPermissions}) {\n  const [hiddenActions, setHiddenActions] = useState([]);\n  const [denied, setDenied] = useState([]);\n  const [reasons, setReasons] = useState([]);\n  const [localActionIds, setLocalActionIds] = useState([]);\n\n  useEffect(() => {\n    const updatedActions = actions?.filter((action) => !localActionIds.includes(action.id));\n\n    if (updatedActions && updatedActions.length > 0) {\n      setLocalActionIds((prevIds) => [...prevIds, ...updatedActions.map(({id}) => id)]);\n\n      setDenied((prevDenied) => prevDenied.map((value, index) => updatedActions[index] ? false : value));\n      setReasons((prevReasons) => prevReasons.map((value, index) => updatedActions[index] ? '' : value));\n    }\n  }, [actions]);\n\n  const handleDeny = (index) => {\n    setDenied((prevDenied) => {\n      const newDeniedState = [...prevDenied];\n      newDeniedState[index] = !newDeniedState[index];\n      return newDeniedState;\n    });\n  };\n\n  const handleSelection = (index, status, permissionId) => {\n    setHiddenActions((prevHiddenActions) => [...prevHiddenActions, index]);\n\n    const data = {\n      status: status,\n      user_feedback: reasons[index],\n    };\n\n    updatePermissions(permissionId, data).then((response) => {\n      if (response.status === 200)\n        setPendingPermissions(pendingPermission - 1)\n    });\n  };\n\n  return (\n    <>\n      {actions && actions.length > 0 ? (\n        <div className={styles.detail_body} style={{height: 'auto'}}>\n          {actions.map((action, index) => {\n            if (action.status === 'PENDING' && !hiddenActions.includes(index)) {\n              return (<ActionBox key={action.id} action={action} index={index} denied={denied} setReasons={setReasons}\n                                 reasons={reasons} handleDeny={handleDeny} handleSelection={handleSelection}/>);\n            } else if (action.status === 'APPROVED' || action.status === 'REJECTED') {\n              return (<HistoryBox key={action.id} action={action}/>);\n            }\n            return null;\n          })}\n        </div>\n      ) : (\n        <div style={{display: 'flex', flexDirection: 'column', alignItems: 'center', marginTop: '40px'}}>\n          <Image width={150} height={60} src=\"/images/no_permissions.svg\" alt=\"no-permissions\"/>\n          <span className={styles.feed_title} style={{marginTop: '8px'}}>No Actions to Display!</span>\n        </div>\n      )}\n    </>\n  );\n}"
  },
  {
    "path": "gui/pages/Content/Agents/ActivityFeed.js",
    "content": "import React, {useEffect, useRef, useState} from 'react';\nimport styles from './Agents.module.css';\nimport {getExecutionFeeds, getDateTime} from \"@/pages/api/DashboardService\";\nimport Image from \"next/image\";\nimport {loadingTextEffect, formatTimeDifference, convertWaitingPeriod, updateDateBasedOnValue} from \"@/utils/utils\";\nimport {EventBus} from \"@/utils/eventBus\";\nimport {ClipLoader} from 'react-spinners';\n\nexport default function ActivityFeed({selectedRunId, selectedView, setFetchedData, agent, selectedRunStatus}) {\n  const [loadingText, setLoadingText] = useState(\"Thinking\");\n  const [feeds, setFeeds] = useState([]);\n  const feedContainerRef = useRef(null);\n  const [runStatus, setRunStatus] = useState(\"CREATED\");\n  const [prevFeedsLength, setPrevFeedsLength] = useState(0);\n  const [scheduleDate, setScheduleDate] = useState(null);\n  const [scheduleTime, setScheduleTime] = useState(null);\n  const [isLoading, setIsLoading] = useState(true);\n  const [waitingPeriod, setWaitingPeriod] = useState(null);\n  const [errorMsg, setErrorMsg] = useState('');\n\n  useEffect(() => {\n    const interval = window.setInterval(function () {\n      if (selectedRunStatus !== \"ERROR_PAUSED\") {\n        fetchFeeds();\n      }\n    }, 5000);\n\n    return () => clearInterval(interval);\n  }, [selectedRunId, selectedRunStatus]);\n\n  function fetchDateTime() {\n    getDateTime(agent.id)\n      .then((response) => {\n        const {start_date, start_time} = response.data;\n        setScheduleDate(start_date);\n        setScheduleTime(start_time);\n      })\n      .catch((error) => {\n        console.error('Error fetching agent data:', error);\n      });\n  }\n\n  useEffect(() => {\n    loadingTextEffect('Thinking', setLoadingText, 250);\n\n    if (agent?.is_scheduled && !agent?.is_running) {\n      fetchDateTime();\n    }\n  }, []);\n\n  useEffect(() => {\n    if (feeds.length !== prevFeedsLength) {\n      if (feedContainerRef.current) {\n        setTimeout(() => {\n          if (feedContainerRef.current !== null) {\n            feedContainerRef.current.scrollTo({top: feedContainerRef.current.scrollHeight, behavior: 'smooth'});\n            setPrevFeedsLength(feeds.length);\n          }\n        }, 100);\n      }\n    }\n  }, [feeds]);\n\n  function scrollToTop() {\n    if (feedContainerRef.current) {\n      setTimeout(() => {\n        feedContainerRef.current.scrollTo({top: 0, behavior: 'smooth'});\n      }, 100);\n    }\n  }\n\n  useEffect(() => {\n    fetchFeeds();\n  }, [selectedRunId])\n\n  useEffect(() => {\n    EventBus.emit('reFetchAgents', {});\n  }, [runStatus])\n\n  function fetchFeeds() {\n    if (selectedRunId !== null) {\n      setIsLoading(true);\n      getExecutionFeeds(selectedRunId)\n        .then((response) => {\n          const data = response.data;\n          setFeeds(data.feeds);\n          setErrorMsg(data.errors)\n          setRunStatus(data.status);\n          setFetchedData(data.permissions);\n          setWaitingPeriod(data.waiting_period ? data.waiting_period : null)\n          EventBus.emit('resetRunStatus', {executionId: selectedRunId, status: data.status});\n          setIsLoading(false); //add this line\n        })\n        .catch((error) => {\n          console.error('Error fetching execution feeds:', error);\n          setIsLoading(false); // and this line\n        });\n    }\n  }\n\n  useEffect(() => {\n    const updateRunStatus = (eventData) => {\n      if (eventData.selectedRunId === selectedRunId) {\n        setRunStatus(eventData.status);\n      }\n    };\n    const refreshDate = () => {\n      fetchDateTime();\n    };\n\n    EventBus.on('updateRunStatus', updateRunStatus);\n    EventBus.on('refreshDate', refreshDate);\n\n    return () => {\n      EventBus.off('updateRunStatus', updateRunStatus);\n      EventBus.off('refreshDate', refreshDate);\n    };\n  });\n\n  return (<>\n    <div style={{overflowY: \"auto\", maxHeight: '80vh', position: 'relative'}} ref={feedContainerRef}>\n      <div style={{marginBottom: '55px'}}>\n        {agent?.is_scheduled && !agent?.is_running && !selectedRunId ?\n          <div style={{display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center'}}>\n            <Image width={72} height={72} src=\"/images/eventSchedule.png\" alt=\"github\"/>\n            <div style={{color: 'white', fontSize: '14px'}}>\n              This agent is scheduled to start on {scheduleDate}, at {scheduleTime}\n            </div>\n          </div> : <div>\n            {feeds && feeds.map((f, index) => (<div key={index} className={styles.history_box}\n                                                    style={{background: '#272335', padding: '20px', cursor: 'default'}}>\n              <div style={{display: 'flex'}}>\n                {f.role === 'user' && <div className={styles.feed_icon}>💁</div>}\n                {f.role === 'system' && <div className={styles.feed_icon}>🛠️ </div>}\n                {f.role === 'assistant' && <div className={styles.feed_icon}>💡</div>}\n                <div className={styles.feed_title}>{f?.feed || ''}</div>\n              </div>\n              <div className={styles.more_details_wrapper}>\n                {f.time_difference && <div className={styles.more_details}>\n                  <div style={{display: 'flex', alignItems: 'center'}}>\n                    <div>\n                      <Image width={12} height={12} src=\"/images/schedule.svg\" alt=\"schedule-icon\"/>\n                    </div>\n                    <div className={styles.history_info}>\n                      {formatTimeDifference(f.time_difference)}\n                    </div>\n                  </div>\n                </div>}\n              </div>\n            </div>))}\n            {runStatus === 'WAIT_STEP' &&\n                <div className=\"history_box padding_20 cursor_default bg_secondary\">\n                  <div style={{display: 'flex'}}>\n                    <div className=\"fs_20 lh_24\">⏳</div>\n                    <div className={styles.feed_title}>Waiting Block Initiated. The Agent will wait for {convertWaitingPeriod(waitingPeriod) || null}</div>\n                  </div>\n                </div>}\n            {runStatus === 'RUNNING' &&\n              <div className=\"history_box padding_20 cursor_default bg_secondary\">\n                <div style={{display: 'flex'}}>\n                  <div className=\"fs_20\">🧠</div>\n                  <div className={styles.feed_title}><i>{loadingText}</i></div>\n                </div>\n              </div>}\n            {runStatus === 'COMPLETED' &&\n              <div className=\"history_box padding_20 cursor_default bg_secondary\">\n                <div style={{display: 'flex'}}>\n                  <div className=\"fs_20\">🏁</div>\n                  <div className={styles.feed_title}><i>All goals completed successfully!</i></div>\n                </div>\n              </div>}\n            {runStatus === 'ITERATION_LIMIT_EXCEEDED' &&\n              <div className=\"history_box padding_20 cursor_default bg_secondary\">\n                <div style={{display: 'flex'}}>\n                  <div className=\"fs_20\">⚠️</div>\n                  <div className={styles.feed_title}><i>Stopped: Maximum iterations exceeded!</i></div>\n                </div>\n              </div>}\n              {runStatus === 'ERROR_PAUSED' &&\n              <div className=\"history_box padding_20 cursor_default bg_secondary\">\n                <div style={{display: 'flex'}}>\n                  <div className=\"fs_20\">❗</div>\n                  <div className={styles.feed_title}>{errorMsg}</div>\n                </div>\n              </div>}\n          </div>\n        }\n        {feeds.length < 1 && !agent?.is_running && !agent?.is_scheduled &&\n             <div style={{\n              color: 'white',\n              fontSize: '14px',\n              display: 'flex',\n              flexDirection: 'column',\n              alignItems: 'center',\n              textAlign: 'center',\n              width: '100%'\n            }}>The Agent is not scheduled</div>\n        }\n      </div>\n      {feedContainerRef.current && feedContainerRef.current.scrollTop >= 1200 &&\n        <div className=\"back_to_top\" onClick={scrollToTop}\n             style={selectedView !== '' ? {right: 'calc(39% - 5vw)'} : {right: '39%'}}>\n          <Image width={15} height={15} src=\"/images/backtotop.svg\" alt=\"back-to-top\"/>\n        </div>}\n    </div>\n  </>)\n}"
  },
  {
    "path": "gui/pages/Content/Agents/AgentCreate.js",
    "content": "import React, {useState, useEffect, useRef} from 'react';\nimport Image from \"next/image\";\nimport {ToastContainer, toast} from 'react-toastify';\nimport 'react-toastify/dist/ReactToastify.css';\nimport {\n  createAgent,\n  editAgentTemplate,\n  fetchAgentTemplateConfigLocal,\n  getOrganisationConfig,\n  getLlmModels,\n  updateExecution,\n  uploadFile,\n  getAgentDetails, addAgentRun, fetchModels,\n  getAgentWorkflows, publishTemplateToMarketplace\n} from \"@/pages/api/DashboardService\";\nimport {formatBytes, openNewTab, removeTab, setLocalStorageValue, setLocalStorageArray, returnResourceIcon, getUserTimezone, createInternalId, preventDefault, excludedToolkits, getUserClick} from \"@/utils/utils\";\nimport {EventBus} from \"@/utils/eventBus\";\nimport styles from \"@/pages/Content/Agents/Agents.module.css\";\nimport styles1 from \"@/pages/Content/Knowledge/Knowledge.module.css\";\nimport 'moment-timezone';\nimport AgentSchedule from \"@/pages/Content/Agents/AgentSchedule\";\n\nexport default function AgentCreate({\n                                      sendAgentData,\n                                      knowledge,\n                                      selectedProjectId,\n                                      fetchAgents,\n                                      toolkits,\n                                      organisationId,\n                                      template,\n                                      internalId,\n                                      sendKnowledgeData,\n                                      env,\n                                      edit,\n                                      editAgentId,\n                                      agents\n                                    }) {\n  const [advancedOptions, setAdvancedOptions] = useState(false);\n  const [agentName, setAgentName] = useState(\"\");\n  const [agentTemplateId, setAgentTemplateId] = useState(null);\n  const [agentDescription, setAgentDescription] = useState(\"\");\n  const [longTermMemory, setLongTermMemory] = useState(true);\n  const [addResources, setAddResources] = useState(true);\n  const [input, setInput] = useState([]);\n  const [isDragging, setIsDragging] = useState(false);\n  const [createClickable, setCreateClickable] = useState(true);\n  const fileInputRef = useRef(null);\n  const [maxIterations, setIterations] = useState(25);\n  const [toolkitList, setToolkitList] = useState(toolkits)\n  const [searchValue, setSearchValue] = useState('');\n  const [showButton, setShowButton] = useState(false);\n  const [showPlaceholder, setShowPlaceholder] = useState(true);\n  const [modelsArray, setModelsArray] = useState(['gpt-4', 'gpt-3.5-turbo', 'gpt-3.5-turbo-16k']);\n\n  const constraintsArray = [\n    \"If you are unsure how you previously did something or want to recall past events, thinking about similar events will help you remember.\",\n    \"Ensure the tool and args are as per current plan and reasoning\",\n    'Exclusively use the tools listed under \"TOOLS\"',\n    \"REMEMBER to format your response as JSON, using double quotes (\\\"\\\") around keys and string values, and commas (,) to separate items in arrays and objects. IMPORTANTLY, to use a JSON object as a string in another JSON object, you need to escape the double quotes.\"\n  ];\n  const [constraints, setConstraints] = useState(constraintsArray);\n\n  const [goals, setGoals] = useState(['Describe the agent goals here']);\n  const [instructions, setInstructions] = useState(['']);\n\n  const models = ['gpt-4', 'gpt-3.5-turbo', 'gpt-3.5-turbo-16k']\n  const [model, setModel] = useState(models[1]);\n  const modelRef = useRef(null);\n  const [modelDropdown, setModelDropdown] = useState(false);\n\n  const [agentWorkflows, setAgentWorkflows] = useState('');\n  const [agentWorkflow, setAgentWorkflow] = useState(agentWorkflows[0]);\n\n  const agentRef = useRef(null);\n  const [agentDropdown, setAgentDropdown] = useState(false);\n\n  const exitCriteria = [\"No exit criterion\", \"System defined\", \"User defined\", \"Number of steps/tasks\"]\n  const [exitCriterion, setExitCriterion] = useState(exitCriteria[0]);\n  const exitRef = useRef(null);\n  const [exitDropdown, setExitDropdown] = useState(false);\n\n  const [stepTime, setStepTime] = useState(500);\n\n  const rollingRef = useRef(null);\n  const [rollingDropdown, setRollingDropdown] = useState(false);\n\n  const [selectedKnowledge, setSelectedKnowledge] = useState('');\n  const [selectedKnowledgeId, setSelectedKnowledgeId] = useState(null);\n  const knowledgeRef = useRef(null);\n  const [knowledgeDropdown, setKnowledgeDropdown] = useState(false);\n\n  const databases = [\"Pinecone\"]\n  const [database, setDatabase] = useState(databases[0]);\n  const databaseRef = useRef(null);\n  const [databaseDropdown, setDatabaseDropdown] = useState(false);\n\n  const permissions = [\"God Mode\", \"RESTRICTED (Will ask for permission before using any tool)\"]\n  const [permission, setPermission] = useState(permissions[0]);\n  const permissionRef = useRef(null);\n  const [permissionDropdown, setPermissionDropdown] = useState(false);\n\n  const [selectedTools, setSelectedTools] = useState([]);\n  const [toolNames, setToolNames] = useState(['SearxSearch', 'Read File', 'Write File']);\n  const toolkitRef = useRef(null);\n  const [toolkitDropdown, setToolkitDropdown] = useState(false);\n\n  const [hasAPIkey, setHasAPIkey] = useState(false);\n\n  const [createDropdown, setCreateDropdown] = useState(false);\n  const [createModal, setCreateModal] = useState(false);\n\n  const [scheduleData, setScheduleData] = useState(null);\n  const [editModal, setEditModal] = useState(false)\n  const [editButtonClicked, setEditButtonClicked] = useState(false);\n\n  const [dropdown, setDropdown] = useState(false);\n  const [publishModal, setPublishModal] = useState(false);\n\n\n  useEffect(() => {\n    getOrganisationConfig(organisationId, \"model_api_key\")\n      .then((response) => {\n        console.log(response.data['api_key'])\n        const apiKey = response.data['api_key']\n        setHasAPIkey(!(apiKey === null));\n      })\n      .catch((error) => {\n        console.error('Error fetching project:', error);\n      });\n  }, [organisationId]);\n\n  const filterToolsByNames = () => {\n    if (toolkitList) {\n      const selectedToolIds = toolkits\n        .flatMap(toolkit => toolkit.tools)\n        .filter(tool => toolNames.includes(tool.name))\n        .map(tool => tool.id);\n\n      setLocalStorageArray(\"tool_ids_\" + String(internalId), selectedToolIds, setSelectedTools);\n    }\n  };\n\n  const handleIterationChange = (event) => {\n    setLocalStorageValue(\"agent_iterations_\" + String(internalId), parseInt(event.target.value), setIterations);\n  };\n\n  useEffect(() => {\n    filterToolsByNames();\n  }, [toolNames]);\n\n  useEffect(() => {\n    fetchModels()\n      .then((response) => {\n        const models = response.data.map(model => model.name) || [];\n        const selected_model = localStorage.getItem(\"agent_model_\" + String(internalId)) || '';\n        setModelsArray(models);\n        if (models.length > 0 && !selected_model) {\n          setLocalStorageValue(\"agent_model_\" + String(internalId), models[0], setModel);\n        } else {\n          setModel(selected_model);\n        }\n        console.log(response)\n      })\n      .catch((error) => {\n        console.error('Error fetching models:', error);\n      });\n\n    getAgentWorkflows()\n      .then((response) => {\n        const agentWorkflows = response.data || [];\n        const selectedAgentWorkflow = localStorage.getItem(\"agent_workflow_\" + String(internalId)) || '';\n        setAgentWorkflows(agentWorkflows);\n        if (agentWorkflows.length > 0 && !selectedAgentWorkflow) {\n          setLocalStorageValue(\"agent_workflow_\" + String(internalId), agentWorkflows[0], setAgentWorkflow);\n        } else {\n          setAgentWorkflow(selectedAgentWorkflow);\n        }\n      })\n      .catch((error) => {\n        console.error('Error fetching agent workflows:', error);\n      });\n    if (edit) {\n      editingAgent();\n    }\n\n    if (template !== null) {\n      fillDetails(template)\n      setLocalStorageValue(\"agent_template_id_\" + String(internalId), template.id, setAgentTemplateId);\n\n      fetchAgentTemplateConfigLocal(template.id)\n        .then((response) => {\n          const data = response.data || [];\n          fillAdvancedDetails(data)\n          setLocalStorageArray(\"tool_names_\" + String(internalId), data.tools, setToolNames);\n          setLocalStorageValue(\"is_agent_template_\" + String(internalId), true, setShowButton);\n          setShowButton(true);\n        })\n        .catch((error) => {\n          console.error('Error fetching template details:', error);\n        });\n    }\n  }, []);\n\n  useEffect(() => {\n    function handleClickOutside(event) {\n      if (modelRef.current && !modelRef.current.contains(event.target)) {\n        setModelDropdown(false)\n      }\n\n      if (agentRef.current && !agentRef.current.contains(event.target)) {\n        setAgentDropdown(false)\n      }\n\n      if (exitRef.current && !exitRef.current.contains(event.target)) {\n        setExitDropdown(false)\n      }\n\n      if (rollingRef.current && !rollingRef.current.contains(event.target)) {\n        setRollingDropdown(false)\n      }\n\n      if (knowledgeRef.current && !knowledgeRef.current.contains(event.target)) {\n        setKnowledgeDropdown(false)\n      }\n\n      if (databaseRef.current && !databaseRef.current.contains(event.target)) {\n        setDatabaseDropdown(false)\n      }\n\n      if (permissionRef.current && !permissionRef.current.contains(event.target)) {\n        setPermissionDropdown(false)\n      }\n\n      if (toolkitRef.current && !toolkitRef.current.contains(event.target)) {\n        setToolkitDropdown(false)\n      }\n    }\n\n    document.addEventListener('mousedown', handleClickOutside);\n    return () => {\n      document.removeEventListener('mousedown', handleClickOutside);\n    };\n  }, []);\n\n  const addTool = (tool) => {\n    if (!selectedTools.includes(tool.id) && !toolNames.includes(tool.name)) {\n      const updatedToolIds = [...selectedTools, tool.id];\n      setLocalStorageArray(\"tool_ids_\" + String(internalId), updatedToolIds, setSelectedTools);\n\n      const updatedToolNames = [...toolNames, tool.name];\n      setLocalStorageArray(\"tool_names_\" + String(internalId), updatedToolNames, setToolNames);\n    }\n    setSearchValue('');\n  };\n\n  const editingAgent = () => {\n    const isLoaded = localStorage.getItem('is_editing_agent_' + String(internalId));\n    const agent = agents.find(agent => agent.id === editAgentId);\n    if (!isLoaded) {\n      fillDetails(agent)\n    }\n    getAgentDetails(editAgentId, -1)\n        .then((response) => {\n          const data = response.data || []\n          if (!isLoaded) {\n            fillAdvancedDetails(data)\n            setLocalStorageArray(\"tool_names_\" + String(internalId), data.tools.map(tool => tool.name), setToolNames);\n          }\n        })\n        .catch((error) => {\n          console.error('Error fetching agent details:', error);\n        });\n    localStorage.setItem('is_editing_agent_' + String(internalId), true);\n  };\n\n  const fillDetails = (agent) => {\n    setLocalStorageValue(\"agent_name_\" + String(internalId), agent.name, setAgentName);\n    setLocalStorageValue(\"agent_description_\" + String(internalId), agent.description, setAgentDescription);\n    setLocalStorageValue(\"advanced_options_\" + String(internalId), true, setAdvancedOptions);\n  }\n  const fillAdvancedDetails = (data) => {\n    setLocalStorageArray(\"agent_goals_\" + String(internalId), data.goal, setGoals);\n    setLocalStorageValue(\"agent_workflow_\" + String(internalId), data.agent_workflow, setAgentWorkflow);\n    setLocalStorageArray(\"agent_constraints_\" + String(internalId), data.constraints, setConstraints);\n    setLocalStorageValue(\"agent_iterations_\" + String(internalId), data.max_iterations, setIterations);\n    setLocalStorageValue(\"agent_step_time_\" + String(internalId), data.iteration_interval, setStepTime);\n    setLocalStorageValue(\"agent_permission_\" + String(internalId), data.permission_type, setPermission);\n    setLocalStorageArray(\"agent_instructions_\" + String(internalId), data.instruction, setInstructions);\n    setLocalStorageValue(\"agent_database_\" + String(internalId), data.LTM_DB, setDatabase);\n    setLocalStorageValue(\"agent_model_\" + String(internalId), data.model, setModel);\n  }\n\n\n  const addToolkit = (toolkit) => {\n    const updatedToolIds = [...selectedTools];\n    const updatedToolNames = [...toolNames];\n\n    toolkit.tools.map((tool) => {\n      if (!selectedTools.includes(tool.id) && !toolNames.includes(tool.name)) {\n        updatedToolIds.push(tool.id);\n        updatedToolNames.push(tool.name);\n      }\n    });\n\n    setLocalStorageArray(\"tool_ids_\" + String(internalId), updatedToolIds, setSelectedTools);\n    setLocalStorageArray(\"tool_names_\" + String(internalId), updatedToolNames, setToolNames);\n    setSearchValue('');\n  }\n\n  const removeTool = (indexToDelete) => {\n    const updatedToolIds = [...selectedTools];\n    updatedToolIds.splice(indexToDelete, 1);\n    setLocalStorageArray(\"tool_ids_\" + String(internalId), updatedToolIds, setSelectedTools);\n\n    const updatedToolNames = [...toolNames];\n    updatedToolNames.splice(indexToDelete, 1);\n    setLocalStorageArray(\"tool_names_\" + String(internalId), updatedToolNames, setToolNames);\n  };\n\n  const handlePermissionSelect = (index) => {\n    setLocalStorageValue(\"agent_permission_\" + String(internalId), permissions[index], setPermission);\n    setPermissionDropdown(false);\n  };\n\n  const handleDatabaseSelect = (index) => {\n    setLocalStorageValue(\"agent_database_\" + String(internalId), databases[index], setDatabase);\n    setDatabaseDropdown(false);\n  };\n\n\n  const handleKnowledgeSelect = (index) => {\n    setLocalStorageValue(\"agent_knowledge_\" + String(internalId), knowledge[index].name, setSelectedKnowledge);\n    setLocalStorageValue(\"agent_knowledge_id_\" + String(internalId), knowledge[index].id, setSelectedKnowledgeId);\n    setKnowledgeDropdown(false);\n  };\n\n  const handleStepChange = (event) => {\n    setLocalStorageValue(\"agent_step_time_\" + String(internalId), event.target.value, setStepTime);\n  };\n\n  const handleExitSelect = (index) => {\n    setLocalStorageValue(\"agent_exit_criterion_\" + String(internalId), exitCriteria[index], setExitCriterion);\n    setExitDropdown(false);\n  };\n\n  const handleAgentSelect = (index) => {\n    setLocalStorageValue(\"agent_workflow_\" + String(internalId), agentWorkflows[index], setAgentWorkflow);\n    setAgentDropdown(false);\n  };\n\n  const handleModelSelect = (index) => {\n    setLocalStorageValue(\"agent_model_\" + String(internalId), modelsArray[index], setModel);\n    if (modelsArray[index] === \"google-palm-bison-001\" || modelsArray[index] === \"replicate-llama13b-v2-chat\") {\n      setAgentType(\"Fixed Task Queue\")\n    }\n    setModelDropdown(false);\n  };\n\n  const handleGoalChange = (index, newValue) => {\n    const updatedGoals = [...goals];\n    updatedGoals[index] = newValue;\n    setLocalStorageArray(\"agent_goals_\" + String(internalId), updatedGoals, setGoals);\n  };\n\n  const handleInstructionChange = (index, newValue) => {\n    const updatedInstructions = [...instructions];\n    updatedInstructions[index] = newValue;\n    setLocalStorageArray(\"agent_instructions_\" + String(internalId), updatedInstructions, setInstructions);\n  };\n\n  const handleConstraintChange = (index, newValue) => {\n    const updatedConstraints = [...constraints];\n    updatedConstraints[index] = newValue;\n    setLocalStorageArray(\"agent_constraints_\" + String(internalId), updatedConstraints, setConstraints);\n  };\n\n  const handleGoalDelete = (index) => {\n    const updatedGoals = [...goals];\n    updatedGoals.splice(index, 1);\n    setLocalStorageArray(\"agent_goals_\" + String(internalId), updatedGoals, setGoals);\n  };\n\n  const handleInstructionDelete = (index) => {\n    const updatedInstructions = [...instructions];\n    updatedInstructions.splice(index, 1);\n    setLocalStorageArray(\"agent_instructions_\" + String(internalId), updatedInstructions, setInstructions);\n  };\n\n  const handleConstraintDelete = (index) => {\n    const updatedConstraints = [...constraints];\n    updatedConstraints.splice(index, 1);\n    setLocalStorageArray(\"agent_constraints_\" + String(internalId), updatedConstraints, setConstraints);\n  };\n\n  const addGoal = () => {\n    setLocalStorageArray(\"agent_goals_\" + String(internalId), [...goals, 'new goal'], setGoals);\n  };\n\n  const addInstruction = () => {\n    setLocalStorageArray(\"agent_instructions_\" + String(internalId), [...instructions, 'new instructions'], setInstructions);\n  };\n\n  const addConstraint = () => {\n    setLocalStorageArray(\"agent_constraints_\" + String(internalId), [...constraints, 'new constraint'], setConstraints);\n  };\n\n  const handleNameChange = (event) => {\n    setLocalStorageValue(\"agent_name_\" + String(internalId), event.target.value, setAgentName);\n  };\n\n  const handleDescriptionChange = (event) => {\n    setLocalStorageValue(\"agent_description_\" + String(internalId), event.target.value, setAgentDescription);\n  };\n\n  const closeCreateModal = () => {\n    setCreateModal(false);\n    setCreateDropdown(false);\n  };\n\n  function uploadResource(agentId, fileData) {\n    const formData = new FormData();\n    formData.append('file', fileData.file);\n    formData.append('name', fileData.name);\n    formData.append('size', fileData.size);\n    formData.append('type', fileData.type);\n\n    return uploadFile(agentId, formData);\n  }\n\n  useEffect(() => {\n    const keySet = (eventData) => {\n      setHasAPIkey(true);\n    };\n\n    const handleAgentScheduling = (item) => {\n      setScheduleData(item)\n    };\n\n    EventBus.on('keySet', keySet);\n    EventBus.on('handleAgentScheduling', handleAgentScheduling);\n\n    return () => {\n      EventBus.off('keySet', keySet);\n      EventBus.off('handleAgentScheduling', handleAgentScheduling);\n    };\n  });\n\n  useEffect(() => {\n    if (scheduleData) {\n      handleAddAgent()\n    }\n  }, [scheduleData]);\n\n  const validateAgentData = (isNewAgent) => {\n    if (isNewAgent && !hasAPIkey) {\n      toast.error(\"Your API key is empty!\", {autoClose: 1800});\n      openNewTab(-3, \"Settings\", \"Settings\", false);\n      return false;\n    }\n\n    if (agentName?.replace(/\\s/g, '') === '') {\n      toast.error(\"Agent name can't be blank\", {autoClose: 1800});\n      return false;\n    }\n\n    if (agentDescription?.replace(/\\s/g, '') === '') {\n      toast.error(\"Agent description can't be blank\", {autoClose: 1800});\n      return false;\n    }\n\n    const isEmptyGoal = goals.some((goal) => goal.replace(/\\s/g, '') === '');\n    if (isEmptyGoal) {\n      toast.error(\"Goal can't be empty\", {autoClose: 1800});\n      return false;\n    }\n\n    if (selectedTools.length <= 0) {\n      toast.error(\"Add atleast one tool\", {autoClose: 1800});\n      return false;\n    }\n\n    if (!modelsArray.includes(model)) {\n      toast.error(\"Your key does not have access to the selected model\", {autoClose: 1800});\n      return false;\n    }\n\n    if (toolNames.includes('Knowledge Search') && !selectedKnowledge) {\n      toast.error(\"Add atleast one knowledge\", {autoClose: 1800});\n      return;\n    }\n\n    return true;\n  }\n\n  const handleAddAgent = async () => {\n    if (!validateAgentData(true)) {\n      return;\n    }\n\n    setCreateClickable(false);\n\n    const agentData = setAgentData()\n\n    const scheduleAgentData = {\n      \"agent_config\": agentData,\n      \"schedule\": scheduleData,\n    }\n\n    if(edit){\n      if (editButtonClicked) return;\n      setEditButtonClicked(true);\n      agentData.agent_id = editAgentId;\n      const name = agentData.name\n      const adjustedDate = new Date((new Date()).getTime());\n      const formattedDate = `${adjustedDate.getDate()} ${['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'][adjustedDate.getMonth()]} ${adjustedDate.getFullYear()} ${adjustedDate.getHours().toString().padStart(2, '0')}:${adjustedDate.getMinutes().toString().padStart(2, '0')}`;\n      agentData.name = \"Run \" + formattedDate\n      addAgentRun(agentData)\n        .then((response) => {\n        if(response){\n          fetchAgents();\n          uploadResources(editAgentId, name)\n        }\n      })\n    }\n    else\n      {\n        createAgent(createModal ? scheduleAgentData : agentData, createModal)\n            .then((response) => {\n              const agentId = response.data.id;\n              const name = response.data.name;\n              const executionId = response.data.execution_id;\n              fetchAgents();\n              getUserClick('Agent Created Successfully', {'templateName': template?.id ? template.name : ''})\n              getUserClick('Agent Run created successfully', {})\n              uploadResources(agentId, name, executionId)\n            })\n            .catch((error) => {\n              console.error('Error creating agent:', error);\n              setCreateClickable(true);\n            });\n      }\n  };\n  const setAgentData= () => {\n    let permission_type = permission;\n    if (permission.includes(\"RESTRICTED\")) {\n      permission_type = \"RESTRICTED\";\n    }\n\n    const agentData = {\n      \"name\": agentName,\n      \"project_id\": selectedProjectId,\n      \"description\": agentDescription,\n      \"goal\": goals,\n      \"instruction\": instructions,\n      \"agent_workflow\": agentWorkflow,\n      \"constraints\": constraints,\n      \"toolkits\": [],\n      \"tools\": selectedTools,\n      \"exit\": exitCriterion,\n      \"iteration_interval\": stepTime,\n      \"model\": model,\n      \"max_iterations\": maxIterations,\n      \"permission_type\": permission_type,\n      \"LTM_DB\": longTermMemory ? database : null,\n      \"user_timezone\": getUserTimezone(),\n      \"knowledge\": toolNames.includes('Knowledge Search') ? selectedKnowledgeId : null,\n    };\n\n    return agentData\n  }\n  const uploadResources = (agentId, name, executionId) => {\n    if (addResources && input.length > 0) {\n      const uploadPromises = input.map(fileData => {\n        return uploadResource(agentId, fileData)\n            .catch(error => {\n              console.error('Error uploading resource:', error);\n              return Promise.reject(error);\n            });\n      });\n\n      Promise.all(uploadPromises)\n          .then(() => {\n            runDecision(agentId, name, executionId)\n          })\n          .catch(error => {\n            console.error('Error uploading files:', error);\n            setCreateClickable(true);\n          });\n    } else {\n      runDecision(agentId, name, executionId)\n    }\n  }\n\n  const runDecision = (agentId, name, executionId) => {\n    if(edit){\n      setEditModal(false)\n      sendAgentData({\n        id: editAgentId,\n        name: name,\n        contentType: \"Agents\",\n      });\n      removeTab(editAgentId, name, \"Agents\", internalId)\n    }\n    else {\n      runExecution(agentId, name, executionId, createModal);\n    }\n  }\n\n  const finaliseAgentCreation = (agentId, name, executionId) => {\n    toast.success('Agent created successfully', {autoClose: 1800});\n    let timeoutValue = executionId ? 0 : 1500;\n\n    setTimeout(() => {\n      sendAgentData({\n        id: agentId,\n        name: name,\n        contentType: \"Agents\",\n        execution_id: executionId,\n        internalId: createInternalId()\n      });\n      setCreateClickable(true);\n      setCreateModal(false);\n    }, timeoutValue)\n  }\n\n  function runExecution(agentId, name, executionId, createModal) {\n    if (createModal) {\n      finaliseAgentCreation(agentId, name, null);\n      return;\n    }\n\n    updateExecution(executionId, {\"status\": 'RUNNING'})\n      .then((response) => {\n        finaliseAgentCreation(agentId, name, executionId);\n      })\n      .catch((error) => {\n        setCreateClickable(true);\n        console.error('Error updating execution:', error);\n      });\n  }\n\n  const toggleToolkit = (e, id) => {\n    e.stopPropagation();\n    const toolkitToUpdate = toolkitList.find(toolkit => toolkit.id === id);\n    if (toolkitToUpdate) {\n      const newOpenValue = !toolkitToUpdate.isOpen;\n      setToolkitOpen(id, newOpenValue);\n    }\n  };\n\n  const setToolkitOpen = (id, isOpen) => {\n    const updatedToolkits = toolkitList.map(toolkit =>\n      toolkit.id === id ? {...toolkit, isOpen: isOpen} : {...toolkit, isOpen: false}\n    );\n    setToolkitList(updatedToolkits);\n  };\n\n  const clearTools = (e) => {\n    e.stopPropagation();\n    setLocalStorageArray(\"tool_names_\" + String(internalId), [], setToolNames);\n    setLocalStorageArray(\"tool_ids_\" + String(internalId), [], setSelectedTools);\n  };\n\n  const handleFileInputChange = (event) => {\n    const files = event.target.files;\n    setFileData(files);\n  };\n\n  const handleDropAreaClick = () => {\n    fileInputRef.current.click();\n  };\n\n  const handleDragEnter = (event) => {\n    event.preventDefault();\n    setIsDragging(true);\n  };\n\n  const handleDragLeave = () => {\n    setIsDragging(false);\n  };\n\n  const handleDragOver = (event) => {\n    event.preventDefault();\n  };\n\n  function updateTemplate() {\n\n    if (!validateAgentData(false)) return;\n\n    let permission_type = permission;\n    if (permission.includes(\"RESTRICTED\")) {\n      permission_type = \"RESTRICTED\";\n    }\n\n    const agentTemplateConfigData = {\n      \"goal\": goals,\n      \"instruction\": instructions,\n      \"agent_workflow\": agentWorkflow,\n      \"constraints\": constraints,\n      \"tools\": toolNames,\n      \"exit\": exitCriterion,\n      \"iteration_interval\": stepTime,\n      \"model\": model,\n      \"max_iterations\": maxIterations,\n      \"permission_type\": permission_type,\n      \"LTM_DB\": longTermMemory ? database : null,\n    }\n    const editTemplateData = {\n      \"name\": agentName,\n      \"description\": agentDescription,\n      \"agent_configs\": agentTemplateConfigData\n    }\n\n    editAgentTemplate(agentTemplateId, editTemplateData)\n      .then((response) => {\n        if (response.status === 200) {\n          toast.success('Agent template has been updated successfully!', {autoClose: 1800});\n        }\n      })\n      .catch((error) => {\n        toast.error(\"Error updating agent template\")\n        console.error('Error updating agent template:', error);\n      });\n  };\n\n  function setFileData(files) {\n    if (files.length > 0) {\n      const fileData = {\n        \"file\": files[0],\n        \"name\": files[0].name,\n        \"size\": files[0].size,\n        \"type\": files[0].type,\n      };\n      const updatedFiles = [...input, fileData];\n      setLocalStorageArray('agent_files_' + String(internalId), updatedFiles, setInput);\n    }\n  }\n\n  function checkSelectedToolkit(toolkit) {\n    const toolIds = toolkit.tools.map((tool) => tool.id);\n    const toolNameList = toolkit.tools.map((tool) => tool.name);\n    return toolIds.every((toolId) => selectedTools.includes(toolId)) && toolNameList.every((toolName) => toolNames.includes(toolName));\n  }\n\n  const handleDrop = (event) => {\n    event.preventDefault();\n    setIsDragging(false);\n    const files = event.dataTransfer.files;\n    setFileData(files);\n  };\n\n  const removeFile = (index) => {\n    const updatedFiles = input.filter((file) => input.indexOf(file) !== index);\n    setLocalStorageArray('agent_files_' + String(internalId), updatedFiles, setInput);\n  };\n\n  useEffect(() => {\n    if (internalId !== null) {\n      const has_resource = localStorage.getItem(\"has_resource_\" + String(internalId)) || 'true';\n      if (has_resource) {\n        setAddResources(JSON.parse(has_resource));\n      }\n\n      const has_LTM = localStorage.getItem(\"has_LTM_\" + String(internalId)) || 'true';\n      if (has_LTM) {\n        setLongTermMemory(JSON.parse(has_LTM));\n      }\n\n      const advanced_options = localStorage.getItem(\"advanced_options_\" + String(internalId)) || 'false';\n      if (advanced_options) {\n        setAdvancedOptions(JSON.parse(advanced_options));\n      }\n\n      const is_agent_template = localStorage.getItem(\"is_agent_template_\" + String(internalId));\n      if (is_agent_template) {\n        setShowButton(true);\n      }\n\n      const agent_name = localStorage.getItem(\"agent_name_\" + String(internalId));\n      if (agent_name) {\n        setAgentName(agent_name);\n      }\n\n      const agent_template_id = localStorage.getItem(\"agent_template_id_\" + String(internalId));\n      if (agent_template_id) {\n        setAgentTemplateId(agent_template_id)\n      }\n\n      const agent_description = localStorage.getItem(\"agent_description_\" + String(internalId));\n      if (agent_description) {\n        setAgentDescription(agent_description);\n      }\n\n      const agent_goals = localStorage.getItem(\"agent_goals_\" + String(internalId));\n      if (agent_goals) {\n        setGoals(JSON.parse(agent_goals));\n      }\n\n      const tool_ids = localStorage.getItem(\"tool_ids_\" + String(internalId));\n      if (tool_ids) {\n        setSelectedTools(JSON.parse(tool_ids));\n      }\n\n      const tool_names = localStorage.getItem(\"tool_names_\" + String(internalId));\n      if (tool_names) {\n        setToolNames(JSON.parse(tool_names));\n      }\n\n      const agent_instructions = localStorage.getItem(\"agent_instructions_\" + String(internalId));\n      if (agent_instructions) {\n        setInstructions(JSON.parse(agent_instructions));\n      }\n\n      const agent_constraints = localStorage.getItem(\"agent_constraints_\" + String(internalId));\n      if (agent_constraints) {\n        setConstraints(JSON.parse(agent_constraints));\n      }\n\n      const agent_model = localStorage.getItem(\"agent_model_\" + String(internalId));\n      if (agent_model) {\n        setModel(agent_model);\n      }\n\n      const agent_workflow = localStorage.getItem(\"agent_workflow_\" + String(internalId));\n      if (agent_workflow) {\n        setAgentWorkflow(agent_workflow);\n      }\n\n      const agent_database = localStorage.getItem(\"agent_database_\" + String(internalId));\n      if (agent_database) {\n        setDatabase(agent_database);\n      }\n\n      const agent_permission = localStorage.getItem(\"agent_permission_\" + String(internalId));\n      if (agent_permission) {\n        setPermission(agent_permission);\n      }\n\n      const exit_criterion = localStorage.getItem(\"agent_exit_criterion_\" + String(internalId));\n      if (exit_criterion) {\n        setExitCriterion(exit_criterion);\n      }\n\n      const iterations = localStorage.getItem(\"agent_iterations_\" + String(internalId));\n      if (iterations) {\n        setIterations(Number(iterations));\n      }\n\n      const step_time = localStorage.getItem(\"agent_step_time_\" + String(internalId));\n      if (step_time) {\n        setStepTime(Number(step_time));\n      }\n\n      const agent_files = localStorage.getItem(\"agent_files_\" + String(internalId));\n      if (agent_files) {\n        setInput(JSON.parse(agent_files));\n      }\n    }\n\n    const agent_knowledge = localStorage.getItem(\"agent_knowledge_\" + String(internalId));\n    if (agent_knowledge) {\n      setSelectedKnowledge(agent_knowledge);\n    }\n  }, [internalId])\n\n  function openMarketplace() {\n    openNewTab(-4, \"Marketplace\", \"Marketplace\", false);\n    localStorage.setItem('marketplace_tab', 'market_knowledge');\n  }\n\n  const checkPermissionValidity = (permit) => {\n   if(!(agentWorkflow === 'Fixed Task Workflow' || agentWorkflow === 'Dynamic Task Workflow' || agentWorkflow === 'Goal Based Workflow' ) && permit === 'RESTRICTED (Will ask for permission before using any tool)')\n     return true;\n   else\n     return false;\n  }\n\n  const openModelMarket = () => {\n    openNewTab(-4, \"Marketplace\", \"Marketplace\", false);\n    localStorage.setItem('marketplace_tab', 'market_models');\n  }\n\n  const handleAddToMarketplace = () => {\n    const agentData = setAgentData()\n    agentData.agent_template_id = template.id\n    publishTemplateToMarketplace(agentData)\n      .then((response) => {\n        setDropdown(false)\n        setPublishModal(true)\n      })\n      .catch((error) => {\n        toast.error(\"Error Publishing to marketplace\")\n        console.error('Error Publishing to marketplace:', error);\n      });\n  }\n\n  return (<>\n    <div className=\"row\" style={{overflowY: 'scroll', height: 'calc(100vh - 92px)'}}>\n      <div className=\"col-3\"></div>\n      <div className=\"col-6\" style={{padding: '25px 20px'}}>\n        <div>\n          {!edit ? <div className={styles.page_title}>Create new agent</div> : <div className={styles.page_title}>Edit agent</div>}\n        </div>\n        <div style={{marginTop: '10px'}}>\n          <div>\n            <label className={styles.form_label}>Name</label>\n            <input className=\"input_medium\" type=\"text\" value={agentName} disabled={edit}  onChange={handleNameChange}/>\n          </div>\n          <div style={{marginTop: '15px'}}>\n            <label className={styles.form_label}>Description</label>\n            <textarea className=\"textarea_medium\" rows={3} value={agentDescription} disabled={edit} onChange={handleDescriptionChange}/>\n          </div>\n          <div style={{marginTop: '15px'}}>\n            <div><label className={styles.form_label}>Goals</label></div>\n            {goals?.map((goal, index) => (<div key={index} style={{\n              marginBottom: '10px',\n              display: 'flex',\n              alignItems: 'center',\n              justifyContent: 'space-between'\n            }}>\n              <div style={{flex: '1'}}><input className=\"input_medium\" type=\"text\" value={goal}\n                                              onChange={(event) => handleGoalChange(index, event.target.value)}/></div>\n              {goals.length > 1 && <div>\n                <button className=\"secondary_button\" style={{marginLeft: '4px', padding: '5px'}}\n                        onClick={() => handleGoalDelete(index)}>\n                  <Image width={20} height={21} src=\"/images/close.svg\" alt=\"close-icon\"/>\n                </button>\n              </div>}\n            </div>))}\n            <div>\n              <button className=\"secondary_button\" onClick={addGoal}>+ Add</button>\n            </div>\n          </div>\n\n          <div style={{marginTop: '15px'}}>\n            <div><label className={styles.form_label}>Instructions<span\n              style={{fontSize: '9px'}}>&nbsp;(optional)</span></label></div>\n            {instructions?.map((goal, index) => (<div key={index} style={{\n              marginBottom: '10px',\n              display: 'flex',\n              alignItems: 'center',\n              justifyContent: 'space-between'\n            }}>\n              <div style={{flex: '1'}}><input className=\"input_medium\" type=\"text\" value={goal}\n                                              onChange={(event) => handleInstructionChange(index, event.target.value)}/>\n              </div>\n              {instructions.length > 1 && <div>\n                <button className=\"secondary_button\" style={{marginLeft: '4px', padding: '5px'}}\n                        onClick={() => handleInstructionDelete(index)}>\n                  <Image width={20} height={21} src=\"/images/close.svg\" alt=\"close-icon\"/>\n                </button>\n              </div>}\n            </div>))}\n            <div>\n              <button className=\"secondary_button\" onClick={addInstruction}>+ Add</button>\n            </div>\n          </div>\n\n          <div style={{marginTop: '15px'}}>\n            <label className={styles.form_label}>Model</label><br/>\n            <div className=\"dropdown_container_search\" style={{width: '100%'}}>\n              <div className=\"custom_select_container\" onClick={() => setModelDropdown(!modelDropdown)}\n                   style={{width: '100%'}}>\n                {model}<Image width={20} height={21}\n                              src={!modelDropdown ? '/images/dropdown_down.svg' : '/images/dropdown_up.svg'}\n                              alt=\"expand-icon\"/>\n              </div>\n              <div>\n                {modelDropdown && (\n                    <div className=\"custom_select_options\" ref={modelRef} style={{width: '100%', maxHeight: '300px'}}>\n                      <div className=\"model_options\">\n                        {modelsArray?.map((model, index) => (\n                            <div key={index} className=\"custom_select_option\" onClick={() => handleModelSelect(index)}\n                                 style={{padding: '12px 14px', maxWidth: '100%'}}>\n                              {model}\n                            </div>\n                        ))}\n                      </div>\n                      <div className=\"vertical_containers sticky_option\">\n                        <div onClick={() => openModelMarket()} className=\"custom_select_option horizontal_container mxw_100 padding_12_14 gap_6 bt_white\">\n                          <Image width={16} height={16} src=\"/images/marketplace_logo.png\" alt=\"marketplace_logo\" />\n                          <span>Browse models from marketplace</span>\n                        </div>\n                        <div onClick={() => openNewTab(-5, \"new model\", \"Add_Model\", false)} className=\"custom_select_option horizontal_container mxw_100 padding_12_14 gap_6 bt_white\">\n                          <Image width={16} height={16} src=\"/images/plus.png\" alt=\"plus_image\" />\n                          <span>Add new custom model</span>\n                        </div>\n                      </div>\n                    </div>\n                )}\n              </div>\n            </div>\n          </div>\n          <div style={{marginTop: '15px'}}>\n            <label className={styles.form_label}>Tools</label>\n            <div className=\"dropdown_container_search\" style={{width: '100%'}}>\n              <div className=\"custom_select_container\" onClick={() => setToolkitDropdown(!toolkitDropdown)}\n                   style={{width: '100%', alignItems: 'flex-start'}}>\n                <div style={{display: 'flex', flexWrap: 'wrap', width: '100%', alignItems: 'start'}}>\n                  {toolNames && toolNames.length > 0 && toolNames.map((tool, index) => (\n                    <div key={index} className=\"tool_container\" style={{margin: '2px'}} onClick={preventDefault}>\n                      <div className={styles.tool_text}>{tool}</div>\n                      <div><Image width={12} height={12} src='/images/close_light.svg' alt=\"close-icon\"\n                                  style={{margin: '-2px -5px 0 2px'}} onClick={() => removeTool(index)}/></div>\n                    </div>\n                  ))}\n                  <input type=\"text\" className=\"dropdown_search_text\" value={searchValue} style={{flexGrow: 1}}\n                         onChange={(e) => setSearchValue(e.target.value)}\n                         onFocus={() => {\n                           setToolkitDropdown(true);\n                           setShowPlaceholder(false);\n                         }} onBlur={() => {\n                    setShowPlaceholder(true);\n                  }}\n                         onClick={(e) => e.stopPropagation()}/>\n                  {toolNames && toolNames.length === 0 && showPlaceholder && searchValue.length === 0 &&\n                    <div style={{color: '#666666', position: 'absolute'}}>Select Tools</div>}\n                </div>\n                <div style={{display: 'inline-flex'}}>\n                  <Image width={20} height={21} onClick={(e) => clearTools(e)} src='/images/clear_input.svg'\n                         alt=\"clear-input\"/>\n                  <Image width={20} height={21}\n                         src={!toolkitDropdown ? '/images/dropdown_down.svg' : '/images/dropdown_up.svg'}\n                         alt=\"expand-icon\"/>\n                </div>\n              </div>\n              <div>\n                {toolkitDropdown && <div className=\"custom_select_options\" ref={toolkitRef} style={{width: '100%'}}>\n                  {toolkitList && toolkitList.filter((toolkit) => toolkit.tools ? toolkit.tools.some((tool) => tool.name.toLowerCase().includes(searchValue.toLowerCase())) : false).map((toolkit, index) => (\n                    <div key={index}>\n                      {toolkit.name !== null && !excludedToolkits().includes(toolkit.name) && <div>\n                        <div onClick={() => addToolkit(toolkit)} className=\"custom_select_option\" style={{\n                          padding: '10px 14px',\n                          maxWidth: '100%',\n                          display: 'flex',\n                          alignItems: 'center',\n                          justifyContent: 'space-between'\n                        }}>\n                          <div style={{display: 'flex', alignItems: 'center', justifyContent: 'flex-start'}}>\n                            <div onClick={(e) => toggleToolkit(e, toolkit.id)}\n                                 style={{marginLeft: '-8px', marginRight: '8px'}}>\n                              <Image src={toolkit.isOpen ? \"/images/arrow_down.svg\" : \"/images/arrow_forward.svg\"}\n                                     width={11} height={11} alt=\"expand-arrow\"/>\n                            </div>\n                            <div style={{width: '100%'}}>{toolkit.name}</div>\n                          </div>\n                          {checkSelectedToolkit(toolkit) && <div style={{order: '1', marginLeft: '10px'}}>\n                            <Image src=\"/images/tick.svg\" width={17} height={17} alt=\"selected-toolkit\"/>\n                          </div>}\n                        </div>\n                        {toolkit.isOpen && toolkit.tools.filter((tool) => tool.name ? tool.name.toLowerCase().includes(searchValue.toLowerCase()) : true).map((tool, index) => (\n                          <div key={index} className=\"custom_select_option\" onClick={() => addTool(tool)} style={{\n                            padding: '10px 14px 10px 40px',\n                            maxWidth: '100%',\n                            display: 'flex',\n                            alignItems: 'center',\n                            justifyContent: 'space-between'\n                          }}>\n                            <div>{tool.name}</div>\n                            {(selectedTools.includes(tool.id) || toolNames.includes(tool.name)) &&\n                              <div style={{order: '1', marginLeft: '10px'}}>\n                                <Image src=\"/images/tick.svg\" width={17} height={17} alt=\"selected-tool\"/>\n                              </div>}\n                          </div>))}\n                      </div>}\n                    </div>))}\n                </div>}\n              </div>\n            </div>\n          </div>\n          {toolNames.includes(\"Knowledge Search\") && <div style={{marginTop: '5px'}}>\n            <label className={styles.form_label}>Add knowledge</label>\n            <div className=\"dropdown_container_search\" style={{width: '100%'}}>\n              <div className=\"custom_select_container\" onClick={() => setKnowledgeDropdown(!knowledgeDropdown)}\n                   style={selectedKnowledge ? {width: '100%'} : {width: '100%', color: '#888888'}}>\n                {selectedKnowledge || 'Select knowledge'}<Image width={20} height={21}\n                                                                src={!knowledgeDropdown ? '/images/dropdown_down.svg' : '/images/dropdown_up.svg'}\n                                                                alt=\"expand-icon\"/>\n              </div>\n              <div>\n                {knowledgeDropdown && knowledge && knowledge.length > 0 &&\n                  <div className=\"custom_select_options\" ref={knowledgeRef} style={{width: '100%'}}>\n                    {knowledge.map((item, index) => (\n                      <div key={index} className=\"custom_select_option\" onClick={() => handleKnowledgeSelect(index)}\n                           style={{padding: '12px 14px', maxWidth: '100%'}}>\n                        {item.name}\n                      </div>))}\n                    <div className={styles1.knowledge_db}\n                         style={{maxWidth: '100%', borderTop: '1px solid #3F3A4E'}}>\n                      <div className=\"custom_select_option\"\n                           style={{padding: '12px 14px', maxWidth: '100%', borderRadius: '0'}}\n                           onClick={() => sendKnowledgeData({\n                             id: -6,\n                             name: \"new knowledge\",\n                             contentType: \"Add_Knowledge\",\n                             internalId: createInternalId()\n                           })}>\n                        <Image width={15} height={15} src=\"/images/plus_symbol.svg\" alt=\"add-icon\"/>&nbsp;&nbsp;Add\n                        new knowledge\n                      </div>\n                    </div>\n                    <div className={styles1.knowledge_db}\n                         style={{maxWidth: '100%', borderTop: '1px solid #3F3A4E'}}>\n                      <div className=\"custom_select_option\" style={{\n                        padding: '12px 14px',\n                        maxWidth: '100%',\n                        borderTopLeftRadius: '0',\n                        borderTopRightRadius: '0'\n                      }}\n                           onClick={openMarketplace}>\n                        <Image width={15} height={15} src=\"/images/widgets.svg\"\n                               alt=\"marketplace\"/>&nbsp;&nbsp;Browse knowledge from marketplace\n                      </div>\n                    </div>\n                  </div>}\n                {knowledgeDropdown && knowledge && knowledge.length <= 0 &&\n                  <div className=\"custom_select_options\" ref={knowledgeRef}\n                       style={{width: '100%', maxHeight: '400px'}}>\n                    <div style={{\n                      display: 'flex',\n                      flexDirection: 'column',\n                      alignItems: 'center',\n                      justifyContent: 'center',\n                      marginTop: '30px',\n                      marginBottom: '20px',\n                      width: '100%'\n                    }}>\n                      <Image width={150} height={60} src=\"/images/no_permissions.svg\" alt=\"no-permissions\"/>\n                      <span className={styles.feed_title} style={{marginTop: '8px'}}>No knowledge found</span>\n                    </div>\n                    <div className={styles1.knowledge_db}\n                         style={{maxWidth: '100%', borderTop: '1px solid #3F3A4E'}}>\n                      <div className=\"custom_select_option\"\n                           style={{padding: '12px 14px', maxWidth: '100%', borderRadius: '0'}}\n                           onClick={() => sendKnowledgeData({\n                             id: -6,\n                             name: \"new knowledge\",\n                             contentType: \"Add_Knowledge\",\n                             internalId: createInternalId()\n                           })}>\n                        <Image width={15} height={15} src=\"/images/plus_symbol.svg\" alt=\"add-icon\"/>&nbsp;&nbsp;Add\n                        new knowledge\n                      </div>\n                    </div>\n                    <div className={styles1.knowledge_db}\n                         style={{maxWidth: '100%', borderTop: '1px solid #3F3A4E'}}>\n                      <div className=\"custom_select_option\" style={{\n                        padding: '12px 14px',\n                        maxWidth: '100%',\n                        borderTopLeftRadius: '0',\n                        borderTopRightRadius: '0'\n                      }}\n                           onClick={openMarketplace}>\n                        <Image width={15} height={15} src=\"/images/widgets.svg\"\n                               alt=\"marketplace\"/>&nbsp;&nbsp;Browse knowledge from marketplace\n                      </div>\n                    </div>\n                  </div>}\n              </div>\n            </div>\n          </div>}\n          <div style={{marginTop: '15px'}}>\n            <button className=\"medium_toggle\"\n                    onClick={() => setLocalStorageValue(\"advanced_options_\" + String(internalId), !advancedOptions, setAdvancedOptions)}\n                    style={advancedOptions ? {background: '#494856'} : {}}>\n              {advancedOptions ? 'Hide Advanced Options' : 'Show Advanced Options'}{advancedOptions ?\n              <Image style={{marginLeft: '10px'}} width={20} height={21} src=\"/images/dropdown_up.svg\"\n                     alt=\"expand-icon\"/> :\n              <Image style={{marginLeft: '10px'}} width={20} height={21} src=\"/images/dropdown_down.svg\"\n                     alt=\"expand-icon\"/>}\n            </button>\n          </div>\n          {advancedOptions &&\n            <div>\n              <div style={{marginTop: '15px'}}>\n                <label className={styles.form_label}>Agent Workflow</label><br/>\n                <div className=\"dropdown_container_search\" style={{width: '100%'}}>\n                  <div className={`${\"custom_select_container\"} ${edit ? 'cursor_not_allowed' : ''}`} onClick={() => {setAgentDropdown(!edit ? !agentDropdown : false)}}\n                       style={{width: '100%'}}>\n                    {agentWorkflow}<Image width={20} height={21}\n                                      src={!agentDropdown ? '/images/dropdown_down.svg' : '/images/dropdown_up.svg'}\n                                      alt=\"expand-icon\"/>\n                  </div>\n                  <div>\n                    {agentDropdown && <div className=\"custom_select_options\" ref={agentRef} style={{width: '100%'}}>\n                      {agentWorkflows.map((agent, index) => (\n                        <div key={index} className=\"custom_select_option\" onClick={() => handleAgentSelect(index)}\n                             style={{padding: '12px 14px', maxWidth: '100%'}}>\n                          {agent}\n                        </div>))}\n                    </div>}\n                  </div>\n                </div>\n              </div>\n              <div style={{marginTop: '15px'}}>\n                <div style={{display: 'flex'}}>\n                  <input className=\"checkbox\" type=\"checkbox\" checked={addResources}\n                         onChange={() => setLocalStorageValue(\"has_resource_\" + String(internalId), !addResources, setAddResources)}/>\n                  <label className={styles.form_label} style={{marginLeft: '7px', cursor: 'pointer'}}\n                         onClick={() => setLocalStorageValue(\"has_resource_\" + String(internalId), !addResources, setAddResources)}>\n                    Add Resources\n                  </label>\n                </div>\n              </div>\n              <div style={{width: '100%', height: 'auto', marginTop: '10px'}}>\n                {addResources && <div style={{paddingBottom: '10px'}}>\n                  <div className={`file-drop-area ${isDragging ? 'dragging' : ''}`} onDragEnter={handleDragEnter}\n                       onDragLeave={handleDragLeave} onDragOver={handleDragOver} onDrop={handleDrop}\n                       onClick={handleDropAreaClick}>\n                    <div><p style={{textAlign: 'center', color: 'white', fontSize: '14px'}}>+ Choose or drop a file\n                      here</p>\n                      <p style={{textAlign: 'center', color: '#888888', fontSize: '12px'}}>Supported file formats are\n                        txt, pdf, docx, epub, csv, pptx only</p>\n                      <input type=\"file\" ref={fileInputRef} style={{display: 'none'}} onChange={handleFileInputChange}/>\n                    </div>\n                  </div>\n                  <div className={styles.agent_resources}>\n                    {input.map((file, index) => (\n                      <div key={index} className={styles.history_box}\n                           style={{background: '#272335', padding: '0px 10px', width: '100%', cursor: 'default'}}>\n                        <div style={{display: 'flex', alignItems: 'center', justifyContent: 'flex-start'}}>\n                          <div><Image width={28} height={46} src={returnResourceIcon(file)} alt=\"pdf-icon\"/></div>\n                          <div style={{marginLeft: '5px', width: '100%'}}>\n                            <div style={{fontSize: '11px'}} className={styles.single_line_block}>{file.name}</div>\n                            <div style={{\n                              color: '#888888',\n                              fontSize: '9px'\n                            }}>{file.type.split(\"/\")[1]}{file.size !== '' ? ` • ${formatBytes(file.size)}` : ''}</div>\n                          </div>\n                          <div style={{cursor: 'pointer'}} onClick={() => removeFile(index)}><Image width={20}\n                                                                                                    height={20}\n                                                                                                    src='/images/close.svg'\n                                                                                                    alt=\"close-icon\"/>\n                          </div>\n                        </div>\n                      </div>\n                    ))}\n                  </div>\n                </div>}\n              </div>\n              <div style={{marginTop: '15px'}}>\n                <div><label className={styles.form_label}>Constraints</label></div>\n                {constraints?.map((constraint, index) => (<div key={index} style={{\n                  marginBottom: '10px',\n                  display: 'flex',\n                  alignItems: 'center',\n                  justifyContent: 'space-between'\n                }}>\n                  <div style={{flex: '1'}}><input className=\"input_medium\" type=\"text\" value={constraint}\n                                                  onChange={(event) => handleConstraintChange(index, event.target.value)}/>\n                  </div>\n                  <div>\n                    <button className=\"secondary_button\" style={{marginLeft: '4px', padding: '5px'}}\n                            onClick={() => handleConstraintDelete(index)}>\n                      <Image width={20} height={21} src=\"/images/close.svg\" alt=\"close-icon\"/>\n                    </button>\n                  </div>\n                </div>))}\n                <div>\n                  <button className=\"secondary_button\" onClick={addConstraint}>+ Add</button>\n                </div>\n              </div>\n              <div style={{marginTop: '15px'}}>\n                <label className={styles.form_label}>Max iterations</label>\n                <div style={{display: 'flex', alignItems: 'center', justifyContent: 'space-between'}}>\n                  <input style={{width: '90%'}} type=\"range\" min={5} max={100} value={maxIterations}\n                         onChange={handleIterationChange}/>\n                  <input style={{width: '9%', order: '1', textAlign: 'center', paddingLeft: '0', paddingRight: '0'}}\n                         disabled={true} className=\"input_medium\" type=\"text\" value={maxIterations}/>\n                </div>\n              </div>\n              {/*<div style={{marginTop: '15px'}}>*/}\n              {/*  <label className={styles.form_label}>Exit criterion</label>*/}\n              {/*  <div className=\"dropdown_container_search\" style={{width:'100%'}}>*/}\n              {/*    <div className=\"custom_select_container\" onClick={() => setExitDropdown(!exitDropdown)} style={{width:'100%'}}>*/}\n              {/*      {exitCriterion}<Image width={20} height={21} src={!exitDropdown ? '/images/dropdown_down.svg' : '/images/dropdown_up.svg'} alt=\"expand-icon\"/>*/}\n              {/*    </div>*/}\n              {/*    <div>*/}\n              {/*      {exitDropdown && <div className=\"custom_select_options\" ref={exitRef} style={{width:'100%'}}>*/}\n              {/*        {exitCriteria.map((exit, index) => (<div key={index} className=\"custom_select_option\" onClick={() => handleExitSelect(index)} style={{padding:'12px 14px',maxWidth:'100%'}}>*/}\n              {/*          {exit}*/}\n              {/*        </div>))}*/}\n              {/*      </div>}*/}\n              {/*    </div>*/}\n              {/*  </div>*/}\n              {/*</div>*/}\n              {/*<div style={{marginTop: '15px'}}>*/}\n              {/*  <label className={styles.form_label}>Time between steps (in milliseconds)</label>*/}\n              {/*  <input className=\"input_medium\" type=\"number\" value={stepTime} onChange={handleStepChange}/>*/}\n              {/*</div>*/}\n              {/*<div style={{marginTop: '15px'}}>*/}\n              {/*  <div style={{display:'flex'}}>*/}\n              {/*    <input className=\"checkbox\" type=\"checkbox\" checked={longTermMemory} onChange={() => setLocalStorageValue(\"has_LTM_\" + String(internalId), !longTermMemory, setLongTermMemory)} />*/}\n              {/*    <label className={styles.form_label} style={{marginLeft:'7px',cursor:'pointer'}} onClick={() => setLocalStorageValue(\"has_LTM_\" + String(internalId), !longTermMemory, setLongTermMemory)}>*/}\n              {/*      Long term memory*/}\n              {/*    </label>*/}\n              {/*  </div>*/}\n              {/*</div>*/}\n              {/*{longTermMemory === true && <div style={{marginTop: '10px'}}>*/}\n              {/*  <label className={styles.form_label}>Choose an LTM database</label>*/}\n              {/*  <div className=\"dropdown_container_search\" style={{width:'100%'}}>*/}\n              {/*    <div className=\"custom_select_container\" onClick={() => setDatabaseDropdown(!databaseDropdown)} style={{width:'100%'}}>*/}\n              {/*      {database}<Image width={20} height={21} src={!databaseDropdown ? '/images/dropdown_down.svg' : '/images/dropdown_up.svg'} alt=\"expand-icon\"/>*/}\n              {/*    </div>*/}\n              {/*    <div>*/}\n              {/*      {databaseDropdown && <div className=\"custom_select_options\" ref={databaseRef} style={{width:'100%'}}>*/}\n              {/*        {databases.map((data, index) => (<div key={index} className=\"custom_select_option\" onClick={() => handleDatabaseSelect(index)} style={{padding:'12px 14px',maxWidth:'100%'}}>*/}\n              {/*          {data}*/}\n              {/*        </div>))}*/}\n              {/*      </div>}*/}\n              {/*    </div>*/}\n              {/*  </div>*/}\n              {/*</div>}*/}\n              <div style={{marginTop: '15px'}}>\n                <label className={styles.form_label}>Permission Type</label>\n                <div className=\"dropdown_container_search\" style={{width: '100%'}}>\n                  <div className=\"custom_select_container\" onClick={() => setPermissionDropdown(!permissionDropdown)}\n                       style={{width: '100%'}}>\n                    {permission}<Image width={20} height={21}\n                                       src={!permissionDropdown ? '/images/dropdown_down.svg' : '/images/dropdown_up.svg'}\n                                       alt=\"expand-icon\"/>\n                  </div>\n                  <div className=\"mb_34\">\n                    {permissionDropdown &&\n                      <div className=\"custom_select_options mb_30\" ref={permissionRef} style={{width: '100%'}}>\n                        {permissions.map((permit, index) => (<div key={index} className=\"custom_select_option padding_12_14 mxw_100\"\n                                                                  onClick={() => handlePermissionSelect(index)}  style={checkPermissionValidity(permit) ? {color: '#888888', textDecoration: 'line-through',pointerEvents: 'none'} : {}}>\n                          {permit}\n                        </div>))}\n                      </div>}\n                  </div>\n                </div>\n              </div>\n            </div>\n          }\n\n          <div style={{marginTop: '10px', display: 'flex', justifyContent: 'flex-end'}}>\n            <div className=\"display_flex_container position_relative mr_7\">\n              <div>\n                {dropdown && (<div className={styles.dropdown_container_agent} onMouseOver={() => setDropdown(true)} onMouseOut={() => setDropdown(false)}>\n                  <ul className=\"padding_0 margin_0\">\n                    <li className={`${styles.dropdown_item_agent} ${\"dropdown_item\"}`} onClick={() => updateTemplate()}>Update template</li>\n                    {env === 'PROD' && <li className={`${styles.dropdown_item_agent} ${\"dropdown_item\"}`} onClick={() => handleAddToMarketplace()}>Publish to Marketplace</li>}\n                </ul>\n                </div>)}\n              </div>\n              {showButton && <div>\n                  <button className=\"secondary_button padding_8\" onClick={() => setDropdown(true)}>\n                    <Image width={20} height={20} src=\"/images/three_dots.svg\" alt=\"run-icon\"/>\n                  </button>\n                </div>}\n              </div>\n            <button style={{marginRight: '7px'}} className=\"secondary_button\"\n                    onClick={() => removeTab(-1, \"new agent\", \"Create_Agent\", internalId)}>Cancel\n            </button>\n            {!edit ? <div style={{display: 'flex', position: 'relative'}}>\n              {createDropdown && (<div className=\"create_agent_dropdown_options\" onClick={() => {\n                setCreateModal(true);\n                setCreateDropdown(false);\n              }}>Create & Schedule Run\n              </div>)}\n              <div className=\"primary_button\"\n                   style={{backgroundColor: 'white', marginBottom: '4px', paddingLeft: '0', paddingRight: '5px'}}>\n                <button disabled={!createClickable} className=\"primary_button\" style={{paddingRight: '5px'}}\n                        onClick={() => {handleAddAgent();}}>{createClickable ? 'Create and Run' : 'Creating Agent...'}</button>\n                <button onClick={() => setCreateDropdown(!createDropdown)}\n                        style={{border: 'none', backgroundColor: 'white'}}>\n                  <Image width={20} height={21}\n                         src={!createDropdown ? '/images/dropdown_down.svg' : '/images/dropdown_up.svg'}\n                         alt=\"expand-icon\"/>\n                </button>\n              </div>\n            </div>: <div className=\"primary_button\" style={{backgroundColor: 'white', marginBottom: '4px', paddingLeft: '0', paddingRight: '5px'}}>\n              <button className=\"primary_button\" style={{paddingRight: '5px'}}\n                      onClick={() => setEditModal(true)}>Update changes</button> </div>}\n          </div>\n\n          {createModal && (\n            <AgentSchedule env={env} internalId={internalId} closeCreateModal={closeCreateModal} type=\"create_agent\"/>\n          )}\n\n          {editModal && (<div className=\"modal\" onClick={() => setEditModal(!editModal)}>\n            <div className=\"modal-content w_35\" onClick={preventDefault}>\n              <div className={styles.detail_name}>Update agent</div>\n              <div><label className={styles.form_label}>All the new runs of this agent will be updated with the latest changes. Are you sure you want to update changes?</label></div>\n              <div className=\"mt_20 justify_end display_flex\">\n                <button className=\"secondary_button mr_10\" onClick={() => setEditModal(false)}>\n                  Cancel\n                </button>\n                <button className={`${styles.run_button} h_32p padding_0_15 `} onClick={handleAddAgent}>\n                  Update changes\n                </button>\n              </div>\n            </div>\n          </div>)}\n\n          {publishModal && <div className=\"modal\" onClick={() => {setPublishModal(false)}}>\n            <div className=\"modal-content w_35\" onClick={preventDefault}>\n              <div className={styles.detail_name}>Template submitted successfully!</div>\n              <div>\n                <label className={styles.form_label}>Your template is under review. Please check the marketplace in 2-3 days. If your template is not visible on the marketplace, reach out to us on Discord&nbsp;\n                  <a href=\"https://discord.com/channels/1107593006032355359/1143813784683692093\" target=\"_blank\" rel=\"noopener noreferrer\">\n                    #agent-templates-submission\n                  </a> channel.</label>\n              </div>\n              <div className={styles.modal_buttons}>\n                <button className=\"primary_button\" onClick={() => {setPublishModal(false)}}>\n                  Okay\n                </button>\n              </div>\n            </div>\n          </div>}\n\n        </div>\n      </div>\n      <div className=\"col-3\"></div>\n    </div>\n    <ToastContainer/>\n  </>)\n}"
  },
  {
    "path": "gui/pages/Content/Agents/AgentSchedule.js",
    "content": "import React, {useState, useEffect, useRef} from 'react';\nimport {setLocalStorageValue, convertToGMT, preventDefault, getUserClick} from \"@/utils/utils\";\nimport styles from \"@/pages/Content/Agents/Agents.module.css\";\nimport styles1 from \"@/pages/Content/Agents/react-datetime.css\";\nimport Image from \"next/image\";\nimport Datetime from \"react-datetime\";\nimport {toast} from \"react-toastify\";\nimport {agentScheduleComponent, createAndScheduleRun, updateSchedule} from \"@/pages/api/DashboardService\";\nimport {EventBus} from \"@/utils/eventBus\";\nimport moment from 'moment';\n\nexport default function AgentSchedule({\n                                        internalId,\n                                        closeCreateModal,\n                                        type,\n                                        agentId,\n                                        setCreateModal,\n                                        setCreateEditModal,\n                                        env,\n                                      }) {\n  const [isRecurring, setIsRecurring] = useState(false);\n  const [timeDropdown, setTimeDropdown] = useState(false);\n  const [expiryDropdown, setExpiryDropdown] = useState(false);\n\n  const [startTime, setStartTime] = useState('');\n\n  const timeUnitArray = (env === 'PROD') ? ['Days', 'Hours'] : ['Days', 'Hours', 'Minutes'];\n  const [timeUnit, setTimeUnit] = useState(timeUnitArray[1]);\n  const [timeValue, setTimeValue] = useState(null);\n\n  const expiryTypeArray = ['Specific Date', 'After certain number of runs', 'No expiry'];\n  const [expiryType, setExpiryType] = useState(expiryTypeArray[1]);\n  const [expiryRuns, setExpiryRuns] = useState(0);\n  const [expiryDate, setExpiryDate] = useState(null);\n\n  const timeRef = useRef(null);\n  const expiryRef = useRef(null);\n\n  const [modalHeading, setModalHeading] = useState('Schedule Run')\n  const [modalButton, setModalButton] = useState('Create and Schedule Run')\n  const [localStartTime, setLocalStartTime] = useState('')\n\n  useEffect(() => {\n    function handleClickOutside(event) {\n      if (timeRef.current && !timeRef.current.contains(event.target)) {\n        setTimeDropdown(false)\n      }\n\n      if (expiryRef.current && !expiryRef.current.contains(event.target)) {\n        setExpiryDropdown(false);\n      }\n    }\n\n    document.addEventListener('mousedown', handleClickOutside);\n    return () => {\n      document.removeEventListener('mousedown', handleClickOutside);\n    };\n  }, []);\n\n  useEffect(() => {\n    if (type === \"edit_schedule_agent\") {\n      setModalHeading('Edit Schedule')\n      setModalButton(\"Update Schedule\")\n      fetchAgentScheduleComponent();\n    }\n  }, []);\n\n  useEffect(() => {\n    if (internalId !== null) {\n      const agent_is_recurring = localStorage.getItem(\"agent_is_recurring_\" + String(internalId));\n      if (agent_is_recurring) {\n        setIsRecurring(JSON.parse(agent_is_recurring));\n      }\n\n      const agent_time_unit = localStorage.getItem(\"agent_time_unit_\" + String(internalId));\n      if (agent_time_unit) {\n        setTimeUnit(agent_time_unit);\n      }\n\n      const agent_time_value = localStorage.getItem(\"agent_time_value_\" + String(internalId));\n      if (agent_time_value) {\n        setTimeValue(Number(agent_time_value));\n      }\n\n      const agent_expiry_type = localStorage.getItem(\"agent_expiry_type_\" + String(internalId));\n      if (agent_expiry_type) {\n        setExpiryType(agent_expiry_type);\n      }\n\n      const agent_expiry_runs = localStorage.getItem(\"agent_expiry_runs_\" + String(internalId));\n      if (agent_expiry_runs) {\n        setExpiryRuns(Number(agent_expiry_runs));\n      }\n\n      const agent_start_time = localStorage.getItem(\"agent_start_time_\" + String(internalId));\n      if (agent_start_time) {\n        setStartTime(agent_start_time);\n      }\n\n      const agent_expiry_date = localStorage.getItem(\"agent_expiry_date_\" + String(internalId));\n      if (agent_expiry_date) {\n        setExpiryDate(agent_expiry_date);\n      }\n    }\n  }, [internalId])\n\n  const handleDateTimeChange = (momentObj) => {\n    const expiryDate = convertToGMT(momentObj);\n    setLocalStorageValue(\"agent_expiry_date_\" + String(internalId), expiryDate, setExpiryDate);\n  };\n\n  const handleTimeChange = (momentObj) => {\n    const startTime = convertToGMT(momentObj);\n    setLocalStartTime(typeof momentObj === 'string' ? '' : momentObj.toDate())\n    setLocalStorageValue(\"agent_start_time_\" + String(internalId), startTime, setStartTime);\n  };\n\n  const toggleRecurring = () => {\n    setLocalStorageValue(\"agent_is_recurring_\" + String(internalId), !isRecurring, setIsRecurring);\n  };\n\n  const handleTimeSelect = (index) => {\n    setLocalStorageValue(\"agent_time_unit_\" + String(internalId), timeUnitArray[index], setTimeUnit);\n    setTimeDropdown(false);\n  }\n\n  const handleExpirySelect = (index) => {\n    setLocalStorageValue(\"agent_expiry_type_\" + String(internalId), expiryTypeArray[index], setExpiryType);\n    setExpiryDropdown(false);\n  }\n\n  const handleDateChange = (event) => {\n    setLocalStorageValue(\"agent_time_value_\" + String(internalId), event.target.value, setTimeValue);\n  };\n\n  const handleExpiryRuns = (event) => {\n    setLocalStorageValue(\"agent_expiry_runs_\" + String(internalId), event.target.value, setExpiryRuns);\n  };\n\n  const addScheduledAgent = () => {\n    if ((startTime === '' || (isRecurring === true && (timeValue == null || (expiryType === \"After certain number of runs\" && (parseInt(expiryRuns, 10) < 1)) || (expiryType === \"Specific date\" && expiryDate == null))))) {\n      toast.error('Please input correct details', {autoClose: 1800});\n      return;\n    }\n\n    if (type === \"create_agent\") {\n      const scheduleData = {\n        \"start_time\": startTime,\n        \"recurrence_interval\": timeValue ? `${timeValue} ${timeUnit}` : null,\n        \"expiry_runs\": expiryType === 'After certain number of runs' ? parseInt(expiryRuns) : -1,\n        \"expiry_date\": expiryType === 'Specific Date' ? expiryDate : null,\n      }\n      EventBus.emit('handleAgentScheduling', scheduleData);\n      getUserClick('Agent Scheduled', {'Type': 'New Agent'})\n    } else {\n      if (type === \"schedule_agent\") {\n        const requestData = {\n          \"agent_id\": agentId,\n          \"start_time\": startTime,\n          \"recurrence_interval\": timeValue && isRecurring ? `${timeValue} ${timeUnit}` : null,\n          \"expiry_runs\": expiryType === 'After certain number of runs' && isRecurring ? parseInt(expiryRuns) : -1,\n          \"expiry_date\": expiryType === 'Specific Date' && isRecurring ? expiryDate : null,\n        };\n\n        createAndScheduleRun(requestData)\n          .then(response => {\n            const {schedule_id} = response.data;\n            toast.success('Scheduled successfully!', {autoClose: 1800});\n            setCreateModal();\n            getUserClick('Agent Scheduled', {'Type': 'Existing Agent'})\n            EventBus.emit('reFetchAgents', {});\n            setTimeout(() => {\n                EventBus.emit('refreshDate', {});\n            }, 1000)\n          })\n          .catch(error => {\n            console.error('Error:', error);\n          });\n      } else {\n        if (type === \"edit_schedule_agent\") {\n          fetchUpdateSchedule();\n        }\n      }\n    }\n  };\n\n  function checkTime() {\n    if (expiryDate === null) {\n      return true;\n    }\n    let date1 = expiryDate;\n    if (typeof expiryDate === 'string' && expiryDate.includes('/')) {\n      date1 = moment(expiryDate, 'DD/MM/YYYY').toDate();\n    } else if (typeof expiryDate === 'string') {\n      date1 = moment.utc(expiryDate, 'YYYY-MM-DD HH:mm:ss').local().toDate();\n    } else\n      return\n    let date2 = moment.utc(startTime, 'YYYY-MM-DD HH:mm:ss').local().toDate();\n\n    date1.setHours(0, 0, 0, 0);\n    date2.setHours(0, 0, 0, 0);\n\n    date1 = convertToGMT(date1);\n    date2 = convertToGMT(date2);\n\n    return date1 <= date2;\n  }\n\n  function fetchUpdateSchedule() {\n    if (expiryType === 'Specific Date' && checkTime()) {\n      toast.error('Expiry Date of agent is before Start Date')\n      return;\n    }\n    const requestData = {\n      \"agent_id\": agentId,\n      \"start_time\": startTime,\n      \"recurrence_interval\": timeValue && isRecurring ? `${timeValue} ${timeUnit}` : null,\n      \"expiry_runs\": expiryType === 'After certain number of runs' && isRecurring ? parseInt(expiryRuns) : -1,\n      \"expiry_date\": expiryType === 'Specific Date' && isRecurring ? (expiryDate && expiryDate.includes('/') ? convertToGMT(moment(expiryDate, 'DD/MM/YYYY').toDate()) : expiryDate) : null,\n    };\n\n    updateSchedule(requestData)\n      .then((response) => {\n        if (response.status === 200) {\n          toast.success('Schedule updated successfully', {autoClose: 1800});\n          EventBus.emit('refreshDate', {});\n          setCreateEditModal();\n          EventBus.emit('reFetchAgents', {});\n        } else {\n          toast.error('Error updating agent schedule', {autoClose: 1800});\n        }\n      })\n      .catch((error) => {\n        console.error('Error updating agent schedule:', error);\n      });\n  }\n\n  function fetchAgentScheduleComponent() {\n    agentScheduleComponent(agentId)\n      .then((response) => {\n        const {current_datetime, recurrence_interval, expiry_date, expiry_runs, start_date, start_time} = response.data;\n        setExpiryRuns(expiry_runs);\n        setExpiryDate(expiry_date);\n        if ((expiry_date || expiry_runs !== -1) && recurrence_interval !== null) {\n          setTimeValue(parseInt(recurrence_interval.substring(0, 1), 10))\n          setTimeUnit(recurrence_interval.substring(2,))\n          setIsRecurring(true);\n          setExpiryType(expiry_date ? 'Specific Date' : 'After certain number of runs');\n        } else {\n          setExpiryType('No expiry');\n        }\n      })\n      .catch((error) => {\n        console.error('Error fetching agent data:', error);\n      });\n  }\n\n  return (\n    <div>\n      <div className=\"modal\" onClick={closeCreateModal}>\n        <div className=\"modal-content\" style={{width: '35%'}} onClick={preventDefault}>\n          <div className={styles.detail_name}>{modalHeading}</div>\n          <div>\n            <label className={styles.form_label}>Select a date and time</label>\n            <div>\n              <Datetime className={`${styles1.className} ${styles.rdtPicker}`} onChange={handleTimeChange}\n                        inputProps={{placeholder: new Date()}}\n                        isValidDate={current => current.isAfter(Datetime.moment().subtract(1, 'day'))}/>\n            </div>\n          </div>\n          <div style={{display: 'flex', marginTop: '20px'}}>\n            <input className=\"checkbox\" type=\"checkbox\" checked={isRecurring} onChange={toggleRecurring}/>\n            <label className={styles.form_label} style={{marginLeft: '7px', cursor: 'pointer'}}\n                   onClick={toggleRecurring}>\n              Recurring run\n            </label>\n          </div>\n          {isRecurring && (<div style={{marginTop: '20px'}}>\n            <div style={{color: \"white\", marginBottom: '10px'}}>Recurring run details</div>\n            <label className={styles.form_label}>Repeat every</label>\n            <div style={{display: 'flex', marginBottom: '20px'}}>\n              <div style={{width: '70%', marginRight: '5px'}}>\n                <input className=\"input_medium\" type=\"number\" value={timeValue} onChange={handleDateChange}\n                       placeholder='Enter here'/>\n              </div>\n              <div style={{width: '30%'}}>\n                <div className=\"custom_select_container\" onClick={() => setTimeDropdown(!timeDropdown)}\n                     style={{width: '100%'}}>\n                  {timeUnit}<Image width={20} height={21}\n                                   src={!timeDropdown ? '/images/dropdown_down.svg' : '/images/dropdown_up.svg'}\n                                   alt=\"expand-icon\"/>\n                </div>\n                <div>\n                  {timeDropdown && <div className=\"custom_select_options\" ref={timeRef} style={{width: '137px'}}>\n                    {timeUnitArray.map((timeUnit, index) => (\n                      <div key={index} className=\"custom_select_option\" onClick={() => handleTimeSelect(index)}\n                           style={{padding: '12px 14px', maxWidth: '100%'}}>\n                        {timeUnit}\n                      </div>))}\n                  </div>}\n                </div>\n              </div>\n            </div>\n            <label className={styles.form_label}>Recurring expiry</label>\n            <div>\n              <div style={{display: 'inline'}}>\n                <div style={{width: '100%', marginRight: '5px'}}>\n                  <div className=\"custom_select_container\" onClick={() => setExpiryDropdown(!expiryDropdown)}\n                       style={{width: '100%'}}>\n                    {expiryType}<Image width={20} height={21}\n                                       src={!expiryDropdown ? '/images/dropdown_down.svg' : '/images/dropdown_up.svg'}\n                                       alt=\"expand-icon\"/>\n                  </div>\n                  <div>\n                    {expiryDropdown && <div className=\"custom_select_options\" ref={expiryRef}>\n                      {expiryTypeArray.map((expiryType, index) => (\n                        <div key={index} className=\"custom_select_option\" onClick={() => handleExpirySelect(index)}\n                             style={{padding: '12px 14px', maxWidth: '100%'}}>\n                          {expiryType}\n                        </div>))}\n                    </div>}\n                  </div>\n                </div>\n                {expiryType === 'After certain number of runs' && (\n                  <div style={{width: '100%', marginTop: '10px'}}>\n                    <input className=\"input_medium\" type=\"number\" value={expiryRuns} onChange={handleExpiryRuns}\n                           placeholder=\"Enter the number of runs\"/>\n                  </div>\n                )}\n                {expiryType === 'Specific Date' && (\n                  <div style={{width: '100%', marginTop: '10px'}}>\n                    {type !== \"edit_schedule_agent\" &&\n                      <Datetime timeFormat={false} className={`${styles1.className} ${styles.rdtPicker}`}\n                                onChange={handleDateTimeChange} inputProps={{placeholder: new Date()}}\n                                isValidDate={current => current.isAfter(moment(localStartTime))}/>}\n                    {type === \"edit_schedule_agent\" && expiryDate && <div className={styles.form_label} style={{\n                      display: 'flex',\n                      fontSize: '14px',\n                      justifyContent: 'space-between'\n                    }}>\n                      <div>The expiry date of the run\n                        is {(new Date(`${expiryDate}Z`).toLocaleString()).substring(0, 10) == \"Invalid Da\" ? expiryDate : (new Date(`${expiryDate}Z`).toLocaleString()).substring(0, 10)}</div>\n                      <div className=\"secondary_button\" style={{cursor: 'pointer', height: '20px', fontSize: '12px'}}\n                           onClick={() => setExpiryDate(null)}>Edit\n                      </div>\n                    </div>}\n                    {type === \"edit_schedule_agent\" && !expiryDate &&\n                      <Datetime timeFormat={false} className={`${styles1.className} ${styles.rdtPicker}`}\n                                onChange={handleDateTimeChange} inputProps={{placeholder: new Date()}}\n                                isValidDate={current => current.isAfter(moment(localStartTime))}/>}\n                  </div>\n                )}\n              </div>\n            </div>\n          </div>)}\n          <div style={{display: 'flex', justifyContent: 'flex-end', marginTop: '20px'}}>\n            <button className=\"secondary_button\" style={{marginRight: '10px'}} onClick={closeCreateModal}>\n              Cancel\n            </button>\n            <button className={styles.run_button} style={{paddingLeft: '15px', paddingRight: '15px', height: '32px'}}\n                    onClick={addScheduledAgent}>\n              {modalButton}\n            </button>\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n};"
  },
  {
    "path": "gui/pages/Content/Agents/AgentTemplatesList.js",
    "content": "import React, {useEffect, useState} from \"react\";\nimport Image from \"next/image\";\nimport styles from '../Marketplace/Market.module.css';\nimport {fetchAgentTemplateListLocal} from \"@/pages/api/DashboardService\";\nimport AgentCreate from \"@/pages/Content/Agents/AgentCreate\";\nimport {setLocalStorageValue, openNewTab, getUserClick} from \"@/utils/utils\";\n\nexport default function AgentTemplatesList({\n                                             sendAgentData,\n                                             knowledge,\n                                             selectedProjectId,\n                                             fetchAgents,\n                                             toolkits,\n                                             organisationId,\n                                             internalId,\n                                             sendKnowledgeData,\n                                             env\n                                           }) {\n  const [agentTemplates, setAgentTemplates] = useState([])\n  const [createAgentClicked, setCreateAgentClicked] = useState(false)\n  const [sendTemplate, setSendTemplate] = useState(null)\n\n  useEffect(() => {\n    fetchAgentTemplateListLocal()\n      .then((response) => {\n        const data = response.data || [];\n        setAgentTemplates(data);\n      })\n      .catch((error) => {\n        console.error('Error fetching agent templates:', error);\n      });\n  }, [])\n\n  useEffect(() => {\n    if (internalId !== null) {\n      const agent_create_click = localStorage.getItem(\"agent_create_click_\" + String(internalId)) || 'false';\n      if (agent_create_click) {\n        setCreateAgentClicked(JSON.parse(agent_create_click));\n      }\n    }\n  }, [internalId])\n\n  function redirectToCreateAgent() {\n    getUserClick('Agent Creating From Scratch', {})\n    setLocalStorageValue(\"agent_create_click_\" + String(internalId), true, setCreateAgentClicked);\n  }\n\n  function openMarketplace() {\n    getUserClick('Going To Marketplace to see Agent Templates', {})\n    openNewTab(-4, \"Marketplace\", \"Marketplace\", false);\n    localStorage.setItem('marketplace_tab', 'market_agents');\n  }\n\n  function handleTemplateClick(item) {\n    getUserClick('Agent Creating Using Template', {'Template Name': item.name})\n    setSendTemplate(item);\n    setLocalStorageValue(\"agent_create_click_\" + String(internalId), true, setCreateAgentClicked);\n  }\n\n  return (\n    <div>\n      {!createAgentClicked ?\n        <div>\n          <div className='row' style={{marginTop: '10px'}}>\n            <div className='col-12'>\n                        <span className={styles.description_heading}\n                              style={{\n                                fontWeight: '400',\n                                verticalAlign: 'text-top',\n                                marginLeft: '10px',\n                                fontSize: '16px'\n                              }}>Choose a template</span>\n              <button className=\"primary_button\" onClick={redirectToCreateAgent}\n                      style={{float: 'right', marginRight: '3px'}}>&nbsp;Build From Scratch\n              </button>\n            </div>\n          </div>\n          <div className={styles.rowContainer}\n               style={{maxHeight: '78vh', overflowY: 'auto', marginTop: '10px', marginLeft: '3px'}}>\n            {agentTemplates.length > 0 ? <div className=\"marketplaceGrid3\">\n              {agentTemplates.map((item) => (\n                <div className=\"market_containers cursor_pointer\" key={item.id} style={{cursor: 'pointer', height: '85px'}}\n                     onClick={() => handleTemplateClick(item)}>\n                  <div style={{display: 'inline', overflow: 'auto'}}>\n                    <div>{item.name}</div>\n                    <div className={styles.tool_description}>{item.description}</div>\n                  </div>\n                </div>\n              ))}\n              <div className=\"market_containers cursor_pointer\" style={{cursor: 'pointer', height: '85px', background: '#413C4F'}}\n                   onClick={openMarketplace}>\n                <div style={{display: 'inline', overflow: 'auto'}}>\n                  <div style={{display: 'flex', justifyContent: 'space-between', gap: '0.3vw'}}>\n                    <div style={{order: '0'}}><Image style={{marginTop: '-3px'}} width={16} height={16}\n                                                     src=\"/images/marketplace.svg\"\n                                                     alt=\"arrow-outward\"/>&nbsp;&nbsp;Browse templates from marketplace\n                    </div>\n                    <div style={{order: '1'}}><Image style={{marginTop: '-3px'}} width={16} height={16}\n                                                     src=\"/images/arrow_outward.svg\" alt=\"arrow-outward\"/></div>\n                  </div>\n                  <div className={styles.tool_description}>\n                    SuperAGI marketplace offers a large selection of templates to choose from, so you are sure to find\n                    one that is right for you!\n                  </div>\n                </div>\n              </div>\n            </div> : <div className={styles.empty_templates}>\n              <div style={{textAlign: 'center'}}>\n                <Image width={100} height={100} src=\"/images/marketplace_empty.svg\" alt=\"empty-templates\"/>\n                <div style={{textAlign: 'center', color: 'white', marginTop: '15px', fontSize: '15px'}}>Browse templates\n                  from marketplace\n                </div>\n                <div style={{marginTop: '15px', display: 'flex', justifyContent: 'center', alignItems: 'center'}}>\n                  <button className=\"primary_button\" onClick={openMarketplace}>Go to marketplace</button>\n                </div>\n              </div>\n            </div>}\n          </div>\n        </div> : <AgentCreate sendKnowledgeData={sendKnowledgeData} knowledge={knowledge} internalId={internalId}\n                              organisationId={organisationId} sendAgentData={sendAgentData}\n                              selectedProjectId={selectedProjectId} fetchAgents={fetchAgents} toolkits={toolkits}\n                              template={sendTemplate} env={env}/>}\n    </div>\n  )\n};\n"
  },
  {
    "path": "gui/pages/Content/Agents/AgentWorkspace.js",
    "content": "import React, {useEffect, useState, useMemo} from 'react';\nimport Image from 'next/image';\nimport {ToastContainer, toast} from 'react-toastify';\nimport 'react-toastify/dist/ReactToastify.css';\nimport styles from './Agents.module.css';\nimport ActivityFeed from './ActivityFeed';\nimport TaskQueue from './TaskQueue';\nimport RunHistory from \"./RunHistory\";\nimport ActionConsole from \"./ActionConsole\";\nimport Details from \"./Details\";\nimport ResourceManager from \"./ResourceManager\";\nimport {createInternalId, getUserClick, preventDefault} from \"@/utils/utils\";\nimport {\n  getAgentDetails,\n  getAgentExecutions,\n  updateExecution,\n  addExecution,\n  getExecutionDetails,\n  saveAgentAsTemplate,\n  stopSchedule,\n  getDateTime,\n  deleteAgent, publishToMarketplace\n} from \"@/pages/api/DashboardService\";\nimport {EventBus} from \"@/utils/eventBus\";\nimport 'moment-timezone';\nimport AgentSchedule from \"@/pages/Content/Agents/AgentSchedule\";\n\nexport default function AgentWorkspace({env, agentId, agentName, selectedView, agents, internalId, sendAgentData}) {\n  const [leftPanel, setLeftPanel] = useState('activity_feed')\n  const [rightPanel, setRightPanel] = useState('details')\n  const [history, setHistory] = useState(true)\n  const [selectedRun, setSelectedRun] = useState(null)\n  const [runModal, setRunModal] = useState(false)\n  const [deleteModal, setDeleteModal] = useState(false)\n  const [goals, setGoals] = useState(null)\n  const [currentGoals, setCurrentGoals] = useState(null)\n  const [runName, setRunName] = useState(\"New Run\")\n  const [agentDetails, setAgentDetails] = useState(null)\n  const [agentExecutions, setAgentExecutions] = useState(null)\n  const [dropdown, setDropdown] = useState(false);\n  const [fetchedData, setFetchedData] = useState(null);\n  const [instructions, setInstructions] = useState(['']);\n  const [currentInstructions, setCurrentInstructions] = useState(['']);\n  const [pendingPermission, setPendingPermissions] = useState(0);\n\n  const agent = agents.find(agent => agent.id === agentId);\n\n  const [createModal, setCreateModal] = useState(false);\n  const [createEditModal, setCreateEditModal] = useState(false);\n  const [createStopModal, setCreateStopModal] = useState(false);\n  const [agentScheduleDetails, setAgentScheduleDetails] = useState(null)\n\n  const [publishModal, setPublishModal] = useState(false);\n  const [publishModalState, setPublishModalState] = useState(false);\n\n  const closeCreateModal = () => {\n    setCreateModal(false);\n    setCreateEditModal(false);\n    setCreateStopModal(false);\n  };\n\n  const handleEditScheduleClick = () => {\n    setCreateEditModal(true);\n    setDropdown(false);\n  };\n\n  const handlePublishToMarketplace =() => {\n    if(agent?.is_scheduled && agentExecutions?.length < 1){\n      setDropdown(false)\n      setPublishModalState(true)\n      setPublishModal(true)\n      return;\n    }\n    publishToMarketplace(selectedRun?.id)\n      .then((response) => {\n        setDropdown(false)\n        setPublishModalState(false)\n        setPublishModal(true)\n    })\n      .catch((error) => {\n        console.error('Error publishing to marketplace:', error);\n      });\n  };\n\n  const handleStopScheduleClick = () => {\n    setCreateStopModal(true);\n    setCreateModal(false);\n    setDropdown(false);\n  };\n\n  function fetchStopSchedule() {//Stop Schedule\n    stopSchedule(agentId)\n      .then((response) => {\n        if (response.status === 200) {\n          toast.success('Schedule stopped successfully!', {autoClose: 1800});\n          setCreateStopModal(false);\n          EventBus.emit('reFetchAgents', {});\n          setAgentScheduleDetails(null)\n        }\n      })\n      .catch((error) => {\n        console.error('Error stopping agent schedule:', error);\n      });\n  };\n\n  const pendingPermissions = useMemo(() => {\n    if (!fetchedData) return 0;\n    setPendingPermissions(fetchedData.filter(permission => permission.status === \"PENDING\").length);\n  }, [fetchedData]);\n\n  const addInstruction = () => {\n    setInstructions((prevArray) => [...prevArray, 'new instructions']);\n  };\n\n  const handleInstructionDelete = (index) => {\n    const updatedInstructions = [...instructions];\n    updatedInstructions.splice(index, 1);\n    setInstructions(updatedInstructions);\n  };\n\n  const handleInstructionChange = (index, newValue) => {\n    const updatedInstructions = [...instructions];\n    updatedInstructions[index] = newValue;\n    setInstructions(updatedInstructions);\n  };\n\n  const addGoal = () => {\n    setGoals((prevArray) => [...prevArray, 'new goal']);\n  };\n\n  const handleGoalChange = (index, newValue) => {\n    const updatedGoals = [...goals];\n    updatedGoals[index] = newValue;\n    setGoals(updatedGoals);\n  };\n\n  const handleGoalDelete = (index) => {\n    const updatedGoals = [...goals];\n    updatedGoals.splice(index, 1);\n    setGoals(updatedGoals);\n  };\n\n  const handleRunNameChange = (event) => {\n    setRunName(event.target.value);\n  }\n\n  const handleCreateRun = () => {\n    if (runName.replace(/\\s/g, '') === '') {\n      toast.error(\"Run name can't be blank\", {autoClose: 1800});\n      return\n    }\n    setGoals(goals.length< 0 ? agentDetails.goal : goals)\n    setInstructions(instructions.length < 0 ? agentDetails.instruction : instructions)\n\n    if (goals.length <= 0) {\n      toast.error(\"Agent needs to have goals\", {autoClose: 1800});\n      return\n    }\n\n    const executionData = {\n      \"agent_id\": agentId,\n      \"name\": runName,\n      \"goal\": goals,\n      \"instruction\": instructions\n    }\n\n    addExecution(executionData)\n      .then((response) => {\n        setRunModal(false);\n        fetchExecutions(agentId, response.data);\n        fetchAgentDetails(agentId, selectedRun?.id);\n        EventBus.emit('reFetchAgents', {});\n        toast.success(\"New run created\", {autoClose: 1800});\n        getUserClick('Agent New Run Created Successfully',{'IsReRun' : true})\n      })\n      .catch((error) => {\n        console.error('Error creating execution:', error);\n        toast.error(\"Could not create run\", {autoClose: 1800});\n      });\n  };\n\n  const handleDeleteAgent = () => {\n    deleteAgent(agentId)\n      .then((response) => {\n        setDeleteModal(false);\n        if (response.status === 200) {\n          EventBus.emit('reFetchAgents', {});\n          EventBus.emit('removeTab', {\n            element: {\n              id: agentId,\n              name: agentName,\n              contentType: \"Agents\",\n              internalId: internalId\n            }\n          })\n          toast.success(\"Agent Deleted Successfully\", {autoClose: 1800});\n        } else {\n          toast.error(\"Agent Could not be Deleted\", {autoClose: 1800});\n        }\n      })\n      .catch((error) => {\n        setDeleteModal(false);\n        toast.error(\"Agent Could not be Deleted\", {autoClose: 1800});\n        console.error(\"Agent could not be deleted: \", error);\n      });\n  }\n  const closeRunModal = () => {\n    setRunName(\"New Run\");\n    setRunModal(false);\n  };\n\n  const closeDeleteModal = () => {\n    setDeleteModal(false);\n  }\n\n  const updateRunStatus = (status) => {\n    const executionData = {\"status\": status};\n\n    updateExecution(selectedRun.id, executionData)\n      .then((response) => {\n        EventBus.emit('updateRunStatus', {selectedRunId: selectedRun.id, status: status});\n        if (status !== 'TERMINATED') {\n          fetchExecutions(agentId, response.data);\n        } else {\n          fetchExecutions(agentId);\n        }\n        EventBus.emit('reFetchAgents', {});\n      })\n      .catch((error) => {\n        console.error('Error updating execution:', error);\n      });\n\n    setDropdown(false);\n  };\n\n  useEffect(() => {\n    fetchAgentDetails(agentId, selectedRun?.id);\n    fetchExecutions(agentId);\n    fetchAgentScheduleComponent()\n  }, [agentId])\n\n  useEffect(() => {\n    // fetchExecutionDetails(selectedRun?.id);\n    fetchAgentDetails(agentId, selectedRun?.id);\n  }, [selectedRun?.id])\n\n  useEffect(() => {\n    if (agentDetails) {\n      setRightPanel(agentDetails.permission_type === 'RESTRICTED' ? 'action_console' : 'details');\n    }\n  }, [agentDetails])\n\n  function setNewRunDetails() {\n    getAgentDetails(agentId,  -1)\n      .then((response) => {\n        setGoals(response.data.goal)\n        setInstructions(response.data.instruction)\n        setRunModal(true);\n      })\n      .catch((error) => {\n        console.error('Error fetching agent details:', error);\n      });\n  }\n\n  function fetchAgentDetails(agentId, runId) {\n    getAgentDetails(agentId, runId ? runId : -1)\n      .then((response) => {\n        const data = response.data\n        setAgentDetails(data);\n      })\n      .catch((error) => {\n        console.error('Error fetching agent details:', error);\n      });\n  }\n\n  function fetchAgentScheduleComponent() {\n    if (agent?.is_scheduled) {\n      getDateTime(agentId)\n        .then((response) => {\n          setAgentScheduleDetails(response.data)\n        })\n        .catch((error) => {\n          console.error('Error fetching agent data:', error);\n        });\n    }\n  }\n\n  function fetchExecutions(agentId, currentRun = null) {\n    getAgentExecutions(agentId)\n      .then((response) => {\n        let data = response.data\n        data = data.filter((run) => run.status !== 'TERMINATED');\n        setAgentExecutions(data);\n        setSelectedRun(currentRun ? currentRun : data[0]);\n      })\n      .catch((error) => {\n        console.error('Error fetching agent executions:', error);\n      });\n  }\n\n  // function fetchExecutionDetails(executionId) {\n  //   getExecutionDetails(executionId || -1, agentId)\n  //     .then((response) => {\n  //       setGoals(response.data.goal);\n  //       setCurrentGoals(response.data.goal);\n  //       setInstructions(response.data.instruction);\n  //       setCurrentInstructions(response.data.instruction);\n  //     })\n  //     .catch((error) => {\n  //       console.error('Error fetching agent execution details:', error);\n  //     });\n  // }\n\n  function saveAgentTemplate() {\n    saveAgentAsTemplate(agentId, selectedRun?.id ? selectedRun?.id : -1)\n      .then((response) => {\n        toast.success(\"Agent saved as template successfully\", {autoClose: 1800});\n      })\n      .catch((error) => {\n        console.error('Error saving agent as template:', error);\n      });\n\n    setDropdown(false);\n  }\n\n  useEffect(() => {\n    const resetRunStatus = (eventData) => {\n      if (eventData.executionId === selectedRun.id) {\n        setSelectedRun((prevSelectedRun) => (\n          {...prevSelectedRun, status: eventData.status}\n        ));\n      }\n    };\n\n    const refreshDate = () => {\n      fetchAgentScheduleComponent()\n    };\n\n    EventBus.on('resetRunStatus', resetRunStatus);\n    EventBus.on('refreshDate', refreshDate);\n\n    return () => {\n      EventBus.off('resetRunStatus', resetRunStatus);\n      EventBus.off('refreshDate', refreshDate);\n    };\n  });\n\n  return (<>\n    <div style={{display: 'flex'}}>\n      {history && selectedRun !== null &&\n        <RunHistory runs={agentExecutions} selectedRunId={selectedRun?.id} setSelectedRun={setSelectedRun}\n                    setHistory={setHistory} setAgentExecutions={setAgentExecutions}/>}\n      <div style={{width: history ? '40%' : '60%'}}>\n        <div className={styles.detail_top}>\n          <div style={{display: 'flex'}}>\n            {!history && selectedRun !== null &&\n              <div style={{display: 'flex', alignItems: 'center', cursor: 'pointer', marginRight: '7px'}}\n                   onClick={() => setHistory(true)}>\n                <div className={styles.run_history_button}><Image style={{marginTop: '-2px'}} width={16} height={16}\n                                                                  src=\"/images/update.svg\"\n                                                                  alt=\"update-icon\"/><span>&nbsp;Show run history</span>\n                </div>\n              </div>}\n            <div style={{display: 'flex', alignItems: 'center', marginLeft: '2px'}} className={styles.tab_text}>\n              {selectedRun && selectedRun.status === 'RUNNING' &&\n                <div style={{marginLeft: '-6px'}}><Image width={14} height={14} style={{mixBlendMode: 'exclusion'}}\n                                                         src=\"/images/loading.gif\" alt=\"loading-icon\"/></div>}\n              <div className={styles.single_line_block} style={selectedRun && selectedRun.status === 'RUNNING' ? {\n                marginLeft: '7px',\n                maxWidth: '100px'\n              } : {marginLeft: '-8px', maxWidth: '100px'}}>{selectedRun?.name || ''}</div>\n            </div>\n            <div style={{marginLeft: '7px'}}>\n              <button onClick={() => setLeftPanel('activity_feed')} className={styles.tab_button}\n                      style={leftPanel === 'activity_feed' ? {background: '#454254'} : {background: 'transparent'}}>Activity\n                Feed\n              </button>\n            </div>\n            {agentDetails && (agentDetails.agent_workflow === 'Dynamic Task Workflow' || agentDetails.agent_workflow === \"Fixed Task Workflow\") &&\n              <div style={{marginLeft: '7px'}}>\n                <button onClick={() => setLeftPanel('agent_workflow')} className={styles.tab_button}\n                        style={leftPanel === 'agent_workflow' ? {background: '#454254'} : {background: 'transparent'}}>Task\n                  Queue\n                </button>\n              </div>}\n          </div>\n          <div style={{display: 'flex'}}>\n            <div>\n              <button className={styles.run_button} onClick={setNewRunDetails}>\n                <Image width={14} height={14} src=\"/images/run_icon.svg\" alt=\"run-icon\"/>&nbsp;New Run\n              </button>\n            </div>\n            <button className=\"secondary_button\" style={{padding: '8px', height: '31px'}}\n                    onMouseEnter={() => setDropdown(true)} onMouseLeave={() => setDropdown(false)} >\n              <Image width={14} height={14} src=\"/images/three_dots.svg\" alt=\"run-icon\"/>\n            </button>\n            {dropdown && <div onMouseEnter={() => setDropdown(true)} onMouseLeave={() => setDropdown(false)}>\n              <ul className=\"dropdown_container w_180p\" style={{marginTop: '31px', marginLeft: '-32px'}}>\n                {selectedRun && selectedRun.status === 'RUNNING' && <li className=\"dropdown_item\" onClick={() => {\n                  updateRunStatus(\"PAUSED\")\n                }}>Pause</li>}\n                {selectedRun && (selectedRun.status === 'CREATED' || selectedRun.status === 'PAUSED' || selectedRun.status === 'ERROR_PAUSED') &&\n                  <li className=\"dropdown_item\" onClick={() => {\n                    updateRunStatus(\"RUNNING\")\n                  }}>Resume</li>}\n                {agentExecutions && agentExecutions.length > 1 && <li className=\"dropdown_item\" onClick={() => {\n                  updateRunStatus(\"TERMINATED\")\n                }}>Delete Run</li>}\n                {agentExecutions && selectedRun && (selectedRun.status === 'CREATED' || selectedRun.status === 'PAUSED' || selectedRun.status === 'RUNNING' || agentExecutions.length > 1 || selectedRun.status === 'ERROR_PAUSED') && <div className={styles.dropdown_separator}/>}\n                <li className=\"dropdown_item\" onClick={() => saveAgentTemplate()}>Save as Template</li>\n                {agent && env === 'PROD' &&\n                  <li className=\"dropdown_item\" onClick={() => {\n                    handlePublishToMarketplace()\n                  }}>Publish to marketplace</li>}\n                <div className={styles.dropdown_separator} />\n                <li className=\"dropdown_item\" onClick={() => sendAgentData({\n                  id: agentId,\n                  name: \"Edit Agent\",\n                  contentType: \"Edit_Agent\",\n                  internalId: createInternalId()\n                })}>Edit Agent</li>\n                <li className=\"dropdown_item\" onClick={() => {\n                  setDropdown(false);\n                  setDeleteModal(true)\n                }}>Delete Agent\n                </li>\n                <div className={styles.dropdown_separator} />\n                {agent?.is_scheduled ? (<div>\n                  <li className=\"dropdown_item\" onClick={handleEditScheduleClick}>Edit Schedule</li>\n                  <li className=\"dropdown_item\" onClick={handleStopScheduleClick}>Stop Schedule</li>\n                </div>) : (<div>\n                  {agent && !agent?.is_running && !agent?.is_scheduled &&\n                    <li className=\"dropdown_item\" onClick={() => {\n                      setDropdown(false);\n                      setCreateModal(true)\n                    }}>Schedule Run</li>}\n                </div>)}\n              </ul>\n            </div>}\n\n            {createModal &&\n              <AgentSchedule env={env} internalId={internalId} closeCreateModal={closeCreateModal} type=\"schedule_agent\"\n                             agentId={agentId} setCreateModal={() => setCreateModal(false)}/>}\n            {createEditModal &&\n              <AgentSchedule env={env} internalId={internalId} closeCreateModal={closeCreateModal}\n                             type=\"edit_schedule_agent\"\n                             agentId={agentId} setCreateEditModal={() => setCreateEditModal(false)}/>}\n            {createStopModal && (\n              <div className=\"modal\" onClick={closeCreateModal}>\n                <div className=\"modal-content\" style={{width: '35%'}} onClick={preventDefault}>\n                  <div className={styles.detail_name}>Stop Schedule</div>\n                  <label className={styles.form_label}>All further schedules of this agent will be stopped. Are you sure\n                    you want to proceed?</label>\n                  <div style={{display: 'flex', justifyContent: 'flex-end', marginTop: '20px'}}>\n                    <button className=\"secondary_button\" style={{marginRight: '10px'}} onClick={closeCreateModal}>\n                      Cancel\n                    </button>\n                    <button className={styles.run_button} style={{paddingLeft: '15px', paddingRight: '25px'}}\n                            onClick={fetchStopSchedule}>\n                      Stop Schedule\n                    </button>\n                  </div>\n                </div>\n              </div>\n            )}\n          </div>\n        </div>\n        <div className={styles.detail_body}>\n          {leftPanel === 'activity_feed' && <div className={styles.detail_content}>\n            <ActivityFeed selectedView={selectedView} selectedRunId={selectedRun?.id || null}\n                          setFetchedData={setFetchedData} agent={agent} selectedRunStatus={selectedRun?.status || null}/>\n          </div>}\n          {leftPanel === 'agent_workflow' &&\n            <div className={styles.detail_content}><TaskQueue selectedRunId={selectedRun?.id || 0}/></div>}\n        </div>\n      </div>\n      <div style={{width: '40%'}}>\n        <div className={styles.detail_top}>\n          <div style={{display: 'flex', overflowX: 'scroll'}}>\n            {agentDetails && ((fetchedData && fetchedData.length > 0) || agentDetails.permission_type === 'RESTRICTED') && <div>\n              <button onClick={() => setRightPanel('action_console')} className={styles.tab_button}\n                      style={rightPanel === 'action_console' ? {background: '#454254'} : {background: 'transparent'}}>\n                <Image style={{marginTop: '-1px'}} width={14} height={14} src=\"/images/action_console.svg\"\n                       alt=\"action-console-icon\"/>&nbsp;Action Console &nbsp; {pendingPermission > 0 &&\n                <span className={styles.notification_circle}>{pendingPermission}</span>}\n              </button>\n            </div>}\n            {/*<div>*/}\n            {/*  <button onClick={() => setRightPanel('feedback')} className={styles.tab_button} style={rightPanel === 'feedback' ? {background:'#454254'} : {background:'transparent'}}>*/}\n            {/*    Feedback*/}\n            {/*  </button>*/}\n            {/*</div>*/}\n            <div>\n              <button onClick={() => setRightPanel('details')} className={styles.tab_button}\n                      style={rightPanel === 'details' ? {\n                        background: '#454254',\n                        paddingRight: '15px'\n                      } : {background: 'transparent', paddingRight: '15px'}}>\n                <Image width={14} height={14} src=\"/images/info.svg\" alt=\"details-icon\"/>&nbsp;Details\n              </button>\n            </div>\n            <div>\n              <button onClick={() => setRightPanel('resource_manager')} className={styles.tab_button}\n                      style={rightPanel === 'resource_manager' ? {\n                        background: '#454254',\n                        paddingRight: '15px'\n                      } : {background: 'transparent', paddingRight: '15px'}}>\n                <Image width={14} height={14} src=\"/images/home_storage.svg\" alt=\"manager-icon\"/>&nbsp;Resource Manager\n              </button>\n            </div>\n            {/*<div>*/}\n            {/*  <button onClick={() => setRightPanel('logs')} className={styles.tab_button} style={rightPanel === 'logs' ? {background:'#454254'} : {background:'transparent'}}>*/}\n            {/*    Logs*/}\n            {/*  </button>*/}\n            {/*</div>*/}\n          </div>\n        </div>\n        <div className={styles.detail_body} style={{paddingRight: '0'}}>\n          {rightPanel === 'action_console' && agentDetails && (\n            <div className={styles.detail_content}>\n              <ActionConsole key={JSON.stringify(fetchedData)} actions={fetchedData}\n                             pendingPermission={pendingPermission} setPendingPermissions={setPendingPermissions}/>\n            </div>\n          )}\n          {rightPanel === 'details' && agentDetails && agentDetails !== null &&\n            <div className={styles.detail_content}><Details agentDetails1={agentDetails}\n                                                            runCount={agentExecutions?.length || 0}\n                                                            agentScheduleDetails={agentScheduleDetails} agent={agent}/>\n            </div>}\n          {rightPanel === 'resource_manager' &&\n            <div className={styles.detail_content}><ResourceManager agentId={agentId} runs={agentExecutions}/></div>}\n        </div>\n      </div>\n\n      {runModal && (<div className=\"modal\" onClick={closeRunModal}>\n        <div className=\"modal-content\" style={{width: '35%'}} onClick={preventDefault}>\n          <div className={styles.detail_name}>Run agent name</div>\n          <div>\n            <label className={styles.form_label}>Name</label>\n            <input className=\"input_medium\" type=\"text\" value={runName} onChange={handleRunNameChange}/>\n          </div>\n          {goals && goals.length > 0 && <div style={{marginTop: '15px'}}>\n            <div><label className={styles.form_label}>Goals</label></div>\n            {goals.map((goal, index) => (<div key={index} style={{\n              marginBottom: '10px',\n              display: 'flex',\n              alignItems: 'center',\n              justifyContent: 'space-between'\n            }}>\n              <div style={{flex: '1'}}><input className=\"input_medium\" type=\"text\" value={goal}\n                                              onChange={(event) => handleGoalChange(index, event.target.value)}/></div>\n              {goals.length > 1 && <div>\n                <button className=\"secondary_button\" style={{marginLeft: '4px', padding: '5px'}}\n                        onClick={() => handleGoalDelete(index)}>\n                  <Image width={20} height={21} src=\"/images/close.svg\" alt=\"close-icon\"/>\n                </button>\n              </div>}\n            </div>))}\n            <div>\n              <button className=\"secondary_button\" onClick={addGoal}>+ Add</button>\n            </div>\n          </div>}\n          <div style={{marginTop: '15px'}}>\n            <div><label className={styles.form_label}>Instructions<span\n              style={{fontSize: '9px'}}>&nbsp;(optional)</span></label></div>\n            {instructions.map((goal, index) => (<div key={index} style={{\n              marginBottom: '10px',\n              display: 'flex',\n              alignItems: 'center',\n              justifyContent: 'space-between'\n            }}>\n              <div style={{flex: '1'}}><input className=\"input_medium\" type=\"text\" value={goal}\n                                              onChange={(event) => handleInstructionChange(index, event.target.value)}/>\n              </div>\n              {instructions.length > 1 && <div>\n                <button className=\"secondary_button\" style={{marginLeft: '4px', padding: '5px'}}\n                        onClick={() => handleInstructionDelete(index)}>\n                  <Image width={20} height={21} src=\"/images/close.svg\" alt=\"close-icon\"/>\n                </button>\n              </div>}\n            </div>))}\n            <div>\n              <button className=\"secondary_button\" onClick={addInstruction}>+ Add</button>\n            </div>\n          </div>\n          <div style={{display: 'flex', justifyContent: 'flex-end'}}>\n            <button className=\"secondary_button\" style={{marginRight: '10px'}} onClick={closeRunModal}>\n              Cancel\n            </button>\n            <button className={styles.run_button} style={{paddingLeft: '15px', paddingRight: '25px'}}\n                    onClick={() => handleCreateRun()}>\n              <Image width={14} height={14} src=\"/images/run_icon.svg\" alt=\"run-icon\"/>&nbsp;Run\n            </button>\n          </div>\n        </div>\n      </div>)}\n\n      {deleteModal && (<div className=\"modal\" onClick={closeDeleteModal}>\n        <div className=\"modal-content\" style={{width: '502px', padding: '16px', gap: '24px'}} onClick={preventDefault}>\n          <div>\n            <label className={styles.delete_agent_modal_label}>Delete Agent</label>\n          </div>\n          <div>\n            <label className={styles.delete_modal_text}>All the runs and details of this agent will be deleted. Are you\n              sure you want to proceed?</label>\n          </div>\n          <div style={{display: 'flex', justifyContent: 'flex-end'}}>\n            <button className=\"secondary_button\" style={{marginRight: '10px'}} onClick={closeDeleteModal}>\n              Cancel\n            </button>\n            <button className=\"primary_button\" onClick={() => handleDeleteAgent()}>\n              Delete Agent\n            </button>\n          </div>\n        </div>\n      </div>)}\n\n      {publishModal && (<div className=\"modal\" onClick={() => {setPublishModal(false)}}>\n        <div className=\"modal-content w_35\" onClick={preventDefault}>\n          {publishModalState ? <div className={styles.detail_name}>Run the agent at least once to publish!</div> : <div className={styles.detail_name}>Template submitted successfully!</div>}\n          <div>\n            {!publishModalState ? <label className={styles.form_label}>Your template is under review. Please check the marketplace in 2-3 days. If your template is not visible on the marketplace, reach out to us on Discord&nbsp;\n              <a href=\"https://discord.com/channels/1107593006032355359/1143813784683692093\" target=\"_blank\" rel=\"noopener noreferrer\">\n                #agent-templates-submission\n              </a> channel.</label> : <label className={styles.form_label}>Before publishing your agent to the marketplace, you need to run it at least once. To do this, click the New Run button (on the agent screen). Once the agent has run successfully, you can proceed to try publishing your template.</label>}\n          </div>\n          <div className={styles.modal_buttons}>\n            <button className=\"primary_button\" onClick={() => {setPublishModal(false)}}>\n              Okay\n            </button>\n          </div>\n        </div>\n      </div>)}\n\n    </div>\n    <ToastContainer/>\n  </>);\n}"
  },
  {
    "path": "gui/pages/Content/Agents/Agents.js",
    "content": "import React from 'react';\nimport Image from \"next/image\";\nimport 'react-toastify/dist/ReactToastify.css';\nimport {createInternalId, getUserClick} from \"@/utils/utils\";\nimport mixpanel from 'mixpanel-browser'\n\nexport default function Agents({sendAgentData, agents}) {\n  return (<>\n      <div className=\"container\">\n        <p className=\"text_14 mt_8 mb_12 ml_8\">Agents</p>\n        <div className=\"w_100 mb_10\">\n          <button className=\"secondary_button w_100\" onClick={() => {\n            sendAgentData({\n              id: -1,\n              name: \"new agent\",\n              contentType: \"Create_Agent\",\n              internalId: createInternalId()\n            }); getUserClick('Agent Create Clicked', {'Click Position': 'Sidebar'})\n          }}>\n            + Create Agent\n          </button>\n        </div>\n\n        {agents && agents.length > 0 ? <div className=\"vertical_selection_scroll w_100\">\n          {agents.map((agent, index) => (\n            <div key={index}>\n              <div className=\"agent_box w_100\" onClick={() => sendAgentData(agent)}>\n                {agent?.is_running && <Image width={14} height={14} className=\"mix_blend_mode\" src=\"/images/loading.gif\" alt=\"active-icon\"/>}\n                <div className=\"text_ellipsis\"><span className=\"agent_text text_ellipsis\">{agent.name}</span></div>\n                {agent?.is_scheduled && <Image className=\"ml_4\" width={17} height={17} src=\"/images/event_repeat.svg\" alt=\"check-icon\"/>}\n              </div>\n            </div>\n          ))}\n        </div> : <div className=\"form_label mt_20 horizontal_container justify_center\">No Agents found</div>}\n      </div>\n    </>\n  );\n}\n"
  },
  {
    "path": "gui/pages/Content/Agents/Agents.module.css",
    "content": ".container {\n    height: 100%;\n    width: 100%;\n    padding: 0 0 0 8px;\n}\n\n.title_box {\n    width: 100%;\n    padding: 8px;\n    display: flex;\n    align-items: center;\n}\n\n.title_text {\n    font-style: normal;\n    font-weight: 400;\n    font-size: 14px;\n    line-height: 17px;\n    display: flex;\n    align-items: center;\n    color: white;\n}\n\n.wrapper {\n    margin-bottom: 5px;\n    width: 100%;\n}\n\n.agent_active {\n    display: flex;\n    flex-direction: row;\n    align-items: center;\n    padding: 0;\n}\n\n.text_block {\n    display:flex;\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 1;\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.form_label {\n    font-size: 13px;\n    margin-bottom: 4px;\n    font-weight: 500;\n    color: #888888;\n    line-height: 17px;\n}\n\n.page_title {\n    text-align: left;\n    font-style: normal;\n    font-weight: 400;\n    font-size: 16px;\n    line-height: 17px;\n    display: flex;\n    align-items: center;\n    color: white;\n    margin-bottom: 25px;\n}\n\n.tool_text {\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 1;\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.detail_top {\n    width: 100%;\n    height: 44px;\n    display: flex;\n    align-items: center;\n    justify-content: space-between;\n    padding-right: 10px;\n}\n\n.detail_body {\n    width: 100%;\n    padding-right: 10px;\n    margin-bottom: 20px;\n}\n\n.detail_content {\n    height: calc(100vh - 140px);\n    border-radius: 8px;\n    overflow-y: scroll;\n    padding-bottom: 0;\n}\n\n.tab_button {\n    border: none;\n    font-style: normal;\n    font-weight: 400;\n    font-size: 12px;\n    line-height: 15px;\n    color: #FFFFFF;\n    border-radius: 8px;\n    padding: 8px 10px;\n    display: -webkit-inline-flex;\n    align-items: center;\n    justify-content: center;\n}\n\n.tab_text {\n    font-style: normal;\n    font-weight: 400;\n    font-size: 12px;\n    line-height: 15px;\n    color: #FFFFFF;\n    padding: 8px;\n}\n\n.tab_button:hover {\n    background: #454254;\n}\n.run_history_button{\n    background: rgba(255, 255, 255, 0.14);\n    border: none;\n    font-style: normal;\n    font-weight: 400;\n    font-size: 12px;\n    line-height: 12px;\n    color: #FFFFFF;\n    border-radius: 8px;\n    padding: 8px 10px 8px 5px;\n}\n.run_button {\n    background: #62A168;\n    border: none;\n    font-style: normal;\n    font-weight: 500;\n    font-size: 12px;\n    line-height: 15px;\n    color: #FFFFFF;\n    border-radius: 8px;\n    padding: 7px 10px 8px 5px;\n    height: 31px;\n    margin-right: 7px;\n}\n\n.run_button:hover {\n    background: #57825b;\n}\n\n.pause_button {\n    background: #F78166;\n    border: none;\n    font-style: normal;\n    font-weight: 500;\n    font-size: 12px;\n    line-height: 15px;\n    color: #FFFFFF;\n    border-radius: 8px;\n    padding: 8px 10px;\n}\n\n.pause_button:hover {\n    background: #C95034;\n}\n\n.history_box {\n    width: 100%;\n    padding: 10px;\n    color: white;\n    font-style: normal;\n    font-weight: 400;\n    font-size: 12px;\n    line-height: 14px;\n    border-radius: 8px;\n    cursor: pointer;\n    margin-bottom: 7px;\n}\n\n.notification_bubble {\n    width: 14px;\n    height: 14px;\n    background: #DC6261;\n    border-radius: 200px;\n    display: flex;\n    align-items: center;\n    text-align: center;\n    padding: 4px;\n    font-size: 9px;\n    order: 1;\n}\n\n.history_info {\n    font-style: normal;\n    font-weight: 400;\n    font-size: 10px;\n    line-height: 12px;\n    color: #888888;\n    margin-left: 4px;\n    margin-top: 3px;\n}\n\n.feed_title {\n    font-family: 'Source Code Pro';\n    margin-left: 10px;\n    font-style: normal;\n    font-weight: 500;\n    font-size: 12px;\n    line-height: 15px;\n    color: white;\n    white-space: pre-line;\n    word-wrap: break-word;\n    max-width: 95%;\n}\n\n.feed_icon {\n    font-size: 20px;\n    margin-top: 5px;\n}\n\n.custom_task_box {\n    font-style: normal;\n    font-weight: 500;\n    font-size: 12px;\n    line-height: 14px;\n    color: white;\n    width: 100%;\n    border-radius: 8px;\n    margin-bottom: 7px;\n    padding: 15px 20px;\n}\n\n.console_icons {\n    margin: -3px 3px 0 0;\n}\n\n.detail_name {\n    font-style: normal;\n    font-weight: 400;\n    font-size: 16px;\n    line-height: 19px;\n    color: #FFFFFF;\n    margin-bottom: 10px;\n}\n\n.separator {\n    height: 15px;\n    margin-bottom: 15px;\n    border-bottom: 1px solid rgba(255, 255, 255, 0.08);\n}\n\n.agent_info_box {\n    display: flex;\n    align-items: center;\n    justify-content: flex-start;\n    margin-bottom: 10px;\n}\n\n.agent_info_tools {\n    display: flex;\n    flex-direction: row;\n    flex-wrap: wrap;\n    align-items: flex-start;\n}\n\n.resources {\n    display: flex;\n    justify-content: space-between;\n    flex-wrap: wrap;\n}\n\n.agent_resources {\n    width: 100%;\n    margin-top: 10px;\n}\n\n.large_text_box {\n    -webkit-line-clamp: 5;\n    -webkit-box-orient: vertical;\n}\n\n.show_more_button {\n    margin-top: 10px;\n    cursor: pointer;\n    width: fit-content;\n    color: #888888;\n}\n\n.single_line_block {\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n    max-width: 80%;\n}\n\n.three_dots {\n    margin-left: 5px;\n    background: transparent;\n    border: none;\n    border-radius: 8px;\n}\n\n.more_details {\n    display: flex;\n    align-items: center;\n    margin-right: 30px;\n}\n\n.more_details_wrapper {\n    display: flex;\n    align-items: center;\n    margin-top: 20px;\n    justify-content: flex-start;\n}\n\n.task_header {\n    color: rgb(255, 255, 255);\n    padding: 7px;\n    font-size: 13px;\n    font-weight: 500;\n    font-family: 'Source Code Pro';\n}\n\n.text_12_n\n{\n    font-style: normal;\n    font-weight: 400;\n    font-size: 12px;\n    line-height: 14px;\n    color: #FFFFFF;\n}\n\n.notification_circle\n{\n    display: flex;\n    flex-direction: row;\n    align-items: center;\n    justify-content: center;\n    gap: 4px;\n    width: fit-content;\n    padding: 2px 5px;\n    height: fit-content;\n    background: #DC6161;\n    border-radius: 16px;\n\n    font-style: normal;\n    font-weight: 500;\n    font-size: 10px;\n    line-height: 12px;\n    color: #FFFFFF;\n}\n.delete_agent_modal_label\n{\n    color: #FFF;\n    font-size: 16px;\n    font-family: \"Public Sans\", sans-serif;\n    font-style: normal;\n    font-weight: 400;\n    line-height: normal;\n}\n\n.delete_button\n{\n    display: flex;\n    padding: 0px 12px;\n    align-items: flex-start;\n    gap: 4px;\n    border-radius: 8px;\n    border: 1px solid rgba(255, 255, 255, 0.08);\n    background: #FFF;\n    color: #000;\n    font-size: 12px;\n    font-family: \"Public Sans\", sans-serif;\n    font-style: normal;\n    font-weight: 500;\n    line-height: normal;\n\n}\n\n.delete_modal_text\n{\n    color: #888;\n    font-size: 12px;\n    font-family: \"Roboto Flex\", sans-serif;\n    font-style: normal;\n    font-weight: 400;\n    line-height: normal;\n}\n  \n.rdtPicker input {\n    display: flex !important;\n    flex-direction: row !important;\n    align-items: center !important;\n    padding: 8px 14px 8px 14px !important;\n    gap: 4px !important;\n    border-radius: 8px !important;\n    width: 100% !important;\n    height: 32px !important;\n    background: #3B3B49 !important;\n    border: 1px solid #4A4A55 !important;\n    font-style: normal !important;\n    font-weight: 400 !important;\n    font-size: 12px !important;\n    line-height: 16px !important;\n    transition: 0.2s !important;\n    color: white !important;\n}\n\n.rdtPicker input:focus {\n    display: flex;\n    flex-direction: row;\n    align-items: center;\n    padding: 8px 14px 8px 14px;\n    gap: 4px;\n    border-radius: 8px;\n    width: 100%;\n    height: 32px;\n    background: #3B3B49;\n    border: 1px solid #4A4A55;\n    font-style: normal;\n    font-weight: 400;\n    font-size: 12px;\n    line-height: 16px;\n    transition: 0.2s;\n    color: white;\n    outline: none;\n}\n\n.permission_changes {\n    color: #888888 !important;\n    text-decoration: line-through;\n    pointerEvents: none !important;\n}\n\n.modal_buttons{\n    display: flex;\n    justify-content: flex-end;\n    margin-top: 20px\n}\n\n.modal_info_class{\n    margin-left: -5px;\n    margin-right: 5px;\n}\n\n.table_contents{\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    margin-top: 40px;\n    width: 100%\n}\n\n.create_settings_button{\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    margin-top: 10px\n}\n\n.button_margin{\n    margin-top: -10px;\n}\n\n.dropdown_separator{\n    border-bottom: 1px solid rgba(255, 255, 255, 0.08);\n    margin-left:-5px;\n    width: 180px\n}\n\n.dropdown_container_agent{\n    bottom: 40px;\n    z-index: 9999;\n    padding: 0px;\n    width: fit-content;\n    height: fit-content;\n    margin-right: 40px;\n    background: #3B3B49;\n    border-radius: 8px;\n    position: absolute;\n    box-shadow: 0 2px 7px rgba(0,0,0,.4), 0 0 2px rgba(0,0,0,.22);\n}\n\n.dropdown_item_agent{\n    height:30px;\n    paddingTop: 2px;\n    paddingBottom: 2px;\n}"
  },
  {
    "path": "gui/pages/Content/Agents/Details.js",
    "content": "import React, {useEffect, useState, useRef} from 'react';\nimport styles from './Agents.module.css';\nimport Image from \"next/image\";\nimport {formatNumber} from \"@/utils/utils\";\nimport {EventBus} from \"@/utils/eventBus\";\n\nexport default function Details({agentDetails1, runCount, agentScheduleDetails, agent}) {\n  const [showGoals, setShowGoals] = useState(false);\n  const [showConstraints, setShowConstraints] = useState(false);\n  const [showInstructions, setShowInstructions] = useState(false);\n  const [filteredInstructions, setFilteredInstructions] = useState([]);\n  const [scheduleText, setScheduleText] = useState('');\n  const [agentDetails, setAgentDetails] = useState(null)\n  const goalBoxRef = useRef(null);\n  const instructionBoxRef = useRef(null);\n  const constrainBoxRef = useRef(null);\n  const [isOverflowing, setIsOverflowing] = useState([false, false, false]);\n  const info_text = {\n    marginLeft: '7px',\n  };\n\n  const info_text_secondary = {\n    marginLeft: '3px',\n    marginTop: '2px',\n    color: '#888888',\n    lineHeight: '13px',\n    fontSize: '11px'\n  };\n\n  useEffect(() => {\n    const newOverflowing = [...isOverflowing];\n\n    if (goalBoxRef.current) {\n      newOverflowing[0] = goalBoxRef.current.scrollHeight > goalBoxRef.current.clientHeight;\n    }\n    if (instructionBoxRef.current) {\n      newOverflowing[1] = instructionBoxRef.current.scrollHeight > instructionBoxRef.current.clientHeight;\n    }\n    if (constrainBoxRef.current) {\n      newOverflowing[2] = constrainBoxRef.current.scrollHeight > constrainBoxRef.current.clientHeight;\n    }\n\n    setIsOverflowing(newOverflowing);\n  }, [agentDetails?.goal, filteredInstructions, agentDetails?.constraints]);\n\n  const openToolkitTab = (toolId) => {\n    EventBus.emit('openToolkitTab', {toolId: toolId});\n  }\n\n  useEffect(() => {\n    if (Array.isArray(agentDetails?.instruction)) {\n      setFilteredInstructions(agentDetails.instruction.filter(instruction => instruction.trim() !== ''));\n    }\n  }, [agentDetails]);\n  useEffect(() => {\n    setAgentDetails(agentDetails1)\n  }, [agentDetails1]);\n\n  useEffect(() => {\n    if(!agentScheduleDetails){\n      setScheduleText('')\n      return\n    }\n    if (agent?.is_scheduled) {\n      if (agentScheduleDetails?.recurrence_interval !== null) {\n        if ((agentScheduleDetails?.expiry_runs === -1 || agentScheduleDetails?.expiry_runs == null) && agentScheduleDetails?.expiry_date !== null) {\n          let expiryDate;\n\n          if (agentScheduleDetails?.expiry_date) {\n            const [day, month, year] = agentScheduleDetails.expiry_date.split(\"/\");\n            expiryDate = new Date(year, month - 1, day);\n          }\n\n          const tempScheduleText = `The agent is scheduled to run on ${agentScheduleDetails?.start_date} ${agentScheduleDetails?.start_time} and will recursively run after every ${agentScheduleDetails?.recurrence_interval} and will expire after ${\n            expiryDate ? new Intl.DateTimeFormat('en-GB', {\n              day: '2-digit',\n              month: 'short',\n              year: 'numeric'\n            }).format(expiryDate) : ''\n          }`;\n\n          setScheduleText(tempScheduleText);\n        } else if ((agentScheduleDetails?.expiry_runs > 0) && agentScheduleDetails?.expiry_date == null) {\n          setScheduleText('The agent is scheduled to run on ' + agentScheduleDetails?.start_date + ' ' + agentScheduleDetails?.start_time + ' and will recursively run after every ' + agentScheduleDetails?.recurrence_interval + ' and will expire after ' + agentScheduleDetails?.expiry_runs + ' runs')\n        } else {\n          setScheduleText('The agent is scheduled to run on ' + agentScheduleDetails?.start_date + ' ' + agentScheduleDetails?.start_time + ' and will recursively run after every ' + agentScheduleDetails?.recurrence_interval + ' and will never expire')\n        }\n      } else {\n        setScheduleText('The agent is scheduled to run on ' + agentScheduleDetails?.start_date + ' ' + agentScheduleDetails?.start_time)\n      }\n    }\n  }, [agentScheduleDetails]);\n\n  return (<>\n    <div className={styles.history_box} style={{background: '#272335', padding: '15px', cursor: 'default'}}>\n      <div className={styles.detail_name}>{agentDetails?.name || ''}</div>\n      <div>{agentDetails?.description || ''}</div>\n      <div className={styles.separator}></div>\n      <div\n        style={{display: 'flex', marginBottom: '5px', alignItems: 'center', justifyContent: 'flex-start', gap: '7.5%'}}>\n        <div>\n          <div className={styles.agent_info_box}>\n            <div><Image width={12} height={12} src=\"/images/runs_made.svg\" alt=\"runs-icon\"/></div>\n            <div style={info_text_secondary}>Total Runs</div>\n          </div>\n          <div className={styles.feed_title} style={{fontSize: '20px', marginLeft: '0'}}>{runCount || 0}</div>\n        </div>\n        <div>\n          <div className={styles.agent_info_box}>\n            <div><Image width={12} height={12} src=\"/images/calls_made.svg\" alt=\"calls-icon\"/></div>\n            <div style={info_text_secondary}>Total Calls</div>\n          </div>\n          <div className={styles.feed_title}\n               style={{fontSize: '20px', marginLeft: '0'}}>{formatNumber(agentDetails?.calls || 0)}</div>\n        </div>\n        <div>\n          <div className={styles.agent_info_box}>\n            <div><Image width={12} height={12} src=\"/images/tokens_consumed.svg\" alt=\"tokens-icon\"/></div>\n            <div style={info_text_secondary}>Tokens Consumed</div>\n          </div>\n          <div className={styles.feed_title}\n               style={{fontSize: '20px', marginLeft: '0'}}>{formatNumber(agentDetails?.tokens || 0)}</div>\n        </div>\n      </div>\n      <div className={styles.separator}></div>\n      <div className={styles.agent_info_box}>\n        <div><Image width={15} height={15} src=\"/images/flag.svg\" alt=\"goals-icon\"/></div>\n        <div style={info_text}>{agentDetails?.goal?.length || 0} Goals</div>\n      </div>\n      {agentDetails?.goal && agentDetails?.goal?.length > 0 && <div>\n        <div ref={goalBoxRef} className={styles.large_text_box} style={!showGoals ? {overflow: 'hidden', display: '-webkit-box'} : {}}>\n          {agentDetails?.goal?.map((goal, index) => (<div key={index} style={{marginTop: '0'}}>\n            <div>{index + 1}. {goal || ''}</div>\n            {index !== agentDetails?.goal?.length - 1 && <br/>}\n          </div>))}\n        </div>\n        {isOverflowing[0] && <div className={styles.show_more_button} onClick={() => setShowGoals(!showGoals)}>\n          {showGoals ? 'Show Less' : 'Show More'}\n        </div>}\n      </div>}\n      {filteredInstructions && filteredInstructions.length > 0 && <div>\n        <div className={styles.separator}></div>\n        <div className={styles.agent_info_box}>\n          <div><Image width={15} height={15} src=\"/images/instructions.svg\" alt=\"instruction-icon\"/></div>\n          <div style={info_text}>{filteredInstructions.length || 0} Instructions</div>\n        </div>\n        <div>\n          <div className={styles.large_text_box} ref={instructionBoxRef}\n               style={!showInstructions ? {overflow: 'hidden', display: '-webkit-box'} : {}}>\n            {filteredInstructions.map((instruction, index) => (<div key={index} style={{marginTop: '0'}}>\n              <div>{index + 1}. {instruction || ''}</div>\n              {index !== filteredInstructions.length - 1 && <br/>}\n            </div>))}\n          </div>\n          {isOverflowing[1] && <div className={styles.show_more_button}\n               onClick={() => setShowInstructions(!showInstructions)}>{showInstructions ? 'Show Less' : 'Show More'}</div>}\n        </div>\n      </div>}\n      {agentDetails && <div>{agentDetails.tools && agentDetails.tools.length > 0 && <div>\n        <div className={styles.separator}></div>\n        <div className={styles.agent_info_box}>\n          <div><Image width={15} height={15} src=\"/images/tools_dark.svg\" alt=\"tools-icon\"/></div>\n          <div style={info_text}>Tools assigned</div>\n        </div>\n        <div className={styles.agent_info_tools}>\n          {agentDetails?.tools?.map((tool, index) =>\n            (<div onClick={() => openToolkitTab(tool.id)} key={index} className=\"tool_container\"\n                  style={{marginTop: '0', marginBottom: '5px', cursor: 'pointer'}}>\n              <div className={styles.tool_text}>{tool.name || ''}</div>\n            </div>))}\n        </div>\n      </div>}</div>}\n      {agentDetails && <div>{agentDetails.constraints && agentDetails.constraints?.length > 0 && <div>\n        <div className={styles.separator}></div>\n        <div className={styles.agent_info_box}>\n          <div><Image width={15} height={15} src=\"/images/close_fullscreen.svg\" alt=\"constraint-icon\"/></div>\n          <div style={info_text}>{agentDetails?.constraints.length || 0} Constraints</div>\n        </div>\n        <div className={styles.large_text_box} ref={constrainBoxRef}\n             style={!showConstraints ? {overflow: 'hidden', display: '-webkit-box'} : {}}>\n          {agentDetails?.constraints?.map((constraint, index) => (<div key={index} style={{marginTop: '0'}}>\n            <div>{index + 1}. {constraint || ''}</div>\n            {index !== agentDetails.constraints.length - 1 && <br/>}\n          </div>))}\n        </div>\n        {isOverflowing[2] && <div className={styles.show_more_button}\n             onClick={() => setShowConstraints(!showConstraints)}>{showConstraints ? 'Show Less' : 'Show More'}</div>}\n      </div>}</div>}\n      <div className={styles.separator}></div>\n      <div className={styles.agent_info_box}>\n        <div><Image width={15} height={15} src=\"/images/fact_check.svg\" alt=\"queue-icon\"/></div>\n        <div style={info_text}>{agentDetails?.agent_workflow || ''}</div>\n      </div>\n      {agentDetails?.knowledge_name && <div className={styles.agent_info_box}>\n        <div><Image width={15} height={15} src=\"/images/books.svg\" alt=\"book-icon\"/></div>\n        <div style={info_text}>{agentDetails?.knowledge_name}</div>\n      </div>}\n      <div className={styles.agent_info_box}>\n        <div><Image width={15} height={15} src=\"/images/deployed_code.svg\" alt=\"model-icon\"/></div>\n        <div style={info_text}>{agentDetails?.model || ''}</div>\n      </div>\n      {/*<div className={styles.agent_info_box}>*/}\n      {/*  <div><Image width={15} height={15} src=\"/images/cancel_presentation.svg\" alt=\"exit-icon\"/></div>*/}\n      {/*  <div style={info_text}>{exit}</div>*/}\n      {/*</div>*/}\n      {/* <div className={styles.agent_info_box}>\n        <div><Image width={15} height={15} src=\"/images/overview.svg\" alt=\"window-icon\"/></div>\n        <div style={info_text}>{agentDetails?.memory_window || 0} milliseconds</div>\n      </div> */}\n      <div className={styles.agent_info_box}>\n        <div><Image width={15} height={15} src=\"/images/key.svg\" alt=\"permission-type-icon\"/></div>\n        <div style={info_text}>{agentDetails?.permission_type?.replace(/\\s*\\([^)]*\\)/g, '') || ''}</div>\n      </div>\n      {agentDetails?.max_iterations && <div className={styles.agent_info_box}>\n        <div><Image width={15} height={15} src=\"/images/info.svg\" alt=\"info-icon\"/></div>\n        <div style={info_text}>Stop after {agentDetails.max_iterations} iterations</div>\n      </div>}\n      {agent?.is_scheduled && scheduleText && <div className={styles.agent_info_box}>\n        <div><Image width={15} height={15} src=\"/images/event_repeat.svg\" alt=\"info-icon\"/></div>\n        <div style={info_text}>{scheduleText}</div>\n      </div>}\n    </div>\n  </>)\n}"
  },
  {
    "path": "gui/pages/Content/Agents/ResourceList.js",
    "content": "import React, {useState, useMemo} from 'react';\nimport styles from './Agents.module.css';\nimport Image from \"next/image\";\nimport {downloadFile, downloadAllFiles, formatBytes, returnResourceIcon} from \"@/utils/utils\";\n\nexport default function ResourceList({files, channel, runs}) {\n  const [selectedRunId, setSelectedRunId] = useState(null);\n  const filesByRun = useMemo(() => runs.map(run => {\n    const relatedFiles = files.filter(file => file.agent_execution_id === run.id);\n    return relatedFiles.length !== 0 && {\"run\": run, \"files\": relatedFiles};\n  }).filter(Boolean), [files, runs]);\n\n  const downloadRunFiles = (run_id, name) => {\n    const runFiles = files.filter(file => file.agent_execution_id === run_id);\n    runFiles.length !== 0 && downloadAllFiles(runFiles, name);\n  }\n\n  const isAnyFileWithAgentId = files.some(file => file.agent_execution_id !== null);\n\n  const File = ({file, index}) => (\n    <div key={index} onClick={() => downloadFile(file.id, file.name)} className={styles.history_box}\n         style={{background: '#272335', padding: '0px 10px', width: '49.5%'}}>\n      <div style={{display: 'flex', alignItems: 'center', justifyContent: 'flex-start'}}>\n        <div><Image width={28} height={46} src={returnResourceIcon(file)} alt=\"file-icon\"/></div>\n        <div style={{marginLeft: '5px', width: '100%'}}>\n          <div style={{fontSize: '11px'}} className={styles.single_line_block}>{file.name}</div>\n          <div style={{\n            color: '#888888',\n            fontSize: '9px'\n          }}>{file.type.split(\"/\")[1]}{file.size !== '' ? ` • ${formatBytes(file.size)}` : ''}</div>\n        </div>\n      </div>\n    </div>\n  )\n\n  return (\n    <div id=\"resource-list\">\n      {channel === 'output' && (!isAnyFileWithAgentId || files.length <= 0 ?\n          <div className=\"vertical_container\">\n            <Image width={150} height={60} src=\"/images/no_permissions.svg\" alt=\"no-permissions\"/>\n            <span className=\"feed_title mt_8\">No Output files!</span>\n          </div>\n          :\n          <div id=\"division_by_runs\">\n            {filesByRun.map((filesRun, index) => (\n              <div key={filesByRun.length - index - 1}>\n                <div className=\"horizontal_container justify_space_between cursor_pointer padding_8_6\"\n                     onClick={() => setSelectedRunId(filesRun.run.id === selectedRunId ? null : filesRun.run.id)}>\n                  <div className=\"horizontal_container\">\n                    <Image src={selectedRunId === filesRun.run.id ? \"/images/arrow_downward_dropdown.svg\" : \"/images/arrow_forward.svg\"}\n                      alt=\"arrow\" width={14} height={14}/>\n                    <span className=\"text_12 ml_8 text_ellipsis mxw_360\">{filesRun.run.name}</span>\n                    <div className=\"resource_manager_tip ml_8\"><Image src=\"/images/bolt.svg\" alt=\"bolt\" width={10} height={10}/> <span\n                      className=\"text_9\">Run {filesByRun.length - index}</span></div>\n                  </div>\n                  <Image src=\"/images/download.svg\" alt=\"download_icon\" width={16} height={16} onClick={() => downloadRunFiles(filesRun.run.id, filesRun.run.name)}/>\n                </div>\n\n                {selectedRunId === filesRun.run.id && (\n                  <div className=\"horizontal_space_between flex_wrap padding_2_8\">\n                    {filesRun.files.map((file, index) => <File key={index} file={file}/>)}\n                  </div>\n                )}\n              </div>\n            ))}\n          </div>\n      )}\n\n      {channel === 'input' &&\n        <div className=\"horizontal_space_between flex_wrap\">\n          {files.map((file, index) => <File key={index} file={file}/>)}\n        </div>}\n    </div>\n  )\n}"
  },
  {
    "path": "gui/pages/Content/Agents/ResourceManager.js",
    "content": "import React, {useState, useRef, useEffect} from 'react';\nimport styles from './Agents.module.css';\nimport Image from \"next/image\";\nimport {ToastContainer, toast} from 'react-toastify';\nimport 'react-toastify/dist/ReactToastify.css';\nimport {getResources, uploadFile} from \"@/pages/api/DashboardService\";\nimport {downloadAllFiles} from \"@/utils/utils\";\nimport ResourceList from \"@/pages/Content/Agents/ResourceList\";\n\nexport default function ResourceManager({agentId, runs}) {\n  const [output, setOutput] = useState([]);\n  const [input, setInput] = useState([]);\n  const [channel, setChannel] = useState('input')\n  const [isDragging, setIsDragging] = useState(false);\n  const fileInputRef = useRef(null);\n\n  function handleFile(files) {\n    if (files.length > 0) {\n      const sizeInMB = files[0].size / (1024 * 1024);\n      if (sizeInMB > 5) {\n        toast.error('File size should not exceed 5MB', {autoClose: 1800});\n      } else {\n        const fileData = {\n          \"file\": files[0],\n          \"name\": files[0].name,\n          \"size\": files[0].size,\n          \"type\": files[0].type,\n        };\n        uploadResource(fileData);\n      }\n    }\n  };\n  const handleFileInputChange = (event) => {\n    const files = event.target.files;\n    handleFile(files);\n  };\n\n  const handleDropAreaClick = () => {\n    fileInputRef.current.click();\n  };\n\n  const handleDragEnter = (event) => {\n    event.preventDefault();\n    setIsDragging(true);\n  };\n\n  const handleDragLeave = () => {\n    setIsDragging(false);\n  };\n\n  const handleDragOver = (event) => {\n    event.preventDefault();\n  };\n\n  const handleDrop = (event) => {\n    event.preventDefault();\n    setIsDragging(false);\n    const files = event.dataTransfer.files;\n    handleFile(files);\n  };\n\n  useEffect(() => {\n    fetchResources();\n  }, [agentId]);\n\n  function uploadResource(fileData) {\n    const formData = new FormData();\n    formData.append('file', fileData.file);\n    formData.append('name', fileData.name);\n    formData.append('size', fileData.size);\n    formData.append('type', fileData.type);\n\n    uploadFile(agentId, formData)\n      .then((response) => {\n        fetchResources();\n        toast.success('Resource added successfully', {autoClose: 1800});\n      })\n      .catch((error) => {\n        toast.error(error, {autoClose: 1800});\n        console.error('Error uploading resource:', error);\n      });\n  }\n\n  function fetchResources() {\n    getResources(agentId)\n      .then((response) => {\n        const resources = response.data;\n        const inputFiles = resources.filter((resource) => resource.channel === 'INPUT');\n        const outputFiles = resources.filter((resource) => resource.channel === 'OUTPUT');\n        setInput(inputFiles);\n        setOutput(outputFiles);\n      })\n      .catch((error) => {\n        console.error('Error fetching resources:', error);\n      });\n  }\n\n  return (<>\n    <div className=\"detail_top mb_10\">\n      <button onClick={() => setChannel('input')} className={channel === 'input' ? 'tab_button_selected' : 'tab_button'}>Input</button>\n      <button onClick={() => setChannel('output')} className={channel === 'output' ? 'tab_button_selected' : 'tab_button'}>Output</button>\n    </div>\n    <div className=\"w_100 mr_10 mb_20\">\n      {channel === 'input' &&\n        <div className={`file-drop-area ${isDragging ? 'dragging' : ''}`} onDragEnter={handleDragEnter}\n             onDragLeave={handleDragLeave} onDragOver={handleDragOver} onDrop={handleDrop}\n             onClick={handleDropAreaClick}>\n            <p className=\"text_14 text_align_center\">+ Choose or drop a file here</p>\n            <p className=\"text_12 text_align_center\">Supported file formats are txt, pdf,\n              docx, epub, csv, pptx only</p>\n            <input type=\"file\" ref={fileInputRef} style={{display: 'none'}} onChange={handleFileInputChange}/>\n        </div>}\n      <ResourceList files={channel === 'output' ? output : input} channel={channel} runs={runs}/>\n    </div>\n    <ToastContainer/>\n  </>)\n}"
  },
  {
    "path": "gui/pages/Content/Agents/RunHistory.js",
    "content": "import React, {useEffect} from 'react';\nimport styles from './Agents.module.css';\nimport Image from \"next/image\";\nimport {formatNumber, formatTimeDifference} from \"@/utils/utils\";\nimport {EventBus} from \"@/utils/eventBus\";\n\nexport default function RunHistory({runs, setHistory, selectedRunId, setSelectedRun, setAgentExecutions}) {\n  useEffect(() => {\n    const resetRunStatus = (eventData) => {\n      const updatedExecutions = runs.map((run) => {\n        if (run.id === eventData.executionId) {\n          return {...run, status: eventData.status};\n        }\n        return run;\n      });\n\n      setAgentExecutions(updatedExecutions);\n    };\n\n    EventBus.on('resetRunStatus', resetRunStatus);\n\n    return () => {\n      EventBus.off('resetRunStatus', resetRunStatus);\n    };\n  });\n\n  return (<>\n    <div className=\"w_20 h_100\">\n      <div className=\"detail_top mt_8 mb_8\">\n        <div className=\"text_12 horizontal_container padding_0 gap_6\">\n          <Image width={16} height={16} src=\"/images/update.svg\" alt=\"update-icon\"/>\n          <div className=\"color_white lh_16\">Run history</div>\n        </div>\n        <Image className=\"cursor_pointer\" onClick={() => setHistory(false)} width={28} height={28} src=\"/images/close_history.svg\" alt=\"close-history-icon\"/>\n      </div>\n\n      <div className=\"detail_body mb_20\">\n        {runs && runs.map((run) => (<div key={run.id} onClick={() => setSelectedRun(run)} className={selectedRunId === run.id ? 'history_box_selected padding_10' : 'history_box padding_10'}>\n          <div className=\"horizontal_container mb_14\">\n            {run.status === 'RUNNING' && <Image className=\"mix_blend_mode mr_7\" width={14} height={14} src=\"/images/loading.gif\" alt=\"loading-icon\"/>}\n            <div className=\"text_ellipsis\">{run.name}</div>\n            {/*{run.notification_count > 0 && <div className={styles.notification_bubble}>{run.notification_count}</div>}*/}\n          </div>\n          <div className=\"horizontal_container align_center\">\n            <div className=\"horizontal_container w_fit_content\">\n              <Image width={12} height={12} src=\"/images/calls_made.svg\" alt=\"call-icon\"/>\n              <div className=\"text_10 ml_4\">{formatNumber(run?.num_of_calls || 0)} Calls</div>\n            </div>\n            <div className=\"horizontal_container ml_10 w_fit_content\">\n              <Image width={12} height={12} src=\"/images/schedule.svg\" alt=\"schedule-icon\"/>\n              <div className=\"text_10 ml_4\">\n                {formatTimeDifference(run.time_difference)}\n              </div>\n            </div>\n          </div>\n        </div>))}\n      </div>\n    </div>\n  </>)\n}"
  },
  {
    "path": "gui/pages/Content/Agents/TaskQueue.js",
    "content": "import React, {useEffect, useState} from 'react';\nimport styles from './Agents.module.css';\nimport 'react-toastify/dist/ReactToastify.css';\nimport {getExecutionTasks} from '@/pages/api/DashboardService';\nimport Image from \"next/image\";\n\nexport default function TaskQueue({selectedRunId}) {\n  const [tasks, setTasks] = useState({pending: [], completed: []});\n\n  useEffect(() => {\n    fetchTasks();\n  }, [selectedRunId]);\n\n  function fetchTasks() {\n    getExecutionTasks(selectedRunId)\n      .then((response) => {\n        setTasks({\n          pending: response.data.tasks,\n          completed: response.data.completed_tasks,\n        });\n      })\n      .catch((error) => {\n        console.error('Error fetching execution feeds:', error);\n      });\n  }\n\n  return (\n    <>\n      {tasks.pending.length <= 0 && tasks.completed.length <= 0 ? <div style={{\n        display: 'flex',\n        flexDirection: 'column',\n        alignItems: 'center',\n        justifyContent: 'center',\n        marginTop: '40px',\n        width: '100%'\n      }}>\n        <Image width={150} height={60} src=\"/images/no_permissions.svg\" alt=\"no-permissions\"/>\n        <span className={styles.feed_title} style={{marginTop: '8px'}}>No Tasks found!</span>\n      </div> : <div>\n        {tasks.pending.length > 0 && <div className={styles.task_header}>Pending Tasks</div>}\n        {tasks.pending.map((task, index) => (\n          <div key={index} className={styles.history_box}\n               style={{background: '#272335', padding: '20px', cursor: 'default'}}>\n            <div style={{display: 'flex'}}>\n              <div>\n                <Image width={14} height={14} style={{mixBlendMode: 'exclusion'}} src=\"/images/loading.gif\"\n                       alt=\"loading-icon\"/>\n              </div>\n              <div className={styles.feed_title}>\n                {task.name}\n              </div>\n            </div>\n          </div>\n        ))}\n        {tasks.completed.length > 0 && <div className={styles.task_header}>Completed Tasks</div>}\n        {tasks.completed.map((task, index) => (\n          <div key={index} className={styles.history_box}\n               style={{background: '#272335', padding: '20px', cursor: 'default'}}>\n            <div style={{display: 'flex'}}>\n              <div className={styles.feed_title} style={{marginLeft: '0'}}>\n                {task.name}\n              </div>\n            </div>\n          </div>\n        ))}\n      </div>}\n    </>\n  );\n}\n"
  },
  {
    "path": "gui/pages/Content/Agents/react-datetime.css",
    "content": ".rdt {\n  position: relative;\n}\n\n.rdtPicker {\n  display: none;\n  position: absolute;\n  min-width: 250px;\n  padding: 4px;\n  margin-top: 1px;\n  z-index: 99999 !important;\n  background: #1F1B32;\n  box-shadow: 0 1px 3px rgba(0,0,0,.1);\n  border-radius: 8px;\n  color:white;\n}\n\n.rdtOpen .rdtPicker {\n  display: block;\n}\n\n.rdtStatic .rdtPicker {\n  box-shadow: none;\n  position: static;\n}\n\n.rdtPicker .rdtTimeToggle {\n  text-align: center;\n}\n\n.rdtPicker table {\n  width: 100%;\n  margin: 0;\n}\n\n.rdtPicker td,\n.rdtPicker th {\n  text-align: center;\n  height: 28px;\n}\n\n.rdtPicker td {\n  cursor: pointer;\n}\n\n.rdtPicker td.rdtDay:hover,\n.rdtPicker td.rdtHour:hover,\n.rdtPicker td.rdtMinute:hover,\n.rdtPicker td.rdtSecond:hover,\n.rdtPicker .rdtTimeToggle:hover {\n  background: grey;\n  cursor: pointer;\n}\n\n.rdtPicker td.rdtOld,\n.rdtPicker td.rdtNew {\n  color: #999999;\n}\n\n.rdtPicker td.rdtToday {\n  position: relative;\n}\n\n.rdtPicker td.rdtToday:before {\n  content: '';\n  display: inline-block;\n  border-left: 7px solid transparent;\n  border-bottom: 7px solid #428bca;\n  border-top-color: rgba(0, 0, 0, 0.2);\n  position: absolute;\n  bottom: 4px;\n  right: 4px;\n}\n\n.rdtPicker td.rdtActive,\n.rdtPicker td.rdtActive:hover {\n  background-color: #428bca;\n  color:#fff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n\n.rdtPicker td.rdtActive.rdtToday:before {\n  border-bottom-color: #fff;\n}\n\n.rdtPicker td.rdtDisabled,\n.rdtPicker td.rdtDisabled:hover {\n  background: none;\n  color: #999999;\n  cursor: not-allowed;\n}\n\n.rdtPicker td span.rdtOld {\n  color: #999999;\n}\n\n.rdtPicker td span.rdtDisabled,\n.rdtPicker td span.rdtDisabled:hover {\n  background: none;\n  color: #999999;\n  cursor: not-allowed;\n}\n\n.rdtPicker th {\n  border-bottom: 1px solid #f9f9f9;\n}\n\n.rdtPicker .dow {\n  width: 14.2857%;\n  border-bottom: none;\n  cursor: default;\n}\n\n.rdtPicker th.rdtSwitch {\n  width: 100px;\n}\n\n.rdtPicker th.rdtSwitch:hover {\n  background-color: grey;\n}\n\n.rdtPicker th.rdtNext,\n.rdtPicker th.rdtPrev {\n  font-size: 21px;\n  vertical-align: top;\n}\n\n.rdtSwitch:hover{\n  background-color: grey !important;\n}\n\n.rdtPrev:hover{\n  background-color: grey !important;\n}\n\n.rdtNext:hover{\n  background-color: grey !important;\n}\n\n.rdtPrev span,\n.rdtNext span {\n  display: block;\n  -webkit-touch-callout: none; /* iOS Safari */\n  -webkit-user-select: none;   /* Chrome/Safari/Opera */\n  -khtml-user-select: none;    /* Konqueror */\n  -moz-user-select: none;      /* Firefox */\n  -ms-user-select: none;       /* Internet Explorer/Edge */\n  user-select: none;\n}\n\n.rdtPicker th.rdtDisabled,\n.rdtPicker th.rdtDisabled:hover {\n  background: none;\n  color: #999999;\n  cursor: not-allowed;\n}\n\n.rdtPicker thead tr:first-of-type th {\n  cursor: pointer;\n}\n\n.rdtPicker thead tr:first-of-type th:hover {\n  background: #eeeeee;\n}\n\n.rdtPicker tfoot {\n  border-top: 1px solid #f9f9f9;\n}\n\n.rdtPicker button {\n  border: none;\n  background: none;\n  cursor: pointer;\n}\n\n.rdtPicker button:hover {\n  background-color: grey;\n}\n\n.rdtPicker thead button {\n  width: 100%;\n  height: 100%;\n}\n\ntd.rdtMonth,\ntd.rdtYear {\n  height: 50px;\n  width: 25%;\n  cursor: pointer;\n}\n\ntd.rdtMonth:hover,\ntd.rdtYear:hover {\n  background: grey;\n}\n\n.rdtCounters {\n  display: inline-block;\n}\n\n.rdtCounters > div {\n  float: left;\n}\n\n.rdtCounter {\n  height: 100px;\n}\n\n.rdtCounter {\n  width: 40px;\n}\n\n.rdtCounterSeparator {\n  line-height: 100px;\n}\n\n.rdtCounter .rdtBtn {\n  height: 40%;\n  line-height: 40px;\n  cursor: pointer;\n  display: block;\n  margin-top: 5px !important;\n\n  -webkit-touch-callout: none; /* iOS Safari */\n  -webkit-user-select: none;   /* Chrome/Safari/Opera */\n  -khtml-user-select: none;    /* Konqueror */\n  -moz-user-select: none;      /* Firefox */\n  -ms-user-select: none;       /* Internet Explorer/Edge */\n  user-select: none;\n}\n\n.rdtCounter .rdtBtn:hover {\n  background: grey;\n}\n\n.rdtCounter .rdtCount {\n  height: 20%;\n  font-size: 1.2em;\n}\n\n.rdtMilli {\n  vertical-align: middle;\n  padding-left: 8px;\n  width: 48px;\n}\n\n.rdtMilli input {\n  width: 100%;\n  font-size: 1.2em;\n  margin-top: 37px;\n}\n\n.rdtTime td {\n  cursor: default;\n}"
  },
  {
    "path": "gui/pages/Content/Knowledge/AddKnowledge.js",
    "content": "import React, {useState, useEffect} from 'react';\nimport KnowledgeForm from \"@/pages/Content/Knowledge/KnowledgeForm\";\n\nexport default function AddKnowledge({internalId, sendKnowledgeData}) {\n  const [knowledgeName, setKnowledgeName] = useState('');\n  const [knowledgeDescription, setKnowledgeDescription] = useState('');\n  const [selectedIndex, setSelectedIndex] = useState(null);\n\n  useEffect(() => {\n    const knowledge_name = localStorage.getItem(\"knowledge_name_\" + String(internalId))\n    if (knowledge_name) {\n      setKnowledgeName(knowledge_name);\n    }\n\n    const knowledge_description = localStorage.getItem(\"knowledge_description_\" + String(internalId))\n    if (knowledge_description) {\n      setKnowledgeDescription(knowledge_description);\n    }\n\n    const knowledge_index = localStorage.getItem(\"knowledge_index_\" + String(internalId))\n    if (knowledge_index) {\n      setSelectedIndex(JSON.parse(knowledge_index));\n    }\n  }, [internalId])\n\n  return (<>\n    <div className=\"row\">\n      <div className=\"col-3\"></div>\n      <div className=\"col-6 col-6-scrollable\">\n        <KnowledgeForm internalId={internalId}\n                       knowledgeId={null}\n                       knowledgeName={knowledgeName}\n                       setKnowledgeName={setKnowledgeName}\n                       knowledgeDescription={knowledgeDescription}\n                       setKnowledgeDescription={setKnowledgeDescription}\n                       selectedIndex={selectedIndex}\n                       setSelectedIndex={setSelectedIndex}\n                       isEditing={false}\n                       setIsEditing={null}\n                       sendKnowledgeData={sendKnowledgeData}\n        />\n      </div>\n      <div className=\"col-3\"></div>\n    </div>\n  </>)\n}"
  },
  {
    "path": "gui/pages/Content/Knowledge/Knowledge.js",
    "content": "import React from 'react';\nimport Image from \"next/image\";\nimport styles from '../Toolkits/Tool.module.css';\nimport styles1 from '../Agents/Agents.module.css'\nimport {createInternalId, getUserClick} from \"@/utils/utils\";\n\nexport default function Knowledge({sendKnowledgeData, knowledge}) {\n  return (\n    <>\n      <div className=\"container\">\n        <p className=\"text_14 mt_8 mb_12 ml_8\">Knowledges</p>\n        <div className=\"w_100 mb_10\">\n          <button className=\"secondary_button w_100\" onClick={() => {sendKnowledgeData({\n            id: -6,\n            name: \"new knowledge\",\n            contentType: \"Add_Knowledge\",\n            internalId: createInternalId()\n          }); getUserClick('Knowledge Added', {})}}>\n            + Add Knowledge\n          </button>\n        </div>\n\n        {knowledge && knowledge.length > 0 ? (\n          <div className=\"vertical_selection_scroll\">\n            <div className={styles.tool_container}>\n              {knowledge.map((item, index) => (\n                <div key={index} className={styles.tool_box} onClick={() => sendKnowledgeData({\n                  id: item.id,\n                  name: item.name,\n                  contentType: \"Knowledge\",\n                  internalId: createInternalId()\n                })}>\n                  <div className=\"row\">\n                    <div className=\"col-12\">\n                      <div\n                        style={{display: 'flex', alignItems: 'center', justifyContent: 'flex-start', padding: '5px'}}>\n                        <div style={{marginLeft: '8px'}}>\n                          <div className={styles.tool_name}>{item.name}&nbsp;{item.is_marketplace &&\n                            <Image width={13} height={13} src=\"/images/widgets.svg\" alt=\"markteplace-icon\"/>}</div>\n                          <div className=\"item_publisher\">by {item.contributed_by}</div>\n                        </div>\n                      </div>\n                    </div>\n                  </div>\n                </div>)\n              )}\n            </div>\n          </div>\n        ) : (<div className=\"form_label mt_20 horizontal_container justify_center\">No Knowledge found</div>\n        )}\n      </div>\n    </>\n  );\n}"
  },
  {
    "path": "gui/pages/Content/Knowledge/Knowledge.module.css",
    "content": ".knowledge_label {\n    margin-bottom: 4px;\n    font-size: 12px;\n    color: #888888;\n}\n\n.knowledge_info {\n    font-size: 12px;\n    color: white;\n}\n\n.knowledge_info_box {\n    margin-bottom: 20px;\n}\n\n.knowledge_wrapper {\n    margin-bottom: 20px;\n    display: flex;\n    justify-content: space-between;\n}\n\n.knowledge_db {\n    font-size: 12px;\n    color: #888888;\n    font-weight: normal;\n    height: auto;\n    max-width: 240px;\n    white-space: nowrap;\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.knowledge_db_name {\n    padding:12px 14px;\n    border-top: 1px solid #888888;\n}\n\n.knowledge_alert {\n    border-radius: 8px;\n    background-color: #423D52;\n    border-left: 4px solid #B3B2BB;\n    color: white;\n    font-size: 12px;\n    padding: 12px 14px;\n    display: flex;\n    justify-content: flex-start;\n}\n\n.database_container {\n    background-color: rgb(39, 35, 53);\n    width: calc(33% - 10px);\n    padding: 10px;\n    color: white;\n    font-style: normal;\n    font-weight: 400;\n    font-size: 15px;\n    border-radius: 8px;\n    cursor: pointer;\n    text-align: center;\n}\n\n.database_wrapper {\n    display: flex;\n    justify-content: flex-start;\n    gap: 10px;\n    flex-wrap: wrap;\n}\n.installed_knowledge_card_class {\n    border-radius: 16px;\n    border: 1px solid rgba(255, 255, 255, 0.08);\n    background: rgba(255, 255, 255, 0.14);\n    display: flex;\n    padding: 4px 8px;\n    align-items: center;\n    gap: 6px;\n}\n\n.knowledge_options_dropdown{\n    right: 25px;\n    width: 165px;\n}"
  },
  {
    "path": "gui/pages/Content/Knowledge/KnowledgeDetails.js",
    "content": "import React, {useEffect, useState} from 'react';\nimport styles1 from './Knowledge.module.css'\nimport {ToastContainer, toast} from \"react-toastify\";\nimport styles from \"@/pages/Content/Toolkits/Tool.module.css\";\nimport Image from \"next/image\";\nimport KnowledgeForm from \"@/pages/Content/Knowledge/KnowledgeForm\";\nimport {deleteCustomKnowledge, deleteMarketplaceKnowledge, getKnowledgeDetails} from \"@/pages/api/DashboardService\";\nimport {removeTab, returnToolkitIcon, setLocalStorageValue} from \"@/utils/utils\";\nimport {EventBus} from \"@/utils/eventBus\";\nimport Metrics from \"@/pages/Content/Toolkits/Metrics\";\n\nexport default function KnowledgeDetails({internalId, knowledgeId}) {\n  const [showDescription, setShowDescription] = useState(false);\n  const [dropdown, setDropdown] = useState(false);\n  const [isEditing, setIsEditing] = useState(false);\n  const [knowledgeName, setKnowledgeName] = useState('');\n  const [knowledgeDescription, setKnowledgeDescription] = useState('');\n  const [installationType, setInstallationType] = useState('');\n  const [model, setModel] = useState('');\n  const [tokenizer, setTokenizer] = useState('');\n  const [chunkSize, setChunkSize] = useState('');\n  const [vectorDatabase, setVectorDatabase] = useState('');\n  const [knowledgeDatatype, setKnowledgeDatatype] = useState('');\n  const [textSplitters, setTextSplitters] = useState('');\n  const [chunkOverlap, setChunkOverlap] = useState('');\n  const [dimension, setDimension] = useState('');\n  const [vectorDBIndex, setVectorDBIndex] = useState('');\n  const [activeTab, setActiveTab] = useState('metrics');\n\n\n  const uninstallKnowledge = () => {\n    setDropdown(false);\n\n    if (installationType === 'Marketplace') {\n      deleteMarketplaceKnowledge(knowledgeName)\n        .then((response) => {\n          console.log(response)\n          toast.success(\"Knowledge uninstalled successfully\", {autoClose: 1800});\n            removeTab(knowledgeId, knowledgeName, \"Knowledge\", internalId);\n            EventBus.emit('reFetchKnowledge', {});\n        })\n        .catch((error) => {\n          toast.error(\"Unable to uninstall knowledge\", {autoClose: 1800});\n          console.error('Error uninstalling knowledge:', error);\n        });\n    } else {\n      deleteCustomKnowledge(knowledgeId)\n        .then((response) => {\n            toast.success(\"Knowledge uninstalled successfully\", {autoClose: 1800});\n          removeTab(knowledgeId, knowledgeName, \"Knowledge\", internalId);\n          EventBus.emit('reFetchKnowledge', {});\n        })\n        .catch((error) => {\n          toast.error(\"Unable to uninstall knowledge\", {autoClose: 1800});\n          console.error('Error uninstalling knowledge:', error);\n        });\n    }\n  }\n\n  const viewKnowledge = () => {\n    setDropdown(false);\n  }\n\n  const editKnowledge = () => {\n    setIsEditing(true);\n    setDropdown(false);\n  }\n\n  useEffect(() => {\n    if (knowledgeId) {\n      getKnowledgeDetails(knowledgeId)\n        .then((response) => {\n          const data = response.data || [];\n          setKnowledgeName(data.name);\n          setKnowledgeDescription(data.description);\n          setInstallationType(data.installation_type);\n          setModel(data.model);\n          setTokenizer(data.tokenizer);\n          setChunkSize(data.chunk_size);\n          setVectorDatabase(data.vector_database);\n          setKnowledgeDatatype(data.data_type);\n          setTextSplitters(data.text_splitter);\n          setChunkOverlap(data.chunk_overlap);\n          setDimension(data.dimensions);\n          setVectorDBIndex(data.vector_database_index);\n        })\n        .catch((error) => {\n          console.error('Error fetching knowledge details:', error);\n        });\n    }\n  }, [internalId]);\n\n  return (<>\n    <div className=\"row\">\n      <div className=\"col-12 col-6-scrollable\">\n        <div className=\"horizontal_container align_start mb_20\">\n          <div className=\"vertical_containers text_align_left mr_10 w_97\">\n            <div className=\"text_17\">{knowledgeName}</div>\n            <div className=\"text_12\" >\n              {knowledgeDescription}\n            </div>\n          </div>\n            <div className=\"w_3\">\n                <button className=\"secondary_button padding_8 h_31p\"\n                        onMouseEnter={() => setDropdown(true)} onMouseLeave={() => setDropdown(false)}>\n                    <Image width={14} height={14} src=\"/images/three_dots.svg\" alt=\"run-icon\"/>\n                </button>\n                {dropdown && <div onMouseEnter={() => setDropdown(true)} onMouseLeave={() => setDropdown(false)}>\n                    <ul className={`${\"dropdown_container\"} ${styles1.knowledge_options_dropdown}`}>\n                        {installationType !== 'Marketplace' &&\n                            // <li className=\"dropdown_item\" onClick={viewKnowledge}>View in marketplace</li> :\n                            <li className=\"dropdown_item\" onClick={editKnowledge}>Edit details</li>}\n                        <li className=\"dropdown_item\" onClick={uninstallKnowledge}>Uninstall knowledge</li>\n                    </ul>\n                </div>}\n            </div>\n        </div>\n        <div className=\"horizontal_container mb_10 border_bottom_grey pd_bottom_5\">\n          <div className={activeTab === 'metrics' ? 'tab_button_small_selected' : 'tab_button_small'}\n               onClick={() => setActiveTab('metrics')}>\n            <div className=\"text_12 color_white padding_8\">Metrics</div>\n          </div>\n          <div className={activeTab === 'configuration' ? 'tab_button_small_selected' : 'tab_button_small'}\n               onClick={() => setActiveTab('configuration')}>\n            <div className=\"text_12 color_white padding_8\">Configuration</div>\n          </div>\n        </div>\n        {activeTab === 'metrics' && <div>\n          <Metrics knowledgeName={knowledgeName} />\n        </div>}\n        { activeTab === \"configuration\" && <div className=\"row\">\n          <div className=\"col-3\" />\n          <div className=\"col-6\">\n        {isEditing ?\n          <KnowledgeForm internalId={internalId}\n                         knowledgeId={knowledgeId}\n                         knowledgeName={knowledgeName}\n                         setKnowledgeName={setKnowledgeName}\n                         knowledgeDescription={knowledgeDescription}\n                         setKnowledgeDescription={setKnowledgeDescription}\n                         selectedIndex={vectorDBIndex}\n                         setSelectedIndex={setVectorDBIndex}\n                         isEditing={true}\n                         setIsEditing={setIsEditing}\n                         sendKnowledgeData={null}\n          /> :\n          <div>\n            {installationType === 'Marketplace' && <div className={`${styles1.knowledge_wrapper} ${\"col-6\"} ${\"w_100\"}`}>\n              <div className=\"w_50\">\n                <div className={styles1.knowledge_info_box}>\n                  <label className={styles1.knowledge_label}>Installation Type</label>\n                  <div className={styles1.knowledge_info}>{installationType}</div>\n                </div>\n                <div className={styles1.knowledge_info_box}>\n                  <label className={styles1.knowledge_label}>Model</label>\n                  <div className={styles1.knowledge_info}>{model}</div>\n                </div>\n                <div className={styles1.knowledge_info_box}>\n                  <label className={styles1.knowledge_label}>Tokenizer</label>\n                  <div className={styles1.knowledge_info}>{tokenizer}</div>\n                </div>\n                <div className={styles1.knowledge_info_box}>\n                  <label className={styles1.knowledge_label}>Chunk Size</label>\n                  <div className={styles1.knowledge_info}>{chunkSize}</div>\n                </div>\n                <div className={styles1.knowledge_info_box}>\n                  <label className={styles1.knowledge_label}>Vector Database</label>\n                  <div className={styles1.knowledge_info}>{vectorDatabase}</div>\n                </div>\n              </div>\n              <div style={{width: '50%'}}>\n                <div className={styles1.knowledge_info_box}>\n                  <label className={styles1.knowledge_label}>Knowledge datatype</label>\n                  <div className={styles1.knowledge_info}>{knowledgeDatatype}</div>\n                </div>\n                <div className={styles1.knowledge_info_box}>\n                  <label className={styles1.knowledge_label}>Text splitters</label>\n                  <div className={styles1.knowledge_info}>{textSplitters}</div>\n                </div>\n                <div className={styles1.knowledge_info_box}>\n                  <label className={styles1.knowledge_label}>Chunk overlap</label>\n                  <div className={styles1.knowledge_info}>{chunkOverlap}</div>\n                </div>\n                <div className={styles1.knowledge_info_box}>\n                  <label className={styles1.knowledge_label}>Dimension</label>\n                  <div className={styles1.knowledge_info}>{dimension}</div>\n                </div>\n                <div className={styles1.knowledge_info_box}>\n                  <label className={styles1.knowledge_label}>Vector database index</label>\n                  <div className={styles1.knowledge_info}>{vectorDBIndex?.name || ''}</div>\n                </div>\n              </div>\n            </div>}\n            {installationType === 'Custom' && <div className={styles1.knowledge_wrapper}>\n              <div style={{width: '50%'}}>\n                <div className={styles1.knowledge_info_box}>\n                  <label className={styles1.knowledge_label}>Installation Type</label>\n                  <div className={styles1.knowledge_info}>{installationType}</div>\n                </div>\n                <div className={styles1.knowledge_info_box}>\n                  <label className={styles1.knowledge_label}>Vector database index</label>\n                  <div className={styles1.knowledge_info}>{vectorDBIndex?.name || ''}</div>\n                </div>\n              </div>\n              <div style={{width: '50%'}}>\n                <div className={styles1.knowledge_info_box}>\n                  <label className={styles1.knowledge_label}>Vector Database</label>\n                  <div className={styles1.knowledge_info}>{vectorDatabase}</div>\n                </div>\n              </div>\n            </div>}\n          </div>}\n          </div>\n          <div className=\"col-3\" />\n        </div>}\n      </div>\n    </div>\n    <ToastContainer/>\n  </>);\n}"
  },
  {
    "path": "gui/pages/Content/Knowledge/KnowledgeForm.js",
    "content": "import React, {useState, useEffect, useRef} from 'react';\nimport styles1 from '@/pages/Content/Knowledge/Knowledge.module.css'\nimport {removeTab, setLocalStorageValue, setLocalStorageArray, createInternalId, getUserClick} from \"@/utils/utils\";\nimport styles from \"@/pages/Content/Agents/Agents.module.css\";\nimport Image from \"next/image\";\nimport {ToastContainer, toast} from \"react-toastify\";\nimport {addUpdateKnowledge, getValidIndices} from \"@/pages/api/DashboardService\";\nimport {EventBus} from \"@/utils/eventBus\";\n\nexport default function KnowledgeForm({\n                                        internalId,\n                                        knowledgeId,\n                                        knowledgeName,\n                                        setKnowledgeName,\n                                        knowledgeDescription,\n                                        setKnowledgeDescription,\n                                        selectedIndex,\n                                        setSelectedIndex,\n                                        isEditing,\n                                        setIsEditing,\n                                        sendKnowledgeData\n                                      }) {\n  const [addClickable, setAddClickable] = useState(true);\n  const indexRef = useRef(null);\n  const [indexDropdown, setIndexDropdown] = useState(false);\n  const [pinconeIndices, setPineconeIndices] = useState([]);\n  const [qdrantIndices, setQdrantIndices] = useState([]);\n  const [weaviateIndices, setWeaviateIndices] = useState([]);\n\n  useEffect(() => {\n    getValidIndices()\n      .then((response) => {\n        const data = response.data || [];\n        if (data) {\n          setPineconeIndices(data.pinecone || []);\n          setQdrantIndices(data.qdrant || []);\n          setWeaviateIndices(data.weaviate || []);\n        }\n      })\n      .catch((error) => {\n        console.error('Error fetching indices:', error);\n      });\n  }, []);\n\n  useEffect(() => {\n    function handleClickOutside(event) {\n      if (indexRef.current && !indexRef.current.contains(event.target)) {\n        setIndexDropdown(false);\n      }\n    }\n\n    document.addEventListener('mousedown', handleClickOutside);\n    return () => {\n      document.removeEventListener('mousedown', handleClickOutside);\n    };\n  }, []);\n\n  const handleNameChange = (event) => {\n    setLocalStorageValue(\"knowledge_name_\" + String(internalId), event.target.value, setKnowledgeName);\n  };\n\n  const handleDescriptionChange = (event) => {\n    setLocalStorageValue(\"knowledge_description_\" + String(internalId), event.target.value, setKnowledgeDescription);\n  };\n\n  function validationCheck() {\n    let isValid = true;\n\n    if (knowledgeName.replace(/\\s/g, '') === '') {\n      toast.error(\"Knowledge name can't be blank\", {autoClose: 1800});\n      isValid = false;\n    }\n\n    if (!selectedIndex) {\n      toast.error(\"Please select an index\", {autoClose: 1800});\n      isValid = false;\n    }\n\n    return isValid;\n  }\n\n  const handleAddKnowledge = () => {\n    if (!validationCheck()) {\n      return\n    }\n\n    const knowledgeData = {\n      \"id\": 0,\n      \"name\": knowledgeName,\n      \"description\": knowledgeDescription,\n      \"index_id\": selectedIndex.id\n    }\n\n    addUpdateKnowledge(knowledgeData)\n      .then((response) => {\n        toast.success(\"Knowledge added successfully\", {autoClose: 1800});\n        sendKnowledgeData({\n          id: response.data.id,\n          name: knowledgeName,\n          contentType: \"Knowledge\",\n          internalId: createInternalId()\n        });\n        EventBus.emit('reFetchKnowledge', {});\n        getUserClick('Knowledge Added Successfully', {})\n      })\n      .catch((error) => {\n        toast.error(\"Unable to add knowledge\", {autoClose: 1800});\n        console.error('Error deleting knowledge:', error);\n      });\n\n    setAddClickable(false);\n  }\n\n  const handleUpdateKnowledge = () => {\n    if (!validationCheck()) {\n      return\n    }\n\n    const knowledgeData = {\n      \"id\": knowledgeId,\n      \"name\": knowledgeName,\n      \"description\": knowledgeDescription,\n      \"index_id\": selectedIndex.id\n    }\n\n    addUpdateKnowledge(knowledgeData)\n      .then((response) => {\n        toast.success(\"Knowledge updated successfully\", {autoClose: 1800});\n        EventBus.emit('reFetchKnowledge', {});\n      })\n      .catch((error) => {\n        toast.error(\"Unable to update knowledge\", {autoClose: 1800});\n        console.error('Error deleting knowledge:', error);\n      });\n\n    setIsEditing(false);\n    setAddClickable(false);\n  }\n\n  const handleIndexSelect = (index) => {\n    if(index.is_valid_state) {\n      setLocalStorageArray(\"knowledge_index_\" + String(internalId), index, setSelectedIndex);\n      setIndexDropdown(false);\n    }\n    else{\n      toast.error('Select valid index', {autoClose: 1800})\n    }\n  }\n\n  const checkIndexValidity = (validState) => {\n    let errorMessage = \"\";\n    let isValid = true;\n\n    if (!validState) {\n      isValid = false;\n      errorMessage = \"The configured index is either empty or has marketplace knowledge\";\n    }\n\n    return [isValid, errorMessage];\n  }\n\n  return (<>\n    <div>\n      <div className={styles.page_title}>{isEditing ? 'Edit knowledge' : 'Add a new knowledge'}</div>\n    </div>\n    <div style={{marginTop: '10px'}}>\n      <div className={styles1.knowledge_alert}>\n        <div style={{marginRight: '5px', marginLeft: '-5px'}}>\n          <Image width={20} height={20} src='/images/info.svg' alt=\"info-icon\"/>\n        </div>\n        <div>\n          Currently we support Open AI “text-embedding-ada-002” model knowledge only. Please make sure you add the same.\n        </div>\n      </div>\n    </div>\n    <div style={{marginTop: '10px'}}>\n      <div>\n        <label className={styles.form_label}>Knowledge name</label>\n        <input className=\"input_medium\" type=\"text\" value={knowledgeName} onChange={handleNameChange}/>\n      </div>\n      <div style={{marginTop: '15px'}}>\n        <label className={styles.form_label}>Description</label><br/>\n        <label className={styles.form_label}>This description will be passed to the agent as knowledge context.</label>\n        <textarea className=\"textarea_medium\" rows={3} value={knowledgeDescription} onChange={handleDescriptionChange}/>\n      </div>\n      <div style={{marginTop: '15px'}}>\n        <label className={styles.form_label}>Collection/Index</label><br/>\n        <div className=\"dropdown_container_search\" style={{width: '100%'}}>\n          <div className=\"custom_select_container\" onClick={() => setIndexDropdown(!indexDropdown)}\n               style={{width: '100%', color: !selectedIndex ? '#888888' : ''}}>\n            {selectedIndex?.name || 'Select Index'}<Image width={20} height={21}\n                                                          src={!indexDropdown ? '/images/dropdown_down.svg' : '/images/dropdown_up.svg'}\n                                                          alt=\"expand-icon\"/>\n          </div>\n          <div>\n            {indexDropdown && <div className=\"custom_select_options\" ref={indexRef} style={{width: '100%'}}>\n              <div className={styles1.knowledge_label} style={{padding: '12px 14px', maxWidth: '100%'}}>Select an\n                existing vector database collection/index to install the knowledge\n              </div>\n              {pinconeIndices && pinconeIndices.length > 0 &&\n                <div className={styles1.knowledge_db} style={{maxWidth: '100%'}}>\n                  <div className={styles1.knowledge_db_name}>Pinecone</div>\n                  {pinconeIndices.map((index) => (<div key={index.id} className=\"custom_select_option index_options\"\n                                                       onClick={() => handleIndexSelect(index)}>\n                    <div style={!checkIndexValidity(index.is_valid_state)[0] ? {\n                      color: '#888888',\n                      textDecoration: 'line-through',\n                      pointerEvents : 'none',\n                    } : {}}>{index.name}</div>\n                    {!checkIndexValidity(index.is_valid_state)[0] &&\n                      <div>\n                        <Image width={15} height={15} src=\"/images/info.svg\" alt=\"info-icon\"\n                               title={checkIndexValidity(index.is_valid_state)[1]}/>\n                      </div>}\n                  </div>))}\n                </div>}\n              {qdrantIndices && qdrantIndices.length > 0 &&\n                <div className={styles1.knowledge_db} style={{maxWidth: '100%'}}>\n                  <div className={styles1.knowledge_db_name}>Qdrant</div>\n                  {qdrantIndices.map((index) => (<div key={index.id} className=\"custom_select_option index_options\"\n                                                      onClick={() => handleIndexSelect(index)}>\n                    <div style={!checkIndexValidity(index.is_valid_state)[0] ? {\n                      color: '#888888',\n                      textDecoration: 'line-through',\n                      pointerEvents : 'none',\n                    } : {}}>{index.name}</div>\n                    {!checkIndexValidity(index.is_valid_state)[0] &&\n                      <div>\n                        <Image width={15} height={15} src=\"/images/info.svg\" alt=\"info-icon\"\n                               title={checkIndexValidity(index.is_valid_state)[1]}/>\n                      </div>}\n                  </div>))}\n                </div>}\n              {weaviateIndices && weaviateIndices.length > 0 &&\n                <div className={styles1.knowledge_db} style={{maxWidth: '100%'}}>\n                  <div className={styles1.knowledge_db_name}>Weaviate</div>\n                  {weaviateIndices.map((index) => (<div key={index.id} className=\"custom_select_option index_options\"\n                                                      onClick={() => handleIndexSelect(index)}>\n                    <div style={!checkIndexValidity(index.is_valid_state)[0] ? {\n                      color: '#888888',\n                      textDecoration: 'line-through',\n                      pointerEvents : 'none',\n                    } : {}}>{index.name}</div>\n                    {!checkIndexValidity(index.is_valid_state)[0] &&\n                      <div>\n                        <Image width={15} height={15} src=\"/images/info.svg\" alt=\"info-icon\"\n                               title={checkIndexValidity(index.is_valid_state)[1]}/>\n                      </div>}\n                  </div>))}\n                </div>}\n            </div>}\n          </div>\n        </div>\n      </div>\n      {isEditing ? <div style={{marginTop: '15px', display: 'flex', justifyContent: 'flex-end'}}>\n        <button style={{marginRight: '7px'}} className=\"secondary_button\" onClick={() => setIsEditing(false)}>Cancel\n        </button>\n        <button disabled={!addClickable} className=\"primary_button\" onClick={handleUpdateKnowledge}>Update Changes\n        </button>\n      </div> : <div style={{marginTop: '15px', display: 'flex', justifyContent: 'flex-end'}}>\n        <button style={{marginRight: '7px'}} className=\"secondary_button\"\n                onClick={() => removeTab(-6, \"new knowledge\", \"Add_Knowledge\", internalId)}>Cancel\n        </button>\n        <button disabled={!addClickable} className=\"primary_button\" onClick={handleAddKnowledge}>Add knowledge</button>\n      </div>}\n    </div>\n    <ToastContainer/>\n  </>)\n}"
  },
  {
    "path": "gui/pages/Content/Marketplace/AgentTemplate.js",
    "content": "import React, {useEffect, useState} from 'react';\nimport Image from \"next/image\";\nimport styles from '.././Toolkits/Tool.module.css';\nimport styles1 from '../Agents/Agents.module.css'\nimport {ToastContainer, toast} from 'react-toastify';\nimport 'react-toastify/dist/ReactToastify.css';\nimport styles2 from \"./Market.module.css\"\nimport {fetchAgentTemplateConfig, installAgentTemplate} from \"@/pages/api/DashboardService\";\nimport {EventBus} from \"@/utils/eventBus\";\nimport axios from 'axios';\nimport {getUserClick, loadingTextEffect} from \"@/utils/utils\";\n\nexport default function AgentTemplate({template, env}) {\n  const [tools, setTools] = useState([])\n  const [agentWorkflow, setAgentWorkflow] = useState('')\n  const [templateModel, setTemplateModel] = useState('')\n  const [rightPanel, setRightPanel] = useState('overview')\n  const [goals, setGoals] = useState([])\n  const [instructions, setInstructions] = useState([])\n  const [installed, setInstalled] = useState('')\n  const [constraints, setConstraints] = useState([])\n  const [isLoading, setIsLoading] = useState(true)\n  const [loadingText, setLoadingText] = useState(\"Loading Template Details\")\n  const [isInstalled, setIsInstalled] = useState(false)\n\n  useEffect(() => {\n    loadingTextEffect('Loading Template Details', setLoadingText, 500);\n    if (window.location.href.toLowerCase().includes('marketplace')) {\n      setInstalled('Sign in to install')\n      axios.get(`https://app.superagi.com/api/agent_templates/marketplace/template_details/${template.id}`)\n        .then((response) => {\n          const data = response.data || [];\n          setValues(data)\n        })\n        .catch((error) => {\n          console.error('Error fetching agent templates:', error);\n        });\n    } else {\n      setInstalled(template && template.is_installed ? 'Installed' : 'Install');\n      fetchAgentTemplateConfig(template.id)\n        .then((response) => {\n          const data = response.data || [];\n          setValues(data)\n        })\n        .catch((error) => {\n          console.error('Error fetching template details:', error);\n        });\n    }\n  }, []);\n\n  function setValues(data) {\n    setAgentWorkflow(data.agent_workflow_name)\n    setTemplateModel(data.configs.model.value)\n    setGoals(data.configs.goal.value)\n    setConstraints(data.configs.constraints.value)\n    setTools(data.configs.tools.value)\n    setInstructions(data.configs.instruction ? data.configs.instruction.value : null);\n    setIsLoading(false)\n  }\n\n  function handleInstallClick() {\n    setIsInstalled(true)\n    getUserClick(\"Agent Template Installed\",{\"Agent Template Name\": template.name})\n    if (window.location.href.toLowerCase().includes('marketplace')) {\n      localStorage.setItem('agent_to_install', template.id);\n      if (env === 'PROD') {\n        window.open(`https://app.superagi.com/`, '_self');\n      } else {\n        window.location.href = '/';\n      }\n      return;\n    }\n\n    if (template && template.is_installed) {\n      toast.error(\"Template is already installed\", {autoClose: 1800});\n      return;\n    }\n\n    installAgentTemplate(template.id)\n      .then((response) => {\n        toast.success(\"Template installed\", {autoClose: 1800});\n        setInstalled('Installed');\n      })\n      .catch((error) => {\n        console.error('Error installing template:', error);\n      });\n  }\n\n  function handleBackClick() {\n    EventBus.emit('goToMarketplace', {});\n  }\n\n  return (\n    <>\n      <div>\n        {!isLoading ? <div className=\"row\" style={{marginLeft: 'auto'}}>\n          <div className={styles2.back_button} style={{margin: '8px 0', padding: '2px'}}\n               onClick={() => handleBackClick()}>\n            <Image src=\"/images/arrow_back.svg\" alt=\"back_button\" width={14} height={12}/>\n            <span className={styles2.back_button_text}>Back</span>\n          </div>\n          <div className=\"col-3\" style={{maxHeight: '84vh', overflowY: 'auto', padding: '0'}}>\n            <div className={styles2.left_container}>\n              <span className={styles2.top_heading}>{template.name}</span>\n              <span style={{fontSize: '12px', marginTop: '15px',}} className={styles.tool_publisher}>By SuperAGI <Image\n                width={14} height={14} src=\"/images/is_verified.svg\" alt=\"is_verified\"/>&nbsp;{'\\u00B7'}&nbsp;<Image\n                width={14} height={14} src=\"/images/upload_icon.svg\" alt=\"upload-icon\"/></span>\n              {isInstalled || (template && template.is_installed) ? (\n                  <button\n                      className=\"primary_button\"\n                      style={{\n                        marginTop: '15px',\n                        width: '100%',\n                        background: 'rgba(255, 255, 255, 0.14)',\n                        color: '#FFFFFF'\n                      }}\n                  >\n                    <Image width={14} height={14} src=\"/images/tick.svg\" alt=\"tick-icon\"/>&nbsp; Installed\n                  </button>\n              ) : (\n                  <button\n                      className=\"primary_button\"\n                      style={{\n                        marginTop: '15px',\n                        width: '100%',\n                        background: '#FFF',\n                        color: '#000'\n                      }}\n                      onClick={() => handleInstallClick()}\n                  >\n                    <Image width={14} height={14} src=\"/images/upload_icon_dark.svg\" alt=\"upload-icon\"/>&nbsp; Install\n                  </button>\n              )}\n\n              <hr className={styles2.horizontal_line}/>\n\n              <span className={styles2.description_text}>{template.description}</span>\n\n              <hr className={styles2.horizontal_line}/>\n\n              <span style={{fontSize: '12px',}} className={styles.tool_publisher}>Tools</span>\n              <div className={styles1.agent_info_tools} style={{marginTop: '10px'}}>\n                {tools.map((tool, index) => (\n                  <div key={index} className=\"tool_container\" style={{marginTop: '0', marginBottom: '5px'}}>\n                    <div className={styles1.tool_text}>{tool || ''}</div>\n                  </div>))}\n              </div>\n              <br/>\n              <span style={{fontSize: '12px'}} className={styles.tool_publisher}>Agent Workflow</span>\n              <div className=\"tool_container\" style={{marginTop: '10px', width: 'fit-content'}}>\n                <div className={styles1.tool_text}>{agentWorkflow}</div>\n              </div>\n              <br/>\n              <span style={{fontSize: '12px'}} className={styles.tool_publisher}>Model(s)</span>\n              <div className=\"tool_container\" style={{marginTop: '10px', width: 'fit-content'}}>\n                <div className={styles1.tool_text}>{templateModel}</div>\n              </div>\n\n              <hr className={styles2.horizontal_line}/>\n\n              <span style={{fontSize: '12px',}} className={styles.tool_publisher}>Last updated</span>\n              <span className={styles2.description_text}>{template.updated_at}</span>\n            </div>\n          </div>\n          <div className=\"col-9\" style={{paddingLeft: '8px'}}>\n            {/*<div className={styles2.left_container} style={{marginBottom:'5px'}}>*/}\n            {/*    <div className=\"row\">*/}\n            {/*        <div className=\"col-4\">*/}\n            {/*            <button onClick={() => setRightPanel('overview')} className={styles2.tab_button} style={rightPanel === 'overview' ? {background:'#454254',paddingRight:'15px'} : {background:'transparent',paddingRight:'15px'}}>*/}\n            {/*                &nbsp;Overview*/}\n            {/*            </button>*/}\n            {/*            <button onClick={() => setRightPanel('tool_view')} className={styles2.tab_button} style={rightPanel === 'tool_view' ? {background:'#454254',paddingRight:'15px'} : {background:'transparent',paddingRight:'15px'}}>*/}\n            {/*                &nbsp;Toolkits Included*/}\n            {/*            </button>*/}\n            {/*        </div>*/}\n            {/*    </div>*/}\n            {/*</div>*/}\n            <div style={{maxHeight: '84vh', overflowY: 'auto'}}>\n              <div className={styles2.left_container} style={{marginBottom: '8px'}}>\n                <div>\n                  <span className={styles2.description_heading}\n                        style={{fontWeight: '400'}}>{goals.length}&nbsp;Goals</span><br/><br/>\n                  {goals.map((goal, index) => (<div key={index} style={{marginTop: '0'}}>\n                    <div className={styles2.description_text}>{index + 1}. {goal || ''}</div>\n                    {index !== goals.length - 1}\n                  </div>))}\n                </div>\n              </div>\n              {instructions && instructions.length > 0 &&\n                <div className={styles2.left_container} style={{marginBottom: '8px'}}>\n                  <div>\n                    <span className={styles2.description_heading}\n                          style={{fontWeight: '400'}}>{instructions.length} Instructions</span><br/><br/>\n                    {instructions.map((instruction, index) => (\n                      <div key={index} style={{marginTop: '0'}}>\n                        <div className={styles2.description_text}>{index + 1}. {instruction || ''}</div>\n                      </div>))}\n                  </div>\n                </div>}\n              <div className={styles2.left_container} style={{marginBottom: '8px'}}>\n                <div>\n                  <span className={styles2.description_heading}\n                        style={{fontWeight: '400'}}>{constraints.length}&nbsp;Constraints</span><br/><br/>\n                  {constraints.map((goal, index) => (<div key={index} style={{marginTop: '0'}}>\n                    <div className={styles2.description_text}>{index + 1}. {goal || ''}</div>\n                    {index !== constraints.length - 1}\n                  </div>))}\n                </div>\n              </div>\n            </div>\n          </div>\n        </div> : <div style={{display: 'flex', justifyContent: 'center', alignItems: 'center', height: '75vh'}}>\n          <div className=\"signInInfo\" style={{fontSize: '16px', fontFamily: 'Source Code Pro'}}>{loadingText}</div>\n        </div>}\n      </div>\n      <ToastContainer/>\n    </>\n  );\n}"
  },
  {
    "path": "gui/pages/Content/Marketplace/KnowledgeTemplate.js",
    "content": "import React, {useEffect, useRef, useState} from 'react';\nimport Image from \"next/image\";\nimport styles from '.././Toolkits/Tool.module.css';\nimport styles1 from '../Agents/Agents.module.css';\nimport {ToastContainer, toast} from 'react-toastify';\nimport 'react-toastify/dist/ReactToastify.css';\nimport styles2 from \"./Market.module.css\"\nimport styles3 from \"../Knowledge/Knowledge.module.css\"\nimport {EventBus} from \"@/utils/eventBus\";\nimport axios from 'axios';\nimport {\n  deleteMarketplaceKnowledge,\n  fetchKnowledgeTemplateOverview,\n  getValidMarketplaceIndices,\n  installKnowledgeTemplate\n} from \"@/pages/api/DashboardService\";\nimport {loadingTextEffect} from \"@/utils/utils\";\n\nexport default function KnowledgeTemplate({template, env}) {\n  const [installed, setInstalled] = useState('');\n  const [dropdown, setDropdown] = useState(false);\n  const [templateData, setTemplateData] = useState([]);\n  const [markdownContent, setMarkdownContent] = useState('');\n  const indexRef = useRef(null);\n  const [indexDropdown, setIndexDropdown] = useState(false);\n  const [pinconeIndices, setPineconeIndices] = useState([]);\n  const [qdrantIndices, setQdrantIndices] = useState([]);\n  const [weaviateIndices, setWeaviateIndices] = useState([]);\n\n  useEffect(() => {\n    getValidMarketplaceIndices(template.name)\n      .then((response) => {\n        const data = response.data || [];\n        if (data) {\n          setPineconeIndices(data.pinecone || []);\n          setQdrantIndices(data.qdrant || []);\n          setWeaviateIndices(data.weaviate || [])\n        }\n      })\n      .catch((error) => {\n        console.error('Error fetching indices:', error);\n      });\n  }, []);\n\n  useEffect(() => {\n    function handleClickOutside(event) {\n      if (indexRef.current && !indexRef.current.contains(event.target)) {\n        setIndexDropdown(false);\n      }\n    }\n\n    document.addEventListener('mousedown', handleClickOutside);\n    return () => {\n      document.removeEventListener('mousedown', handleClickOutside);\n    };\n  }, []);\n\n  useEffect(() => {\n    if (template) {\n      setInstalled(template.is_installed ? 'Installed' : 'Install');\n    }\n\n    if (window.location.href.toLowerCase().includes('marketplace')) {\n      setInstalled('Sign in to install');\n      axios.get(`https://app.superagi.com/api/knowledges/marketplace/get/details/${template.name}`)\n        .then((response) => {\n          const data = response.data || [];\n          setTemplateData(data);\n          if (data) {\n            setMarkdownContent(data.readme);\n          }\n        })\n        .catch((error) => {\n          console.error('Error fetching template details:', error);\n        });\n    } else {\n      fetchKnowledgeTemplateOverview(template.name)\n        .then((response) => {\n          const data = response.data || [];\n          setTemplateData(data);\n          if (data) {\n            setMarkdownContent(data.readme);\n          }\n        })\n        .catch((error) => {\n          console.error('Error fetching template details:', error);\n        });\n    }\n  }, []);\n\n  const handleInstallClick = (index) => {\n    const indexId = index.id\n    if(!index.is_valid_state){\n      toast.error(\"Select valid index\", {autoClose : 1800})\n      return\n    }\n    if (template && template.is_installed) {\n      toast.error(\"Template is already installed\", {autoClose: 1800});\n      return;\n    }\n    setInstalled(\"Installing\");\n\n    if (window.location.href.toLowerCase().includes('marketplace')) {\n      localStorage.setItem('knowledge_to_install', template.name);\n      localStorage.setItem('knowledge_index_to_install', indexId);\n\n      if (env === 'PROD') {\n        window.open(`https://app.superagi.com/`, '_self');\n      } else {\n        window.location.href = '/';\n      }\n      return;\n    }\n\n    setIndexDropdown(false);\n\n    installKnowledgeTemplate(template.name, indexId)\n      .then((response) => {\n          toast.success(\"Knowledge installed\", {autoClose: 1800});\n          setInstalled('Installed');\n          EventBus.emit('reFetchKnowledge', {});\n      })\n      .catch((error) => {\n        toast.error(\"Error installing Knowledge: \", {autoClose: 1800});\n        console.error('Error installing Knowledge:', error);\n        setInstalled('Install');\n      });\n  }\n\n  function handleBackClick() {\n    EventBus.emit('goToMarketplace', {});\n  }\n\n  const uninstallKnowledge = () => {\n    deleteMarketplaceKnowledge(template.name)\n      .then((response) => {\n        console.log(response)\n        toast.success(\"Knowledge uninstalled successfully\", {autoClose: 1800});\n        handleBackClick()\n      })\n      .catch((error) => {\n        toast.error(\"Unable to uninstall knowledge\", {autoClose: 1800});\n        console.error('Error uninstalling knowledge:', error);\n      });\n  }\n\n  const checkIndexValidity = (validState, validDimension) => {\n    let errorMessage = \"\";\n    let isValid = true;\n\n    if (!validState && validDimension) {\n      isValid = false;\n      errorMessage = \"The configured index already consists of custom knowledge\";\n    } else if ((!validState && !validDimension) || (validState && !validDimension)) {\n      isValid = false;\n      errorMessage = \"The dimension of the configured index does not match the dimensions of the selected knowledge\";\n    }\n\n    return [isValid, errorMessage];\n  }\n\n  const installClicked = () => {\n    setIndexDropdown(!indexDropdown)\n    if (window.location.href.toLowerCase().includes('marketplace')) {\n      if (env === 'PROD') {\n        window.open(`https://app.superagi.com/`, '_self');\n      } else {\n        window.location.href = '/';\n      }\n      return;\n    }\n  }\n\n  return (\n    <>\n      <div>\n        <div className=\"row\" style={{marginLeft: 'auto'}}>\n          <div className={styles2.back_button} style={{margin: '8px 0', padding: '2px'}}\n               onClick={() => handleBackClick()}>\n            <Image src=\"/images/arrow_back.svg\" alt=\"back_button\" width={14} height={12}/>\n            <span className={styles2.back_button_text}>Back</span>\n          </div>\n          <div className=\"col-3\" style={{maxHeight: '84vh', overflowY: 'auto', padding: '0'}}>\n            <div className={styles2.left_container}>\n              <span className={styles2.top_heading}>{templateData?.name}</span>\n              <span style={{fontSize: '12px', marginTop: '15px',}}\n                    className={styles.tool_publisher}>by {templateData?.contributed_by}&nbsp;{'\\u00B7'}&nbsp;<Image\n                width={14} height={14} src=\"/images/upload_icon.svg\"\n                alt=\"upload-icon\"\n                style={{marginBottom: '1px'}}/>&nbsp;{'\\u00B7'}&nbsp;{templateData?.install_number || 0}</span>\n\n              {!template?.is_installed && <div className=\"dropdown_container_search\" style={{width: '100%'}}>\n                <div className=\"primary_button\" onClick={installClicked}\n                     style={{marginTop: '15px', cursor: 'pointer', width: '100%'}}>\n                  <Image width={14} height={14} src=\"/images/upload_icon_dark.svg\" alt=\"upload-icon\"/>&nbsp;\n                  <span>{installed}</span>{installed === 'Installing' && <span className=\"loader ml_10\"></span>}\n                </div>\n                <div>\n                  {indexDropdown && installed === 'Install' &&\n                    <div className=\"custom_select_options\" ref={indexRef} style={{width: '100%', maxHeight: '500px'}}>\n                      <div className={styles3.knowledge_label} style={{padding: '12px 14px', maxWidth: '100%'}}>Select\n                        an existing vector database collection/index to install the knowledge\n                      </div>\n                      {pinconeIndices && pinconeIndices.length > 0 &&\n                        <div className={styles3.knowledge_db} style={{maxWidth: '100%'}}>\n                          <div className={styles3.knowledge_db_name}>Pinecone</div>\n                          {pinconeIndices.map((index) => (<div key={index.id} className=\"custom_select_option\"\n                                                               onClick={() => handleInstallClick(index)} style={{\n                            padding: '12px 14px',\n                            maxWidth: '100%',\n                            display: 'flex',\n                            justifyContent: 'space-between'\n                          }}>\n                            <div style={!checkIndexValidity(index.is_valid_state, index.is_valid_dimension)[0] ? {\n                              color: '#888888',\n                              textDecoration: 'line-through',\n                              pointerEvents : 'none',\n                            } : {}}>{index.name}</div>\n                            {!checkIndexValidity(index.is_valid_state, index.is_valid_dimension)[0] &&\n                              <div>\n                                <Image width={15} height={15} src=\"/images/info.svg\" alt=\"info-icon\"\n                                       title={checkIndexValidity(index.is_valid_state, index.is_valid_dimension)[1]}/>\n                              </div>}\n                          </div>))}\n                        </div>}\n                      {qdrantIndices && qdrantIndices.length > 0 &&\n                        <div className={styles3.knowledge_db} style={{maxWidth: '100%'}}>\n                          <div className={styles3.knowledge_db_name}>Qdrant</div>\n                          {qdrantIndices.map((index) => (<div key={index.id} className=\"custom_select_option\"\n                                                              onClick={() => handleInstallClick(index)} style={{\n                            padding: '12px 14px',\n                            maxWidth: '100%',\n                            display: 'flex',\n                            justifyContent: 'space-between'\n                          }}>\n                            <div style={!checkIndexValidity(index.is_valid_state, index.is_valid_dimension)[0] ? {\n                              color: '#888888',\n                              textDecoration: 'line-through',\n                              pointerEvents : 'none',\n                            } : {}}>{index.name}</div>\n                            {!checkIndexValidity(index.is_valid_state, index.is_valid_dimension)[0] &&\n                              <div>\n                                <Image width={15} height={15} src=\"/images/info.svg\" alt=\"info-icon\"\n                                       title={checkIndexValidity(index.is_valid_state, index.is_valid_dimension)[1]}/>\n                              </div>}\n                          </div>))}\n                        </div>}\n                      {weaviateIndices && weaviateIndices.length > 0 &&\n                        <div className={styles3.knowledge_db} style={{maxWidth: '100%'}}>\n                          <div className={styles3.knowledge_db_name}>Weaviate</div>\n                          {weaviateIndices.map((index) => (<div key={index.id} className=\"custom_select_option\"\n                                                              onClick={() => handleInstallClick(index)} style={{\n                            padding: '12px 14px',\n                            maxWidth: '100%',\n                            display: 'flex',\n                            justifyContent: 'space-between'\n                          }}>\n                            <div style={!checkIndexValidity(index.is_valid_state, index.is_valid_dimension)[0] ? {\n                              color: '#888888',\n                              textDecoration: 'line-through',\n                              pointerEvents : 'none',\n                            } : {}}>{index.name}</div>\n                            {!checkIndexValidity(index.is_valid_state, index.is_valid_dimension)[0] &&\n                              <div>\n                                <Image width={15} height={15} src=\"/images/info.svg\" alt=\"info-icon\"\n                                       title={checkIndexValidity(index.is_valid_state, index.is_valid_dimension)[1]}/>\n                              </div>}\n                          </div>))}\n                        </div>}\n                    </div>}\n                </div>\n              </div>}\n\n              {template?.is_installed &&\n                <div style={{width: '100%', display: 'flex', justifyContent: 'flex-start', marginTop: '15px'}}>\n                  <div className=\"secondary_button\" style={{cursor: 'default', width: '85%'}}>\n                    <Image width={14} height={14} src=\"/images/tick.svg\" alt=\"tick-icon\"/>&nbsp;{installed}\n                  </div>\n                  <div style={{width: '5%', marginLeft: '10px'}}>\n                    <button className=\"secondary_button\" style={{padding: '8px', height: '31px'}}\n                            onMouseEnter={() => setDropdown(true)} onMouseLeave={() => setDropdown(false)}>\n                      <Image width={14} height={14} src=\"/images/three_dots.svg\" alt=\"run-icon\"/>\n                    </button>\n                    {dropdown && <div onMouseEnter={() => setDropdown(true)} onMouseLeave={() => setDropdown(false)}>\n                      <ul className=\"dropdown_container\" style={{marginTop: '0', width: '165px'}}>\n                        <li className=\"dropdown_item\" onClick={uninstallKnowledge}>Uninstall knowledge</li>\n                      </ul>\n                    </div>}\n                  </div>\n                </div>}\n\n              <hr className={styles2.horizontal_line}/>\n\n              <span className={styles2.description_text}>{templateData?.description}</span>\n\n              <hr className={styles2.horizontal_line}/>\n\n              <span style={{fontSize: '12px'}} className={styles.tool_publisher}>Model</span>\n              <div className=\"tool_container\" style={{marginTop: '10px', width: 'fit-content'}}>\n                <div className={styles1.tool_text}>{templateData?.model}</div>\n              </div>\n              <br/>\n\n              <span style={{fontSize: '12px'}} className={styles.tool_publisher}>Knowledge datatype</span>\n              <div className=\"tool_container\" style={{marginTop: '10px', width: 'fit-content'}}>\n                <div className={styles1.tool_text}>{templateData?.data_type}</div>\n              </div>\n              <br/>\n\n              <span style={{fontSize: '12px'}} className={styles.tool_publisher}>Tokenizer</span>\n              <div className=\"tool_container\" style={{marginTop: '10px', width: 'fit-content'}}>\n                <div className={styles1.tool_text}>{templateData?.tokenizer}</div>\n              </div>\n              <br/>\n\n              <span style={{fontSize: '12px'}} className={styles.tool_publisher}>Chunk size</span>\n              <div className=\"tool_container\" style={{marginTop: '10px', width: 'fit-content'}}>\n                <div className={styles1.tool_text}>{templateData?.chunk_size}</div>\n              </div>\n              <br/>\n\n              <span style={{fontSize: '12px'}} className={styles.tool_publisher}>Chunk overlap</span>\n              <div className=\"tool_container\" style={{marginTop: '10px', width: 'fit-content'}}>\n                <div className={styles1.tool_text}>{templateData?.chunk_overlap}</div>\n              </div>\n              <br/>\n\n              <span style={{fontSize: '12px'}} className={styles.tool_publisher}>Text splitter</span>\n              <div className=\"tool_container\" style={{marginTop: '10px', width: 'fit-content'}}>\n                <div className={styles1.tool_text}>{templateData?.text_splitter}</div>\n              </div>\n              <br/>\n\n              <span style={{fontSize: '12px'}} className={styles.tool_publisher}>Dimensions</span>\n              <div className=\"tool_container\" style={{marginTop: '10px', width: 'fit-content'}}>\n                <div className={styles1.tool_text}>{templateData?.dimensions}</div>\n              </div>\n\n              <hr className={styles2.horizontal_line}/>\n\n              <span style={{fontSize: '12px',}} className={styles.tool_publisher}>Last updated</span>\n              <span className={styles2.description_text}>{templateData?.updated_at}</span>\n            </div>\n          </div>\n          <div className=\"col-9\" style={{paddingLeft: '8px'}}>\n            <div style={{overflowY: 'scroll', height: '84vh'}}>\n              <div className={styles2.left_container}\n                   style={{marginBottom: '5px', color: 'white', padding: '16px'}}>\n                <span className=\"text_20_bold\">Overview</span><br/>\n                {/*{templateData?.overview.map((item, index) => (<div key={index} style={{marginTop: '0'}}>*/}\n                {/*  <div className={styles2.description_text}>{index + 1}. {item || ''}</div>*/}\n                {/*  {index !== item.length - 1}*/}\n                {/*</div>))}*/}\n                <span className={styles2.sub_text}>{templateData?.overview}</span>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n      <ToastContainer/>\n    </>\n  );\n}\n"
  },
  {
    "path": "gui/pages/Content/Marketplace/Market.js",
    "content": "import React, {useState, useEffect} from 'react';\nimport Image from \"next/image\";\nimport styles from './Market.module.css';\nimport MarketKnowledge from './MarketKnowledge';\nimport MarketAgent from './MarketAgent';\nimport MarketTools from './MarketTools';\nimport MarketModels from '../Models/MarketModels';\nimport ToolkitTemplate from './ToolkitTemplate';\nimport ModelTemplate from \"../Models/ModelTemplate\";\nimport {EventBus} from \"@/utils/eventBus\";\nimport AgentTemplate from \"./AgentTemplate\";\nimport KnowledgeTemplate from \"./KnowledgeTemplate\";\nimport {setLocalStorageValue, setLocalStorageArray} from \"@/utils/utils\";\n\nexport default function Market({env, getModels, sendModelData}) {\n  const [activeTab, setActiveTab] = useState('market_tools');\n  const [itemClicked, setItemClicked] = useState(false);\n  const [templateData, setTemplateData] = useState([]);\n  const [detailType, setDetailType] = useState('');\n\n  useEffect(() => {\n    const marketplace_tab = localStorage.getItem('marketplace_tab');\n    if (marketplace_tab) {\n      setActiveTab(marketplace_tab);\n    }\n\n    const item_clicked = localStorage.getItem('market_item_clicked');\n    const detail_type = localStorage.getItem('market_detail_type');\n    const market_item = localStorage.getItem('market_item');\n\n    if (item_clicked) {\n      setItemClicked(JSON.parse(item_clicked));\n      if (detail_type) {\n        setDetailType(item_clicked === 'true' ? detail_type : '');\n        setTemplateData(item_clicked === 'true' ? JSON.parse(market_item) : []);\n      }\n    }\n\n    EventBus.on('openTemplateDetails', handleOpenTemplateDetails);\n    EventBus.on('goToMarketplace', handleBackClick);\n\n    return () => {\n      EventBus.off('openTemplateDetails', handleOpenTemplateDetails);\n      EventBus.off('goToMarketplace', handleBackClick);\n    };\n  }, []);\n\n  const switchTab = (tab) => {\n    setActiveTab(tab);\n    localStorage.setItem('marketplace_tab', tab);\n  };\n\n  const tabData = [\n    { id: 'market_tools', label: 'Tools', image: '/images/tools_light.svg' },\n    { id: 'market_knowledge', label: 'Knowledge', image: '/images/knowledge.svg' },\n    { id: 'market_agents', label: 'Agent Templates', image: '/images/agents_light.svg' },\n    { id: 'market_models', label: 'Models', image: '/images/models.svg' },\n  ];\n\n  const renderTab = (tab) => {\n    if(tab.id === 'market_models' && !(window.location.href.toLowerCase().includes('marketplace')))\n      return\n\n    return (\n        <button\n            key={tab.id}\n            onClick={() => switchTab(tab.id)}\n            className={activeTab === tab.id ? 'tab_button_selected' : 'tab_button'}\n        >\n          <Image width={14} height={14} src={tab.image} alt={`${tab.label}-icon`} />\n          <span>{tab.label}</span>\n        </button>\n    );\n  };\n\n  const handleOpenTemplateDetails = ({ item, contentType }) => {\n    localStorage.setItem('market_detail_type', contentType);\n    setDetailType(contentType);\n    localStorage.setItem('market_item', JSON.stringify(item));\n    setTemplateData(item);\n    localStorage.setItem('market_item_clicked', true);\n    setItemClicked(true);\n  };\n\n  const handleBackClick = () => {\n    localStorage.setItem('market_item_clicked', false);\n    setItemClicked(false);\n  };\n\n  return (\n      <div>\n        {!itemClicked ? (\n            <div className={styles.empty_state}>\n              <div style={{ width: '100%', display: 'flex', flexDirection: 'column' }}>\n                <div className={styles.detail_top}>\n                  <div style={{ display: 'flex', overflowX: 'scroll', marginLeft: '8px' }}>\n                    {tabData.map(renderTab)}\n                  </div>\n                </div>\n                <div>\n                  {activeTab === 'market_tools' && <MarketTools />}\n                  {activeTab === 'market_knowledge' && <MarketKnowledge />}\n                  {activeTab === 'market_agents' && <MarketAgent />}\n                  {activeTab === 'market_models' && <MarketModels />}\n                </div>\n              </div>\n            </div>\n        ) : (\n            <div style={{padding: '0 3px'}}>\n              {detailType === 'agent_template' && <AgentTemplate env={env} template={templateData}/>}\n              {detailType === 'knowledge_template' && <KnowledgeTemplate env={env} template={templateData}/>}\n              {detailType === 'tool_template' && <ToolkitTemplate env={env} template={templateData}/>}\n              {detailType === 'model_template' && <ModelTemplate env={env} template={templateData} getModels={getModels} sendModelData={sendModelData} />}\n            </div>\n        )}\n      </div>\n  );\n}\n\n"
  },
  {
    "path": "gui/pages/Content/Marketplace/Market.module.css",
    "content": ".container {\n    height: 100%;\n    width: 100%;\n    padding: 0 8px;\n}\n\n.title_box {\n    width: 100%;\n    padding: 8px;\n    display: flex;\n    align-items: center;\n}\n\n.title_text {\n    font-style: normal;\n    font-weight: 400;\n    font-size: 14px;\n    line-height: 17px;\n    display: flex;\n    align-items: center;\n    color: white;\n}\n\n.wrapper {\n    margin-bottom: 5px;\n    width: 100%;\n}\n\n.agent_box {\n    width: 120px;\n    justify-content: center;\n    display: flex;\n    float: left;\n    flex-direction: row;\n    align-items: center;\n    padding: 3px 3px;\n    gap: 6px;\n    border-radius: 8px;\n    flex: none;\n    order: 0;\n    flex-grow: 0;\n    cursor: pointer;\n    margin-right: 10px;\n}\n\n.agent_box:hover {\n    background-color: #494856;\n}\n\n.agent_active {\n    display: flex;\n    flex-direction: row;\n    align-items: center;\n    padding: 0;\n}\n\n.agent_text {\n    font-style: normal;\n    font-weight: 400;\n    font-size: 13px;\n    line-height: 15px;\n    align-items: center;\n    color: white;\n    flex: none;\n    order: 1;\n    flex-grow: 0;\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 1;\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.text_block {\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 1;\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.form_label {\n    font-size: 13px;\n    margin-bottom: 4px;\n    font-weight: 500;\n    color: #888888;\n    line-height: 17px;\n}\n\n.page_title {\n    text-align: left;\n    font-style: normal;\n    font-weight: 400;\n    font-size: 16px;\n    line-height: 17px;\n    display: flex;\n    align-items: center;\n    color: white;\n\n}\n\n.tool_text {\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 1;\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.detail_top {\n    width: 100%;\n    height: 50px;\n    display: flex;\n    align-items: center;\n\n    margin-bottom: 10px;\n    justify-content: space-between;\n}\n\n.detail_body {\n    width: 100%;\n    padding-right: 10px;\n}\n\n.detail_content {\n    height: calc(100vh - 140px);\n    border-radius: 8px;\n    overflow-y: scroll;\n    padding-bottom: 0;\n}\n\n.tab_button {\n    border: none;\n    font-style: normal;\n    font-weight: 400;\n    font-size: 12px;\n    line-height: 15px;\n    color: #FFFFFF;\n    border-radius: 8px;\n    padding: 8px 10px;\n}\n\n.tab_text {\n    font-style: normal;\n    font-weight: 400;\n    font-size: 11px;\n    line-height: 15px;\n    color: #FFFFFF;\n    padding: 8px;\n    display: flex;\n    align-items: center;\n}\n\n.tab_button:hover {\n    background: #454254;\n}\n\n.run_button {\n    background: #62A168;\n    border: none;\n    font-style: normal;\n    font-weight: 500;\n    font-size: 12px;\n    line-height: 15px;\n    color: #FFFFFF;\n    border-radius: 8px;\n    padding: 8px 10px 8px 5px;\n}\n\n.run_button:hover {\n    background: #57825b;\n}\n\n.pause_button {\n    background: #F78166;\n    border: none;\n    font-style: normal;\n    font-weight: 500;\n    font-size: 12px;\n    line-height: 15px;\n    color: #FFFFFF;\n    border-radius: 8px;\n    padding: 8px 10px;\n}\n\n.pause_button:hover {\n    background: #C95034;\n}\n\n.history_box {\n    background-color: rgb(39, 35, 53);\n    width: 100%;\n    padding: 10px;\n    color: white;\n    font-style: normal;\n    font-weight: 400;\n    font-size: 15px;\n    line-height: 120px;\n    border-radius: 8px;\n    cursor: pointer;\n    margin-bottom: 7px;\n    text-align: center;\n}\n\n.notification_bubble {\n    width: 14px;\n    height: 14px;\n    background: #DC6261;\n    border-radius: 200px;\n    display: flex;\n    align-items: center;\n    text-align: center;\n    padding: 4px;\n    font-size: 9px;\n    order: 1;\n}\n\n.history_info {\n    font-style: normal;\n    font-weight: 400;\n    font-size: 10px;\n    line-height: 12px;\n    color: #888888;\n    margin-left: 4px;\n    margin-top: 3px;\n}\n\n.feed_title {\n    font-family: 'Source Code Pro';\n    margin-left: 10px;\n    font-style: normal;\n    font-weight: 500;\n    font-size: 12px;\n    line-height: 15px;\n    color: white;\n    white-space: pre-line;\n}\n\n.feed_icon {\n    font-size: 20px;\n    margin-top: 5px;\n}\n\n.custom_task_box {\n    font-style: normal;\n    font-weight: 500;\n    font-size: 12px;\n    line-height: 14px;\n    color: white;\n    width: 100%;\n    border-radius: 8px;\n    margin-bottom: 5px;\n    padding: 15px 20px;\n}\n\n.console_icons {\n    margin: -3px 3px 0 0;\n}\n\n.detail_name {\n    font-style: normal;\n    font-weight: 400;\n    font-size: 16px;\n    line-height: 19px;\n    color: #FFFFFF;\n    margin-bottom: 10px;\n}\n\n.separator {\n    height: 15px;\n    margin-bottom: 15px;\n    border-bottom: 1px solid rgba(255, 255, 255, 0.08);\n}\n\n.agent_info_box {\n    display: flex;\n    align-items: center;\n    justify-content: flex-start;\n    margin-bottom: 10px;\n}\n\n.agent_info_tools {\n    display: flex;\n    flex-direction: row;\n    flex-wrap: wrap;\n    align-items: flex-start;\n}\n\n.resources {\n    display: flex;\n    justify-content: flex-start;\n    flex-wrap: wrap;\n    gap: 6px;\n}\n\n.agent_resources {\n    width: 100%;\n    margin-top: 10px;\n}\n\n.large_text_box {\n    -webkit-line-clamp: 5;\n    -webkit-box-orient: vertical;\n}\n\n.show_more_button {\n    margin-top: 10px;\n    cursor: pointer;\n    width: fit-content;\n    color: #888888;\n}\n\n.single_line_block {\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n    max-width: 80%;\n}\n\n.three_dots {\n    margin-left: 5px;\n    background: transparent;\n    border: none;\n    border-radius: 8px;\n}\n\n.more_details {\n    display: flex;\n    align-items: center;\n    margin-right: 30px;\n}\n\n.more_details_wrapper {\n    display: flex;\n    align-items: center;\n    margin-top: 20px;\n    justify-content: flex-start;\n}\n\n.empty_state {\n    width: 100%;\n    height: 100%;\n    border-radius: 8px;\n    display: flex;\n    align-items: center;\n    justify-content: space-between;\n}\n\n.main_workspace {\n    height: 100%;\n    padding: 0 10px 10px 0;\n}\n\n.featured_text {\n    color: white;\n}\n\n.search_box {\n\n}\n\n.search_box input {\n    width: 160px;\n    height: 25px;\n    font-size: x-small;\n    padding: 5px;\n    border: 1px solid rgb(96, 96, 96);\n    border-radius: 6px;\n    background-color: #454254;\n}\n\n.market_tool {\n    display: flex;\n    height: 105px;\n    color: white;\n    font-size: small;\n    padding: 12px;\n    width: 33% !important;\n    background-color: rgb(39, 35, 53);\n    border-radius: 8px;\n    flex-direction: column;\n}\n\n.tool_description {\n    line-height:16px;\n    margin-top: 5px;\n    color: #888888;\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 2;\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.rowContainer {\n    height: 100%;\n}\n\n.top_heading {\n    font-style: normal;\n    font-weight: 400;\n    font-size: 20px;\n    line-height: 24px;\n    color: #FFFFFF;\n}\n\n.description_text {\n    font-size: 12px;\n    line-height: 14px;\n    color: #FFFFFF;\n    margin-bottom: 16px;\n}\n\n.left_container {\n    padding: 20px;\n    background: rgba(0, 0, 0, 0.2);\n    border-radius: 6px;\n    margin-bottom: 4vh;\n}\n\n.description_heading {\n    font-size: 20px;\n    color: #FFFFFF;\n    font-weight: 600;\n}\n\n.back_button {\n    font-weight: 500;\n    font-size: 12px;\n    color: #888888;\n    cursor: pointer;\n    margin-bottom: 8px;\n}\n\n.sub_text {\n    font-weight: 400;\n    font-size: 12px;\n    color: #888888;\n}\n\n.vertical_line{\n    width: 0;\n    height: 20px;\n    border: 1px solid rgba(255, 255, 255, 0.1);\n    flex: none;\n    margin-left:8px;\n}\n\n.topbar_heading{\n    font-style: normal;\n    font-weight: 500;\n    font-size: 14px;\n    line-height: 18px;\n    color: #FFFFFF;\n    margin-left:8px;\n    pointer-events: none;\n}\n\n.empty_templates {\n    display: flex;\n    margin-top: 60px;\n    justify-content: center;\n}\n\n.horizontal_line {\n    margin: 20px 0 20px -20px;\n    border: 1px solid #ffffff20;\n    width: calc(100% + 40px);\n    display: flex;\n    height: 0;\n}\n\n.back_button_text {\n    font-style: normal;\n    font-weight: 500;\n    font-size: 12px;\n    line-height: 14px;\n    color: #888888;\n    margin-left: 4px;\n}\n\n.marketplace_public_button{\n    display: flex;\n    justify-content: flex-end;\n    align-items: center;\n    width:100%;\n    padding-right:8px;\n}\n\n.marketplace_public_content{\n    height:92.5vh;\n    width:99vw;\n    background: rgba(255, 255, 255, 0.08) ;\n    margin-left:8px;\n    border-radius: 8px\n}\n\n.marketplace_public_container{\n    height:6.5vh;\n    display:flex;\n    width:100%;\n}\n\n.markdown_style{\n    color:white;\n}\n\n.markdown_style img {\n    max-width: 100%;\n    height: auto;\n}\n\n.markdown_container{\n    height:68vh;\n    overflow-y:scroll;\n    overflow-x:hidden;\n}\n\n.settings_tab_button_clicked{\n    background: #454254;\n    padding-right: 15px\n}\n\n.settings_tab_button{\n    background: transparent;\n    padding-right: 15px\n}\n\n.settings_tab_img{\n    margin-top: -1px;\n}\n\n.checkboxGroup {\n    display: flex;\n    justify-content: space-between;\n    flex-wrap: wrap;\n    height: 15vh;\n}\n\n.checkboxLabel {\n    display: flex;\n    align-items: center;\n    width: 15vw;\n    cursor:pointer\n}\n\n.checkboxText {\n    font-weight: 400;\n    font-size: 12px;\n    color: #FFF;\n    margin-left:5px;\n}"
  },
  {
    "path": "gui/pages/Content/Marketplace/MarketAgent.js",
    "content": "import React, {useEffect, useState} from \"react\";\nimport Image from \"next/image\";\nimport {fetchAgentTemplateList} from \"@/pages/api/DashboardService\";\nimport {EventBus} from \"@/utils/eventBus\";\nimport {loadingTextEffect, getUserClick} from \"@/utils/utils\";\nimport axios from 'axios';\n\nexport default function MarketAgent() {\n  const [agentTemplates, setAgentTemplates] = useState([])\n  const [showMarketplace, setShowMarketplace] = useState(false);\n  const [isLoading, setIsLoading] = useState(true)\n  const [loadingText, setLoadingText] = useState(\"Loading Agent Templates\");\n\n  useEffect(() => {\n    loadingTextEffect('Loading Agent Templates', setLoadingText, 500);\n\n    if (window.location.href.toLowerCase().includes('marketplace')) {\n      setShowMarketplace(true);\n      axios.get('https://app.superagi.com/api/agent_templates/marketplace/list')\n        .then((response) => {\n          const data = response.data || [];\n          setAgentTemplates(data);\n          setIsLoading(false);\n        })\n        .catch((error) => {\n          console.error('Error fetching agent templates:', error);\n        });\n    } else {\n      fetchAgentTemplateList()\n        .then((response) => {\n          const data = response.data || [];\n          setAgentTemplates(data);\n          setIsLoading(false);\n        })\n        .catch((error) => {\n          console.error('Error fetching agent templates:', error);\n        });\n    }\n  }, []);\n\n  function handleTemplateClick(item) {\n    getUserClick(\"Marketplace Agent Template Viewed\", {\"Agent Template Name\": item.name})\n    const contentType = 'agent_template';\n    EventBus.emit('openTemplateDetails', {item, contentType});\n  }\n\n  return (\n    <div className={showMarketplace ? 'ml_8' : 'ml_3'}>\n      <div className=\"w_100 overflowY_auto mxh_78vh\">\n        {!isLoading ? <div>\n          {agentTemplates.length > 0 ? <div className=\"marketplaceGrid3\">{agentTemplates.map((item, index) => (\n            <div className=\"market_containers cursor_pointer\" key={item.id} onClick={() => handleTemplateClick(item)}>\n              <div className=\"vertical_containers overflow_auto\">\n                <div>{item.name}</div>\n                <div className=\"color_gray lh_16\">by SuperAgi&nbsp;<Image width={14} height={14}\n                                                                                            src=\"/images/is_verified.svg\"\n                                                                                            alt=\"is_verified\"/></div>\n                <div className=\"text_ellipsis mt_8 color_gray\">{item.description}</div>\n              </div>\n            </div>\n          ))}</div> : <div className=\"center_container mt_40\">\n            <Image width={150} height={60} src=\"/images/no_permissions.svg\" alt=\"no-permissions\"/>\n            <span className=\"feed_title mt_8\">No Agent Templates found!</span>\n          </div>}\n        </div> : <div className=\"horizontal_container_center h_75vh\">\n          <div className=\"signInInfo text_16 ff_sourceCode\">{loadingText}</div>\n        </div>}\n      </div>\n    </div>\n  )\n};\n"
  },
  {
    "path": "gui/pages/Content/Marketplace/MarketKnowledge.js",
    "content": "import React, {useEffect, useState} from \"react\";\nimport Image from \"next/image\";\nimport styles from './Market.module.css';\nimport styles1 from '../Knowledge/Knowledge.module.css';\nimport {EventBus} from \"@/utils/eventBus\";\nimport {loadingTextEffect} from \"@/utils/utils\";\nimport axios from 'axios';\nimport {fetchKnowledgeTemplateList} from \"@/pages/api/DashboardService\";\n\nexport default function MarketKnowledge() {\n  const [knowledgeTemplates, setKnowledgeTemplates] = useState([])\n  const [showMarketplace, setShowMarketplace] = useState(false);\n  const [isLoading, setIsLoading] = useState(true)\n  const [loadingText, setLoadingText] = useState(\"Loading Knowledge Templates\");\n\n  useEffect(() => {\n    loadingTextEffect('Loading Knowledge Templates', setLoadingText, 500);\n\n    if (window.location.href.toLowerCase().includes('marketplace')) {\n      setShowMarketplace(true);\n      axios.get(`https://app.superagi.com/api/knowledges/marketplace/list/0`)\n        .then((response) => {\n          const data = response.data || [];\n          setKnowledgeTemplates(data);\n          setIsLoading(false);\n        })\n        .catch((error) => {\n          console.error('Error fetching knowledge templates:', error);\n        });\n    } else {\n      fetchKnowledgeTemplateList()\n        .then((response) => {\n          const data = response.data || [];\n          setKnowledgeTemplates(data);\n          setIsLoading(false);\n        })\n        .catch((error) => {\n          console.error('Error fetching knowledge templates:', error);\n        });\n    }\n  }, []);\n\n  function handleTemplateClick(item) {\n    const contentType = 'knowledge_template';\n    EventBus.emit('openTemplateDetails', {item, contentType});\n  }\n\n  return (\n    <div className={showMarketplace ? 'ml_8' : 'ml_3'}>\n      <div className=\"w_100 overflowY_auto mxh_78vh\">\n        {!isLoading ? <div>\n          {knowledgeTemplates.length > 0 ? <div className=\"marketplaceGrid3\">{knowledgeTemplates.map((item, index) => (\n            <div className=\"market_containers cursor_pointer\" key={item.id} style={{cursor: 'pointer', display: 'block'}}\n                 onClick={() => handleTemplateClick(item)}>\n              <div style={{display: 'inline', overflow: 'auto'}}>\n                <div className=\"horizontal_space_between\">\n                  <span>{item.name}</span>\n                  {item.is_installed &&\n                    <div className={styles1.installed_knowledge_card_class}>{'\\u2713'}&nbsp;Installed</div>}\n                </div>\n                <div style={{\n                  color: '#888888',\n                  lineHeight: '16px',\n                  display: 'flex',\n                  alignItems: 'center',\n                  marginTop: item.is_installed ? '-2.5%' : ''\n                }}>by {item.contributed_by}&nbsp;{'\\u00B7'}&nbsp;<Image\n                  width={14} height={14} src=\"/images/upload_icon.svg\" alt=\"upload-icon\"/>&nbsp;{item.install_number}\n                </div>\n                <div className=\"text_ellipsis mt_6 color_gray\">{item.description}</div>\n              </div>\n            </div>\n          ))}</div> : <div className=\"center_container mt_40\">\n            <Image width={150} height={60} src=\"/images/no_permissions.svg\" alt=\"no-permissions\"/>\n            <span className=\"feed_title mt_8\" style={{marginTop: '8px'}}>No Knowledge found!</span>\n          </div>}\n        </div> : <div className=\"horizontal_container_center h_75vh\">\n          <div className=\"signInInfo text_16 ff_sourceCode\">{loadingText}</div>\n        </div>}\n      </div>\n    </div>\n  )\n}"
  },
  {
    "path": "gui/pages/Content/Marketplace/MarketTools.js",
    "content": "import React, {useEffect, useState} from \"react\";\nimport Image from \"next/image\";\nimport {fetchToolTemplateList} from \"@/pages/api/DashboardService\";\nimport {EventBus} from \"@/utils/eventBus\";\nimport {loadingTextEffect, excludedToolkits, returnToolkitIcon} from \"@/utils/utils\";\nimport axios from 'axios';\n\nexport default function MarketTools() {\n  const [toolTemplates, setToolTemplates] = useState([])\n  const [showMarketplace, setShowMarketplace] = useState(false);\n  const [isLoading, setIsLoading] = useState(true)\n  const [loadingText, setLoadingText] = useState(\"Loading Toolkits\");\n\n  useEffect(() => {\n    loadingTextEffect('Loading Toolkits', setLoadingText, 500);\n\n    if (window.location.href.toLowerCase().includes('marketplace')) {\n      setShowMarketplace(true);\n      axios.get('https://app.superagi.com/api/toolkits/marketplace/list/0')\n        .then((response) => {\n          const data = response.data || [];\n          const filteredData = data?.filter((item) => !excludedToolkits().includes(item.name));\n          setToolTemplates(filteredData);\n          setIsLoading(false);\n        })\n        .catch((error) => {\n          console.error('Error fetching tool templates:', error);\n        });\n    } else {\n      fetchToolTemplateList()\n        .then((response) => {\n          const data = response.data || [];\n          const filteredData = data?.filter((item) => !excludedToolkits().includes(item.name));\n          setToolTemplates(filteredData);\n          setIsLoading(false);\n        })\n        .catch((error) => {\n          console.error('Error fetching tools:', error);\n        });\n    }\n  }, []);\n\n  function handleTemplateClick(item) {\n    const contentType = 'tool_template';\n    EventBus.emit('openTemplateDetails', {item, contentType});\n  }\n\n  return (\n    <div className={showMarketplace ? 'ml_8' : 'ml_3'}>\n      <div className=\"w_100 overflowY_auto mxh_78vh\">\n        {!isLoading ? <div>\n          {toolTemplates.length > 0 ? <div className=\"marketplaceGrid3\">{toolTemplates.map((item) => (\n            <div className=\"market_containers cursor_pointer\" key={item.id} onClick={() => handleTemplateClick(item)}>\n              <div className=\"horizontal_container overflow_auto\">\n                <Image className=\"tool_icon\" width={40} height={40} src={returnToolkitIcon(item.name)} alt=\"tool-icon\"/>\n                <div className=\"ml_12 mb_8\">\n                    <div>{item.name}</div>\n                    <div className=\"color_gray lh_16\">by SuperAgi&nbsp;<Image width={14} height={14} src=\"/images/is_verified.svg\" alt=\"is_verified\"/></div>\n                </div>\n              </div>\n              <div className=\"text_ellipsis mt_6 color_gray\">{item.description}</div>\n            </div>\n          ))}</div> : <div className=\"center_container mt_40\">\n            <Image width={150} height={60} src=\"/images/no_permissions.svg\" alt=\"no-permissions\"/>\n            <span className=\"feed_title mt_8\">No Tools found!</span>\n          </div>}\n        </div> : <div className=\"horizontal_container_center h_75vh\">\n          <div className=\"signInInfo text_16 ff_sourceCode\">{loadingText}</div>\n        </div>}\n      </div>\n    </div>\n  )\n};"
  },
  {
    "path": "gui/pages/Content/Marketplace/MarketplacePublic.js",
    "content": "import React from 'react';\nimport Image from \"next/image\";\nimport styles from './Market.module.css';\nimport Market from './Market';\n\nexport default function MarketplacePublic({env}) {\n  const handleSignupClick = () => {\n    if (env === 'PROD') {\n      const url = localStorage.getItem('marketplace_tab') === 'market_models' ? 'https://models.superagi.com/' : 'https://app.superagi.com/';\n      window.open(url, '_self');\n    } else {\n      window.location.href = '/';\n    }\n  };\n\n  return (\n    <div style={{height: '100vh', width: '100%'}}>\n      <div className={styles.marketplace_public_container}>\n        <div className=\"superAgiLogo\" style={{paddingLeft: '15px'}}><Image width={132} height={24}\n                                                                           style={{cursor: 'pointer'}}\n                                                                           onClick={handleSignupClick}\n                                                                           src=\"/images/sign-in-logo.svg\"\n                                                                           alt=\"super-agi-logo\"/>\n          <div className={styles.vertical_line}/>\n          <div className={styles.topbar_heading}>&nbsp;Marketplace</div>\n        </div>\n        <div className={styles.marketplace_public_button}>\n          <button className=\"primary_button\" onClick={handleSignupClick}>Sign Up/Sign In</button>\n        </div>\n      </div>\n      <div className={styles.marketplace_public_content}>\n        <Market env={env}/>\n      </div>\n    </div>\n  );\n};\n\n\n"
  },
  {
    "path": "gui/pages/Content/Marketplace/ToolkitTemplate.js",
    "content": "import React, {useEffect, useState} from 'react';\nimport Image from \"next/image\";\nimport styles from '.././Toolkits/Tool.module.css';\nimport styles3 from '../Agents/Agents.module.css';\nimport {ToastContainer, toast} from 'react-toastify';\nimport 'react-toastify/dist/ReactToastify.css';\nimport styles2 from \"./Market.module.css\"\nimport {\n  checkToolkitUpdate,\n  fetchToolTemplateOverview,\n  installToolkitTemplate,\n  updateMarketplaceToolTemplate\n} from \"@/pages/api/DashboardService\";\nimport {EventBus} from \"@/utils/eventBus\";\nimport ReactMarkdown from 'react-markdown';\nimport axios from 'axios';\nimport {returnToolkitIcon} from \"@/utils/utils\";\n\nexport default function ToolkitTemplate({template, env}) {\n  const [rightPanel, setRightPanel] = useState('tool_view')\n  const [installed, setInstalled] = useState('')\n  const [markdownContent, setMarkdownContent] = useState('');\n\n  useEffect(() => {\n    if(template.is_installed && !window.location.href.toLowerCase().includes('marketplace')) {\n      checkToolkitUpdate(template.name).then((response) => {\n        setInstalled(response.data ? 'Update' :  'Installed');\n      })\n          .catch((error) => {\n            console.error('Error fetching update details:', error);\n          });\n    }\n    else{\n      setInstalled(window.location.href.toLowerCase().includes('marketplace') ? 'Sign in to install' : 'Install');\n    }\n    fetchReadme()\n  }, []);\n\n  function handleInstallClick() {\n    if (window.location.href.toLowerCase().includes('marketplace')) {\n      localStorage.setItem('toolkit_to_install', template.name);\n      if (env === 'PROD') {\n        window.open(`https://app.superagi.com/`, '_self');\n      } else {\n        window.location.href = '/';\n      }\n      return;\n    }\n\n    if(installed === \"Update\"){\n      updateMarketplaceToolTemplate(template.name)\n          .then((response) => {\n            toast.success(\"Toolkit Updated\", {autoClose: 1800});\n            setInstalled('Installed');\n          })\n          .catch((error) => {\n            console.error('Error installing Toolkit:', error);\n          });\n      return;\n    }\n\n    if (template && template.is_installed) {\n      toast.error(\"Toolkit is already installed\", {autoClose: 1800});\n      return;\n    }\n\n    installToolkitTemplate(template.name)\n      .then((response) => {\n        toast.success(\"Toolkit installed\", {autoClose: 1800});\n        setInstalled('Installed');\n      })\n      .catch((error) => {\n        console.error('Error installing Toolkit', error);\n      });\n  }\n\n  function handleBackClick() {\n    EventBus.emit('goToMarketplace', {});\n  }\n\n  function fetchReadme() {\n    if (window.location.href.toLowerCase().includes('marketplace')) {\n      axios.get(`https://app.superagi.com/api/toolkits/marketplace/readme/${template.name}`)\n          .then((response) => {\n            setMarkdownContent(response.data || '');\n            setRightPanel(response.data ? 'overview' : 'tool_view');\n          })\n          .catch((error) => {\n            setRightPanel('tool_view');\n            console.error('Error fetching template details:', error);\n          });\n    } else {\n      fetchToolTemplateOverview(template.name)\n          .then((response) => {\n            setMarkdownContent(response.data || '');\n            setRightPanel(response.data ? 'overview' : 'tool_view');\n          })\n          .catch((error) => {\n            setRightPanel('tool_view');\n            console.error('Error fetching template details:', error);\n          });\n    }\n  }\n\n  return (\n    <>\n      <div>\n        <div className=\"row\" style={{marginLeft: 'auto'}}>\n          <div className={styles2.back_button} style={{margin: '8px 0', padding: '2px'}}\n               onClick={() => handleBackClick()}>\n            <Image src=\"/images/arrow_back.svg\" alt=\"back_button\" width={14} height={12}/>\n            <span className={styles2.back_button_text}>Back</span>\n          </div>\n          <div className=\"col-3\" style={{maxHeight: '84vh', overflowY: 'auto', padding: '0'}}>\n            <div className={styles2.left_container}>\n              <div style={{marginBottom: '15px'}}>\n                <Image style={{borderRadius: '25px', background: 'black'}} width={50} height={50}\n                       src={returnToolkitIcon(template.name)} alt=\"tool-icon\"/>\n              </div>\n              <span className={styles2.top_heading}>{template.name}</span>\n              <span style={{fontSize: '12px', marginTop: '15px',}} className={styles.tool_publisher}>By SuperAGI <Image\n                width={14} height={14} src=\"/images/is_verified.svg\"\n                alt=\"is_verified\"/>&nbsp;{'\\u00B7'}&nbsp;<Image width={14} height={14}\n                                                                src=\"/images/upload_icon.svg\"\n                                                                alt=\"upload-icon\"/></span>\n              <button className=\"primary_button\" style={{\n                marginTop: '15px',\n                width: '100%',\n                background: template && template.is_installed && installed !== 'Update' ? 'rgba(255, 255, 255, 0.14)' : '#FFF',\n                color: template && template.is_installed && installed !== 'Update' ? '#FFFFFF' : '#000'\n              }} onClick={() => handleInstallClick()}>\n                {(template && template.is_installed && installed !== 'Update') ?\n                  <Image width={14} height={14} src=\"/images/tick.svg\" alt=\"tick-icon\"/> :\n                  <Image width={14} height={14} src=\"/images/upload_icon_dark.svg\"\n                         alt=\"upload-icon\"/>}&nbsp;{installed}</button>\n              <hr className={styles2.horizontal_line}/>\n              <span className={styles2.description_text}>{template.description}</span>\n              <hr className={styles2.horizontal_line}/>\n              <span style={{fontSize: '12px',}} className={styles.tool_publisher}>Last updated</span>\n              <span className={styles2.description_text}>{template.updated_at}</span>\n            </div>\n          </div>\n          <div className=\"col-9\" style={{paddingLeft: '8px'}}>\n            <div>\n              <div className={styles2.left_container} style={{marginBottom: '5px', padding: '8px'}}>\n                <div className=\"row\">\n                  <div className=\"col-4\">\n                    {markdownContent && markdownContent !== '' &&\n                      <button onClick={() => setRightPanel('overview')} className={styles2.tab_button}\n                              style={rightPanel === 'overview' ? {\n                                background: '#454254',\n                                paddingRight: '15px'\n                              } : {background: 'transparent', paddingRight: '15px'}}>\n                        &nbsp;Overview\n                      </button>}\n                    <button onClick={() => setRightPanel('tool_view')}\n                            className={styles2.tab_button} style={rightPanel === 'tool_view' ? {\n                      background: '#454254',\n                      paddingRight: '15px'\n                    } : {background: 'transparent', paddingRight: '15px'}}>\n                      &nbsp;Tools Included\n                    </button>\n                  </div>\n                </div>\n              </div>\n              {rightPanel === 'overview' &&\n                <div className={styles2.left_container} style={{marginBottom: '8px'}}>\n                  <div className={styles2.markdown_container}>\n                    {markdownContent && markdownContent !== '' ? <ReactMarkdown\n                        className={styles2.markdown_style}>{markdownContent}</ReactMarkdown> :\n                      <div style={{\n                        display: 'flex',\n                        flexDirection: 'column',\n                        alignItems: 'center',\n                        justifyContent: 'center',\n                        marginTop: '40px',\n                        width: '100%'\n                      }}>\n                        <Image width={150} height={60} src=\"/images/no_permissions.svg\" alt=\"no-permissions\"/>\n                        <span className={styles3.feed_title} style={{marginTop: '8px'}}>No Overview to display!</span>\n                      </div>\n                    }\n                  </div>\n                </div>}\n              {rightPanel === 'tool_view' && <div>\n                <div style={{overflowY: 'scroll', height: '70vh'}}>\n                  {template.tools.map((value, index) => (\n                    <div key={index} className={styles2.left_container}\n                         style={{marginBottom: '5px', color: 'white', padding: '16px'}}>\n                      <span className={styles2.description_text}>{value.name}</span><br/>\n                      <span className={styles2.sub_text}>{value.description}</span>\n                    </div>\n                  ))}\n                </div>\n              </div>}\n            </div>\n          </div>\n        </div>\n      </div>\n      <ToastContainer/>\n    </>\n  );\n}"
  },
  {
    "path": "gui/pages/Content/Models/AddModel.js",
    "content": "import React, {useEffect, useState} from \"react\";\nimport ModelForm from \"./ModelForm\";\n\nexport default function AddModel({internalId, getModels, sendModelData, env}){\n\n    return(\n        <div id=\"add_model\">\n            <div className=\"row\">\n                <div className=\"col-3\" />\n                <div className=\"col-6 col-6-scrollable\">\n                    <ModelForm internalId={internalId} getModels={getModels} sendModelData={sendModelData} env={env}/>\n                </div>\n                <div className=\"col-3\" />\n            </div>\n        </div>\n    )\n}"
  },
  {
    "path": "gui/pages/Content/Models/AddModelMarketPlace.js",
    "content": "import React, {useState, useEffect} from \"react\";\nimport Image from \"next/image\";\nimport {openNewTab, modelIcon, modelGetAuth} from \"@/utils/utils\";\nimport {fetchApiKey, storeModel} from \"@/pages/api/DashboardService\";\nimport {toast} from \"react-toastify\";\n\nexport default function AddModelMarketPlace({ template, getModels, sendModelData }){\n    const [modelTokenLimit, setModelTokenLimit] = useState(4096);\n    const [modelVersion, setModelVersion] = useState('');\n    const [modelEndpoint, setModelEndpoint] = useState('');\n    const [tokenError, setTokenError] = useState(false);\n    const [templateData, setTemplateData] = useState(template);\n    const [isLoading, setIsLoading] = useState(false);\n    const [providerId, setProviderId] = useState(1);\n    const [disableInstall, setDisableInstall] = useState(false);\n\n    useEffect(() => {\n        if(modelVersion === '' && modelEndpoint === '')\n            setDisableInstall(true)\n        else\n            setDisableInstall(false)\n    },[modelVersion, modelEndpoint])\n\n    useEffect(()=>{\n        console.log(templateData)\n        checkModelProvider().then().catch();\n    },[])\n\n    const checkModelProvider = async () => {\n        if(templateData){\n            const response = await fetchApiKey(templateData.provider);\n            console.log(response.data)\n            if(response.data.length === 0) {\n                setTokenError(true)\n                return true\n            }\n            else {\n                setTokenError(false)\n                setProviderId(response.data[0].id)\n                return false\n            }\n        }\n    }\n\n    const storeModelDetails = () => {\n        storeModel(templateData.model_name, templateData.description, modelEndpoint, providerId, modelTokenLimit, \"Marketplace\", modelVersion).then((response) =>{\n            setIsLoading(false)\n            let data = response.data\n            if (data.error) {\n                toast.error(data.error,{autoClose: 1800});\n            } else if (data.success) {\n                toast.success(data.success,{autoClose: 1800});\n                getModels()\n                console.log(data)\n                handleModelSuccess({id: data.model_id, name: templateData.model_name})\n            }\n        }).catch((error) => {\n            console.log(\"SORRY, There was an error storing the model details\" + error);\n            setIsLoading(false)\n        });\n    }\n\n    const handleModelSuccess = (model) => {\n        model.contentType = 'Model'\n        sendModelData(model)\n    }\n\n    return(\n        <div id=\"add_model_marketplace\" className=\"row text_12 color_gray\">\n            <div className=\"col-3\" />\n            <div className=\"col-6 col-6-scrollable\">\n                {templateData && <div className=\"vertical_containers\">\n                    <span className=\"text_16 color_white\">Add Model</span>\n\n                    <div className=\"vertical_containers tag_container mt_24\">\n                        <span className=\"text_14 color_white\">{templateData.model_name}</span>\n                        <div className=\"horizontal_container mt_8\">\n                            <span className=\"mr_8\">By {templateData.model_name.includes('/') ? templateData.model_name.split('/')[0] : templateData.provider}</span>·\n                            <Image className=\"ml_8\" width={18} height={18} src={modelIcon(templateData.provider)} alt=\"logo-icon\" />\n                            <span className=\"ml_4\">{templateData.provider}</span>\n                        </div>\n                    </div>\n\n                    {templateData.provider === 'Hugging Face' && <div className=\"vertical_containers\">\n                        <span className=\"mt_24\">{templateData.provider} Model Endpoint</span>\n                        <input className=\"input_medium mt_8\" type=\"text\" placeholder=\"Enter Model Endpoint URL\"\n                               onChange={(event) => setModelEndpoint(event.target.value)}/>\n                    </div>}\n\n                    {templateData.provider === 'Replicate' && <div className=\"vertical_containers\">\n                        <span className=\"mt_24\">{templateData.provider} Version</span>\n                        <input className=\"input_medium mt_8\" type=\"text\" placeholder=\"Enter Model Version\"\n                               onChange={(event) => setModelVersion(event.target.value)}/>\n                    </div>}\n\n                    <span className=\"mt_24\">Token Limit</span>\n                    <input className=\"input_medium mt_8\" type=\"number\" placeholder=\"Enter the Token Limit\" value={modelTokenLimit}\n                           onChange={(event) => setModelTokenLimit(+event.target.value)} />\n\n                    {tokenError && <div className=\"horizontal_container align_start error_box mt_24 gap_6\">\n                        <Image width={16} height={16} src=\"/images/icon_error.svg\" alt=\"error-icon\" />\n                        <div className=\"vertical_containers\">\n                            <span className=\"text_12 color_white lh_16\">The <b>{templateData.provider}</b> auth token is not added to your settings. In order to start using the model, you need to add the auth token to your settings. You can find the auth token in the <b>{templateData.provider}</b> dashboard. </span>\n                            <div className=\"horizontal_container mt_16\">\n                                <button className=\"primary_button_small\" onClick={() => openNewTab(-3, \"Settings\", \"Settings\", false)}>Add auth token</button>\n                                <button className=\"secondary_button_small ml_8\"\n                                        onClick={() => window.open(modelGetAuth(templateData.provider),\"_blank\")}>Get auth token<Image src=\"/images/open_in_new.svg\" alt=\"deploy_icon\" width={12} height={12} className=\"ml_4\" />\n                                </button>\n                            </div>\n                        </div>\n                    </div>}\n\n                    {templateData.provider === 'Hugging Face' && <div className=\"horizontal_container align_start info_box mt_24 gap_6\">\n                        <Image width={16} height={16} src=\"/images/icon_info.svg\" alt=\"error-icon\" />\n                        <div className=\"vertical_containers\">\n                            <span className=\"text_12 color_white lh_16\">In order to get the endpoint for this model, you will need to deploy it on your Replicate dashboard. Once you have deployed your model on Hugging Face, you will be able to access the endpoint through the Hugging Face dashboard. The endpoint is a URL that you can use to send requests to your model.</span>\n                            <button className=\"secondary_button_small w_fit_content mt_16\"\n                                    onClick={() => window.open(\"https://ui.endpoints.huggingface.co/\", \"_blank\")}>Deploy<Image src=\"/images/open_in_new.svg\" alt=\"deploy_icon\" width={12} height={12} className=\"ml_4\" /></button>\n                        </div>\n                    </div>}\n\n                    <button className=\"primary_button w_fit_content align_self_end mt_24\" disabled={tokenError}\n                            onClick={() => storeModelDetails()}>Install</button>\n                </div>}\n            </div>\n            <div className=\"col-3\" />\n        </div>\n    )\n}"
  },
  {
    "path": "gui/pages/Content/Models/MarketModels.js",
    "content": "import React, {useState, useEffect} from \"react\";\nimport styles from \"@/pages/Content/Marketplace/Market.module.css\";\nimport Image from \"next/image\";\nimport {loadingTextEffect, modelIcon, returnToolkitIcon} from \"@/utils/utils\";\nimport {EventBus} from \"@/utils/eventBus\";\nimport {fetchMarketPlaceModel} from \"@/pages/api/DashboardService\";\nimport axios from \"axios\";\n\nexport default function MarketModels(){\n    const [showMarketplace, setShowMarketplace] = useState(false);\n    const [isLoading, setIsLoading] = useState(false)\n    const [loadingText, setLoadingText] = useState(\"Loading Models\");\n    const [modelTemplates, setModelTemplates] = useState([]);\n\n    // useEffect(() => {\n    //     loadingTextEffect('Loading Models', setLoadingText, 500);\n    //     setIsLoading(true)\n    //     if (window.location.href.toLowerCase().includes('marketplace')) {\n    //         axios.get('https://app.superagi.com/api/models_controller/get/models_details')\n    //             .then((response) => {\n    //                 setModelTemplates(response.data)\n    //             })\n    //     }\n    //     else {\n    //         fetchMarketPlaceModel().then((response) => {\n    //             setModelTemplates(response.data)\n    //         })\n    //     }\n    // },[])\n\n    // useEffect(() => {\n    //     if(modelTemplates.length > 0)\n    //         setIsLoading(true)\n    //     else\n    //         setIsLoading(false)\n    // }, [modelTemplates])\n\n    function handleTemplateClick(item) {\n        const contentType = 'model_template';\n        EventBus.emit('openTemplateDetails', {item, contentType});\n    }\n\n    useEffect(() => {\n        loadingTextEffect('Loading Models', setLoadingText, 500);\n        setIsLoading(true)\n        setTimeout(() => {\n            setIsLoading(false)\n        }, 2500);\n    }, []);\n\n    return(\n        <div>\n            <div className={`${\"h_calc_sub_60\"} ${\"w_99vw\"} ${isLoading ? 'display_none' : 'display_block'}`}>\n                <iframe\n                    id=\"marketplace_models\"\n                    src=\"https://models.superagi.com/marketplace\"\n                    width=\"100%\"\n                    height=\"100%\"\n                    frameBorder=\"0\"\n                    allowFullScreen\n                ></iframe>\n            </div>\n            {isLoading && <div className=\"horizontal_container_center h_75vh\">\n                <div className=\"signInInfo text_16 ff_sourceCode\">{loadingText}</div>\n            </div>}\n        </div>\n        // <div id=\"market_models\" className={showMarketplace ? 'ml_8' : 'ml_3'}>\n        //     <div className=\"w_100 overflowY_auto mxh_78vh\">\n        //         {isLoading ? <div>\n        //             {modelTemplates.length > 0 ? <div className=\"marketplaceGrid\">{modelTemplates.map((item) => (\n        //                 <div className=\"market_containers cursor_pointer\" key={item.id} onClick={() => handleTemplateClick(item)}>\n        //                     <div>{item.model_name && item.model_name.includes('/') ? item.model_name.split('/')[1] : item.model_name}</div>\n        //                     <div className=\"horizontal_container color_gray\">\n        //                         <span>by { item.model_name && item.model_name.includes('/') ? item.model_name.split('/')[0] : item.provider }</span>\n        //                         <Image className=\"mr_8 ml_4\" width={14} height={14} src=\"/images/is_verified.svg\" alt=\"is_verified\" />·\n        //                         <Image className=\"ml_8 mr_4\" width={16} height={16} src={modelIcon(item.provider)} alt=\"source-icon\" />\n        //                         <span className=\"mr_8\">{item.provider}</span>·\n        //                         <Image className=\"ml_8 mr_4\" width={15} height={15} src=\"/images/upload_icon.svg\" alt=\"download-icon\" />\n        //                         <span>{item.installs}</span>\n        //                     </div>\n        //                     <div className=\"text_ellipsis mt_14 color_gray\">{item.description}</div>\n        //                 </div>\n        //             ))}</div> : <div className=\"center_container mt_40\">\n        //                 <Image width={150} height={60} src=\"/images/no_permissions.svg\" alt=\"no-permissions\"/>\n        //                 <span className=\"feed_title mt_8\">No Models found!</span>\n        //             </div>}\n        //         </div> : <div className=\"horizontal_container_center h_75vh\">\n        //             <div className=\"signInInfo text_16 ff_sourceCode\">{loadingText}</div>\n        //         </div>}\n        //     </div>\n        // </div>\n    )\n}"
  },
  {
    "path": "gui/pages/Content/Models/ModelDetails.js",
    "content": "import React, {useState, useEffect} from \"react\";\nimport Image from \"next/image\";\nimport ModelMetrics from \"./ModelMetrics\";\nimport ModelInfo from \"./ModelInfo\";\nimport {fetchModel} from \"@/pages/api/DashboardService\";\nimport {loadingTextEffect} from \"@/utils/utils\";\n\nexport default function ModelDetails({modelId, modelName}){\n    const [modelDetails, setModelDetails] = useState([])\n    const [selectedOption, setSelectedOption] = useState('metrics')\n    const [isLoading, setIsLoading] = useState(true)\n    const [loadingText, setLoadingText] = useState(\"Loading Models\");\n\n    useEffect(() => {\n        loadingTextEffect('Loading Models', setLoadingText, 500);\n        const fetchModelDetails = async () => {\n            try {\n                const response = await fetchModel(modelId);\n                setModelDetails(response.data)\n                setIsLoading(false)\n            } catch(error) {\n                console.log(`Error Fetching the Details of the Model ${modelName}`, error)\n            }\n        };\n\n        fetchModelDetails().then().catch();\n    },[])\n\n    return(\n        <div id=\"model_details\" className=\"col-12 padding_5 overflowY_auto h_calc92\">\n            {!isLoading && <div className=\"vertical_containers padding_16_8\">\n                <span className=\"text_16\">{ modelDetails.name ? (modelDetails.name.split('/')[1] || modelDetails.name) : \"\"}</span>\n                <span className=\"text_12 color_gray mt_8 lh_18\">{modelDetails.description}</span>\n                <div className=\"horizontal_container gap_4 mt_16 mb_2\">\n                    <button className={selectedOption === 'metrics' ? 'tab_button_selected' : 'tab_button'}\n                            onClick={() => setSelectedOption('metrics')}>Metrics</button>\n                    <button className={selectedOption === 'details' ? 'tab_button_selected' : 'tab_button'}\n                            onClick={() => setSelectedOption('details')}>Details</button>\n                </div>\n            </div>}\n            {selectedOption === 'metrics' && !isLoading && <ModelMetrics modelDetails={modelDetails} />}\n            {selectedOption === 'details' && !isLoading &&  <ModelInfo modelDetails={modelDetails} />}\n            {isLoading && <div className=\"loading_container h_75vh\"><div className=\"signInInfo loading_text\">{loadingText}</div></div>}\n        </div>\n    )\n}"
  },
  {
    "path": "gui/pages/Content/Models/ModelForm.js",
    "content": "import React, {useEffect, useRef, useState} from \"react\";\nimport {removeTab, openNewTab, createInternalId, getUserClick} from \"@/utils/utils\";\nimport Image from \"next/image\";\nimport {fetchApiKey, storeModel, testModel, verifyEndPoint} from \"@/pages/api/DashboardService\";\nimport {BeatLoader, ClipLoader} from \"react-spinners\";\nimport {ToastContainer, toast} from 'react-toastify';\n\nexport default function ModelForm({internalId, getModels, sendModelData, env}){\n    const models = env === 'DEV' ? ['OpenAI', 'Replicate', 'Hugging Face', 'Google Palm', 'Local LLM'] : ['OpenAI', 'Replicate', 'Hugging Face', 'Google Palm'];\n    const [selectedModel, setSelectedModel] = useState('Select a Model');\n    const [modelName, setModelName] = useState('');\n    const [modelDescription, setModelDescription] = useState('');\n    const [modelTokenLimit, setModelTokenLimit] = useState(4096);\n    const [modelEndpoint, setModelEndpoint] = useState('');\n    const [modelDropdown, setModelDropdown] = useState(false);\n    const [modelVersion, setModelVersion] = useState('');\n    const [modelContextLength, setContextLength] = useState(4096);\n    const [tokenError, setTokenError] = useState(false);\n    const [lockAddition, setLockAddition] = useState(true);\n    const [isLoading, setIsLoading] = useState(false)\n    const [modelStatus, setModelStatus] = useState(null);\n    const [createClickable, setCreateClickable] = useState(true);\n    const modelRef = useRef(null);\n\n    useEffect(() => {\n        function handleClickOutside(event) {\n            if (modelRef.current && !modelRef.current.contains(event.target)) {\n                setModelDropdown(false)\n            }\n        }\n    },[]);\n\n    useEffect(() => {\n        const fetchMyAPI = async () => {\n            const error = await checkModelProvider(selectedModel)\n            if(selectedModel !== 'Select a Model' && !error)\n                setLockAddition(false)\n            else\n                setLockAddition(true)\n        }\n\n        fetchMyAPI();\n    },[selectedModel])\n\n    const handleModelSelect = async (index) => {\n        setSelectedModel(models[index])\n        setModelDropdown(false);\n    }\n\n    const checkModelProvider = async (model_provider) => {\n        const response = await fetchApiKey(model_provider);\n        console.log(response.data)\n        if(selectedModel !== 'Select a Model'){\n            if(response.data.length === 0) {\n                setTokenError(true)\n                return true\n            }\n            else {\n                setTokenError(false)\n                return false\n            }\n        }\n    }\n\n    const handleAddModel = () =>{\n        setIsLoading(true)\n        fetchApiKey(selectedModel).then((response) =>{\n            if(response.data.length > 0)\n            {\n                const modelProviderId = response.data[0].id\n                verifyEndPoint(response.data[0].api_key, modelEndpoint, selectedModel).then((response) =>{\n                    if(response.data.success)\n                        storeModelDetails(modelProviderId)\n                    else{\n                        toast.error(\"The Endpoint is not Valid\",{autoClose: 1800});\n                        setIsLoading(false);\n                    }\n                }).catch((error) => {\n                    console.log(\"Error Message:: \" + error)\n                })\n            }\n        })\n    }\n\n    const handleModelStatus = async () => {\n        try {\n            setCreateClickable(false);\n            const response = await testModel();\n            if(response.status === 200) {\n                setModelStatus(true);\n                setCreateClickable(true);\n            } else {\n                setModelStatus(false);\n                setCreateClickable(true);\n            }\n        } catch(error) {\n            console.log(\"Error Message:: \" + error);\n            setModelStatus(false);\n            setCreateClickable(true);\n        }\n    }\n\n    const handleModelSuccess = (model) => {\n        model.contentType = 'Model'\n        sendModelData(model)\n    }\n\n    const storeModelDetails = (modelProviderId) => {\n        storeModel(modelName,modelDescription, modelEndpoint, modelProviderId, modelTokenLimit, \"Custom\", modelVersion, modelContextLength).then((response) =>{\n            setIsLoading(false)\n            let data = response.data\n            if (data.error) {\n                toast.error(data.error,{autoClose: 1800});\n            } else if (data.success) {\n                toast.success(data.success,{autoClose: 1800});\n                getModels()\n                handleModelSuccess({id: data.model_id, name: modelName})\n            }\n        }).catch((error) => {\n            console.log(\"SORRY, There was an error storing the model details:\", error);\n            setIsLoading(false)\n        });\n    }\n\n    return(\n        <div id=\"model_form\" className=\"vertical_containers text_12\">\n            <div className=\"page_title mt_10\">Add new model</div>\n\n            <span className=\"mt_4\">Name</span>\n            <input className=\"input_medium mt_8\" type=\"text\" placeholder=\"Enter Model Name\"\n                   onChange={(event) => setModelName(event.target.value)}/>\n\n            <span className=\"mt_24\">Description</span>\n            <textarea className=\"textarea_medium mt_8\" placeholder=\"Write a Description\"\n                      onChange={(event) => setModelDescription(event.target.value)}/>\n\n            <span className=\"mt_24\">Model Provider</span>\n            <div className=\"dropdown_container_search mt_8 w_100\">\n                <div className=\"custom_select_container w_100\" onClick={() => setModelDropdown(!modelDropdown)}>\n                    {selectedModel}\n                    <Image width={20} height={21} src={!modelDropdown ? '/images/dropdown_down.svg' : '/images/dropdown_up.svg'} alt=\"expand-icon\"/>\n                </div>\n                <div>\n                    {modelDropdown && <div className=\"custom_select_options w_100\" ref={modelRef}>\n                        {models.map((model, index) => (\n                            <div key={index} className=\"custom_select_option\" onClick={() => {setModelStatus(null); handleModelSelect(index)}} style={{padding: '12px 14px', maxWidth: '100%'}}>\n                                {model}\n                            </div>))}\n                    </div>}\n                </div>\n            </div>\n\n            {tokenError && <div className=\"horizontal_container align_start error_box mt_24 gap_6\">\n                <Image width={16} height={16} src=\"/images/icon_error.svg\" alt=\"error-icon\" />\n                <div className=\"vertical_containers\">\n                    <span className=\"text_12 color_white lh_16\">The <b>{selectedModel}</b> auth token is not added to your settings. In order to start using the model, you need to add the auth token to your settings. You can find the auth token in the <b>{selectedModel}</b> dashboard. </span>\n                    <div className=\"horizontal_container mt_16\">\n                        <button className=\"primary_button_small\" onClick={() => {openNewTab(-3, \"Settings\", \"Settings\", false); getUserClick('Get Auth Token CLicked',{})}}>Add auth token</button>\n                        <button className=\"secondary_button_small ml_8\"\n                                onClick={() => window.open(modelGetAuth(selectedModel), \"_blank\")}>Get auth token<Image src=\"/images/open_in_new.svg\" alt=\"deploy_icon\" width={12} height={12} className=\"ml_4\" /></button>\n                    </div>\n                </div>\n            </div>}\n\n            {(selectedModel === 'Hugging Face') && <div className=\"mt_24\">\n                <span>Model Endpoint URL</span>\n                <input className=\"input_medium mt_8\" type=\"text\" placeholder=\"Enter Model Endpoint URL\"\n                       onChange={(event) => setModelEndpoint(event.target.value)}/>\n            </div>}\n\n            {(selectedModel === 'Replicate') && <div className=\"mt_24\">\n                <span>Model Version</span>\n                <input className=\"input_medium mt_8\" type=\"text\" placeholder=\"Enter Model Version\"\n                       onChange={(event) => setModelVersion(event.target.value)}/>\n            </div>}\n\n            {(selectedModel === 'Local LLM') && <div className=\"mt_24\">\n                <span>Model Context Length</span>\n                <input className=\"input_medium mt_8\" type=\"number\" placeholder=\"Enter Model Context Length\" value={modelContextLength}\n                       onChange={(event) => setContextLength(event.target.value)}/>\n            </div>}\n\n            <div className=\"mt_24\">\n                <span>Token Limit</span>\n                <input className=\"input_medium mt_8\" type=\"number\" placeholder=\"Enter Model Token Limit\" value={modelTokenLimit}\n                       onChange={(event) => setModelTokenLimit(parseInt(event.target.value, 10))}/>\n            </div>\n\n            {selectedModel === 'Local LLM' && modelStatus===false && <div className=\"horizontal_container align_start error_box mt_24 gap_6\">\n                <Image width={16} height={16} src=\"/images/icon_error.svg\" alt=\"error-icon\" />\n                <div className=\"vertical_containers\">\n                    <span className=\"text_12 color_white lh_16\">Test model failed</span>\n                </div>\n            </div>}\n\n            {selectedModel === 'Local LLM' && modelStatus===true && <div className=\"horizontal_container align_start success_box mt_24 gap_6\">\n                <Image width={16} height={16} src=\"/images/icon_info.svg\"/>\n                <div className=\"vertical_containers\">\n                    <span className=\"text_12 color_white lh_16\">Test model successful</span>\n                </div>\n            </div>}\n\n            <div className=\"horizontal_container justify_space_between w_100 mt_24\">\n                {selectedModel==='Local LLM' && <button className=\"secondary_button flex_none\" disabled={!createClickable} \n                onClick={() => {handleModelStatus();}}>{createClickable ? 'Test Model' : 'Testing model...'}</button>}\n                <div className=\"horizontal_container justify_end\">\n                    <button className=\"secondary_button mr_7\"\n                            onClick={() => removeTab(-5, \"new model\", \"Add_Model\", internalId)}>Cancel</button>\n                    <button className='primary_button' onClick={handleAddModel} disabled={lockAddition || isLoading || (selectedModel==='Local LLM' && !modelStatus)}>\n                        {isLoading ? <><span>Adding Model &nbsp;</span><ClipLoader size={16} color={\"#000000\"} /></> : 'Add Model'}\n                    </button>\n                </div>\n            </div>\n            <ToastContainer className=\"text_16\"/>\n        </div>\n    )\n}"
  },
  {
    "path": "gui/pages/Content/Models/ModelInfo.js",
    "content": "import React, {useState, useEffect} from \"react\";\nimport Image from \"next/image\";\n\nexport default function ModelInfo(modelDetails){\n    const [modelData, setModelData] = useState(modelDetails?.modelDetails)\n    return(\n        <div id=\"model_info\" className=\"text_12\">\n            <hr className=\"horizontal_line padding_0\" />\n            <div className=\"row\">\n                <div className=\"col-3\" />\n                <div className=\"col-6 col-6-scrollable vertical_containers\">\n                    <span>Installation Type</span>\n                    <div className=\"horizontal_container mt_8 color_white gap_4\">\n                        {modelData === 'Marketplace' && <Image width={16} height={16} src=\"/images/marketplace_logo.png\" alt=\"marketplace_logo\" />}\n                        <span>{modelData.type}</span>\n                    </div>\n\n                    <span className=\"mt_24\">Model Provider</span>\n                    <span className=\"mt_8 color_white\">{modelData.model_provider}</span>\n\n                    {modelData.end_point && <div className=\"vertical_containers\">\n                        <span className=\"mt_24\">Model Endpoint</span>\n                        <span className=\"mt_8 color_white\">{modelData.end_point}</span>\n                    </div>}\n\n                    <span className=\"mt_24\">Token Limit</span>\n                    <input className=\"input_medium mt_8\" type=\"number\" placeholder=\"Enter Model Token Limit\" value={modelData.token_limit} disabled/>\n                </div>\n                <div className=\"col-3\" />\n            </div>\n        </div>\n    )\n}"
  },
  {
    "path": "gui/pages/Content/Models/ModelMetrics.js",
    "content": "import React, {useState, useEffect} from \"react\";\nimport {fetchModelData} from \"@/pages/api/DashboardService\";\nimport {formatDateTime, formatNumber, returnToolkitIcon} from \"@/utils/utils\";\nimport Image from \"next/image\";\n\nexport default function ModelMetrics(modelDetails) {\n    const [modelData, setModelData] = useState(modelDetails);\n    const [modelMeta, setModelMeta] = useState([])\n    const [modelRunData, setModelRunData] = useState([])\n\n    useEffect(()=>{\n        setModelData(modelDetails.modelDetails);\n    },[modelDetails])\n\n    useEffect(()=>{\n        getModelInfo()\n    },[modelData, modelDetails])\n\n    const getModelInfo = () =>{\n        if(modelData.name !== undefined){\n            fetchModelData(modelData.name).then((response)=>{\n                console.log(response)\n                setModelMeta(response.data)\n                setModelRunData(response.data.runs)\n            })\n        }\n    }\n\n    return(\n        <div id=\"model_metrics\" className=\"overflowY_scroll\">\n            <div className=\"my_rows\">\n                <div className=\"my_col_4 display_column_container\">\n                    <span className=\"text_14 mb_8\">Total Calls</span>\n                    <div className=\"text_60_bold display_flex justify_center align_center w_100 h_100 mb_24\">{modelMeta.total_calls}</div>\n                </div>\n\n                <div className=\"my_col_4 display_column_container\">\n                    <span className=\"text_14 mb_8\">Total Tokens</span>\n                    <div className=\"text_60_bold display_flex justify_center align_center w_100 h_100 mb_24\">{formatNumber(modelMeta.total_tokens)}</div>\n                </div>\n\n                <div className=\"my_col_4 display_column_container\">\n                    <span className=\"text_14 mb_8\">Total Agents</span>\n                    <div className=\"text_60_bold display_flex justify_center align_center w_100 h_100 mb_24\">{modelMeta.total_agents}</div>\n                </div>\n            </div>\n            <div className=\"my_rows mt_8\">\n                <div className=\"my_col_12 display_column_container h_60vh\">\n                    <span className=\"text_14 mb_8\">Call Logs</span>\n                    {modelRunData.length === 0 ?\n                        <div className=\"vertical_container align_center mt_70 w_100\">\n                            <img src=\"/images/no_permissions.svg\" width={190} height={74} alt=\"No Data\"/>\n                            <span className=\"text_12 color_white mt_6\">No Used Tools Found</span>\n                        </div> : <div className=\"scrollable_container\">\n                            <table className=\"table_css margin_0 padding_0\">\n                                <thead>\n                                <tr style={{borderTop: 'none'}}>\n                                    <th className=\"table_header w_20\">Log Timestamp</th>\n                                    <th className=\"table_header w_20\">Agent Name</th>\n                                    <th className=\"table_header w_20\">Run Name</th>\n                                    <th className=\"table_header w_20\">Tool</th>\n                                    <th className=\"table_header text_align_right w_20\">Tokens Used</th>\n                                </tr>\n                                </thead>\n                            </table>\n\n                            <div className=\"overflow_auto w_100\">\n                                <table className=\"table_css margin_0\">\n                                    <tbody>\n                                    {modelRunData.map((data, index) => (\n                                        <tr key={index}>\n                                            <td className=\"table_data w_20\">{formatDateTime(data.created_at)}</td>\n                                            <td className=\"table_data w_20 br_left_grey\">{data.agent_name}</td>\n                                            <td className=\"table_data w_20 br_left_grey\">{data.agent_execution_name}</td>\n                                            <td className=\"table_data w_20 br_left_grey horizontal_container\">\n                                                {data.tool_used && <Image className=\"image_class bg_black\" width={20} height={20}\n                                                       src={returnToolkitIcon(data.toolkit_name)} alt=\"tool-icon\"/>}\n                                                <span>{data.tool_used ? data.tool_used : '-NA-'}</span>\n                                            </td>\n                                            <td className=\"table_data text_align_right w_20 br_left_grey\">{formatNumber(data.tokens_consumed)}</td>\n                                        </tr>\n                                    ))}\n                                    </tbody>\n                                </table>\n                            </div>\n                        </div>}\n                </div>\n            </div>\n        </div>\n    )\n}"
  },
  {
    "path": "gui/pages/Content/Models/ModelTemplate.js",
    "content": "import React, {useEffect, useState} from 'react';\nimport Image from \"next/image\";\nimport {EventBus} from \"@/utils/eventBus\";\nimport {getFormattedDate, modelIcon} from \"@/utils/utils\";\nimport AddModelMarketPlace from \"./AddModelMarketPlace\";\nexport default function ModelTemplate({env, template, getModels, sendModelData}){\n    const [isInstalled, setIsInstalled] = useState(false);\n\n    function handleBackClick() {\n        EventBus.emit('goToMarketplace', {});\n    }\n\n    function handleInstallClick() {\n        if (window.location.href.toLowerCase().includes('marketplace')) {\n            if (env === 'PROD') {\n                window.open(`https://app.superagi.com/`, '_self');\n            } else {\n                window.location.href = '/';\n            }\n        }\n        else {\n            setIsInstalled(true)\n        }\n    }\n\n    return (\n        <div id=\"model_template\">\n            <div className=\"back_button mt_16 mb_16\" onClick={() => isInstalled ? setIsInstalled(false) : handleBackClick()}>\n                <Image src=\"/images/arrow_back.svg\" alt=\"back_button\" width={14} height={12}/>\n                <span className=\"text_12 color_gray fw_500 ml_4\">Back</span>\n            </div>\n            { !isInstalled ? (<div className=\"gridContainer\">\n                <div className=\"col_3 display_column_container padding_16\">\n                    <span className=\"text_20 color_white\">{template.model_name}</span>\n                    <span className=\"text_12 color_gray mt_4\">by {template.model_name.includes('/') ? template.model_name.split('/')[0] : template.provider}</span>\n                    <button className=\"primary_button w_100 mt_16\" disabled={template.is_installed} onClick={() => handleInstallClick()}>\n                        <Image width={16} height={16} src={template.is_installed ? '/images/tick.svg' : '/images/marketplace_download.svg'} alt=\"download-icon\" />\n                        <span className=\"ml_8\">{template.is_installed ? 'Installed' : 'Install'}</span>\n                    </button>\n\n                    <hr className=\"horizontal_line\" />\n                    <span className=\"text_12 color_white lh_18\">{template.description}</span>\n                    <hr className=\"horizontal_line\" />\n\n                    <span className=\"text_12 color_gray\">Model Provider</span>\n                    <div className=\"tags mt_8\">\n                        <Image width={18} height={18} src={modelIcon(template.provider)} alt=\"logo-icon\" />\n                        <span className=\"text_12 color_white ml_4\">{template.provider}</span>\n                    </div>\n\n                    <hr className=\"horizontal_line\" />\n                    <span className=\"text_12 color_gray\">Updated At</span>\n                    <span className=\"text_12 color_white mt_8\">{getFormattedDate(template.updated_at)}</span>\n                </div>\n                <div className=\"col_9 display_column_container padding_16 color_white text_12 lh_18\" dangerouslySetInnerHTML={{ __html: template.model_features }} />\n            </div> ):(\n                <AddModelMarketPlace template={template} getModels={getModels} sendModelData={sendModelData}/>\n                )}\n        </div>\n    )\n}"
  },
  {
    "path": "gui/pages/Content/Models/Models.js",
    "content": "import React from \"react\";\nimport 'react-toastify/dist/ReactToastify.css';\nimport {createInternalId, getUserClick} from \"@/utils/utils\";\n\nexport default function Models({sendModelData, models}){\n\n    const handleModelSelect = (model) => {\n        getUserClick('Existing Model Clicked', {})\n        model.contentType = 'Model'\n        sendModelData(model)\n    }\n\n    return(\n        <div id=\"models\">\n            <div className=\"container\">\n                <p className=\"text_14 mt_8 mb_12 ml_8\">Models</p>\n                <div className=\"w_100 mb_10\">\n                    <button className=\"secondary_button w_100\"\n                            onClick={() => {sendModelData({id: -5, name: \"new model\", contentType: \"Add_Model\", internalId: createInternalId()}); getUserClick('Add Model Clicked',{})}}>\n                        + Add Model\n                    </button>\n                </div>\n\n                {models && models.length > 0 ? <div className=\"vertical_selection_scroll w_100\">\n                    {models.map((model, index) => (\n                        <div key={index}>\n                            <div className=\"sidebar_box flex_dir_col align_start w_100\" onClick={() => handleModelSelect(model)}>\n                                <div className=\"text_ellipsis\"><span className=\"text_13 lh_18 color_white text_ellipsis\">{model.name.split('/')[1] || model.name}</span></div>\n                                <div className=\"text_12 color_gray mt_4\">by {model.name.includes('/') ? model.name.split('/')[0] : model.model_provider} · {model.model_provider}</div>\n                            </div>\n                        </div>\n                    ))}\n                </div> : <div className=\"form_label mt_20 horizontal_container justify_center\">No Models found</div>}\n            </div>\n        </div>\n    )\n}"
  },
  {
    "path": "gui/pages/Content/Toolkits/AddTool.js",
    "content": "import React, {useState, useEffect} from 'react';\nimport {addTool} from \"@/pages/api/DashboardService\";\nimport {removeTab, setLocalStorageValue} from \"@/utils/utils\";\nimport {ToastContainer, toast} from \"react-toastify\";\n\nexport default function AddTool({internalId}) {\n  const [githubURL, setGithubURl] = useState('');\n  const [addClickable, setAddClickable] = useState(true);\n\n  const handleURLChange = (event) => {\n    setLocalStorageValue(\"tool_github_\" + String(internalId), event.target.value, setGithubURl);\n  };\n\n  const handleAddTool = () => {\n    if (githubURL.replace(/\\s/g, '') === '') {\n      toast.error(\"Github URL can't be blank\", {autoClose: 1800});\n      return\n    }\n\n    setAddClickable(false);\n\n    const toolData = {\n      \"github_link\": githubURL\n    }\n\n    addTool(toolData)\n      .then((response) => {\n        if (response.status === 200) {\n          toast.success('Tool will be installed in a while', {autoClose: 1800});\n          setAddClickable(true);\n          setLocalStorageValue(\"tool_github_\" + String(internalId), '', setGithubURl);\n        }\n      })\n      .catch((error) => {\n        if (error.response && error.response.status === 400) {\n          console.error('Error adding tool:', error);\n          toast.error('Invalid Github URL', {autoClose: 1800});\n        } else {\n          console.error('Error adding tool:', error);\n          toast.error(error.message, {autoClose: 1800});\n        }\n        setAddClickable(true);\n        setLocalStorageValue(\"tool_github_\" + String(internalId), '', setGithubURl);\n      });\n\n  };\n\n  useEffect(() => {\n    if (internalId !== null) {\n      const github_url = localStorage.getItem(\"tool_github_\" + String(internalId))\n      if (github_url) {\n        setGithubURl(github_url);\n      }\n    }\n  }, [internalId])\n\n  return (<>\n    <div className=\"row\">\n      <div className=\"col-3\"></div>\n      <div className=\"col-6 col-6-scrollable\">\n        <div className=\"page_title mt_10\">Add a new tool</div>\n        <label className=\"form_label_13\">Github Repository URL</label><br/>\n        <label className=\"form_label_13\">Paste your toolkits Github repo url here and we will sync & install</label>\n        <input placeholder=\"Enter URL here\" className=\"input_medium\" type=\"text\" value={githubURL} onChange={handleURLChange}/>\n\n        <div className=\"horizontal_container justify_end mt_14\">\n          <button className=\"secondary_button mr_7\" onClick={() => removeTab(-2, \"new tool\", \"Add_Toolkit\", internalId)}>Cancel\n          </button>\n          <button disabled={!addClickable} className=\"primary_button\" onClick={handleAddTool}>Add tool</button>\n        </div>\n      </div>\n      <div className=\"col-3\"></div>\n    </div>\n    <ToastContainer/>\n  </>)\n}"
  },
  {
    "path": "gui/pages/Content/Toolkits/Metrics.js",
    "content": "import React, {useState, useEffect, useRef} from 'react';\nimport {ToastContainer, toast} from 'react-toastify';\nimport 'react-toastify/dist/ReactToastify.css';\nimport {\n  getApiKeys, getToolMetrics, getToolLogs, getKnowledgeMetrics, getKnowledgeLogs\n} from \"@/pages/api/DashboardService\";\nimport {\n  loadingTextEffect,\n} from \"@/utils/utils\";\n\nexport default function Metrics({toolName, knowledgeName}) {\n  const [apiKeys, setApiKeys] = useState([]);\n  const [totalTokens, setTotalTokens] = useState(0)\n  const [totalAgentsUsing, setTotalAgentsUsing] = useState(0)\n  const [totalCalls, setTotalCalls] = useState(0)\n  const [callLogs, setCallLogs] = useState([])\n  const [isLoading, setIsLoading] = useState(true)\n  const [loadingText, setLoadingText] = useState(\"Loading Metrics\");\n  const metricsData = [\n    { label: 'Total Calls', value: totalCalls },\n    { label: 'Total Agents Using', value: totalAgentsUsing }\n  ];\n\n  useEffect(() => {\n    loadingTextEffect('Loading Metrics', setLoadingText, 500);\n  }, []);\n\n  useEffect(() => {\n    if(toolName && !knowledgeName){\n      fetchToolMetrics()\n      fetchToolLogs()\n      return;\n    }\n    if(!toolName && knowledgeName){\n      fetchKnowledgeMetrics()\n      fetchKnowledgeLogs()\n      return;\n    }\n  }, [toolName, knowledgeName]);\n\n  const fetchToolMetrics = () => {\n    getToolMetrics(toolName)\n      .then((response) => {\n        setTotalAgentsUsing(response.data.tool_unique_agents ? response.data.tool_unique_agents : 0)\n        setTotalCalls(response.data.tool_calls ? response.data.tool_calls : 0)\n        setIsLoading(false)\n      })\n      .catch((error) => {\n        console.error('Error fetching Metrics', error);\n      });\n  }\n\n  const fetchToolLogs = () => {\n    getToolLogs(toolName)\n      .then((response) => {\n        setCallLogs(response.data ? response.data : [])\n        setIsLoading(false)\n      })\n      .catch((error) => {\n        console.error('Error fetching Metrics', error);\n      });\n  }\n\n  const fetchKnowledgeMetrics = () => {\n    getKnowledgeMetrics(knowledgeName)\n      .then((response) => {\n        setTotalAgentsUsing(response.data.knowledge_unique_agents ? response.data.knowledge_unique_agents : 0)\n        setTotalCalls(response.data.knowledge_calls ? response.data.knowledge_calls : 0)\n        setIsLoading(false)\n      })\n      .catch((error) => {\n        console.error('Error fetching Metrics', error);\n      });\n  }\n\n  const fetchKnowledgeLogs = () => {\n    getKnowledgeLogs(knowledgeName)\n      .then((response) => {\n        setCallLogs(response.data ? response.data : [])\n        setIsLoading(false)\n      })\n      .catch((error) => {\n        console.error('Error fetching Metrics', error);\n      });\n  }\n\n  return (<>\n    <div className=\"row\">\n      <div className=\"col-12 padding_5 \">\n        {!isLoading ?\n          <div>\n            <div className=\"display_flex_container gap_5\">\n            {metricsData.map((metric, index) => (\n              <div className=\"display_column_container\" key={index}>\n                <span className=\"text_14\">{metric.label}</span>\n                <div className=\"text_60_bold display_flex justify_center align_center w_100 h_100 mb_24\">\n                  {metric.value}\n                </div>\n              </div>\n            ))}\n            </div>\n              <div className=\"display_column_container mt_5\">\n                <span className=\"text_14\">Call Logs</span>\n                {callLogs.length > 0 ? <div className=\"scrollable_container pd_bottom_5 br_8 bg_none\">\n                  <table className=\"w_100 margin_0 padding_0\">\n                    <thead>\n                    <tr className=\"border_top_none text_align_left border_bottom_none\">\n                      <th className=\"table_header w_15\">Log Timestamp</th>\n                      <th className=\"table_header w_15\">Agent Name</th>\n                      <th className=\"table_header w_40\">Run Name</th>\n                      <th className=\"table_header w_15\">Model</th>\n                      <th className=\"table_header w_15\">Tokens Used</th>\n                    </tr>\n                    </thead>\n                  </table>\n                  <div className=\"overflow_auto w_100\">\n                    <table className=\"table_css margin_0\">\n                      <tbody>\n                      {callLogs.map((item, index) => (\n                        <tr key={index} className=\"text_align_left\">\n                          <td className=\"table_data w_15\">{item.created_at}</td>\n                          <td className=\"table_data w_15 br_left_grey\">{item.agent_name}</td>\n                          <td className=\"table_data w_40 br_left_grey\">{item.agent_execution_name}</td>\n                          <td className=\"table_data w_15 br_left_grey\">{item.model}</td>\n                          <td className=\"table_data w_15 br_left_grey\">{item.tokens_consumed}</td>\n                        </tr>\n                      ))}\n                      </tbody>\n                    </table>\n                  </div>\n                </div> :\n                  <div className=\"vertical_container align_center mt_90 w_100 mb_90\">\n                    <img src=\"/images/no_permissions.svg\" width={190} height={74} alt=\"No Data\"/>\n                    <span className=\"text_12 color_white mt_6\">No logs to show!</span>\n                  </div>}\n          </div>\n          </div>\n          :  <div className=\"loading_container\">\n          <div className=\"signInInfo loading_text\">{loadingText}</div>\n        </div>}\n      </div>\n    </div>\n    <ToastContainer/>\n  </>)\n}"
  },
  {
    "path": "gui/pages/Content/Toolkits/Tool.module.css",
    "content": ".tool_filter {\n    font-size: 14px;\n    padding: 5px 8px;\n    border-radius: 8px;\n    cursor: pointer;\n    margin-right: 10px;\n    min-width: 55px;\n    text-align: center;\n}\n\n.tab_button {\n    width: 100%;\n    border: none;\n    font-style: normal;\n    font-weight: 400;\n    font-size: 12px;\n    line-height: 15px;\n    color: #FFFFFF;\n    border-radius: 8px;\n    padding: 8px 10px;\n}\n\n.selected {\n    background: #EBEBEB;\n    color: #111111;\n}\n\n.not_selected {\n    background: transparent;\n    color: #666666;\n}\n\n.tool_container {\n    display: flex;\n    flex-wrap: wrap;\n    justify-content: flex-start;\n    overflow-y: scroll;\n    gap: 10px;\n}\n\n.tool_name {\n    font-style: normal;\n    font-weight: 500;\n    font-size: 12px;\n    line-height: 21px;\n    color: #FEFEFE;\n    margin-top: -2px;\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 1;\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.tool_publisher {\n    font-style: normal;\n    font-weight: 500;\n    font-size: 9px;\n    line-height: 12px;\n    display: flex;\n    align-items: center;\n    color: #666666;\n    margin-top: 2px;\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 1;\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.tool_description {\n    line-height:16px;\n    margin-top: 5px;\n    color: #888888;\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 2;\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.toolkit_description {\n    line-height:16px;\n    margin-top: 5px;\n    color: #888888;\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 1;\n}\n\n.tool_box {\n    cursor: pointer;\n    width: 100%;\n    border-radius: 8px;\n}\n\n.tag_box {\n    display: flex;\n    margin: 15px 0 0 0;\n    flex-wrap: wrap;\n}\n.more_button{\n    margin-left: 4px;\n    box-sizing: border-box;\n    display: flex;\n    flex-direction: row;\n    justify-content: center;\n    align-items: center;\n    padding: 8px 10px;\n    gap: 6px;\n    width: 36px;\n    height: 32px;\n    background: none;\n    border: none;\n    border-radius: 8px;\n    cursor: pointer;\n}\n\n.tool_box:hover{\n    background-color: #494856;\n}\n\n.image_class{\n    background: #FFFFFF80;\n    border-radius: 20px;\n}\n\n.CodeMirror{\n    background-color: #291A66 !important;\n    border: 1px solid #4A4A55 !important;\n}\n\n.code_head{\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    height: 26px;\n    font-style: normal;\n    font-weight: 400;\n    font-size: 12px;\n    line-height: 18px;\n    color: #FFFFFF;\n    background: rgba(255, 255, 255, 0.2);\n}\n\n.button_class{\n    margin-top:20px;\n    float: right;\n    display: flex;\n    gap: 5px;\n}\n\n.tool1_box {\n    height: 30px;\n    font-size: 12px;\n    text-align: center;\n    display: flex;\n    align-items: center;\n    padding: 8px;\n    border-radius: 8px;\n    cursor: pointer;\n}\n\n.tab_text {\n    font-style: normal;\n    font-weight: 400;\n    font-size: 12px;\n    line-height: 15px;\n    color: #FFFFFF;\n    padding: 8px;\n}\n\n.tools_container{\n    text-align: center;\n    font-size: 12px;\n    color: white;\n}\n\n.feed_title {\n    font-family: 'Source Code Pro';\n    margin-left: 10px;\n    font-style: normal;\n    font-weight: 500;\n    font-size: 12px;\n    line-height: 15px;\n    color: white;\n    white-space: pre-line;\n    word-wrap: break-word;\n    max-width: 95%;\n}\n\n.search_box {\n    width: 100%;\n}\n\n.search_box input {\n    width: 100%;\n    height: 25px;\n    font-size: x-small;\n    padding: 5px;\n    border: 1px solid rgb(96, 96, 96);\n    border-radius: 6px;\n    background-color: #454254;\n}\n\n.search_box textarea {\n    width: 100%;\n    min-height: 60px;\n    max-height: 120px;\n    font-size: x-small;\n    padding: 5px;\n    border: 1px solid rgb(96, 96, 96);\n    border-radius: 6px;\n    background-color: #454254;\n}\n\n.show_more_button {\n    cursor: pointer;\n    color: white;\n}\n\n.tools_included{\n    font-size: small;\n    background-color:rgb(39,35,53);\n    border-radius: 8px;\n    width:100%;\n    height: auto;\n    text-align: left;\n    padding:13px;\n    margin-bottom: 6px;\n}\n"
  },
  {
    "path": "gui/pages/Content/Toolkits/ToolkitWorkspace.js",
    "content": "import React, {useEffect, useRef, useState} from 'react';\nimport Image from 'next/image';\nimport {ToastContainer, toast} from 'react-toastify';\nimport {\n  updateToolConfig,\n  getToolConfig,\n  authenticateGoogleCred,\n  authenticateTwitterCred\n} from \"@/pages/api/DashboardService\";\nimport styles from './Tool.module.css';\nimport {setLocalStorageValue, setLocalStorageArray, returnToolkitIcon, convertToTitleCase} from \"@/utils/utils\";\nimport Metrics from \"@/pages/Content/Toolkits/Metrics\";\n\nexport default function ToolkitWorkspace({env, toolkitDetails, internalId}) {\n  const [activeTab, setActiveTab] = useState('metrics')\n  const [showDescription, setShowDescription] = useState(false)\n  const [apiConfigs, setApiConfigs] = useState([]);\n  const [toolsIncluded, setToolsIncluded] = useState([]);\n  const [loading, setLoading] = useState(true);\n  const authenticateToolkits = ['Google Calendar Toolkit', 'Twitter Toolkit'];\n  const [toolDropdown, setToolDropdown] = useState(false);\n  const toolRef = useRef(null);\n  const [currTool, setCurrTool] = useState(false);\n\n\n  let handleKeyChange = (event, index) => {\n    const updatedData = [...apiConfigs];\n    updatedData[index].value = event.target.value;\n    setLocalStorageArray('api_configs_' + String(internalId), updatedData, setApiConfigs);\n  };\n\n  function getGoogleToken(client_data) {\n    var redirect_uri = \"\";\n    if (env == \"PROD\") {\n      redirect_uri = 'https://app.superagi.com/api/google/oauth-tokens';\n    } else {\n      redirect_uri = \"http://localhost:3000/api/google/oauth-tokens\";\n    }\n    const client_id = client_data.client_id\n    const scope = 'https://www.googleapis.com/auth/calendar';\n    window.location.href = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${client_id}&redirect_uri=${redirect_uri}&access_type=offline&approval_prompt=force&response_type=code&scope=${scope}&state=${toolkitDetails.id}`;\n  }\n\n  function getTwitterToken(oauth_data) {\n    window.location.href = `https://api.twitter.com/oauth/authenticate?oauth_token=${oauth_data.oauth_token}`\n  }\n\n  useEffect(() => {\n    if (toolkitDetails !== null) {\n      if (toolkitDetails.tools) {\n        setToolsIncluded(toolkitDetails.tools);\n        setCurrTool(toolkitDetails.tools[0].name)\n      }\n\n      getToolConfig(toolkitDetails.name)\n        .then((response) => {\n          const localStoredConfigs = localStorage.getItem('api_configs_' + String(internalId));\n          const apiConfigs = response.data || [];\n          setApiConfigs(localStoredConfigs ? JSON.parse(localStoredConfigs) : apiConfigs);\n        })\n        .catch((error) => {\n          console.log('Error fetching API data:', error);\n        })\n        .finally(() => {\n          setLoading(false);\n        });\n    }\n  }, [toolkitDetails]);\n\n  const handleUpdateChanges = async () => {\n    if(apiConfigs.some(config => config?.is_required && !config.value)){\n      toast.error(\"Please input necessary details\", 1800)\n      return\n    }\n    const updatedConfigData = apiConfigs.map((config) => ({\n      key: config.key,\n      value: config.value,\n    }));\n\n    updateToolConfig(toolkitDetails.name, updatedConfigData)\n      .then((response) => {\n        toast.success('Toolkit configuration updated', {autoClose: 1800});\n      })\n      .catch((error) => {\n        toast.error('Unable to update Toolkit configuration', {autoClose: 1800});\n        console.error('Error updating tool config:', error);\n      });\n  };\n\n  const handleAuthenticateClick = async (toolkitName) => {\n    handleUpdateChanges();\n    if (toolkitName === \"Google Calendar Toolkit\") {\n      authenticateGoogleCred(toolkitDetails.id)\n        .then((response) => {\n          localStorage.setItem(\"google_calendar_toolkit_id\", toolkitDetails.id)\n          getGoogleToken(response.data);\n        })\n        .catch((error) => {\n          toast.error('Unable to authenticate tool', {autoClose: 1800});\n          console.error('Error fetching data:', error);\n        });\n    } else if (toolkitName === \"Twitter Toolkit\") {\n      authenticateTwitterCred(toolkitDetails.id)\n        .then((response) => {\n          localStorage.setItem(\"twitter_toolkit_id\", toolkitDetails.id)\n          getTwitterToken(response.data);\n        })\n        .catch((error) => {\n          toast.error('Unable to authenticate tool', {autoClose: 1800});\n          console.error('Error fetching data: ', error);\n        });\n    }\n  };\n\n  useEffect(() => {\n    if (internalId !== null) {\n      const active_tab = localStorage.getItem('toolkit_tab_' + String(internalId));\n      if (active_tab) {\n        setActiveTab(active_tab);\n      }\n    }\n  }, [internalId]);\n\n  useEffect(() => {\n    function handleClickOutside(event) {\n      if (toolRef.current && !toolRef.current.contains(event.target)) {\n        setToolDropdown(false)\n      }\n    }\n    document.addEventListener('mousedown', handleClickOutside);\n    return () => {\n      document.removeEventListener('mousedown', handleClickOutside);\n    };\n  }, []);\n  return (<>\n    <div className=\"row\">\n      <div className=\"col-12 col-6-scrollable\">\n        <div className={styles.tools_container}>\n          <div className=\"horizontal_container align_start mb_20\">\n            <Image src={returnToolkitIcon(toolkitDetails?.name)} alt=\"toolkit-icon\" width={45} height={45} className=\"tool_icon\" />\n            <div className=\"vertical_containers ml_15 text_align_left mr_10\">\n              <div className=\"text_17\">{toolkitDetails.name}</div>\n              <div className={styles.toolkit_description} style={!showDescription ? {overflow: 'hidden'} : {display: 'block'}}>\n                {`${showDescription ? toolkitDetails.description : toolkitDetails.description.slice(0, 70)}`}\n                {toolkitDetails.description.length > 70 &&\n                    <span className={styles.show_more_button} onClick={() => setShowDescription(!showDescription)}>\n                      {showDescription ? '...less' : '...more'}\n                  </span>}\n              </div>\n            </div>\n          </div>\n          <div className=\"horizontal_container mb_10 border_bottom_grey pd_bottom_5\">\n            <div className=\"w_50 display_flex_container\">\n            <div className={activeTab === 'metrics' ? 'tab_button_small_selected' : 'tab_button_small'}\n                 onClick={() => setLocalStorageValue('toolkit_tab_' + String(internalId), 'metrics', setActiveTab)}>\n              <div className=\"text_12 color_white padding_8\">Metrics</div>\n            </div>\n            <div className={activeTab === 'configuration' ? 'tab_button_small_selected' : 'tab_button_small'}\n                 onClick={() => setLocalStorageValue('toolkit_tab_' + String(internalId), 'configuration', setActiveTab)}>\n              <div className=\"text_12 color_white padding_8\">Configuration</div>\n            </div>\n            <div className={activeTab === 'tools_included' ? 'tab_button_small_selected' : 'tab_button_small'}\n                 onClick={() => setLocalStorageValue('toolkit_tab_' + String(internalId), 'tools_included', setActiveTab)}>\n              <div className=\"text_12 color_white padding_8\">Tools Included</div>\n            </div>\n            </div>\n            {!loading && activeTab === 'metrics' && <div className=\"display_flex_container w_50 justify_end\">\n              <div className=\"dropdown_container_search \">\n                <div className=\"custom_select_container w_180p\" onClick={() => setToolDropdown(!toolDropdown)}>\n                  {currTool}<Image width={20} height={21}\n                                        src={!toolDropdown ? '/images/dropdown_down.svg' : '/images/dropdown_up.svg'}\n                                        alt=\"expand-icon\"/>\n                </div>\n                <div>\n                  {toolDropdown && <div className=\"custom_select_options text_align_left w_100\" ref={toolRef}>\n                    {toolsIncluded.map((tool, index) => (\n                      <div key={index} className=\"custom_select_option mxw_100 padding_12_14\" onClick={() => {setCurrTool(tool.name); setToolDropdown(false)}}>\n                        {tool.name}\n                      </div>))}\n                  </div>}\n                </div>\n              </div>\n            </div>}\n          </div>\n          <div className=\"row\">\n            <div className=\"col-3\"></div>\n            <div className=\"col-6\">\n          {!loading && activeTab === 'configuration' && <div>\n            {apiConfigs.length > 0 ? (apiConfigs.map((config, index) => (\n              <div key={index}>\n                <div className=\"vertical_containers w_100 color_gray mb_20 text_align_left\">\n                  <label className=\"mb_6\">{convertToTitleCase(config.key)}</label>\n                  <div className={styles.search_box}>\n                    {config?.key_type !== \"file\" && <input className=\"color_white\" type={config?.is_secret ? 'password' : 'text'} value={config.value || ''} onChange={(event) => handleKeyChange(event, index)}/>}\n                    {config?.key_type === \"file\" && <textarea className=\"color_white\" type={config?.is_secret ? 'password' : 'text'} value={config.value || ''} onChange={(event) => handleKeyChange(event, index)}/>}\n                  </div>\n                </div>\n              </div>\n            ))) : (<div className=\"vertical_container mt_40 w_100\">\n              <Image width={150} height={60} src=\"/images/no_permissions.svg\" alt=\"no-permissions\"/>\n              <span className=\"feed_title mt_8\">No Keys found!</span>\n            </div>)}\n\n            {apiConfigs.length > 0 && (\n              <div className=\"horizontal_space_between\">\n                {authenticateToolkits.includes(toolkitDetails.name) &&\n                  <button className=\"primary_button w_fit_content\" onClick={() => handleAuthenticateClick(toolkitDetails.name)}>Authenticate Tool</button>}\n                  <button className=\"primary_button\" onClick={handleUpdateChanges}>Update Changes</button>\n              </div>)}\n          </div>}\n          {activeTab === 'tools_included' && <div>\n            {toolsIncluded.map((tool, index) => (\n              <div key={index} className={styles.tools_included}>\n                <div>\n                  <div className=\"color_white\">{tool.name}</div>\n                  <div className=\"color_gray mt_5\">{tool.description}</div>\n                </div>\n              </div>\n            ))}\n          </div>}\n            </div>\n          <div className=\"col-3\"></div>\n          </div>\n          {activeTab === 'metrics' && <div>\n            <Metrics toolName={currTool} />\n          </div>}\n        </div>\n      </div>\n    </div>\n    <ToastContainer/>\n  </>);\n}\n\n\n\n\n"
  },
  {
    "path": "gui/pages/Content/Toolkits/Toolkits.js",
    "content": "import React from 'react';\nimport Image from \"next/image\";\nimport {createInternalId, returnToolkitIcon, excludedToolkits} from \"@/utils/utils\";\n\nexport default function Toolkits({sendToolkitData, toolkits, env}) {\n  return (\n    <>\n      <div className=\"container\">\n        <p className=\"text_14 mt_8 mb_12 ml_8\">Toolkits</p>\n        {env !== 'PROD' && <div className=\"w_100 mb_10\">\n          <button className=\"secondary_button w_100\" onClick={() => sendToolkitData({\n            id: -2,\n            name: \"new tool\",\n            contentType: \"Add_Toolkit\",\n            internalId: createInternalId()\n          })}>\n            + Add Tool\n          </button>\n        </div>}\n        {toolkits && toolkits.length > 0 ? (\n          <div className={`${env === \"PROD\" ? 'h_calc_add40' : 'h_80vh'} ${\"overflowY_scroll\"}`}>\n          {toolkits.map((tool, index) =>\n              tool.name !== null && !excludedToolkits().includes(tool.name) && (\n                <div key={index} className=\"item_box mb_10\" onClick={() => sendToolkitData(tool)}>\n                  <div className=\"row\">\n                    <div className=\"col-12\">\n                      <div className=\"item_container padding_5\">\n                         <Image className=\"image_class bg_black\" width={30} height={30}\n                             src={returnToolkitIcon(tool.name)}\n                             alt=\"tool-icon\"/>\n                        <div className=\"ml_8\">\n                          <div className=\"item_name\">{tool.name}</div>\n                          <div className=\"item_publisher\">by SuperAGI</div>\n                        </div>\n                      </div>\n                    </div>\n                  </div>\n                </div>\n              )\n          )}\n          </div>\n        ) : (\n          <div className=\"form_label mt_20 horizontal_container justify_center\">No Toolkits found</div>\n        )}\n      </div>\n    </>\n  );\n}\n"
  },
  {
    "path": "gui/pages/Dashboard/Content.js",
    "content": "import React, {useEffect, useRef, useState} from 'react';\nimport Agents from '../Content/Agents/Agents';\nimport Knowledge from '../Content/Knowledge/Knowledge';\nimport AddKnowledge from '../Content/Knowledge/AddKnowledge';\nimport KnowledgeDetails from '../Content/Knowledge/KnowledgeDetails';\nimport AgentWorkspace from '../Content/Agents/AgentWorkspace';\nimport AgentCreate from '../Content/Agents/AgentCreate';\nimport ToolkitWorkspace from '../Content/./Toolkits/ToolkitWorkspace';\nimport Toolkits from '../Content/./Toolkits/Toolkits';\nimport Settings from \"./Settings/Settings\";\nimport styles from './Dashboard.module.css';\nimport ApmDashboard from \"../Content/APM/ApmDashboard\";\nimport AddModel from \"../Content/Models/AddModel\";\nimport Models from \"../Content/Models/Models\";\nimport ModelDetails from \"../Content/Models/ModelDetails\";\nimport Image from \"next/image\";\nimport {EventBus} from \"@/utils/eventBus\";\nimport {\n  getAgents,\n  getToolKit,\n  getKnowledge,\n  getLastActiveAgent,\n  sendGoogleCreds,\n  sendTwitterCreds,\n  fetchModels,\n} from \"@/pages/api/DashboardService\";\nimport Market from \"../Content/Marketplace/Market\";\nimport AgentTemplatesList from '../Content/Agents/AgentTemplatesList';\nimport {useRouter} from 'next/router';\nimport querystring from 'querystring';\nimport styles1 from '../Content/Agents/Agents.module.css';\nimport AddTool from \"@/pages/Content/Toolkits/AddTool\";\nimport {createInternalId, resetLocalStorage, preventDefault, getUserClick} from \"@/utils/utils\";\nimport AddDatabase from \"@/pages/Dashboard/Settings/AddDatabase\";\nimport DatabaseDetails from \"@/pages/Dashboard/Settings/DatabaseDetails\";\n\nexport default function Content({env, selectedView, selectedProjectId, organisationId}) {\n  const [tabs, setTabs] = useState([]);\n  const [selectedTab, setSelectedTab] = useState(null);\n  const [agents, setAgents] = useState(null);\n  const [toolkits, setToolkits] = useState(null);\n  const [knowledge, setKnowledge] = useState(null);\n  const tabContainerRef = useRef(null);\n  const [toolkitDetails, setToolkitDetails] = useState({});\n  const [models, setModels] = useState([]);\n  const [starModal, setStarModal] = useState(false);\n  const router = useRouter();\n  const multipleTabContentTypes = ['Create_Agent', 'Add_Toolkit', 'Add_Knowledge', 'Add_Database', 'Add_Model', 'Edit_Agent'];\n  const [isApmOpened, setIsApmOpened] = useState(false);\n  const [prevView, setPrevView] = useState(null);\n\n  useEffect(() => {\n    if (prevView !== selectedView) {\n      const apmTab = tabs.find(tab => tab.contentType === 'APM');\n      setIsApmOpened(!!apmTab);\n      setPrevView(selectedView);\n    }\n  }, [selectedView, tabs, prevView]);\n\n  async function fetchAgents() {\n    try {\n      const response = await getAgents(selectedProjectId);\n      const data = response.data || [];\n      const updatedData = data.map(item => {\n        return {...item, contentType: \"Agents\"};\n      });\n      setAgents(updatedData);\n    } catch (error) {\n      console.error('Error fetching agents:', error);\n    }\n  }\n\n  function getAgentList() {\n    fetchAgents()\n      .then(() => {\n        console.log('Agents fetched successfully!');\n      })\n      .catch((error) => {\n        console.error('Error fetching agents:', error);\n      });\n  }\n\n  async function fetchToolkits() {\n    try {\n      const response = await getToolKit();\n      const data = response.data || [];\n      const updatedData = data.map(item => {\n        let updatedName = item.name === \"Web Scrapper Toolkit\" ? \"Web Scraper Toolkit\" : item.name;\n        return {...item,name: updatedName,  contentType: \"Toolkits\", isOpen: false, internalId: createInternalId()};\n      });\n      setToolkits(updatedData);\n    } catch (error) {\n      console.error('Error fetching toolkits:', error);\n    }\n  }\n\n  function getToolkitList() {\n    fetchToolkits()\n      .then(() => {\n        console.log('Toolkits fetched successfully!');\n      })\n      .catch((error) => {\n        console.error('Error fetching toolkits:', error);\n      });\n  }\n\n  async function getModels() {\n    try{\n      const response = await fetchModels();\n      console.log(response.data)\n      setModels(response.data)\n\n    } catch(error){\n      console.error('Error fetching models:', error);\n    }\n  }\n\n  async function fetchKnowledge() {\n    try {\n      const response = await getKnowledge();\n      const data = response.data || [];\n      const updatedData = data.map(item => {\n        return {...item, contentType: \"Knowledge\", internalId: createInternalId()};\n      });\n      setKnowledge(updatedData);\n    } catch (error) {\n      console.error('Error fetching knowledge:', error);\n    }\n  }\n\n  function getKnowledgeList() {\n    fetchKnowledge()\n      .then(() => {\n        console.log('Knowledge fetched successfully!');\n      })\n      .catch((error) => {\n        console.error('Error fetching knowledge:', error);\n      });\n  }\n\n  useEffect(() => {\n    getAgentList();\n    getToolkitList();\n    getModels();\n  }, [selectedProjectId])\n\n  useEffect(() => {\n    getKnowledgeList();\n  }, [organisationId])\n\n  const cancelTab = (index, contentType, internalId) => {\n    let updatedTabs = [...tabs];\n\n    if (selectedTab === index) {\n      updatedTabs.splice(index, 1);\n\n      if (index === 0 && tabs.length === 1) {\n        setSelectedTab(null);\n      } else {\n        const newIndex = index === tabs.length - 1 ? index - 1 : index;\n        setSelectedTab(newIndex);\n      }\n    } else {\n      if (selectedTab > index) {\n        setSelectedTab(selectedTab - 1);\n      }\n\n      updatedTabs.splice(index, 1);\n    }\n\n    if(contentType === \"APM\")\n      getUserClick('APM Closed',{})\n\n    resetLocalStorage(contentType, internalId);\n    setTabs(updatedTabs);\n  };\n\n  const addTab = (element) => {\n    let addedTabIndex = null;\n    if (element.contentType === \"Toolkits\") {\n      setToolkitDetails(element);\n    }\n\n    const isExistingTab = tabs.some(\n      (tab) => tab.id === element.id && tab.name === element.name && tab.contentType === element.contentType && !multipleTabContentTypes.includes(element.contentType)\n    );\n\n    if (!isExistingTab) {\n      const updatedTabs = [...tabs, element];\n      setTabs(updatedTabs);\n      addedTabIndex = updatedTabs.length - 1;\n      setSelectedTab(addedTabIndex);\n    } else {\n      const existingTabIndex = tabs.findIndex(\n        (tab) => tab.id === element.id && tab.name === element.name && tab.contentType === element.contentType\n      );\n      setSelectedTab(existingTabIndex);\n    }\n  };\n\n  const selectTab = (element, index) => {\n    setSelectedTab(index);\n    if (element.contentType === \"Toolkits\") {\n      setToolkitDetails(element);\n    }\n  };\n\n  useEffect(() => {\n    if (tabContainerRef.current) {\n      const tabElement = tabContainerRef.current.querySelector(`[data-tab-id=\"${selectedTab}\"]`);\n      if (tabElement) {\n        const containerScrollLeft = tabContainerRef.current.scrollLeft;\n        const tabOffsetLeft = tabElement.offsetLeft;\n        const containerWidth = tabContainerRef.current.offsetWidth;\n\n        if (tabOffsetLeft < containerScrollLeft || tabOffsetLeft >= containerScrollLeft + containerWidth) {\n          tabContainerRef.current.scrollLeft = tabOffsetLeft;\n        }\n      }\n    }\n\n    const queryParams = router.asPath.split('?')[1];\n    const parsedParams = querystring.parse(queryParams);\n    parsedParams[\"toolkit_id\"] = toolkitDetails.toolkit_id;\n\n    if (window.location.href.indexOf(\"twitter_creds\") > -1) {\n      parsedParams[\"toolkit_id\"] = localStorage.getItem(\"twitter_toolkit_id\") || null;\n      const params = JSON.stringify(parsedParams)\n\n      sendTwitterCreds(params)\n        .then((response) => {\n          console.log(\"Authentication completed successfully\");\n        })\n        .catch((error) => {\n          console.error(\"Error fetching data: \", error);\n        })\n    }\n\n    if (window.location.href.indexOf(\"google_calendar_creds\") > -1) {\n      const toolkit_id = localStorage.getItem(\"google_calendar_toolkit_id\") || null;\n      let data = Object.keys(parsedParams)[0];\n      let params = JSON.parse(data);\n\n      sendGoogleCreds(params, toolkit_id)\n        .then((response) => {\n          console.log(\"Authentication completed successfully\");\n        })\n        .catch((error) => {\n          console.error(\"Error fetching data: \", error);\n        })\n    }\n  }, [selectedTab]);\n\n  useEffect(() => {\n    const openNewTab = (eventData) => {\n      addTab(eventData.element);\n    };\n\n    const openToolkitTab = (eventData) => {\n      const toolkit = toolkits?.find((toolkit) => toolkit.tools.some((tool) => tool.id === eventData.toolId));\n      if (toolkit) {\n        localStorage.setItem('toolkit_tab_' + String(toolkit.internalId), 'tools_included');\n        addTab(toolkit);\n      }\n    }\n\n    const removeTab = (eventData) => {\n      const element = eventData.element;\n      const tabIndex = tabs.findIndex(\n        (tab) => tab.id === element.id &&\n          tab.name === element.name &&\n          tab.contentType === element.contentType &&\n          tab.internalId === element.internalId\n      );\n      cancelTab(tabIndex, element.contentType, element.internalId);\n    };\n\n    EventBus.on('openNewTab', openNewTab);\n    EventBus.on('reFetchAgents', getAgentList);\n    EventBus.on('reFetchKnowledge', getKnowledgeList);\n    EventBus.on('removeTab', removeTab);\n    EventBus.on('openToolkitTab', openToolkitTab);\n\n    return () => {\n      EventBus.off('openNewTab', openNewTab);\n      EventBus.off('reFetchAgents', getAgentList);\n      EventBus.off('reFetchKnowledge', getKnowledgeList);\n      EventBus.off('removeTab', removeTab);\n    };\n  });\n\n  async function fetchLastActive() {\n    try {\n      const response = await getLastActiveAgent(selectedProjectId);\n      addTab(response.data);\n    } catch (error) {\n      console.error('Error fetching last active agent:', error);\n    }\n  }\n\n  function getLastActive() {\n    fetchLastActive()\n      .then(() => {\n        console.log('Last active agent fetched successfully!');\n      })\n      .catch((error) => {\n        console.error('Error fetching last active agent:', error);\n      });\n  }\n\n  const openGithubRepo = () => {\n    window.open('https://github.com/TransformerOptimus/SuperAGI', '_blank');\n    localStorage.setItem('repo_starred', 'starred');\n    setStarModal(false);\n  };\n\n  const closeStarModal = () => {\n    const closedTime = Date.now();\n    localStorage.setItem('popup_closed_time', JSON.stringify(closedTime));\n    setStarModal(false);\n  };\n\n  useEffect(() => {\n    const last_closed_time = localStorage.getItem('popup_closed_time');\n    const minTime = 4 * 24 * 60 * 60 * 1000;\n    const repo_starred = localStorage.getItem('repo_starred');\n\n    if (!repo_starred && Date.now() - JSON.parse(last_closed_time) > minTime) {\n      setStarModal(true);\n    }\n  }, []);\n\n  return (<>\n      <div style={{display: 'flex', height: '100%'}}>\n        {(selectedView === 'agents' || selectedView === 'toolkits' || selectedView === 'knowledge' || selectedView === 'models') &&\n          <div className={styles.item_list} style={{width: '13vw'}}>\n            {selectedView === 'agents' && <div><Agents sendAgentData={addTab} agents={agents}/></div>}\n            {selectedView === 'toolkits' && <div><Toolkits env={env} sendToolkitData={addTab} toolkits={toolkits}/></div>}\n            {selectedView === 'knowledge' && <div><Knowledge sendKnowledgeData={addTab} knowledge={knowledge}/></div>}\n            {selectedView === 'models' && <div><Models sendModelData={addTab} models={models} /></div>}\n          </div>}\n\n        {tabs.length <= 0 ? <div className={styles.main_workspace} style={selectedView === '' ? {\n          width: '93.5vw',\n          paddingLeft: '10px'\n        } : {width: '80.5vw'}}>\n          <div className={styles.empty_state}>\n            <div>\n              <div><Image width={264} height={144} src=\"/images/watermark.png\" alt=\"empty-state\"/></div>\n              <div style={{width: '100%', display: 'flex', justifyContent: 'center', marginTop: '30px'}}>\n                <button onClick={() => {addTab({\n                  id: -1,\n                  name: \"new agent\",\n                  contentType: \"Create_Agent\",\n                  internalId: createInternalId()\n                }); getUserClick('Agent Create Clicked', {'Click Position': 'Content'})}} className={styles.empty_state_button}>\n                  Create new agent&nbsp;<Image width={17} height={17} src=\"/images/arrow_forward_secondary.svg\"\n                                               alt=\"forward-arrow\"/>\n                </button>\n              </div>\n              {agents && agents.length > 0 &&\n                <div style={{width: '100%', display: 'flex', justifyContent: 'center', marginTop: '12px'}}>\n                  <button onClick={getLastActive} className={styles.empty_state_button}>\n                    View last active agent&nbsp;<Image width={17} height={17} src=\"/images/arrow_forward_secondary.svg\"\n                                                       alt=\"forward-arrow\"/>\n                  </button>\n                </div>}\n              {env !== 'PROD' &&\n                <div style={{width: '100%', display: 'flex', justifyContent: 'center', marginTop: '12px'}}>\n                  <button onClick={() => addTab({\n                    id: -2,\n                    name: \"new tool\",\n                    contentType: \"Add_Toolkit\",\n                    internalId: createInternalId()\n                  })} className={styles.empty_state_button}>\n                    Add custom tool&nbsp;<Image width={17} height={17} src=\"/images/arrow_forward_secondary.svg\"\n                                                alt=\"forward-arrow\"/>\n                  </button>\n                </div>}\n              <div style={{width: '100%', display: 'flex', justifyContent: 'center', marginTop: '12px'}}>\n                <button onClick={() => addTab({id: -3, name: \"Settings\", contentType: \"Settings\"})}\n                        className={styles.empty_state_button}>\n                  Go to settings&nbsp;<Image width={17} height={17} src=\"/images/arrow_forward_secondary.svg\"\n                                             alt=\"forward-arrow\"/>\n                </button>\n              </div>\n            </div>\n          </div>\n        </div> : <div className={styles.main_workspace}\n                      style={(selectedView === 'agents' || selectedView === 'toolkits' || selectedView === 'knowledge' || selectedView === 'models') ? {width: '80.5vw'} : {width: '100%'}}>\n          <div style={{display: 'flex', alignItems: 'center', justifyContent: 'center', width: '100%'}}>\n            <div className={styles.tabs} ref={tabContainerRef}>\n              {tabs.map((tab, index) => (\n                <div data-tab-id={index} key={index}\n                     className={`${styles.tab_box} ${selectedTab === index ? styles.tab_box_selected : ''}`}\n                     onClick={() => {\n                       selectTab(tab, index)\n                     }}>\n                  <div style={{display: 'flex', order: '0', overflowX: 'hidden'}}>\n                    {(tab.contentType === 'Agents' || tab.contentType === 'Create_Agent' || tab.contentType === 'Edit_Agent') &&\n                      <div className={styles.tab_active}><Image width={13} height={13} src=\"/images/agents_light.svg\"\n                                                                alt=\"agent-icon\"/></div>}\n                    {(tab.contentType === 'Toolkits' || tab.contentType === 'Add_Toolkit') &&\n                      <div className={styles.tab_active}><Image width={13} height={13} src=\"/images/tools_light.svg\"\n                                                                alt=\"tools-icon\"/></div>}\n                    {(tab.contentType === 'Knowledge' || tab.contentType === 'Add_Knowledge') &&\n                      <div className={styles.tab_active}><Image width={13} height={13} src=\"/images/knowledge.svg\"\n                                                                alt=\"knowledge-icon\"/></div>}\n                    {(tab.contentType === 'Database' || tab.contentType === 'Add_Database') &&\n                      <div className={styles.tab_active}><Image width={13} height={13} src=\"/images/database.svg\"\n                                                                alt=\"database-icon\"/></div>}\n                    {tab.contentType === 'Settings' &&\n                      <div className={styles.tab_active}><Image width={13} height={13} src=\"/images/settings.svg\"\n                                                                alt=\"settings-icon\"/></div>}\n                    {tab.contentType === 'Marketplace' &&\n                      <div className={styles.tab_active}><Image width={13} height={13} src=\"/images/marketplace.svg\"\n                                                                alt=\"marketplace-icon\"/></div>}\n                    {tab.contentType === 'APM' &&\n                      <div className={styles.tab_active}><Image width={13} height={13} src=\"/images/apm.svg\"\n                                                                alt=\"apm-icon\"/></div>}\n                    <div style={{marginLeft: '8px'}}><span className={styles.tab_text}>{tab.name}</span></div>\n                  </div>\n                  <div onClick={(e) => {\n                    e.stopPropagation();\n                    cancelTab(index, tab.contentType, tab.internalId || 0)\n                  }} className={styles.tab_active} style={{order: '1'}}><Image width={13} height={13}\n                                                                               src=\"/images/close.svg\"\n                                                                               alt=\"close-icon\"/></div>\n                </div>\n              ))}\n            </div>\n          </div>\n          <div className={styles.tab_detail}\n               style={tabs.length > 0 ? {backgroundColor: '#2F2C40', overflowX: 'hidden'} : {}}>\n            <div style={{padding: '0 5px 5px 5px'}}>\n              {tabs.map((tab, index) => (\n                <div key={index}>\n                  {selectedTab === index && <div>\n                    {tab.contentType === 'Agents' &&\n                      <AgentWorkspace env={env} internalId={tab.internalId || index} agentId={tab.id} agentName={tab.name}\n                                      selectedView={selectedView}\n                                      agents={agents} fetchAgents={getAgentList} sendAgentData={addTab} />}\n                    {tab.contentType === 'Toolkits' &&\n                      <ToolkitWorkspace env={env} internalId={tab.internalId || index}\n                                        toolkitDetails={toolkitDetails}/>}\n                    {tab.contentType === 'Knowledge' &&\n                      <KnowledgeDetails internalId={tab.internalId || index} knowledgeId={tab.id}/>}\n                    {tab.contentType === 'Database' &&\n                      <DatabaseDetails internalId={tab.internalId || index} databaseId={tab.id}/>}\n                    {tab.contentType === 'Knowledge' &&\n                      <KnowledgeDetails internalId={tab.internalId || index} knowledgeId={tab.id}/>}\n                    {tab.contentType === 'Database' &&\n                      <DatabaseDetails internalId={tab.internalId || index} databaseId={tab.id}/>}\n                    {tab.contentType === 'Settings' &&\n                      <Settings organisationId={organisationId} sendDatabaseData={addTab}/>}\n                    {tab.contentType === 'Marketplace' && <Market env={env} selectedView={selectedView} getModels={getModels} sendModelData={addTab} />}\n                    {tab.contentType === 'Add_Toolkit' && <AddTool internalId={tab.internalId || index}/>}\n                    {tab.contentType === 'Add_Knowledge' &&\n                      <AddKnowledge internalId={tab.internalId || index} sendKnowledgeData={addTab}/>}\n                    {tab.contentType === 'Add_Database' &&\n                      <AddDatabase internalId={tab.internalId || index} sendDatabaseDetailsData={addTab}/>}\n                    {tab.contentType === 'Create_Agent' &&\n                      <AgentTemplatesList knowledge={knowledge} internalId={tab.internalId || index}\n                                          organisationId={organisationId} sendKnowledgeData={addTab}\n                                          sendAgentData={addTab} selectedProjectId={selectedProjectId}\n                                          fetchAgents={getAgentList} toolkits={toolkits} env={env} />}\n                    {tab.contentType === 'APM' && <ApmDashboard />}\n                    {tab.contentType === 'Edit_Agent' &&\n                        <AgentCreate knowledge={knowledge} internalId={tab.internalId || index}\n                                     organisationId={organisationId} sendKnowledgeData={addTab}\n                                     sendAgentData={addTab} selectedProjectId={selectedProjectId} editAgentId={tab.id}\n                                     fetchAgents={getAgentList} toolkits={toolkits} template={null} edit={true} agents={agents}/>}\n                    {tab.contentType === 'Add_Model' && <AddModel internalId={tab.internalId} getModels={getModels} sendModelData={addTab} env={env}/>}\n                    {tab.contentType === 'Model' && <ModelDetails modelId={tab.id} modelName={tab.name} />}\n                  </div>}\n                </div>\n              ))}\n            </div>\n          </div>\n        </div>}\n\n        {starModal && (<div className=\"modal\" onClick={closeStarModal}>\n          <div className=\"modal-content\" style={{width: '35%'}} onClick={preventDefault}>\n            <div className={styles1.detail_name} style={{width: '100%', textAlign: 'center'}}>Support the project by\n              leaving a star on GitHub repository\n            </div>\n            <div style={{display: 'flex', alignItems: 'center', justifyContent: 'center'}}>\n              <button className=\"secondary_button\" style={{marginTop: '10px', width: 'fit-content'}}\n                      onClick={openGithubRepo}>\n                Leave a ⭐ star on GitHub\n              </button>\n            </div>\n            <div style={{display: 'flex', alignItems: 'center', justifyContent: 'center'}}>\n              <div className=\"cancel_action\" onClick={closeStarModal}>\n                I’ll do it later\n              </div>\n            </div>\n          </div>\n        </div>)}\n      </div>\n    </>\n  );\n}"
  },
  {
    "path": "gui/pages/Dashboard/Dashboard.module.css",
    "content": ".logo {\n    cursor: default;\n}\n\n.empty_state {\n    background-color: #2F2C40;\n    width: 100%;\n    height: 100%;\n    border-radius: 8px;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n}\n\n.section {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    border-radius: 8px;\n    font-weight: 400;\n    cursor: pointer;\n    width: 100%;\n    font-size: 9px;\n    padding: 10px 0;\n    text-align: center;\n}\n\n.button_icon {\n    margin-bottom: 4px;\n}\n\n.selected {\n    background-color: #333141;\n}\n\n.section:hover {\n    background-color: #333141;\n}\n\n.sideBar_image {\n    margin-left: 10px;\n    margin-top: -1px;\n}\n\n.item_list {\n    height: 100%;\n    position: relative;\n}\n\n.main_workspace {\n    height: 100%;\n    padding: 0 10px 10px 10px;\n    display: flex;\n    flex-wrap: wrap;\n}\n\n.tab_detail {\n    height: calc(100% - 36px);\n    width: 100%;\n    border-radius: 8px;\n    overflow-y: hidden;\n    position: relative;\n}\n\n.tabs {\n    width: 98.5%;\n    display: flex;\n    overflow-x: scroll;\n    height: 36px;\n}\n\n.tab_box {\n    display: flex;\n    flex-direction: row;\n    align-items: center;\n    padding: 6px 8px 10px 8px;\n    gap: 6px;\n    cursor: pointer;\n    width: 175px;\n    min-width: 175px;\n    height: 100%;\n    border-top-left-radius: 8px;\n    border-top-right-radius: 8px;\n    justify-content: space-between;\n}\n\n.tab_box_selected {\n    background-color: #2F2C40;\n}\n\n.tab_active {\n    display: flex;\n    flex-direction: row;\n    align-items: center;\n    padding: 0;\n    margin-top: 1px;\n}\n\n.tab_text {\n    font-style: normal;\n    font-weight: 400;\n    font-size: 13px;\n    line-height: 15px;\n    align-items: center;\n    color: white;\n    flex: none;\n    order: 1;\n    flex-grow: 0;\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 1;\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.empty_state_button {\n    border: none;\n    border-radius: 8px;\n    background: transparent;\n    color: white;\n    padding: 5px 20px;\n}\n\n.empty_state_button:hover {\n    background: #494856;\n}"
  },
  {
    "path": "gui/pages/Dashboard/Settings/AddDatabase.js",
    "content": "import React, {useState, useEffect} from 'react';\nimport {ToastContainer, toast} from 'react-toastify';\nimport 'react-toastify/dist/ReactToastify.css';\nimport agentStyles from \"@/pages/Content/Agents/Agents.module.css\";\nimport {\n  createInternalId,\n  removeTab,\n  returnDatabaseIcon,\n  setLocalStorageArray,\n  setLocalStorageValue\n} from \"@/utils/utils\";\nimport knowledgeStyles from \"@/pages/Content/Knowledge/Knowledge.module.css\";\nimport styles from \"@/pages/Content/Marketplace/Market.module.css\";\nimport Image from \"next/image\";\nimport styles1 from \"@/pages/Content/Agents/Agents.module.css\";\nimport {connectPinecone, connectQdrant, connectWeaviate, fetchVectorDBList} from \"@/pages/api/DashboardService\";\n\nexport default function AddDatabase({internalId, sendDatabaseDetailsData}) {\n  const [activeView, setActiveView] = useState('select_database');\n  const [vectorDatabases, setVectorDatabases] = useState(null);\n  const [selectedDB, setSelectedDB] = useState('');\n  const [databaseName, setDatabaseName] = useState('database name');\n  const [collections, setCollections] = useState(['']);\n\n  const [pineconeApiKey, setPineconeApiKey] = useState('');\n  const [pineconeEnvironment, setPineconeEnvironment] = useState('');\n\n  const [qdrantApiKey, setQdrantApiKey] = useState('');\n  const [qdrantURL, setQdrantURL] = useState('');\n\n  const [weaviateApiKey, setWeaviateApiKey] = useState('');\n  const [weaviateURL, setWeaviateURL] = useState('');\n\n  const [qdrantPort, setQdrantPort] = useState(8001);\n  const [connectText, setConnectText] = useState('Connect');\n\n  useEffect(() => {\n    const active_view = localStorage.getItem('add_database_tab_' + String(internalId));\n    if (active_view) {\n      setActiveView(active_view);\n    }\n\n    const db_name = localStorage.getItem('db_name_' + String(internalId));\n    if (db_name) {\n      setDatabaseName(db_name);\n    }\n\n    const db_collections = localStorage.getItem('db_collections_' + String(internalId));\n    if (db_collections) {\n      setCollections(JSON.parse(db_collections));\n    }\n\n    const pinecone_api = localStorage.getItem('pincone_api_' + String(internalId));\n    if (pinecone_api) {\n      setPineconeApiKey(pinecone_api);\n    }\n\n    const pinecone_env = localStorage.getItem('pinecone_env_' + String(internalId));\n    if (pinecone_env) {\n      setPineconeEnvironment(pinecone_env);\n    }\n\n    const qdrant_api = localStorage.getItem('qdrant_api_' + String(internalId));\n    if (qdrant_api) {\n      setQdrantApiKey(qdrant_api);\n    }\n\n    const qdrant_url = localStorage.getItem('qdrant_url_' + String(internalId));\n    if (qdrant_url) {\n      setQdrantURL(qdrant_url);\n    }\n\n    const qdrant_port = localStorage.getItem('qdrant_port_' + String(internalId));\n    if (qdrant_port) {\n      setQdrantPort(Number(qdrant_port));\n    }\n\n    const weaviate_api = localStorage.getItem('weaviate_api_' + String(internalId));\n    if (weaviate_api) {\n      setWeaviateApiKey(weaviate_api);\n    }\n\n    const weaviate_url = localStorage.getItem('weaviate_url_' + String(internalId));\n    if (weaviate_url) {\n      setWeaviateURL(weaviate_url);\n    }\n\n  }, [internalId]);\n\n  useEffect(() => {\n    fetchVectorDBList()\n      .then((response) => {\n        const data = response.data || [];\n        setVectorDatabases(data);\n        const selected_db = localStorage.getItem('selected_db_' + String(internalId));\n        setSelectedDB(selected_db ? selected_db : data[0].name || '');\n      })\n      .catch((error) => {\n        console.error('Error fetching vector databases:', error);\n      });\n  }, [internalId]);\n\n  const handleNameChange = (event) => {\n    setLocalStorageValue('db_name_' + String(internalId), event.target.value, setDatabaseName);\n  }\n\n  const handlePineconeAPIKeyChange = (event) => {\n    setLocalStorageValue('pincone_api_' + String(internalId), event.target.value, setPineconeApiKey);\n  }\n\n  const handlePineconeEnvironmentChange = (event) => {\n    setLocalStorageValue('pinecone_env_' + String(internalId), event.target.value, setPineconeEnvironment);\n  }\n\n  const handleQdrantAPIKeyChange = (event) => {\n    setLocalStorageValue('qdrant_api_' + String(internalId), event.target.value, setQdrantApiKey);\n  }\n\n  const handleQdrantURLChange = (event) => {\n    setLocalStorageValue('qdrant_url_' + String(internalId), event.target.value, setQdrantURL);\n  }\n\n  const handleQdrantPortChange = (event) => {\n    setLocalStorageValue('qdrant_port_' + String(internalId), event.target.value, setQdrantPort);\n  }\n\n  const handleWeaviateAPIKeyChange = (event) => {\n    setLocalStorageValue('weaviate_api_' + String(internalId), event.target.value, setWeaviateApiKey);\n  }\n\n  const handleWeaviateURLChange = (event) => {\n    setLocalStorageValue('weaviate_url_' + String(internalId), event.target.value, setWeaviateURL);\n  }\n\n  const addCollection = () => {\n    setLocalStorageArray(\"db_collections_\" + String(internalId), [...collections, 'collection name'], setCollections);\n  };\n\n  const handleCollectionChange = (index, newValue) => {\n    const updatedCollections = [...collections];\n    updatedCollections[index] = newValue;\n    setLocalStorageArray(\"db_collections_\" + String(internalId), updatedCollections, setCollections);\n  };\n\n  const handleCollectionDelete = (index) => {\n    const updatedCollections = [...collections];\n    updatedCollections.splice(index, 1);\n    setLocalStorageArray(\"db_collections_\" + String(internalId), updatedCollections, setCollections);\n  };\n\n  const connectResponse = (data) => {\n    if (!data) {\n      return;\n    }\n      toast.success(\"Database connected successfully\", {autoClose: 1800});\n      setConnectText(\"Connected\");\n      sendDatabaseDetailsData({id: data.id, name: data.name, contentType: \"Database\", internalId: createInternalId()});\n  }\n\n  const connectDatabase = () => {\n    if (databaseName.replace(/\\s/g, '') === '') {\n      toast.error(\"Database name can't be blank\", {autoClose: 1800});\n      return;\n    }\n\n    if(collections.length === 1 && collections[0].length < 1){\n      toast.error(\"Atleast add 1 Collection/Index\", {autoClose: 1800});\n      return;\n    }\n\n    if (selectedDB === 'Pinecone') {\n      if (pineconeApiKey.replace(/\\s/g, '') === '') {\n        toast.error(\"Pinecone API key is empty\", {autoClose: 1800});\n        return;\n      }\n\n      if (pineconeEnvironment.replace(/\\s/g, '') === '') {\n        toast.error(\"Pinecone environment is empty\", {autoClose: 1800});\n        return;\n      }\n\n      setConnectText(\"Connecting...\");\n\n      const pineconeData = {\n        \"name\": databaseName,\n        \"collections\": collections,\n        \"api_key\": pineconeApiKey,\n        \"environment\": pineconeEnvironment,\n      }\n\n      connectPinecone(pineconeData)\n        .then((response) => {\n          connectResponse(response.data);\n        })\n        .catch((error) => {\n          toast.error(\"Unable to connect database\", {autoClose: 1800});\n          console.error('Error fetching vector databases:', error);\n          setConnectText(\"Connect\");\n        });\n    }\n\n    if (selectedDB === 'Qdrant') {\n      if (qdrantApiKey.replace(/\\s/g, '') === '') {\n        toast.error(\"Qdrant API key is empty\", {autoClose: 1800});\n        return;\n      }\n\n      if (qdrantURL.replace(/\\s/g, '') === '') {\n        toast.error(\"Qdrant URL is empty\", {autoClose: 1800});\n        return;\n      }\n\n      if (String(qdrantPort).replace(/\\s/g, '') === '') {\n        toast.error(\"Qdrant port can't be blank\", {autoClose: 1800});\n        return;\n      }\n\n      setConnectText(\"Connecting...\");\n\n      const qdrantData = {\n        \"name\": databaseName,\n        \"collections\": collections,\n        \"api_key\": qdrantApiKey,\n        \"url\": qdrantURL,\n        \"port\": qdrantPort\n      }\n\n      connectQdrant(qdrantData)\n        .then((response) => {\n          connectResponse(response.data);\n        })\n        .catch((error) => {\n          toast.error(\"Unable to connect database\", {autoClose: 1800});\n          console.error('Error fetching vector databases:', error);\n          setConnectText(\"Connect\");\n        });\n    }\n\n    if (selectedDB === 'Weaviate') {\n      if (weaviateApiKey.replace(/\\s/g, '') === '') {\n        toast.error(\"Weaviate API key is empty\", {autoClose: 1800});\n        return;\n      }\n\n      if (weaviateURL.replace(/\\s/g, '') === '') {\n        toast.error(\"Weaviate URL is empty\", {autoClose: 1800});\n        return;\n      }\n\n      setConnectText(\"Connecting...\");\n\n      const weaviateData = {\n        \"name\": databaseName,\n        \"collections\": collections,\n        \"api_key\": weaviateApiKey,\n        \"url\": weaviateURL,\n      }\n\n      connectWeaviate(weaviateData)\n        .then((response) => {\n          connectResponse(response.data);\n        })\n        .catch((error) => {\n          toast.error(\"Unable to connect database\", {autoClose: 1800});\n          console.error('Error fetching vector databases:', error);\n          setConnectText(\"Connect\");\n        });\n    }\n  }\n\n  const proceedAddDatabase = () => {\n    if (selectedDB === null) {\n      toast.error(\"Please select a database\", {autoClose: 1800});\n      return;\n    }\n\n    setLocalStorageValue('add_database_tab_' + String(internalId), 'form_database', setActiveView)\n  }\n\n  return (<>\n    <div className=\"row\">\n      <div className=\"col-3\"></div>\n      {activeView === 'select_database' &&\n        <div className=\"col-6\" style={{overflowY: 'scroll', height: 'calc(100vh - 92px)', padding: '25px 20px'}}>\n          <div className=\"title_wrapper\">\n            <div className={agentStyles.page_title}>Choose a vector database</div>\n          </div>\n          <div className={knowledgeStyles.database_wrapper}>\n            {vectorDatabases?.map((item, index) => (\n              <div key={index}\n                   style={item.name === selectedDB ? {border: '1px solid #9B9AA1'} : {border: '1px solid rgb(39, 35, 53)'}}\n                   className={knowledgeStyles.database_container}\n                   onClick={() => setLocalStorageValue('selected_db_' + String(internalId), item.name, setSelectedDB)}>\n                <div style={{display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '20px'}}>\n                  <Image width={40} height={40} src={returnDatabaseIcon(item.name)} alt=\"\"/>\n                </div>\n                <div className={styles.text_block}\n                     style={{width: '100%', marginBottom: '10px', textAlign: 'center'}}>{item.name}</div>\n              </div>))}\n          </div>\n          <div style={{display: 'flex', justifyContent: 'flex-end', marginTop: '15px'}}>\n            <button onClick={() => removeTab(-7, \"new database\", \"Add_Database\", internalId)}\n                    className=\"secondary_button\" style={{marginRight: '10px'}}>\n              Cancel\n            </button>\n            <button className=\"primary_button\" onClick={proceedAddDatabase}>\n              Proceed\n            </button>\n          </div>\n        </div>}\n      {activeView === 'form_database' &&\n        <div className=\"col-6\" style={{overflowY: 'scroll', height: 'calc(100vh - 92px)', padding: '25px 20px'}}>\n          <div className={styles.back_button} style={{margin: '8px 0', padding: '2px'}}\n               onClick={() => setLocalStorageValue('add_database_tab_' + String(internalId), 'select_database', setActiveView)}>\n            <Image src=\"/images/arrow_back.svg\" alt=\"back_button\" width={14} height={12}/>\n            <span className={styles.back_button_text}>Back</span>\n          </div>\n          <div className=\"title_wrapper\">\n            <div className={agentStyles.page_title}>Connect new vector database</div>\n          </div>\n          <div className=\"database_box\">\n            <div style={{display: 'flex', justifyContent: 'flex-start', alignItems: 'center'}}>\n              <div style={{marginLeft: '15px'}}>\n                <Image src={returnDatabaseIcon(selectedDB)} alt=\"database-icon\" width={40} height={40}/>\n              </div>\n              <div style={{marginLeft: '15px', fontSize: '14px', marginTop: '23px'}} className={agentStyles.page_title}>\n                <p>{selectedDB}</p></div>\n            </div>\n          </div>\n          <div style={{marginTop: '15px'}}>\n            <label className={styles1.form_label}>Name</label>\n            <input className=\"input_medium\" type=\"text\" value={databaseName} onChange={handleNameChange}/>\n          </div>\n          <div style={{marginTop: '15px'}}>\n            <div>{selectedDB === 'Weaviate' ? <label className={styles.form_label}>Class/Collection/Index</label> : <label className={styles.form_label}>Collection/Index</label>}</div>\n            {collections.map((collection, index) => (<div key={index} style={{\n              marginBottom: '10px',\n              display: 'flex',\n              alignItems: 'center',\n              justifyContent: 'space-between'\n            }}>\n              <div style={{flex: '1'}}>\n                <input className=\"input_medium\" type=\"text\" value={collection}\n                       onChange={(event) => handleCollectionChange(index, event.target.value)}/>\n              </div>\n              {collections.length > 1 && <div>\n                <button className=\"secondary_button\" style={{marginLeft: '4px', padding: '5px'}}\n                        onClick={() => handleCollectionDelete(index)}>\n                  <Image width={20} height={21} src=\"/images/close.svg\" alt=\"close-icon\"/>\n                </button>\n              </div>}\n            </div>))}\n            <div>\n              <button className=\"secondary_button\" onClick={addCollection}>+ Add</button>\n            </div>\n          </div>\n          {selectedDB === 'Pinecone' && <div>\n            <div style={{marginTop: '15px'}}>\n              <label className={styles1.form_label}>Pinecone API key</label>\n              <input className=\"input_medium\" type=\"password\" value={pineconeApiKey}\n                     onChange={handlePineconeAPIKeyChange}/>\n            </div>\n            <div style={{marginTop: '15px'}}>\n              <label className={styles1.form_label}>Pinecone environment</label>\n              <input className=\"input_medium\" type=\"text\" value={pineconeEnvironment}\n                     onChange={handlePineconeEnvironmentChange}/>\n            </div>\n          </div>}\n          {selectedDB === 'Qdrant' && <div>\n            <div style={{marginTop: '15px'}}>\n              <label className={styles1.form_label}>Qdrant API key</label>\n              <input className=\"input_medium\" type=\"password\" value={qdrantApiKey} onChange={handleQdrantAPIKeyChange}/>\n            </div>\n            <div style={{marginTop: '15px'}}>\n              <label className={styles1.form_label}>Qdrant URL</label>\n              <input className=\"input_medium\" type=\"text\" value={qdrantURL} onChange={handleQdrantURLChange}/>\n            </div>\n            <div style={{marginTop: '15px'}}>\n              <label className={styles1.form_label}>Port</label>\n              <input className=\"input_medium\" type=\"number\" value={qdrantPort} onChange={handleQdrantPortChange}/>\n            </div>\n          </div>}\n          {selectedDB === 'Weaviate' && <div>\n            <div className=\"mt_15\">\n              <label className={styles1.form_label}>Weaviate API key</label>\n              <input className=\"input_medium\" type=\"password\" value={weaviateApiKey} onChange={handleWeaviateAPIKeyChange}/>\n            </div>\n            <div className=\"mt_15\">\n              <label className={styles1.form_label}>Weaviate URL</label>\n              <input className=\"input_medium\" type=\"text\" value={weaviateURL} onChange={handleWeaviateURLChange}/>\n            </div>\n          </div>}\n          <div style={{display: 'flex', justifyContent: 'flex-end', marginTop: '15px'}}>\n            <button onClick={() => removeTab(-7, \"new database\", \"Add_Database\", internalId)}\n                    className=\"secondary_button\" style={{marginRight: '10px'}}>\n              Cancel\n            </button>\n            <button className=\"primary_button\" onClick={connectDatabase}>\n              {connectText}\n            </button>\n          </div>\n        </div>}\n      <div className=\"col-3\"></div>\n    </div>\n    <ToastContainer/>\n  </>)\n}"
  },
  {
    "path": "gui/pages/Dashboard/Settings/ApiKeys.js",
    "content": "import React, {useState, useEffect, useRef} from 'react';\nimport {ToastContainer, toast} from 'react-toastify';\nimport 'react-toastify/dist/ReactToastify.css';\nimport agentStyles from \"@/pages/Content/Agents/Agents.module.css\";\nimport {\n  createApiKey, deleteApiKey,\n  editApiKey, getApiKeys,\n} from \"@/pages/api/DashboardService\";\nimport {EventBus} from \"@/utils/eventBus\";\nimport {createInternalId, loadingTextEffect, preventDefault, removeTab, returnToolkitIcon} from \"@/utils/utils\";\nimport Image from \"next/image\";\nimport styles from \"@/pages/Content/Marketplace/Market.module.css\";\nimport styles1 from \"@/pages/Content/Knowledge/Knowledge.module.css\";\n\nexport default function ApiKeys() {\n  const [apiKeys, setApiKeys] = useState([]);\n  const [keyName, setKeyName] = useState('');\n  const [editKey, setEditKey] = useState('');\n  const apiKeyRef = useRef(null);\n  const editKeyRef = useRef(null);\n  const [editKeyId, setEditKeyId] = useState(-1);\n  const [deleteKey, setDeleteKey] = useState('')\n  const [isLoading, setIsLoading] = useState(true)\n  const [activeDropdown, setActiveDropdown] = useState(null);\n  const [editModal, setEditModal] = useState(false);\n  const [deleteKeyId, setDeleteKeyId] = useState(-1);\n  const [deleteModal, setDeleteModal] = useState(false);\n  const [createModal, setCreateModal] = useState(false);\n  const [displayModal, setDisplayModal] = useState(false);\n  const [apiKeyGenerated, setApiKeyGenerated] = useState('');\n  const [loadingText, setLoadingText] = useState(\"Loading Api Keys\");\n\n\n\n  useEffect(() => {\n    loadingTextEffect('Loading Api Keys', setLoadingText, 500);\n    fetchApiKeys()\n  }, []);\n\n\n  const handleModelApiKey = (event) => {\n    setKeyName(event.target.value);\n  };\n\n  const handleEditApiKey = (event) => {\n    setEditKey(event.target.value);\n  };\n\n  const createApikey = () => {\n    if(!keyName){\n      toast.error(\"Enter key name\", {autoClose: 1800});\n      return;\n    }\n    createApiKey({name : keyName})\n      .then((response) => {\n        setApiKeyGenerated(response.data.api_key)\n        toast.success(\"Api Key Generated\", {autoClose: 1800});\n        setCreateModal(false);\n        setDisplayModal(true);\n        fetchApiKeys();\n      })\n      .catch((error) => {\n        console.error('Error creating api key', error);\n      });\n  }\n  const handleCopyClick = async () => {\n    if (apiKeyRef.current) {\n      try {\n        await navigator.clipboard.writeText(apiKeyRef.current.value);\n        toast.success(\"Key Copied\", {autoClose: 1800});\n      } catch (err) {\n        toast.error('Failed to Copy', {autoClose: 1800});\n      }\n    }\n  };\n\n  const fetchApiKeys = () => {\n    getApiKeys()\n      .then((response) => {\n        const formattedData = response.data.map(item => {\n          return {\n            ...item,\n            created_at: `${new Date(item.created_at).getDate()}-${[\"JAN\", \"FEB\", \"MAR\", \"APR\", \"MAY\", \"JUN\", \"JUL\", \"AUG\", \"SEP\", \"OCT\", \"NOV\", \"DEC\"][new Date(item.created_at).getMonth()]}-${new Date(item.created_at).getFullYear()}`\n          };\n        });\n        setApiKeys(formattedData)\n        setIsLoading(false)\n      })\n      .catch((error) => {\n        console.error('Error fetching Api Keys', error);\n      });\n  }\n\n  const handleEditClick = () => {\n    if(editKeyRef.current.value.length <1){\n      toast.error(\"Enter valid key name\", {autoClose: 1800});\n      return;\n    }\n    editApiKey({id: editKeyId,name : editKey})\n      .then((response) => {\n        toast.success(\"Api Key Edited\", {autoClose: 1800});\n        fetchApiKeys();\n        setEditModal(false);\n        setEditKey('')\n        setEditKeyId(-1)\n      })\n      .catch((error) => {\n        console.error('Error editing api key', error);\n      });\n  }\n\n  const handleDeleteClick = () => {\n    deleteApiKey(deleteKeyId)\n      .then((response) => {\n        toast.success(\"Api Key Deleted\", {autoClose: 1800});\n        fetchApiKeys();\n        setDeleteModal(false);\n        setDeleteKeyId(-1)\n        setDeleteKey('')\n      })\n      .catch((error) => {\n        toast.error(\"Error deleting api key\", {autoClose: 1800});\n        console.error('Error deleting api key', error);\n      });\n  }\n\n  return (<>\n    <div className=\"row\">\n      <div className=\"col-2\"></div>\n      <div className=\"col-8 col-6-scrollable\">\n        {!isLoading ? <div>\n          <div className=\"title_wrapper mb_15\">\n          <div className={styles.page_title}>API Keys</div>\n            {apiKeys && apiKeys.length > 0 && !isLoading &&\n              <button className={`${'primary_button mr_20'} ${agentStyles.button_margin}`} onClick={() => {setCreateModal(true); setKeyName('')}}>\n                Create Key\n              </button>}\n          </div>\n          <div>\n          <label className={agentStyles.form_label}>Your secret API keys are important and should be kept safe. Do not share them with anyone or expose them in any case.</label>\n          <label className={agentStyles.form_label}>To help keep your API keys safe, you can store them in a secure location, rotate them regularly, and use different API keys for different applications. By following these tips, you can help protect your account and your data.</label>\n\n            {apiKeys.length < 1 && <div className={agentStyles.table_contents}>\n            <Image width={150} height={60} src=\"/images/no_permissions.svg\" alt=\"no-permissions\"/>\n            <span className={`${styles.feed_title} ${'mt_8'}`}>No API Keys created!</span>\n            <div className={agentStyles.create_settings_button}>\n              <button className=\"primary_button\" onClick={() => {setCreateModal(true); setKeyName('')}}>Create Key\n              </button>\n            </div>\n          </div>}\n\n            {apiKeys.length > 0 && <div className=\"scrollable_container table_container\">\n              <table className=\"table_css margin_0 padding_0\">\n                <thead>\n                <tr className=\"border_top_none\">\n                  <th className=\"table_header w_60\">Name</th>\n                  <th className=\"table_header w_18\">Key</th>\n                  <th className=\"table_header w_18\">Created Date</th>\n                  <th className=\"table_header w_4\"></th>\n                </tr>\n                </thead>\n              </table>\n              <div className=\"overflow_auto w_100\">\n                <table className=\"table_css margin_0\">\n                  <tbody>\n                  {apiKeys.map((item, index) => (\n                    <tr key={index}>\n                      <td className=\"table_data w_60\">{item.name}</td>\n                      <td className=\"table_data w_18\">{item.key.slice(0, 2) + \"****\" + item.key.slice(-4)}</td>\n                      <td className=\"table_data w_18\">{item.created_at}</td>\n                      <td className=\"table_data w_4 cursor_pointer\" onMouseLeave={() => setActiveDropdown(null)} onClick={() => {\n                        if (activeDropdown === index) {\n                          setActiveDropdown(null);\n                        } else {\n                          setActiveDropdown(index);\n                        }\n                      }}>\n                        <Image className=\"rotate_90\" width={16} height={16} src=\"/images/three_dots.svg\" alt=\"run-icon\"/>\n                       <div style={activeDropdown === index ? {display: 'block'} : {display: 'none'}} onMouseLeave={() => setActiveDropdown(null)}>\n                          <ul className=\"dropdown_container\">\n                            <li className=\"dropdown_item\" onClick={() => {setEditKey(item.name); setEditKeyId(item.id); setEditModal(true); setActiveDropdown(null);}}>Edit</li>\n                            <li className=\"dropdown_item\" onClick={() => {setDeleteKeyId(item.id); setDeleteKey(item.name) ; setDeleteModal(true); setActiveDropdown(null);}}>Delete</li>\n                          </ul> </div></td>\n                    </tr>\n                  ))}\n                  </tbody>\n                </table>\n              </div>\n            </div>}\n        </div>\n      </div> :  <div className=\"loading_container\">\n          <div className=\"signInInfo loading_text\">{loadingText}</div>\n        </div>}\n      </div>\n      <div className=\"col-2\"></div>\n    </div>\n\n    {createModal && (<div className=\"modal\" onClick={() => setCreateModal(false)}>\n      <div className=\"modal-content w_35\" onClick={preventDefault}>\n        <div className={styles.detail_name}>Create new API Key</div>\n        <div>\n          <label className={styles.form_label}>Name</label>\n          <input placeholder=\"Enter key name\" className=\"input_medium\" type=\"text\" value={keyName} onChange={handleModelApiKey}/>\n        </div>\n        <div className={agentStyles.modal_buttons}>\n          <button className=\"secondary_button mr_10\" onClick={() => setCreateModal(false)}>\n            Cancel\n          </button>\n          <button className=\"primary_button\" onClick={() => createApikey()}>\n            Create Key\n          </button>\n        </div>\n      </div>\n    </div>)}\n\n    {displayModal && apiKeyGenerated && (<div className=\"modal\" onClick={() => setDisplayModal(false)}>\n      <div className=\"modal-content w_35\" onClick={preventDefault}>\n        <div className={styles.detail_name}>{keyName} is created</div>\n        <div>\n          <div className=\"mt_15 mb_25\">\n            <div className={styles1.knowledge_alert}>\n              <div className={agentStyles.modal_info_class}>\n                <Image width={20} height={20} src='/images/info.svg' alt=\"info-icon\"/>\n              </div>\n              <div>\n                Your secret API keys are sensitive pieces of information that should be kept confidential. Do not share them with anyone, and do not expose them in any way. If your secret API keys are compromised, someone could use them to access your API and make unauthorized changes to your data. This secret key is only displayed once for security reasons. Please save it in a secure location where you can access it easily.\n              </div>\n            </div>\n          </div>\n          <div>\n           <div className=\"title_wrapper\">\n              <div className=\"flex_1\"><input ref={apiKeyRef} className=\"input_medium\" type=\"text\" value={apiKeyGenerated} disabled />\n              </div>\n             <div>\n                <button className=\"secondary_button ml_4 padding_5\" onClick={handleCopyClick}>\n                  <Image width={20} height={21} src=\"/images/copy_icon.svg\" alt=\"copy-icon\"/>\n                </button>\n              </div>\n            </div>\n          </div>\n        </div>\n        <div className={agentStyles.modal_buttons}>\n          <button className=\"primary_button\" onClick={() => setDisplayModal(false)}>\n            OK\n          </button>\n        </div>\n      </div>\n    </div>)}\n\n    {editModal && (<div className=\"modal\" onClick={() => {setEditModal(false); setEditKey(''); setEditKeyId(-1)}}>\n      <div className=\"modal-content w_35\" onClick={preventDefault}>\n        <div className={styles.detail_name}>Edit API Key</div>\n            <div>\n                <label className={styles.form_label}>Name</label>\n                <input ref={editKeyRef} placeholder={editKey} className=\"input_medium\" type=\"text\" onChange={handleEditApiKey}/>\n            </div>\n        <div className={agentStyles.modal_buttons}>\n          <button className=\"secondary_button mr_10\" onClick={() => {setEditModal(false); setEditKey(''); setEditKeyId(-1)}}>\n            Cancel\n          </button>\n          <button className=\"primary_button\" onClick={() => handleEditClick()}>\n            Update Changes\n          </button>\n        </div>\n      </div>\n    </div>)}\n\n    {deleteModal && (<div className=\"modal\" onClick={() => {setDeleteModal(false); setDeleteKeyId(-1); setDeleteKey('')}}>\n      <div className=\"modal-content w_35\" onClick={preventDefault}>\n        <div className={styles.detail_name}>Delete {deleteKey} Key</div>\n        <div>\n          <label className={styles.form_label}>Deleting this API key will make it unusable. Any API requests made using this key will be rejected. Are you sure you want to proceed?</label>\n        </div>\n        <div className={agentStyles.modal_buttons}>\n          <button className=\"secondary_button mr_10\" onClick={() => {setDeleteModal(false); setDeleteKeyId(-1); setDeleteKey('')}}>\n            Cancel\n          </button>\n          <button className=\"primary_button\" onClick={() => handleDeleteClick()}>\n            Delete Key\n          </button>\n        </div>\n      </div>\n    </div>)}\n    <ToastContainer/>\n  </>)\n}"
  },
  {
    "path": "gui/pages/Dashboard/Settings/Database.js",
    "content": "import React, {useState, useEffect} from 'react';\nimport {ToastContainer, toast} from 'react-toastify';\nimport 'react-toastify/dist/ReactToastify.css';\nimport agentStyles from \"@/pages/Content/Agents/Agents.module.css\";\nimport {createInternalId, formatTimeDifference, loadingTextEffect, preventDefault} from \"@/utils/utils\";\nimport styles from \"@/pages/Content/Marketplace/Market.module.css\";\nimport knowledgeStyles from \"@/pages/Content/Knowledge/Knowledge.module.css\";\nimport Image from \"next/image\";\nimport {deleteVectorDB, getVectorDatabases} from \"@/pages/api/DashboardService\";\n\nexport default function Database({sendDatabaseData}) {\n  const [vectorDB, setVectorDB] = useState([]);\n  const [isLoading, setIsLoading] = useState(true)\n  const [loadingText, setLoadingText] = useState(\"Loading Databases\");\n  const [dropdown, setDropdown] = useState([]);\n  const [deleteModal, setDeleteModal] = useState(false);\n  const [selectedDatabase, setSelectedDatabase] = useState(null);\n\n  function fetchDatabases() {\n    setIsLoading(true);\n\n    getVectorDatabases()\n      .then((response) => {\n        const data = response.data || [];\n        setVectorDB(data);\n        setIsLoading(false);\n      })\n      .catch((error) => {\n        console.error('Error fetching vector databases:', error);\n      });\n  }\n\n  useEffect(() => {\n    loadingTextEffect('Loading Databases', setLoadingText, 500);\n    fetchDatabases();\n  }, []);\n\n  useEffect(() => {\n    setDropdown(Array(vectorDB.length).fill(false));\n  }, [vectorDB]);\n\n  const setDropdownWithIndex = (index, state) => {\n    setDropdown((prevDropdown) => {\n      const newDropdown = [...prevDropdown];\n      newDropdown[index] = state;\n      return newDropdown;\n    });\n  }\n\n  const openDeleteModal = (e, index) => {\n    e.stopPropagation();\n    setDeleteModal(true);\n    setSelectedDatabase(vectorDB[index]);\n    setDropdownWithIndex(index, false);\n  }\n\n  const deleteDatabase = (databaseId) => {\n    setDeleteModal(false);\n\n    deleteVectorDB(databaseId)\n      .then((response) => {\n        toast.success(\"Database deleted successfully\", {autoClose: 1800});\n        fetchDatabases();\n      })\n      .catch((error) => {\n        toast.error(\"Unable to delete database\", {autoClose: 1800});\n        console.error('Error fetching knowledge templates:', error);\n      });\n  }\n\n  return (<>\n    <div className=\"row\">\n      <div className=\"col-2\"></div>\n      <div className=\"col-8\" style={{overflowY: 'scroll', height: 'calc(100vh - 92px)', padding: '25px 20px'}}>\n        <div className=\"title_wrapper\">\n          <div className={agentStyles.page_title}>Vector Database</div>\n          {vectorDB && vectorDB.length > 0 && !isLoading &&\n            <button className=\"primary_button\" onClick={() => sendDatabaseData({\n              id: -7,\n              name: \"new database\",\n              contentType: \"Add_Database\",\n              internalId: createInternalId()\n            })} style={{marginTop: '-10px', marginRight: '20px'}}>\n              Add\n            </button>}\n        </div>\n        <div>\n          <div className={styles.rowContainer} style={{maxHeight: '78vh', overflowY: 'auto'}}>\n            {!isLoading ? <div>\n              {vectorDB && vectorDB.length > 0 ? <div className={knowledgeStyles.database_wrapper}>\n                {vectorDB.map((item, index) => (<div key={index} className={knowledgeStyles.database_container}\n                                                     onClick={() => sendDatabaseData({\n                                                       id: item.id,\n                                                       name: item.name,\n                                                       contentType: \"Database\",\n                                                       internalId: createInternalId()\n                                                     })}>\n                  <div style={{display: 'flex', alignItems: 'center', justifyContent: 'space-between'}}>\n                    <div style={{display: 'flex', order: '0'}}>\n                      <div className={styles.text_block}>{item.name}</div>\n                    </div>\n                    <div style={{order: '1'}}>\n                      <button className=\"three_dots_vertical\" style={{padding: '8px', height: '31px'}}\n                              onMouseEnter={() => setDropdownWithIndex(index, true)}\n                              onMouseLeave={() => setDropdownWithIndex(index, false)}>\n                        <Image width={14} height={14} src=\"/images/three_dots_vertical.svg\" alt=\"run-icon\"/>\n                      </button>\n                      {dropdown[index] && <div onMouseEnter={() => setDropdownWithIndex(index, true)}\n                                               onMouseLeave={() => setDropdownWithIndex(index, false)}>\n                        <ul className=\"dropdown_container\" style={{marginLeft: '-15px'}}>\n                          <li className=\"dropdown_item\" onClick={(e) => openDeleteModal(e, index)}>Delete database</li>\n                        </ul>\n                      </div>}\n                    </div>\n                  </div>\n                  <div style={{display: 'flex', alignItems: 'center', justifyContent: 'flex-start'}}>\n                    <div style={{display: 'flex', alignItems: 'center'}}>\n                      <div>\n                        <Image width={12} height={12} src=\"/images/stack.svg\" alt=\"database-icon\"/>\n                      </div>\n                      <div className={styles.history_info}>\n                        {item.db_type}\n                      </div>\n                    </div>\n                    <div style={{display: 'flex', alignItems: 'center', marginLeft: '10px'}}>\n                      <div>\n                        <Image width={12} height={12} src=\"/images/schedule.svg\" alt=\"schedule-icon\"/>\n                      </div>\n                      <div className={styles.history_info}>\n                        Added {formatTimeDifference(item.updated_at)}\n                      </div>\n                    </div>\n                  </div>\n                </div>))}</div> : <div style={{\n                display: 'flex',\n                flexDirection: 'column',\n                alignItems: 'center',\n                justifyContent: 'center',\n                marginTop: '40px',\n                width: '100%'\n              }}>\n                <Image width={150} height={60} src=\"/images/no_permissions.svg\" alt=\"no-permissions\"/>\n                <span className={styles.feed_title} style={{marginTop: '8px'}}>No vector database added!</span>\n                <div style={{display: 'flex', justifyContent: 'center', alignItems: 'center', marginTop: '10px'}}>\n                  <button className=\"primary_button\" onClick={() => sendDatabaseData({\n                    id: -7,\n                    name: \"new database\",\n                    contentType: \"Add_Database\",\n                    internalId: createInternalId()\n                  })}>Add\n                  </button>\n                </div>\n              </div>}\n            </div> : <div style={{display: 'flex', justifyContent: 'center', alignItems: 'center', height: '50vh'}}>\n              <div className=\"signInInfo\" style={{fontSize: '16px', fontFamily: 'Source Code Pro'}}>{loadingText}</div>\n            </div>}\n          </div>\n        </div>\n      </div>\n      <div className=\"col-2\"></div>\n    </div>\n\n    {deleteModal && (<div className=\"modal\" onClick={() => setDeleteModal(false)}>\n      <div className=\"modal-content\" style={{width: '35%'}} onClick={preventDefault}>\n        <div className={styles.detail_name}>Delete {selectedDatabase.name}</div>\n        <div>\n          <label className={styles.form_label}>Deleting database will delete all the corresponding knowledge also. Do\n            you want to delete database?</label>\n        </div>\n        <div style={{display: 'flex', justifyContent: 'flex-end', marginTop: '20px'}}>\n          <button className=\"secondary_button\" style={{marginRight: '10px'}} onClick={() => setDeleteModal(false)}>\n            Cancel\n          </button>\n          <button className=\"primary_button\" onClick={() => deleteDatabase(selectedDatabase.id)}>\n            Delete\n          </button>\n        </div>\n      </div>\n    </div>)}\n    <ToastContainer/>\n  </>)\n}"
  },
  {
    "path": "gui/pages/Dashboard/Settings/DatabaseDetails.js",
    "content": "import React, {useState, useEffect} from 'react';\nimport {ToastContainer, toast} from 'react-toastify';\nimport 'react-toastify/dist/ReactToastify.css';\nimport agentStyles from \"@/pages/Content/Agents/Agents.module.css\";\nimport {removeTab, returnDatabaseIcon, setLocalStorageArray, preventDefault} from \"@/utils/utils\";\nimport knowledgeStyles from \"@/pages/Content/Knowledge/Knowledge.module.css\";\nimport styles from \"@/pages/Content/Marketplace/Market.module.css\";\nimport Image from \"next/image\";\nimport {deleteVectorDB, getVectorDBDetails, updateVectorDB} from \"@/pages/api/DashboardService\";\n\nexport default function DatabaseDetails({internalId, databaseId}) {\n  const [dropdown, setDropdown] = useState(false);\n  const [deleteModal, setDeleteModal] = useState(false);\n  const [collections, setCollections] = useState([]);\n  const [initialCollections, setInitialCollections] = useState([]);\n  const [hasChanges, setHasChanges] = useState(false);\n  const [databaseDetails, setDatabaseDetails] = useState([]);\n\n  useEffect(() => {\n    if (databaseId) {\n      getVectorDBDetails(databaseId)\n        .then((response) => {\n          const data = response.data || [];\n          setDatabaseDetails(data);\n          if (data) {\n            const localIndices = localStorage.getItem(\"db_details_collections_\" + String(internalId));\n            const indices = data.indices || [];\n            setCollections(localIndices ? JSON.parse(localIndices) : indices);\n            setInitialCollections(indices);\n          }\n        })\n        .catch((error) => {\n          console.error('Error deleting database:', error);\n        });\n    }\n  }, [internalId]);\n\n  useEffect(() => {\n    if (JSON.stringify(collections) !== JSON.stringify(initialCollections)) {\n      setHasChanges(true);\n    } else {\n      setHasChanges(false);\n    }\n  }, [collections]);\n\n  const addCollection = () => {\n    setLocalStorageArray(\"db_details_collections_\" + String(internalId), [...collections, 'collection name'], setCollections);\n  };\n\n  const handleCollectionChange = (index, newValue) => {\n    const updatedCollections = [...collections];\n    updatedCollections[index] = newValue;\n    setLocalStorageArray(\"db_details_collections_\" + String(internalId), updatedCollections, setCollections);\n  };\n\n  const handleCollectionDelete = (index) => {\n    const updatedCollections = [...collections];\n    updatedCollections.splice(index, 1);\n    setLocalStorageArray(\"db_details_collections_\" + String(internalId), updatedCollections, setCollections);\n  };\n\n  const deleteDatabase = () => {\n    setDeleteModal(false);\n\n    deleteVectorDB(databaseId)\n      .then((response) => {\n        toast.success(\"Database deleted successfully\", {autoClose: 1800});\n        removeTab(databaseId, databaseDetails?.name, \"Database\", internalId);\n      })\n      .catch((error) => {\n        toast.error(\"Unable to delete database\", {autoClose: 1800});\n        console.error('Error deleting database:', error);\n      });\n  }\n\n  const revertChanges = () => {\n    setCollections(initialCollections);\n    setHasChanges(false);\n  };\n\n  const updateChanges = () => {\n    updateVectorDB(databaseId, collections)\n      .then((response) => {\n          toast.success(\"Database updated successfully\", {autoClose: 1800});\n          setInitialCollections(collections);\n          setHasChanges(false);\n      })\n      .catch((error) => {\n        toast.error(\"Unable to update database\", {autoClose: 1800});\n        console.error('Error fetching knowledge templates:', error);\n      });\n  };\n\n  return (<>\n    <div className=\"row\">\n      <div className=\"col-3\"></div>\n      <div className=\"col-6\" style={{overflowY: 'scroll', height: 'calc(100vh - 92px)', padding: '25px 20px'}}>\n        <div className=\"title_wrapper\">\n          <div className={agentStyles.page_title}>{databaseDetails?.name}</div>\n          <div>\n            <button className=\"secondary_button\" style={{padding: '8px', height: '31px', marginTop: '-20px'}}\n                    onMouseEnter={() => setDropdown(true)} onMouseLeave={() => setDropdown(false)}>\n              <Image width={14} height={14} src=\"/images/three_dots.svg\" alt=\"run-icon\"/>\n            </button>\n            {dropdown && <div onMouseEnter={() => setDropdown(true)} onMouseLeave={() => setDropdown(false)}>\n              <ul className=\"dropdown_container\">\n                <li className=\"dropdown_item\" onClick={() => {\n                  setDropdown(false);\n                  setDeleteModal(true)\n                }}>Delete database\n                </li>\n              </ul>\n            </div>}\n          </div>\n        </div>\n        <div className=\"database_box\">\n          <div style={{display: 'flex', justifyContent: 'flex-start', order: '0', alignItems: 'center'}}>\n            <div style={{marginLeft: '15px'}}>\n              <Image src={returnDatabaseIcon(databaseDetails?.db_type)} alt=\"database-icon\" width={40} height={40}/>\n            </div>\n            <div style={{marginLeft: '15px', fontSize: '14px', marginTop: '23px'}}\n                 className={agentStyles.page_title}>{databaseDetails?.db_type}</div>\n          </div>\n        </div>\n        <div style={{marginTop: '15px'}}>\n          <div><label className={styles.form_label}>Collection/Index</label></div>\n          {collections.map((collection, index) => (<div key={index} style={{\n            marginBottom: '10px',\n            display: 'flex',\n            alignItems: 'center',\n            justifyContent: 'space-between'\n          }}>\n            <div style={{flex: '1'}}>\n              <input className=\"input_medium\" type=\"text\" value={collection}\n                     onChange={(event) => handleCollectionChange(index, event.target.value)}/>\n            </div>\n            {collections.length > 1 && <div>\n              <button className=\"secondary_button\" style={{marginLeft: '4px', padding: '5px'}}\n                      onClick={() => handleCollectionDelete(index)}>\n                <Image width={20} height={21} src=\"/images/close.svg\" alt=\"close-icon\"/>\n              </button>\n            </div>}\n          </div>))}\n          <div>\n            <button className=\"secondary_button\" onClick={addCollection}>+ Add</button>\n          </div>\n        </div>\n        {databaseDetails?.db_type === 'Pinecone' && <div>\n          <div style={{marginTop: '15px'}}>\n            <label className={knowledgeStyles.knowledge_label}>Pinecone API key</label>\n            <div className={knowledgeStyles.knowledge_info}>{databaseDetails?.api_key}</div>\n          </div>\n          <div style={{marginTop: '15px'}}>\n            <label className={knowledgeStyles.knowledge_label}>Pinecone environment</label>\n            <div className={knowledgeStyles.knowledge_info}>{databaseDetails?.environment}</div>\n          </div>\n        </div>}\n        {databaseDetails?.db_type === 'Qdrant' && <div>\n          <div style={{marginTop: '15px'}}>\n            <label className={knowledgeStyles.knowledge_label}>Qdrant API key</label>\n            <div className={knowledgeStyles.knowledge_info}>{databaseDetails?.api_key}</div>\n          </div>\n          <div style={{marginTop: '15px'}}>\n            <label className={knowledgeStyles.knowledge_label}>Qdrant URL</label>\n            <div className={knowledgeStyles.knowledge_info}>{databaseDetails?.url}</div>\n          </div>\n          <div style={{marginTop: '15px'}}>\n            <label className={knowledgeStyles.knowledge_label}>Port</label>\n            <div className={knowledgeStyles.knowledge_info}>{databaseDetails?.port}</div>\n          </div>\n        </div>}\n        {hasChanges && <div style={{display: 'flex', justifyContent: 'flex-end', marginTop: '15px'}}>\n          <button className=\"secondary_button\" style={{marginRight: '10px'}} onClick={revertChanges}>\n            Cancel\n          </button>\n          <button className=\"primary_button\" onClick={updateChanges}>\n            Update\n          </button>\n        </div>}\n      </div>\n      <div className=\"col-3\"></div>\n    </div>\n\n    {deleteModal && (<div className=\"modal\" onClick={() => setDeleteModal(false)}>\n      <div className=\"modal-content\" style={{width: '35%'}} onClick={preventDefault}>\n        <div className={styles.detail_name}>Delete {databaseDetails?.name}</div>\n        <div>\n          <label className={styles.form_label}>Deleting database will delete all the corresponding knowledge also. Do\n            you want to delete database?</label>\n        </div>\n        <div style={{display: 'flex', justifyContent: 'flex-end', marginTop: '20px'}}>\n          <button className=\"secondary_button\" style={{marginRight: '10px'}} onClick={() => setDeleteModal(false)}>\n            Cancel\n          </button>\n          <button className=\"primary_button\" onClick={deleteDatabase}>\n            Delete\n          </button>\n        </div>\n      </div>\n    </div>)}\n\n    <ToastContainer/>\n  </>)\n}"
  },
  {
    "path": "gui/pages/Dashboard/Settings/Model.js",
    "content": "import React, {useState, useEffect, useRef} from 'react';\nimport {ToastContainer, toast} from 'react-toastify';\nimport 'react-toastify/dist/ReactToastify.css';\nimport agentStyles from \"@/pages/Content/Agents/Agents.module.css\";\nimport {storeApiKey, fetchApiKeys, validateLLMApiKey, fetchApiKey} from \"@/pages/api/DashboardService\";\nimport {EventBus} from \"@/utils/eventBus\";\nimport {getUserClick, removeTab} from \"@/utils/utils\";\nimport Image from \"next/image\";\n\nexport default function Model({organisationId}) {\n  const [temperature, setTemperature] = useState(0.5);\n  const [models, setModels] = useState([\n    {'name':'Open AI API key','logo':'/images/openai_logo.svg','source':'OpenAi', 'api_key': ''},\n    {'name':'Hugging Face auth token','logo':'/images/huggingface_logo.svg','source':'Hugging Face', 'api_key': ''},\n    {'name':'Replicate auth token','logo':'/images/replicate_logo.svg','source':'Replicate', 'api_key': ''},\n    {'name':'Google Palm API key','logo':'/images/google_palm_logo.svg','source':'Google Palm', 'api_key': ''}\n  ]);\n  const [updatedModels, setUpdatedModels] = useState([]);\n\n  useEffect(() => {\n    fetchApiKeys().then((response) => {\n      if(response.data.length > 0) {\n        response.data.forEach(item => {\n          const index = models.findIndex(model => model.source.toLowerCase() === item.provider.toLowerCase());\n          if (index !== -1) {\n            const newModels = [...models];\n            newModels[index].api_key = item.api_key;\n            setModels(newModels);\n          }\n        });\n      }\n    })\n  },[])\n\n  const saveSettings = () => {\n    updatedModels.forEach(model => {\n      if (model.api_key === null || model.api_key.replace(/\\s/g, '') === '') {\n        toast.error(\"API key is empty\", {autoClose: 1800});\n        return\n      }\n      validateLLMApiKey(model.source, model.api_key)\n          .then((response) => {\n            if (response.data.status === \"success\") {\n              storeKey(model.source, model.api_key)\n            }\n            else {\n              toast.error(`Invalid API key for ${model.source}`, {autoClose: 1800});\n            }\n          });\n    });\n  };\n\n  const storeKey = (model_provider, api_key) => {\n    if(model_provider === 'OpenAi')\n      model_provider = 'OpenAI'\n    storeApiKey(model_provider,api_key).then((response) => {\n      if(response.status === 200) {\n        getUserClick('API Key Updated', {'Model': model_provider})\n        toast.success(`Successfully Stored the API Key of ${model_provider}`, {autoClose: 1800})\n      }\n      else\n        toast.error(\"Error\", {autoClose: 1800})\n    })\n  }\n\n  const handleInputChange = (source, value) => {\n    const updatedModel = models.find(model => model.source === source);\n    if (updatedModel) {\n      updatedModel.api_key = value;\n      setUpdatedModels(prevModels => {\n        const existingIndex = prevModels.findIndex(model => model.source === source);\n        if (existingIndex !== -1) {\n          return [\n            ...prevModels.slice(0, existingIndex),\n            updatedModel,\n            ...prevModels.slice(existingIndex + 1)\n          ];\n        } else {\n          return [...prevModels, updatedModel];\n        }\n      });\n    }\n  };\n\n  useEffect(() => {\n    console.log(updatedModels)\n  },[updatedModels])\n\n  const handleTemperatureChange = (event) => {\n    setTemperature(event.target.value);\n  };\n\n  return (\n      <>\n        <div className=\"row\">\n          <div className=\"col-3\"></div>\n          <div className=\"col-6 col-6-scrollable\">\n            {models.map(model => (\n                <div key={model.name}>\n                  <div className=\"horizontal_container align_center mt_24 gap_8\">\n                    <Image width={16} height={16} src={model.logo} alt={`${model.name}-icon`} />\n                    <span className=\"text_13 color_gray\">{model.name}</span>\n                  </div>\n                  <input placeholder={`Enter your ${model.name}`} className=\"input_medium mt_8\" type=\"password\" value={model.api_key}\n                      onChange={(event) => handleInputChange(model.source, event.target.value)}/>\n                </div>\n            ))}\n            {updatedModels.length > 0 && <div style={{display: 'flex', justifyContent: 'flex-end', marginTop: '15px'}}>\n              <button onClick={() => removeTab(-3, \"Settings\", \"Settings\", 0)} className=\"secondary_button mr_10\">Cancel</button>\n              <button className=\"primary_button\" onClick={saveSettings}>Update Changes</button>\n            </div>}\n          </div>\n          <div className=\"col-3\"></div>\n        </div>\n        <ToastContainer/>\n      </>\n  )\n}"
  },
  {
    "path": "gui/pages/Dashboard/Settings/Settings.js",
    "content": "import React, {useState, useEffect} from 'react';\nimport 'react-toastify/dist/ReactToastify.css';\nimport styles from \"@/pages/Content/Marketplace/Market.module.css\";\nimport Image from \"next/image\";\nimport Model from \"@/pages/Dashboard/Settings/Model\";\nimport Database from \"@/pages/Dashboard/Settings/Database\";\nimport ApiKeys from \"@/pages/Dashboard/Settings/ApiKeys\";\nimport Webhooks from \"@/pages/Dashboard/Settings/Webhooks\";\n\nexport default function Settings({organisationId, sendDatabaseData}) {\n  const [activeTab, setActiveTab] = useState('model');\n\n  useEffect(() => {\n    const settings_tab = localStorage.getItem('settings_tab');\n    if (settings_tab) {\n      setActiveTab(settings_tab);\n    }\n  }, []);\n\n  const switchTab = (tab) => {\n    setActiveTab(tab);\n    localStorage.setItem('settings_tab', tab);\n  };\n\n  return (<>\n    <div className={styles.empty_state}>\n      <div className=\"vertical_containers w_100\">\n        <div className={styles.detail_top}>\n          <div style={{display: 'flex', overflowX: 'scroll', marginLeft: '8px', gap:'4px'}}>\n            <button onClick={() => switchTab('model')} className={activeTab === 'model' ? 'tab_button_selected' : 'tab_button'}>\n              <Image width={14} height={14} src=\"/images/model_light.svg\" alt=\"model-icon\"/>\n              <span>Model Providers</span>\n            </button>\n            <button onClick={() => switchTab('database')} className={activeTab === 'database' ? 'tab_button_selected' : 'tab_button'}>\n              <Image width={14} height={14} src=\"/images/database.svg\" alt=\"database-icon\"/>\n              <span>Database</span>\n            </button>\n            <button onClick={() => switchTab('apikeys')} className={activeTab === 'apikeys' ? 'tab_button_selected' : 'tab_button'}>\n              <Image width={14} height={14} src=\"/images/key_white.svg\" alt=\"api-key-icon\"/>\n              <span>API Keys</span>\n            </button>\n            <button onClick={() => switchTab('webhooks')} className={activeTab === 'webhooks' ? 'tab_button_selected' : 'tab_button'}>\n              <Image className={styles.settings_tab_img} width={14} height={14} src=\"/images/webhook_icon.svg\"\n                     alt=\"database-icon\"/>&nbsp;Webhooks\n            </button>\n          </div>\n        </div>\n        <div>\n          {activeTab === 'model' && <Model organisationId={organisationId}/>}\n          {activeTab === 'database' && <Database sendDatabaseData={sendDatabaseData} organisationId={organisationId}/>}\n          {activeTab === 'apikeys' && <ApiKeys />}\n          {activeTab === 'webhooks' && <Webhooks />}\n        </div>\n      </div>\n    </div>\n  </>)\n}"
  },
  {
    "path": "gui/pages/Dashboard/Settings/Webhooks.js",
    "content": "import React, {useState, useEffect} from 'react';\nimport {ToastContainer, toast} from 'react-toastify';\nimport 'react-toastify/dist/ReactToastify.css';\nimport agentStyles from \"@/pages/Content/Agents/Agents.module.css\";\nimport {\n  editWebhook,\n  getWebhook, saveWebhook,\n} from \"@/pages/api/DashboardService\";\nimport {loadingTextEffect, removeTab} from \"@/utils/utils\";\nimport styles from \"@/pages/Content/Marketplace/Market.module.css\";\nexport default function Webhooks() {\n  const [webhookUrl, setWebhookUrl] = useState('');\n  const [webhookId, setWebhookId] = useState(-1);\n  const [isLoading, setIsLoading] = useState(true)\n  const [existingWebhook, setExistingWebhook] = useState(false)\n  const [isEdtiting, setIsEdtiting] = useState(false)\n  const [loadingText, setLoadingText] = useState(\"Loading Webhooks\");\n  const [selectedCheckboxes, setSelectedCheckboxes] = useState([]);\n  const checkboxes = [\n    { label: 'Agent is running', value: 'RUNNING' },\n    { label: 'Agent run is paused', value: 'PAUSED' },\n    { label: 'Agent run is completed', value: 'COMPLETED' },\n    { label: 'Agent is terminated ', value: 'TERMINATED' },\n    { label: 'Agent run max iteration reached', value: 'MAX ITERATION REACHED' },\n  ];\n\n\n  useEffect(() => {\n    loadingTextEffect('Loading Webhooks', setLoadingText, 500);\n    fetchWebhooks();\n  }, []);\n\n  const handleWebhookChange = (event) => {\n    setWebhookUrl(event.target.value);\n  };\n\n  const handleSaveWebhook = () => {\n    if(!webhookUrl || webhookUrl.trim() === \"\"){\n      toast.error(\"Enter valid webhook\", {autoClose: 1800});\n      return;\n    }\n    if(isEdtiting){\n      editWebhook(webhookId, { url: webhookUrl, filters: {status: selectedCheckboxes}})\n          .then((response) => {\n            setIsEdtiting(false)\n            fetchWebhooks()\n            toast.success(\"Webhook edited successfully\", {autoClose: 1800});\n          })\n          .catch((error) => {\n            console.error('Error fetching webhook', error);\n          });\n      return;\n    }\n    saveWebhook({name : \"Webhook 1\", url: webhookUrl, headers: {}, filters: {status: selectedCheckboxes}})\n      .then((response) => {\n        setExistingWebhook(true)\n        setWebhookId(response.data.id)\n        toast.success(\"Webhook created successfully\", {autoClose: 1800});\n      })\n      .catch((error) => {\n        toast.error(\"Unable to create webhook\", {autoClose: 1800});\n        console.error('Error saving webhook', error);\n      });\n  }\n\n  const fetchWebhooks = () => {\n    getWebhook()\n      .then((response) => {\n        setIsLoading(false)\n        if(response.data){\n          setWebhookUrl(response.data.url)\n          setExistingWebhook(true)\n          setWebhookId(response.data.id)\n          setSelectedCheckboxes(response.data.filters.status)\n        }\n        else{\n          setWebhookUrl('')\n          setExistingWebhook(false)\n          setWebhookId(-1)\n        }\n      })\n      .catch((error) => {\n        console.error('Error fetching webhook', error);\n      });\n  }\n\n  const toggleCheckbox = (value) => {\n    if (selectedCheckboxes.includes(value)) {\n      setSelectedCheckboxes(selectedCheckboxes.filter((item) => item !== value));\n    } else {\n      setSelectedCheckboxes([...selectedCheckboxes, value]);\n    }\n  };\n\n  return (<>\n    <div className=\"row\">\n      <div className=\"col-3\"></div>\n      <div className=\"col-6 col-6-scrollable\">\n        {!isLoading ? <div>\n          <div className=\"title_wrapper mb_15\">\n            <div className={styles.page_title}>Webhooks</div>\n            {existingWebhook &&\n              <button className=\"primary_button\" onClick={() => {setExistingWebhook(false);setIsEdtiting(true)} } >\n                Edit\n              </button>}\n          </div>\n\n          <div>\n            <label className={agentStyles.form_label}>Destination URL</label>\n              <input disabled={existingWebhook ? true : false} className=\"input_medium\" placeholder=\"Enter your destination url\" type=\"text\" value={webhookUrl}\n                     onChange={handleWebhookChange}/>\n            <br />\n            <label className={agentStyles.form_label}>Events to include</label>\n            <div className={styles.checkboxGroup} >\n              {checkboxes.map((checkbox) => (\n                <label key={checkbox.value} className={styles.checkboxLabel}>\n                  <input\n                    disabled={existingWebhook ? true : false}\n                    className=\"checkbox\"\n                    type=\"checkbox\"\n                    value={checkbox.value}\n                    checked={selectedCheckboxes.includes(checkbox.value)}\n                    onChange={() => toggleCheckbox(checkbox.value)}\n                  />\n                  <span className={styles.checkboxText}>&nbsp;{checkbox.label}</span>\n                </label>\n              ))}\n            </div>\n          </div>\n\n          {!existingWebhook && <div className=\"justify_end display_flex_container mt_15\">\n            <button onClick={() => removeTab(-3, \"Settings\", \"Settings\", 0)} className=\"secondary_button mr_10\">\n              Cancel\n            </button>\n            <button className=\"primary_button\" onClick={handleSaveWebhook}>\n              {isEdtiting ? \"Update\" : \"Create\"}\n            </button>\n          </div>}\n\n        </div> :  <div className=\"loading_container\">\n          <div className=\"signInInfo loading_text\">{loadingText}</div>\n        </div>}\n      </div>\n      <div className=\"col-3\"></div>\n    </div>\n    <ToastContainer/>\n  </>)\n}"
  },
  {
    "path": "gui/pages/Dashboard/SideBar.js",
    "content": "import React, {useState} from 'react';\nimport Image from 'next/image';\nimport styles from './Dashboard.module.css';\nimport {getUserClick, openNewTab} from \"@/utils/utils\";\n\nexport default function SideBar({onSelectEvent, env}) {\n    const [sectionSelected, setSelection] = useState('');\n\n    const sections = [\n        { name: 'agents', icon: '/images/agents_light.svg' },\n        { name: 'toolkits', icon: '/images/tools_light.svg' },\n        { name: 'apm', icon: '/images/apm.svg' },\n        { name: 'knowledge', icon: '/images/knowledge.svg' },\n        { name: 'models', icon: '/images/models.svg'},\n    ];\n\n    const handleClick = (value) => {\n        getUserClick(value + \"SIDEBAR ICON\", {})\n        setSelection(value);\n        onSelectEvent(value);\n        if (value === 'apm') {\n            openNewTab(-9, \"APM\", \"APM\", false);\n        }\n    };\n\n    return (\n        <div className=\"side_bar\">\n            <Image width={72} height={56} className=\"cursor_default mt_4 mb_4\"\n                   src={env === 'PROD' ? '/images/superagi_logo_beta.png' : '/images/superagi_logo.png'} alt=\"super-agi-logo\"/>\n\n            {sections.map((section) => (\n                <div key={section.name} className=\"w_100 mb_5\">\n                    <div onClick={() => handleClick(sectionSelected !== section.name ? section.name : '')}\n                         className={`${styles.section} ${sectionSelected === section.name ? styles.selected : ''}`}>\n                        <div className={styles.button_icon}>\n                            <Image width={17} height={17} src={section.icon} alt={`${section.name}-icon`}/>\n                        </div>\n                        {section.name === 'apm' ? <div>APM</div> : <div>{section.name.charAt(0).toUpperCase() + section.name.slice(1)}</div>}\n                    </div>\n                </div>\n            ))}\n        </div>\n    );\n}"
  },
  {
    "path": "gui/pages/Dashboard/TopBar.js",
    "content": "import React, {useState} from 'react';\nimport Image from 'next/image';\nimport styles from './Dashboard.module.css';\nimport {useRouter} from 'next/router';\nimport {ToastContainer, toast} from 'react-toastify';\nimport 'react-toastify/dist/ReactToastify.css';\nimport {refreshUrl, openNewTab, getUserClick} from \"@/utils/utils\";\nimport Cookies from 'js-cookie';\n\nexport default function TopBar({selectedProject, userName, env}) {\n  const [dropdown, setDropdown] = useState(false);\n  const router = useRouter();\n  const [showDropdown, setShowDropdown] = useState(false)\n  const [selectedImagePath, setSelectedImagePath] = useState('/images/agents_icon_dropdown.svg')\n  const [selectedOption, setSelectedOption] = useState('Agents')\n\n  const logoutUser = () => {\n    setDropdown(false);\n\n    if (typeof window === 'undefined') {\n      return;\n    }\n    getUserClick('Logged Out',{})\n    // localStorage.removeItem('accessToken');\n    Cookies.set('accessToken', '', { expires: new Date(0),domain: '.superagi.com', path: '/'});\n    Cookies.set('Source', 'app.superagi', {domain: '.superagi.com', path: '/'});\n    Cookies.set('mixpanel_initialized', 'false', {domain: '.superagi.com', path: '/'});\n    refreshUrl();\n    router.reload();\n  };\n\n  function handleClick (option) {\n    if (option === 'Models') {\n      setSelectedImagePath(\"/images/models_icon_dropdown.svg\")\n      setSelectedOption('Models')\n      window.location.href = 'https://models.superagi.com'\n    } else {\n      setSelectedImagePath(\"/images/agents_icon_dropdown.svg\")\n      setSelectedOption('Agents')\n    }\n    setShowDropdown(false)\n  }\n\n  return (\n    <div className=\"top_bar\">\n      <div className=\"top_left\">\n        <div className=\"top_bar_section cursor_default\">\n          {env === 'PROD' && false && <div className=\"horizontal_container\">\n            <div onClick={() => setShowDropdown(!showDropdown)} className=\"horizontal_container align-middle cursor-pointer\">\n              <Image className=\"mr_8\" width={20} height={20} src={selectedImagePath} alt=\"models-icon\" />\n              <span className=\"text_dropdown text_dropdown_18\">{selectedOption}</span>\n              <Image className=\"ml_8\" width={14} height={14} src=\"/images/arrow_down.svg\" alt=\"down_arrow\" />\n            </div>\n            {showDropdown && <div className=\"dropdown_container_models mt_130\">\n              <ul className=\"padding_0 margin_0\">\n                <li className=\"dropdown_item text_dropdown_15\" onClick={() => handleClick('Models')}>\n                  <Image className=\"mr_8\" width={20} height={20} src=\"/images/models_icon_dropdown.svg\" alt=\"models-icon\" />\n                  <span className=\"text_dropdown\">Models</span>\n                </li>\n                <li className=\"dropdown_item text_dropdown_15\" onClick={() => handleClick('Agents')}>\n                  <Image className=\"mr_8\" width={20} height={20} src=\"/images/agents_icon_dropdown.svg\" alt=\"agents-icon\" />\n                  <span className=\"text_dropdown\">Agents</span>\n                </li>\n              </ul>\n            </div>}\n          </div>}\n        </div>\n        {env === 'PROD' && false && <div className=\"vertical_divider ml_12 mr_20 responsiveness\" />}\n        <div className=\"top_bar_section top_bar_input cursor_default\">\n          <div className=\"horizontal_container\">\n            <Image width={14} height={14} src=\"/images/project.svg\" alt=\"project-icon\"/>\n            <div className=\"top_bar_font\">{selectedProject?.name || ''}</div>\n          </div>\n        </div>\n        <div className=\"top_bar_section ml_7 cursor_pointer\">\n          <Image width={14} height={14} src=\"/images/widgets.svg\" alt=\"widgets-icon\"/>\n          <div className=\"top_bar_font\" onClick={() => openNewTab(-4, \"Marketplace\", \"Marketplace\", false)}>Marketplace</div>\n        </div>\n      </div>\n      <div className=\"top_right\">\n        <div className=\"horizontal_container gap_20\">\n          <div className=\"horizontal_container w_fit_content cursor_pointer gap_4\" onClick={() => {window.open(\"https://superagi.com/docs\", \"_blank\"); getUserClick('SuperAGI Docs Visited', {})}}>\n            <Image width={20} height={20} src=\"/images/docs_icon.svg\" alt=\"docs-icon\" />\n            <p className=\"top_bar_font\">Docs</p>\n          </div>\n          <div className=\"horizontal_container w_fit_content cursor_pointer gap_4\" onClick={() => window.open(\"https://discord.com/invite/dXbRe5BHJC\", \"_blank\")}>\n            <Image width={20} height={20} src=\"/images/discord.svg\" alt=\"discord-icon\" />\n            <p className=\"top_bar_font\">Get Help</p>\n          </div>\n          <div className=\"horizontal_container w_fit_content cursor_pointer gap_4\" onClick={() => window.open(\"https://github.com/TransformerOptimus/SuperAGI\", \"_blank\")}>\n            <Image width={20} height={20} src=\"/images/github_white.svg\" alt=\"github-icon\" />\n            <p className=\"top_bar_font\">Github</p>\n          </div>\n        </div>\n\n        <div className=\"horizontal_bar mr_22 ml_22\" />\n\n        <Image onClick={() => {openNewTab(-3, \"Settings\", \"Settings\", false); getUserClick('Settings Viewed', {})}} className=\"top_right_icon\" width={16} height={16} src=\"/images/settings.svg\" alt=\"dropdown-icon\"/>\n        <div className=\"top_right_icon\" onMouseEnter={() => setDropdown(true)}\n             onMouseLeave={() => setDropdown(false)}>\n          <Image width={20} height={20} src=\"/images/profile_pic.png\" alt=\"dropdown-icon\"/>\n        </div>\n        {dropdown && env === 'PROD' &&\n          <div className=\"top_bar_profile_dropdown mt_30\" onMouseEnter={() => setDropdown(true)}\n               onMouseLeave={() => setDropdown(false)}>\n            <ul className=\"dropdown_container w_120p\">\n              {userName && <li className=\"dropdown_item\" onClick={() => setDropdown(false)}>{userName}</li>}\n              <li className=\"dropdown_item\" onClick={logoutUser}>Logout</li>\n            </ul>\n          </div>}\n      </div>\n      <ToastContainer/>\n    </div>\n  )\n}\n"
  },
  {
    "path": "gui/pages/_app.css",
    "content": "* {\n    -webkit-font-smoothing: antialiased !important;\n    text-rendering: optimizelegibility !important;\n    -ms-overflow-style: none;\n    scrollbar-width: none;\n}\n\n::-webkit-scrollbar-thumb {\n    background: transparent;\n}\n\n::-webkit-scrollbar {\n    width: 0;\n    display: none;\n    background: transparent;\n}\n\n.back_to_top {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    width: 28px;\n    height: 28px;\n    background: #1B192C;\n    border-radius: 8px;\n    border: 1px solid #8C8C8C;\n    box-shadow: -3px 3px 8px rgba(0, 0, 0, 0.3);\n    bottom: 4%;\n    position: fixed;\n    z-index: 100;\n    cursor: pointer;\n}\n\n.file-drop-area {\n    border-radius: 8px;\n    border: 1px dashed rgba(255, 255, 255, 0.2);\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    height: 120px;\n    cursor: pointer;\n    padding: 20px;\n    background: transparent;\n    margin: 0 8px 10px 0;\n    gap: 2px;\n}\n\n.file-drop-area.dragging {\n    border-radius: 0;\n    background: #3A354A;\n}\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n    -webkit-appearance: none;\n    margin: 0;\n}\n\ninput[type=\"number\"] {\n    -moz-appearance: textfield;\n}\n\ninput[type=checkbox] {\n    height: 17px !important;\n    width: 17px !important;\n    visibility: visible !important;\n}\n\ninput[type=checkbox i] {\n    cursor: pointer !important;\n}\n\ninput[type=\"range\"] {\n    appearance: none;\n    width: 100%;\n    height: 8px;\n    background: #28243A;\n    outline: none;\n    opacity: 1;\n    border-radius: 20px;\n    transition: 0.2s;\n}\n\ninput[type=\"range\"]::-webkit-slider-thumb {\n    border-radius: 100px;\n    border: 2px solid #8C8C8C;\n    appearance: none;\n    width: 20px;\n    height: 20px;\n    background: #FFFFFF;\n    cursor: pointer;\n    box-shadow: -3px 3px 8px rgba(0, 0, 0, 0.3);\n    margin-top: -5px;\n}\n\ninput[type=\"range\"]::-moz-range-thumb {\n    border-radius: 100px;\n    border: 2px solid #8C8C8C;\n    appearance: none;\n    width: 20px;\n    height: 20px;\n    background: #FFFFFF;\n    cursor: pointer;\n    box-shadow: -3px 3px 8px rgba(0, 0, 0, 0.3);\n    margin-top: -5px;\n}\n\ninput[type=\"range\"]::-webkit-slider-runnable-track {\n    width: 100%;\n    height: 8px;\n    cursor: pointer;\n    border-radius: 20px;\n    background: linear-gradient(to right, #8C8C8C 0%, #28243A 0%);\n}\n\ninput[type=\"range\"]::-moz-range-track {\n    width: 100%;\n    height: 8px;\n    cursor: pointer;\n    border-radius: 20px;\n    background: linear-gradient(to right, #8C8C8C 0%, #28243A 0%);\n}\n\n.checkbox {\n    appearance: none;\n    background-color: #222222;\n    border: 1px solid #4A4A55;\n    border-radius: 4px;\n    position: relative;\n}\n\n.checkbox:checked {\n    background-color: rgba(255, 255, 255);\n}\n\n.checkbox:checked::before {\n    content: '\\2713';\n    position: absolute;\n    transform: translateY(-20%);\n    color: #312D44;\n    font-weight: 650;\n}\n\n.tool_container {\n    font-size: 12px;\n    background: #656370;\n    border: 1px solid rgba(255, 255, 255, 0.14);\n    border-radius: 16px;\n    padding: 1px 10px;\n    margin-right: 7px;\n    margin-top: -3px;\n    color: white;\n    display: flex;\n    align-items: center;\n    min-width: fit-content;\n    max-height: 22px;\n    max-width: 150px;\n}\n\n.medium_toggle {\n    font-style: normal;\n    font-weight: 500;\n    font-size: 12px;\n    line-height: 16px;\n    color: white;\n    border: none;\n    background: transparent;\n    border-radius: 8px;\n    padding: 4px 10px 3px 10px;\n}\n\n.medium_toggle:hover {\n    background: #494856;\n}\n\n.modal {\n    position: fixed;\n    top: 0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n    background-color: rgba(0, 0, 0, 0.5);\n    display: flex;\n    justify-content: center;\n    align-items: center;\n}\n\n.modal-content {\n    background-color: #1F1B32;\n    border-radius: 8px;\n    padding: 20px;\n    box-shadow: -10px 10px 100px rgba(0, 0, 0, 0.4);\n}\n\n.page_title {\n    text-align: left;\n    font-style: normal;\n    font-weight: 400;\n    font-size: 16px;\n    line-height: 17px;\n    display: flex;\n    align-items: center;\n    color: white;\n    margin-bottom: 25px;\n}\n\n.form_label_13{\n    font-size: 13px;\n    margin-bottom: 4px;\n    font-weight: 500;\n    color: #888888;\n    line-height: 17px;\n}\n\n.form_label {\n    font-size: 14px;\n    margin-bottom: 4px;\n    font-weight: 500;\n    color: #666666;\n}\n\n.logo {\n    width: 35px;\n    height: 35px;\n    margin-left: 8px;\n}\n\n.dropdown {\n    position: absolute !important;\n    z-index: 10;\n}\n\n.dropdown_container {\n    width: 150px;\n    height: auto;\n    background: #2E293F;\n    flex-direction: column;\n    justify-content: center;\n    position: absolute;\n    border-radius: 8px;\n    box-shadow: -2px 2px 24px rgba(0, 0, 0, 0.4);\n    padding: 5px;\n    display: inline-block;\n    z-index: 99999;\n}\n\n.dropdown_item {\n    width: 100%;\n    padding: 6px 10px;\n    text-align: left;\n    height: 100%;\n    font-size: 14px;\n    color: #FFFFFF;\n    text-decoration: none;\n    border-radius: 8px;\n    list-style: none;\n    cursor: pointer;\n    text-overflow: ellipsis;\n    overflow: hidden;\n    white-space: nowrap;\n}\n\n.dropdown_item:hover {\n    background: #2D334E;\n}\n\n.dropdown ul {\n    background-color: #FFFFFF;\n    box-shadow: 0 12px 26px 1px lightgray;\n    list-style: none;\n    margin: 0;\n    padding: 0;\n    text-align: center;\n    border-radius: 6px;\n}\n\n.dropdown li {\n    width: auto;\n    height: auto;\n    padding: 10px 14px;\n    cursor: pointer;\n    font-style: normal;\n    font-weight: 400;\n    font-size: 14px;\n    line-height: 16px;\n    display: flex;\n    justify-content: left;\n    color: #1A2037;\n}\n\n.dropdown li:hover {\n    background: #F2F2F3;\n    color: black;\n}\n\n.dropdown li:focus {\n    background: #DCDCDC;\n}\n\n.dropdown li:active {\n    background: #DCDCDC;\n}\n\n.input_medium {\n    display: flex;\n    flex-direction: row;\n    align-items: center;\n    padding: 8px 14px 8px 14px;\n    gap: 4px;\n    border-radius: 8px;\n    width: 100%;\n    height: 32px;\n    background: #3B3B49;\n    border: 1px solid #4A4A55;\n    font-style: normal;\n    font-weight: 400;\n    font-size: 12px;\n    line-height: 16px;\n    transition: 0.2s;\n    color: white;\n}\n\n.input_medium:hover, .textarea_medium:hover\n{\n    border: 1px solid #494856;\n    transition: 0.2s;\n}\n\n.input_medium:disabled, .textarea_medium:disabled {\n    cursor: not-allowed;\n}\n\n.input_medium:focus, .textarea_medium:focus\n{\n    transition:0.4s;\n    outline: none;\n    border: 1px solid #494856 !important;\n}\n\n.textarea_medium\n{\n    width: 100%;\n    box-sizing: border-box;\n    display: flex;\n    flex-direction: column;\n    align-items: flex-start;\n    padding: 5px 12px;\n    left: 470px;\n    top: 20px;\n    background: #3B3B49;\n    border: 1px solid #4A4A55;\n    border-radius: 8px;\n    font-style: normal;\n    font-weight: 400;\n    font-size: 12px;\n    line-height: 17px;\n    color: white;\n    flex: none;\n    order: 0;\n    align-self: stretch;\n    transition:0.2s;\n}\n\n.custom_select_container {\n    background-color: #3B3B49;\n    display: flex;\n    align-items: center;\n    cursor: pointer;\n    border: 1px solid #4A4A55;\n    height: fit-content;\n    border-radius: 8px;\n    font-size: 12px;\n    width: 221px;\n    padding: 5px 5px 5px 10px;\n    transition: 0.4s ease-in-out;\n    justify-content: space-between;\n    font-weight: normal;\n    color: white\n}\n\n.dropdown_search_text\n{\n    background: transparent;\n    flex-grow: 1;\n    margin: 2px 0 0 4px;\n    border: none;\n    color: white;\n    outline: none;\n    font-style: normal;\n    font-weight: 400;\n    font-size: 12px;\n    line-height: 16px;\n    transition: 0.4s ease-in-out;\n}\n\n.custom_select_container:focus {\n    outline: none;\n    border: 1px solid #494856;\n    float: left;\n}\n\n.custom_select_container:hover {\n    border: 1px solid #494856;\n    transition: 0.4s ease-in-out;\n}\n\n.custom_select_container i {\n    margin: 0 10px;\n    float: right;\n}\n\n.custom_select_options {\n    background: #2E2C40;\n    border: none;\n    border-radius: 8px;\n    position: absolute;\n    width: 235px;\n    height: auto;\n    z-index: 10;\n    vertical-align: middle;\n    align-self: stretch;\n    margin-top: 2px;\n    max-height: 200px;\n    overflow-y: auto;\n    box-shadow: 0 2px 7px rgba(0,0,0,.4), 0 0 2px rgba(0,0,0,.22);\n}\n\n.custom_select_options::-webkit-scrollbar {\n    width: 6px;\n}\n\n.custom_select_options::-webkit-scrollbar-thumb {\n    background-color: rgba(0,0,0,0.2);\n}\n\n.custom_select_options::-webkit-scrollbar-track {\n    background-color: transparent;\n}\n\n.custom_select_option, .create_agent_dropdown_options {\n    cursor: pointer;\n    font-size: 12px;\n    color: white;\n    font-weight: normal;\n    height: auto;\n    max-width: 240px;\n    white-space: nowrap;\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.custom_select_option:hover, .create_agent_dropdown_options:hover {\n    background: #3B3B49;\n    border-radius: 8px;\n}\n\n.custom_select_option:hover {\n    background: #3B3B49;\n    border-radius: 8px;\n}\n\n.custom_select_option:active, .create_agent_dropdown_options:active {\n    background: #3B3B49;\n    border-radius: 8px;\n}\n\n.create_agent_dropdown_options{\n    background: #3B3B49;\n    border-radius: 8px;\n    position: absolute;\n    top: -40px;\n    right: 0;\n    box-shadow: 0 2px 7px rgba(0,0,0,.4), 0 0 2px rgba(0,0,0,.22);\n    height: 40px;\n    width: 150px;\n    padding-top: 10px;\n    text-align: center;\n}\n\n@keyframes scale-in {\n    from {\n        opacity: 0;\n        transform: scale(0.5);\n    }\n    to {\n        opacity: 1;\n        transform: scale(1);\n    }\n}\n\n@keyframes scale-out {\n    from {\n        opacity: 1;\n        transform: scale(1);\n    }\n    to {\n        opacity: 0;\n        transform: scale(0.5);\n    }\n}\n\n.dropdown_container_search {\n    display: inline-block;\n    position: relative;\n}\n\np {\n    margin: 0;\n    word-break: break-all;\n}\n\n.back_button {\n    font-weight: 500;\n    font-size: 12px;\n    color: #888888;\n    cursor: pointer;\n    margin-bottom: 8px;\n    display: inline-flex;\n    align-items: center;\n}\n\n.primary_button, .primary_button_small{\n    width: auto;\n    border-radius: 8px;\n    color: black;\n    border: none;\n    font-weight: 500;\n    height: 32px;\n    background: white;\n    text-align: center;\n    display: -webkit-inline-flex;\n    justify-content: center;\n    align-items: center;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 1;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    transition: 0.2s ease-in-out;\n}\n\n.primary_button{\n    font-size: 14px;\n    padding: 5px 15px;\n}\n\n.primary_button_small{\n    font-size: 12px;\n    padding: 0 12px;\n}\n\n.primary_button:disabled, .primary_button_small:disabled {\n    opacity: 50%;\n    cursor: not-allowed;\n}\n\n.primary_button:hover, .primary_button_small:hover {\n    background-color: rgba(255, 255, 255, 0.8);\n}\n\n.secondary_button, .secondary_button_small {\n    width: auto;\n    border-radius: 8px;\n    color: white;\n    height: 32px;\n    background: #4D4A5A;\n    border: 1px solid rgba(255, 255, 255, 0.14);\n    text-align: center;\n    display: -webkit-flex;\n    flex-direction: row;\n    align-items: center;\n    justify-content: center;\n    gap: 6px;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 1;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    transition: 0.2s ease-in-out;\n}\n\n.secondary_button{\n    font-size: 14px;\n    padding: 7px 15px;\n}\n\n.secondary_button_small{\n    font-size: 12px;\n    padding: 0 12px;\n}\n\n.secondary_button:disabled, .secondary_button_small:disabled{\n    opacity: 50%;\n    cursor: not-allowed;\n}\n\n.secondary_button:hover, .secondary_button_small:hover {\n    background-color: transparent;\n}\n\n.three_dots_vertical {\n    width: 32px;\n    border: none;\n    font-size: 14px;\n    color: white;\n    height: 32px;\n    background: transparent;\n    padding: 15px;\n    display: -webkit-flex;\n    flex-direction: row;\n    align-items: center;\n    justify-content: center;\n    gap: 6px;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 1;\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.sideBarStyle {\n    height: 100vh;\n    width: 6.5vw;\n    border-right: 1px solid #33303F;\n    overflow-y: scroll;\n    padding: 0 6px;\n}\n\n.contentStyle {\n    height: 93.5vh;\n    width: 100%;\n}\n\n.projectStyle {\n    height: 100vh;\n    width: 100vw;\n    display: flex;\n    background-color: #1B192C;\n}\n\n.workSpaceStyle {\n    height: 100vh;\n    width: 93.5vw;\n}\n\n.topBarStyle {\n    height: 6.5vh;\n    width: 100%;\n}\n\n.signInStyle {\n    background: #21173A;\n    width: 100vw;\n    height: 100vh;\n}\n\n.signInTopBar {\n    width: 100%;\n    height: 10vh;\n}\n\n.superAgiLogo {\n    padding-left: 30px;\n    display: flex;\n    align-items: center;\n}\n\n.signInCenter {\n    width: 100%;\n    height: 90vh;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n}\n\n.signInWrapper {\n    height: fit-content;\n    width: 25vw;\n    padding: 25px 20px;\n    background: #3A2E57;\n    border-radius: 8px;\n    margin-top: -30px;\n}\n\n.signInButton {\n    color: black;\n    width: 100%;\n    border: none;\n    background: white;\n    border-radius: 8px;\n    padding: 7px;\n    font-weight: 500;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n}\n\n.signInInfo {\n    color: white;\n    font-size: 10px;\n    text-align: center;\n    margin-top: 15px;\n    opacity: 0.7;\n}\n\n.history_permission\n{\n    display: flex;\n    flex-direction: row;\n    align-items: center;\n    padding: 6px 8px;\n    gap: 6px;\n    width: fit-content;\n    height: fit-content;\n    background: rgba(255, 255, 255, 0.14);\n    border: 1px solid rgba(255, 255, 255, 0.08);\n    border-radius: 16px;\n}\n\n.cancel_action {\n    margin-top: 10px;\n    width: fit-content;\n    color: #888888;\n    font-size: 12px;\n    cursor: pointer;\n}\n\n.resource_manager_tip{\n    display: flex;\n    padding: 2px 4px;\n    align-items: center;\n    border-radius: 8px;\n    background: rgba(255, 255, 255, 0.10);\n}\n\n.title_wrapper {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n}\n\n.database_box {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    border-radius: 8px;\n    background-color: #282437;\n}\n\n.index_options {\n    padding: 12px 14px;\n    max-width: 100%;\n    display: flex;\n    justify-content: space-between;\n}\n\n.mt_4{margin-top: 4px;}\n.mt_5{margin-top: 5px;}\n.mt_6{margin-top: 6px;}\n.mt_8{margin-top: 8px;}\n.mt_10{margin-top: 10px;}\n.mt_12{margin-top: 12px;}\n.mt_14{margin-top: 14px;}\n.mt_15{margin-top: 15px;}\n.mt_16{margin-top: 16px;}\n.mt_20{margin-top: 20px;}\n.mt_24{margin-top: 24px;}\n.mt_30{margin-top: 30px;}\n.mt_40{margin-top: 40px;}\n.mt_50{margin-top: 50px;}\n.mt_60{margin-top: 60px;}\n.mt_70{margin-top: 70px;}\n.mt_74{margin-top: 74px;}\n.mt_80{margin-top: 80px;}\n.mt_90{margin-top: 90px;}\n\n.mb_1{margin-bottom: 1px;}\n.mb_2{margin-bottom: 2px;}\n.mb_3{margin-bottom: 3px;}\n.mb_4{margin-bottom: 4px;}\n.mb_5{margin-bottom: 5px;}\n.mb_6{margin-bottom: 6px;}\n.mb_7{margin-bottom: 7px;}\n.mb_8{margin-bottom: 8px;}\n.mb_9{margin-bottom: 9px;}\n.mb_10{margin-bottom: 10px;}\n.mb_11{margin-bottom: 11px;}\n.mb_12{margin-bottom: 12px;}\n.mb_13{margin-bottom: 13px;}\n.mb_14{margin-bottom: 14px;}\n.mb_15{margin-bottom: 15px;}\n.mb_16{margin-bottom: 16px;}\n.mb_17{margin-bottom: 17px;}\n.mb_18{margin-bottom: 18px;}\n.mb_19{margin-bottom: 19px;}\n.mb_20{margin-bottom: 20px;}\n.mb_21{margin-bottom: 21px;}\n.mb_22{margin-bottom: 22px;}\n.mb_23{margin-bottom: 23px;}\n.mb_24{margin-bottom: 24px;}\n.mb_25{margin-bottom: 25px;}\n.mb_26{margin-bottom: 26px;}\n.mb_27{margin-bottom: 27px;}\n.mb_28{margin-bottom: 28px;}\n.mb_29{margin-bottom: 29px;}\n.mb_30{margin-bottom: 30px;}\n.mb_31{margin-bottom: 31px;}\n.mb_32{margin-bottom: 32px;}\n.mb_33{margin-bottom: 33px;}\n.mb_34{margin-bottom: 34px;}\n.mb_35{margin-bottom: 35px;}\n.mb_36{margin-bottom: 36px;}\n.mb_37{margin-bottom: 37px;}\n.mb_38{margin-bottom: 38px;}\n.mb_39{margin-bottom: 39px;}\n.mb_40{margin-bottom: 40px;}\n.mb_50{margin-bottom: 50px;}\n.mb_60{margin-bottom: 60px;}\n.mb_70{margin-bottom: 70px;}\n.mb_74{margin-bottom: 74px;}\n.mb_90{margin-bottom: 90px;}\n\n\n.ml_1{margin-left: 1px;}\n.ml_2{margin-left: 2px;}\n.ml_3{margin-left: 3px;}\n.ml_4{margin-left: 4px;}\n.ml_5{margin-left: 5px;}\n.ml_6{margin-left: 6px;}\n.ml_7{margin-left: 7px;}\n.ml_8{margin-left: 8px;}\n.ml_9{margin-left: 9px;}\n.ml_10{margin-left: 10px;}\n.ml_11{margin-left: 11px;}\n.ml_12{margin-left: 12px;}\n.ml_13{margin-left: 13px;}\n.ml_14{margin-left: 14px;}\n.ml_15{margin-left: 15px;}\n.ml_16{margin-left: 16px;}\n.ml_17{margin-left: 17px;}\n.ml_18{margin-left: 18px;}\n.ml_19{margin-left: 19px;}\n.ml_20{margin-left: 20px;}\n.ml_21{margin-left: 21px;}\n.ml_22{margin-left: 22px;}\n.ml_23{margin-left: 23px;}\n.ml_24{margin-left: 24px;}\n.ml_25{margin-left: 25px;}\n.ml_26{margin-left: 26px;}\n.ml_27{margin-left: 27px;}\n.ml_28{margin-left: 28px;}\n.ml_29{margin-left: 29px;}\n.ml_30{margin-left: 30px;}\n.ml_31{margin-left: 31px;}\n.ml_32{margin-left: 32px;}\n.ml_33{margin-left: 33px;}\n.ml_34{margin-left: 34px;}\n.ml_35{margin-left: 35px;}\n.ml_36{margin-left: 36px;}\n.ml_37{margin-left: 37px;}\n.ml_38{margin-left: 38px;}\n.ml_39{margin-left: 39px;}\n.ml_40{margin-left: 40px;}\n\n\n.mr_1{margin-right: 1px;}\n.mr_2{margin-right: 2px;}\n.mr_3{margin-right: 3px;}\n.mr_4{margin-right: 4px;}\n.mr_5{margin-right: 5px;}\n.mr_6{margin-right: 6px;}\n.mr_7{margin-right: 7px;}\n.mr_8{margin-right: 8px;}\n.mr_9{margin-right: 9px;}\n.mr_10{margin-right: 10px;}\n.mr_11{margin-right: 11px;}\n.mr_12{margin-right: 12px;}\n.mr_13{margin-right: 13px;}\n.mr_14{margin-right: 14px;}\n.mr_15{margin-right: 15px;}\n.mr_16{margin-right: 16px;}\n.mr_17{margin-right: 17px;}\n.mr_18{margin-right: 18px;}\n.mr_19{margin-right: 19px;}\n.mr_20{margin-right: 20px;}\n.mr_21{margin-right: 21px;}\n.mr_22{margin-right: 22px;}\n.mr_23{margin-right: 23px;}\n.mr_24{margin-right: 24px;}\n.mr_25{margin-right: 25px;}\n.mr_26{margin-right: 26px;}\n.mr_27{margin-right: 27px;}\n.mr_28{margin-right: 28px;}\n.mr_29{margin-right: 29px;}\n.mr_30{margin-right: 30px;}\n.mr_31{margin-right: 31px;}\n.mr_32{margin-right: 32px;}\n.mr_33{margin-right: 33px;}\n.mr_34{margin-right: 34px;}\n.mr_35{margin-right: 35px;}\n.mr_36{margin-right: 36px;}\n.mr_37{margin-right: 37px;}\n.mr_38{margin-right: 38px;}\n.mr_39{margin-right: 39px;}\n.mr_40{margin-right: 40px;}\n.mr_70{margin-right: 70px;}\n.mr_74{margin-right: 74px;}\n.mr_80{margin-right: 80px;}\n\n.fw_500{font-weight: 500;}\n\n.br_4{border-radius: 4px}\n.br_5{border-radius: 5px}\n.br_6{border-radius: 6px}\n.br_8{border-radius: 8px}\n\n.fs_10{font-size: 10px}\n.fs_20{font-size: 20px}\n\n.text_9{\n    color: #FFF;\n    font-family: Inter;\n    font-size: 9px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: normal;\n}\n\n.text_10{\n    font-style: normal;\n    font-weight: 400;\n    font-size: 10px;\n    line-height: 12px;\n    color: #888888;\n}\n\n.text_12{\n    color: #888;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: normal;\n}\n\n.text_13{\n    font-style: normal;\n    font-weight: 400;\n    font-size: 13px;\n    line-height: 15px;\n    align-items: center;\n}\n\n.text_14\n{\n    color: #FFF;\n    font-size: 14px;\n    font-weight: 400;\n}\n.text_16{\n    color: #FFF;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: normal;\n}\n\n.text_17{\n    color: #FFF;\n    font-size: 17px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: normal;\n}\n\n.text_20 {\n    color: #FFF;\n    font-size: 20px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: normal;\n}\n\n.text_20_bold{\n    color: #FFF;\n    font-size: 20px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: normal;\n    text-align: left;\n}\n\n.text_60_bold\n{\n    color: #FFF;\n    font-size: 60px;\n    font-weight: 500;\n}\n\n.horizontal_container{\n    display: inline-flex;\n    align-items: center;\n    width: 100%;\n}\n\n.horizontal_container_center{\n    display: inline-flex;\n    align-items: center;\n    justify-content: center;\n    width: 100%;\n}\n\n.vertical_containers{\n    display: flex;\n    flex-direction: column;\n}\n\n.vertical_container{\n    display: flex;\n    flex-direction: column;\n    width: 100%;\n    align-items: center;\n}\n\n.display_column_container\n{\n    display: flex;\n    flex-direction: column;\n    align-items: flex-start;\n    border-radius: 8px;\n    background: rgba(0, 0, 0, 0.20);\n    padding: 8px;\n    width: 100%;\n    height: fit-content;\n}\n\n.horizontal_space_between{\n    display: inline-flex;\n    justify-content: space-between;\n    flex-direction: row;\n    width: 100%;\n}\n\n.horizontal_container{\n    display: inline-flex;\n    align-items: center;\n}\n\n.vertical_container{\n    display: flex;\n    flex-direction: column;\n}\n\n.center_container{\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    width: 100%;\n}\n\n.margin_0{margin: 0}\n\n.r_0{right: 0}\n\n.w_120p{width: 120px}\n.w_3{width: 3%}\n.w_180p{width: 180px}\n.w_4{width: 4%}\n.w_6{width: 6%}\n.w_10{width: 10%}\n.w_12{width: 12%}\n.w_15{width: 15%}\n.w_18{width: 18%}\n.w_20{width: 20%}\n.w_22{width: 22%}\n.w_35{width: 35%}\n.w_50{width: 50%}\n.w_56{width: 56%}\n.w_60{width: 60%}\n.w_73{width: 73%}\n.w_97{width: 97%}\n.w_100{width: 100%}\n.w_inherit{width: inherit}\n.w_fit_content{width:fit-content}\n.w_inherit{width: inherit}\n\n.mxw_100{max-width: 100%}\n.mxw_360{max-width: 360px}\n\n.h_31p{height: 31px}\n.h_32p{height: 32px}\n.h_44p{height: 44px}\n.h_100{height: 100%}\n.h_auto{height: auto}\n.h_60vh{height: 60vh}\n.h_75vh{height: 75vh}\n.h_80vh{height: 80vh}\n.h_calc92{height: calc(100vh - 92px)}\n.h_calc_add40{height: calc(80vh + 40px)}\n\n.mxh_78vh{max-height: 78vh}\n\n.flex_dir_col{flex-direction: column}\n.flex_none{flex: none}\n\n.justify_center{justify-content: center}\n.justify_end{justify-content: flex-end}\n.justify_start{justify-content: flex-start}\n.justify_space_between{justify-content: space-between}\n\n.display_flex{display: inline-flex}\n.display_flex_container{display: flex}\n\n.align_center{align-items: center}\n.align_start{align-items: flex-start}\n.align_end{align-items: flex-end}\n\n.align_self_end{align-self: flex-end}\n\n.text_align_right{text-align: right}\n.text_align_center{text-align: center}\n.text_align_left{text-align: left}\n\n.position_relative{position: relative}\n.position_absolute{position: absolute}\n\n.cursor_pointer{cursor: pointer}\n.cursor_default{cursor: default}\n.cursor_not_allowed{cursor: not-allowed}\n\n.overflow_auto{overflow: auto}\n.overflowY_scroll{overflow-y: scroll}\n.overflowY_auto{overflow-y: auto}\n.overflowX_scroll{overflow-x: scroll}\n.overflowX_auto{overflow-x: auto}\n\n.gap_4{gap:4px;}\n.gap_5{gap:5px;}\n.gap_6{gap:6px;}\n.gap_8{gap:8px;}\n.gap_16{gap:16px;}\n.gap_20{gap:20px;}\n\n.br_left_grey{border-left: 1px solid rgba(255, 255, 255, 0.08)}\n.border_top_none{border-top: none;}\n.border_bottom_none{border-bottom: none;}\n.border_bottom_grey{border-bottom: 1px solid rgba(255, 255, 255, 0.08)}\n\n.bt_white{border-top: 1px solid rgba(255, 255, 255, 0.08);}\n\n.color_white{color:#FFFFFF}\n.color_gray{color:#888888}\n\n.lh_16{line-height: 16px;}\n.lh_17{line-height: 17px;}\n.lh_18{line-height: 18px;}\n.lh_24{line-height: 24px;}\n\n.padding_0{padding: 0;}\n.padding_5{padding: 5px;}\n.padding_6{padding: 6px;}\n.padding_8{padding: 8px;}\n.padding_10{padding: 10px;}\n.padding_12{padding: 12px;}\n.padding_16{padding: 16px;}\n.padding_20{padding: 20px;}\n\n.padding_8_6{padding: 8px 6px;}\n.padding_2_8{padding: 2px 8px;}\n.padding_0_8{padding: 0px 8px;}\n.padding_16_8{padding: 16px 8px;}\n.padding_12_14{padding: 12px 14px;}\n.padding_0_15{padding: 0px 15px;}\n\n.pd_bottom_5{padding-bottom: 5px}\n\n.flex_1{flex: 1}\n.flex_wrap{flex-wrap: wrap;}\n\n.mix_blend_mode{mix-blend-mode: exclusion;}\n\n.ff_sourceCode{font-family: 'Source Code Pro'}\n.ff_robotoFlex{font-family: 'Roboto Flex'}\n\n.model_options{\n    max-height: 200px;\n    overflow-y: auto;\n}\n.sticky_option{\n    position: sticky;\n    bottom: 0;\n}\n\n.rotate_90{transform: rotate(90deg)}\n\n/*------------------------------- My ROWS AND COLUMNS -------------------------------*/\n.my_rows {\n    display: flex;\n    flex-direction: row;\n    flex-wrap: wrap;\n    justify-content: space-between;\n    align-items: flex-start;\n    width: 100%;\n    height: fit-content;\n    gap: 8px;\n}\n\n.my_col {\n    display: flex;\n    flex-direction: column;\n}\n\n.my_col_12 {\n    width: 100%;\n}\n\n.my_col_10 {\n    width: calc(83.33% - 6px);\n}\n\n.my_col_8 {\n    width: calc(66.67% - 3px);\n}\n\n.my_col_7 {\n    width: calc(58.33% - 6px);\n}\n\n.my_col_6 {\n    width: calc(50% - 4px);\n}\n\n.my_col_5 {\n    width: calc(41.67% - 6px);\n}\n\n.my_col_4 {\n    width: calc(33.33% - 6px);\n}\n\n.my_col_3 {\n    width: calc(25% - 6px);\n}\n\n.my_col_2 {\n    width: calc(16.67% - 3px);\n}\n\n.my_col_1 {\n    width: calc(8.34% - 6px);\n}\n\n@media screen and (max-width: 768px) {\n    .my_col_1, .my_col_2, .my_col_3, .my_col_4,\n    .my_col_5, .my_col_6, .my_col_7, .my_col_8 {\n        width: calc(100% - 8px);\n    }\n}\n\n.scrollable_container{\n    display:flex;\n    flex-direction:column;\n    width:100%;\n    overflow: auto;\n    align-items: center;\n}\n\n.progress-bar {\n    width: 100%;\n    height: 20px;\n    border-radius: 4px;\n    background: rgba(255, 255, 255, 0.10);\n}\n\n.filled {\n    height: 20px;\n    background: linear-gradient(90deg, #7491EA 0%, #9865D9 100%);\n    border-radius: 4px;\n    position: relative;\n    overflow: hidden;\n}\n\n.shine {\n    position: absolute;\n    top: -10%;\n    left: -50%;\n    height: 120%;\n    width: 25%;\n    background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.5), transparent);\n    animation: shine 1.5s ease-in-out infinite;\n}\n\n@keyframes shine {\n    0% { left: -50%; opacity: 0; }\n    10% { left: 0%; opacity: 0.3; }\n    90% { left: 100%; opacity: 0.3; }\n    100% { left: 150%; opacity: 0; }\n}\n\n.bar-chart {\n    display: flex;\n    flex-direction: column;\n    align-items: flex-start;\n}\n\n.bar {\n    width: 0;\n    height: 40px;\n    background: linear-gradient(90deg, #7491EA 0%, #9865D9 100%);\n    border-radius: 10px;\n    line-height: 40px;\n    color: white;\n    padding-left: 10px;\n    text-align: left;\n    transition: width 2s;\n}\n\n.active_runs{\n    display: flex;\n    width: 100%;\n    padding: 8px;\n    flex-direction: column;\n    align-items: flex-start;\n    gap: 2px;\n    border-radius: 8px;\n    background: rgba(255, 255, 255, 0.06);\n}\n\n.table_css{\n    border-bottom: 1px solid rgba(255, 255, 255, 0.08);\n    width: 100%;\n}\n\n.table_header{\n    color: #888;\n    font-size: 12px;\n    font-weight: 500;\n    padding: 8px;\n    align-items: center;\n}\n\n.table_data{\n    gap: 10px;\n    color: #FFF;\n    font-size: 12px;\n    font-weight: 400;\n    padding: 8px;\n}\n\ntr{\n    border: 1px solid rgba(255, 255, 255, 0.08);\n    border-right: none;\n    border-left: none;\n}\n\n.table_border{border-right: 1px solid rgba(255, 255, 255, 0.08);}\n\n.bar_label_dot{\n    display: inline-block;\n    width: 12px;\n    height: 12px;\n    border-radius: 10px;\n}\n\n.bar_label_text{\n    color: #888;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: normal;\n    margin-left: 8px;\n}\n\n.tools_used{\n    border-radius: 16px;\n    border: 1px solid rgba(255, 255, 255, 0.08);\n    background: rgba(255, 255, 255, 0.14);\n    display: inline-flex;\n    height: 20px;\n    padding: 3px 8px;\n    align-items: center;\n    gap: 6px;\n    color: #FFF;\n    font-size: 11px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: normal;\n    margin: 2px;\n}\n\n.image_class{\n    background: #FFFFFF80;\n    border-radius: 20px;\n}\n\n.tool_icon{\n    border-radius: 25px;\n    background: black;\n    position: relative;\n}\n\n.loader {\n    font-size: 2px;\n    width: 1em;\n    height: 1em;\n    border-radius: 50%;\n    position: relative;\n    text-indent: -9999em;\n    -webkit-animation: load5 1.1s infinite ease;\n    animation: load5 1.1s infinite ease;\n    -webkit-transform: translateZ(0);\n    -ms-transform: translateZ(0);\n    transform: translateZ(0);\n}\n\n@-webkit-keyframes load5 {\n    0%,\n    100% {\n        box-shadow: 0em -2.6em 0em 0em #231f1f, 1.8em -1.8em 0 0em rgba(35,31,31, 0.2), 2.5em 0em 0 0em rgba(35,31,31, 0.2), 1.75em 1.75em 0 0em rgba(35,31,31, 0.2), 0em 2.5em 0 0em rgba(35,31,31, 0.2), -1.8em 1.8em 0 0em rgba(35,31,31, 0.2), -2.6em 0em 0 0em rgba(35,31,31, 0.5), -1.8em -1.8em 0 0em rgba(35,31,31, 0.7);\n    }\n    12.5% {\n        box-shadow: 0em -2.6em 0em 0em rgba(35,31,31, 0.7), 1.8em -1.8em 0 0em #231f1f, 2.5em 0em 0 0em rgba(35,31,31, 0.2), 1.75em 1.75em 0 0em rgba(35,31,31, 0.2), 0em 2.5em 0 0em rgba(35,31,31, 0.2), -1.8em 1.8em 0 0em rgba(35,31,31, 0.2), -2.6em 0em 0 0em rgba(35,31,31, 0.2), -1.8em -1.8em 0 0em rgba(35,31,31, 0.5);\n    }\n    25% {\n        box-shadow: 0em -2.6em 0em 0em rgba(35,31,31, 0.5), 1.8em -1.8em 0 0em rgba(35,31,31, 0.7), 2.5em 0em 0 0em #231f1f, 1.75em 1.75em 0 0em rgba(35,31,31, 0.2), 0em 2.5em 0 0em rgba(35,31,31, 0.2), -1.8em 1.8em 0 0em rgba(35,31,31, 0.2), -2.6em 0em 0 0em rgba(35,31,31, 0.2), -1.8em -1.8em 0 0em rgba(35,31,31, 0.2);\n    }\n    37.5% {\n        box-shadow: 0em -2.6em 0em 0em rgba(35,31,31, 0.2), 1.8em -1.8em 0 0em rgba(35,31,31, 0.5), 2.5em 0em 0 0em rgba(35,31,31, 0.7), 1.75em 1.75em 0 0em #231f1f, 0em 2.5em 0 0em rgba(35,31,31, 0.2), -1.8em 1.8em 0 0em rgba(35,31,31, 0.2), -2.6em 0em 0 0em rgba(35,31,31, 0.2), -1.8em -1.8em 0 0em rgba(35,31,31, 0.2);\n    }\n    50% {\n        box-shadow: 0em -2.6em 0em 0em rgba(35,31,31, 0.2), 1.8em -1.8em 0 0em rgba(35,31,31, 0.2), 2.5em 0em 0 0em rgba(35,31,31, 0.5), 1.75em 1.75em 0 0em rgba(35,31,31, 0.7), 0em 2.5em 0 0em #231f1f, -1.8em 1.8em 0 0em rgba(35,31,31, 0.2), -2.6em 0em 0 0em rgba(35,31,31, 0.2), -1.8em -1.8em 0 0em rgba(35,31,31, 0.2);\n    }\n    62.5% {\n        box-shadow: 0em -2.6em 0em 0em rgba(35,31,31, 0.2), 1.8em -1.8em 0 0em rgba(35,31,31, 0.2), 2.5em 0em 0 0em rgba(35,31,31, 0.2), 1.75em 1.75em 0 0em rgba(35,31,31, 0.5), 0em 2.5em 0 0em rgba(35,31,31, 0.7), -1.8em 1.8em 0 0em #231f1f, -2.6em 0em 0 0em rgba(35,31,31, 0.2), -1.8em -1.8em 0 0em rgba(35,31,31, 0.2);\n    }\n    75% {\n        box-shadow: 0em -2.6em 0em 0em rgba(35,31,31, 0.2), 1.8em -1.8em 0 0em rgba(35,31,31, 0.2), 2.5em 0em 0 0em rgba(35,31,31, 0.2), 1.75em 1.75em 0 0em rgba(35,31,31, 0.2), 0em 2.5em 0 0em rgba(35,31,31, 0.5), -1.8em 1.8em 0 0em rgba(35,31,31, 0.7), -2.6em 0em 0 0em #231f1f, -1.8em -1.8em 0 0em rgba(35,31,31, 0.2);\n    }\n    87.5% {\n        box-shadow: 0em -2.6em 0em 0em rgba(35,31,31, 0.2), 1.8em -1.8em 0 0em rgba(35,31,31, 0.2), 2.5em 0em 0 0em rgba(35,31,31, 0.2), 1.75em 1.75em 0 0em rgba(35,31,31, 0.2), 0em 2.5em 0 0em rgba(35,31,31, 0.2), -1.8em 1.8em 0 0em rgba(35,31,31, 0.5), -2.6em 0em 0 0em rgba(35,31,31, 0.7), -1.8em -1.8em 0 0em #231f1f;\n    }\n}\n@keyframes load5 {\n    0%,\n    100% {\n        box-shadow: 0em -2.6em 0em 0em #231f1f, 1.8em -1.8em 0 0em rgba(35,31,31, 0.2), 2.5em 0em 0 0em rgba(35,31,31, 0.2), 1.75em 1.75em 0 0em rgba(35,31,31, 0.2), 0em 2.5em 0 0em rgba(35,31,31, 0.2), -1.8em 1.8em 0 0em rgba(35,31,31, 0.2), -2.6em 0em 0 0em rgba(35,31,31, 0.5), -1.8em -1.8em 0 0em rgba(35,31,31, 0.7);\n    }\n    12.5% {\n        box-shadow: 0em -2.6em 0em 0em rgba(35,31,31, 0.7), 1.8em -1.8em 0 0em #231f1f, 2.5em 0em 0 0em rgba(35,31,31, 0.2), 1.75em 1.75em 0 0em rgba(35,31,31, 0.2), 0em 2.5em 0 0em rgba(35,31,31, 0.2), -1.8em 1.8em 0 0em rgba(35,31,31, 0.2), -2.6em 0em 0 0em rgba(35,31,31, 0.2), -1.8em -1.8em 0 0em rgba(35,31,31, 0.5);\n    }\n    25% {\n        box-shadow: 0em -2.6em 0em 0em rgba(35,31,31, 0.5), 1.8em -1.8em 0 0em rgba(35,31,31, 0.7), 2.5em 0em 0 0em #231f1f, 1.75em 1.75em 0 0em rgba(35,31,31, 0.2), 0em 2.5em 0 0em rgba(35,31,31, 0.2), -1.8em 1.8em 0 0em rgba(35,31,31, 0.2), -2.6em 0em 0 0em rgba(35,31,31, 0.2), -1.8em -1.8em 0 0em rgba(35,31,31, 0.2);\n    }\n    37.5% {\n        box-shadow: 0em -2.6em 0em 0em rgba(35,31,31, 0.2), 1.8em -1.8em 0 0em rgba(35,31,31, 0.5), 2.5em 0em 0 0em rgba(35,31,31, 0.7), 1.75em 1.75em 0 0em #231f1f, 0em 2.5em 0 0em rgba(35,31,31, 0.2), -1.8em 1.8em 0 0em rgba(35,31,31, 0.2), -2.6em 0em 0 0em rgba(35,31,31, 0.2), -1.8em -1.8em 0 0em rgba(35,31,31, 0.2);\n    }\n    50% {\n        box-shadow: 0em -2.6em 0em 0em rgba(35,31,31, 0.2), 1.8em -1.8em 0 0em rgba(35,31,31, 0.2), 2.5em 0em 0 0em rgba(35,31,31, 0.5), 1.75em 1.75em 0 0em rgba(35,31,31, 0.7), 0em 2.5em 0 0em #231f1f, -1.8em 1.8em 0 0em rgba(35,31,31, 0.2), -2.6em 0em 0 0em rgba(35,31,31, 0.2), -1.8em -1.8em 0 0em rgba(35,31,31, 0.2);\n    }\n    62.5% {\n        box-shadow: 0em -2.6em 0em 0em rgba(35,31,31, 0.2), 1.8em -1.8em 0 0em rgba(35,31,31, 0.2), 2.5em 0em 0 0em rgba(35,31,31, 0.2), 1.75em 1.75em 0 0em rgba(35,31,31, 0.5), 0em 2.5em 0 0em rgba(35,31,31, 0.7), -1.8em 1.8em 0 0em #231f1f, -2.6em 0em 0 0em rgba(35,31,31, 0.2), -1.8em -1.8em 0 0em rgba(35,31,31, 0.2);\n    }\n    75% {\n        box-shadow: 0em -2.6em 0em 0em rgba(35,31,31, 0.2), 1.8em -1.8em 0 0em rgba(35,31,31, 0.2), 2.5em 0em 0 0em rgba(35,31,31, 0.2), 1.75em 1.75em 0 0em rgba(35,31,31, 0.2), 0em 2.5em 0 0em rgba(35,31,31, 0.5), -1.8em 1.8em 0 0em rgba(35,31,31, 0.7), -2.6em 0em 0 0em #231f1f, -1.8em -1.8em 0 0em rgba(35,31,31, 0.2);\n    }\n    87.5% {\n        box-shadow: 0em -2.6em 0em 0em rgba(35,31,31, 0.2), 1.8em -1.8em 0 0em rgba(35,31,31, 0.2), 2.5em 0em 0 0em rgba(35,31,31, 0.2), 1.75em 1.75em 0 0em rgba(35,31,31, 0.2), 0em 2.5em 0 0em rgba(35,31,31, 0.2), -1.8em 1.8em 0 0em rgba(35,31,31, 0.5), -2.6em 0em 0 0em rgba(35,31,31, 0.7), -1.8em -1.8em 0 0em #231f1f;\n    }\n}\n\n.bg_black{background: black;}\n.bg_white{background: white;}\n.bg_none{background: none;}\n.bg_primary{background: #2E293F;}\n.bg_secondary{background: #272335;}\n\n.container {\n    height: 100%;\n    width: 100%;\n    padding: 0 0 0 8px;\n}\n\n.title_box {\n    width: 100%;\n    padding: 8px;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n}\n\n.item_container{\n    display: flex;\n    align-items: center;\n    justify-content: flex-start;\n}\n\n.item_name {\n    font-style: normal;\n    font-weight: 500;\n    font-size: 12px;\n    line-height: 21px;\n    color: #FEFEFE;\n    margin-top: -2px;\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 1;\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.item_publisher {\n    font-style: normal;\n    font-weight: 500;\n    font-size: 11px;\n    line-height: 12px;\n    display: flex;\n    align-items: center;\n    color: #666666;\n    margin-top: 2px;\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 1;\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.item_box {\n    cursor: pointer;\n    width: 100%;\n    border-radius: 8px;\n}\n\n.item_box:hover{\n    background-color: #494856;\n}\n\n.vertical_selection_scroll{\n    overflow-y: scroll;\n    height: 80vh;\n}\n\n.agent_text {\n    font-style: normal;\n    font-weight: 400;\n    font-size: 13px;\n    line-height: 15px;\n    align-items: center;\n    color: white;\n    flex: none;\n    order: 1;\n    flex-grow: 0;\n}\n\n.agent_box {\n    display: inline-flex;\n    flex-direction: row;\n    align-items: center;\n    justify-content: flex-start;\n    padding: 10px 8px;\n    gap: 6px;\n    border-radius: 8px;\n    flex: none;\n    order: 0;\n    flex-grow: 0;\n    cursor: pointer;\n    height: 35px;\n}\n\n.agent_box:hover, .sidebar_box:hover {\n    background-color: #494856;\n}\n\n.sidebar_box{\n    display: flex;\n    padding: 10px 8px;\n    gap: 6px;\n    border-radius: 8px;\n    flex: none;\n    order: 0;\n    flex-grow: 0;\n    cursor: pointer;\n    height: fit-content;\n}\n\n.text_ellipsis{\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 1;\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.tab_button, .tab_button_selected{\n    background: transparent;\n    border: none;\n    font-style: normal;\n    font-weight: 400;\n    font-size: 12px;\n    line-height: 15px;\n    color: #FFFFFF;\n    border-radius: 8px;\n    padding: 5px 10px;\n    display: -webkit-inline-flex;\n    align-items: center;\n    justify-content: center;\n    gap: 6px;\n}\n\n.tab_button{\n    background: transparent;\n}\n\n.tab_button_selected{\n    background: #454254;\n}\n\n.tab_button_small, .tab_button_small_selected{\n    height: 30px;\n    font-size: 12px;\n    text-align: center;\n    display: flex;\n    align-items: center;\n    padding: 8px;\n    border-radius: 8px;\n    cursor: pointer;\n}\n\n.tab_button_small{\n    background: transparent;\n}\n\n.tab_button_small_selected{\n    background: #454254;\n}\n\n.detail_top {\n    width: 100%;\n    height: fit-content;\n    display: inline-flex;\n    align-items: center;\n    padding-right: 10px;\n}\n\n.detail_body{\n    overflow-y: auto;\n    max-height: 80vh;\n    position: relative;\n    width: 100%;\n    padding-right: 10px;\n}\n\n.detail_content {\n    height: calc(100vh - 140px);\n    border-radius: 8px;\n    overflow-y: scroll;\n    padding-bottom: 0;\n}\n\n.feed_title {\n    font-family: 'Source Code Pro';\n    margin-left: 10px;\n    font-style: normal;\n    font-weight: 500;\n    font-size: 12px;\n    line-height: 15px;\n    color: white;\n    white-space: pre-line;\n    word-wrap: break-word;\n    max-width: 95%;\n}\n\n\n.top_bar {\n    padding: 8px 10px;\n    height: 100%;\n    display: flex;\n    align-items: center;\n    justify-content: space-between;\n}\n\n.top_bar_section {\n    display: flex;\n    align-items: center;\n    justify-content: space-between;\n    padding: 2px 9px;\n    gap: 8px;\n    border-radius: 8px;\n    cursor: pointer;\n}\n\n.top_bar_input{\n    border: 1px solid rgba(255, 255, 255, 0.14);\n    width: 150px;\n}\n\n.top_bar_font {\n    display: flex;\n    align-items: center;\n    font-style: normal;\n    font-weight: 400;\n    font-size: 12px;\n    color: white;\n    margin-left: 5px;\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 1;\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n\n.top_right {\n    display: flex;\n    flex-direction: row;\n    align-items: center;\n    justify-content: flex-end;\n    width: fit-content;\n    order: 1;\n    height: 100%;\n}\n\n.top_left {\n    display: flex;\n    order: 0;\n    justify-content: flex-start;\n    align-items: center;\n}\n\n.top_right_icon {\n    margin-right: 10px;\n    cursor: pointer;\n    display: flex;\n    order: 1;\n    justify-content: flex-end;\n    align-items: center;\n    height: 100%;\n}\n\n.horizontal_bar{\n    background: rgba(255, 255, 255, 0.10);\n    width: 4px;\n    height: 80%;\n    border-radius: 8px;\n    border: rgba(255, 255, 255, 0.10);\n}\n\n.side_bar {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    position: relative;\n    height: 100%;\n    color: white;\n}\n\n.col-6-scrollable {\n    overflow-y: scroll;\n    height: calc(100vh - 92px);\n    padding: 25px 20px;\n}\n\n.market_tool, .market_containers {\n    display: flex;\n    height: fit-content;\n    color: white;\n    font-size: small;\n    padding: 12px;\n    background-color: rgb(39, 35, 53);\n    border-radius: 8px;\n    flex-direction: column;\n}\n\n.marketplaceGrid {\n    display: grid;\n    grid-template-columns: repeat(2,1fr);\n    grid-gap: 6px;\n}\n\n.marketplaceGrid3 {\n    display: grid;\n    grid-template-columns: repeat(3,1fr);\n    grid-gap: 6px;\n}\n\n.market_tool{\n    width: 33% !important;\n}\n\n.history_box, .history_box_selected {\n    width: 100%;\n    color: white;\n    font-style: normal;\n    font-weight: 400;\n    font-size: 12px;\n    line-height: 14px;\n    border-radius: 8px;\n    cursor: pointer;\n    margin-bottom: 7px;\n}\n\n.history_box{\n    background: #272335;\n}\n\n.history_box_selected{\n    background: #474255;\n}\n\n.loading_container{\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    height: 50vh\n}\n\n.loading_text{\n    font-size: 16px;\n    font-family: 'Source Code Pro';\n}\n\n.table_container{\n    background: #272335;\n    border-radius: 8px;\n    margin-top:15px\n}\n\n.error_box{\n    border-radius: 8px;\n    border-left: 4px solid rgba(255, 65, 65, 0.60);\n    background: rgba(255, 65, 65, 0.16);\n    padding: 12px;\n}\n\n.info_box{\n    border-radius: 8px;\n    border-left: 4px solid rgba(255, 255, 255, 0.60);\n    background: rgba(255, 255, 255, 0.08);\n    padding: 12px;\n}\n\n.success_box{\n    border-radius: 8px;\n    padding: 12px;\n    border-left: 4px solid rgba(255, 255, 255, 0.60);\n    background: rgba(255, 255, 255, 0.08);\n}\n\n.horizontal_line {\n    margin: 16px 0 16px -16px;\n    border: 1px solid #ffffff20;\n    width: calc(100% + 32px);\n    display: flex;\n    height: 0;\n}\n\n.gridContainer {\n    display: grid;\n    grid-template-columns: repeat(12, 1fr);\n    gap: 8px;\n}\n\n.col_1 {grid-column: span 1;}\n.col_2 {grid-column: span 2;}\n.col_3 {grid-column: span 3;}\n.col_4 {grid-column: span 4;}\n.col_5 {grid-column: span 5;}\n.col_6 {grid-column: span 6;}\n.col_7 {grid-column: span 7;}\n.col_8 {grid-column: span 8;}\n.col_9 {grid-column: span 9;}\n.col_10 {grid-column: span 10;}\n.col_11 {grid-column: span 11;}\n.col_12 {grid-column: span 12;}\n\n.tag_container {\n    border-radius: 8px;\n    background: rgba(0, 0, 0, 0.20);\n    padding: 16px;\n}\n\n.tags {\n    border-radius: 16px;\n    border: 1px solid rgba(255, 255, 255, 0.08);\n    background: rgba(255, 255, 255, 0.14);\n    display: flex;\n    flex-direction: row;\n    align-items: center;\n    padding: 2px 8px;\n}\n.top_bar_profile_dropdown{\n    display: flex;\n    flex-direction: row;\n    justify-content: center;\n}\n\n.tooltip-class {\n    background-color: green;\n    border-radius: 6px;\n}"
  },
  {
    "path": "gui/pages/_app.js",
    "content": "import React, {useState, useEffect} from 'react';\nimport SideBar from './Dashboard/SideBar';\nimport Content from './Dashboard/Content';\nimport TopBar from './Dashboard/TopBar';\nimport 'bootstrap/dist/css/bootstrap.css';\nimport \"react-grid-layout/css/styles.css\";\nimport \"react-resizable/css/styles.css\";\nimport './_app.css'\nimport Head from 'next/head';\nimport Image from \"next/image\";\nimport {\n  getOrganisation,\n  getProject,\n  validateAccessToken,\n  checkEnvironment,\n  addUser,\n  installToolkitTemplate, installAgentTemplate, installKnowledgeTemplate, getFirstSignup\n} from \"@/pages/api/DashboardService\";\nimport {githubClientId, mixpanelId} from \"@/pages/api/apiConfig\";\nimport {\n  getGithubClientId\n} from \"@/pages/api/DashboardService\";\nimport {useRouter} from 'next/router';\nimport querystring from 'querystring';\nimport {refreshUrl, loadingTextEffect, getUTMParametersFromURL, setLocalStorageValue, getUserClick, sendGAEvent} from \"@/utils/utils\";\nimport MarketplacePublic from \"./Content/Marketplace/MarketplacePublic\"\nimport {toast} from \"react-toastify\";\nimport mixpanel from 'mixpanel-browser';\nimport Cookies from 'js-cookie';\n\nexport default function App() {\n  const [selectedView, setSelectedView] = useState('');\n  const [applicationState, setApplicationState] = useState(\"LOADING\");\n  const [selectedProject, setSelectedProject] = useState(null);\n  const [userName, setUserName] = useState('');\n  const [organisationId, setOrganisationId] = useState(null);\n  const [env, setEnv] = useState('DEV');\n  const [loadingText, setLoadingText] = useState(\"Initializing SuperAGI\");\n  const router = useRouter();\n  const [showMarketplace, setShowMarketplace] = useState(false);\n  const excludedKeys = [\n    'repo_starred',\n    'popup_closed_time',\n    'twitter_toolkit_id',\n    'accessToken',\n    'agent_to_install',\n    'toolkit_to_install',\n    'google_calendar_toolkit_id',\n    'knowledge_to_install',\n    'knowledge_index_to_install',\n    'myLayoutKey'\n  ];\n\n  function fetchOrganisation(userId) {\n    getOrganisation(userId)\n      .then((response) => {\n        setOrganisationId(response.data.id);\n      })\n      .catch((error) => {\n        console.error('Error fetching project:', error);\n      });\n  }\n\n\n  const installFromMarketplace = () => {\n    const toolkitName = localStorage.getItem('toolkit_to_install') || null;\n    const agentTemplateId = localStorage.getItem('agent_to_install') || null;\n    const knowledgeTemplateName = localStorage.getItem('knowledge_to_install') || null;\n    const knowledgeIndexId = localStorage.getItem('knowledge_index_to_install') || null;\n\n    if (knowledgeTemplateName !== null && knowledgeIndexId !== null) {\n      installKnowledgeTemplate(knowledgeTemplateName, knowledgeIndexId)\n        .then((response) => {\n          toast.success(\"Template installed\", {autoClose: 1800});\n        })\n        .catch((error) => {\n          console.error('Error installing template:', error);\n        });\n      localStorage.removeItem('knowledge_to_install');\n      localStorage.removeItem('knowledge_index_to_install');\n    }\n\n    if (toolkitName !== null) {\n      installToolkitTemplate(toolkitName)\n        .then((response) => {\n          toast.success(\"Template installed\", {autoClose: 1800});\n        })\n        .catch((error) => {\n          console.error('Error installing template:', error);\n        });\n      localStorage.removeItem('toolkit_to_install');\n    }\n\n    if (agentTemplateId !== null) {\n      installAgentTemplate(agentTemplateId)\n        .then((response) => {\n          toast.success(\"Template installed\", {autoClose: 1800});\n        })\n        .catch((error) => {\n          console.error('Error installing template:', error);\n        });\n      localStorage.removeItem('agent_to_install');\n    }\n  }\n\n  useEffect(() => {\n    handleMarketplace()\n    loadingTextEffect('Initializing SuperAGI', setLoadingText, 500);\n\n    checkEnvironment()\n      .then((response) => {\n        const env = response.data.env;\n        setEnv(env);\n        const mixpanelInitialized = Cookies.get('mixpanel_initialized') === 'true'\n        if (typeof window !== 'undefined') {\n          if(response.data.env === 'PROD' && mixpanelId()) {\n            mixpanel.init(mixpanelId(), {debug: false, track_pageview: !mixpanelInitialized, persistence: 'localStorage'});\n          }\n          localStorage.setItem('applicationEnvironment', env);\n        }\n\n        if (response.data.env === 'PROD') {\n          setApplicationState(\"NOT_AUTHENTICATED\");\n          const queryParams = router.asPath.split('?')[1];\n          const parsedParams = querystring.parse(queryParams);\n          let access_token = parsedParams.access_token || null;\n          let first_login = parsedParams.first_time_login || ''\n\n          const utmParams = getUTMParametersFromURL();\n          if (utmParams) {\n            sessionStorage.setItem('utm_source', utmParams.utm_source);\n            sessionStorage.setItem('utm_medium', utmParams.utm_medium);\n            sessionStorage.setItem('campaign', utmParams.utm_campaign);\n          }\n          const signupSource = sessionStorage.getItem('utm_source');\n          const signupMedium = sessionStorage.getItem('utm_medium');\n          const singupCampaign = sessionStorage.getItem('campaign');\n\n          if (typeof window !== 'undefined' && access_token) {\n            // localStorage.setItem('accessToken', access_token);\n            Cookies.set('accessToken', access_token, {domain: '.superagi.com', path: '/'});\n            refreshUrl();\n          }\n          validateAccessToken()\n            .then((response) => {\n              setUserName(response.data.name || '');\n              sendGAEvent(response.data.email, 'Signed Up Successfully', {'utm_source': signupSource || '', 'utm_medium': signupMedium || '', 'campaign': singupCampaign || ''})\n              if(mixpanelId())\n                mixpanel.identify(response.data.email)\n              if(first_login === 'True') {\n                getUserClick('New Sign Up', {})\n              }\n              else {\n                if (first_login === 'False')\n                  getUserClick('User Logged In', {})\n              }\n\n              if(signupSource) {\n                handleSignUpSource(signupSource)\n              }\n              fetchOrganisation(response.data.id);\n              Cookies.set('mixpanel_initialized', 'true', {domain: '.superagi.com', path: '/'});\n            })\n            .catch((error) => {\n              console.error('Error validating access token:', error);\n            });\n        } else {\n          handleLocalEnviroment()\n        }\n      })\n      .catch((error) => {\n        console.error('Error fetching project:', error);\n      });\n\n  }, []);\n\n  useEffect(() => {\n    if (organisationId !== null) {\n      getProject(organisationId)\n        .then((response) => {\n          setSelectedProject(response.data[0]);\n        })\n        .catch((error) => {\n          console.error('Error fetching project:', error);\n        });\n    }\n  }, [organisationId]);\n\n  useEffect(() => {\n    if (selectedProject !== null) {\n      const source = Cookies.get('Source')\n      if (source === 'models.superagi')\n        window.open('https://models.superagi.com/', '_self');\n      else\n        setApplicationState(\"AUTHENTICATED\");\n    }\n  }, [selectedProject]);\n\n  const handleSelectionEvent = (data) => {\n    setSelectedView(data);\n  };\n\n  async function signInUser() {\n    let github_client_id = githubClientId();\n\n      // If `github_client_id` does not exist, make the API call\n      if (!github_client_id) {\n        const response = await getGithubClientId();\n        github_client_id = response.data.github_client_id;\n      }\n      if(!github_client_id) {\n         console.error('Error fetching github client id make sure to set it in the config file');\n      }\n      else {\n        window.open(`https://github.com/login/oauth/authorize?scope=user:email&client_id=${github_client_id}`, '_self')\n      }\n  }\n\n  const handleLocalEnviroment = () => {\n    const userData = {\n      \"name\": \"SuperAGI User\",\n      \"email\": \"super6@agi.com\",\n      \"password\": \"pass@123\",\n    }\n\n    addUser(userData)\n        .then((response) => {\n          setUserName(response.data.name);\n          fetchOrganisation(response.data.id);\n        })\n        .catch((error) => {\n          console.error('Error adding user:', error);\n        });\n  };\n  const handleSignUpSource = (signup) => {\n    getFirstSignup(signup)\n        .then((response) => {\n        })\n        .catch((error) => {\n          console.error('Error validating source:', error);\n        })\n  };\n\n  const handleMarketplace = () => {\n    if (window.location.href.toLowerCase().includes('marketplace')) {\n      setShowMarketplace(true);\n    } else {\n      installFromMarketplace();\n    }\n  };\n\n  useEffect(() => {\n    const clearLocalStorage = () => {\n      Object.keys(localStorage).forEach((key) => {\n        if (!excludedKeys.includes(key)) {\n          localStorage.removeItem(key);\n        }\n      });\n    };\n\n    window.addEventListener('beforeunload', clearLocalStorage);\n    window.addEventListener('unload', clearLocalStorage);\n\n    return () => {\n      window.removeEventListener('beforeunload', clearLocalStorage);\n      window.removeEventListener('unload', clearLocalStorage);\n    };\n  }, []);\n\n  return (\n    <div className=\"app\">\n      <Head>\n        <title>SuperAGI</title>\n        {/* eslint-disable-next-line @next/next/no-page-custom-font */}\n        <link href=\"https://fonts.googleapis.com/css2?family=Source+Code+Pro&display=swap\" rel=\"stylesheet\"/>\n        {/* eslint-disable-next-line @next/next/no-page-custom-font */}\n        <link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap\"\n              rel=\"stylesheet\"/>\n      </Head>\n      {showMarketplace && <div className=\"projectStyle\"><MarketplacePublic env={env}/></div>}\n      {applicationState === 'AUTHENTICATED' && !showMarketplace ? (<div className=\"projectStyle\">\n        <div className=\"sideBarStyle\">\n          <SideBar onSelectEvent={handleSelectionEvent} env={env}/>\n        </div>\n        <div className=\"workSpaceStyle\">\n          <div className=\"topBarStyle\">\n            <TopBar selectedProject={selectedProject} organisationId={organisationId} userName={userName} env={env}/>\n          </div>\n          <div className=\"contentStyle\">\n            <Content env={env} organisationId={organisationId} selectedView={selectedView}\n                     selectedProjectId={selectedProject?.id || ''}/>\n          </div>\n        </div>\n      </div>) : !showMarketplace ? (<div className=\"signInStyle\">\n        <div className=\"signInTopBar\">\n          <div className=\"superAgiLogo\"><Image width={132} height={72} src=\"/images/sign-in-logo.svg\"\n                                               alt=\"super-agi-logo\"/></div>\n        </div>\n        <div className=\"signInCenter\">\n          {applicationState === 'NOT_AUTHENTICATED' && !showMarketplace ? <div className=\"signInWrapper\">\n            <button className=\"signInButton\" onClick={signInUser}>\n              <Image width={20} height={20} src=\"/images/github.svg\" alt=\"github\"/>&nbsp;Continue with Github\n            </button>\n            <div className=\"signInInfo\">\n              By continuing, you agree to Super AGI’s Terms of Service and Privacy Policy, and to receive important\n              updates.\n            </div>\n          </div> : <div className=\"signInWrapper\" style={{background: 'transparent'}}>\n            <div className=\"signInInfo\" style={{fontSize: '16px', fontFamily: 'Source Code Pro'}}>{loadingText}</div>\n          </div>}\n        </div>\n      </div>) : true}\n    </div>\n  );\n}"
  },
  {
    "path": "gui/pages/api/DashboardService.js",
    "content": "import api from './apiConfig';\n\nexport const getOrganisation = (userId) => {\n  return api.get(`/organisations/get/user/${userId}`);\n};\n\nexport const getGithubClientId = () => {\n  return api.get(`/get/github_client_id`);\n};\n\nexport const addUser = (userData) => {\n  return api.post(`/users/add`, userData);\n};\n\nexport const getProject = (organisationId) => {\n  return api.get(`/projects/get/organisation/${organisationId}`);\n};\n\nexport const getAgents = (projectId) => {\n  return api.get(`/agents/get/project/${projectId}`);\n};\n\nexport const getToolKit = () => {\n  return api.get(`/toolkits/get/local/list`);\n};\n\nexport const getTools = () => {\n  return api.get(`/tools/list`);\n};\n\nexport const getAgentDetails = (agentId, agentExecutionId) => {\n  return api.get(`/agent_executions_configs/details/agent_id/${agentId}/agent_execution_id/${agentExecutionId}`);\n};\n\nexport const getAgentExecutions = (agentId) => {\n  return api.get(`/agentexecutions/get/agent/${agentId}`);\n};\n\nexport const getExecutionFeeds = (executionId) => {\n  return api.get(`/agentexecutionfeeds/get/execution/${executionId}`);\n};\n\nexport const getExecutionTasks = (executionId) => {\n  return api.get(`/agentexecutionfeeds/get/tasks/${executionId}`);\n};\n\nexport const createAgent = (agentData, scheduledCreate) => {\n  return api.post(scheduledCreate ? `/agents/schedule` : `/agents/create`, agentData);\n};\n\nexport const addAgentRun = (agentData) => {\n  return api.post( `/agentexecutions/add_run`, agentData);\n};\n\nexport const addTool = (toolData) => {\n  return api.post(`/toolkits/get/local/install`, toolData);\n};\n\nexport const updateExecution = (executionId, executionData) => {\n  return api.put(`/agentexecutions/update/${executionId}`, executionData);\n};\n\nexport const editAgentTemplate = (agentTemplateId, agentTemplateData) => {\n  return api.put(`/agent_templates/update_agent_template/${agentTemplateId}`, agentTemplateData)\n};\n\nexport const addExecution = (executionData) => {\n  return api.post(`/agentexecutions/add`, executionData);\n};\n\nexport const getResources = (agentId) => {\n  return api.get(`/resources/get/all/${agentId}`);\n};\n\nexport const getLastActiveAgent = (projectId) => {\n  return api.get(`/agentexecutions/get/latest/agent/project/${projectId}`);\n};\n\nexport const uploadFile = (agentId, formData) => {\n  return api.post(`/resources/add/${agentId}`, formData);\n};\n\nexport const validateAccessToken = () => {\n  return api.get(`/validate-access-token`);\n};\n\nexport const validateLLMApiKey = (model_source, model_api_key) => {\n  return api.post(`/validate-llm-api-key`, {model_source, model_api_key});\n};\n\nexport const checkEnvironment = () => {\n  return api.get(`/configs/get/env`);\n};\n\nexport const getOrganisationConfig = (organisationId, key) => {\n  return api.get(`/configs/get/organisation/${organisationId}/key/${key}`);\n};\n\nexport const updateOrganisationConfig = (organisationId, configData) => {\n  return api.post(`/configs/add/organisation/${organisationId}`, configData);\n};\n\nexport const fetchAgentTemplateList = () => {\n  return api.get('/agent_templates/list?template_source=marketplace');\n};\n\nexport const fetchAgentTemplateDetails = (templateId) => {\n  return api.get(`/agent_templates/get/${templateId}`);\n};\n\nexport const getToolConfig = (toolKitName) => {\n  return api.get(`/tool_configs/get/toolkit/${toolKitName}`);\n};\n\nexport const updateToolConfig = (toolKitName, configData) => {\n  return api.post(`/tool_configs/add/${toolKitName}`, configData);\n};\n\nexport const fetchAgentTemplateListLocal = () => {\n  return api.get('/agent_templates/list?template_source=local');\n};\n\nexport const saveAgentAsTemplate = (agentId, executionId) => {\n  return api.post(`/agent_templates/save_agent_as_template/agent_id/${agentId}/agent_execution_id/${executionId}`);\n};\n\nexport const fetchAgentTemplateConfig = (templateId) => {\n  return api.get(`/agent_templates/get/${templateId}?template_source=marketplace`);\n};\n\nexport const installAgentTemplate = (templateId) => {\n  return api.post(`/agent_templates/download?agent_template_id=${templateId}`);\n};\n\nexport const fetchAgentTemplateConfigLocal = (templateId) => {\n  return api.get(`/agent_templates/agent_config?agent_template_id=${templateId}`);\n};\n\nexport const updatePermissions = (permissionId, data) => {\n  return api.put(`/agentexecutionpermissions/update/status/${permissionId}`, data)\n};\n\nexport const deleteAgent = (agentId) => {\n  return api.put(`/agents/delete/${agentId}`)\n};\n\nexport const authenticateGoogleCred = (toolKitId) => {\n  return api.get(`/google/get_google_creds/toolkit_id/${toolKitId}`);\n};\n\nexport const authenticateTwitterCred = (toolKitId) => {\n  return api.get(`/twitter/get_twitter_creds/toolkit_id/${toolKitId}`);\n};\n\nexport const sendTwitterCreds = (twitter_creds) => {\n  return api.post(`/twitter/send_twitter_creds/${twitter_creds}`);\n};\n\nexport const sendGoogleCreds = (google_creds, toolkit_id) => {\n  return api.post(`/google/send_google_creds/toolkit_id/${toolkit_id}`, google_creds);\n};\n\nexport const fetchToolTemplateList = () => {\n  return api.get(`/toolkits/get/list?page=0`);\n};\n\nexport const fetchKnowledgeTemplateList = () => {\n  return api.get(`/knowledges/get/list?page=0`);\n};\n\nexport const fetchToolTemplateOverview = (toolTemplateName) => {\n  return api.get(`/toolkits/marketplace/readme/${toolTemplateName}`);\n};\n\nexport const updateMarketplaceToolTemplate = (templateName) => {\n  return api.put(`/toolkits/update/${templateName}`);\n};\n\nexport const installToolkitTemplate = (templateName) => {\n  return api.get(`/toolkits/get/install/${templateName}`);\n};\n\nexport const checkToolkitUpdate = (templateName) => {\n  return api.get(`/toolkits/check_update/${templateName}`);\n};\n\nexport const getExecutionDetails = (executionId, agentId) => {\n  return api.get(`/agent_executions_configs/details/agent/${agentId}/agent_execution/${executionId}`);\n};\n\nexport const stopSchedule = (agentId) => {\n  return api.post(`/agents/stop/schedule?agent_id=${agentId}`);\n};\n\nexport const createAndScheduleRun = (requestData) => {\n  return api.post(`/agentexecutions/schedule`, requestData);\n};\n\nexport const agentScheduleComponent = (agentId) => {\n  return api.get(`/agents/get/schedule_data/${agentId}`);\n};\n\nexport const updateSchedule = (requestData) => {\n  return api.put(`/agents/edit/schedule`, requestData);\n};\n\nexport const getDateTime = (agentId) => {\n  return api.get(`/agents/get/schedule_data/${agentId}`);\n};\n\nexport const getMetrics = () => {\n  return api.get(`/analytics/metrics`)\n};\n\nexport const getAllAgents = () => {\n  return api.get(`/analytics/agents/all`)\n};\n\nexport const getAgentRuns = (agent_id) => {\n  return api.get(`analytics/agents/${agent_id}`);\n};\n\nexport const getActiveRuns = () => {\n  return api.get(`analytics/runs/active`);\n};\n\nexport const getToolsUsage = () => {\n  return api.get(`analytics/tools/used`);\n};\n\nexport const modelInfo = (model) => {\n  return api.get(`analytics/model_details/${model}`)\n}\n\nexport const getLlmModels = () => {\n  return api.get(`organisations/llm_models`);\n};\n\nexport const getAgentWorkflows = () => {\n  return api.get(`organisations/agent_workflows`);\n};\n\nexport const fetchVectorDBList = () => {\n  return api.get(`/vector_dbs/get/list`);\n};\n\nexport const getVectorDatabases = () => {\n  return api.get(`/vector_dbs/user/list`);\n};\n\nexport const getVectorDBDetails = (vectorDBId) => {\n  return api.get(`/vector_dbs/db/details/${vectorDBId}`);\n};\n\nexport const deleteVectorDB = (vectorDBId) => {\n  return api.post(`/vector_dbs/delete/${vectorDBId}`);\n};\n\nexport const updateVectorDB = (vectorDBId, newIndices) => {\n  return api.put(`/vector_dbs/update/vector_db/${vectorDBId}`, newIndices);\n};\n\nexport const connectPinecone = (pineconeData) => {\n  return api.post(`/vector_dbs/connect/pinecone`, pineconeData);\n};\n\nexport const connectQdrant = (qdrantData) => {\n  return api.post(`/vector_dbs/connect/qdrant`, qdrantData);\n};\n\nexport const connectWeaviate = (weaviateData) => {\n  return api.post(`/vector_dbs/connect/weaviate`, weaviateData);\n};\n\nexport const getKnowledge = () => {\n  return api.get(`/knowledges/user/list`);\n};\n\nexport const getKnowledgeDetails = (knowledgeId) => {\n  return api.get(`/knowledges/user/get/details/${knowledgeId}`);\n};\n\nexport const deleteCustomKnowledge = (knowledgeId) => {\n  return api.post(`/knowledges/delete/${knowledgeId}`);\n};\n\nexport const deleteMarketplaceKnowledge = (knowledgeName) => {\n  return api.post(`/knowledges/uninstall/${knowledgeName}`);\n};\n\nexport const addUpdateKnowledge = (knowledgeData) => {\n  return api.post(`/knowledges/add_or_update/data`, knowledgeData);\n};\n\nexport const getValidIndices = () => {\n  return api.get(`/vector_db_indices/user/valid_indices`);\n};\n\nexport const getValidMarketplaceIndices = (knowledgeName) => {\n  return api.get(`/vector_db_indices/marketplace/valid_indices/${knowledgeName}`);\n};\n\nexport const fetchKnowledgeTemplateOverview = (knowledgeName) => {\n  return api.get(`/knowledges/marketplace/get/details/${knowledgeName}`);\n};\n\nexport const installKnowledgeTemplate = (knowledgeName, indexId) => {\n  return api.get(`/knowledges/install/${knowledgeName}/index/${indexId}`);\n};\n\nexport const createApiKey = (apiName) => {\n  return api.post(`/api-keys`, apiName);\n};\n\nexport const getApiKeys = () => {\n  return api.get(`/api-keys`);\n};\n\nexport const editApiKey = (apiDetails) => {\n  return api.put(`/api-keys`, apiDetails);\n};\n\nexport const deleteApiKey = (apiId) => {\n  return api.delete(`/api-keys/${apiId}`);\n};\n\nexport const saveWebhook = (webhook) => {\n  return api.post(`/webhook/add`, webhook);\n};\n\nexport const getWebhook = () => {\n  return api.get(`/webhook/get`);\n};\n\nexport const editWebhook = (webhook_id, webook_data) => {\n  return api.post(`/webhook/edit/${webhook_id}`, webook_data);\n};\n\nexport const publishToMarketplace = (executionId) => {\n  return api.post(`/agent_templates/publish_template/agent_execution_id/${executionId}`);\n};\n\nexport const storeApiKey = (model_provider, model_api_key) => {\n  return api.post(`/models_controller/store_api_keys`, {model_provider, model_api_key});\n}\n\nexport const fetchApiKeys = () => {\n  return api.get(`/models_controller/get_api_keys`);\n}\n\nexport const fetchApiKey = (model_provider) => {\n  return api.get(`/models_controller/get_api_key?model_provider=${model_provider}`);\n}\n\nexport const verifyEndPoint = (model_api_key, end_point, model_provider) => {\n  return api.get(`/models_controller/verify_end_point`, {\n    params: { model_api_key, end_point, model_provider }\n  });\n}\n\nexport const storeModel = (model_name, description, end_point, model_provider_id, token_limit, type, version, context_length) => {\n  return api.post(`/models_controller/store_model`,{model_name, description, end_point, model_provider_id, token_limit, type, version, context_length});\n}\n\nexport const testModel = () => {\n  return api.get(`/models_controller/test_local_llm`);\n}\n\nexport const fetchModels = () => {\n  return api.get(`/models_controller/fetch_models`);\n}\n\nexport const fetchModel = (model_id) => {\n  return api.get(`/models_controller/fetch_model/${model_id}`);\n}\n\nexport const fetchModelData = (model) => {\n  return api.post(`/models_controller/fetch_model_data`, { model: model })\n}\n\nexport const fetchMarketPlaceModel = () => {\n  return api.get(`/models_controller/get/list`)\n}\n\nexport const getToolMetrics = (toolName) => {\n  return api.get(`analytics/tools/${toolName}/usage`)\n}\n\nexport const getToolLogs = (toolName) => {\n  return api.get(`analytics/tools/${toolName}/logs`)\n}\n\nexport const publishTemplateToMarketplace = (agentData) => {\n  return api.post(`/agent_templates/publish_template`, agentData);\n};\nexport const getKnowledgeMetrics = (knowledgeName) => {\n  return api.get(`analytics/knowledge/${knowledgeName}/usage`)\n}\n\nexport const getKnowledgeLogs = (knowledgeName) => {\n  return api.get(`analytics/knowledge/${knowledgeName}/logs`)\n}\n\nexport const getFirstSignup = (source) => {\n  return api.post(`/users/first_login_source/${source}`,);\n};"
  },
  {
    "path": "gui/pages/api/apiConfig.js",
    "content": "import axios from 'axios';\nimport Cookies from \"js-cookie\";\n\nconst GITHUB_CLIENT_ID = process.env.GITHUB_CLIENT_ID;\nconst API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:8001';\nconst GOOGLE_ANALYTICS_MEASUREMENT_ID =  process.env.GOOGLE_ANALYTICS_MEASUREMENT_ID;\nconst GOOGLE_ANALYTICS_API_SECRET =  process.env.GOOGLE_ANALYTICS_API_SECRET;\nconst MIXPANEL_AUTH_ID = process.env.NEXT_PUBLIC_MIXPANEL_AUTH_ID\n\nexport const baseUrl = () => {\n  return API_BASE_URL;\n};\n\nexport const githubClientId = () => {\n  return GITHUB_CLIENT_ID;\n};\n\nexport const analyticsMeasurementId = () => {\n  return GOOGLE_ANALYTICS_MEASUREMENT_ID;\n};\n\nexport const analyticsApiSecret = () => {\n  return GOOGLE_ANALYTICS_API_SECRET;\n};\n\nexport const mixpanelId = () => {\n  return MIXPANEL_AUTH_ID;\n};\n\nconst api = axios.create({\n  baseURL: API_BASE_URL,\n  headers: {\n    common: {\n      'Content-Type': 'application/json',\n    },\n  },\n});\n\napi.interceptors.request.use(config => {\n  if (typeof window !== 'undefined') {\n    // const accessToken = localStorage.getItem(\"accessToken\");\n    const accessToken = Cookies.get(\"accessToken\");\n    if (accessToken) {\n      config.headers['Authorization'] = `Bearer ${accessToken}`;\n    }\n  }\n  return config;\n});\n\nexport default api;\n"
  },
  {
    "path": "gui/utils/eventBus.js",
    "content": "import mitt from 'mitt';\n\nconst emitter = mitt();\n\nexport const EventBus = {\n  on: emitter.on,\n  off: emitter.off,\n  emit: emitter.emit,\n};\n"
  },
  {
    "path": "gui/utils/utils.js",
    "content": "import {formatDistanceToNow, format, addMinutes} from 'date-fns';\nimport {utcToZonedTime} from 'date-fns-tz';\nimport {baseUrl, analyticsMeasurementId, analyticsApiSecret, mixpanelId} from \"@/pages/api/apiConfig\";\nimport {EventBus} from \"@/utils/eventBus\";\nimport JSZip from \"jszip\";\nimport moment from 'moment';\nimport mixpanel from 'mixpanel-browser'\nimport Cookies from \"js-cookie\";\n\nconst toolkitData = {\n  'Jira Toolkit': '/images/jira_icon.svg',\n  'Email Toolkit': '/images/gmail_icon.svg',\n  'Google Calendar Toolkit': '/images/google_calender_icon.svg',\n  'GitHub Toolkit': '/images/github_icon.svg',\n  'Google Search Toolkit': '/images/google_search_icon.svg',\n  'Searx Toolkit': '/images/searx_icon.svg',\n  'Slack Toolkit': '/images/slack_icon.svg',\n  'Web Scraper Toolkit': '/images/webscraper_icon.svg',\n  'Web Scrapper Toolkit': '/images/webscraper_icon.svg',\n  'Twitter Toolkit': '/images/twitter_icon.svg',\n  'Google SERP Toolkit': '/images/google_serp_icon.svg',\n  'File Toolkit': '/images/filemanager_icon.svg',\n  'CodingToolkit': '/images/superagi_logo.png',\n  'Thinking Toolkit': '/images/superagi_logo.png',\n  'Image Generation Toolkit': '/images/superagi_logo.png',\n  'DuckDuckGo Search Toolkit': '/images/duckduckgo_icon.png',\n  'Instagram Toolkit': '/images/instagram.png',\n  'Knowledge Search Toolkit': '/images/knowledeg_logo.png',\n  'Notion Toolkit': '/images/notion_logo.png',\n  'ApolloToolkit': '/images/apollo_logo.png',\n  'Google Analytics Toolkit': '/images/google_analytics_logo.png'\n};\n\nexport const getUserTimezone = () => {\n  return Intl.DateTimeFormat().resolvedOptions().timeZone;\n}\n\nexport const convertToGMT = (dateTime) => {\n  if (!dateTime) {\n    return null;\n  }\n  return moment.utc(dateTime).format('YYYY-MM-DD HH:mm:ss');\n};\n\nexport const formatTimeDifference = (timeDifference) => {\n  const units = ['years', 'months', 'days', 'hours', 'minutes'];\n  const singularUnits = ['year', 'month', 'day', 'hour', 'minute'];\n\n  for (let i = 0; i < units.length; i++) {\n    const unit = units[i];\n    if (timeDifference[unit] !== 0) {\n      if (unit === 'minutes') {\n        return `${timeDifference[unit]} ${timeDifference[unit] === 1 ? singularUnits[i] : unit} ago`;\n      } else {\n        return `${timeDifference[unit]} ${timeDifference[unit] === 1 ? singularUnits[i] : unit} ago`;\n      }\n    }\n  }\n\n  return 'Just now';\n};\n\nexport const formatNumber = (number) => {\n  if (number === null || number === undefined || number === 0) {\n    return '0';\n  }\n\n  const suffixes = ['', 'k', 'M', 'B', 'T'];\n  const magnitude = Math.floor(Math.log10(number) / 3);\n  const scaledNumber = number / Math.pow(10, magnitude * 3);\n  const suffix = suffixes[magnitude];\n\n  if (scaledNumber % 1 === 0) {\n    return scaledNumber.toFixed(0) + suffix;\n  }\n\n  return scaledNumber.toFixed(1) + suffix;\n};\n\nexport const formatTime = (lastExecutionTime) => {\n  try {\n    const parsedTime = new Date(lastExecutionTime + 'Z'); // append 'Z' to indicate UTC\n    if (isNaN(parsedTime.getTime())) {\n      throw new Error('Invalid time value');\n    }\n\n    const timeZone = 'Asia/Kolkata';\n    const zonedTime = utcToZonedTime(parsedTime, timeZone);\n\n    return formatDistanceToNow(zonedTime, {\n      addSuffix: true,\n      includeSeconds: true\n    }).replace(/about\\s/, '')\n      .replace(/minutes?/, 'min')\n      .replace(/hours?/, 'hrs')\n      .replace(/days?/, 'day')\n      .replace(/weeks?/, 'week');\n  } catch (error) {\n    console.error('Error formatting time:', error);\n    return 'Invalid Time';\n  }\n};\n\nexport const formatBytes = (bytes, decimals = 2) => {\n  if (bytes === 0) {\n    return '0 Bytes';\n  }\n\n  const k = 1024;\n  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];\n  const i = Math.floor(Math.log(bytes) / Math.log(k));\n  const formattedValue = parseFloat((bytes / Math.pow(k, i)).toFixed(decimals));\n\n  return `${formattedValue} ${sizes[i]}`;\n};\n\nexport const downloadFile = (fileId, fileName = null) => {\n  // const authToken = localStorage.getItem('accessToken');\n  const authToken = Cookies.get(\"accessToken\");\n  const url = `${baseUrl()}/resources/get/${fileId}`;\n  const env = localStorage.getItem('applicationEnvironment');\n\n  if (env === 'PROD') {\n    const headers = {\n      Authorization: `Bearer ${authToken}`,\n    };\n\n    return fetch(url, {headers})\n      .then((response) => response.blob())\n      .then((blob) => {\n        if (fileName) {\n          const fileUrl = window.URL.createObjectURL(blob);\n          const anchorElement = document.createElement('a');\n          anchorElement.href = fileUrl;\n          anchorElement.download = fileName;\n          anchorElement.click();\n          window.URL.revokeObjectURL(fileUrl);\n        } else {\n          return blob;\n        }\n      })\n      .catch((error) => {\n        console.error('Error downloading file:', error);\n      });\n  } else {\n    if (fileName) {\n      window.open(url, '_blank');\n    } else {\n      return fetch(url)\n        .then((response) => response.blob())\n        .catch((error) => {\n          console.error('Error downloading file:', error);\n        });\n    }\n  }\n};\n\nexport const downloadAllFiles = (files, run_name) => {\n  const zip = new JSZip();\n  const promises = [];\n  const fileNamesCount = {};\n\n  files.forEach((file, index) => {\n    fileNamesCount[file.name]\n      ? fileNamesCount[file.name]++\n      : (fileNamesCount[file.name] = 1);\n\n    let modifiedFileName = file.name;\n    if (fileNamesCount[file.name] > 1) {\n      const fileExtensionIndex = file.name.lastIndexOf(\".\");\n      const name = file.name.substring(0, fileExtensionIndex);\n      const extension = file.name.substring(fileExtensionIndex + 1);\n      modifiedFileName = `${name} (${fileNamesCount[file.name] - 1}).${extension}`;\n    }\n\n    const promise = downloadFile(file.id)\n      .then((blob) => {\n        const fileBlob = new Blob([blob], {type: file.type});\n        zip.file(modifiedFileName, fileBlob);\n      })\n      .catch((error) => {\n        console.error(\"Error downloading file:\", error);\n      });\n\n    promises.push(promise);\n  });\n\n  Promise.all(promises)\n    .then(() => {\n      zip.generateAsync({type: \"blob\"})\n        .then((content) => {\n          const now = new Date();\n          const timestamp = `${now.getFullYear()}-${(\"0\" + (now.getMonth() + 1)).slice(-2)}-${(\"0\" + now.getDate()).slice(-2)}_${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`.replace(/:/g, '-');\n          const zipFilename = `${run_name}_${timestamp}.zip`;\n          const downloadLink = document.createElement(\"a\");\n          downloadLink.href = URL.createObjectURL(content);\n          downloadLink.download = zipFilename;\n          downloadLink.click();\n        })\n        .catch((error) => {\n          console.error(\"Error generating zip:\", error);\n        });\n    });\n};\n\nexport const refreshUrl = () => {\n  if (typeof window === 'undefined') {\n    return;\n  }\n\n  const {origin, pathname} = window.location;\n  const urlWithoutToken = origin + pathname;\n  window.history.replaceState({}, document.title, urlWithoutToken);\n};\n\nexport const loadingTextEffect = (loadingText, setLoadingText, timer) => {\n  const text = loadingText;\n  let dots = '';\n\n  const interval = setInterval(() => {\n    dots = dots.length < 3 ? dots + '.' : '';\n    setLoadingText(`${text}${dots}`);\n  }, timer);\n\n  return () => clearInterval(interval)\n};\n\nexport const openNewTab = (id, name, contentType, hasInternalId = false) => {\n  EventBus.emit('openNewTab', {\n    element: {id: id, name: name, contentType: contentType, internalId: hasInternalId ? createInternalId() : 0}\n  });\n};\n\nexport const removeTab = (id, name, contentType, internalId) => {\n  EventBus.emit('removeTab', {\n    element: {id: id, name: name, contentType: contentType, internalId: internalId}\n  });\n};\n\nexport const setLocalStorageValue = (key, value, stateFunction) => {\n  stateFunction(value);\n  localStorage.setItem(key, value);\n};\n\nexport const setLocalStorageArray = (key, value, stateFunction) => {\n  stateFunction(value);\n  const arrayString = JSON.stringify(value);\n  localStorage.setItem(key, arrayString);\n};\n\nconst getInternalIds = () => {\n  const internal_ids = localStorage.getItem(\"agi_internal_ids\");\n  return internal_ids ? JSON.parse(internal_ids) : [];\n};\n\nconst removeAgentInternalId = (internalId) => {\n  let idsArray = getInternalIds();\n  const internalIdIndex = idsArray.indexOf(internalId);\n\n  if (internalIdIndex !== -1) {\n    idsArray.splice(internalIdIndex, 1);\n    localStorage.setItem('agi_internal_ids', JSON.stringify(idsArray));\n    localStorage.removeItem(\"agent_create_click_\" + String(internalId));\n    localStorage.removeItem(\"agent_name_\" + String(internalId));\n    localStorage.removeItem(\"agent_description_\" + String(internalId));\n    localStorage.removeItem(\"agent_goals_\" + String(internalId));\n    localStorage.removeItem(\"agent_instructions_\" + String(internalId));\n    localStorage.removeItem(\"agent_constraints_\" + String(internalId));\n    localStorage.removeItem(\"agent_model_\" + String(internalId));\n    localStorage.removeItem(\"agent_type_\" + String(internalId));\n    localStorage.removeItem(\"tool_names_\" + String(internalId));\n    localStorage.removeItem(\"tool_ids_\" + String(internalId));\n    localStorage.removeItem(\"agent_rolling_window_\" + String(internalId));\n    localStorage.removeItem(\"agent_database_\" + String(internalId));\n    localStorage.removeItem(\"agent_permission_\" + String(internalId));\n    localStorage.removeItem(\"agent_exit_criterion_\" + String(internalId));\n    localStorage.removeItem(\"agent_iterations_\" + String(internalId));\n    localStorage.removeItem(\"agent_step_time_\" + String(internalId));\n    localStorage.removeItem(\"advanced_options_\" + String(internalId));\n    localStorage.removeItem(\"has_LTM_\" + String(internalId));\n    localStorage.removeItem(\"has_resource_\" + String(internalId));\n    localStorage.removeItem(\"agent_files_\" + String(internalId));\n    localStorage.removeItem(\"agent_start_time_\" + String(internalId));\n    localStorage.removeItem(\"agent_expiry_date_\" + String(internalId));\n    localStorage.removeItem(\"agent_expiry_type_\" + String(internalId));\n    localStorage.removeItem(\"agent_expiry_runs_\" + String(internalId));\n    localStorage.removeItem(\"agent_time_unit_\" + String(internalId));\n    localStorage.removeItem(\"agent_time_value_\" + String(internalId));\n    localStorage.removeItem(\"agent_is_recurring_\" + String(internalId));\n    localStorage.removeItem(\"is_agent_template_\" + String(internalId));\n    localStorage.removeItem(\"agent_template_id_\" + String(internalId));\n    localStorage.removeItem(\"agent_knowledge_\" + String(internalId));\n    localStorage.removeItem(\"agent_knowledge_id_\" + String(internalId));\n    localStorage.removeItem(\"is_editing_agent_\" + String(internalId));\n  }\n};\n\nconst removeAddToolkitInternalId = (internalId) => {\n  let idsArray = getInternalIds();\n  const internalIdIndex = idsArray.indexOf(internalId);\n\n  if (internalIdIndex !== -1) {\n    idsArray.splice(internalIdIndex, 1);\n    localStorage.setItem('agi_internal_ids', JSON.stringify(idsArray));\n    localStorage.removeItem('tool_github_' + String(internalId));\n  }\n};\n\nconst removeToolkitsInternalId = (internalId) => {\n  let idsArray = getInternalIds();\n  const internalIdIndex = idsArray.indexOf(internalId);\n\n  if (internalIdIndex !== -1) {\n    idsArray.splice(internalIdIndex, 1);\n    localStorage.setItem('agi_internal_ids', JSON.stringify(idsArray));\n    localStorage.removeItem('toolkit_tab_' + String(internalId));\n    localStorage.removeItem('api_configs_' + String(internalId));\n  }\n};\n\nconst removeKnowledgeInternalId = (internalId) => {\n  let idsArray = getInternalIds();\n  const internalIdIndex = idsArray.indexOf(internalId);\n\n  if (internalIdIndex !== -1) {\n    idsArray.splice(internalIdIndex, 1);\n    localStorage.setItem('agi_internal_ids', JSON.stringify(idsArray));\n    localStorage.removeItem('knowledge_name_' + String(internalId));\n    localStorage.removeItem('knowledge_description_' + String(internalId));\n    localStorage.removeItem('knowledge_index_' + String(internalId));\n  }\n}\n\nconst removeAddDatabaseInternalId = (internalId) => {\n  let idsArray = getInternalIds();\n  const internalIdIndex = idsArray.indexOf(internalId);\n\n  if (internalIdIndex !== -1) {\n    idsArray.splice(internalIdIndex, 1);\n    localStorage.setItem('agi_internal_ids', JSON.stringify(idsArray));\n    localStorage.removeItem('add_database_tab_' + String(internalId));\n    localStorage.removeItem('selected_db_' + String(internalId));\n    localStorage.removeItem('db_name_' + String(internalId));\n    localStorage.removeItem('db_collections_' + String(internalId));\n    localStorage.removeItem('pincone_api_' + String(internalId));\n    localStorage.removeItem('pinecone_env_' + String(internalId));\n    localStorage.removeItem('qdrant_api_' + String(internalId));\n    localStorage.removeItem('qdrant_url_' + String(internalId));\n    localStorage.removeItem('qdrant_port_' + String(internalId));\n  }\n}\n\nconst removeDatabaseInternalId = (internalId) => {\n  let idsArray = getInternalIds();\n  const internalIdIndex = idsArray.indexOf(internalId);\n\n  if (internalIdIndex !== -1) {\n    idsArray.splice(internalIdIndex, 1);\n    localStorage.setItem('agi_internal_ids', JSON.stringify(idsArray));\n    localStorage.removeItem('db_details_collections_' + String(internalId));\n  }\n}\n\nexport const resetLocalStorage = (contentType, internalId) => {\n  switch (contentType) {\n    case 'Create_Agent':\n      removeAgentInternalId(internalId);\n      break;\n    case 'Add_Toolkit':\n      removeAddToolkitInternalId(internalId);\n      break;\n    case 'Marketplace':\n      localStorage.removeItem('marketplace_tab');\n      localStorage.removeItem('market_item_clicked');\n      localStorage.removeItem('market_detail_type');\n      localStorage.removeItem('market_item');\n      break;\n    case 'Toolkits':\n      removeToolkitsInternalId(internalId);\n      break;\n    case 'Knowledge':\n      removeKnowledgeInternalId(internalId);\n      break;\n    case 'Add_Knowledge':\n      removeKnowledgeInternalId(internalId);\n      break;\n    case 'Add_Database':\n      removeAddDatabaseInternalId(internalId);\n      break;\n    case 'Database':\n      removeDatabaseInternalId(internalId);\n      break;\n    case 'Settings':\n      localStorage.removeItem('settings_tab');\n      break;\n    default:\n      break;\n  }\n};\n\nexport const createInternalId = () => {\n  let newId = 1;\n\n  if (typeof window !== 'undefined') {\n    let idsArray = getInternalIds();\n    let found = false;\n\n    for (let i = 1; !found; i++) {\n      if (!idsArray.includes(i)) {\n        newId = i;\n        found = true;\n      }\n    }\n\n    idsArray.push(newId);\n    localStorage.setItem('agi_internal_ids', JSON.stringify(idsArray));\n  }\n\n  return newId;\n};\n\nexport const returnToolkitIcon = (toolkitName) => {\n  return toolkitData[toolkitName] || '/images/custom_tool.svg';\n};\n\nexport const returnResourceIcon = (file) => {\n  const fileType = file.type;\n\n  switch (true) {\n    case fileType.includes('image'):\n      return '/images/img_file.svg';\n    case fileType === 'application/pdf':\n      return '/images/pdf_file.svg';\n    case fileType === 'application/txt' || fileType === 'text/plain':\n      return '/images/txt_file.svg';\n    default:\n      return '/images/default_file.svg';\n  }\n};\n\nexport const returnDatabaseIcon = (database) => {\n  const dbTypeIcons = {\n    'Pinecone': '/images/pinecone.svg',\n    'Qdrant': '/images/qdrant.svg',\n    'Weaviate' : '/images/weaviate.svg'\n  };\n\n  return dbTypeIcons[database]\n};\n\nexport const convertToTitleCase = (str) => {\n  if (!str) {\n    return '';\n  }\n\n  const words = str.toLowerCase().split('_');\n  const capitalizedWords = words.map((word) => word.charAt(0).toUpperCase() + word.slice(1));\n  return capitalizedWords.join(' ');\n};\n\nexport const preventDefault = (e) => {\n  e.stopPropagation();\n};\n\nexport const excludedToolkits = () => {\n  return [\"Thinking Toolkit\", \"Human Input Toolkit\", \"Resource Toolkit\"];\n}\n\nexport const getFormattedDate = (data) => {\n  let date = new Date(data);\n  const year = date.getFullYear();\n  const day = date.getDate();\n  const months = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"];\n  const month = months[date.getMonth()];\n  return `${day} ${month} ${year}`;\n}\n\nexport const modelIcon = (model) => {\n  const icons = {\n    'Hugging Face': '/images/huggingface_logo.svg',\n    'Google Palm': '/images/google_palm_logo.svg',\n    'Replicate': '/images/replicate_logo.svg',\n    'OpenAI': '/images/openai_logo.svg',\n  }\n\n  return icons[model];\n}\n\nexport const modelGetAuth = (modelProvider) => {\n  const externalLinks = {\n    'Replicate': 'https://replicate.com/account/api-tokens',\n    'Hugging Face': 'https://huggingface.co/settings/tokens',\n    'OpenAI': 'https://platform.openai.com/account/api-keys',\n    'Google Palm': 'https://developers.generativeai.google/products/palm',\n  }\n\n  return externalLinks[modelProvider]\n}\n\nexport const formatDateTime = (dateTimeString) => {\n  const date = new Date(dateTimeString);\n  const adjustedDate = addMinutes(addMinutes(date, 5 * 60), 30);\n  const formattedDate = format(adjustedDate, 'd MMM yyyy HH:mm');\n\n  return formattedDate;\n};\n\nexport const convertWaitingPeriod = (waitingPeriod) => {\n  let convertedValue = waitingPeriod;\n  let unit = 'seconds';\n\n  if (convertedValue >= 60 && convertedValue < 3600) {\n    convertedValue = Math.floor(convertedValue / 60);\n    unit = 'minutes';\n  } else if (convertedValue >= 3600 && convertedValue < 86400) {\n    convertedValue = Math.floor(convertedValue / 3600);\n    unit = 'hours';\n  } else if (convertedValue >= 86400 && convertedValue < 604800) {\n    convertedValue = Math.floor(convertedValue / 86400);\n    unit = 'days';\n  } else if (convertedValue >= 604800) {\n    convertedValue = Math.floor(convertedValue / 604800);\n    unit = 'weeks';\n  }\n\n  return convertedValue + ' ' + unit;\n}\n\nexport const getUTMParametersFromURL = () => {\n  const params = new URLSearchParams(window.location.search);\n\n  const utmParams = {\n    utm_source: params.get('utm_source') || '',\n    utm_medium: params.get('utm_medium') || '',\n    utm_campaign: params.get('utm_campaign') || '',\n  };\n\n  if (!utmParams.utm_source && !utmParams.utm_medium && !utmParams.utm_campaign) {\n    return null;\n  }\n\n  return utmParams;\n}\n\nexport const getUserClick = (event, props) => {\n  const env = localStorage.getItem('applicationEnvironment');\n  if(env === 'PROD' && mixpanelId()){\n    mixpanel.track(event, props)\n  }\n}\n\nexport const sendGAEvent = async (client, eventName, params) => {\n  const measurement_id = analyticsMeasurementId();\n  const api_secret = analyticsApiSecret();\n  await fetch(`https://www.google-analytics.com/mp/collect?measurement_id=${measurement_id}&api_secret=${api_secret}`, {\n    method: \"POST\",\n    body: JSON.stringify({\n      client_id: client,\n      events: [{\n        name: eventName,\n        params: params\n      }]\n    })\n  });\n}"
  },
  {
    "path": "install_tool_dependencies.sh",
    "content": "#!/bin/bash\n\n# Update and upgrade apt settings and apps\napt update && apt upgrade -y\nxargs apt install -y < /app/requirements_apt.txt\n\n# Run the project's main requirements.txt\npip install -r /app/requirements.txt\n\nfor tool in /app/superagi/tools/* /app/superagi/tools/external_tools/* /app/superagi/tools/marketplace_tools/* ; do\n# Loop through the tools directories and install their apt_requirements.txt if they exist\n  if [ -d \"$tool\" ] && [ -f \"$tool/requirements_apt.txt\" ]; then\n    echo \"Installing apt requirements for tool: $(basename \"$tool\")\"\n    xargs apt install -y < \"$tool/requirements_apt.txt\"\n  fi\n# Loop through the tools directories and install their requirements.txt if they exist\n  if [ -d \"$tool\" ] && [ -f \"$tool/requirements.txt\" ]; then\n    echo \"Installing requirements for tool: $(basename \"$tool\")\"\n    pip install -r \"$tool/requirements.txt\"\n  fi\ndone\n"
  },
  {
    "path": "local-llm",
    "content": "version: '3.8'\n\nservices:\n  backend:\n    volumes:\n      - \"./:/app\"\n    build: .\n    ports:\n      - \"8001:8001\"\n    depends_on:\n      - super__tgwui\n      - super__redis\n      - super__postgres\n    networks:\n      - super_network\n\n  celery:\n    volumes:\n      - \"./:/app\"\n    build:\n      context: .\n      dockerfile: DockerfileCelery\n    depends_on:\n      - super__tgwui\n      - super__redis\n      - super__postgres\n    networks:\n      - super_network\n    \n  gui:\n    build: ./gui\n    ports:\n      - \"3000:3000\"\n    environment:\n      - NEXT_PUBLIC_API_BASE_URL=http://localhost:8001\n    networks:\n      - super_network\n    volumes:\n      - ./gui:/app\n      - /app/node_modules\n      - /app/.next\n\n  super__tgwui:\n    build:\n      context: .\n      dockerfile: ./tgwui/DockerfileTGWUI\n    container_name: super__tgwui\n    environment:\n      - EXTRA_LAUNCH_ARGS=\"--listen --verbose --extensions openai --threads 4 --n_ctx 1600\"\n    ports:\n      - 7860:7860  # Default web port\n      - 5000:5000  # Default API port\n      - 5005:5005  # Default streaming port\n      - 5001:5001  # Default OpenAI API extension port\n    volumes:\n      - ./tgwui/config/loras:/app/loras\n      - ./tgwui/config/models:/app/models\n      - ./tgwui/config/presets:/app/presets\n      - ./tgwui/config/prompts:/app/prompts\n      - ./tgwui/config/softprompts:/app/softprompts\n      - ./tgwui/config/training:/app/training\n    logging:\n      driver:  json-file\n      options:\n        max-file: \"3\"   # number of files or file count\n        max-size: '10m'\n    networks:\n      - super_network\n\n  super__redis:\n    image: \"docker.io/library/redis:latest\"\n    networks:\n      - super_network\n\n  super__postgres:\n    image: \"docker.io/library/postgres:latest\"\n    environment:\n      - POSTGRES_USER=superagi\n      - POSTGRES_PASSWORD=password\n      - POSTGRES_DB=super_agi_main\n    volumes:\n      - superagi_postgres_data:/var/lib/postgresql/data/\n    networks:\n      - super_network\n    ports:\n      - \"5432:5432\"\n\nnetworks:\n  super_network:\n    driver: bridge\n\nvolumes:\n  superagi_postgres_data:\n"
  },
  {
    "path": "local-llm-gpu",
    "content": "version: '3.8'\n\nservices:\n  backend:\n    volumes:\n      - \"./:/app\"\n    build: .\n    ports:\n      - \"8001:8001\"\n    depends_on:\n      - super__tgwui\n      - super__redis\n      - super__postgres\n    networks:\n      - super_network\n\n  celery:\n    volumes:\n      - \"./:/app\"\n    build:\n      context: .\n      dockerfile: DockerfileCelery\n    depends_on:\n      - super__tgwui\n      - super__redis\n      - super__postgres\n    networks:\n      - super_network\n    \n  gui:\n    build: ./gui\n    ports:\n      - \"3000:3000\"\n    environment:\n      - NEXT_PUBLIC_API_BASE_URL=http://localhost:8001\n    networks:\n      - super_network\n    volumes:\n      - ./gui:/app\n      - /app/node_modules\n      - /app/.next\n\n  super__tgwui:\n    build:\n      context: ./tgwui/\n      target: llama-cublas\n      dockerfile: DockerfileTGWUI\n#      args:\n#        - LCL_SRC_DIR=text-generation-webui  # Developers - see Dockerfile app_base\n    image: atinoda/text-generation-webui:llama-cublas # Specify variant as the :tag\n    container_name: super__tgwui\n    environment:\n      - EXTRA_LAUNCH_ARGS=\"--no-mmap --verbose --extensions openai --auto-devices --n_ctx 2000 --gpu-memory 22 22 --n-gpu-layers 128 --threads 8\"\n#      - BUILD_EXTENSIONS_LIVE=\"silero_tts whisper_stt\" # Install named extensions during every container launch. THIS WILL SIGNIFICANLTLY SLOW LAUNCH TIME.\n    ports:\n      - 7860:7860  # Default web port\n      - 5000:5000  # Default API port\n      - 5005:5005  # Default streaming port\n      - 5001:5001  # Default OpenAI API extension port\n    volumes:\n      - ./tgwui/config/loras:/app/loras\n      - ./tgwui/config/models:/app/models\n      - ./tgwui/config/presets:/app/presets\n      - ./tgwui/config/prompts:/app/prompts\n      - ./tgwui/config/softprompts:/app/softprompts\n      - ./tgwui/config/training:/app/training\n#      - ./config/extensions:/app/extensions\n    logging:\n      driver:  json-file\n      options:\n        max-file: \"3\"   # number of files or file count\n        max-size: '10m'\n    networks:\n      - super_network\n    deploy:\n        resources:\n          reservations:\n            devices:\n              - driver: nvidia\n#                count: \"all\"\n                device_ids: ['0', '1'] # must comment the above line if this line is uncommented.\n                capabilities: [gpu]\n  super__redis:\n    image: \"docker.io/library/redis:latest\"\n    networks:\n      - super_network\n\n  super__postgres:\n    image: \"docker.io/library/postgres:latest\"\n    environment:\n      - POSTGRES_USER=superagi\n      - POSTGRES_PASSWORD=password\n      - POSTGRES_DB=super_agi_main\n    volumes:\n      - superagi_postgres_data:/var/lib/postgresql/data/\n    networks:\n      - super_network\n    ports:\n      - \"5432:5432\"\n\nnetworks:\n  super_network:\n    driver: bridge\n\nvolumes:\n  superagi_postgres_data:\n"
  },
  {
    "path": "main.py",
    "content": "import requests\nfrom fastapi import FastAPI, HTTPException, Depends, Request, status, Query\nfrom fastapi.middleware.cors import CORSMiddleware\nfrom fastapi.responses import JSONResponse\nfrom fastapi.responses import RedirectResponse\nfrom fastapi_jwt_auth import AuthJWT\nfrom fastapi_jwt_auth.exceptions import AuthJWTException\nfrom fastapi_sqlalchemy import DBSessionMiddleware, db\nfrom pydantic import BaseModel\nfrom sqlalchemy import create_engine\nfrom sqlalchemy.orm import sessionmaker\n\nimport superagi\nfrom datetime import timedelta, datetime\nfrom superagi.agent.workflow_seed import IterationWorkflowSeed, AgentWorkflowSeed\nfrom superagi.config.config import get_config\nfrom superagi.controllers.agent import router as agent_router\nfrom superagi.controllers.agent_execution import router as agent_execution_router\nfrom superagi.controllers.agent_execution_feed import router as agent_execution_feed_router\nfrom superagi.controllers.agent_execution_permission import router as agent_execution_permission_router\nfrom superagi.controllers.agent_template import router as agent_template_router\nfrom superagi.controllers.agent_workflow import router as agent_workflow_router\nfrom superagi.controllers.budget import router as budget_router\nfrom superagi.controllers.config import router as config_router\nfrom superagi.controllers.organisation import router as organisation_router\nfrom superagi.controllers.project import router as project_router\nfrom superagi.controllers.twitter_oauth import router as twitter_oauth_router\nfrom superagi.controllers.google_oauth import router as google_oauth_router\nfrom superagi.controllers.resources import router as resources_router\nfrom superagi.controllers.tool import router as tool_router\nfrom superagi.controllers.tool_config import router as tool_config_router\nfrom superagi.controllers.toolkit import router as toolkit_router\nfrom superagi.controllers.user import router as user_router\nfrom superagi.controllers.agent_execution_config import router as agent_execution_config\nfrom superagi.controllers.analytics import router as analytics_router\nfrom superagi.controllers.models_controller import router as models_controller_router\nfrom superagi.controllers.knowledges import router as knowledges_router\nfrom superagi.controllers.knowledge_configs import router as knowledge_configs_router\nfrom superagi.controllers.vector_dbs import router as vector_dbs_router\nfrom superagi.controllers.vector_db_indices import router as vector_db_indices_router\nfrom superagi.controllers.marketplace_stats import router as marketplace_stats_router\nfrom superagi.controllers.api_key import router as api_key_router\nfrom superagi.controllers.api.agent import router as api_agent_router\nfrom superagi.controllers.webhook import router as web_hook_router\nfrom superagi.helper.tool_helper import register_toolkits, register_marketplace_toolkits\nfrom superagi.lib.logger import logger\nfrom superagi.llms.google_palm import GooglePalm\nfrom superagi.llms.llm_model_factory import build_model_with_api_key\nfrom superagi.llms.openai import OpenAi\nfrom superagi.llms.replicate import Replicate\nfrom superagi.llms.hugging_face import HuggingFace\nfrom superagi.models.agent_template import AgentTemplate\nfrom superagi.models.models_config import ModelsConfig\nfrom superagi.models.organisation import Organisation\nfrom superagi.models.types.login_request import LoginRequest\nfrom superagi.models.types.validate_llm_api_key_request import ValidateAPIKeyRequest\nfrom superagi.models.user import User\nfrom superagi.models.workflows.agent_workflow import AgentWorkflow\nfrom superagi.models.workflows.iteration_workflow import IterationWorkflow\nfrom superagi.models.workflows.iteration_workflow_step import IterationWorkflowStep\nfrom urllib.parse import urlparse\napp = FastAPI()\n\ndb_host = get_config('DB_HOST', 'super__postgres')\ndb_url = get_config('DB_URL', None)\ndb_username = get_config('DB_USERNAME')\ndb_password = get_config('DB_PASSWORD')\ndb_name = get_config('DB_NAME')\nenv = get_config('ENV', \"DEV\")\n\nif db_url is None:\n    if db_username is None:\n        db_url = f'postgresql://{db_host}/{db_name}'\n    else:\n        db_url = f'postgresql://{db_username}:{db_password}@{db_host}/{db_name}'\nelse:\n    db_url = urlparse(db_url)\n    db_url = db_url.scheme + \"://\" + db_url.netloc + db_url.path\n\nengine = create_engine(db_url,\n                       pool_size=20,  # Maximum number of database connections in the pool\n                       max_overflow=50,  # Maximum number of connections that can be created beyond the pool_size\n                       pool_timeout=30,  # Timeout value in seconds for acquiring a connection from the pool\n                       pool_recycle=1800,  # Recycle connections after this number of seconds (optional)\n                       pool_pre_ping=False,  # Enable connection health checks (optional)\n                       )\n\n# app.add_middleware(DBSessionMiddleware, db_url=f'postgresql://{db_username}:{db_password}@localhost/{db_name}')\napp.add_middleware(DBSessionMiddleware, db_url=db_url)\n\n# Configure CORS middleware\norigins = [\n    # Add more origins if needed\n    \"*\",  # Allow all origins\n]\n\napp.add_middleware(\n    CORSMiddleware,\n    allow_origins=[\"*\"],\n    allow_methods=[\"*\"],\n    allow_headers=[\"*\"],\n)\n\n# Creating requrired tables -- Now handled using migrations\n# DBBaseModel.metadata.create_all(bind=engine, checkfirst=True)\n# DBBaseModel.metadata.drop_all(bind=engine,checkfirst=True)\n\n\napp.include_router(user_router, prefix=\"/users\")\napp.include_router(tool_router, prefix=\"/tools\")\napp.include_router(organisation_router, prefix=\"/organisations\")\napp.include_router(project_router, prefix=\"/projects\")\napp.include_router(budget_router, prefix=\"/budgets\")\napp.include_router(agent_router, prefix=\"/agents\")\napp.include_router(agent_execution_router, prefix=\"/agentexecutions\")\napp.include_router(agent_execution_feed_router, prefix=\"/agentexecutionfeeds\")\napp.include_router(agent_execution_permission_router, prefix=\"/agentexecutionpermissions\")\napp.include_router(resources_router, prefix=\"/resources\")\napp.include_router(config_router, prefix=\"/configs\")\napp.include_router(toolkit_router, prefix=\"/toolkits\")\napp.include_router(tool_config_router, prefix=\"/tool_configs\")\napp.include_router(config_router, prefix=\"/configs\")\napp.include_router(agent_template_router, prefix=\"/agent_templates\")\napp.include_router(agent_workflow_router, prefix=\"/agent_workflows\")\napp.include_router(twitter_oauth_router, prefix=\"/twitter\")\napp.include_router(agent_execution_config, prefix=\"/agent_executions_configs\")\napp.include_router(analytics_router, prefix=\"/analytics\")\napp.include_router(models_controller_router, prefix=\"/models_controller\")\napp.include_router(google_oauth_router, prefix=\"/google\")\napp.include_router(knowledges_router, prefix=\"/knowledges\")\napp.include_router(knowledge_configs_router, prefix=\"/knowledge_configs\")\napp.include_router(vector_dbs_router, prefix=\"/vector_dbs\")\napp.include_router(vector_db_indices_router, prefix=\"/vector_db_indices\")\napp.include_router(marketplace_stats_router, prefix=\"/marketplace\")\napp.include_router(api_key_router, prefix=\"/api-keys\")\napp.include_router(api_agent_router,prefix=\"/v1/agent\")\napp.include_router(web_hook_router,prefix=\"/webhook\")\n\n# in production you can use Settings management\n# from pydantic to get secret key from .env\nclass Settings(BaseModel):\n    # jwt_secret = get_config(\"JWT_SECRET_KEY\")\n    authjwt_secret_key: str = superagi.config.config.get_config(\"JWT_SECRET_KEY\")\n\n\ndef create_access_token(email, Authorize: AuthJWT = Depends()):\n    expiry_time_hours = superagi.config.config.get_config(\"JWT_EXPIRY\")\n    if type(expiry_time_hours) == str:\n        expiry_time_hours = int(expiry_time_hours)\n    if expiry_time_hours is None:\n        expiry_time_hours = 200\n    expires = timedelta(hours=expiry_time_hours)\n    access_token = Authorize.create_access_token(subject=email, expires_time=expires)\n    return access_token\n\n\n# callback to get your configuration\n@AuthJWT.load_config\ndef get_config():\n    return Settings()\n\n\n# exception handler for authjwt\n# in production, you can tweak performance using orjson response\n@app.exception_handler(AuthJWTException)\ndef authjwt_exception_handler(request: Request, exc: AuthJWTException):\n    return JSONResponse(\n        status_code=exc.status_code,\n        content={\"detail\": exc.message}\n    )\n\n\ndef replace_old_iteration_workflows(session):\n    templates = session.query(AgentTemplate).all()\n    for template in templates:\n        iter_workflow = IterationWorkflow.find_by_id(session, template.agent_workflow_id)\n        if not iter_workflow:\n            continue\n        if iter_workflow.name == \"Fixed Task Queue\":\n            agent_workflow = AgentWorkflow.find_by_name(session, \"Fixed Task Workflow\")\n            template.agent_workflow_id = agent_workflow.id\n            session.commit()\n\n        if iter_workflow.name == \"Maintain Task Queue\":\n            agent_workflow = AgentWorkflow.find_by_name(session, \"Dynamic Task Workflow\")\n            template.agent_workflow_id = agent_workflow.id\n            session.commit()\n\n        if iter_workflow.name == \"Don't Maintain Task Queue\" or iter_workflow.name == \"Goal Based Agent\":\n            agent_workflow = AgentWorkflow.find_by_name(session, \"Goal Based Workflow\")\n            template.agent_workflow_id = agent_workflow.id\n            session.commit()\n\n@app.on_event(\"startup\")\nasync def startup_event():\n    # Perform startup tasks here\n    logger.info(\"Running Startup tasks\")\n    Session = sessionmaker(bind=engine)\n    session = Session()\n    default_user = session.query(User).filter(User.email == \"super6@agi.com\").first()\n    logger.info(default_user)\n    if default_user is not None:\n        organisation = session.query(Organisation).filter_by(id=default_user.organisation_id).first()\n        logger.info(organisation)\n        register_toolkits(session, organisation)\n\n    def register_toolkit_for_all_organisation():\n        organizations = session.query(Organisation).all()\n        for organization in organizations:\n            register_toolkits(session, organization)\n        logger.info(\"Successfully registered local toolkits for all Organisations!\")\n\n    def register_toolkit_for_master_organisation():\n        marketplace_organisation_id = superagi.config.config.get_config(\"MARKETPLACE_ORGANISATION_ID\")\n        marketplace_organisation = session.query(Organisation).filter(\n            Organisation.id == marketplace_organisation_id).first()\n        if marketplace_organisation is not None:\n            register_marketplace_toolkits(session, marketplace_organisation)\n\n    IterationWorkflowSeed.build_single_step_agent(session)\n    IterationWorkflowSeed.build_task_based_agents(session)\n    IterationWorkflowSeed.build_action_based_agents(session)\n    IterationWorkflowSeed.build_initialize_task_workflow(session)\n\n    AgentWorkflowSeed.build_goal_based_agent(session)\n    AgentWorkflowSeed.build_task_based_agent(session)\n    AgentWorkflowSeed.build_fixed_task_based_agent(session)\n    AgentWorkflowSeed.build_sales_workflow(session)\n    AgentWorkflowSeed.build_recruitment_workflow(session)\n    AgentWorkflowSeed.build_coding_workflow(session)\n\n    # NOTE: remove old workflows. Need to remove this changes later\n    workflows = [\"Sales Engagement Workflow\", \"Recruitment Workflow\", \"SuperCoder\", \"Goal Based Workflow\",\n     \"Dynamic Task Workflow\", \"Fixed Task Workflow\"]\n    workflows = session.query(AgentWorkflow).filter(AgentWorkflow.name.not_in(workflows))\n    for workflow in workflows:\n        session.delete(workflow)\n\n    # AgentWorkflowSeed.doc_search_and_code(session)\n    # AgentWorkflowSeed.build_research_email_workflow(session)\n    replace_old_iteration_workflows(session)\n\n    if env != \"PROD\":\n        register_toolkit_for_all_organisation()\n    else:\n        register_toolkit_for_master_organisation()\n    session.close()\n\n\n@app.post('/login')\ndef login(request: LoginRequest, Authorize: AuthJWT = Depends()):\n    \"\"\"Login API for email and password based login\"\"\"\n\n    email_to_find = request.email\n    user: User = db.session.query(User).filter(User.email == email_to_find).first()\n\n    if user == None or request.email != user.email or request.password != user.password:\n        raise HTTPException(status_code=401, detail=\"Bad username or password\")\n\n    # subject identifier for who this token is for example id or username from database\n    access_token = create_access_token(user.email, Authorize)\n    return {\"access_token\": access_token}\n\n\n# def get_jwt_from_payload(user_email: str,Authorize: AuthJWT = Depends()):\n#     access_token = Authorize.create_access_token(subject=user_email)\n#     return access_token\n\n@app.get('/github-login')\ndef github_login():\n    \"\"\"GitHub login\"\"\"\n\n    github_client_id = \"\"\n    return RedirectResponse(f'https://github.com/login/oauth/authorize?scope=user:email&client_id={github_client_id}')\n\n\n@app.get('/github-auth')\ndef github_auth_handler(code: str = Query(...), Authorize: AuthJWT = Depends()):\n    \"\"\"GitHub login callback\"\"\"\n\n    github_token_url = 'https://github.com/login/oauth/access_token'\n    github_client_id = superagi.config.config.get_config(\"GITHUB_CLIENT_ID\")\n    github_client_secret = superagi.config.config.get_config(\"GITHUB_CLIENT_SECRET\")\n\n    frontend_url = superagi.config.config.get_config(\"FRONTEND_URL\", \"http://localhost:3000\")\n    params = {\n        'client_id': github_client_id,\n        'client_secret': github_client_secret,\n        'code': code\n    }\n    headers = {\n        'Accept': 'application/json'\n    }\n    response = requests.post(github_token_url, params=params, headers=headers)\n    if response.ok:\n        data = response.json()\n        access_token = data.get('access_token')\n        github_api_url = 'https://api.github.com/user'\n        headers = {\n            'Authorization': f'Bearer {access_token}'\n        }\n        response = requests.get(github_api_url, headers=headers)\n        if response.ok:\n            user_data = response.json()\n            user_email = user_data[\"email\"]\n            if user_email is None:\n                user_email = user_data[\"login\"] + \"@github.com\"\n            db_user: User = db.session.query(User).filter(User.email == user_email).first()\n            if db_user is not None:\n                jwt_token = create_access_token(user_email, Authorize)\n                redirect_url_success = f\"{frontend_url}?access_token={jwt_token}&first_time_login={False}\"\n                return RedirectResponse(url=redirect_url_success)\n\n            user = User(name=user_data[\"name\"], email=user_email)\n            db.session.add(user)\n            db.session.commit()\n            jwt_token = create_access_token(user_email, Authorize)\n            redirect_url_success = f\"{frontend_url}?access_token={jwt_token}&first_time_login={True}\"\n            return RedirectResponse(url=redirect_url_success)\n        else:\n            redirect_url_failure = \"https://superagi.com/\"\n            return RedirectResponse(url=redirect_url_failure)\n    else:\n        redirect_url_failure = \"https://superagi.com/\"\n        return RedirectResponse(url=redirect_url_failure)\n\n\n@app.get('/user')\ndef user(Authorize: AuthJWT = Depends()):\n    \"\"\"API to get current logged in User\"\"\"\n\n    Authorize.jwt_required()\n    current_user = Authorize.get_jwt_subject()\n    return {\"user\": current_user}\n\n\n@app.get(\"/validate-access-token\")\nasync def root(Authorize: AuthJWT = Depends()):\n    \"\"\"API to validate access token\"\"\"\n\n    try:\n        Authorize.jwt_required()\n        current_user_email = Authorize.get_jwt_subject()\n        current_user = db.session.query(User).filter(User.email == current_user_email).first()\n        return current_user\n    except:\n        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=\"Invalid token\")\n\n\n@app.post(\"/validate-llm-api-key\")\nasync def validate_llm_api_key(request: ValidateAPIKeyRequest, Authorize: AuthJWT = Depends()):\n    \"\"\"API to validate LLM API Key\"\"\"\n    source = request.model_source\n    api_key = request.model_api_key\n    model = build_model_with_api_key(source, api_key)\n    valid_api_key = model.verify_access_key() if model is not None else False\n    if valid_api_key:\n        return {\"message\": \"Valid API Key\", \"status\": \"success\"}\n    else:\n        return {\"message\": \"Invalid API Key\", \"status\": \"failed\"}\n\n\n@app.get(\"/validate-open-ai-key/{open_ai_key}\")\nasync def root(open_ai_key: str, Authorize: AuthJWT = Depends()):\n    \"\"\"API to validate Open AI Key\"\"\"\n\n    try:\n        llm = OpenAi(api_key=open_ai_key)\n        response = llm.chat_completion([{\"role\": \"system\", \"content\": \"Hey!\"}])\n    except:\n        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=\"Invalid API Key\")\n\n\n# #Unprotected route\n@app.get(\"/hello/{name}\")\nasync def say_hello(name: str, Authorize: AuthJWT = Depends()):\n    Authorize.jwt_required()\n    return {\"message\": f\"Hello {name}\"}\n\n@app.get('/get/github_client_id')\ndef github_client_id():\n    \"\"\"Get GitHub Client ID\"\"\"\n\n    git_hub_client_id = superagi.config.config.get_config(\"GITHUB_CLIENT_ID\")\n    if git_hub_client_id:\n        git_hub_client_id = git_hub_client_id.strip()\n    return {\"github_client_id\": git_hub_client_id}\n\n# # __________________TO RUN____________________________\n# # uvicorn main:app --host 0.0.0.0 --port 8001 --reload\n\n"
  },
  {
    "path": "migrations/README",
    "content": "Generic single-database configuration."
  },
  {
    "path": "migrations/env.py",
    "content": "from logging.config import fileConfig\n\nfrom sqlalchemy import engine_from_config\nfrom sqlalchemy import pool\nfrom alembic import context\nfrom urllib.parse import urlparse\n\n# this is the Alembic Config object, which provides\n# access to the values within the .ini file in use.\nconfig = context.config\n\n# Interpret the config file for Python logging.\n# This line sets up loggers basically.\nif config.config_file_name is not None:\n    fileConfig(config.config_file_name)\n\n# add your model's MetaData object here\n# for 'autogenerate' support\n# from myapp import mymodel\n# target_metadata = mymodel.Base.metadata\nfrom superagi.models.base_model import DBBaseModel\ntarget_metadata = DBBaseModel.metadata\nfrom superagi.models import *\nfrom superagi.config.config import get_config\n\n# other values from the config, defined by the needs of env.py,\n# can be acquired:\n# my_important_option = config.get_main_option(\"my_important_option\")\n# ... etc.\n\ndb_host = get_config('DB_HOST', 'super__postgres')\ndb_username = get_config('DB_USERNAME')\ndb_password = get_config('DB_PASSWORD')\ndb_name = get_config('DB_NAME')\ndatabase_url = get_config('DB_URL', None)\n\ndef run_migrations_offline() -> None:\n    \"\"\"Run migrations in 'offline' mode.\n\n    This configures the context with just a URL\n    and not an Engine, though an Engine is acceptable\n    here as well.  By skipping the Engine creation\n    we don't even need a DBAPI to be available.\n\n    Calls to context.execute() here emit the given string to the\n    script output.\n\n    \"\"\"\n\n    db_url = database_url\n    if db_url is None:\n        if db_username is None:\n            db_url = f'postgresql://{db_host}/{db_name}'\n        else:\n            db_url = f'postgresql://{db_username}:{db_password}@{db_host}/{db_name}'\n    else:\n        db_url = urlparse(db_url)\n        db_url = db_url.scheme + \"://\" + db_url.netloc + db_url.path\n\n    config.set_main_option(\"sqlalchemy.url\", db_url)\n\n    url = config.get_main_option(\"sqlalchemy.url\")\n    context.configure(\n        url=url,\n        target_metadata=target_metadata,\n        literal_binds=True,\n        dialect_opts={\"paramstyle\": \"named\"},\n    )\n\n    with context.begin_transaction():\n        context.run_migrations()\n\n\ndef run_migrations_online() -> None:\n    \"\"\"Run migrations in 'online' mode.\n\n    In this scenario we need to create an Engine\n    and associate a connection with the context.\n\n    \"\"\"\n\n    db_host = get_config('DB_HOST', 'super__postgres')\n    db_username = get_config('DB_USERNAME')\n    db_password = get_config('DB_PASSWORD')\n    db_name = get_config('DB_NAME')\n    db_url = get_config('DB_URL', None)\n\n    if db_url is None:\n        if db_username is None:\n            db_url = f'postgresql://{db_host}/{db_name}'\n        else:\n            db_url = f'postgresql://{db_username}:{db_password}@{db_host}/{db_name}'\n    else:\n        db_url = urlparse(db_url)\n        db_url = db_url.scheme + \"://\" + db_url.netloc + db_url.path\n        \n    config.set_main_option('sqlalchemy.url', db_url)\n    connectable = engine_from_config(\n        config.get_section(config.config_ini_section, {}),\n        prefix=\"sqlalchemy.\",\n        poolclass=pool.NullPool,\n    )\n\n    with connectable.connect() as connection:\n        context.configure(\n            connection=connection, target_metadata=target_metadata\n        )\n\n        with context.begin_transaction():\n            context.run_migrations()\n\n\nif context.is_offline_mode():\n    run_migrations_offline()\nelse:\n    run_migrations_online()\n"
  },
  {
    "path": "migrations/script.py.mako",
    "content": "\"\"\"${message}\n\nRevision ID: ${up_revision}\nRevises: ${down_revision | comma,n}\nCreate Date: ${create_date}\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n${imports if imports else \"\"}\n\n# revision identifiers, used by Alembic.\nrevision = ${repr(up_revision)}\ndown_revision = ${repr(down_revision)}\nbranch_labels = ${repr(branch_labels)}\ndepends_on = ${repr(depends_on)}\n\n\ndef upgrade() -> None:\n    ${upgrades if upgrades else \"pass\"}\n\n\ndef downgrade() -> None:\n    ${downgrades if downgrades else \"pass\"}\n"
  },
  {
    "path": "migrations/versions/1d54db311055_add_permissions.py",
    "content": "\"\"\"add permissions\n\nRevision ID: 1d54db311055\nRevises: 3356a2f89a33\nCreate Date: 2023-06-14 11:05:59.678961\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '1d54db311055'\ndown_revision = '516ecc1c723d'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.create_table('agent_execution_permissions',\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.Column('id', sa.Integer(), nullable=False),\n    sa.Column('agent_execution_id', sa.Integer(), nullable=True),\n    sa.Column('agent_id', sa.Integer(), nullable=True),\n    sa.Column('status', sa.String(), nullable=True),\n    sa.Column('tool_name', sa.String(), nullable=True),\n    sa.Column('user_feedback', sa.Text(), nullable=True),\n    sa.Column('assistant_reply', sa.Text(), nullable=True),\n    sa.PrimaryKeyConstraint('id')\n    )\n    op.add_column('agent_executions', sa.Column('permission_id', sa.Integer(), nullable=True))\n    # index on agent_execution_id\n    op.create_index(op.f('ix_agent_execution_permissions_agent_execution_id')\n                    , 'agent_execution_permissions', ['agent_execution_id'], unique=False)\n\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.drop_column('agent_executions', 'permission_id')\n    op.drop_table('agent_execution_permissions')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/2cc1179834b0_agent_executions_modified.py",
    "content": "\"\"\"agent_executions_modified\n\nRevision ID: 2cc1179834b0\nRevises: 2f97c068fab9\nCreate Date: 2023-06-02 21:01:43.303961\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '2cc1179834b0'\ndown_revision = '2f97c068fab9'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.add_column('agent_executions', sa.Column('calls', sa.Integer(), nullable=True))\n    op.add_column('agent_executions', sa.Column('tokens', sa.Integer(), nullable=True))\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.drop_column('agent_executions', 'tokens')\n    op.drop_column('agent_executions', 'calls')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/2f97c068fab9_resource_modified.py",
    "content": "\"\"\"Resource Modified\n\nRevision ID: 2f97c068fab9\nRevises: a91808a89623\nCreate Date: 2023-06-02 13:13:21.670935\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '2f97c068fab9'\ndown_revision = 'a91808a89623'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.add_column('resources', sa.Column('agent_id', sa.Integer(), nullable=True))\n    op.drop_column('resources', 'project_id')\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.add_column('resources', sa.Column('project_id', sa.INTEGER(), autoincrement=False, nullable=True))\n    op.drop_column('resources', 'agent_id')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/2fbd6472112c_add_feed_group_id_to_execution_and_feed.py",
    "content": "\"\"\"add feed group id to execution and feed\n\nRevision ID: 2fbd6472112c\nRevises: 5184645e9f12\nCreate Date: 2023-08-01 17:09:16.183863\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n# revision identifiers, used by Alembic.\nrevision = '2fbd6472112c'\ndown_revision = '5184645e9f12'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    op.add_column('agent_executions',\n                  sa.Column('current_feed_group_id', sa.String(), nullable=True, server_default=\"DEFAULT\"))\n    op.add_column('agent_execution_feeds', sa.Column('feed_group_id', sa.String(), nullable=True))\n\n\ndef downgrade() -> None:\n    op.drop_column('agent_executions', 'current_feed_group_id')\n    op.drop_column('agent_execution_feeds', 'feed_group_id')\n"
  },
  {
    "path": "migrations/versions/3356a2f89a33_added_configurations_table.py",
    "content": "\"\"\"added_configurations_table\n\nRevision ID: 3356a2f89a33\nRevises: 35e47f20475b\nCreate Date: 2023-06-06 10:51:15.111738\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '3356a2f89a33'\ndown_revision = '35e47f20475b'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.create_table('configurations',\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),\n    sa.Column('organisation_id', sa.Integer(), nullable=True),\n    sa.Column('key', sa.String(), nullable=True),\n    sa.Column('value', sa.Text(), nullable=True),\n    sa.PrimaryKeyConstraint('id')\n    )\n    op.drop_index('ix_aea_step_id', table_name='agent_executions')\n    op.drop_index('ix_ats_unique_id', table_name='agent_template_steps')\n    op.drop_index('ix_at_name', table_name='agent_templates')\n    op.drop_index('ix_agents_agnt_template_id', table_name='agents')\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.create_index('ix_agents_agnt_template_id', 'agents', ['agent_template_id'], unique=False)\n    op.create_index('ix_at_name', 'agent_templates', ['name'], unique=False)\n    op.create_index('ix_ats_unique_id', 'agent_template_steps', ['unique_id'], unique=False)\n    op.create_index('ix_aea_step_id', 'agent_executions', ['current_step_id'], unique=False)\n    op.drop_table('configurations')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/35e47f20475b_renamed_tokens_calls.py",
    "content": "\"\"\"renamed_tokens_calls\n\nRevision ID: 35e47f20475b\nRevises: 598cfb37292a\nCreate Date: 2023-06-06 04:34:15.101672\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '35e47f20475b'\ndown_revision = '598cfb37292a'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.add_column('agent_executions', sa.Column('num_of_calls', sa.Integer(), nullable=True))\n    op.add_column('agent_executions', sa.Column('num_of_tokens', sa.Integer(), nullable=True))\n    op.drop_column('agent_executions', 'calls')\n    op.drop_column('agent_executions', 'tokens')\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.add_column('agent_executions', sa.Column('tokens', sa.INTEGER(), autoincrement=False, nullable=True))\n    op.add_column('agent_executions', sa.Column('calls', sa.INTEGER(), autoincrement=False, nullable=True))\n    op.drop_column('agent_executions', 'num_of_tokens')\n    op.drop_column('agent_executions', 'num_of_calls')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/3867bb00a495_added_first_login_source.py",
    "content": "\"\"\"added_first_login_source\n\nRevision ID: 3867bb00a495\nRevises: 661ec8a4c32e\nCreate Date: 2023-09-15 02:06:24.006555\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '3867bb00a495'\ndown_revision = '661ec8a4c32e'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.add_column('users', sa.Column('first_login_source', sa.String(), nullable=True))\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.drop_column('users', 'first_login_source')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/40affbf3022b_add_filter_colume_in_webhooks.py",
    "content": "\"\"\"add filter colume in webhooks\n\nRevision ID: 40affbf3022b\nRevises: 5d5f801f28e7\nCreate Date: 2023-08-28 12:30:35.171176\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '40affbf3022b'\ndown_revision = '5d5f801f28e7'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.add_column('webhooks', sa.Column('filters', sa.JSON(), nullable=True))\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.drop_column('webhooks', 'filters')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/446884dcae58_add_api_key_and_web_hook.py",
    "content": "\"\"\"add api_key and web_hook\n\nRevision ID: 446884dcae58\nRevises: 71e3980d55f5\nCreate Date: 2023-07-29 10:55:21.714245\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '446884dcae58'\ndown_revision = '2fbd6472112c'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.create_table('api_keys',\n    sa.Column('id', sa.Integer(), nullable=False),\n    sa.Column('org_id', sa.Integer(), nullable=True),\n    sa.Column('name', sa.String(), nullable=True),\n    sa.Column('key', sa.String(), nullable=True),\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.Column('is_expired',sa.Boolean(),nullable=True,default=False),\n    sa.PrimaryKeyConstraint('id')\n    )\n    op.create_table('webhooks',\n    sa.Column('id', sa.Integer(), nullable=False),\n    sa.Column('name', sa.String(), nullable=True),\n    sa.Column('org_id', sa.Integer(), nullable=True),\n    sa.Column('url', sa.String(), nullable=True),\n    sa.Column('headers', sa.JSON(), nullable=True),\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.Column('is_deleted',sa.Boolean(),nullable=True),\n    sa.PrimaryKeyConstraint('id')\n    )\n    op.create_table('webhook_events',\n    sa.Column('id', sa.Integer(), nullable=False),\n    sa.Column('agent_id', sa.Integer(), nullable=True),\n    sa.Column('run_id', sa.Integer(), nullable=True),\n    sa.Column('event', sa.String(), nullable=True),\n    sa.Column('status', sa.String(), nullable=True),\n    sa.Column('errors', sa.Text(), nullable=True),\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.PrimaryKeyConstraint('id')\n    )\n\n    #add index *********************\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    \n    op.drop_table('webhooks')\n    op.drop_table('api_keys')\n    op.drop_table('webhook_events')\n\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/44b0d6f2d1b3_init_models.py",
    "content": "\"\"\"init models\n\nRevision ID: 44b0d6f2d1b3\nRevises: \nCreate Date: 2023-06-01 11:55:35.195423\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '44b0d6f2d1b3'\ndown_revision = None\nbranch_labels = None\ndepends_on = None\n\nfrom sqlalchemy.engine.reflection import Inspector\n\nconn = op.get_bind()\ninspector = Inspector.from_engine(conn)\ntables = inspector.get_table_names()\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    if 'agent_configurations' not in tables:\n        op.create_table('agent_configurations',\n        sa.Column('created_at', sa.DateTime(), nullable=True),\n        sa.Column('updated_at', sa.DateTime(), nullable=True),\n        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),\n        sa.Column('agent_id', sa.Integer(), nullable=True),\n        sa.Column('key', sa.String(), nullable=True),\n        sa.Column('value', sa.Text(), nullable=True),\n        sa.PrimaryKeyConstraint('id')\n        )\n    if 'agent_execution_feeds' not in tables:\n        op.create_table('agent_execution_feeds',\n        sa.Column('created_at', sa.DateTime(), nullable=True),\n        sa.Column('updated_at', sa.DateTime(), nullable=True),\n        sa.Column('id', sa.Integer(), nullable=False),\n        sa.Column('agent_execution_id', sa.Integer(), nullable=True),\n        sa.Column('agent_id', sa.Integer(), nullable=True),\n        sa.Column('feed', sa.Text(), nullable=True),\n        sa.Column('role', sa.String(), nullable=True),\n        sa.PrimaryKeyConstraint('id')\n        )\n    if 'agent_executions' not in tables:\n        op.create_table('agent_executions',\n        sa.Column('created_at', sa.DateTime(), nullable=True),\n        sa.Column('updated_at', sa.DateTime(), nullable=True),\n        sa.Column('id', sa.Integer(), nullable=False),\n        sa.Column('status', sa.String(), nullable=True),\n        sa.Column('agent_id', sa.Integer(), nullable=True),\n        sa.Column('last_execution_time', sa.DateTime(), nullable=True),\n        sa.PrimaryKeyConstraint('id')\n        )\n    if 'agents' not in tables:\n        op.create_table('agents',\n        sa.Column('created_at', sa.DateTime(), nullable=True),\n        sa.Column('updated_at', sa.DateTime(), nullable=True),\n        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),\n        sa.Column('name', sa.String(), nullable=True),\n        sa.Column('project_id', sa.Integer(), nullable=True),\n        sa.Column('description', sa.String(), nullable=True),\n        sa.PrimaryKeyConstraint('id')\n        )\n    if 'budgets' not in tables:\n        op.create_table('budgets',\n        sa.Column('created_at', sa.DateTime(), nullable=True),\n        sa.Column('updated_at', sa.DateTime(), nullable=True),\n        sa.Column('id', sa.Integer(), nullable=False),\n        sa.Column('budget', sa.Float(), nullable=True),\n        sa.Column('cycle', sa.String(), nullable=True),\n        sa.PrimaryKeyConstraint('id')\n        )\n    if 'organisations' not in tables:\n        op.create_table('organisations',\n        sa.Column('created_at', sa.DateTime(), nullable=True),\n        sa.Column('updated_at', sa.DateTime(), nullable=True),\n        sa.Column('id', sa.Integer(), nullable=False),\n        sa.Column('name', sa.String(), nullable=True),\n        sa.Column('description', sa.String(), nullable=True),\n        sa.PrimaryKeyConstraint('id')\n        )\n    if 'projects' not in tables:\n        op.create_table('projects',\n        sa.Column('created_at', sa.DateTime(), nullable=True),\n        sa.Column('updated_at', sa.DateTime(), nullable=True),\n        sa.Column('id', sa.Integer(), nullable=False),\n        sa.Column('name', sa.String(), nullable=True),\n        sa.Column('organisation_id', sa.Integer(), nullable=True),\n        sa.Column('description', sa.String(), nullable=True),\n        sa.PrimaryKeyConstraint('id')\n        )\n    if 'tool_configs' not in tables:\n        op.create_table('tool_configs',\n        sa.Column('created_at', sa.DateTime(), nullable=True),\n        sa.Column('updated_at', sa.DateTime(), nullable=True),\n        sa.Column('id', sa.Integer(), nullable=False),\n        sa.Column('name', sa.String(), nullable=True),\n        sa.Column('key', sa.String(), nullable=True),\n        sa.Column('value', sa.String(), nullable=True),\n        sa.Column('agent_id', sa.Integer(), nullable=True),\n        sa.PrimaryKeyConstraint('id')\n        )\n    if 'tools' not in tables:\n        op.create_table('tools',\n        sa.Column('created_at', sa.DateTime(), nullable=True),\n        sa.Column('updated_at', sa.DateTime(), nullable=True),\n        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),\n        sa.Column('name', sa.String(), nullable=True),\n        sa.Column('folder_name', sa.String(), nullable=True),\n        sa.Column('class_name', sa.String(), nullable=True),\n        sa.Column('file_name', sa.String(), nullable=True),\n        sa.PrimaryKeyConstraint('id')\n        )\n    if 'users' not in tables:\n        op.create_table('users',\n        sa.Column('created_at', sa.DateTime(), nullable=True),\n        sa.Column('updated_at', sa.DateTime(), nullable=True),\n        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),\n        sa.Column('name', sa.String(), nullable=True),\n        sa.Column('email', sa.String(), nullable=True),\n        sa.Column('password', sa.String(), nullable=True),\n        sa.Column('organisation_id', sa.Integer(), nullable=True),\n        sa.PrimaryKeyConstraint('id'),\n        sa.UniqueConstraint('email')\n        )\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.drop_table('users')\n    op.drop_table('tools')\n    op.drop_table('tool_configs')\n    op.drop_table('projects')\n    op.drop_table('organisations')\n    op.drop_table('budgets')\n    op.drop_table('agents')\n    op.drop_table('agent_executions')\n    op.drop_table('agent_execution_feeds')\n    op.drop_table('agent_configurations')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/467e85d5e1cd_updated_resources_added_exec_id.py",
    "content": "\"\"\"updated_resources_added_exec_id\n\nRevision ID: 467e85d5e1cd\nRevises: ba60b12ae109\nCreate Date: 2023-07-10 08:54:46.702652\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '467e85d5e1cd'\ndown_revision = 'ba60b12ae109'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.add_column('resources', sa.Column('agent_execution_id', sa.Integer(), nullable=True))\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.drop_column('resources', 'agent_execution_id')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/516ecc1c723d_adding_marketplace_template_id_to_agent_.py",
    "content": "\"\"\"adding marketplace_template_id to agent tempaltes\n\nRevision ID: 516ecc1c723d\nRevises: 8962bed0d809\nCreate Date: 2023-06-13 17:10:06.262764\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '516ecc1c723d'\ndown_revision = '8962bed0d809'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    op.add_column('agent_templates', sa.Column('marketplace_template_id', sa.Integer(), nullable=True))\n\n\ndef downgrade() -> None:\n    op.drop_column('agent_templates', sa.Column('marketplace_template_id', sa.Integer(), nullable=True))\n"
  },
  {
    "path": "migrations/versions/5184645e9f12_add_question_to_agent_execution_.py",
    "content": "\"\"\"add question to agent execution permission\n\nRevision ID: 5184645e9f12\nRevises: 9419b3340af7\nCreate Date: 2023-07-21 08:16:14.702389\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '5184645e9f12'\ndown_revision = '9419b3340af7'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    op.add_column('agent_execution_permissions', sa.Column('question', sa.Text(), nullable=True))\n\n\ndef downgrade() -> None:\n    op.drop_column('agent_execution_permissions', \"question\")\n"
  },
  {
    "path": "migrations/versions/520aa6776347_create_models_config.py",
    "content": "\"\"\"create models config\n\nRevision ID: 520aa6776347\nRevises: 71e3980d55f5\nCreate Date: 2023-08-01 07:48:13.724938\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '520aa6776347'\ndown_revision = '446884dcae58'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.create_table('models_config',\n    sa.Column('id', sa.Integer(), nullable=False),\n    sa.Column('provider', sa.String(), nullable=False),\n    sa.Column('api_key', sa.String(), nullable=False),\n    sa.Column('org_id', sa.Integer(), nullable=False),\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.PrimaryKeyConstraint('id')\n    )\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.drop_table('models_config')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/598cfb37292a_adding_agent_templates.py",
    "content": "\"\"\"adding agent templates\n\nRevision ID: 598cfb37292a\nRevises: 2f97c068fab9\nCreate Date: 2023-06-05 12:44:30.982492\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\nfrom sqlalchemy.engine import Inspector\n\n# revision identifiers, used by Alembic.\nrevision = '598cfb37292a'\ndown_revision = '2cc1179834b0'\nbranch_labels = None\ndepends_on = None\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.create_table('agent_template_steps',\n                    sa.Column('created_at', sa.DateTime(), nullable=True),\n                    sa.Column('updated_at', sa.DateTime(), nullable=True),\n                    sa.Column('id', sa.Integer(), nullable=False),\n                    sa.Column('agent_template_id', sa.Integer(), nullable=True),\n                    sa.Column('unique_id', sa.String(), nullable=True),\n                    sa.Column('prompt', sa.Text(), nullable=True),\n                    sa.Column('variables', sa.Text(), nullable=True),\n                    sa.Column('output_type', sa.String(), nullable=True),\n                    sa.Column('step_type', sa.String(), nullable=True),\n                    sa.Column('next_step_id', sa.Integer(), nullable=True),\n                    sa.Column('history_enabled', sa.Boolean(), nullable=True),\n                    sa.Column('completion_prompt', sa.Text(), nullable=True),\n                    sa.PrimaryKeyConstraint('id')\n                    )\n\n    op.create_table('agent_templates',\n                    sa.Column('created_at', sa.DateTime(), nullable=True),\n                    sa.Column('updated_at', sa.DateTime(), nullable=True),\n                    sa.Column('id', sa.Integer(), nullable=False),\n                    sa.Column('name', sa.String(), nullable=True),\n                    sa.Column('description', sa.Text(), nullable=True),\n                    sa.PrimaryKeyConstraint('id')\n                    )\n\n    op.add_column('agent_executions', sa.Column('current_step_id', sa.Integer()))\n    op.add_column('agents', sa.Column('agent_template_id', sa.Integer()))\n    op.create_index(\"ix_agents_agnt_template_id\", \"agents\", ['agent_template_id'])\n    op.create_index(\"ix_aea_step_id\", \"agent_executions\", ['current_step_id'])\n\n    op.create_index(\"ix_ats_unique_id\", \"agent_template_steps\", ['unique_id'])\n    op.create_index(\"ix_at_name\", \"agent_templates\", ['name'])\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.drop_column('agents', 'agent_template_id')\n    op.add_column('agent_executions', sa.Column('name', sa.VARCHAR(), autoincrement=False, nullable=True))\n    op.drop_column('agent_executions', 'current_step_id')\n    op.drop_table('agent_templates')\n    op.drop_table('agent_template_steps')\n    # ### end Alembic commands ###\n\n\n"
  },
  {
    "path": "migrations/versions/5d5f801f28e7_create_model_table.py",
    "content": "\"\"\"create model table\n\nRevision ID: 5d5f801f28e7\nRevises: 520aa6776347\nCreate Date: 2023-08-07 05:36:29.791610\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '5d5f801f28e7'\ndown_revision = 'be1d922bf2ad'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.create_table('models',\n    sa.Column('id', sa.Integer(), nullable=False),\n    sa.Column('model_name', sa.String(), nullable=False),\n    sa.Column('description', sa.String(), nullable=True),\n    sa.Column('end_point', sa.String(), nullable=False),\n    sa.Column('model_provider_id', sa.Integer(), nullable=False),\n    sa.Column('token_limit', sa.Integer(), nullable=False),\n    sa.Column('type', sa.String(), nullable=False),\n    sa.Column('version', sa.String(), nullable=False),\n    sa.Column('org_id', sa.Integer(), nullable=False),\n    sa.Column('model_features', sa.String(), nullable=False),\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.PrimaryKeyConstraint('id')\n    )\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.drop_table('models')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/661ec8a4c32e_open_ai_error_handling.py",
    "content": "\"\"\"open_ai_error_handling\n\nRevision ID: 661ec8a4c32e\nRevises: 40affbf3022b\nCreate Date: 2023-09-07 10:41:07.462436\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '661ec8a4c32e'\ndown_revision = 'c4f2f6ba602a'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.add_column('agent_execution_feeds', sa.Column('error_message', sa.String(), nullable=True))\n    op.add_column('agent_executions', sa.Column('last_shown_error_id', sa.Integer(), nullable=True))\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.drop_column('agent_executions', 'last_shown_error_id')\n    op.drop_column('agent_execution_feeds', 'error_message')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/71e3980d55f5_knowledge_and_vector_dbs.py",
    "content": "\"\"\"Knowledge and Vector dbs\n\nRevision ID: 71e3980d55f5\nRevises: cac478732572\nCreate Date: 2023-07-26 07:18:06.492832\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '71e3980d55f5'\ndown_revision = 'cac478732572'\nbranch_labels = None\ndepends_on = None\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.create_table('knowledge_configs',\n    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),\n    sa.Column('knowledge_id', sa.Integer(), nullable=False),\n    sa.Column('key', sa.String(), nullable=True),\n    sa.Column('value', sa.Text(), nullable=True),\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.PrimaryKeyConstraint('id')\n    )\n    op.create_table('knowledges',\n    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),\n    sa.Column('name', sa.String(), nullable=False),\n    sa.Column('description', sa.String(), nullable=True),\n    sa.Column('vector_db_index_id', sa.Integer(), nullable=True),\n    sa.Column('organisation_id', sa.Integer(), nullable=True),\n    sa.Column('contributed_by', sa.String(), nullable=True),\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.PrimaryKeyConstraint('id')\n    )\n    op.create_table('marketplace_stats',\n    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),\n    sa.Column('reference_id', sa.Integer(), nullable=True),\n    sa.Column('reference_name', sa.String(), nullable=True),\n    sa.Column('key', sa.String(), nullable=True),\n    sa.Column('value', sa.Integer(), nullable=True),\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.PrimaryKeyConstraint('id')\n    )\n    op.create_table('vector_db_configs',\n    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),\n    sa.Column('vector_db_id', sa.Integer(), nullable=False),\n    sa.Column('key', sa.String(), nullable=True),\n    sa.Column('value', sa.Text(), nullable=True),\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.PrimaryKeyConstraint('id')\n    )\n    op.create_table('vector_db_indices',\n    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),\n    sa.Column('name', sa.String(), nullable=False),\n    sa.Column('vector_db_id', sa.Integer(), nullable=True),\n    sa.Column('dimensions', sa.Integer(), nullable=True),\n    sa.Column('state', sa.String(), nullable=True),\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.PrimaryKeyConstraint('id')\n    )\n    op.create_table('vector_dbs',\n    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),\n    sa.Column('name', sa.String(), nullable=False),\n    sa.Column('db_type', sa.String(), nullable=True),\n    sa.Column('organisation_id', sa.Integer(), nullable=True),\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.PrimaryKeyConstraint('id')\n    )\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.drop_table('vector_dbs')\n    op.drop_table('vector_db_indices')\n    op.drop_table('vector_db_configs')\n    op.drop_table('knowledges')\n    op.drop_table('knowledge_configs')"
  },
  {
    "path": "migrations/versions/7a3e336c0fba_added_tools_related_models.py",
    "content": "\"\"\"added_tools_related_models\n\nRevision ID: 7a3e336c0fba\nRevises: 516ecc1c723d\nCreate Date: 2023-06-18 11:05:35.801505\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '7a3e336c0fba'\ndown_revision = '1d54db311055'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.create_table('toolkits',\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.Column('id', sa.Integer(), nullable=False),\n    sa.Column('name', sa.String(), nullable=True),\n    sa.Column('description', sa.String(), nullable=True),\n    sa.Column('show_toolkit', sa.Boolean(), nullable=True),\n    sa.Column('organisation_id', sa.Integer(), nullable=True),\n    sa.Column('tool_code_link', sa.String(), nullable=True),\n    sa.PrimaryKeyConstraint('id')\n    )\n\n    op.add_column('tool_configs', sa.Column('toolkit_id', sa.Integer(), nullable=True))\n    op.drop_column('tool_configs', 'name')\n    op.drop_column('tool_configs', 'agent_id')\n    op.add_column('tools', sa.Column('description', sa.String(), nullable=True))\n    op.add_column('tools', sa.Column('toolkit_id', sa.Integer(), nullable=True))\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.drop_column('tools', 'toolkit_id')\n    op.drop_column('tools', 'description')\n    op.add_column('tool_configs', sa.Column('agent_id', sa.INTEGER(), autoincrement=False, nullable=True))\n    op.add_column('tool_configs', sa.Column('name', sa.VARCHAR(), autoincrement=False, nullable=True))\n    op.drop_column('tool_configs', 'toolkit_id')\n    op.drop_table('toolkits')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/83424de1347e_added_agent_execution_config.py",
    "content": "\"\"\"added_agent_execution_config\n\nRevision ID: 83424de1347e\nRevises: c02f3d759bf3\nCreate Date: 2023-07-03 22:42:50.091762\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '83424de1347e'\ndown_revision = 'c02f3d759bf3'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.create_table('agent_execution_configs',\n    sa.Column('id', sa.Integer(), nullable=False),\n    sa.Column('agent_execution_id', sa.Integer(), nullable=True),\n    sa.Column('key', sa.String(), nullable=True),\n    sa.Column('value', sa.Text(), nullable=True),\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.PrimaryKeyConstraint('id')\n    )\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.drop_table('agent_execution_configs')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/8962bed0d809_creating_agent_templates.py",
    "content": "\"\"\"creating agent templates\n\nRevision ID: 8962bed0d809\nRevises: d9b3436197eb\nCreate Date: 2023-06-10 15:40:08.942612\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '8962bed0d809'\ndown_revision = 'd9b3436197eb'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    op.create_table('agent_templates',\n                    sa.Column('created_at', sa.DateTime(), nullable=True),\n                    sa.Column('updated_at', sa.DateTime(), nullable=True),\n                    sa.Column('id', sa.Integer(), nullable=False),\n                    sa.Column('name', sa.String(), nullable=True),\n                    sa.Column('description', sa.Text(), nullable=True),\n                    sa.Column('organisation_id', sa.Integer(), nullable=True),\n                    sa.Column('agent_workflow_id', sa.Integer(), nullable=True),\n                    sa.PrimaryKeyConstraint('id')\n                    )\n\n    op.create_table('agent_template_configs',\n                    sa.Column('created_at', sa.DateTime(), nullable=True),\n                    sa.Column('updated_at', sa.DateTime(), nullable=True),\n                    sa.Column('id', sa.Integer(), nullable=False),\n                    sa.Column('agent_template_id', sa.Integer(), nullable=True),\n                    sa.Column('key', sa.String(), nullable=True),\n                    sa.Column('value', sa.Text(), nullable=True),\n                    sa.PrimaryKeyConstraint('id')\n                    )\n    op.create_index(\"ix_atc_agnt_template_id_key\", \"agent_template_configs\", ['agent_template_id', 'key'])\n    op.create_index(\"ix_agt_agnt_organisation_id\", \"agent_templates\", ['organisation_id'])\n    op.create_index(\"ix_agt_agnt_workflow_id\", \"agent_templates\", ['agent_workflow_id'])\n    op.create_index(\"ix_agt_agnt_name\", \"agent_templates\", ['name'])\n\n\ndef downgrade() -> None:\n    op.drop_table('agent_template_configs')\n    op.drop_table('agent_templates')\n"
  },
  {
    "path": "migrations/versions/9270eb5a8475_local_llms.py",
    "content": "\"\"\"local_llms\n\nRevision ID: 9270eb5a8475\nRevises: 3867bb00a495\nCreate Date: 2023-10-04 09:26:33.865424\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = '9270eb5a8475'\ndown_revision = '3867bb00a495'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.add_column('models', sa.Column('context_length', sa.Integer(), nullable=True))\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.drop_column('models', 'context_length')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/9419b3340af7_create_agent_workflow.py",
    "content": "\"\"\"create agent workflow\n\nRevision ID: 9419b3340af7\nRevises: fe234ea6e9bc\nCreate Date: 2023-07-18 16:46:03.497943\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\nfrom sqlalchemy.dialects import postgresql\n\n# revision identifiers, used by Alembic.\nrevision = '9419b3340af7'\ndown_revision = 'fe234ea6e9bc'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    op.create_table('agent_workflows',\n                    sa.Column('id', sa.Integer(), nullable=False),\n                    sa.Column('name', sa.String(), nullable=True),\n                    sa.Column('description', sa.Text(), nullable=True),\n                    sa.Column('organisation_id', sa.Integer(), nullable=True),\n                    sa.Column('created_at', sa.DateTime(), nullable=True),\n                    sa.Column('updated_at', sa.DateTime(), nullable=True),\n                    sa.PrimaryKeyConstraint('id')\n                   )\n\n    op.create_table('agent_workflow_steps',\n                    sa.Column('id', sa.Integer(), nullable=False),\n                    sa.Column('step_type', sa.String(), nullable=False),\n                    sa.Column('agent_workflow_id', sa.Integer(), nullable=True),\n                    sa.Column('action_reference_id', sa.Integer(), nullable=True),\n                    sa.Column('action_type', sa.String(), nullable=True),\n                    sa.Column('unique_id', sa.String(), nullable=False),\n                    sa.Column('next_steps', postgresql.JSONB(astext_type=sa.Text()), nullable=True),\n                    sa.Column('created_at', sa.DateTime(), nullable=True),\n                    sa.Column('updated_at', sa.DateTime(), nullable=True),\n                    sa.PrimaryKeyConstraint('id')\n                    )\n\n    op.create_table('agent_workflow_step_tools',\n                    sa.Column('id', sa.Integer(), nullable=False),\n                    sa.Column('unique_id', sa.String(), nullable=True),\n                    sa.Column('tool_name', sa.String(), nullable=True),\n                    sa.Column('input_instruction', sa.Text(), nullable=True),\n                    sa.Column('output_instruction', sa.Text(), nullable=True),\n                    sa.Column('history_enabled', sa.Boolean(), nullable=True),\n                    sa.Column('completion_prompt', sa.Text(), nullable=True),\n                    sa.Column('created_at', sa.DateTime(), nullable=True),\n                    sa.Column('updated_at', sa.DateTime(), nullable=True),\n                    sa.PrimaryKeyConstraint('id')\n                    )\n\ndef downgrade() -> None:\n    op.drop_table('agent_workflows')\n    op.drop_table('agent_workflow_steps')\n    op.drop_table('agent_workflow_step_tools')\n"
  },
  {
    "path": "migrations/versions/a91808a89623_added_resources.py",
    "content": "\"\"\"added resources\n\nRevision ID: a91808a89623\nRevises: 44b0d6f2d1b3\nCreate Date: 2023-06-01 07:00:33.982485\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = 'a91808a89623'\ndown_revision = '44b0d6f2d1b3'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.create_table('resources',\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.Column('id', sa.Integer(), nullable=False),\n    sa.Column('name', sa.String(), nullable=True),\n    sa.Column('storage_type', sa.String(), nullable=True),\n    sa.Column('path', sa.String(), nullable=True),\n    sa.Column('size', sa.Integer(), nullable=True),\n    sa.Column('type', sa.String(), nullable=True),\n    sa.Column('channel', sa.String(), nullable=True),\n    sa.Column('project_id', sa.Integer(), nullable=True),\n    sa.PrimaryKeyConstraint('id')\n    )\n    op.add_column('agent_execution_feeds', sa.Column('extra_info', sa.String(), nullable=True))\n    op.add_column('agent_executions', sa.Column('name', sa.String(), nullable=True))\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.drop_column('agent_executions', 'name')\n    op.drop_column('agent_execution_feeds', 'extra_info')\n    op.drop_table('resources')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/ba60b12ae109_create_agent_scheduler.py",
    "content": "\"\"\"create_agent_scheduler\n\nRevision ID: ba60b12ae109\nRevises: 83424de1347e\nCreate Date: 2023-07-04 10:58:37.991063\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = 'ba60b12ae109'\ndown_revision = '83424de1347e'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.create_table('agent_schedule',\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.Column('id', sa.Integer(), nullable=False),\n    sa.Column('agent_id', sa.Integer(), nullable=True),\n    sa.Column('start_time', sa.DateTime(), nullable=True),\n    sa.Column('next_scheduled_time', sa.DateTime(), nullable=True),\n    sa.Column('recurrence_interval', sa.String(), nullable=True),\n    sa.Column('expiry_date', sa.DateTime(), nullable=True),\n    sa.Column('expiry_runs', sa.Integer(), nullable=True),\n    sa.Column('current_runs', sa.Integer(), nullable=True),\n    sa.Column('status', sa.String(), nullable=True),\n    sa.PrimaryKeyConstraint('id')\n    )\n    op.create_index(op.f('ix_agent_schedule_expiry_date'), 'agent_schedule', ['expiry_date'], unique=False)\n    op.create_index(op.f('ix_agent_schedule_status'), 'agent_schedule', ['status'], unique=False)\n    op.create_index(op.f('ix_agent_schedule_agent_id'), 'agent_schedule', ['agent_id'], unique=False)\n    # ### end Alembic commands ###\n\n    \ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.drop_index(op.f('ix_agent_schedule_agent_id'), table_name='agent_schedule')\n    op.drop_index(op.f('ix_agent_schedule_status'), table_name='agent_schedule')\n    op.drop_index(op.f('ix_agent_schedule_expiry_date'), table_name='agent_schedule')\n    op.drop_table('agent_schedule')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/be1d922bf2ad_create_call_logs_table.py",
    "content": "\"\"\"create call logs table\n\nRevision ID: be1d922bf2ad\nRevises: 2fbd6472112c\nCreate Date: 2023-08-08 08:42:37.148178\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = 'be1d922bf2ad'\ndown_revision = '520aa6776347'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.create_table('call_logs',\n    sa.Column('id', sa.Integer(), nullable=False),\n    sa.Column('agent_execution_name', sa.String(), nullable=False),\n    sa.Column('agent_id', sa.Integer(), nullable=False),\n    sa.Column('tokens_consumed', sa.Integer(), nullable=False),\n    sa.Column('tool_used', sa.String(), nullable=False),\n    sa.Column('model', sa.String(), nullable=True),\n    sa.Column('org_id', sa.Integer(), nullable=False),\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.PrimaryKeyConstraint('id')\n    )\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.drop_table('call_logs')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/c02f3d759bf3_add_summary_to_resource.py",
    "content": "\"\"\"add summary to resource\n\nRevision ID: c02f3d759bf3\nRevises: 1d54db311055\nCreate Date: 2023-06-27 05:07:29.016704\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = 'c02f3d759bf3'\ndown_revision = 'c5c19944c90c'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ##\n    op.add_column('resources', sa.Column('summary', sa.Text(), nullable=True))\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.drop_column('resources', 'summary')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/c4f2f6ba602a_agent_workflow_wait_step.py",
    "content": "\"\"\"agent_workflow_wait_step\n\nRevision ID: c4f2f6ba602a\nRevises: 40affbf3022b\nCreate Date: 2023-09-04 05:34:10.195248\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = 'c4f2f6ba602a'\ndown_revision = '40affbf3022b'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.create_table('agent_workflow_step_waits',\n    sa.Column('id', sa.Integer(), nullable=False),\n    sa.Column('name', sa.String(), nullable=True),\n    sa.Column('description', sa.String(), nullable=True),\n    sa.Column('unique_id', sa.String(), nullable=True),\n    sa.Column('delay', sa.Integer(), nullable=True),\n    sa.Column('wait_begin_time', sa.DateTime(), nullable=True),\n    sa.Column('status', sa.String(), nullable=True),\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.PrimaryKeyConstraint('id')\n    )\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.drop_table('agent_workflow_step_waits')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/c5c19944c90c_create_oauth_tokens.py",
    "content": "\"\"\"Create Oauth Tokens\n\nRevision ID: c5c19944c90c\nRevises: 7a3e336c0fba\nCreate Date: 2023-06-30 07:26:29.180784\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = 'c5c19944c90c'\ndown_revision = '7a3e336c0fba'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.create_table('oauth_tokens',\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),\n    sa.Column('user_id', sa.Integer(), nullable=True),\n    sa.Column('organisation_id', sa.Integer(), nullable=True),\n    sa.Column('toolkit_id', sa.Integer(), nullable=True),\n    sa.Column('key', sa.String(), nullable=True),\n    sa.Column('value', sa.Text(), nullable=True),\n    sa.PrimaryKeyConstraint('id')\n    )\n    op.drop_index('ix_agent_execution_permissions_agent_execution_id', table_name='agent_execution_permissions')\n    op.drop_index('ix_atc_agnt_template_id_key', table_name='agent_template_configs')\n    op.drop_index('ix_agt_agnt_name', table_name='agent_templates')\n    op.drop_index('ix_agt_agnt_organisation_id', table_name='agent_templates')\n    op.drop_index('ix_agt_agnt_workflow_id', table_name='agent_templates')\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.create_index('ix_agt_agnt_workflow_id', 'agent_templates', ['agent_workflow_id'], unique=False)\n    op.create_index('ix_agt_agnt_organisation_id', 'agent_templates', ['organisation_id'], unique=False)\n    op.create_index('ix_agt_agnt_name', 'agent_templates', ['name'], unique=False)\n    op.create_index('ix_atc_agnt_template_id_key', 'agent_template_configs', ['agent_template_id', 'key'], unique=False)\n    op.create_index('ix_agent_execution_permissions_agent_execution_id', 'agent_execution_permissions', ['agent_execution_id'], unique=False)\n    op.drop_table('oauth_tokens')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/cac478732572_delete_agent_feature.py",
    "content": "\"\"\"delete_agent_feature\n\nRevision ID: cac478732572\nRevises: e39295ec089c\nCreate Date: 2023-07-13 17:18:42.003412\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n# revision identifiers, used by Alembic.\nrevision = 'cac478732572'\ndown_revision = 'e39295ec089c'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    op.add_column('agents', sa.Column('is_deleted', sa.Boolean(), nullable=True, server_default=sa.false()))\n\n\ndef downgrade() -> None:\n    op.drop_column('agents', 'is_deleted')\n"
  },
  {
    "path": "migrations/versions/d8315244ea43_updated_tool_configs.py",
    "content": "\"\"\"updated_tool_configs\n\nRevision ID: d8315244ea43\nRevises: 71e3980d55f5\nCreate Date: 2023-08-01 11:11:32.725355\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = 'd8315244ea43'\ndown_revision = '71e3980d55f5'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.add_column('tool_configs', sa.Column('key_type', sa.String(), nullable=True))\n    op.add_column('tool_configs', sa.Column('is_secret', sa.Boolean(), nullable=True))\n    op.add_column('tool_configs', sa.Column('is_required', sa.Boolean(), nullable=True))\n    # ### end Alembic commands ###\n\n\ndef downgrade() -> None:\n    # ### commands auto generated by Alembic - please adjust! ###\n    op.drop_column('tool_configs', 'is_required')\n    op.drop_column('tool_configs', 'is_secret')\n    op.drop_column('tool_configs', 'key_type')\n    # ### end Alembic commands ###\n"
  },
  {
    "path": "migrations/versions/d9b3436197eb_renaming_templates.py",
    "content": "\"\"\"renaming templates\n\nRevision ID: d9b3436197eb\nRevises: 3356a2f89a33\nCreate Date: 2023-06-10 09:28:28.262705\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = 'd9b3436197eb'\ndown_revision = '3356a2f89a33'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    op.rename_table('agent_templates', 'agent_workflows')\n    op.rename_table('agent_template_steps', 'agent_workflow_steps')\n    with op.batch_alter_table('agent_workflow_steps') as bop:\n        bop.alter_column('agent_template_id', new_column_name='agent_workflow_id')\n    with op.batch_alter_table('agents') as bop:\n        bop.alter_column('agent_template_id', new_column_name='agent_workflow_id')\n\n\ndef downgrade() -> None:\n    op.rename_table('agent_workflows', 'agent_templates')\n    op.rename_table('agent_workflow_steps', 'agent_template_steps')\n    with op.batch_alter_table('agent_templates') as bop:\n        bop.alter_column('agent_workflow_id', new_column_name='agent_template_id')\n    with op.batch_alter_table('agents') as bop:\n        bop.alter_column('agent_workflow_id', new_column_name='agent_template_id')\n"
  },
  {
    "path": "migrations/versions/e39295ec089c_creating_events.py",
    "content": "\"\"\"creating events\n\nRevision ID: e39295ec089c\nRevises: 7a3e336c0fba\nCreate Date: 2023-06-30 12:23:12.269999\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\nfrom sqlalchemy.dialects import postgresql\n\n# revision identifiers, used by Alembic.\nrevision = 'e39295ec089c'\ndown_revision = '467e85d5e1cd'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    op.create_table('events',\n    sa.Column('created_at', sa.DateTime(), nullable=True),\n    sa.Column('updated_at', sa.DateTime(), nullable=True),\n    sa.Column('id', sa.Integer(), nullable=False),\n    sa.Column('event_name', sa.String(), nullable=False),\n    sa.Column('event_value', sa.Integer(), nullable=False),\n    sa.Column('event_property', postgresql.JSONB(astext_type=sa.Text()), nullable=True),\n    sa.Column('agent_id', sa.Integer(), nullable=True),\n    sa.Column('org_id', sa.Integer(), nullable=True),\n    sa.PrimaryKeyConstraint('id')\n    )\n\n    # Use naming convention similar to the reference code for the index creation\n    op.create_index(op.f('ix_events_agent_id'), 'events', ['agent_id'], unique=False)\n    op.create_index(op.f('ix_events_org_id'), 'events', ['org_id'], unique=False)\n    op.create_index(op.f('ix_events_event_property'), 'events', ['event_property'], unique=False)\n\ndef downgrade() -> None:\n    op.drop_index(op.f('ix_events_event_property'), table_name='events')\n    op.drop_index(op.f('ix_events_org_id'), table_name='events')\n    op.drop_index(op.f('ix_events_agent_id'), table_name='events')\n    op.drop_table('events')"
  },
  {
    "path": "migrations/versions/fe234ea6e9bc_modify_agent_workflow_tables.py",
    "content": "\"\"\"update agent workflow tables\n\nRevision ID: fe234ea6e9bc\nRevises: d8315244ea43\nCreate Date: 2023-07-18 16:46:29.305378\n\n\"\"\"\nfrom alembic import op\nimport sqlalchemy as sa\n\n\n# revision identifiers, used by Alembic.\nrevision = 'fe234ea6e9bc'\ndown_revision = 'd8315244ea43'\nbranch_labels = None\ndepends_on = None\n\n\ndef upgrade() -> None:\n    op.rename_table('agent_workflows', 'iteration_workflows')\n    op.rename_table('agent_workflow_steps', 'iteration_workflow_steps')\n\n    with op.batch_alter_table('iteration_workflow_steps') as bop:\n        bop.alter_column('agent_workflow_id', new_column_name='iteration_workflow_id')\n\n    with op.batch_alter_table('agent_executions') as bop:\n        bop.alter_column('current_step_id', new_column_name='current_agent_step_id')\n\n\n    op.add_column('agent_executions', sa.Column('iteration_workflow_step_id', sa.Integer(), nullable=True))\n    op.add_column('iteration_workflows',\n                  sa.Column('has_task_queue', sa.Boolean(), nullable=True, server_default=sa.false()))\n\n\ndef downgrade() -> None:\n    op.rename_table('iteration_workflows', 'agent_workflows')\n    op.rename_table('iteration_workflow_steps', 'agent_workflow_steps')\n    op.drop_column('agent_executions', 'iteration_workflow_step_id')\n    op.drop_column('agent_workflows', 'has_task_queue')\n"
  },
  {
    "path": "nginx/default.conf",
    "content": "server {\n  listen 80;\n\n  location / {\n    proxy_pass http://gui:3000;\n    proxy_set_header Host $host;\n    proxy_set_header X-Real-IP $remote_addr;\n    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n  }\n\n  location /api {\n    proxy_pass http://backend:8001;\n    client_max_body_size 50M;\n    proxy_set_header Host $host;\n    proxy_set_header X-Real-IP $remote_addr;\n    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    rewrite ^/api/(.*) /$1 break;\n  }\n  location /_next/webpack-hmr {\n    proxy_pass http://gui:3000;\n    proxy_http_version 1.1;\n    proxy_set_header Upgrade $http_upgrade;\n    proxy_set_header Connection \"upgrade\";\n    proxy_set_header Host $host;\n    proxy_cache_bypass $http_upgrade;\n}\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"dependencies\": {\n    \"axios\": \"^1.4.0\",\n    \"react-toastify\": \"^9.1.3\"\n  }\n}\n"
  },
  {
    "path": "requirements.txt",
    "content": "aiohttp==3.8.4\naiosignal==1.3.1\nalembic==1.11.1\namqp==5.1.1\nanyio==3.7.0\napiclient==1.0.4\nappdirs==1.4.4\nasync-timeout==4.0.2\nattrs==23.1.0\nbeautifulsoup4==4.12.2\nbilliard==3.6.4.0\nboto3==1.26.146\nbotocore==1.29.146\nbs4==0.0.1\ncelery==5.2.7\ncertifi==2023.5.7\ncffi==1.15.1\ncharset-normalizer==3.1.0\nclick==8.1.3\nclick-didyoumean==0.3.0\nclick-plugins==1.1.1\nclick-repl==0.2.0\ncolorama==0.4.6\nconfluent-kafka==2.1.1\ncryptography==41.0.1\ncssselect==1.2.0\nchromadb==0.3.26\ndataclasses-json==0.5.7\ndefusedxml==0.7.1\ndocx2txt==0.8\ndnspython==2.3.0\nemail-validator==2.0.0.post2\nexceptiongroup==1.1.1\nfake-useragent==1.1.3\nfastapi==0.95.2\nfastapi-jwt-auth==0.5.0\nFastAPI-SQLAlchemy==0.2.1\nfeedfinder2==0.0.4\nfeedparser==6.0.10\nfilelock==3.12.0\nfrozenlist==1.3.3\ngoogle-search-results==2.4.2\ngoogle-serp-api==1.0.3\ngoogle-api-core==2.11.0\ngoogle-api-python-client==2.88.0\ngoogle-auth==2.19.1\ngoogle-auth-httplib2==0.1.0\ngoogle-auth-oauthlib==1.0.0\ngreenlet==2.0.2\nh11==0.14.0\nhalo==0.0.31\nhttpcore==0.17.2\nhttptools==0.5.0\nhttpx==0.24.1\nidna==3.4\nimportlib-metadata==6.6.0\nimportlib-resources==5.12.0\nitsdangerous==2.1.2\njieba3k==0.35.1\nJinja2==3.1.2\njira==3.5.0\njmespath==1.0.1\njoblib==1.2.0\njson5==0.9.14\njsonmerge==1.9.0\njsonschema==4.17.3\nkombu==5.2.4\nllama-index==0.6.35\nlog-symbols==0.0.14\nloguru==0.7.0\nlxml==4.9.2\nMako==1.2.4\nMarkupSafe==2.1.2\nmarshmallow==3.19.0\nmarshmallow-enum==1.5.1\nmultidict==6.0.4\nmypy-extensions==1.0.0\nnewspaper3k==0.2.8\nnltk==3.8.1\nnumexpr==2.8.4\nnumpy==1.24.3\noauthlib==3.2.2\noauth2client==4.1.3\nopenai==0.27.7\nopenapi-schema-pydantic==1.2.4\norjson==3.8.14\npackaging==23.1\nparse==1.19.0\nPillow==9.5.0\npinecone-client==2.2.1\nprompt-toolkit==3.0.38\npsycopg2==2.9.6\npycparser==2.21\npydantic==1.10.8\nPyJWT==1.7.1\nPyPDF2==3.0.1\npyquery==2.0.0\npyrsistent==0.19.3\npytest==7.3.2\npython-dateutil==2.8.2\npython-dotenv==1.0.0\npython-multipart==0.0.6\npytz==2023.3\nPyYAML==6.0\nqdrant-client==1.3.1\nredis==4.5.5\nregex==2023.5.5\nreplicate==0.8.4\nrequests==2.31.0\nrequests-file==1.5.1\nrequests-html==0.10.0\nrequests-oauthlib==1.3.1\nrequests-toolbelt==1.0.0\ns3transfer==0.6.1\nsafetensors==0.3.2\nsgmllib3k==1.0.0\nsix==1.16.0\nsniffio==1.3.0\nsoupsieve==2.4.1\nspinners==0.0.24\nstarlette==0.27.0\nSQLAlchemy==2.0.16\ntenacity==8.2.2\ntermcolor==2.3.0\ntiktoken==0.4.0\ntinysegmenter==0.3\ntldextract==3.4.4\ntqdm==4.65.0\ntweepy==4.14.0\ntyping-inspect==0.8.0\nujson==5.7.0\nurllib3==1.26.16\nuvicorn==0.22.0\nvine==5.0.0\nw3lib==2.1.1\nwatchfiles==0.19.0\nwcwidth==0.2.6\nweaviate-client==3.20.1\nwebsockets==10.4\nyarl==1.9.2\nzipp==3.15.0\ntiktoken==0.4.0\npsycopg2==2.9.6\nslack-sdk==3.21.3\npytest==7.3.2\npylint==2.17.4\npre-commit==3.3.3\npytest-cov==4.1.0\npytest-mock==3.11.1\ntransformers==4.30.2\npypdf==3.11.0\npython-pptx==0.6.21\nPillow==9.5.0\nEbookLib==0.18\nhtml2text==2020.1.16\nduckduckgo-search==3.8.3 \ngoogle-generativeai==0.1.0\nunstructured==0.8.1\nai21==1.2.6\ntyping-extensions==4.5.0\nllama_cpp_python==0.2.7"
  },
  {
    "path": "run.bat",
    "content": "@echo off\necho Checking if config.yaml file exists...\nif not exist config.yaml (\n    echo ERROR: config.yaml file not found. Please create the config.yaml file.\n    exit /b 1\n)\necho Checking if virtual environment is activated...\nif not defined VIRTUAL_ENV (\n    echo Virtual environment not activated. Creating and activating virtual environment...\n    python3 -m venv venv\n    if errorlevel 1 (\n      echo Error: Failed to create virtual environment.\n      exit /b 1\n    )\n    call venv\\Scripts\\activate.bat\n) else (\n    echo Virtual environment is already activated.\n)\necho Checking requirements...\npip show -r requirements.txt >nul 2>&1\nif errorlevel 1 (\n    echo Installing requirements...\n    pip install -r requirements.txt >nul 2>&1\n) else (\n    echo All packages are already installed.\n)\necho Running test.py with python...\npython test.py\nif errorlevel 1 (\n    echo Running test.py with python3...\n    python3 test.py\n)"
  },
  {
    "path": "run.sh",
    "content": "#!/bin/bash\n\n# Check if config.yaml file exists\nif [ ! -f \"config.yaml\" ]; then\n    echo \"ERROR: config.yaml file not found. Please create the config.yaml file.\"\n    exit 1\nfi\n\nif [ ! -f \"tgwui/text-generation-webui\" ]; then\n    echo \"Downloading tgwui src\"\n    git clone https://github.com/oobabooga/text-generation-webui\n    mv text-generation-webui tgwui\nfi\n\n# Function to check if virtual environment is activated\nis_venv_activated() {\n    [[ -n \"$VIRTUAL_ENV\" ]]\n}\n\n# Check if virtual environment is activated\nif ! is_venv_activated; then\n    echo \"Virtual environment not activated. Creating and activating virtual environment...\"\n\n    # Create virtual environment\n    python3 -m venv venv\n\n    # Activate virtual environment based on the operating system\n    if [[ \"$OSTYPE\" == \"darwin\"* ]]; then\n        source venv/bin/activate\n    else\n        source venv/bin/activate\n    fi\nelse\n    echo \"Virtual environment is already activated.\"\nfi\n\n# Activate virtual environment\nif ! is_venv_activated; then\n    echo \"Activating virtual environment...\"\n    source venv/bin/activate\nfi\n\n# Check if requirements are already installed\necho \"Checking requirements...\"\nif ! pip show -r requirements.txt >/dev/null 2>&1; then\n    echo \"Installing requirements...\"\n    pip install -r requirements.txt >/dev/null 2>&1\nelse\n    echo \"All packages are already installed.\"\nfi\n\n# Run test.py using python\n#echo \"Running test.py with python...\"\n#python test.py\n#\n## If the above command fails, run test.py using python3\n#if [ $? -ne 0 ]; then\n#    echo \"Running test.py with python3...\"\n#    python3 test.py\n#fi\n\n\nif [ \"$1\" = \"ui\" ]; then\n    echo \"Running UI...\"\n    python ui.py\n    if [ $? -ne 0 ]; then\n        echo \"Running UI with python3...\"\n        python3 ui.py\n    fi\nfi\nif [ \"$1\" = \"cli\" ]; then\n    echo \"Running superagi cli...\"\n    python cli2.py\n\n    # If the above command fails, run test.py using python3\n    if [ $? -ne 0 ]; then\n        echo \"Running superagi cli...\"\n        python3 cli2.py\n    fi\nfi"
  },
  {
    "path": "run_gui.py",
    "content": "import os\nimport sys\nimport subprocess\nfrom time import sleep\nimport shutil\nfrom superagi.lib.logger import logger\n\ndef check_command(command, message):\n    if not shutil.which(command):\n        logger.info(message)\n        sys.exit(1)\n\ndef run_npm_commands():\n    os.chdir(\"gui\")\n    try:\n        subprocess.run([\"npm\", \"install\"], check=True)\n    except subprocess.CalledProcessError:\n        logger.error(f\"Error during '{' '.join(sys.exc_info()[1].cmd)}'. Exiting.\")\n        sys.exit(1)\n    os.chdir(\"..\")\n\ndef run_server():\n    api_process = subprocess.Popen([\"uvicorn\", \"main:app\", \"--host\", \"0.0.0.0\", \"--port\", \"8000\"])\n    os.chdir(\"gui\")\n    ui_process = subprocess.Popen([\"npm\", \"run\", \"dev\"])\n    os.chdir(\"..\")\n    return api_process, ui_process\n\ndef cleanup(api_process, ui_process):\n    logger.info(\"Shutting down processes...\")\n    api_process.terminate()\n    ui_process.terminate()\n    logger.info(\"Processes terminated. Exiting.\")\n    sys.exit(1)\n\nif __name__ == \"__main__\":\n    check_command(\"node\", \"Node.js is not installed. Please install it and try again.\")\n    check_command(\"npm\", \"npm is not installed. Please install npm to proceed.\")\n    check_command(\"uvicorn\", \"uvicorn is not installed. Please install uvicorn to proceed.\")\n\n    run_npm_commands()\n\n    try:\n        api_process, ui_process = run_server()\n        while True:\n            try:\n                sleep(30)\n            except KeyboardInterrupt:\n                cleanup(api_process, ui_process)\n    except Exception as e:\n        cleanup(api_process, ui_process)"
  },
  {
    "path": "run_gui.sh",
    "content": "#!/bin/bash\n\napi_process=\"\"\nui_process=\"\"\n\nfunction check_command() {\n  command -v \"$1\" >/dev/null 2>&1\n  if [ $? -ne 0 ]; then\n    echo \"$1 is not installed. Please install $1 to proceed.\"\n    exit 1\n  fi\n}\n\nfunction run_npm_commands() {\n  cd gui\n  npm install\n  if [ $? -ne 0 ]; then\n    echo \"Error during 'npm install'. Exiting.\"\n    exit 1\n  fi\n\n  npm run build\n  if [ $? -ne 0 ]; then\n    echo \"Error during 'npm run build'. Exiting.\"\n    exit 1\n  fi\n\n  cd ..\n}\n\nfunction run_server() {\n  uvicorn main:app --host 0.0.0.0 --port 8000 &\n  api_process=$!\n  cd gui && npm run dev &\n  ui_process=$!\n}\n\nfunction cleanup() {\n  echo \"Shutting down processes...\"\n  kill $api_process\n  kill $ui_process\n  echo \"Processes terminated. Exiting.\"\n  exit 1\n}\n\ntrap cleanup SIGINT\n\ncheck_command \"node\"\ncheck_command \"npm\"\ncheck_command \"uvicorn\"\n\nrun_npm_commands\nrun_server\n\nwait $api_process"
  },
  {
    "path": "superagi/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/agent/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/agent/agent_iteration_step_handler.py",
    "content": "from datetime import datetime\nimport json\nfrom sqlalchemy import asc\nfrom sqlalchemy.sql.operators import and_\nimport logging\nimport superagi\nfrom superagi.agent.agent_message_builder import AgentLlmMessageBuilder\nfrom superagi.agent.agent_prompt_builder import AgentPromptBuilder\nfrom superagi.agent.output_handler import ToolOutputHandler, get_output_handler\nfrom superagi.agent.task_queue import TaskQueue\nfrom superagi.agent.tool_builder import ToolBuilder\nfrom superagi.apm.event_handler import EventHandler\nfrom superagi.config.config import get_config\nfrom superagi.helper.error_handler import ErrorHandler\nfrom superagi.helper.token_counter import TokenCounter\nfrom superagi.lib.logger import logger\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_config import AgentExecutionConfiguration\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nfrom superagi.models.agent_execution_permission import AgentExecutionPermission\nfrom superagi.models.organisation import Organisation\nfrom superagi.models.tool import Tool\nfrom superagi.models.workflows.agent_workflow import AgentWorkflow\nfrom superagi.models.workflows.agent_workflow_step import AgentWorkflowStep\nfrom superagi.models.workflows.iteration_workflow import IterationWorkflow\nfrom superagi.models.workflows.iteration_workflow_step import IterationWorkflowStep\nfrom superagi.resource_manager.resource_summary import ResourceSummarizer\nfrom superagi.tools.resource.query_resource import QueryResourceTool\nfrom superagi.tools.thinking.tools import ThinkingTool\nfrom superagi.apm.call_log_helper import CallLogHelper\n\n\nclass AgentIterationStepHandler:\n    \"\"\" Handles iteration workflow steps in the agent workflow.\"\"\"\n    def __init__(self, session, llm, agent_id: int, agent_execution_id: int, memory=None):\n        self.session = session\n        self.llm = llm\n        self.agent_execution_id = agent_execution_id\n        self.agent_id = agent_id\n        self.memory = memory\n        self.organisation = Agent.find_org_by_agent_id(self.session, agent_id=self.agent_id)\n        self.task_queue = TaskQueue(str(self.agent_execution_id))\n\n    def execute_step(self):\n        agent_config = Agent.fetch_configuration(self.session, self.agent_id)\n        execution = AgentExecution.get_agent_execution_from_id(self.session, self.agent_execution_id)\n        iteration_workflow_step = IterationWorkflowStep.find_by_id(self.session, execution.iteration_workflow_step_id)\n        agent_execution_config = AgentExecutionConfiguration.fetch_configuration(self.session, self.agent_execution_id)\n        if not self._handle_wait_for_permission(execution, agent_config, agent_execution_config,\n                                                iteration_workflow_step):\n            return\n\n        workflow_step = AgentWorkflowStep.find_by_id(self.session, execution.current_agent_step_id)\n        organisation = Agent.find_org_by_agent_id(self.session, agent_id=self.agent_id)\n        iteration_workflow = IterationWorkflow.find_by_id(self.session, workflow_step.action_reference_id)\n        agent_feeds = AgentExecutionFeed.fetch_agent_execution_feeds(self.session, self.agent_execution_id)\n        if not agent_feeds:\n            self.task_queue.clear_tasks()\n\n        agent_tools = self._build_tools(agent_config, agent_execution_config)\n        prompt = self._build_agent_prompt(iteration_workflow=iteration_workflow,\n                                          agent_config=agent_config,\n                                          agent_execution_config=agent_execution_config,\n                                          prompt=iteration_workflow_step.prompt,\n                                          agent_tools=agent_tools)\n\n        messages = AgentLlmMessageBuilder(self.session, self.llm, self.llm.get_model(), self.agent_id, self.agent_execution_id) \\\n            .build_agent_messages(prompt, agent_feeds, history_enabled=iteration_workflow_step.history_enabled,\n                                  completion_prompt=iteration_workflow_step.completion_prompt)\n\n        logger.debug(\"Prompt messages:\", messages)\n        current_tokens = TokenCounter.count_message_tokens(messages = messages, model = self.llm.get_model())\n        response = self.llm.chat_completion(messages, TokenCounter(session=self.session, organisation_id=organisation.id).token_limit(self.llm.get_model()) - current_tokens)\n\n        if 'error' in response and response['message'] is not None:\n            ErrorHandler.handle_openai_errors(self.session, self.agent_id, self.agent_execution_id, response['message'])\n            \n        if 'content' not in response or response['content'] is None:\n            raise RuntimeError(f\"Failed to get response from llm\")\n\n        total_tokens = current_tokens + TokenCounter.count_message_tokens(response['content'], self.llm.get_model())\n        AgentExecution.update_tokens(self.session, self.agent_execution_id, total_tokens)\n        try:\n            content = json.loads(response['content'])\n            tool = content.get('tool', {})\n            tool_name = tool.get('name', '') if tool else ''\n        except json.JSONDecodeError:\n            print(\"Decoding JSON has failed\")\n            tool_name = ''\n\n        CallLogHelper(session=self.session, organisation_id=organisation.id).create_call_log(execution.name,\n                                                                                             agent_config['agent_id'], total_tokens, tool_name, agent_config['model'])\n\n        assistant_reply = response['content']\n        output_handler = get_output_handler(iteration_workflow_step.output_type,\n                                            agent_execution_id=self.agent_execution_id,\n                                            agent_config=agent_config,memory=self.memory, agent_tools=agent_tools)\n        response = output_handler.handle(self.session, assistant_reply)\n        if response.status == \"COMPLETE\":\n            execution.status = \"COMPLETED\"\n            self.session.commit()\n\n            self._update_agent_execution_next_step(execution, iteration_workflow_step.next_step_id, \"COMPLETE\")\n            EventHandler(session=self.session).create_event('run_completed',\n                                                            {'agent_execution_id': execution.id,\n                                                             'name': execution.name,\n                                                             'tokens_consumed': execution.num_of_tokens,\n                                                             \"calls\": execution.num_of_calls},\n                                                            execution.agent_id, organisation.id)\n        elif response.status == \"WAITING_FOR_PERMISSION\":\n            execution.status = \"WAITING_FOR_PERMISSION\"\n            execution.permission_id = response.permission_id\n            self.session.commit()\n        else:\n            # moving to next step of iteration or workflow\n            self._update_agent_execution_next_step(execution, iteration_workflow_step.next_step_id)\n            logger.info(f\"Starting next job for agent execution id: {self.agent_execution_id}\")\n\n        self.session.flush()\n\n    def _update_agent_execution_next_step(self, execution, next_step_id, step_response: str = \"default\"):\n        if next_step_id == -1:\n            next_step = AgentWorkflowStep.fetch_next_step(self.session, execution.current_agent_step_id, step_response)\n            if str(next_step) == \"COMPLETE\":\n                execution.current_agent_step_id = -1\n                execution.status = \"COMPLETED\"\n            else:\n                AgentExecution.assign_next_step_id(self.session, self.agent_execution_id, next_step.id)\n        else:\n            execution.iteration_workflow_step_id = next_step_id\n        self.session.commit()\n\n    def _build_agent_prompt(self, iteration_workflow: IterationWorkflow, agent_config: dict,\n                            agent_execution_config: dict,\n                            prompt: str, agent_tools: list):\n        max_token_limit = int(get_config(\"MAX_TOOL_TOKEN_LIMIT\", 600))\n        prompt = AgentPromptBuilder.replace_main_variables(prompt, agent_execution_config[\"goal\"],\n                                                           agent_execution_config[\"instruction\"],\n                                                           agent_config[\"constraints\"], agent_tools,\n                                                           (not iteration_workflow.has_task_queue))\n        if iteration_workflow.has_task_queue:\n            response = self.task_queue.get_last_task_details()\n            last_task, last_task_result = (response[\"task\"], response[\"response\"]) if response is not None else (\"\", \"\")\n            current_task = self.task_queue.get_first_task() or \"\"\n            token_limit = TokenCounter(session=self.session, organisation_id=self.organisation.id).token_limit() - max_token_limit\n            prompt = AgentPromptBuilder.replace_task_based_variables(prompt, current_task, last_task, last_task_result,\n                                                                     self.task_queue.get_tasks(),\n                                                                     self.task_queue.get_completed_tasks(), token_limit)\n        return prompt\n\n    def _build_tools(self, agent_config: dict, agent_execution_config: dict):\n        agent_tools = [ThinkingTool()]\n\n        config_data = AgentConfiguration.get_model_api_key(self.session, self.agent_id, agent_config[\"model\"])\n        model_api_key = config_data['api_key']\n        tool_builder = ToolBuilder(self.session, self.agent_id, self.agent_execution_id)\n        resource_summary = ResourceSummarizer(session=self.session, agent_id=self.agent_id, model=agent_config['model']).fetch_or_create_agent_resource_summary(default_summary=agent_config.get(\"resource_summary\"))\n        if resource_summary is not None:\n            agent_tools.append(QueryResourceTool())\n        user_tools = self.session.query(Tool).filter(\n            and_(Tool.id.in_(agent_execution_config[\"tools\"]), Tool.file_name is not None)).all()\n        for tool in user_tools:\n            agent_tools.append(tool_builder.build_tool(tool))\n        agent_tools = [tool_builder.set_default_params_tool(tool, agent_config, agent_execution_config,\n                                                            model_api_key, resource_summary,self.memory) for tool in agent_tools]\n        return agent_tools\n\n    def _handle_wait_for_permission(self, agent_execution, agent_config: dict, agent_execution_config: dict,\n                                    iteration_workflow_step: IterationWorkflowStep):\n        \"\"\"\n        Handles the wait for permission when the agent execution is waiting for permission.\n\n        Args:\n            agent_execution (AgentExecution): The agent execution.\n            agent_config (dict): The agent configuration.\n            agent_execution_config (dict): The agent execution configuration.\n            iteration_workflow_step (IterationWorkflowStep): The iteration workflow step.\n\n        Raises:\n            Returns permission success or failure\n        \"\"\"\n        if agent_execution.status != \"WAITING_FOR_PERMISSION\":\n            return True\n        agent_execution_permission = self.session.query(AgentExecutionPermission).filter(\n            AgentExecutionPermission.id == agent_execution.permission_id).first()\n        if agent_execution_permission.status == \"PENDING\":\n            logger.error(\"handle_wait_for_permission: Permission is still pending\")\n            return False\n        if agent_execution_permission.status == \"APPROVED\":\n            agent_tools = self._build_tools(agent_config, agent_execution_config)\n            tool_output_handler = ToolOutputHandler(self.agent_execution_id, agent_config, agent_tools,self.memory)\n            tool_result = tool_output_handler.handle_tool_response(self.session,\n                                                                   agent_execution_permission.assistant_reply)\n            result = tool_result.result\n        else:\n            result = f\"User denied the permission to run the tool {agent_execution_permission.tool_name}\" \\\n                     f\"{' and has given the following feedback : ' + agent_execution_permission.user_feedback if agent_execution_permission.user_feedback else ''}\"\n\n        agent_execution_feed = AgentExecutionFeed(agent_execution_id=agent_execution_permission.agent_execution_id,\n                                                  agent_id=agent_execution_permission.agent_id,\n                                                  feed=agent_execution_permission.assistant_reply,\n                                                  role=\"assistant\",\n                                                  feed_group_id=agent_execution.current_feed_group_id)\n        self.session.add(agent_execution_feed)\n        agent_execution_feed1 = AgentExecutionFeed(agent_execution_id=agent_execution_permission.agent_execution_id,\n                                                  agent_id=agent_execution_permission.agent_id,\n                                                  feed=result, role=\"user\",\n                                                  feed_group_id=agent_execution.current_feed_group_id)\n        self.session.add(agent_execution_feed1)\n        agent_execution.status = \"RUNNING\"\n        execution = AgentExecution.find_by_id(self.session, agent_execution_permission.agent_execution_id)\n        self._update_agent_execution_next_step(execution, iteration_workflow_step.next_step_id)\n        self.session.commit()\n\n\n        return True\n"
  },
  {
    "path": "superagi/agent/agent_message_builder.py",
    "content": "import time\nfrom typing import Tuple, List\nfrom sqlalchemy import asc\n\nfrom superagi.config.config import get_config\nfrom superagi.helper.error_handler import ErrorHandler\nfrom superagi.helper.prompt_reader import PromptReader\nfrom superagi.helper.token_counter import TokenCounter\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nfrom superagi.types.common import BaseMessage\nfrom superagi.models.agent_execution_config import AgentExecutionConfiguration\nfrom superagi.models.agent import Agent\n\n\nclass AgentLlmMessageBuilder:\n    \"\"\"Agent message builder for LLM agent.\"\"\"\n    def __init__(self, session, llm, llm_model: str, agent_id: int, agent_execution_id: int):\n        self.session = session\n        self.llm = llm\n        self.llm_model = llm_model\n        self.agent_id = agent_id\n        self.agent_execution_id = agent_execution_id\n        self.organisation = Agent.find_org_by_agent_id(self.session, self.agent_id)\n\n    def build_agent_messages(self, prompt: str, agent_feeds: list, history_enabled=False,\n                             completion_prompt: str = None):\n        \"\"\" Build agent messages for LLM agent.\n\n        Args:\n            prompt (str): The prompt to be used for generating the agent messages.\n            agent_feeds (list): The list of agent feeds.\n            history_enabled (bool): Whether to use history or not.\n            completion_prompt (str): The completion prompt to be used for generating the agent messages.\n        \"\"\"\n        token_limit = TokenCounter(session=self.session, organisation_id=self.organisation.id).token_limit(self.llm_model)\n        max_output_token_limit = int(get_config(\"MAX_TOOL_TOKEN_LIMIT\", 800))\n        messages = [{\"role\": \"system\", \"content\": prompt}]\n        if history_enabled:\n            messages.append({\"role\": \"system\", \"content\": f\"The current time and date is {time.strftime('%c')}\"})\n            base_token_limit = TokenCounter.count_message_tokens(messages, self.llm_model)\n            full_message_history = [{'role': agent_feed.role, 'content': agent_feed.feed, 'chat_id': agent_feed.id}\n                                                for agent_feed in agent_feeds]\n            past_messages, current_messages = self._split_history(full_message_history,\n                                                              ((token_limit - base_token_limit - max_output_token_limit) // 4) * 3)\n            if past_messages:\n                ltm_summary = self._build_ltm_summary(past_messages=past_messages,\n                                                                   output_token_limit=(token_limit - base_token_limit - max_output_token_limit) // 4)\n                messages.append({\"role\": \"assistant\", \"content\": ltm_summary})\n\n            for history in current_messages:\n                messages.append({\"role\": history[\"role\"], \"content\": history[\"content\"]})\n            messages.append({\"role\": \"user\", \"content\": completion_prompt})\n\n        # insert initial agent feeds\n        self._add_initial_feeds(agent_feeds, messages)\n        return messages\n\n    def _split_history(self, history: List, pending_token_limit: int) -> Tuple[List[BaseMessage], List[BaseMessage]]:\n        hist_token_count = 0\n        i = len(history)\n        for message in reversed(history):\n            token_count = TokenCounter.count_message_tokens([{\"role\": message[\"role\"], \"content\": message[\"content\"]}],\n                                                            self.llm_model)\n            hist_token_count += token_count\n            if hist_token_count > pending_token_limit:\n                self._add_or_update_last_agent_feed_ltm_summary_id(str(history[i-1]['chat_id']))\n                return history[:i], history[i:]\n            i -= 1\n        return [], history\n\n    def _add_initial_feeds(self, agent_feeds: list, messages: list):\n        if agent_feeds:\n            return\n        for message in messages:\n            agent_execution_feed = AgentExecutionFeed(agent_execution_id=self.agent_execution_id,\n                                                      agent_id=self.agent_id,\n                                                      feed=message[\"content\"],\n                                                      role=message[\"role\"],\n                                                      feed_group_id=\"DEFAULT\")\n            self.session.add(agent_execution_feed)\n            self.session.commit()\n\n    def _add_or_update_last_agent_feed_ltm_summary_id(self, last_agent_feed_ltm_summary_id):\n        execution = AgentExecution(id=self.agent_execution_id)\n        agent_execution_configs = {\"last_agent_feed_ltm_summary_id\": last_agent_feed_ltm_summary_id}\n        AgentExecutionConfiguration.add_or_update_agent_execution_config(self.session, execution,\n                                                                         agent_execution_configs)\n\n\n    def _build_ltm_summary(self, past_messages, output_token_limit) -> str:\n        ltm_prompt = self._build_prompt_for_ltm_summary(past_messages=past_messages,\n                                                        token_limit=output_token_limit)\n\n        summary = AgentExecutionConfiguration.fetch_value(self.session, self.agent_execution_id, \"ltm_summary\")\n        previous_ltm_summary = summary.value if summary is not None else \"\"\n\n        ltm_summary_base_token_limit = 10\n        if ((TokenCounter.count_text_tokens(ltm_prompt) + ltm_summary_base_token_limit + output_token_limit)\n            - TokenCounter(session=self.session, organisation_id=self.organisation.id).token_limit(self.llm_model)) > 0:\n            last_agent_feed_ltm_summary_id = AgentExecutionConfiguration.fetch_value(self.session,\n                                                       self.agent_execution_id, \"last_agent_feed_ltm_summary_id\")\n            last_agent_feed_ltm_summary_id = (\n                int(last_agent_feed_ltm_summary_id.value)\n                if last_agent_feed_ltm_summary_id is not None and last_agent_feed_ltm_summary_id.value is not None\n                else 0\n            )\n            past_messages = self.session.query(AgentExecutionFeed.role, AgentExecutionFeed.feed,\n                                               AgentExecutionFeed.id) \\\n                .filter(AgentExecutionFeed.agent_execution_id == self.agent_execution_id,\n                        AgentExecutionFeed.id > last_agent_feed_ltm_summary_id) \\\n                .order_by(asc(AgentExecutionFeed.created_at)) \\\n                .all()\n\n            past_messages = [\n                {'role': past_message.role, 'content': past_message.feed, 'chat_id': past_message.id}\n                for past_message in past_messages]\n\n            ltm_prompt = self._build_prompt_for_recursive_ltm_summary_using_previous_ltm_summary(\n                previous_ltm_summary=previous_ltm_summary, past_messages=past_messages, token_limit=output_token_limit)\n\n        msgs = [{\"role\": \"system\", \"content\": \"You are GPT Prompt writer\"},\n                {\"role\": \"assistant\", \"content\": ltm_prompt}]\n        ltm_summary = self.llm.chat_completion(msgs)\n\n        if 'error' in ltm_summary and ltm_summary['message'] is not None:\n            ErrorHandler.handle_openai_errors(self.session, self.agent_id, self.agent_execution_id, ltm_summary['message'])\n\n        execution = AgentExecution(id=self.agent_execution_id)\n        agent_execution_configs = {\"ltm_summary\": ltm_summary[\"content\"]}\n        AgentExecutionConfiguration.add_or_update_agent_execution_config(session=self.session, execution=execution,\n                                                                 agent_execution_configs=agent_execution_configs)\n\n        return ltm_summary[\"content\"]\n\n    def _build_prompt_for_ltm_summary(self, past_messages: List[BaseMessage], token_limit: int):\n        ltm_summary_prompt = PromptReader.read_agent_prompt(__file__, \"agent_summary.txt\")\n\n        past_messages_prompt = \"\"\n        for past_message in past_messages:\n            past_messages_prompt += past_message[\"role\"] + \": \" + past_message[\"content\"] + \"\\n\"\n        ltm_summary_prompt = ltm_summary_prompt.replace(\"{past_messages}\", past_messages_prompt)\n\n        ltm_summary_prompt = ltm_summary_prompt.replace(\"{char_limit}\", str(token_limit*4))\n\n        return ltm_summary_prompt\n\n    def _build_prompt_for_recursive_ltm_summary_using_previous_ltm_summary(self, previous_ltm_summary: str,\n                                                                    past_messages: List[BaseMessage], token_limit: int):\n        ltm_summary_prompt = PromptReader.read_agent_prompt(__file__, \"agent_recursive_summary.txt\")\n\n        ltm_summary_prompt = ltm_summary_prompt.replace(\"{previous_ltm_summary}\", previous_ltm_summary)\n\n        past_messages_prompt = \"\"\n        for past_message in past_messages:\n            past_messages_prompt += past_message[\"role\"] + \": \" + past_message[\"content\"] + \"\\n\"\n        ltm_summary_prompt = ltm_summary_prompt.replace(\"{past_messages}\", past_messages_prompt)\n\n        ltm_summary_prompt = ltm_summary_prompt.replace(\"{char_limit}\", str(token_limit*4))\n\n        return ltm_summary_prompt\n"
  },
  {
    "path": "superagi/agent/agent_prompt_builder.py",
    "content": "import json\nimport re\n\nfrom pydantic.types import List\n\nfrom superagi.helper.token_counter import TokenCounter\nfrom superagi.tools.base_tool import BaseTool\n\nFINISH_NAME = \"finish\"\n\n\nclass AgentPromptBuilder:\n    \"\"\"Agent prompt builder for LLM agent.\"\"\"\n\n    @staticmethod\n    def add_list_items_to_string(items: List[str]) -> str:\n        list_string = \"\"\n        for i, item in enumerate(items):\n            list_string += f\"{i + 1}. {item}\\n\"\n        return list_string\n\n\n    @classmethod\n    def add_tools_to_prompt(cls, tools: List[BaseTool], add_finish: bool = True) -> str:\n        \"\"\"Add tools to the prompt.\n\n        Args:\n            tools (List[BaseTool]): The list of tools.\n            add_finish (bool): Whether to add finish tool or not.\n        \"\"\"\n        final_string = \"\"\n        print(tools)\n        for i, item in enumerate(tools):\n            final_string += f\"{i + 1}. {cls._generate_tool_string(item)}\\n\"\n        finish_description = (\n            \"use this to signal that you have finished all your objectives\"\n        )\n        finish_args = (\n            '\"response\": \"final response to let '\n            'people know you have finished your objectives\"'\n        )\n        finish_string = (\n            f\"{len(tools) + 1}. \\\"{FINISH_NAME}\\\": \"\n            f\"{finish_description}, args: {finish_args}\"\n        )\n        if add_finish:\n            final_string = final_string + finish_string + \"\\n\\n\"\n        else:\n            final_string = final_string + \"\\n\"\n\n        return final_string\n\n    @classmethod\n    def _generate_tool_string(cls, tool: BaseTool) -> str:\n        output = f\"\\\"{tool.name}\\\": {tool.description}\"\n        # print(tool.args)\n        output += f\", args json schema: {json.dumps(tool.args)}\"\n        return output\n    \n    @classmethod\n    def clean_prompt(cls, prompt):\n        prompt = re.sub('[ \\t]+', ' ', prompt)\n        return prompt.strip()\n\n    @classmethod\n    def replace_main_variables(cls, super_agi_prompt: str, goals: List[str], instructions: List[str], constraints: List[str],\n                               tools: List[BaseTool], add_finish_tool: bool = True):\n        \"\"\"Replace the main variables in the super agi prompt.\n\n        Args:\n            super_agi_prompt (str): The super agi prompt.\n            goals (List[str]): The list of goals.\n            instructions (List[str]): The list of instructions.\n            constraints (List[str]): The list of constraints.\n            tools (List[BaseTool]): The list of tools.\n            add_finish_tool (bool): Whether to add finish tool or not.\n        \"\"\"\n        super_agi_prompt = super_agi_prompt.replace(\"{goals}\", AgentPromptBuilder.add_list_items_to_string(goals))\n        if len(instructions) > 0 and len(instructions[0]) > 0:\n            task_str = \"INSTRUCTION(Follow these instruction to decide the flow of execution and decide the next steps for achieving the task):\"\n            super_agi_prompt = super_agi_prompt.replace(\"{instructions}\", \"INSTRUCTION: \" + '\\n' +  AgentPromptBuilder.add_list_items_to_string(instructions))\n            super_agi_prompt = super_agi_prompt.replace(\"{task_instructions}\", task_str + '\\n' +  AgentPromptBuilder.add_list_items_to_string(instructions))\n        else:\n            super_agi_prompt = super_agi_prompt.replace(\"{instructions}\", '')\n        super_agi_prompt = super_agi_prompt.replace(\"{task_instructions}\", \"\")\n        super_agi_prompt = super_agi_prompt.replace(\"{constraints}\",\n                                                    AgentPromptBuilder.add_list_items_to_string(constraints))\n\n\n        # logger.info(tools)\n        tools_string = AgentPromptBuilder.add_tools_to_prompt(tools, add_finish_tool)\n        super_agi_prompt = super_agi_prompt.replace(\"{tools}\", tools_string)\n        return super_agi_prompt\n\n    @classmethod\n    def replace_task_based_variables(cls, super_agi_prompt: str, current_task: str, last_task: str,\n                                     last_task_result: str, pending_tasks: List[str], completed_tasks: list, token_limit: int):\n        \"\"\"Replace the task based variables in the super agi prompt.\n\n        Args:\n            super_agi_prompt (str): The super agi prompt.\n            current_task (str): The current task.\n            last_task (str): The last task.\n            last_task_result (str): The last task result.\n            pending_tasks (List[str]): The list of pending tasks.\n            completed_tasks (list): The list of completed tasks.\n            token_limit (int): The token limit.\n        \"\"\"\n        if \"{current_task}\" in super_agi_prompt:\n            super_agi_prompt = super_agi_prompt.replace(\"{current_task}\", current_task)\n        if \"{last_task}\" in super_agi_prompt:\n            super_agi_prompt = super_agi_prompt.replace(\"{last_task}\", last_task)\n        if \"{last_task_result}\" in super_agi_prompt:\n            super_agi_prompt = super_agi_prompt.replace(\"{last_task_result}\", last_task_result)\n        if \"{pending_tasks}\" in super_agi_prompt:\n            super_agi_prompt = super_agi_prompt.replace(\"{pending_tasks}\", str(pending_tasks))\n\n        completed_tasks.reverse()\n        if \"{completed_tasks}\" in super_agi_prompt:\n            completed_tasks_arr = []\n            for task in completed_tasks:\n                completed_tasks_arr.append(task['task'])\n            super_agi_prompt = super_agi_prompt.replace(\"{completed_tasks}\", str(completed_tasks_arr))\n\n        base_token_limit = TokenCounter.count_message_tokens([{\"role\": \"user\", \"content\": super_agi_prompt}])\n        pending_tokens = token_limit - base_token_limit\n        final_output = \"\"\n        if \"{task_history}\" in super_agi_prompt:\n            for task in reversed(completed_tasks[-10:]):\n                final_output = f\"Task: {task['task']}\\nResult: {task['response']}\\n\" + final_output\n                token_count = TokenCounter.count_message_tokens([{\"role\": \"user\", \"content\": final_output}])\n                # giving buffer of 100 tokens\n                if token_count > min(600, pending_tokens):\n                    break\n            super_agi_prompt = super_agi_prompt.replace(\"{task_history}\", \"\\n\" + final_output + \"\\n\")\n        return super_agi_prompt\n"
  },
  {
    "path": "superagi/agent/agent_prompt_template.py",
    "content": "import re\n\nfrom pydantic.types import List\n\nfrom superagi.helper.prompt_reader import PromptReader\n\nFINISH_NAME = \"finish\"\n\n\nclass AgentPromptTemplate:\n\n    @staticmethod\n    def add_list_items_to_string(items: List[str]) -> str:\n        list_string = \"\"\n        for i, item in enumerate(items):\n            list_string += f\"{i + 1}. {item}\\n\"\n        return list_string\n\n    @classmethod\n    def clean_prompt(cls, prompt):\n        prompt = re.sub('[ \\t]+', ' ', prompt)\n        return prompt.strip()\n\n    @classmethod\n    def get_super_agi_single_prompt(cls):\n        super_agi_prompt = PromptReader.read_agent_prompt(__file__, \"superagi.txt\")\n\n        return {\"prompt\": super_agi_prompt, \"variables\": [\"goals\", \"instructions\", \"constraints\", \"tools\"]}\n\n    @classmethod\n    def start_task_based(cls):\n        super_agi_prompt = PromptReader.read_agent_prompt(__file__, \"initialize_tasks.txt\")\n\n        return {\"prompt\": AgentPromptTemplate.clean_prompt(super_agi_prompt), \"variables\": [\"goals\", \"instructions\"]}\n        # super_agi_prompt = super_agi_prompt.replace(\"{goals}\", AgentPromptBuilder.add_list_items_to_string(goals))\n\n    @classmethod\n    def analyse_task(cls):\n        constraints = [\n            'Exclusively use the tools listed in double quotes e.g. \"tool name\"'\n        ]\n        super_agi_prompt = PromptReader.read_agent_prompt(__file__, \"analyse_task.txt\")\n        super_agi_prompt = AgentPromptTemplate.clean_prompt(super_agi_prompt) \\\n            .replace(\"{constraints}\", AgentPromptTemplate.add_list_items_to_string(constraints))\n        return {\"prompt\": super_agi_prompt, \"variables\": [\"goals\", \"instructions\", \"tools\", \"current_task\"]}\n\n    @classmethod\n    def create_tasks(cls):\n        # just executed task `{last_task}` and got the result `{last_task_result}`\n        super_agi_prompt = PromptReader.read_agent_prompt(__file__, \"create_tasks.txt\")\n        return {\"prompt\": AgentPromptTemplate.clean_prompt(super_agi_prompt),\n                \"variables\": [\"goals\", \"instructions\", \"last_task\", \"last_task_result\", \"pending_tasks\"]}\n\n    @classmethod\n    def prioritize_tasks(cls):\n        # just executed task `{last_task}` and got the result `{last_task_result}`\n        super_agi_prompt = PromptReader.read_agent_prompt(__file__, \"prioritize_tasks.txt\")\n        return {\"prompt\": AgentPromptTemplate.clean_prompt(super_agi_prompt),\n                \"variables\": [\"goals\", \"instructions\", \"last_task\", \"last_task_result\", \"pending_tasks\"]}\n"
  },
  {
    "path": "superagi/agent/agent_tool_step_handler.py",
    "content": "import json\n\nfrom superagi.agent.task_queue import TaskQueue\nfrom superagi.agent.agent_message_builder import AgentLlmMessageBuilder\nfrom superagi.agent.agent_prompt_builder import AgentPromptBuilder\nfrom superagi.agent.output_handler import ToolOutputHandler\nfrom superagi.agent.output_parser import AgentSchemaToolOutputParser\nfrom superagi.agent.queue_step_handler import QueueStepHandler\nfrom superagi.agent.tool_builder import ToolBuilder\nfrom superagi.helper.error_handler import ErrorHandler\nfrom superagi.helper.prompt_reader import PromptReader\nfrom superagi.helper.token_counter import TokenCounter\nfrom superagi.lib.logger import logger\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_config import AgentExecutionConfiguration\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nfrom superagi.models.agent_execution_permission import AgentExecutionPermission\nfrom superagi.models.tool import Tool\nfrom superagi.models.toolkit import Toolkit\nfrom superagi.models.workflows.agent_workflow_step import AgentWorkflowStep\nfrom superagi.models.workflows.agent_workflow_step_tool import AgentWorkflowStepTool\nfrom superagi.resource_manager.resource_summary import ResourceSummarizer\nfrom superagi.tools.base_tool import BaseTool\nfrom sqlalchemy import and_\n\nclass AgentToolStepHandler:\n    \"\"\"Handles the tools steps in the agent workflow\"\"\"\n    def __init__(self, session, llm, agent_id: int, agent_execution_id: int, memory=None):\n        self.session = session\n        self.llm = llm\n        self.agent_execution_id = agent_execution_id\n        self.agent_id = agent_id\n        self.memory = memory\n        self.task_queue = TaskQueue(str(self.agent_execution_id))\n        self.organisation = Agent.find_org_by_agent_id(self.session, self.agent_id)\n\n    def execute_step(self):\n        execution = AgentExecution.get_agent_execution_from_id(self.session, self.agent_execution_id)\n        workflow_step = AgentWorkflowStep.find_by_id(self.session, execution.current_agent_step_id)\n        step_tool = AgentWorkflowStepTool.find_by_id(self.session, workflow_step.action_reference_id)\n        agent_config = Agent.fetch_configuration(self.session, self.agent_id)\n        agent_execution_config = AgentExecutionConfiguration.fetch_configuration(self.session, self.agent_execution_id)\n        # print(agent_execution_config)\n\n        if not self._handle_wait_for_permission(execution, workflow_step):\n            return\n\n        if step_tool.tool_name == \"TASK_QUEUE\":\n            step_response = QueueStepHandler(self.session, self.llm, self.agent_id, self.agent_execution_id).execute_step()\n            next_step = AgentWorkflowStep.fetch_next_step(self.session, workflow_step.id, step_response)\n            self._handle_next_step(next_step)\n            return\n\n        if step_tool.tool_name == \"WAIT_FOR_PERMISSION\":\n            self._create_permission_request(execution, step_tool)\n            return\n\n        assistant_reply = self._process_input_instruction(agent_config, agent_execution_config, step_tool,\n                                                          workflow_step)\n        tool_obj = self._build_tool_obj(agent_config, agent_execution_config, step_tool.tool_name)\n        tool_output_handler = ToolOutputHandler(self.agent_execution_id, agent_config, [tool_obj],self.memory,\n                                                output_parser=AgentSchemaToolOutputParser())\n        final_response = tool_output_handler.handle(self.session, assistant_reply)\n        step_response = \"default\"\n        if step_tool.output_instruction:\n            step_response = self._process_output_instruction(final_response.result, step_tool, workflow_step)\n\n        next_step = AgentWorkflowStep.fetch_next_step(self.session, workflow_step.id, step_response)\n        self._handle_next_step(next_step)\n        self.session.flush()\n\n    def _create_permission_request(self, execution, step_tool: AgentWorkflowStepTool):\n        new_agent_execution_permission = AgentExecutionPermission(\n            agent_execution_id=self.agent_execution_id,\n            status=\"PENDING\",\n            agent_id=self.agent_id,\n            tool_name=\"WAIT_FOR_PERMISSION\",\n            question=step_tool.input_instruction,\n            assistant_reply=\"\")\n        self.session.add(new_agent_execution_permission)\n        self.session.commit()\n        self.session.flush()\n        execution.permission_id = new_agent_execution_permission.id\n        execution.status = \"WAITING_FOR_PERMISSION\"\n        self.session.commit()\n\n    def _handle_next_step(self, next_step):\n        if str(next_step) == \"COMPLETE\":\n            agent_execution = AgentExecution.get_agent_execution_from_id(self.session, self.agent_execution_id)\n            agent_execution.current_agent_step_id = -1\n            agent_execution.status = \"COMPLETED\"\n        else:\n            AgentExecution.assign_next_step_id(self.session, self.agent_execution_id, next_step.id)\n        self.session.commit()\n\n    def _process_input_instruction(self, agent_config, agent_execution_config, step_tool, workflow_step):\n        tool_obj = self._build_tool_obj(agent_config, agent_execution_config, step_tool.tool_name)\n        prompt = self._build_tool_input_prompt(step_tool, tool_obj, agent_execution_config)\n        logger.info(\"Prompt: \", prompt)\n        agent_feeds = AgentExecutionFeed.fetch_agent_execution_feeds(self.session, self.agent_execution_id)\n        messages = AgentLlmMessageBuilder(self.session, self.llm, self.llm.get_model(), self.agent_id, self.agent_execution_id) \\\n            .build_agent_messages(prompt, agent_feeds, history_enabled=step_tool.history_enabled,\n                                  completion_prompt=step_tool.completion_prompt)\n        # print(messages)\n        current_tokens = TokenCounter.count_message_tokens(messages, self.llm.get_model())\n        response = self.llm.chat_completion(messages, TokenCounter(session=self.session, organisation_id=self.organisation.id).token_limit(self.llm.get_model()) - current_tokens)\n\n        if 'error' in response and response['message'] is not None:\n            ErrorHandler.handle_openai_errors(self.session, self.agent_id, self.agent_execution_id, response['message'])\n        # ModelsHelper(session=self.session, organisation_id=organisation.id).create_call_log(execution.name,agent_config['agent_id'],response['response'].usage.total_tokens,json.loads(response['content'])['tool']['name'],agent_config['model'])\n        if 'content' not in response or response['content'] is None:\n            raise RuntimeError(f\"Failed to get response from llm\")\n        total_tokens = current_tokens + TokenCounter.count_message_tokens(response, self.llm.get_model())\n        AgentExecution.update_tokens(self.session, self.agent_execution_id, total_tokens)\n        assistant_reply = response['content']\n        return assistant_reply\n\n    def _build_tool_obj(self, agent_config, agent_execution_config, tool_name: str):\n        model_api_key = AgentConfiguration.get_model_api_key(self.session, self.agent_id, agent_config[\"model\"])['api_key']\n        tool_builder = ToolBuilder(self.session, self.agent_id, self.agent_execution_id)\n        resource_summary = \"\"\n        if tool_name == \"QueryResourceTool\":\n            resource_summary = ResourceSummarizer(session=self.session,\n                                                  agent_id=self.agent_id,\n                                                  model=agent_config[\"model\"]).fetch_or_create_agent_resource_summary(\n                default_summary=agent_config.get(\"resource_summary\"))\n\n        organisation = Agent.find_org_by_agent_id(self.session, self.agent_id)\n        tool = self.session.query(Tool).join(Toolkit, and_(Tool.toolkit_id == Toolkit.id, Toolkit.organisation_id == organisation.id, Tool.name == tool_name)).first()\n        tool_obj = tool_builder.build_tool(tool)\n        tool_obj = tool_builder.set_default_params_tool(tool_obj, agent_config, agent_execution_config, model_api_key,\n                                                        resource_summary,self.memory)\n        return tool_obj\n\n    def _process_output_instruction(self, final_response: str, step_tool: AgentWorkflowStepTool,\n                                    workflow_step: AgentWorkflowStep):\n        prompt = self._build_tool_output_prompt(step_tool, final_response, workflow_step)\n        messages = [{\"role\": \"system\", \"content\": prompt}]\n        current_tokens = TokenCounter.count_message_tokens(messages, self.llm.get_model())\n        response = self.llm.chat_completion(messages,\n                                            TokenCounter(session=self.session, organisation_id=self.organisation.id).token_limit(self.llm.get_model()) - current_tokens)\n\n        if 'error' in response and response['message'] is not None:\n            ErrorHandler.handle_openai_errors(self.session, self.agent_id, self.agent_execution_id, response['message'])\n            \n        if 'content' not in response or response['content'] is None:\n            raise RuntimeError(f\"ToolWorkflowStepHandler: Failed to get output response from llm\")\n        total_tokens = current_tokens + TokenCounter.count_message_tokens(response, self.llm.get_model())\n        AgentExecution.update_tokens(self.session, self.agent_execution_id, total_tokens)\n        step_response = response['content']\n        step_response = step_response.replace(\"'\", \"\").replace(\"\\\"\", \"\")\n        return step_response\n\n    def _build_tool_input_prompt(self, step_tool: AgentWorkflowStepTool, tool: BaseTool, agent_execution_config: dict):\n        super_agi_prompt = PromptReader.read_agent_prompt(__file__, \"agent_tool_input.txt\")\n        super_agi_prompt = super_agi_prompt.replace(\"{goals}\", AgentPromptBuilder.add_list_items_to_string(\n            agent_execution_config[\"goal\"]))\n        super_agi_prompt = super_agi_prompt.replace(\"{tool_name}\", step_tool.tool_name)\n        super_agi_prompt = super_agi_prompt.replace(\"{instruction}\", step_tool.input_instruction)\n\n        tool_schema = f\"\\\"{tool.name}\\\": {tool.description}, args json schema: {json.dumps(tool.args)}\"\n        super_agi_prompt = super_agi_prompt.replace(\"{tool_schema}\", tool_schema)\n        return super_agi_prompt\n\n    def _get_step_responses(self, workflow_step: AgentWorkflowStep):\n        return [step[\"step_response\"] for step in workflow_step.next_steps]\n\n    def _build_tool_output_prompt(self, step_tool: AgentWorkflowStepTool, tool_output: str,\n                                  workflow_step: AgentWorkflowStep):\n        super_agi_prompt = PromptReader.read_agent_prompt(__file__, \"agent_tool_output.txt\")\n        super_agi_prompt = super_agi_prompt.replace(\"{tool_output}\", tool_output)\n        super_agi_prompt = super_agi_prompt.replace(\"{tool_name}\", step_tool.tool_name)\n        super_agi_prompt = super_agi_prompt.replace(\"{instruction}\", step_tool.output_instruction)\n\n        step_responses = self._get_step_responses(workflow_step)\n        if \"default\" in step_responses:\n            step_responses.remove(\"default\")\n        super_agi_prompt = super_agi_prompt.replace(\"{output_options}\", str(step_responses))\n        return super_agi_prompt\n\n    def _handle_wait_for_permission(self, agent_execution, workflow_step: AgentWorkflowStep):\n        \"\"\"\n        Handles the wait for permission when the agent execution is waiting for permission.\n\n        Args:\n            agent_execution (AgentExecution): The agent execution.\n            workflow_step (AgentWorkflowStep): The workflow step.\n\n        Raises:\n            Returns permission success or failure\n        \"\"\"\n        if agent_execution.status != \"WAITING_FOR_PERMISSION\":\n            return True\n        agent_execution_permission = self.session.query(AgentExecutionPermission).filter(\n            AgentExecutionPermission.id == agent_execution.permission_id).first()\n        if agent_execution_permission.status == \"PENDING\":\n            logger.error(\"handle_wait_for_permission: Permission is still pending\")\n            return False\n        if agent_execution_permission.status == \"APPROVED\":\n            next_step = AgentWorkflowStep.fetch_next_step(self.session, workflow_step.id, \"YES\")\n        else:\n            next_step = AgentWorkflowStep.fetch_next_step(self.session, workflow_step.id, \"NO\")\n            result = f\"{' User has given the following feedback : ' + agent_execution_permission.user_feedback if agent_execution_permission.user_feedback else ''}\"\n\n\n            agent_execution_feed = AgentExecutionFeed(agent_execution_id=agent_execution_permission.agent_execution_id,\n                                                      agent_id=agent_execution_permission.agent_id,\n                                                      feed=result, role=\"user\",\n                                                      feed_group_id=agent_execution.current_feed_group_id)\n            self.session.add(agent_execution_feed)\n\n        agent_execution.status = \"RUNNING\"\n        agent_execution.permission_id = -1\n        self.session.commit()\n        self._handle_next_step(next_step)\n        self.session.commit()\n        return False\n"
  },
  {
    "path": "superagi/agent/agent_workflow_step_wait_handler.py",
    "content": "from datetime import datetime\n\nfrom superagi.agent.types.agent_execution_status import AgentExecutionStatus\nfrom superagi.lib.logger import logger\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.workflows.agent_workflow_step import AgentWorkflowStep\nfrom superagi.models.workflows.agent_workflow_step_wait import AgentWorkflowStepWait\nfrom superagi.agent.types.wait_step_status import AgentWorkflowStepWaitStatus\n\nclass AgentWaitStepHandler:\n    \"\"\"Handle Agent Wait Step in the agent workflow.\"\"\"\n\n    def __init__(self, session, agent_id, agent_execution_id):\n        self.session = session\n        self.agent_id = agent_id\n        self.agent_execution_id = agent_execution_id\n\n    def execute_step(self):\n        \"\"\"Execute the agent wait step.\"\"\"\n\n        logger.info(\"Executing Wait Step\")\n        execution = AgentExecution.get_agent_execution_from_id(self.session, self.agent_execution_id)\n        workflow_step = AgentWorkflowStep.find_by_id(self.session, execution.current_agent_step_id)\n        step_wait = AgentWorkflowStepWait.find_by_id(self.session, workflow_step.action_reference_id)\n        if step_wait is not None:\n            step_wait.wait_begin_time = datetime.now()\n            step_wait.status = AgentWorkflowStepWaitStatus.WAITING.value\n            execution.status = AgentExecutionStatus.WAIT_STEP.value\n\n            self.session.commit()\n\n    def handle_next_step(self):\n        \"\"\"Handle next step of agent workflow in case of wait step.\"\"\"\n\n        execution = AgentExecution.get_agent_execution_from_id(self.session, self.agent_execution_id)\n        workflow_step = AgentWorkflowStep.find_by_id(self.session, execution.current_agent_step_id)\n        step_response = \"default\"\n        next_step = AgentWorkflowStep.fetch_next_step(self.session, workflow_step.id, step_response)\n        if str(next_step) == \"COMPLETE\":\n            agent_execution = AgentExecution.get_agent_execution_from_id(self.session, self.agent_execution_id)\n            agent_execution.current_agent_step_id = -1\n            agent_execution.status = \"COMPLETED\"\n        else:\n            AgentExecution.assign_next_step_id(self.session, self.agent_execution_id, next_step.id)\n        self.session.commit()\n"
  },
  {
    "path": "superagi/agent/common_types.py",
    "content": "from pydantic import BaseModel\n\n\nclass ToolExecutorResponse(BaseModel):\n    status: str\n    result: str = None\n    retry: bool = False\n    is_permission_required: bool = False\n    permission_id: int = None\n\n\nclass TaskExecutorResponse(BaseModel):\n    status: str\n    retry: bool\n"
  },
  {
    "path": "superagi/agent/output_handler.py",
    "content": "import json\nfrom superagi.agent.common_types import TaskExecutorResponse, ToolExecutorResponse\nfrom superagi.agent.output_parser import AgentSchemaOutputParser\nfrom superagi.agent.task_queue import TaskQueue\nfrom superagi.agent.tool_executor import ToolExecutor\nfrom superagi.helper.json_cleaner import JsonCleaner\nfrom superagi.lib.logger import logger\nfrom langchain.text_splitter import TokenTextSplitter\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nfrom superagi.vector_store.base import VectorStore\nimport numpy as np\n\nfrom superagi.models.agent_execution_permission import AgentExecutionPermission\n\n\nclass ToolOutputHandler:\n    \"\"\"Handles the tool output response from the thinking step\"\"\"\n    def __init__(self,\n                 agent_execution_id: int,\n                 agent_config: dict,\n                 tools: list,\n                 memory:VectorStore=None,\n                 output_parser=AgentSchemaOutputParser()):\n        self.agent_execution_id = agent_execution_id\n        self.task_queue = TaskQueue(str(agent_execution_id))\n        self.agent_config = agent_config\n        self.tools = tools\n        self.output_parser = output_parser\n        self.memory=memory\n\n    def handle(self, session, assistant_reply):\n        \"\"\"Handles the tool output response from the thinking step.\n        Step takes care of permission control as well at tool level.\n\n        Args:\n            session (Session): The database session.\n            assistant_reply (str): The assistant reply.\n        \"\"\"\n        response = self._check_permission_in_restricted_mode(session, assistant_reply)\n        if response.is_permission_required:\n            return response\n\n        tool_response = self.handle_tool_response(session, assistant_reply)\n        # print(tool_response)\n\n        agent_execution = AgentExecution.find_by_id(session, self.agent_execution_id)\n        agent_execution_feed = AgentExecutionFeed(agent_execution_id=self.agent_execution_id,\n                                                  agent_id=self.agent_config[\"agent_id\"],\n                                                  feed=assistant_reply,\n                                                  role=\"assistant\",\n                                                  feed_group_id=agent_execution.current_feed_group_id)\n        session.add(agent_execution_feed)\n        tool_response_feed = AgentExecutionFeed(agent_execution_id=self.agent_execution_id,\n                                                agent_id=self.agent_config[\"agent_id\"],\n                                                feed=tool_response.result,\n                                                role=\"system\",\n                                                feed_group_id=agent_execution.current_feed_group_id)\n        session.add(tool_response_feed)\n        session.commit()\n        if not tool_response.retry:\n            tool_response = self._check_for_completion(tool_response)\n\n        self.add_text_to_memory(assistant_reply, tool_response.result)\n        return tool_response\n\n    def add_text_to_memory(self, assistant_reply,tool_response_result):\n        \"\"\"\n        Adds the text generated by the assistant and tool response to the memory.\n\n        Args:\n            assistant_reply (str): The assistant reply.\n            tool_response_result (str): The tool response.\n\n        Returns:\n            None\n        \"\"\"\n        if self.memory is not None:\n            try:\n                data = json.loads(assistant_reply)\n                task_description = data['thoughts']['text']\n                final_tool_response = tool_response_result\n                prompt = task_description + final_tool_response\n                text_splitter = TokenTextSplitter(chunk_size=1024, chunk_overlap=10)\n                chunk_response = text_splitter.split_text(prompt)\n                metadata = {\"agent_execution_id\": self.agent_execution_id}\n                metadatas = []\n                for _ in chunk_response:\n                    metadatas.append(metadata)\n\n                self.memory.add_texts(chunk_response, metadatas)\n            except Exception as exception:\n                logger.error(f\"Exception: {exception}\")\n        \n     \n\n    def handle_tool_response(self, session, assistant_reply):\n        \"\"\"Only handle processing of tool response\"\"\"\n        action = self.output_parser.parse(assistant_reply)\n        agent = session.query(Agent).filter(Agent.id == self.agent_config[\"agent_id\"]).first()\n        organisation = agent.get_agent_organisation(session)\n        tool_executor = ToolExecutor(organisation_id=organisation.id, agent_id=agent.id, tools=self.tools, agent_execution_id=self.agent_execution_id)\n        return tool_executor.execute(session, action.name, action.args)\n\n    def _check_permission_in_restricted_mode(self, session, assistant_reply: str):\n        action = self.output_parser.parse(assistant_reply)\n        tools = {t.name: t for t in self.tools}\n\n        excluded_tools = [ToolExecutor.FINISH, '', None]\n\n        if self.agent_config[\"permission_type\"].upper() == \"RESTRICTED\" and action.name not in excluded_tools and \\\n                tools.get(action.name) and tools[action.name].permission_required:\n            new_agent_execution_permission = AgentExecutionPermission(\n                agent_execution_id=self.agent_execution_id,\n                status=\"PENDING\",\n                agent_id=self.agent_config[\"agent_id\"],\n                tool_name=action.name,\n                assistant_reply=assistant_reply)\n\n            session.add(new_agent_execution_permission)\n            session.commit()\n            return ToolExecutorResponse(is_permission_required=True, status=\"WAITING_FOR_PERMISSION\",\n                                        permission_id=new_agent_execution_permission.id)\n        return ToolExecutorResponse(status=\"PENDING\", is_permission_required=False)\n\n    def _check_for_completion(self, tool_response):\n        self.task_queue.complete_task(tool_response.result)\n        current_tasks = self.task_queue.get_tasks()\n        if self.task_queue.get_completed_tasks() and len(current_tasks) == 0:\n            tool_response.status = \"COMPLETE\"\n        if current_tasks and tool_response.status == \"COMPLETE\":\n            tool_response.status = \"PENDING\"\n        return tool_response\n\n\nclass TaskOutputHandler:\n    \"\"\"Handles the task output from the LLM. Output is mostly in the array of tasks and\n    handler adds every task to the task queue.\n    \"\"\"\n\n    def __init__(self, agent_execution_id: int, agent_config: dict):\n        self.agent_execution_id = agent_execution_id\n        self.task_queue = TaskQueue(str(agent_execution_id))\n        self.agent_config = agent_config\n\n    def handle(self, session, assistant_reply):\n        assistant_reply = JsonCleaner.extract_json_array_section(assistant_reply)\n        tasks = eval(assistant_reply)\n        tasks = np.array(tasks).flatten().tolist()\n        for task in reversed(tasks):\n            self.task_queue.add_task(task)\n        if len(tasks) > 0:\n            logger.info(\"Adding task to queue: \" + str(tasks))\n        agent_execution = AgentExecution.find_by_id(session, self.agent_execution_id)\n        for task in tasks:\n            agent_execution_feed = AgentExecutionFeed(agent_execution_id=self.agent_execution_id,\n                                                      agent_id=self.agent_config[\"agent_id\"],\n                                                      feed=\"New Task Added: \" + task,\n                                                      role=\"system\",\n                                                      feed_group_id=agent_execution.current_feed_group_id)\n            session.add(agent_execution_feed)\n        status = \"COMPLETE\" if len(self.task_queue.get_tasks()) == 0 else \"PENDING\"\n        session.commit()\n        return TaskExecutorResponse(status=status, retry=False)\n\n\nclass ReplaceTaskOutputHandler:\n    \"\"\"Handles the replace/prioritize task output type.\n    Output is mostly in the array of tasks and handler adds every task to the task queue.\n    \"\"\"\n\n    def __init__(self, agent_execution_id: int, agent_config: dict):\n        self.agent_execution_id = agent_execution_id\n        self.task_queue = TaskQueue(str(agent_execution_id))\n        self.agent_config = agent_config\n\n    def handle(self, session, assistant_reply):\n        assistant_reply = JsonCleaner.extract_json_array_section(assistant_reply)\n        tasks = eval(assistant_reply)\n        self.task_queue.clear_tasks()\n        for task in reversed(tasks):\n            self.task_queue.add_task(task)\n        if len(tasks) > 0:\n            logger.info(\"Tasks reprioritized in order: \" + str(tasks))\n        status = \"COMPLETE\" if len(self.task_queue.get_tasks()) == 0 else \"PENDING\"\n        session.commit()\n        return TaskExecutorResponse(status=status, retry=False)\n\n\ndef get_output_handler(output_type: str, agent_execution_id: int, agent_config: dict, agent_tools: list = [],memory=None):\n    if output_type == \"tools\":\n        return ToolOutputHandler(agent_execution_id, agent_config, agent_tools,memory=memory)\n    elif output_type == \"replace_tasks\":\n        return ReplaceTaskOutputHandler(agent_execution_id, agent_config)\n    elif output_type == \"tasks\":\n        return TaskOutputHandler(agent_execution_id, agent_config)\n    return ToolOutputHandler(agent_execution_id, agent_config, agent_tools,memory=memory)\n"
  },
  {
    "path": "superagi/agent/output_parser.py",
    "content": "import json\nfrom abc import ABC, abstractmethod\nfrom typing import Dict, NamedTuple, List\nimport re\nimport ast\nimport json\nfrom superagi.helper.json_cleaner import JsonCleaner\nfrom superagi.lib.logger import logger\n\n\nclass AgentGPTAction(NamedTuple):\n    name: str\n    args: Dict\n\n\nclass AgentTasks(NamedTuple):\n    tasks: List[str] = []\n    error: str = \"\"\n\n\nclass BaseOutputParser(ABC):\n    @abstractmethod\n    def parse(self, text: str) -> AgentGPTAction:\n        \"\"\"Return AgentGPTAction\"\"\"\n\n\nclass AgentSchemaOutputParser(BaseOutputParser):\n    \"\"\"Parses the output from the agent schema\"\"\"\n    def parse(self, response: str) -> AgentGPTAction:\n        if response.startswith(\"```\") and response.endswith(\"```\"):\n            response = \"```\".join(response.split(\"```\")[1:-1])\n        response = JsonCleaner.extract_json_section(response)\n        # ast throws error if true/false params passed in json\n        response = JsonCleaner.clean_boolean(response)\n\n        # OpenAI returns `str(content_dict)`, literal_eval reverses this\n        try:\n            logger.debug(\"AgentSchemaOutputParser: \", response)\n            response_obj = ast.literal_eval(response)\n            args = response_obj['tool']['args'] if 'args' in response_obj['tool'] else {}\n            return AgentGPTAction(\n                name=response_obj['tool']['name'],\n                args=args,\n            )\n        except BaseException as e:\n            logger.info(f\"AgentSchemaOutputParser: Error parsing JSON response {e}\")\n            raise e\n\n\nclass AgentSchemaToolOutputParser(BaseOutputParser):\n    \"\"\"Parses the output from the agent schema for the tool\"\"\"\n    def parse(self, response: str) -> AgentGPTAction:\n        if response.startswith(\"```\") and response.endswith(\"```\"):\n            response = \"```\".join(response.split(\"```\")[1:-1])\n        response = JsonCleaner.extract_json_section(response)\n        # ast throws error if true/false params passed in json\n        response = JsonCleaner.clean_boolean(response)\n\n        # OpenAI returns `str(content_dict)`, literal_eval reverses this\n        try:\n            logger.debug(\"AgentSchemaOutputParser: \", response)\n            response_obj = ast.literal_eval(response)\n            args = response_obj['args'] if 'args' in response_obj else {}\n            return AgentGPTAction(\n                name=response_obj['name'],\n                args=args,\n            )\n        except BaseException as e:\n            logger.info(f\"AgentSchemaToolOutputParser: Error parsing JSON response {e}\")\n            raise e\n"
  },
  {
    "path": "superagi/agent/prompts/agent_queue_input.txt",
    "content": "Use the below instruction and break down the last response to an individual array of items that can be inserted into the queue.\n\nINSTRUCTION: `{instruction}`\n\nRespond with an array of items that are JSON parsable and can be inserted into the queue.\nIgnore the header row in the case of csv.\n"
  },
  {
    "path": "superagi/agent/prompts/agent_recursive_summary.txt",
    "content": "AI, you are provided with a previous summary of interactions between the system, user, and assistant, as well as additional conversations that were not included in the original summary.\nIf the previous summary is empty, your task is to create a summary based solely on the new interactions.\n\nPrevious Summary: {previous_ltm_summary}\n\n{past_messages}\n\nIf the previous summary is not empty, your final summary should integrate the new interactions into the existing summary to create a comprehensive recap of all interactions.\nIf the previous summary is empty, your summary should encapsulate the main points of the new conversations.\nIn both cases, highlight the key issues discussed, decisions made, and any actions assigned.\nPlease ensure that the final summary does not exceed {char_limit} characters."
  },
  {
    "path": "superagi/agent/prompts/agent_summary.txt",
    "content": "AI, your task is to generate a concise summary of the previous interactions between the system, user, and assistant.\nThe interactions are as follows:\n\n{past_messages}\n\nThis summary should encapsulate the main points of the conversation, highlighting the key issues discussed, decisions made, and any actions assigned.\nIt should serve as a recap of the past interaction, providing a clear understanding of the conversation's context and outcomes.\nPlease ensure that the summary does not exceed {char_limit} characters."
  },
  {
    "path": "superagi/agent/prompts/agent_tool_input.txt",
    "content": "{tool_name} is the most suitable tool for the given instruction, use {tool_name} to perform the below instruction which lets you achieve the high level goal.\n\nHigh-Level GOAL:\n`{goals}`\n\nINSTRUCTION: `{instruction}`\n\nRespond with tool name and tool arguments to achieve the instruction.\n\n{tool_schema}\n\nRespond with only valid JSON conforming to the following json schema. You should generate JSON as output and not JSON schema.\n\nJSON Schema:\n{\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n    \"type\": \"object\",\n    \"properties\": {\n            \"name\": {\n                \"type\": \"string\",\n                \"description\": \"{tool_name}\",\n            },\n            \"args\": {\n                \"type\": \"object\",\n                \"description\": \"tool arguments\",\n            }\n     },\n     \"required\": [\"name\", \"args\"]\n}"
  },
  {
    "path": "superagi/agent/prompts/agent_tool_output.txt",
    "content": "Analyze {tool_name} output and follow the instruction to come up with the response:\nHigh-Level GOAL:\n`{goals}`\n\nTOOL OUTPUT:\n`{tool_output}`\n\nINSTRUCTION: `{instruction}`\n\nAnalyze the instruction and respond with one of the below outputs. Response should be one of the below options:\n{output_options}"
  },
  {
    "path": "superagi/agent/prompts/analyse_task.txt",
    "content": "High level goal:\n{goals}\n\n{task_instructions}\n\nYour Current Task: `{current_task}`\n\nTask History:\n`{task_history}`\n\nBased on this, your job is to understand the current task, pick out key parts, and think smart and fast.\nExplain why you are doing each action, create a plan, and mention any worries you might have.\nEnsure next action tool is picked from the below tool list.\n\nTOOLS:\n{tools}\n\nRespond with only valid JSON conforming to the following schema:\n{\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n    \"type\": \"object\",\n    \"properties\": {\n        \"thoughts\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"reasoning\": {\n                    \"type\": \"string\",\n                    \"description\": \"short reasoning\",\n                }\n            },\n            \"required\": [\"reasoning\"]\n        },\n        \"tool\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"name\": {\n                    \"type\": \"string\",\n                    \"description\": \"tool name\",\n                },\n                \"args\": {\n                    \"type\": \"object\",\n                    \"description\": \"tool arguments\",\n                }\n            },\n            \"required\": [\"name\", \"args\"]\n        }\n    }\n}\n\n"
  },
  {
    "path": "superagi/agent/prompts/create_tasks.txt",
    "content": "You are an AI assistant to create task.\n\nHigh level goal:\n{goals}\n\n{task_instructions}\n\nYou have following incomplete tasks `{pending_tasks}`. You have following completed tasks `{completed_tasks}`.\n\nTask History:\n`{task_history}`\n\nBased on this, create a single task in plain english to be completed by your AI system ONLY IF REQUIRED to get closer to or fully reach your high level goal.\nDon't create any task if it is already covered in incomplete or completed tasks.\nEnsure your new task are not deviated from completing the goal.\n\nYour answer should be an array of tasks in plain english that can be used with JSON.parse() and NOTHING ELSE. Return empty array if no new task is required.\n"
  },
  {
    "path": "superagi/agent/prompts/initialize_tasks.txt",
    "content": "You are a task-generating AI known as SuperAGI. You are not a part of any system or device. Your role is to understand the goals presented to you, identify important components, Go through the instruction provided by the user and construct a thorough execution plan.\n\nGOALS:\n{goals}\n\n{task_instructions}\n\nConstruct a sequence of actions, not exceeding 3 steps, to achieve this goal.\n\nSubmit your response as a formatted ARRAY of strings, suitable for utilization with JSON.parse().\n\n"
  },
  {
    "path": "superagi/agent/prompts/prioritize_tasks.txt",
    "content": "You are a task prioritization AI assistant.\n\nHigh level goal:\n{goals}\n\n{task_instructions}\n\nYou have following incomplete tasks `{pending_tasks}`. You have following completed tasks `{completed_tasks}`.\n\nBased on this, evaluate the incomplete tasks and sort them in the order of execution. In output first task will be executed first and so on.\nRemove if any tasks are unnecessary or duplicate incomplete tasks. Remove tasks if they are already covered in completed tasks.\nRemove tasks if it does not help in achieving the main goal.\n\nYour answer should be an array of strings that can be used with JSON.parse() and NOTHING ELSE."
  },
  {
    "path": "superagi/agent/prompts/superagi.txt",
    "content": "You are SuperAGI an AI assistant to solve complex problems. Your decisions must always be made independently without seeking user assistance.\nPlay to your strengths as an LLM and pursue simple strategies with no legal complications.\nIf you have completed all your tasks or reached end state, make sure to use the \"finish\" tool.\n\nGOALS:\n{goals}\n\n{instructions}\n\nCONSTRAINTS:\n{constraints}\n\nTOOLS:\n{tools}\n\nPERFORMANCE EVALUATION:\n1. Continuously review and analyze your actions to ensure you are performing to the best of your abilities.\n2. Use instruction to decide the flow of execution and decide the next steps for achieving the task.\n3. Constructively self-criticize your big-picture behavior constantly.\n4. Reflect on past decisions and strategies to refine your approach.\n5. Every tool has a cost, so be smart and efficient.\n\nRespond with only valid JSON conforming to the following schema:\n{\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n    \"type\": \"object\",\n    \"properties\": {\n        \"thoughts\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"text\": {\n                    \"type\": \"string\",\n                    \"description\": \"thought\"\n                },\n                \"reasoning\": {\n                    \"type\": \"string\",\n                    \"description\": \"short reasoning\"\n                },\n                \"plan\": {\n                    \"type\": \"string\",\n                    \"description\": \"- short bulleted\\n- list that conveys\\n- long-term plan\"\n                },\n                \"criticism\": {\n                    \"type\": \"string\",\n                    \"description\": \"constructive self-criticism\"\n                },\n                \"speak\": {\n                    \"type\": \"string\",\n                    \"description\": \"thoughts summary to say to user\"\n                }\n            },\n            \"required\": [\"text\", \"reasoning\", \"plan\", \"criticism\", \"speak\"],\n            \"additionalProperties\": false\n        },\n        \"tool\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"name\": {\n                    \"type\": \"string\",\n                    \"description\": \"tool name\"\n                },\n                \"args\": {\n                    \"type\": \"object\",\n                    \"description\": \"tool arguments\"\n                }\n            },\n            \"required\": [\"name\", \"args\"],\n            \"additionalProperties\": false\n        }\n    },\n    \"required\": [\"thoughts\", \"tool\"],\n    \"additionalProperties\": false\n}"
  },
  {
    "path": "superagi/agent/queue_step_handler.py",
    "content": "import time\n\nimport numpy as np\n\nfrom superagi.agent.agent_message_builder import AgentLlmMessageBuilder\nfrom superagi.agent.task_queue import TaskQueue\nfrom superagi.helper.error_handler import ErrorHandler\nfrom superagi.helper.json_cleaner import JsonCleaner\nfrom superagi.helper.prompt_reader import PromptReader\nfrom superagi.helper.token_counter import TokenCounter\nfrom superagi.lib.logger import logger\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nfrom superagi.models.workflows.agent_workflow_step import AgentWorkflowStep\nfrom superagi.models.workflows.agent_workflow_step_tool import AgentWorkflowStepTool\nfrom superagi.models.agent import Agent\nfrom superagi.types.queue_status import QueueStatus\n\n\nclass QueueStepHandler:\n    \"\"\"Handles the queue step of the agent workflow\"\"\"\n    def __init__(self, session, llm, agent_id: int, agent_execution_id: int):\n        self.session = session\n        self.llm = llm\n        self.agent_execution_id = agent_execution_id\n        self.agent_id = agent_id\n        self.organisation = Agent.find_org_by_agent_id(self.session, agent_id=self.agent_id)\n\n    def _queue_identifier(self, step_tool):\n        return step_tool.unique_id + \"_\" + str(self.agent_execution_id)\n\n    def _build_task_queue(self, step_tool):\n        return TaskQueue(self._queue_identifier(step_tool))\n\n    def execute_step(self):\n        execution = AgentExecution.get_agent_execution_from_id(self.session, self.agent_execution_id)\n        workflow_step = AgentWorkflowStep.find_by_id(self.session, execution.current_agent_step_id)\n        step_tool = AgentWorkflowStepTool.find_by_id(self.session, workflow_step.action_reference_id)\n        task_queue = self._build_task_queue(step_tool)\n\n        if not task_queue.get_status() or task_queue.get_status() == QueueStatus.COMPLETE.value:\n            task_queue.set_status(QueueStatus.INITIATED.value)\n\n        if task_queue.get_status() == QueueStatus.INITIATED.value:\n            self._add_to_queue(task_queue, step_tool)\n            execution.current_feed_group_id = \"DEFAULT\"\n            task_queue.set_status(QueueStatus.PROCESSING.value)\n\n        if not task_queue.get_tasks():\n            task_queue.set_status(QueueStatus.COMPLETE.value)\n            return \"COMPLETE\"\n        self._consume_from_queue(task_queue)\n        return \"default\"\n\n    def _add_to_queue(self, task_queue: TaskQueue, step_tool: AgentWorkflowStepTool):\n        assistant_reply = self._process_input_instruction(step_tool)\n        self._process_reply(task_queue, assistant_reply)\n\n    def _consume_from_queue(self, task_queue: TaskQueue):\n        tasks = task_queue.get_tasks()\n        agent_execution = AgentExecution.find_by_id(self.session, self.agent_execution_id)\n        if tasks:\n            task = task_queue.get_first_task()\n            # generating the new feed group id\n            agent_execution.current_feed_group_id = \"GROUP_\" + str(int(time.time()))\n            self.session.commit()\n            task_response_feed = AgentExecutionFeed(agent_execution_id=self.agent_execution_id,\n                                                    agent_id=self.agent_id,\n                                                    feed=\"Input: \" + task,\n                                                    role=\"assistant\",\n                                                    feed_group_id=agent_execution.current_feed_group_id)\n            self.session.add(task_response_feed)\n            self.session.commit()\n            task_queue.complete_task(\"PROCESSED\")\n\n    def _process_reply(self, task_queue: TaskQueue, assistant_reply: str):\n        assistant_reply = JsonCleaner.extract_json_array_section(assistant_reply)\n        print(\"Queue reply:\", assistant_reply)\n        task_array = np.array(eval(assistant_reply)).flatten().tolist()\n        for task in task_array:\n            task_queue.add_task(str(task))\n            logger.info(\"RAMRAM: Added task to queue: \", task)\n\n    def _process_input_instruction(self, step_tool):\n        prompt = self._build_queue_input_prompt(step_tool)\n        logger.info(\"Prompt: \", prompt)\n        agent_feeds = AgentExecutionFeed.fetch_agent_execution_feeds(self.session, self.agent_execution_id)\n        print(\".........//////////////..........2\")\n        messages = AgentLlmMessageBuilder(self.session, self.llm, self.llm.get_model(), self.agent_id, self.agent_execution_id) \\\n            .build_agent_messages(prompt, agent_feeds, history_enabled=step_tool.history_enabled,\n                                  completion_prompt=step_tool.completion_prompt)\n        current_tokens = TokenCounter.count_message_tokens(messages, self.llm.get_model())\n        response = self.llm.chat_completion(messages, TokenCounter(session=self.session, organisation_id=self.organisation.id).token_limit(self.llm.get_model()) - current_tokens)\n        \n        if 'error' in response and response['message'] is not None:\n            ErrorHandler.handle_openai_errors(self.session, self.agent_id, self.agent_execution_id, response['message'])\n            \n        if 'content' not in response or response['content'] is None:\n            raise RuntimeError(f\"Failed to get response from llm\")\n        total_tokens = current_tokens + TokenCounter.count_message_tokens(response, self.llm.get_model())\n        AgentExecution.update_tokens(self.session, self.agent_execution_id, total_tokens)\n        assistant_reply = response['content']\n        return assistant_reply\n\n    def _build_queue_input_prompt(self, step_tool: AgentWorkflowStepTool):\n        queue_input_prompt = PromptReader.read_agent_prompt(__file__, \"agent_queue_input.txt\")\n        queue_input_prompt = queue_input_prompt.replace(\"{instruction}\", step_tool.input_instruction)\n\n        return queue_input_prompt\n"
  },
  {
    "path": "superagi/agent/task_queue.py",
    "content": "import json\n\nimport redis\n\nfrom superagi.config.config import get_config\n\nredis_url = get_config('REDIS_URL') or \"localhost:6379\"\n\"\"\"TaskQueue manages current tasks and past tasks in Redis \"\"\"\nclass TaskQueue:\n    def __init__(self, queue_name: str):\n        self.queue_name = queue_name + \"_q\"\n        self.completed_tasks = queue_name + \"_q_completed\"\n        self.db = redis.Redis.from_url(\"redis://\" + redis_url + \"/0\", decode_responses=True)\n\n    def add_task(self, task: str):\n        self.db.lpush(self.queue_name, task)\n        # print(\"Added task. New tasks:\", str(self.get_tasks()))\n\n    def complete_task(self, response):\n        if len(self.get_tasks()) <= 0:\n            return\n        task = self.db.lpop(self.queue_name)\n        self.db.lpush(self.completed_tasks, str({\"task\": task, \"response\": response}))\n\n    def get_first_task(self):\n        return self.db.lindex(self.queue_name, 0)\n\n    def get_tasks(self):\n        return self.db.lrange(self.queue_name, 0, -1)\n\n    def get_completed_tasks(self):\n        tasks = self.db.lrange(self.completed_tasks, 0, -1)\n        return [eval(task) for task in tasks]\n\n    def clear_tasks(self):\n        self.db.delete(self.queue_name)\n\n    def get_last_task_details(self):\n        response = self.db.lindex(self.completed_tasks, 0)\n        if response is None:\n            return None\n\n        return eval(response)\n\n    def set_status(self, status):\n        self.db.set(self.queue_name + \"_status\", status)\n\n    def get_status(self):\n        return self.db.get(self.queue_name + \"_status\")\n\n"
  },
  {
    "path": "superagi/agent/tool_builder.py",
    "content": "import importlib\nimport os\nfrom superagi.config.config import get_config\nfrom superagi.llms.llm_model_factory import get_model\nfrom superagi.models.tool import Tool\nfrom superagi.models.tool_config import ToolConfig\nfrom superagi.models.agent import Agent\nfrom superagi.resource_manager.file_manager import FileManager\nfrom superagi.tools.base_tool import BaseToolkitConfiguration\nfrom superagi.tools.tool_response_query_manager import ToolResponseQueryManager\nfrom superagi.helper.encyption_helper import decrypt_data, is_encrypted\n\nclass DBToolkitConfiguration(BaseToolkitConfiguration):\n    session = None\n    toolkit_id: int\n\n    def __init__(self, session=None, toolkit_id=None):\n        self.session = session\n        self.toolkit_id = toolkit_id\n\n    def get_tool_config(self, key: str):\n        tool_config = self.session.query(ToolConfig).filter_by(key=key, toolkit_id=self.toolkit_id).first()\n        if tool_config and tool_config.value:\n            if is_encrypted(tool_config.value):\n                return decrypt_data(tool_config.value)\n            else:\n                return tool_config.value\n        return super().get_tool_config(key=key)\n\nclass ToolBuilder:\n    def __init__(self, session, agent_id: int, agent_execution_id: int = None):\n        self.session = session\n        self.agent_id = agent_id\n        self.agent_execution_id = agent_execution_id\n\n    def __validate_filename(self, filename):\n        \"\"\"\n        Validate the filename by removing the last three characters if the filename ends with \".py\".\n\n        Args:\n            filename (str): The filename.\n\n        Returns:\n            str: The validated filename.\n        \"\"\"\n        if filename.endswith(\".py\"):\n            return filename[:-3]  # Remove the last three characters (i.e., \".py\")\n        return filename\n\n    def build_tool(self, tool: Tool):\n        \"\"\"\n        Create an object of a agent usable tool dynamically.\n\n        Args:\n            tool (Tool) : Tool object from which agent tool would be made.\n\n        Returns:\n            object: The object of the agent usable tool.\n        \"\"\"\n        file_name = self.__validate_filename(filename=tool.file_name)\n\n        tools_dir=\"\"\n        tool_paths = [\"superagi/tools\", \"superagi/tools/external_tools\", \"superagi/tools/marketplace_tools\"]\n        for tool_path in tool_paths:\n            if os.path.exists(os.path.join(os.getcwd(), tool_path) + '/' + tool.folder_name):\n                tools_dir = tool_path\n                break\n        parsed_tools_dir = tools_dir.rstrip(\"/\")\n        module_name = \".\".join(parsed_tools_dir.split(\"/\") + [tool.folder_name, file_name])\n\n        # module_name = f\"superagi.tools.{folder_name}.{file_name}\"\n\n        # Load the module dynamically\n        module = importlib.import_module(module_name)\n\n        # Get the class from the loaded module\n        obj_class = getattr(module, tool.class_name)\n\n        # Create an instance of the class\n        new_object = obj_class()\n        new_object.toolkit_config = DBToolkitConfiguration(session=self.session, toolkit_id=tool.toolkit_id)\n        return new_object\n\n    def set_default_params_tool(self, tool, agent_config, agent_execution_config, model_api_key: str,\n                                resource_summary: str = \"\",memory=None):\n        \"\"\"\n        Set the default parameters for the tools.\n\n        Args:\n            tool : Tool object.\n            agent_config (dict): Parsed agent configuration.\n            agent_execution_config (dict): Parsed execution configuration\n            agent_id (int): The ID of the agent.\n            model_api_key (str): The API key of the model\n\n        Returns:\n            list: The list of tools with default parameters.\n        \"\"\"\n        organisation = Agent.find_org_by_agent_id(self.session, agent_id=agent_config['agent_id'])\n        if hasattr(tool, 'goals'):\n            tool.goals = agent_execution_config[\"goal\"]\n        if hasattr(tool, 'instructions'):\n            tool.instructions = agent_execution_config[\"instruction\"]\n        if hasattr(tool, 'llm') and (agent_config[\"model\"] == \"gpt4\" or agent_config[\n            \"model\"] == \"gpt-3.5-turbo\") and tool.name != \"QueryResource\":\n            tool.llm = get_model(model=\"gpt-3.5-turbo\", api_key=model_api_key, organisation_id=organisation.id , temperature=0.4)\n        elif hasattr(tool, 'llm'):\n            tool.llm = get_model(model=agent_config[\"model\"], api_key=model_api_key, organisation_id=organisation.id, temperature=0.4)\n        if hasattr(tool, 'agent_id'):\n            tool.agent_id = self.agent_id\n        if hasattr(tool, 'agent_execution_id'):\n            tool.agent_execution_id = self.agent_execution_id\n        if hasattr(tool, 'resource_manager'):\n            tool.resource_manager = FileManager(session=self.session, agent_id=self.agent_id,\n                                                agent_execution_id=self.agent_execution_id)\n        if hasattr(tool, 'tool_response_manager'):\n            tool.tool_response_manager = ToolResponseQueryManager(session=self.session,\n                                                                  agent_execution_id=self.agent_execution_id,memory=memory)\n\n        if tool.name == \"QueryResourceTool\":\n            tool.description = tool.description.replace(\"{summary}\", resource_summary)\n\n        return tool"
  },
  {
    "path": "superagi/agent/tool_executor.py",
    "content": "from pydantic import ValidationError\n\nfrom superagi.agent.common_types import ToolExecutorResponse\nfrom superagi.apm.event_handler import EventHandler\nfrom superagi.lib.logger import logger\n\n\nclass ToolExecutor:\n    \"\"\"Executes the tool with the given args.\"\"\"\n    FINISH = \"finish\"\n\n    def __init__(self, organisation_id: int, agent_id: int, tools: list, agent_execution_id: int):\n        self.organisation_id = organisation_id\n        self.agent_id = agent_id\n        self.tools = tools\n        self.agent_execution_id = agent_execution_id\n\n    def execute(self, session, tool_name, tool_args):\n        \"\"\"Executes the tool with the given args.\n\n        Args:\n            session (Session): The database session.\n            tool_name (str): The name of the tool to execute.\n            tool_args (dict): The arguments to pass to the tool.\n        \"\"\"\n        tools = {t.name.lower().replace(\" \", \"\"): t for t in self.tools}\n        tool_name = tool_name.lower().replace(\" \", \"\")\n        if tool_name == ToolExecutor.FINISH or tool_name == \"\":\n            logger.info(\"\\nTask Finished :) \\n\")\n            return ToolExecutorResponse(status=\"COMPLETE\", result=\"\")\n        if tool_name in tools.keys():\n            status = \"SUCCESS\"\n            tool = tools[tool_name]\n            retry = False\n            EventHandler(session=session).create_event('tool_used', {'tool_name': tool.name, 'agent_execution_id': self.agent_execution_id}, self.agent_id,\n                                                       self.organisation_id),\n            try:\n                parsed_args = self.clean_tool_args(tool_args)\n                observation = tool.execute(parsed_args)\n            except ValidationError as e:\n                status = \"ERROR\"\n                retry = True\n                observation = (\n                    f\"Validation Error in args: {str(e)}, args: {tool_args}\"\n                )\n            except Exception as e:\n                status = \"ERROR\"\n                retry = True\n                observation = (\n                    f\"Error1: {str(e)}, {type(e).__name__}, args: {tool_args}\"\n                )\n            output = ToolExecutorResponse(status=status, result=f\"Tool {tool.name} returned: {observation}\",\n                                          retry=retry)\n        elif tool_name == \"ERROR\":\n            output = ToolExecutorResponse(status=\"ERROR\", result=f\"Error Tool Name: {tool_args}. \", retry=False)\n        else:\n            result = (\n                f\"Unknown tool '{tool_name}'. \"\n                f\"Please refer to the 'TOOLS' list for available \"\n                f\"tools and only respond in the specified JSON format.\"\n            )\n            output = ToolExecutorResponse(status=\"ERROR\", result=result, retry=True)\n\n        logger.info(\"Tool Response : \" + str(output) + \"\\n\")\n        return output\n\n    def clean_tool_args(self, args):\n        parsed_args = {}\n        for key in args.keys():\n            parsed_args[key] = args[key]\n            if type(args[key]) is dict and \"value\" in args[key]:\n                parsed_args[key] = args[key][\"value\"]\n        return parsed_args\n"
  },
  {
    "path": "superagi/agent/types/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/agent/types/agent_execution_status.py",
    "content": "from enum import Enum\n\n\nclass AgentExecutionStatus(Enum):\n    RUNNING = 'RUNNING'\n    WAITING_FOR_PERMISSION = 'WAITING_FOR_PERMISSION'\n    ITERATION_LIMIT_EXCEEDED = 'ITERATION_LIMIT_EXCEEDED'\n    WAIT_STEP = 'WAIT_STEP'\n    COMPLETED = 'COMPLETED'\n\n    @classmethod\n    def get_agent_execution_status(cls, store):\n        if store is None:\n            raise ValueError(\"Storage type cannot be None.\")\n        store = store.upper()\n        if store in cls.__members__:\n            return cls[store]\n        raise ValueError(f\"{store} is not a valid storage name.\")\n"
  },
  {
    "path": "superagi/agent/types/agent_workflow_step_action_types.py",
    "content": "from enum import Enum\n\n\nclass AgentWorkflowStepAction(Enum):\n    ITERATION_WORKFLOW = 'ITERATION_WORKFLOW'\n    TOOL = 'TOOL'\n    WAIT_STEP = 'WAIT_STEP'\n\n\n    @classmethod\n    def get_agent_workflow_action_type(cls, store):\n        if store is None:\n            raise ValueError(\"Storage type cannot be None.\")\n        store = store.upper()\n        if store in cls.__members__:\n            return cls[store]\n        raise ValueError(f\"{store} is not a valid storage name.\")\n"
  },
  {
    "path": "superagi/agent/types/wait_step_status.py",
    "content": "from enum import Enum\n\n\nclass AgentWorkflowStepWaitStatus(Enum):\n    PENDING = 'PENDING'\n    WAITING = 'WAITING'\n    COMPLETED = 'COMPLETED'\n\n    @classmethod\n    def get_agent_workflow_step_wait_status(cls, store):\n        if store is None:\n            raise ValueError(\"Storage type cannot be None.\")\n        store = store.upper()\n        if store in cls.__members__:\n            return cls[store]\n        raise ValueError(f\"{store} is not a valid storage name.\")\n"
  },
  {
    "path": "superagi/agent/workflow_seed.py",
    "content": "from superagi.agent.agent_prompt_builder import AgentPromptBuilder\nfrom superagi.agent.agent_prompt_template import AgentPromptTemplate\nfrom superagi.models.workflows.agent_workflow import AgentWorkflow\nfrom superagi.models.workflows.agent_workflow_step import AgentWorkflowStep\nfrom superagi.models.workflows.iteration_workflow import IterationWorkflow\nfrom superagi.models.workflows.iteration_workflow_step import IterationWorkflowStep\nfrom superagi.tools.apollo.apollo_search import ApolloSearchTool\nfrom superagi.tools.code.write_code import CodingTool\nfrom superagi.tools.code.write_spec import WriteSpecTool\nfrom superagi.tools.code.write_test import WriteTestTool\nfrom superagi.tools.email.read_email import ReadEmailTool\nfrom superagi.tools.email.send_email import SendEmailTool\nfrom superagi.tools.file.append_file import AppendFileTool\nfrom superagi.tools.file.list_files import ListFileTool\nfrom superagi.tools.file.read_file import ReadFileTool\nfrom superagi.tools.file.write_file import WriteFileTool\nfrom superagi.tools.github.add_file import GithubAddFileTool\nfrom superagi.tools.google_calendar.create_calendar_event import CreateEventCalendarTool\nfrom superagi.tools.google_calendar.google_calendar_toolkit import GoogleCalendarToolKit\nfrom superagi.tools.google_search.google_search import GoogleSearchTool\nfrom superagi.tools.jira.create_issue import CreateIssueTool\nfrom superagi.tools.searx.searx import SearxSearchTool\nfrom superagi.tools.slack.send_message import SlackMessageTool\nfrom superagi.tools.thinking.tools import ThinkingTool\nfrom superagi.tools.twitter.send_tweets import SendTweetsTool\nfrom superagi.tools.webscaper.tools import WebScraperTool\n\n\nclass AgentWorkflowSeed:\n    @classmethod\n    def build_sales_workflow(cls, session):\n        agent_workflow = AgentWorkflow.find_or_create_by_name(session, \"Sales Engagement Workflow\",\n                                                              \"Sales Engagement Workflow\")\n        # step1 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id,\n        #                                                             str(agent_workflow.id) + \"_step1\",\n        #                                                             ApolloSearchTool().name,\n        #                                                             \"Search for leads based on the given goals\",\n        #                                                             step_type=\"TRIGGER\")\n        #\n        step2 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id,\n                                                                    str(agent_workflow.id) + \"_step2\",\n                                                                    ListFileTool().name,\n                                                                    \"list the files\",\n                                                                    step_type=\"TRIGGER\")\n\n        step3 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id,\n                                                                    str(agent_workflow.id) + \"_step3\",\n                                                                    ReadFileTool().name,\n                                                                    \"Read the leads from the file\")\n\n        # task queue ends when the elements gets over\n        step4 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id,\n                                                                    str(agent_workflow.id) + \"_step4\",\n                                                                    \"TASK_QUEUE\",\n                                                                    \"Break the above response array of items\",\n                                                                    completion_prompt=\"Get array of items from the above response. Array should suitable utilization of JSON.parse().\")\n\n        step5 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id,\n                                                                    str(agent_workflow.id) + \"_step5\",\n                                                                    GoogleSearchTool().name,\n                                                                    \"Search about the company in which the lead is working\")\n\n        step6 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id,\n                                                                    str(agent_workflow.id) + \"_step6\",\n                                                                    \"WAIT_FOR_PERMISSION\",\n                                                                    \"Email will be based on this content. Do you want send the email?\")\n\n        step7 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id,\n                                                                    str(agent_workflow.id) + \"_step7\",\n                                                                    SearxSearchTool().name,\n                                                                    \"Search about the company given in the high-end goal only\")\n\n        step8 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id,\n                                                                    str(agent_workflow.id) + \"_step8\",\n                                                                    SendEmailTool().name,\n                                                                    \"Customize the Email according to the company information in the mail\")\n\n        step9 = AgentWorkflowStep.find_or_create_wait_workflow_step(session, agent_workflow.id,\n                                                                    str(agent_workflow.id) + \"_step9\",\n                                                                    \"Wait for 2 minutes\",\n                                                                    2*60)\n\n        step10 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id,\n                                                                    str(agent_workflow.id) + \"_step10\",\n                                                                     ReadEmailTool().name,\n                                                                     \"Read the email from adarshdeepmurari@gmail.com\")\n\n        step11 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id,\n                                                                    str(agent_workflow.id) + \"_step11\",\n                                                                    SendEmailTool().name,\n                                                                    \"Customize the Email according to the company information in the mail\")\n\n        # AgentWorkflowStep.add_next_workflow_step(session, step1.id, step2.id)\n        AgentWorkflowStep.add_next_workflow_step(session, step2.id, step3.id)\n        AgentWorkflowStep.add_next_workflow_step(session, step3.id, step4.id)\n        AgentWorkflowStep.add_next_workflow_step(session, step4.id, -1, \"COMPLETE\")\n        AgentWorkflowStep.add_next_workflow_step(session, step4.id, step5.id)\n        AgentWorkflowStep.add_next_workflow_step(session, step5.id, step6.id)\n        AgentWorkflowStep.add_next_workflow_step(session, step6.id, step7.id, \"YES\")\n        AgentWorkflowStep.add_next_workflow_step(session, step6.id, step5.id, \"NO\")\n        AgentWorkflowStep.add_next_workflow_step(session, step7.id, step8.id)\n        AgentWorkflowStep.add_next_workflow_step(session, step8.id, step9.id)\n        AgentWorkflowStep.add_next_workflow_step(session, step9.id, step10.id)\n        AgentWorkflowStep.add_next_workflow_step(session, step10.id, step11.id)\n        AgentWorkflowStep.add_next_workflow_step(session, step11.id, step4.id)\n        session.commit()\n\n    @classmethod\n    def build_recruitment_workflow(cls, session):\n        agent_workflow = AgentWorkflow.find_or_create_by_name(session, \"Recruitment Workflow\",\n                                                              \"Recruitment Workflow\")\n        step1 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id,\n                                                                    str(agent_workflow.id) + \"_step1\",\n                                                                    ListFileTool().name,\n                                                                    \"List the files from the resource manager\",\n                                                                    step_type=\"TRIGGER\")\n\n        # task queue ends when the elements gets over\n        step2 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id,\n                                                                    str(agent_workflow.id) + \"_step2\",\n                                                                    \"TASK_QUEUE\",\n                                                                    \"Break the above response array of items\",\n                                                                    completion_prompt=\"Get array of items from the above response. Array should suitable utilization of JSON.parse(). Skip job_description file from list.\")\n\n        step3 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id,\n                                                                    str(agent_workflow.id) + \"_step3\",\n                                                                    ReadFileTool().name,\n                                                                    \"Read the resume from above input\",\n                                                                    \"Check if the resume matches High-Level GOAL\")\n\n        step4 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id,\n                                                                    str(agent_workflow.id) + \"_step4\",\n                                                                    SendEmailTool().name,\n                                                                    \"Write a custom acceptance Email to the candidates\")\n\n        step5 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id,\n                                                                    str(agent_workflow.id) + \"_step5\",\n                                                                    SendEmailTool().name,\n                                                                    \"Write a custom Reject Email to the candidates\")\n\n        AgentWorkflowStep.add_next_workflow_step(session, step1.id, step2.id)\n        AgentWorkflowStep.add_next_workflow_step(session, step2.id, step3.id)\n        AgentWorkflowStep.add_next_workflow_step(session, step2.id, -1, \"COMPLETE\")\n        AgentWorkflowStep.add_next_workflow_step(session, step3.id, step4.id, \"YES\")\n        AgentWorkflowStep.add_next_workflow_step(session, step3.id, step5.id, \"NO\")\n        AgentWorkflowStep.add_next_workflow_step(session, step4.id, step2.id)\n        AgentWorkflowStep.add_next_workflow_step(session, step5.id, step2.id)\n        session.commit()\n\n    @classmethod\n    def build_coding_workflow(cls, session):\n        agent_workflow = AgentWorkflow.find_or_create_by_name(session, \"SuperCoder\", \"SuperCoder\")\n        step1 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id,\n                                                                    str(agent_workflow.id) + \"_step1\",\n                                                                    WriteSpecTool().name,\n                                                                    \"Spec description\",\n                                                                    step_type=\"TRIGGER\")\n\n        step2 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id,\n                                                                    str(agent_workflow.id) + \"_step2\",\n                                                                    WriteTestTool().name,\n                                                                    \"Test description\")\n\n        step3 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id,\n                                                                    str(agent_workflow.id) + \"_step3\",\n                                                                    CodingTool().name,\n                                                                    \"Code description\")\n\n\n        step4 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id,\n                                                                    str(agent_workflow.id) + \"_step4\",\n                                                                    \"WAIT_FOR_PERMISSION\",\n                                                                    \"Your code is ready. Do you want end?\")\n\n        AgentWorkflowStep.add_next_workflow_step(session, step1.id, step2.id)\n        AgentWorkflowStep.add_next_workflow_step(session, step2.id, step3.id)\n        AgentWorkflowStep.add_next_workflow_step(session, step3.id, step4.id)\n        AgentWorkflowStep.add_next_workflow_step(session, step4.id, -1, \"YES\")\n        AgentWorkflowStep.add_next_workflow_step(session, step4.id, step3.id, \"NO\")\n\n\n    @classmethod\n    def build_goal_based_agent(cls, session):\n        agent_workflow = AgentWorkflow.find_or_create_by_name(session, \"Goal Based Workflow\", \"Goal Based Workflow\")\n        step1 = AgentWorkflowStep.find_or_create_iteration_workflow_step(session, agent_workflow.id,\n                                                                         str(agent_workflow.id) + \"_step1\",\n                                                                         \"Goal Based Agent-I\", step_type=\"TRIGGER\")\n        AgentWorkflowStep.add_next_workflow_step(session, step1.id, step1.id)\n        AgentWorkflowStep.add_next_workflow_step(session, step1.id, -1, \"COMPLETE\")\n\n    @classmethod\n    def build_task_based_agent(cls, session):\n        agent_workflow = AgentWorkflow.find_or_create_by_name(session, \"Dynamic Task Workflow\", \"Dynamic Task Workflow\")\n        step1 = AgentWorkflowStep.find_or_create_iteration_workflow_step(session, agent_workflow.id,\n                                                                         str(agent_workflow.id) + \"_step1\",\n                                                                         \"Initialize Tasks-I\", step_type=\"TRIGGER\")\n        step2 = AgentWorkflowStep.find_or_create_iteration_workflow_step(session, agent_workflow.id,\n                                                                         str(agent_workflow.id) + \"_step2\",\n                                                                         \"Dynamic Task Queue-I\", step_type=\"NORMAL\")\n        AgentWorkflowStep.add_next_workflow_step(session, step1.id, step2.id)\n        AgentWorkflowStep.add_next_workflow_step(session, step2.id, step2.id)\n        AgentWorkflowStep.add_next_workflow_step(session, step2.id, -1, \"COMPLETE\")\n\n    @classmethod\n    def build_fixed_task_based_agent(cls, session):\n        agent_workflow = AgentWorkflow.find_or_create_by_name(session, \"Fixed Task Workflow\", \"Fixed Task Workflow\")\n        step1 = AgentWorkflowStep.find_or_create_iteration_workflow_step(session, agent_workflow.id,\n                                                                         str(agent_workflow.id) + \"_step1\",\n                                                                         \"Initialize Tasks-I\", step_type=\"TRIGGER\")\n        step2 = AgentWorkflowStep.find_or_create_iteration_workflow_step(session, agent_workflow.id,\n                                                                         str(agent_workflow.id) + \"_step2\",\n                                                                         \"Fixed Task Queue-I\", step_type=\"NORMAL\")\n        AgentWorkflowStep.add_next_workflow_step(session, step1.id, step2.id)\n        AgentWorkflowStep.add_next_workflow_step(session, step2.id, step2.id)\n        AgentWorkflowStep.add_next_workflow_step(session, step2.id, -1, \"COMPLETE\")\n\n\nclass IterationWorkflowSeed:\n    @classmethod\n    def build_single_step_agent(cls, session):\n        iteration_workflow = IterationWorkflow.find_or_create_by_name(session, \"Goal Based Agent-I\", \"Goal Based Agent\")\n        output = AgentPromptTemplate.get_super_agi_single_prompt()\n        IterationWorkflowStep.find_or_create_step(session, iteration_workflow.id, \"gb1\",\n                                                  output[\"prompt\"],\n                                                  str(output[\"variables\"]), \"TRIGGER\", \"tools\",\n                                                  history_enabled=True,\n                                                  completion_prompt=\"Determine which next tool to use, and respond using the format specified above:\")\n\n    @classmethod\n    def build_task_based_agents(cls, session):\n        iteration_workflow = IterationWorkflow.find_or_create_by_name(session, \"Dynamic Task Queue-I\",\n                                                                      \"Dynamic Task Queue\", has_task_queue=True)\n\n        output = AgentPromptTemplate.analyse_task()\n        workflow_step1 = IterationWorkflowStep.find_or_create_step(session, iteration_workflow.id, \"tb1\",\n                                                                   output[\"prompt\"],\n                                                                   str(output[\"variables\"]), \"TRIGGER\", \"tools\")\n\n        output = AgentPromptTemplate.create_tasks()\n        workflow_step2 = IterationWorkflowStep.find_or_create_step(session, iteration_workflow.id, \"tb2\",\n                                                                   output[\"prompt\"],\n                                                                   str(output[\"variables\"]), \"NORMAL\", \"tasks\")\n\n        output = AgentPromptTemplate.prioritize_tasks()\n        workflow_step3 = IterationWorkflowStep.find_or_create_step(session, iteration_workflow.id, \"tb3\",\n                                                                   output[\"prompt\"],\n                                                                   str(output[\"variables\"]), \"NORMAL\", \"replace_tasks\")\n\n        workflow_step1.next_step_id = workflow_step2.id\n        workflow_step2.next_step_id = workflow_step3.id\n\n        session.commit()\n\n    @classmethod\n    def build_initialize_task_workflow(cls, session):\n        iteration_workflow = IterationWorkflow.find_or_create_by_name(session, \"Initialize Tasks-I\", \"Initialize Tasks\",\n                                                                      has_task_queue=True)\n        output = AgentPromptTemplate.start_task_based()\n\n        IterationWorkflowStep.find_or_create_step(session, iteration_workflow.id, \"init_task1\",\n                                                  output[\"prompt\"], str(output[\"variables\"]), \"TRIGGER\", \"tasks\")\n\n    @classmethod\n    def build_action_based_agents(cls, session):\n        iteration_workflow = IterationWorkflow.find_or_create_by_name(session, \"Fixed Task Queue-I\", \"Fixed Task Queue\",\n                                                                      has_task_queue=True)\n        output = AgentPromptTemplate.analyse_task()\n        IterationWorkflowStep.find_or_create_step(session, iteration_workflow.id, \"ab1\",\n                                                  output[\"prompt\"], str(output[\"variables\"]), \"TRIGGER\", \"tools\")\n"
  },
  {
    "path": "superagi/apm/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/apm/analytics_helper.py",
    "content": "from typing import List, Dict, Union, Any\nfrom sqlalchemy import text, func, and_\nfrom sqlalchemy.orm import Session\n\nfrom superagi.models.events import Event\n\n\nclass AnalyticsHelper:\n\n    def __init__(self, session: Session, organisation_id: int):\n        self.session = session\n        self.organisation_id = organisation_id\n\n    def calculate_run_completed_metrics(self) -> Dict[str, Dict[str, Union[int, List[Dict[str, int]]]]]:\n\n        agent_model_query = self.session.query(\n            Event.event_property['model'].label('model'),\n            Event.agent_id\n        ).filter_by(event_name=\"agent_created\", org_id=self.organisation_id).subquery()\n\n        agent_runs_query = self.session.query(\n            agent_model_query.c.model,\n            func.count(Event.id).label('runs')\n        ).join(Event, and_(Event.agent_id == agent_model_query.c.agent_id, Event.org_id == self.organisation_id)).filter(Event.event_name.in_(['run_completed', 'run_iteration_limit_crossed'])).group_by(agent_model_query.c.model).subquery()\n\n        agent_tokens_query = self.session.query(\n            agent_model_query.c.model,\n            func.sum(text(\"(event_property->>'tokens_consumed')::int\")).label('tokens')\n        ).join(Event, and_(Event.agent_id == agent_model_query.c.agent_id, Event.org_id == self.organisation_id)).filter(Event.event_name.in_(['run_completed', 'run_iteration_limit_crossed'])).group_by(agent_model_query.c.model).subquery()\n\n        agent_count_query = self.session.query(\n            agent_model_query.c.model,\n            func.count(agent_model_query.c.agent_id).label('agents')\n        ).group_by(agent_model_query.c.model).subquery()\n\n        agents = self.session.query(agent_count_query).all()\n        runs = self.session.query(agent_runs_query).all()\n        tokens = self.session.query(agent_tokens_query).all()\n\n        metrics = {\n            'agent_details': {\n                'total_agents': sum([item.agents for item in agents]),\n                'model_metrics': [{'name': item.model, 'value': item.agents} for item in agents]\n            },\n            'run_details': {\n                'total_runs': sum([item.runs for item in runs]),\n                'model_metrics': [{'name': item.model, 'value': item.runs} for item in runs]\n            },\n            'tokens_details': {\n                'total_tokens': sum([item.tokens for item in tokens]),\n                'model_metrics': [{'name': item.model, 'value': item.tokens} for item in tokens]\n            },\n        }\n\n        return metrics\n\n    def fetch_agent_data(self) -> Dict[str, List[Dict[str, Any]]]:\n        agent_subquery = self.session.query(\n            Event.agent_id,\n            Event.event_property['agent_name'].label('agent_name'),\n            Event.event_property['model'].label('model')\n        ).filter_by(event_name=\"agent_created\", org_id=self.organisation_id).subquery()\n\n        run_subquery = self.session.query(\n            Event.agent_id,\n            func.sum(text(\"(event_property->>'tokens_consumed')::int\")).label('total_tokens'),\n            func.sum(text(\"(event_property->>'calls')::int\")).label('total_calls'),\n            func.count(Event.id).label('runs_completed'),\n        ).filter(and_(Event.event_name.in_(['run_completed', 'run_iteration_limit_crossed']), Event.org_id == self.organisation_id)).group_by(Event.agent_id).subquery()\n\n        tool_subquery = self.session.query(\n            Event.agent_id,\n            func.array_agg(Event.event_property['tool_name'].distinct()).label('tools_used'),\n        ).filter_by(event_name=\"tool_used\", org_id=self.organisation_id).group_by(Event.agent_id).subquery()\n\n        start_time_subquery = self.session.query(\n            Event.agent_id,\n            Event.event_property['agent_execution_id'].label('agent_execution_id'),\n            func.min(func.extract('epoch', Event.created_at)).label('start_time')\n        ).filter_by(event_name=\"run_created\", org_id=self.organisation_id).group_by(Event.agent_id, Event.event_property['agent_execution_id']).subquery()\n\n        end_time_subquery = self.session.query(\n            Event.agent_id,\n            Event.event_property['agent_execution_id'].label('agent_execution_id'),\n            func.max(func.extract('epoch', Event.created_at)).label('end_time')\n        ).filter(and_(Event.event_name.in_(['run_completed', 'run_iteration_limit_crossed']), Event.org_id == self.organisation_id)).group_by(Event.agent_id, Event.event_property['agent_execution_id']).subquery()\n\n        time_diff_subquery = self.session.query(\n            start_time_subquery.c.agent_id,\n            (func.avg(end_time_subquery.c.end_time - start_time_subquery.c.start_time)).label('avg_run_time')\n        ).join(end_time_subquery, start_time_subquery.c.agent_execution_id == end_time_subquery.c.agent_execution_id). \\\n            group_by(start_time_subquery.c.agent_id).subquery()\n\n        query = self.session.query(\n            agent_subquery.c.agent_id,\n            agent_subquery.c.agent_name,\n            agent_subquery.c.model,\n            run_subquery.c.total_tokens,\n            run_subquery.c.total_calls,\n            run_subquery.c.runs_completed,\n            tool_subquery.c.tools_used,\n            time_diff_subquery.c.avg_run_time\n        ).outerjoin(run_subquery, run_subquery.c.agent_id == agent_subquery.c.agent_id) \\\n            .outerjoin(tool_subquery, tool_subquery.c.agent_id == agent_subquery.c.agent_id) \\\n            .outerjoin(time_diff_subquery, time_diff_subquery.c.agent_id == agent_subquery.c.agent_id)\n\n        result = query.all()\n\n        agent_details = [{\n            \"name\": row.agent_name,\n            \"agent_id\": row.agent_id,\n            \"runs_completed\": row.runs_completed if row.runs_completed else 0,\n            \"total_calls\": row.total_calls if row.total_calls else 0,\n            \"total_tokens\": row.total_tokens if row.total_tokens else 0,\n            \"tools_used\": row.tools_used,\n            \"model_name\": row.model,\n            \"avg_run_time\": row.avg_run_time if row.avg_run_time else 0,\n        } for row in result]\n\n        return {'agent_details': agent_details}\n\n\n    def fetch_agent_runs(self, agent_id: int) -> List[Dict[str, int]]:\n        agent_runs = []\n        completed_subquery = self.session.query(\n            Event.event_property['agent_execution_id'].label('completed_agent_execution_id'),\n            Event.event_property['tokens_consumed'].label('tokens_consumed'),\n            Event.event_property['calls'].label('calls'),\n            Event.updated_at\n        ).filter(Event.event_name.in_(['run_completed','run_iteration_limit_crossed']), Event.agent_id == agent_id, Event.org_id == self.organisation_id).subquery()\n\n        created_subquery = self.session.query(\n            Event.event_property['agent_execution_id'].label('created_agent_execution_id'),\n            Event.event_property['agent_execution_name'].label('agent_execution_name'),\n            Event.created_at\n        ).filter(Event.event_name == \"run_created\", Event.agent_id == agent_id, Event.org_id == self.organisation_id).subquery()\n\n        query = self.session.query(\n            created_subquery.c.agent_execution_name,\n            completed_subquery.c.tokens_consumed,\n            completed_subquery.c.calls,\n            created_subquery.c.created_at,\n            completed_subquery.c.updated_at\n        ).join(completed_subquery, completed_subquery.c.completed_agent_execution_id == created_subquery.c.created_agent_execution_id)\n\n        result = query.all()\n\n        agent_runs = [{\n            'name': row.agent_execution_name,\n            'tokens_consumed': int(row.tokens_consumed) if row.tokens_consumed else 0,\n            'calls': int(row.calls) if row.calls else 0,\n            'created_at': row.created_at,\n            'updated_at': row.updated_at\n        } for row in result]\n\n        return agent_runs\n\n\n    def get_active_runs(self) -> List[Dict[str, str]]:\n        running_executions = []\n\n        end_event_subquery = self.session.query(\n            Event.event_property['agent_execution_id'].label('agent_execution_id'),\n        ).filter(\n            Event.event_name.in_(['run_completed', 'run_iteration_limit_crossed']),\n            Event.org_id == self.organisation_id\n        ).subquery()\n\n        start_subquery = self.session.query(\n            Event.event_property['agent_execution_id'].label('agent_execution_id'),\n            Event.event_property['agent_execution_name'].label('agent_execution_name'),\n            Event.created_at,\n            Event.agent_id\n        ).filter_by(event_name=\"run_created\", org_id = self.organisation_id).subquery()\n\n        agent_created_subquery = self.session.query(\n            Event.event_property['agent_name'].label('agent_name'),\n            Event.agent_id\n        ).filter_by(event_name=\"agent_created\", org_id = self.organisation_id).subquery()\n\n        query = self.session.query(\n            start_subquery.c.agent_execution_name,\n            start_subquery.c.created_at,\n            agent_created_subquery.c.agent_name\n        ).select_from(start_subquery)\n\n        query = query.outerjoin(end_event_subquery, start_subquery.c.agent_execution_id == end_event_subquery.c.agent_execution_id).filter(end_event_subquery.c.agent_execution_id == None)\n\n        query = query.join(agent_created_subquery, start_subquery.c.agent_id == agent_created_subquery.c.agent_id)\n\n        result = query.all()\n\n        running_executions = [{\n            'name': row.agent_execution_name,\n            'created_at': row.created_at,\n            'agent_name': row.agent_name or 'Unknown',\n        } for row in result]\n\n        return running_executions\n"
  },
  {
    "path": "superagi/apm/call_log_helper.py",
    "content": "import logging\nfrom typing import Optional\nfrom sqlalchemy.exc import SQLAlchemyError\nfrom sqlalchemy.orm import Session\nfrom sqlalchemy import func, distinct\nfrom superagi.models.call_logs import CallLogs\nfrom superagi.models.agent import Agent\nfrom superagi.models.tool import Tool\nfrom superagi.models.toolkit import Toolkit\n\nclass CallLogHelper:\n\n    def __init__(self, session: Session, organisation_id: int):\n        self.session = session\n        self.organisation_id = organisation_id\n\n    def create_call_log(self, agent_execution_name: str, agent_id: int, tokens_consumed: int, tool_used: str, model: str) -> Optional[CallLogs]:\n        try:\n            call_log = CallLogs(\n                agent_execution_name=agent_execution_name,\n                agent_id=agent_id,\n                tokens_consumed=tokens_consumed,\n                tool_used=tool_used,\n                model=model,\n                org_id=self.organisation_id,\n            )\n            self.session.add(call_log)\n            self.session.commit()\n            return call_log\n        except SQLAlchemyError as err:\n            logging.error(f\"Error while creating call log: {str(err)}\")\n            return None\n\n    def fetch_data(self, model: str):\n        try:\n            result = self.session.query(\n                func.sum(CallLogs.tokens_consumed),\n                func.count(CallLogs.id),\n                func.count(distinct(CallLogs.agent_id))\n            ).filter(CallLogs.model == model, CallLogs.org_id == self.organisation_id).first()\n\n            if result is None:\n                return None\n\n            model_data = {\n                'model': model,\n                'total_tokens': result[0],\n                'total_calls': result[1],\n                'total_agents': result[2],\n                'runs': []\n            }\n\n            runs = self.session.query(CallLogs).filter(CallLogs.model == model,\n                                                       CallLogs.org_id == self.organisation_id).all()\n\n            run_agent_ids = [run.agent_id for run in runs]\n            agents = self.session.query(Agent).filter(Agent.id.in_(run_agent_ids)).all()\n            agent_id_name_map = {agent.id: agent.name for agent in agents}\n            tools_used = [run.tool_used for run in runs]\n            toolkit_ids_allowed = self.session.query(Toolkit.id).filter(Toolkit.organisation_id == self.organisation_id).all()\n            toolkit_ids_allowed = [toolkit_id[0] for toolkit_id in toolkit_ids_allowed]\n            tools = self.session.query(Tool).filter(Tool.name.in_(tools_used), Tool.toolkit_id.in_(toolkit_ids_allowed))\\\n                .all()\n            tools_name_toolkit_id_map = {tool.name: tool.toolkit_id for tool in tools}\n\n            for run in runs:\n                model_data['runs'].append({\n                    'id': run.id,\n                    'agent_execution_name': run.agent_execution_name,\n                    'agent_id': run.agent_id,\n                    'agent_name': agent_id_name_map[run.agent_id] if run.agent_id in agent_id_name_map else None,\n                    'tokens_consumed': run.tokens_consumed,\n                    'tool_used': run.tool_used,\n                    'toolkit_name': tools_name_toolkit_id_map[run.tool_used] if run.tool_used in tools_name_toolkit_id_map else None,\n                    'org_id': run.org_id,\n                    'created_at': run.created_at,\n                    'updated_at': run.updated_at,\n                })\n\n            model_data['runs'] = model_data['runs'][::-1]\n\n            return model_data\n\n        except SQLAlchemyError as err:\n            logging.error(f\"Error while fetching call log data: {str(err)}\")\n            return None\n"
  },
  {
    "path": "superagi/apm/event_handler.py",
    "content": "import logging\nfrom typing import Optional, Dict\nfrom sqlalchemy.exc import SQLAlchemyError\nfrom sqlalchemy.orm import Session\n\nfrom superagi.models.events import Event\n\nclass EventHandler:\n\n    def __init__(self, session: Session):\n        self.session = session\n\n    def create_event(self, event_name: str, event_property: Dict, agent_id: int,\n                     org_id: int, event_value: int = 1) -> Optional[Event]:\n        try:\n            event = Event(\n                event_name=event_name,\n                event_value=event_value,\n                event_property=event_property,\n                agent_id=agent_id,\n                org_id=org_id,\n            )\n            self.session.add(event)\n            self.session.commit()\n            return event\n        except SQLAlchemyError as err:\n            logging.error(f\"Error while creating event: {str(err)}\")\n            return None"
  },
  {
    "path": "superagi/apm/knowledge_handler.py",
    "content": "from sqlalchemy.orm import Session\nfrom superagi.models.events import Event\nfrom superagi.models.knowledges import Knowledges\nfrom sqlalchemy import Integer, or_, label, case, and_\nfrom fastapi import HTTPException\nfrom typing import List, Dict, Union, Any\nfrom sqlalchemy.sql import func\nfrom sqlalchemy.orm import aliased\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.models.agent_execution_config import AgentExecutionConfiguration\nimport pytz\nfrom datetime import datetime\n\n\nclass KnowledgeHandler:\n    def __init__(self, session: Session, organisation_id: int):\n        self.session = session\n        self.organisation_id = organisation_id\n\n\n    def get_knowledge_usage_by_name(self, knowledge_name: str) -> Dict[str, Dict[str, int]]:\n\n        is_knowledge_valid = self.session.query(Knowledges.id).filter_by(name=knowledge_name).filter(Knowledges.organisation_id == self.organisation_id).first()\n        if not is_knowledge_valid:\n            raise HTTPException(status_code=404, detail=\"Knowledge not found\")\n        EventAlias = aliased(Event)\n\n        knowledge_used_event = self.session.query(\n            Event.event_property['knowledge_name'].label('knowledge_name'),\n            func.count(Event.agent_id.distinct()).label('knowledge_unique_agents')\n        ).filter(\n            Event.event_name == 'knowledge_picked',\n            Event.org_id == self.organisation_id,\n            Event.event_property['knowledge_name'].astext == knowledge_name\n        ).group_by(\n            Event.event_property['knowledge_name']\n        ).first()\n\n        if knowledge_used_event is None:\n            return {}\n\n        knowledge_data = {\n                'knowledge_unique_agents': knowledge_used_event.knowledge_unique_agents,\n                'knowledge_calls': self.session.query(\n                    EventAlias\n                ).filter(\n                    EventAlias.event_property['tool_name'].astext == 'Knowledge Search',\n                    EventAlias.event_name == 'tool_used',\n                    EventAlias.org_id == self.organisation_id,\n                    EventAlias.agent_id.in_(self.session.query(Event.agent_id).filter(\n                        Event.event_name == 'knowledge_picked',\n                        Event.org_id == self.organisation_id,\n                        Event.event_property['knowledge_name'].astext == knowledge_name\n                    ))\n                ).count()\n            }\n\n        return knowledge_data\n    \n\n    def get_knowledge_events_by_name(self, knowledge_name: str) -> List[Dict[str, Union[str, int, List[str]]]]:\n\n        is_knowledge_valid = self.session.query(Knowledges.id).filter_by(name=knowledge_name).filter(Knowledges.organisation_id == self.organisation_id).first()\n\n        if not is_knowledge_valid:\n            raise HTTPException(status_code=404, detail=\"Knowledge not found\")\n\n        knowledge_events = self.session.query(Event).filter(\n            Event.org_id == self.organisation_id,\n            Event.event_name == 'knowledge_picked',\n            Event.event_property['knowledge_name'].astext == knowledge_name\n        ).all()\n\n        knowledge_events = [ke for ke in knowledge_events if 'agent_execution_id' in ke.event_property]\n\n        event_runs = self.session.query(Event).filter(\n            Event.org_id == self.organisation_id,\n            or_(Event.event_name == 'run_completed', Event.event_name == 'run_iteration_limit_crossed')\n        ).all()\n\n        agent_created_events = self.session.query(Event).filter(\n            Event.org_id == self.organisation_id,\n            Event.event_name == 'agent_created'\n        ).all()\n\n        results = []\n\n        for knowledge_event in knowledge_events:\n            agent_execution_id = knowledge_event.event_property['agent_execution_id']\n\n            event_run = next((er for er in event_runs if er.agent_id == knowledge_event.agent_id and er.event_property['agent_execution_id'] == agent_execution_id), None)\n            agent_created_event = next((ace for ace in agent_created_events if ace.agent_id == knowledge_event.agent_id), None)\n\n            model_query = self.session.query(AgentExecutionConfiguration).filter(\n                AgentExecutionConfiguration.agent_execution_id == agent_execution_id, \n                AgentExecutionConfiguration.key == 'model'\n            ).first()\n\n            if model_query and model_query.value != 'None':\n                model_value = model_query.value\n            else:\n                model_value = None\n            try:\n                user_timezone = AgentConfiguration.get_agent_config_by_key_and_agent_id(session=self.session, key='user_timezone', agent_id=knowledge_event.agent_id)\n                if user_timezone and user_timezone.value != 'None':\n                    tz = pytz.timezone(user_timezone.value)\n                else:\n                    tz = pytz.timezone('GMT')       \n            except AttributeError:\n                tz = pytz.timezone('GMT')\n\n            if event_run and agent_created_event:\n                actual_time = knowledge_event.created_at.astimezone(tz).strftime(\"%d %B %Y %H:%M\")\n\n                result_dict = {\n                    'agent_execution_id': agent_execution_id,\n                    'created_at': actual_time,\n                    'tokens_consumed': event_run.event_property['tokens_consumed'],\n                    'calls': event_run.event_property['calls'],\n                    'agent_execution_name': event_run.event_property['name'],\n                    'agent_name': agent_created_event.event_property['agent_name'],\n                    'model': model_value if model_value else agent_created_event.event_property['model']\n                }\n                if agent_execution_id not in [i['agent_execution_id'] for i in results]:\n                    results.append(result_dict)\n\n        results = sorted(results, key=lambda x: datetime.strptime(x['created_at'], '%d %B %Y %H:%M'), reverse=True)\n        return results"
  },
  {
    "path": "superagi/apm/tools_handler.py",
    "content": "from typing import List, Dict, Union\nfrom sqlalchemy import func, distinct, and_\nfrom sqlalchemy.orm import Session\nfrom sqlalchemy import Integer, String\nfrom fastapi import HTTPException\nfrom superagi.models.events import Event\nfrom superagi.models.tool import Tool\nfrom superagi.models.toolkit import Toolkit\nfrom sqlalchemy import or_\nfrom sqlalchemy.sql import label\nfrom datetime import datetime\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.models.agent_execution_config import AgentExecutionConfiguration\nimport pytz\n\nclass ToolsHandler:\n    def __init__(self, session: Session, organisation_id: int):\n        self.session = session\n        self.organisation_id = organisation_id\n\n    def get_tool_and_toolkit(self):\n        tools_and_toolkits = self.session.query(\n            func.lower(Tool.name).label('tool_name'), Toolkit.name.label('toolkit_name')).join(\n            Toolkit, Tool.toolkit_id == Toolkit.id).all()\n\n        return {item.tool_name.lower(): item.toolkit_name for item in tools_and_toolkits}\n\n    def calculate_tool_usage(self) -> List[Dict[str, int]]:\n        tool_usage = []\n        tool_used_subquery = self.session.query(\n            Event.event_property['tool_name'].label('tool_name'),\n            Event.agent_id\n        ).filter_by(event_name=\"tool_used\", org_id=self.organisation_id).subquery()\n\n        agent_count = self.session.query(\n            tool_used_subquery.c.tool_name,\n            func.count(func.distinct(tool_used_subquery.c.agent_id)).label('unique_agents')\n        ).group_by(tool_used_subquery.c.tool_name).subquery()\n\n        total_usage = self.session.query(\n            tool_used_subquery.c.tool_name,\n            func.count(tool_used_subquery.c.tool_name).label('total_usage')\n        ).group_by(tool_used_subquery.c.tool_name).subquery()\n\n        query = self.session.query(\n            agent_count.c.tool_name,\n            agent_count.c.unique_agents,\n            total_usage.c.total_usage,\n        ).join(total_usage, total_usage.c.tool_name == agent_count.c.tool_name)\n\n        tool_and_toolkit = self.get_tool_and_toolkit()\n\n        result = query.all()\n\n        tool_usage = [{\n            'tool_name': row.tool_name,\n            'unique_agents': row.unique_agents,\n            'total_usage': row.total_usage,\n            'toolkit': tool_and_toolkit.get(row.tool_name.lower(), None)\n        } for row in result]\n\n        tool_usage.sort(key=lambda tool: tool['total_usage'], reverse=True)\n\n        return tool_usage\n    \n    def get_tool_usage_by_name(self, tool_name: str) -> Dict[str, Dict[str, int]]:\n        is_tool_name_valid = self.session.query(Tool).filter_by(name=tool_name).first()\n\n        if not is_tool_name_valid:\n            raise HTTPException(status_code=404, detail=\"Tool not found\")\n\n        tool_name_event = self.session.query(\n            Event.event_property['tool_name'].cast(String).label('tool_name'), \n            func.count(Event.id).label('tool_calls'),\n            func.count(distinct(Event.agent_id)).label('tool_unique_agents')\n        ).filter(\n            Event.event_name == 'tool_used',\n            Event.org_id == self.organisation_id,\n            Event.event_property['tool_name'].astext == tool_name\n        ).group_by(\n            Event.event_property['tool_name'].cast(String)\n        ).first()\n\n        tool_data = {}\n        tool_calls = 0\n        tool_unique_agents = 0\n\n        if tool_name_event:\n            tool_calls += tool_name_event.tool_calls\n            tool_unique_agents += tool_name_event.tool_unique_agents\n\n        tool_data = {\n            'tool_calls': tool_calls,\n            'tool_unique_agents': tool_unique_agents\n        }   \n\n        return tool_data\n\n\n    def get_tool_events_by_name(self, tool_name: str) -> List[Dict[str, Union[str, int, List[str]]]]:\n        is_tool_name_valid = self.session.query(Tool).filter_by(name=tool_name).first()\n\n        if not is_tool_name_valid:\n            raise HTTPException(status_code=404, detail=\"Tool not found\")\n\n        tool_events = self.session.query(Event).filter(\n            Event.org_id == self.organisation_id,\n            Event.event_name == 'tool_used',\n            Event.event_property['tool_name'].astext == tool_name\n        ).all()\n\n        tool_events = [te for te in tool_events if 'agent_execution_id' in te.event_property]\n\n        event_runs = self.session.query(Event).filter(\n            Event.org_id == self.organisation_id,\n            or_(Event.event_name == 'run_completed', Event.event_name == 'run_iteration_limit_crossed')\n        ).all()\n\n        agent_created_events = self.session.query(Event).filter(\n            Event.org_id == self.organisation_id,\n            Event.event_name == 'agent_created'\n        ).all()\n\n        results = []\n\n        for tool_event in tool_events:\n            agent_execution_id = tool_event.event_property['agent_execution_id']\n\n            event_run = next((er for er in event_runs if er.agent_id == tool_event.agent_id and er.event_property['agent_execution_id'] == agent_execution_id), None)\n            agent_created_event = next((ace for ace in agent_created_events if ace.agent_id == tool_event.agent_id), None)\n\n            model_query = self.session.query(AgentExecutionConfiguration).filter(\n                AgentExecutionConfiguration.agent_execution_id == agent_execution_id, \n                AgentExecutionConfiguration.key == 'model'\n            ).first()\n\n            if model_query and model_query.value != 'None':\n                model_value = model_query.value\n            else:\n                model_value = None\n            try:\n                user_timezone = AgentConfiguration.get_agent_config_by_key_and_agent_id(session=self.session, key='user_timezone', agent_id=tool_event.agent_id)\n                if user_timezone and user_timezone.value != 'None':\n                    tz = pytz.timezone(user_timezone.value)\n                else:\n                    tz = pytz.timezone('GMT')       \n            except AttributeError:\n                tz = pytz.timezone('GMT')\n\n            if event_run and agent_created_event:\n                actual_time = tool_event.created_at.astimezone(tz).strftime(\"%d %B %Y %H:%M\")\n                other_tools_events = self.session.query(\n                    Event\n                ).filter(\n                    Event.org_id == self.organisation_id,\n                    Event.event_name == 'tool_used',\n                    Event.event_property['tool_name'].astext != tool_name,\n                    Event.agent_id == tool_event.agent_id, \n                    Event.id.between(tool_event.id, event_run.id)\n                ).all()\n\n                other_tools = [ote.event_property['tool_name'] for ote in other_tools_events]\n\n                result_dict = {\n                    'created_at': actual_time,\n                    'agent_execution_id': agent_execution_id,\n                    'tokens_consumed': event_run.event_property['tokens_consumed'],\n                    'calls': event_run.event_property['calls'],\n                    'agent_execution_name': event_run.event_property['name'],\n                    'other_tools': other_tools,\n                    'agent_name': agent_created_event.event_property['agent_name'],\n                    'model': model_value if model_value else agent_created_event.event_property['model']\n                }\n\n                if agent_execution_id not in [i['agent_execution_id'] for i in results]:\n                    results.append(result_dict)\n\n        results = sorted(results, key=lambda x: datetime.strptime(x['created_at'], '%d %B %Y %H:%M'), reverse=True)\n\n        return results\n    "
  },
  {
    "path": "superagi/config/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/config/config.py",
    "content": "import os\nfrom pydantic import BaseSettings\nfrom pathlib import Path\nimport yaml\nfrom superagi.lib.logger import logger\n\nCONFIG_FILE = \"config.yaml\"\n\n\nclass Config(BaseSettings):\n    class Config:\n        env_file_encoding = \"utf-8\"\n        extra = \"allow\"  # Allow extra fields\n\n    @classmethod\n    def load_config(cls, config_file: str) -> dict:\n        # If config file exists, read it\n        if os.path.exists(config_file):\n            with open(config_file, \"r\") as file:\n                config_data = yaml.safe_load(file)\n            if config_data is None:\n                config_data = {}\n        else:\n            # If config file doesn't exist, prompt for credentials and create new file\n            logger.info(\"\\033[91m\\033[1m\"\n        + \"\\nConfig file not found. Enter required keys and values.\"\n        + \"\\033[0m\\033[0m\")\n            config_data = {}\n            with open(config_file, \"w\") as file:\n                yaml.dump(config_data, file, default_flow_style=False)\n\n        # Merge environment variables and config data\n        env_vars = dict(os.environ)\n        config_data = {**config_data, **env_vars}\n\n        return config_data\n\n    def __init__(self, config_file: str, **kwargs):\n        config_data = self.load_config(config_file)\n        super().__init__(**config_data, **kwargs)\n\n    def get_config(self, key: str, default: str = None) -> str:\n        return self.dict().get(key, default)\n\n\nROOT_DIR = os.path.dirname(Path(__file__).parent.parent)\n_config_instance = Config(ROOT_DIR + \"/\" + CONFIG_FILE)\n\n\ndef get_config(key: str, default: str = None) -> str:\n    return _config_instance.get_config(key, default)"
  },
  {
    "path": "superagi/controllers/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/controllers/agent.py",
    "content": "from fastapi import APIRouter\nfrom fastapi import HTTPException, Depends\nfrom fastapi_jwt_auth import AuthJWT\nfrom fastapi_sqlalchemy import db\nfrom pydantic import BaseModel\nfrom sqlalchemy import desc\nimport ast\n\nfrom pytz import timezone\nfrom sqlalchemy import func, or_\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_execution_config import AgentExecutionConfiguration\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.models.agent_schedule import AgentSchedule\nfrom superagi.models.agent_template import AgentTemplate\nfrom superagi.models.project import Project\nfrom superagi.models.workflows.agent_workflow import AgentWorkflow\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.tool import Tool\nfrom superagi.controllers.types.agent_schedule import AgentScheduleInput\nfrom superagi.controllers.types.agent_with_config import AgentConfigInput\nfrom superagi.controllers.types.agent_with_config_schedule import AgentConfigSchedule\nfrom jsonmerge import merge\nfrom datetime import datetime\nimport json\n\nfrom superagi.models.toolkit import Toolkit\nfrom superagi.models.knowledges import Knowledges\n\nfrom sqlalchemy import func\n# from superagi.types.db import AgentOut, AgentIn\nfrom superagi.helper.auth import check_auth\nfrom superagi.apm.event_handler import EventHandler\nfrom superagi.models.workflows.iteration_workflow import IterationWorkflow\n\nrouter = APIRouter()\n\n\nclass AgentOut(BaseModel):\n    id: int\n    name: str\n    project_id: int\n    description: str\n    created_at: datetime\n    updated_at: datetime\n\n    class Config:\n        orm_mode = True\n\n\nclass AgentIn(BaseModel):\n    name: str\n    project_id: int\n    description: str\n\n    class Config:\n        orm_mode = True\n\n\n@router.post(\"/create\", status_code=201)\ndef create_agent_with_config(agent_with_config: AgentConfigInput,\n                             Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Create a new agent with configurations.\n\n    Args:\n        agent_with_config (AgentConfigInput): Data for creating a new agent with configurations.\n            - name (str): Name of the agent.\n            - project_id (int): Identifier of the associated project.\n            - description (str): Description of the agent.\n            - goal (List[str]): List of goals for the agent.\n            - constraints (List[str]): List of constraints for the agent.\n            - tools (List[int]): List of tool identifiers associated with the agent.\n            - exit (str): Exit condition for the agent.\n            - iteration_interval (int): Interval between iterations for the agent.\n            - model (str): Model information for the agent.\n            - permission_type (str): Permission type for the agent.\n            - LTM_DB (str): LTM database for the agent.\n            - max_iterations (int): Maximum number of iterations for the agent.\n            - user_timezone (string): Timezone of the user\n\n    Returns:\n        dict: Dictionary containing the created agent's ID, execution ID, name, and content type.\n\n    Raises:\n        HTTPException (status_code=404): If the associated project or any of the tools is not found.\n    \"\"\"\n\n    project = db.session.query(Project).get(agent_with_config.project_id)\n    if not project:\n        raise HTTPException(status_code=404, detail=\"Project not found\")\n\n    invalid_tools = Tool.get_invalid_tools(agent_with_config.tools, db.session)\n    if len(invalid_tools) > 0:  # If the returned value is not True (then it is an invalid tool_id)\n        raise HTTPException(status_code=404,\n                           \n                            detail=f\"Tool with IDs {str(invalid_tools)} does not exist. 404 Not Found.\")\n\n    agent_toolkit_tools = Toolkit.fetch_tool_ids_from_toolkit(session=db.session,\n                                                              toolkit_ids=agent_with_config.toolkits)\n    agent_with_config.tools.extend(agent_toolkit_tools)\n    db_agent = Agent.create_agent_with_config(db, agent_with_config)\n\n    start_step = AgentWorkflow.fetch_trigger_step_id(db.session, db_agent.agent_workflow_id)\n    iteration_step_id = IterationWorkflow.fetch_trigger_step_id(db.session,\n                                                                start_step.action_reference_id).id if start_step.action_type == \"ITERATION_WORKFLOW\" else -1\n\n    # Creating an execution with RUNNING status\n    execution = AgentExecution(status='CREATED', last_execution_time=datetime.now(), agent_id=db_agent.id,\n                               name=\"New Run\", current_agent_step_id=start_step.id, iteration_workflow_step_id=iteration_step_id)\n\n    agent_execution_configs = {\n        \"goal\": agent_with_config.goal,\n        \"instruction\": agent_with_config.instruction,\n        \"constraints\": agent_with_config.constraints,\n        \"toolkits\": agent_with_config.toolkits,\n        \"exit\": agent_with_config.exit,\n        \"tools\": agent_with_config.tools,\n        \"iteration_interval\": agent_with_config.iteration_interval,\n        \"model\": agent_with_config.model,\n        \"permission_type\": agent_with_config.permission_type,\n        \"LTM_DB\": agent_with_config.LTM_DB,\n        \"max_iterations\": agent_with_config.max_iterations,\n        \"user_timezone\": agent_with_config.user_timezone,\n        \"knowledge\": agent_with_config.knowledge\n    }\n    db.session.add(execution)\n    db.session.commit()\n    db.session.flush()\n    AgentExecutionConfiguration.add_or_update_agent_execution_config(session=db.session, execution=execution,\n                                                                     agent_execution_configs=agent_execution_configs)\n\n    agent = db.session.query(Agent).filter(Agent.id == db_agent.id,  ).first()\n    organisation = agent.get_agent_organisation(db.session)\n    \n    EventHandler(session=db.session).create_event('run_created', \n                                                  {'agent_execution_id': execution.id,\n                                                   'agent_execution_name':  execution.name},\n                                                    db_agent.id,\n                                                    organisation.id if organisation else 0),\n\n    if agent_with_config.knowledge:\n        knowledge_name = db.session.query(Knowledges.name).filter(Knowledges.id == agent_with_config.knowledge).first()[0]\n        EventHandler(session=db.session).create_event('knowledge_picked', \n                                                      {'knowledge_name': knowledge_name, \n                                                        'agent_execution_id': execution.id},\n                                                      db_agent.id, \n                                                      organisation.id if organisation else 0)\n    \n    EventHandler(session=db.session).create_event('agent_created', \n                                                  {'agent_name': agent_with_config.name,\n                                                   'model': agent_with_config.model}, \n                                                  db_agent.id,\n                                                  organisation.id if organisation else 0)\n\n    db.session.commit()\n\n    return {\n        \"id\": db_agent.id,\n        \"execution_id\": execution.id,\n        \"name\": db_agent.name,\n        \"contentType\": \"Agents\"\n    }\n\n\n\n@router.post(\"/schedule\", status_code=201)\ndef create_and_schedule_agent(agent_config_schedule: AgentConfigSchedule,\n                              Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Create a new agent with configurations and scheduling.\n\n    Args:\n        agent_with_config_schedule (AgentConfigSchedule): Data for creating a new agent with configurations and scheduling.\n\n    Returns:\n        dict: Dictionary containing the created agent's ID, name, content type and schedule ID of the agent.\n\n    Raises:\n        HTTPException (status_code=500): If the associated agent fails to get scheduled.\n    \"\"\"\n\n    project = db.session.query(Project).get(agent_config_schedule.agent_config.project_id)\n    if not project:\n        raise HTTPException(status_code=404, detail=\"Project not found\")\n    agent_config = agent_config_schedule.agent_config\n    invalid_tools = Tool.get_invalid_tools(agent_config.tools, db.session)\n    if len(invalid_tools) > 0:  # If the returned value is not True (then it is an invalid tool_id)\n        raise HTTPException(status_code=404,\n                           \n                            detail=f\"Tool with IDs {str(invalid_tools)} does not exist. 404 Not Found.\")\n\n    agent_toolkit_tools = Toolkit.fetch_tool_ids_from_toolkit(session=db.session,\n                                                              toolkit_ids=agent_config.toolkits)\n    agent_config.tools.extend(agent_toolkit_tools)\n    db_agent = Agent.create_agent_with_config(db, agent_config)\n\n    # Update the agent_id of schedule before scheduling the agent\n    agent_schedule = agent_config_schedule.schedule\n\n    # Create a new agent schedule\n    agent_schedule = AgentSchedule(\n        agent_id=db_agent.id,\n        start_time=agent_schedule.start_time,\n        next_scheduled_time=agent_schedule.start_time,\n        recurrence_interval=agent_schedule.recurrence_interval,\n        expiry_date=agent_schedule.expiry_date,\n        expiry_runs=agent_schedule.expiry_runs,\n        current_runs=0,\n        status=\"SCHEDULED\"\n    )\n\n    agent_schedule.agent_id = db_agent.id\n    db.session.add(agent_schedule)\n    db.session.commit()\n\n    if agent_schedule.id is None:\n        raise HTTPException(status_code=500, detail=\"Failed to schedule agent\")\n\n    agent = db.session.query(Agent).filter(Agent.id == db_agent.id, ).first()\n    organisation = agent.get_agent_organisation(db.session)\n\n    EventHandler(session=db.session).create_event('agent_created', {'agent_name': agent_config.name,\n                                                                        'model': agent_config.model}, db_agent.id,\n                                                      organisation.id if organisation else 0)\n\n    db.session.commit()\n\n    return {\n        \"id\": db_agent.id,\n        \"name\": db_agent.name,\n        \"contentType\": \"Agents\",\n        \"schedule_id\": agent_schedule.id\n    }\n\n\n\n@router.post(\"/stop/schedule\", status_code=200)\ndef stop_schedule(agent_id: int, Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Stopping the scheduling for a given agent.\n\n    Args:\n        agent_id (int): Identifier of the Agent\n        Authorize (AuthJWT, optional): Authorization dependency. Defaults to Depends(check_auth).\n\n    Raises:\n        HTTPException (status_code=404): If the agent schedule is not found.\n    \"\"\"\n\n    agent_to_delete = db.session.query(AgentSchedule).filter(AgentSchedule.agent_id == agent_id,\n                                                             AgentSchedule.status == \"SCHEDULED\").first()\n    if not agent_to_delete:\n        raise HTTPException(status_code=404, detail=\"Schedule not found\")\n    agent_to_delete.status = \"STOPPED\"\n    db.session.commit()\n\n\n@router.put(\"/edit/schedule\", status_code=200)\ndef edit_schedule(schedule: AgentScheduleInput,\n                  Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Edit the scheduling for a given agent.\n\n    Args:\n        agent_id (int): Identifier of the Agent\n        schedule (AgentSchedule): New schedule data\n        Authorize (AuthJWT, optional): Authorization dependency. Defaults to Depends(check_auth).\n\n    Raises:\n        HTTPException (status_code=404): If the agent schedule is not found.\n    \"\"\"\n\n    agent_to_edit = db.session.query(AgentSchedule).filter(AgentSchedule.agent_id == schedule.agent_id, AgentSchedule.status == \"SCHEDULED\").first()\n                        \n    if not agent_to_edit:\n        raise HTTPException(status_code=404, detail=\"Schedule not found\")\n\n    # Update agent schedule with new data\n    agent_to_edit.start_time = schedule.start_time\n    agent_to_edit.next_scheduled_time = schedule.start_time\n    agent_to_edit.recurrence_interval = schedule.recurrence_interval\n    agent_to_edit.expiry_date = schedule.expiry_date\n    agent_to_edit.expiry_runs = schedule.expiry_runs\n\n    db.session.commit()\n\n\n@router.get(\"/get/schedule_data/{agent_id}\")\ndef get_schedule_data(agent_id: int, Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Get the scheduling data for a given agent.\n\n    Args:\n        agent_id (int): Identifier of the Agent\n\n    Raises:\n        HTTPException (status_code=404): If the agent schedule is not found.\n\n    Returns:\n        current_datetime (DateTime): Current Date and Time.\n        recurrence_interval (String): Time interval for recurring schedule run.\n        expiry_date (DateTime): The date and time when the agent is scheduled to stop runs.\n        expiry_runs (Integer): The number of runs before the agent expires.\n    \"\"\"\n    agent = db.session.query(AgentSchedule).filter(AgentSchedule.agent_id == agent_id,\n                                                   AgentSchedule.status == \"SCHEDULED\").first()\n\n    if not agent:\n        raise HTTPException(status_code=404, detail=\"Agent Schedule not found\")\n\n    user_timezone = db.session.query(AgentConfiguration).filter(AgentConfiguration.key == \"user_timezone\",\n                                                                AgentConfiguration.agent_id == agent_id).first()\n\n    if user_timezone and user_timezone.value != \"None\":\n        tzone = timezone(user_timezone.value)\n    else:\n        tzone = timezone('GMT')\n\n    current_datetime = datetime.now(tzone).strftime(\"%d/%m/%Y %I:%M %p\")\n\n    return {\n        \"current_datetime\": current_datetime,\n        \"start_date\": agent.start_time.astimezone(tzone).strftime(\"%d %b %Y\"),\n        \"start_time\": agent.start_time.astimezone(tzone).strftime(\"%I:%M %p\"),\n        \"recurrence_interval\": agent.recurrence_interval if agent.recurrence_interval else None,\n        \"expiry_date\": agent.expiry_date.astimezone(tzone).strftime(\"%d/%m/%Y\") if agent.expiry_date else None,\n        \"expiry_runs\": agent.expiry_runs if agent.expiry_runs != -1 else None\n    }\n\n\n@router.get(\"/get/project/{project_id}\")\ndef get_agents_by_project_id(project_id: int,\n                             Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Get all agents by project ID.\n\n    Args:\n        project_id (int): Identifier of the project.\n        Authorize (AuthJWT, optional): Authorization dependency. Defaults to Depends(check_auth).\n\n    Returns:\n        list: List of agents associated with the project, including their status and scheduling information.\n\n    Raises:\n        HTTPException (status_code=404): If the project is not found.\n    \"\"\"\n\n    # Checking for project\n    project = db.session.query(Project).get(project_id)\n    if not project:\n        raise HTTPException(status_code=404, detail=\"Project not found\")\n\n    agents = db.session.query(Agent).filter(Agent.project_id == project_id, or_(or_(Agent.is_deleted == False, Agent.is_deleted is None), Agent.is_deleted is None)).all()\n\n    new_agents, new_agents_sorted = [], []\n    for agent in agents:\n        agent_dict = vars(agent)\n\n        agent_id = agent.id\n\n        # Query the AgentExecution table using the agent ID\n        executions = db.session.query(AgentExecution).filter_by(agent_id=agent_id).all()\n        is_running = False\n        for execution in executions:\n            if execution.status == \"RUNNING\":\n                is_running = True\n                break\n        # Check if the agent is scheduled\n        is_scheduled = db.session.query(AgentSchedule).filter_by(agent_id=agent_id, status=\"SCHEDULED\").first() is not None\n                                                                 \n\n        new_agent = {\n            **agent_dict,\n            'is_running': is_running,\n            'is_scheduled': is_scheduled\n        }\n        new_agents.append(new_agent)\n        new_agents_sorted = sorted(new_agents, key=lambda agent: agent['is_running'] == True, reverse=True)\n    return new_agents_sorted\n\n\n@router.put(\"/delete/{agent_id}\", status_code=200)\ndef delete_agent(agent_id: int, Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n        Delete an existing Agent\n            - Updates the is_deleted flag: Executes a soft delete\n            - AgentExecutions are updated to: \"TERMINATED\" if agentexecution is created, All the agent executions are updated\n            - AgentExecutionPermission is set to: \"REJECTED\" if agentexecutionpersmision is created\n            \n        Args:\n            agent_id (int): Identifier of the Agent to delete\n\n        Returns:\n            A dictionary containing a \"success\" key with the value True to indicate a successful delete.\n\n        Raises:\n            HTTPException (Status Code=404): If the Agent or associated Project is not found or deleted already.\n    \"\"\"\n\n    db_agent = db.session.query(Agent).filter(Agent.id == agent_id).first()\n    db_agent_executions = db.session.query(AgentExecution).filter(AgentExecution.agent_id == agent_id).all()\n    db_agent_schedule = db.session.query(AgentSchedule).filter(AgentSchedule.agent_id == agent_id, AgentSchedule.status == \"SCHEDULED\").first()\n    \n    if not db_agent or db_agent.is_deleted:\n        raise HTTPException(status_code=404, detail=\"agent not found\")\n\n    # Deletion Procedure \n    db_agent.is_deleted = True\n    if db_agent_executions:\n        # Updating all the RUNNING executions to TERMINATED\n        for db_agent_execution in db_agent_executions:\n            db_agent_execution.status = \"TERMINATED\"\n\n    if db_agent_schedule:\n        # Updating the schedule status to STOPPED\n        db_agent_schedule.status = \"STOPPED\"\n    \n    db.session.commit()\n"
  },
  {
    "path": "superagi/controllers/agent_execution.py",
    "content": "from datetime import datetime\nfrom typing import Optional, Union, List\n\nfrom fastapi_sqlalchemy import db\nfrom fastapi import HTTPException, Depends\nfrom fastapi_jwt_auth import AuthJWT\nfrom pydantic import BaseModel\nfrom pydantic.fields import List\nfrom superagi.controllers.types.agent_execution_config import AgentRunIn\n\nfrom superagi.helper.time_helper import get_time_difference\nfrom superagi.models.agent_execution_config import AgentExecutionConfiguration\nfrom superagi.models.workflows.agent_workflow import AgentWorkflow\nfrom superagi.models.agent_schedule import AgentSchedule\nfrom superagi.models.workflows.iteration_workflow import IterationWorkflow\nfrom superagi.worker import execute_agent\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent import Agent\nfrom superagi.models.models import Models\nfrom fastapi import APIRouter\nfrom sqlalchemy import desc\nfrom superagi.helper.auth import check_auth\nfrom superagi.controllers.types.agent_schedule import AgentScheduleInput\nfrom superagi.apm.event_handler import EventHandler\nfrom superagi.controllers.tool import ToolOut\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.models.knowledges import Knowledges\n\nrouter = APIRouter()\n\n\nclass AgentExecutionOut(BaseModel):\n    id: int\n    status: str\n    name: str\n    agent_id: int\n    last_execution_time: datetime\n    num_of_calls: int\n    num_of_tokens: int\n    current_agent_step_id: int\n    permission_id: Optional[int]\n    created_at: datetime\n    updated_at: datetime\n\n    class Config:\n        orm_mode = True\n\nclass AgentExecutionIn(BaseModel):\n    status: Optional[str]\n    name: Optional[str]\n    agent_id: Optional[int]\n    last_execution_time: Optional[datetime]\n    num_of_calls: Optional[int]\n    num_of_tokens: Optional[int]\n    current_agent_step_id: Optional[int]\n    permission_id: Optional[int]\n    goal: Optional[List[str]]\n    instruction: Optional[List[str]]\n\n    class config:\n        orm_mode = True\n\n\n# CRUD Operations\n@router.post(\"/add\", response_model=AgentExecutionOut, status_code=201)\ndef create_agent_execution(agent_execution: AgentExecutionIn,\n                           Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Create a new agent execution/run.\n\n    Args:\n        agent_execution (AgentExecution): The agent execution data.\n\n    Returns:\n        AgentExecution: The created agent execution.\n\n    Raises:\n        HTTPException (Status Code=404): If the agent is not found.\n    \"\"\"\n\n    agent = db.session.query(Agent).filter(Agent.id == agent_execution.agent_id, Agent.is_deleted == False).first()\n    if not agent:\n        raise HTTPException(status_code=404, detail=\"Agent not found\")\n\n    start_step = AgentWorkflow.fetch_trigger_step_id(db.session, agent.agent_workflow_id)\n\n    iteration_step_id = IterationWorkflow.fetch_trigger_step_id(db.session,\n                                                                start_step.action_reference_id).id if start_step.action_type == \"ITERATION_WORKFLOW\" else -1\n\n    db_agent_execution = AgentExecution(status=\"CREATED\", last_execution_time=datetime.now(),\n                                        agent_id=agent_execution.agent_id, name=agent_execution.name, num_of_calls=0,\n                                        num_of_tokens=0,\n                                        current_agent_step_id=start_step.id,\n                                        iteration_workflow_step_id=iteration_step_id)\n\n    agent_execution_configs = {\n        \"goal\": agent_execution.goal,\n        \"instruction\": agent_execution.instruction\n    }\n\n    agent_configs = db.session.query(AgentConfiguration).filter(AgentConfiguration.agent_id == agent_execution.agent_id).all()\n    keys_to_exclude = [\"goal\", \"instruction\"]\n    for agent_config in agent_configs:\n        if agent_config.key not in keys_to_exclude:\n            if agent_config.key == \"toolkits\":\n                if agent_config.value:\n                    toolkits = [int(item) for item in agent_config.value.strip('{}').split(',') if item.strip() and item != '[]']\n                    agent_execution_configs[agent_config.key] = toolkits\n                else:\n                    agent_execution_configs[agent_config.key] = []\n            elif agent_config.key == \"constraints\":\n                if agent_config.value:\n                    agent_execution_configs[agent_config.key] = agent_config.value\n                else:\n                    agent_execution_configs[agent_config.key] = []\n            else:\n                agent_execution_configs[agent_config.key] = agent_config.value\n\n    db.session.add(db_agent_execution)\n    db.session.commit()\n    db.session.flush()\n\n    #update status from CREATED to RUNNING\n    db_agent_execution.status = \"RUNNING\"\n    db.session.commit()\n\n    AgentExecutionConfiguration.add_or_update_agent_execution_config(session=db.session, execution=db_agent_execution,\n                                                                     agent_execution_configs=agent_execution_configs)\n\n    organisation = agent.get_agent_organisation(db.session)\n    agent_execution_knowledge = AgentConfiguration.get_agent_config_by_key_and_agent_id(session= db.session, key= 'knowledge', agent_id= agent_execution.agent_id)\n\n    EventHandler(session=db.session).create_event('run_created',\n                                                  {'agent_execution_id': db_agent_execution.id,\n                                                   'agent_execution_name':db_agent_execution.name},\n                                                   agent_execution.agent_id,\n                                                   organisation.id if organisation else 0)\n    if agent_execution_knowledge and agent_execution_knowledge.value != 'None':\n        knowledge_name = Knowledges.get_knowledge_from_id(db.session, int(agent_execution_knowledge.value)).name\n        if knowledge_name is not None:\n            EventHandler(session=db.session).create_event('knowledge_picked',\n                                                        {'knowledge_name': knowledge_name,\n                                                         'agent_execution_id': db_agent_execution.id},\n                                                        agent_execution.agent_id,\n                                                        organisation.id if organisation else 0)\n    Models.api_key_from_configurations(session=db.session, organisation_id=organisation.id)\n    if db_agent_execution.status == \"RUNNING\":\n      execute_agent.delay(db_agent_execution.id, datetime.now())\n\n    return db_agent_execution\n\n@router.post(\"/add_run\", status_code = 201)\ndef create_agent_run(agent_execution: AgentRunIn, Authorize: AuthJWT = Depends(check_auth)):\n\n    \"\"\"\n    Create a new agent run with all the information(goals, instructions, model, etc).\n\n    Args:\n        agent_execution (AgentExecution): The agent execution data.\n\n    Returns:\n        AgentExecution: The created agent execution.\n\n    Raises:\n        HTTPException (Status Code=404): If the agent is not found.\n    \"\"\"\n\n    agent = db.session.query(Agent).filter(Agent.id == agent_execution.agent_id, Agent.is_deleted == False).first()\n    if not agent:\n        raise HTTPException(status_code = 404, detail = \"Agent not found\")\n    \n    #Update the agent configurations table with the data of the latest agent execution\n    AgentConfiguration.update_agent_configurations_table(session=db.session, agent_id=agent_execution.agent_id, updated_details=agent_execution)\n    \n    start_step = AgentWorkflow.fetch_trigger_step_id(db.session, agent.agent_workflow_id)\n\n    iteration_step_id = IterationWorkflow.fetch_trigger_step_id(db.session,\n                                                                start_step.action_reference_id).id if start_step.action_type == \"ITERATION_WORKFLOW\" else -1\n\n    db_agent_execution = AgentExecution(status=\"CREATED\", last_execution_time=datetime.now(),\n                                        agent_id=agent_execution.agent_id, name=agent_execution.name, num_of_calls=0,\n                                        num_of_tokens=0,\n                                        current_agent_step_id=start_step.id,\n                                        iteration_workflow_step_id=iteration_step_id)\n    agent_execution_configs = {\n        \"goal\": agent_execution.goal,\n        \"instruction\": agent_execution.instruction,\n        \"constraints\": agent_execution.constraints,\n        \"toolkits\": agent_execution.toolkits,\n        \"exit\": agent_execution.exit,\n        \"tools\": agent_execution.tools,\n        \"iteration_interval\": agent_execution.iteration_interval,\n        \"model\": agent_execution.model,\n        \"permission_type\": agent_execution.permission_type,\n        \"LTM_DB\": agent_execution.LTM_DB,\n        \"max_iterations\": agent_execution.max_iterations,\n        \"user_timezone\": agent_execution.user_timezone,\n        \"knowledge\": agent_execution.knowledge\n    }\n    \n    db.session.add(db_agent_execution)\n    db.session.commit()\n    db.session.flush()\n\n    #update status from CREATED to RUNNING\n    db_agent_execution.status = \"RUNNING\"\n    db.session.commit()\n\n    AgentExecutionConfiguration.add_or_update_agent_execution_config(session = db.session, execution = db_agent_execution,\n                                                                     agent_execution_configs = agent_execution_configs)\n\n    organisation = agent.get_agent_organisation(db.session)\n    EventHandler(session=db.session).create_event('run_created',\n                                                  {'agent_execution_id': db_agent_execution.id,\n                                                    'agent_execution_name':db_agent_execution.name},\n                                                    agent_execution.agent_id,\n                                                    organisation.id if organisation else 0)\n    agent_execution_knowledge = AgentConfiguration.get_agent_config_by_key_and_agent_id(session= db.session, key= 'knowledge', agent_id= agent_execution.agent_id)\n    if agent_execution_knowledge and agent_execution_knowledge.value != 'None':\n        knowledge_name = Knowledges.get_knowledge_from_id(db.session, int(agent_execution_knowledge.value)).name\n        if knowledge_name is not None:\n            EventHandler(session=db.session).create_event('knowledge_picked',\n                                                        {'knowledge_name': knowledge_name,\n                                                         'agent_execution_id': db_agent_execution.id},\n                                                        agent_execution.agent_id,\n                                                        organisation.id if organisation else 0)\n\n    if db_agent_execution.status == \"RUNNING\":\n      execute_agent.delay(db_agent_execution.id, datetime.now())\n\n    return db_agent_execution\n\n\n@router.post(\"/schedule\", status_code=201)\ndef schedule_existing_agent(agent_schedule: AgentScheduleInput,\n                            Authorize: AuthJWT = Depends(check_auth)):\n\n    \"\"\"\n    Schedules an already existing agent.\n\n    Args:\n        agent_schedule (AgentScheduleInput): Data for creating a scheduling for an existing agent.\n            agent_id (Integer): The ID of the agent being scheduled.\n            start_time (DateTime): The date and time from which the agent is scheduled.\n            recurrence_interval (String): Stores \"none\" if not recurring, \n            or a time interval like '2 Weeks', '1 Month', '2 Minutes' based on input.\n            expiry_date (DateTime): The date and time when the agent is scheduled to stop runs.\n            expiry_runs (Integer): The number of runs before the agent expires.\n\n    Returns:\n        Schedule ID: Unique Schedule ID of the Agent.\n\n    Raises:\n        HTTPException (Status Code=500): If the agent fails to get scheduled.\n    \"\"\"\n\n    # Check if the agent is already scheduled\n    scheduled_agent = db.session.query(AgentSchedule).filter(AgentSchedule.agent_id == agent_schedule.agent_id,\n                                                             AgentSchedule.status == \"SCHEDULED\").first()\n\n    if scheduled_agent:\n        # Update the old record with new data\n        scheduled_agent.start_time = agent_schedule.start_time\n        scheduled_agent.next_scheduled_time = agent_schedule.start_time\n        scheduled_agent.recurrence_interval = agent_schedule.recurrence_interval\n        scheduled_agent.expiry_date = agent_schedule.expiry_date\n        scheduled_agent.expiry_runs = agent_schedule.expiry_runs\n\n        db.session.commit()\n    else:                      \n        # Schedule the agent\n        scheduled_agent = AgentSchedule(\n            agent_id=agent_schedule.agent_id,\n            start_time=agent_schedule.start_time,\n            next_scheduled_time=agent_schedule.start_time,\n            recurrence_interval=agent_schedule.recurrence_interval,\n            expiry_date=agent_schedule.expiry_date,\n            expiry_runs=agent_schedule.expiry_runs,\n            current_runs=0,\n            status=\"SCHEDULED\"\n        )\n\n    db.session.add(scheduled_agent)\n    db.session.commit()\n\n    schedule_id = scheduled_agent.id\n\n    if schedule_id is None:\n        raise HTTPException(status_code=500, detail=\"Failed to schedule agent\")\n        \n    return {\n        \"schedule_id\": schedule_id\n    }\n\n\n@router.get(\"/get/{agent_execution_id}\", response_model=AgentExecutionOut)\ndef get_agent_execution(agent_execution_id: int,\n                        Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Get an agent execution by agent_execution_id.\n\n    Args:\n        agent_execution_id (int): The ID of the agent execution.\n\n    Returns:\n        AgentExecution: The requested agent execution.\n\n    Raises:\n        HTTPException (Status Code=404): If the agent execution is not found.\n    \"\"\"\n\n    if (\n        db_agent_execution := db.session.query(AgentExecution)\n        .filter(AgentExecution.id == agent_execution_id)\n        .first()\n    ):\n        return db_agent_execution\n    else:\n        raise HTTPException(status_code=404, detail=\"Agent execution not found\")\n\n\n@router.put(\"/update/{agent_execution_id}\", response_model=AgentExecutionOut)\ndef update_agent_execution(agent_execution_id: int,\n                           agent_execution: AgentExecutionIn,\n                           Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"Update details of particular agent_execution by agent_execution_id\"\"\"\n\n    db_agent_execution = db.session.query(AgentExecution).filter(AgentExecution.id == agent_execution_id).first()\n    if agent_execution.status == \"COMPLETED\":\n        raise HTTPException(status_code=400, detail=\"Invalid Request\")\n\n    if not db_agent_execution:\n        raise HTTPException(status_code=404, detail=\"Agent Execution not found\")\n\n    if agent_execution.agent_id:\n        if agent := db.session.query(Agent).get(agent_execution.agent_id):\n            db_agent_execution.agent_id = agent.id\n        else:\n            raise HTTPException(status_code=404, detail=\"Agent not found\")\n    if agent_execution.status not in [\n        \"CREATED\",\n        \"RUNNING\",\n        \"PAUSED\",\n        \"COMPLETED\",\n        \"TERMINATED\",\n    ]:\n        raise HTTPException(status_code=400, detail=\"Invalid Request\")\n    db_agent_execution.status = agent_execution.status\n\n    db_agent_execution.last_execution_time = datetime.now()\n    db.session.commit()\n\n    if db_agent_execution.status == \"RUNNING\":\n        execute_agent.delay(db_agent_execution.id, datetime.now())\n\n    return db_agent_execution\n\n\n@router.get(\"/get/agents/status/{status}\")\ndef agent_list_by_status(status: str,\n                         Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"Get list of all agent_ids for a given status\"\"\"\n\n    running_agent_ids = db.session.query(AgentExecution.agent_id).filter(\n        AgentExecution.status == status.upper()).distinct().all()\n    agent_ids = [agent_id for (agent_id) in running_agent_ids]\n    return agent_ids\n\n\n@router.get(\"/get/agent/{agent_id}\")\ndef list_running_agents(agent_id: str,\n                        Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"Get all running state agents\"\"\"\n\n    executions = db.session.query(AgentExecution).filter(AgentExecution.agent_id == agent_id).order_by(\n        desc(AgentExecution.status == 'RUNNING'), desc(AgentExecution.last_execution_time)).all()\n    for execution in executions:\n        execution.time_difference = get_time_difference(execution.last_execution_time,str(datetime.now()))\n    return executions\n\n\n@router.get(\"/get/latest/agent/project/{project_id}\")\ndef get_agent_by_latest_execution(project_id: int,\n                                  Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"Get latest executing agent details\"\"\"\n\n    latest_execution = (\n        db.session.query(AgentExecution)\n        .join(Agent, AgentExecution.agent_id == Agent.id)\n        .filter(Agent.project_id == project_id, Agent.is_deleted == False)\n        .order_by(desc(AgentExecution.last_execution_time))\n        .first()\n    )\n    isRunning = False\n    if latest_execution.status == \"RUNNING\":\n        isRunning = True\n    agent = db.session.query(Agent).filter(Agent.id == latest_execution.agent_id).first()\n    return {\n        \"agent_id\": latest_execution.agent_id,\n        \"project_id\": project_id,\n        \"created_at\": agent.created_at,\n        \"description\": agent.description,\n        \"updated_at\": agent.updated_at,\n        \"name\": agent.name,\n        \"id\": agent.id,\n        \"status\": isRunning,\n        \"contentType\": \"Agents\"\n    }"
  },
  {
    "path": "superagi/controllers/agent_execution_config.py",
    "content": "import ast\nimport json\n\nfrom fastapi import APIRouter\nfrom fastapi import HTTPException, Depends\nfrom fastapi_jwt_auth import AuthJWT\nfrom fastapi_sqlalchemy import db\nfrom typing import Optional, Union\nfrom sqlalchemy import func, or_\nfrom sqlalchemy import desc\n\nfrom superagi.helper.auth import check_auth\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_config import AgentExecutionConfiguration\nfrom superagi.models.tool import Tool\nfrom superagi.models.knowledges import Knowledges\n\n\nrouter = APIRouter()\n\n@router.get(\"/details/agent_id/{agent_id}/agent_execution_id/{agent_execution_id}\")\ndef get_agent_execution_configuration(agent_id : Union[int, None, str],\n                                      agent_execution_id: Union[int, None, str],\n                                      Authorize: AuthJWT = Depends(check_auth)):\n   \n    \"\"\"\n    Get the agent configuration using the agent ID and the agent execution ID.\n\n    Args:\n        agent_id (int): Identifier of the agent.\n        agent_execution_id (int): Identifier of the agent execution.\n        Authorize (AuthJWT, optional): Authorization dependency. Defaults to Depends(check_auth).\n\n    Returns:\n        dict: Agent configuration including its details.\n\n    Raises:\n        HTTPException (status_code=404): If the agent is not found or deleted.\n        HTTPException (status_code=404): If the agent_id or the agent_execution_id is undefined.\n    \"\"\"\n\n    # Check\n    if isinstance(agent_id, str):\n        raise HTTPException(status_code = 404, detail = \"Agent Id undefined\")\n    if isinstance(agent_execution_id, str):\n        raise HTTPException(status_code = 404, detail = \"Agent Execution Id undefined\")\n\n    # Define the agent_config keys to fetch\n    agent = db.session.query(Agent).filter(agent_id == Agent.id,or_(Agent.is_deleted == False)).first()\n    if not agent:\n        raise HTTPException(status_code = 404, detail = \"Agent not found\")\n    \n    #If the agent_execution_id received is -1 then the agent_execution_id is set as the most recent execution\n    if agent_execution_id == -1:\n        agent_execution = db.session.query(AgentExecution).filter(AgentExecution.agent_id == agent_id).order_by(desc(AgentExecution.created_at)).first()\n        if agent_execution: agent_execution_id = agent_execution.id\n\n    #Fetch agent id from agent execution id and check whether the agent_id received is correct or not.\n    if agent_execution_id!=-1: \n        agent_execution_config = AgentExecution.get_agent_execution_from_id(db.session, agent_execution_id)\n        if agent_execution_config is None:\n            raise HTTPException(status_code = 404, detail = \"Agent Execution not found\")\n        agent_id_from_execution_id = agent_execution_config.agent_id\n        if agent_id != agent_id_from_execution_id:\n            raise HTTPException(status_code = 404, detail = \"Wrong agent id\")\n\n    # Query the AgentConfiguration table and the AgentExecuitonConfiguration table for all the keys\n    results_agent = db.session.query(AgentConfiguration).filter(AgentConfiguration.agent_id == agent_id).all()\n    if agent_execution_id!=-1: results_agent_execution = db.session.query(AgentExecutionConfiguration).filter(AgentExecutionConfiguration.agent_execution_id == agent_execution_id).all()\n    \n    total_calls = db.session.query(func.sum(AgentExecution.num_of_calls)).filter(\n        AgentExecution.agent_id == agent_id).scalar()\n    total_tokens = db.session.query(func.sum(AgentExecution.num_of_tokens)).filter(\n        AgentExecution.agent_id == agent_id).scalar()\n    \n    response = {}\n    if agent_execution_id!=-1: \n        response = AgentExecutionConfiguration.build_agent_execution_config(db.session, agent, results_agent, results_agent_execution, total_calls, total_tokens)\n    else: \n        response = AgentExecutionConfiguration.build_scheduled_agent_execution_config(db.session, agent, results_agent, total_calls, total_tokens)\n        \n    # Close the session\n    db.session.close()\n\n    return response"
  },
  {
    "path": "superagi/controllers/agent_execution_feed.py",
    "content": "import asyncio\nfrom datetime import datetime\nimport time\nfrom typing import Optional\n\nfrom fastapi import APIRouter, BackgroundTasks\nfrom fastapi import HTTPException, Depends\nfrom fastapi_jwt_auth import AuthJWT\nfrom fastapi_sqlalchemy import db\nfrom pydantic import BaseModel\n\nfrom sqlalchemy.sql import asc\n\nfrom superagi.agent.task_queue import TaskQueue\nfrom superagi.helper.auth import check_auth\nfrom superagi.helper.time_helper import get_time_difference\nfrom superagi.models.agent_execution_permission import AgentExecutionPermission\nfrom superagi.helper.feed_parser import parse_feed\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nfrom superagi.lib.logger import logger\nfrom superagi.agent.types.agent_workflow_step_action_types import AgentWorkflowStepAction\nfrom superagi.models.workflows.agent_workflow_step import AgentWorkflowStep\nfrom superagi.models.workflows.agent_workflow_step_wait import AgentWorkflowStepWait\n\nimport re\n# from superagi.types.db import AgentExecutionFeedOut, AgentExecutionFeedIn\n\nrouter = APIRouter()\n\n\nclass AgentExecutionFeedOut(BaseModel):\n    id: int\n    agent_execution_id: int\n    agent_id: int\n    feed: str\n    role: str\n    extra_info: Optional[str]\n    created_at: datetime\n    updated_at: datetime\n\n    class Config:\n        orm_mode = True\n\n\nclass AgentExecutionFeedIn(BaseModel):\n    id: int\n    agent_execution_id: int\n    agent_id: int\n    feed: str\n    role: str\n    extra_info: str\n\n    class Config:\n        orm_mode = True\n\n# CRUD Operations\n@router.post(\"/add\", response_model=AgentExecutionFeedOut, status_code=201)\ndef create_agent_execution_feed(agent_execution_feed: AgentExecutionFeedIn,\n                                Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Add a new agent execution feed.\n\n    Args:\n        agent_execution_feed (AgentExecutionFeed): The data for the agent execution feed.\n\n    Returns:\n        AgentExecutionFeed: The newly created agent execution feed.\n\n    Raises:\n        HTTPException (Status Code=404): If the associated agent execution is not found.\n    \"\"\"\n\n    agent_execution = db.session.query(AgentExecution).get(agent_execution_feed.agent_execution_id)\n\n    if not agent_execution:\n        raise HTTPException(status_code=404, detail=\"Agent Execution not found\")\n\n    db_agent_execution_feed = AgentExecutionFeed(agent_execution_id=agent_execution_feed.agent_execution_id,\n                                                 feed=agent_execution_feed.feed, type=agent_execution_feed.type,\n                                                 extra_info=agent_execution_feed.extra_info,\n                                                 feed_group_id=agent_execution.current_feed_group_id)\n    db.session.add(db_agent_execution_feed)\n    db.session.commit()\n    return db_agent_execution_feed\n\n\n@router.get(\"/get/{agent_execution_feed_id}\", response_model=AgentExecutionFeedOut)\ndef get_agent_execution_feed(agent_execution_feed_id: int,\n                             Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Get an agent execution feed by agent_execution_feed_id.\n\n    Args:\n        agent_execution_feed_id (int): The ID of the agent execution feed.\n\n    Returns:\n        AgentExecutionFeed: The agent execution feed with the specified ID.\n\n    Raises:\n        HTTPException (Status Code=404): If the agent execution feed is not found.\n    \"\"\"\n\n    db_agent_execution_feed = db.session.query(AgentExecutionFeed).filter(\n        AgentExecutionFeed.id == agent_execution_feed_id).first()\n    if not db_agent_execution_feed:\n        raise HTTPException(status_code=404, detail=\"agent_execution_feed not found\")\n    return db_agent_execution_feed\n\n\n@router.put(\"/update/{agent_execution_feed_id}\", response_model=AgentExecutionFeedOut)\ndef update_agent_execution_feed(agent_execution_feed_id: int,\n                                agent_execution_feed: AgentExecutionFeedIn,\n                                Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Update a particular agent execution feed.\n\n    Args:\n        agent_execution_feed_id (int): The ID of the agent execution feed to update.\n        agent_execution_feed (AgentExecutionFeed): The updated agent execution feed.\n\n    Returns:\n        AgentExecutionFeed: The updated agent execution feed.\n\n    Raises:\n        HTTPException (Status Code=404): If the agent execution feed or agent execution is not found.\n    \"\"\"\n\n    db_agent_execution_feed = db.session.query(AgentExecutionFeed).filter(\n        AgentExecutionFeed.id == agent_execution_feed_id).first()\n    if not db_agent_execution_feed:\n        raise HTTPException(status_code=404, detail=\"Agent Execution Feed not found\")\n\n    if agent_execution_feed.agent_execution_id:\n        agent_execution = db.session.query(AgentExecution).get(agent_execution_feed.agent_execution_id)\n        if not agent_execution:\n            raise HTTPException(status_code=404, detail=\"Agent Execution not found\")\n        db_agent_execution_feed.agent_execution_id = agent_execution.id\n\n    if agent_execution_feed.type is not None:\n        db_agent_execution_feed.type = agent_execution_feed.type\n    if agent_execution_feed.feed is not None:\n        db_agent_execution_feed.feed = agent_execution_feed.feed\n    # if agent_execution_feed.extra_info is not None:\n    #     db_agent_execution_feed.extra_info = agent_execution_feed.extra_info\n\n    db.session.commit()\n    return db_agent_execution_feed\n\n\n@router.get(\"/get/execution/{agent_execution_id}\")\ndef get_agent_execution_feed(agent_execution_id: int,\n                                         Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Get agent execution feed with other execution details.\n\n    Args:\n        agent_execution_id (int): The ID of the agent execution.\n\n    Returns:\n        dict: The agent execution status and feeds.\n\n    Raises:\n        HTTPException (Status Code=400): If the agent run is not found.\n    \"\"\"\n\n    agent_execution = db.session.query(AgentExecution).filter(AgentExecution.id == agent_execution_id).first()\n    if agent_execution is None:\n        raise HTTPException(status_code=400, detail=\"Agent Run not found!\")\n    feeds = db.session.query(AgentExecutionFeed).filter_by(agent_execution_id=agent_execution_id).order_by(\n        asc(AgentExecutionFeed.created_at)).all()\n    # # parse json\n    final_feeds = []\n    error = \"\"\n    for feed in feeds:\n        if feed.error_message:\n            if (agent_execution.last_shown_error_id is None) or (feed.id > agent_execution.last_shown_error_id):\n                #new error occured\n                error = feed.error_message\n                agent_execution.last_shown_error_id = feed.id\n                agent_execution.status = \"ERROR_PAUSED\"\n                db.session.commit()\n            if feed.id == agent_execution.last_shown_error_id and agent_execution.status == \"ERROR_PAUSED\":\n                error = feed.error_message\n        if feed.feed != \"\" and re.search(r\"The current time and date is\\s(\\w{3}\\s\\w{3}\\s\\s?\\d{1,2}\\s\\d{2}:\\d{2}:\\d{2}\\s\\d{4})\",feed.feed) == None :\n            final_feeds.append(parse_feed(feed))\n\n    # get all permissions\n    execution_permissions = db.session.query(AgentExecutionPermission).\\\n        filter_by(agent_execution_id=agent_execution_id). \\\n        order_by(asc(AgentExecutionPermission.created_at)).all()\n\n    permissions = [\n        {\n                \"id\": permission.id,\n                \"created_at\": permission.created_at,\n                \"response\": permission.user_feedback,\n                \"status\": permission.status,\n                \"tool_name\": permission.tool_name,\n                \"question\": permission.question,\n                \"user_feedback\": permission.user_feedback,\n                \"time_difference\": get_time_difference(permission.created_at, str(datetime.now()))\n        } for permission in execution_permissions\n    ]\n\n    waiting_period = None\n\n    if agent_execution.status == AgentWorkflowStepAction.WAIT_STEP.value:\n        workflow_step = AgentWorkflowStep.find_by_id(db.session, agent_execution.current_agent_step_id)\n        waiting_period = (AgentWorkflowStepWait.find_by_id(db.session, workflow_step.action_reference_id)).delay\n\n    return {\n        \"status\": agent_execution.status,\n        \"feeds\": final_feeds,\n        \"permissions\": permissions,\n        \"waiting_period\": waiting_period,\n        \"errors\": error\n    }\n\n\n@router.get(\"/get/tasks/{agent_execution_id}\")\ndef get_execution_tasks(agent_execution_id: int,\n                        Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Get agent execution tasks and completed tasks.\n\n    Args:\n        agent_execution_id (int): The ID of the agent execution.\n\n    Returns:\n        dict: The tasks and completed tasks for the agent execution.\n    \"\"\"\n    task_queue = TaskQueue(str(agent_execution_id))\n    tasks = []\n    for task in task_queue.get_tasks():\n        tasks.append({\"name\": task})\n    completed_tasks = []\n    for task in reversed(task_queue.get_completed_tasks()):\n        completed_tasks.append({\"name\": task['task']})\n\n    return {\n        \"tasks\": tasks,\n        \"completed_tasks\": completed_tasks\n    }"
  },
  {
    "path": "superagi/controllers/agent_execution_permission.py",
    "content": "from datetime import datetime\nfrom typing import Annotated\n\nfrom fastapi_sqlalchemy import db\nfrom fastapi import HTTPException, Depends, Body\nfrom fastapi_jwt_auth import AuthJWT\nfrom pydantic import BaseModel\n\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_permission import AgentExecutionPermission\nfrom superagi.worker import execute_agent\nfrom fastapi import APIRouter\n\nfrom superagi.helper.auth import check_auth\n# from superagi.types.db import AgentExecutionPermissionOut, AgentExecutionPermissionIn\n\nrouter = APIRouter()\n\n\nclass AgentExecutionPermissionOut(BaseModel):\n    id: int\n    agent_execution_id: int\n    agent_id: int\n    status: str\n    tool_name: str\n    user_feedback: str\n    assistant_reply: str\n    created_at: datetime\n    updated_at: datetime\n\n    class Config:\n        orm_mode = True\n\n\nclass AgentExecutionPermissionIn(BaseModel):\n    agent_execution_id: int\n    agent_id: int\n    status: str\n    tool_name: str\n    user_feedback: str\n    assistant_reply: str\n\n    class Config:\n        orm_mode = True\n\n\n@router.get(\"/get/{agent_execution_permission_id}\")\ndef get_agent_execution_permission(agent_execution_permission_id: int,\n                                   Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Get an agent execution permission by its ID.\n\n    Args:\n        agent_execution_permission_id (int): The ID of the agent execution permission.\n        Authorize (AuthJWT, optional): Authentication object. Defaults to Depends(check_auth).\n\n    Raises:\n        HTTPException: If the agent execution permission is not found.\n\n    Returns:\n        AgentExecutionPermission: The requested agent execution permission.\n    \"\"\"\n\n    db_agent_execution_permission = db.session.query(AgentExecutionPermission).get(agent_execution_permission_id)\n    if not db_agent_execution_permission:\n        raise HTTPException(status_code=404, detail=\"Agent execution permission not found\")\n    return db_agent_execution_permission\n\n\n@router.post(\"/add\", response_model=AgentExecutionPermissionOut)\ndef create_agent_execution_permission(\n        agent_execution_permission: AgentExecutionPermissionIn\n        , Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Create a new agent execution permission.\n\n    Args:\n        agent_execution_permission : An instance of AgentExecutionPermission model as json.\n        Authorize (AuthJWT, optional): Authorization token, by default depends on the check_auth function.\n\n    Returns:\n        new_agent_execution_permission: A newly created agent execution permission instance.\n    \"\"\"\n    new_agent_execution_permission = AgentExecutionPermission(**agent_execution_permission.dict())\n    db.session.add(new_agent_execution_permission)\n    db.session.commit()\n    return new_agent_execution_permission\n\n\n@router.patch(\"/update/{agent_execution_permission_id}\",\n              response_model=AgentExecutionPermissionIn)\ndef update_agent_execution_permission(agent_execution_permission_id: int,\n                                      agent_execution_permission: AgentExecutionPermissionIn,\n                                      Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Update an AgentExecutionPermission in the database.\n\n    Given an agent_execution_permission_id and the updated agent_execution_permission, this function updates the\n    corresponding AgentExecutionPermission in the database. If the AgentExecutionPermission is not found, an HTTPException\n    is raised.\n\n    Args:\n        agent_execution_permission_id (int): The ID of the AgentExecutionPermission to update.\n        agent_execution_permission : The updated AgentExecutionPermission object as json.\n        Authorize (AuthJWT, optional): Dependency to authenticate the user.\n\n    Returns:\n        db_agent_execution_permission (AgentExecutionPermission): The updated AgentExecutionPermission in the database.\n\n    Raises:\n        HTTPException: If the AgentExecutionPermission is not found in the database.\n    \"\"\"\n    db_agent_execution_permission = db.session.query(AgentExecutionPermission).get(agent_execution_permission_id)\n    if not db_agent_execution_permission:\n        raise HTTPException(status_code=404, detail=\"Agent execution permission not found\")\n\n    for key, value in agent_execution_permission.dict().items():\n        setattr(db_agent_execution_permission, key, value)\n\n    db.session.commit()\n    return db_agent_execution_permission\n\n\n@router.put(\"/update/status/{agent_execution_permission_id}\")\ndef update_agent_execution_permission_status(agent_execution_permission_id: int,\n                                             status: Annotated[bool, Body(embed=True)],\n                                             user_feedback: Annotated[str, Body(embed=True)] = \"\",\n                                             Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Update the execution permission status of an agent in the database.\n\n    This function updates the execution permission status of an agent in the database. The status can be\n    either \"APPROVED\" or \"REJECTED\". The function also updates the user feedback if provided,\n    commits the changes to the database, and enqueues the agent for execution.\n\n    :params:\n    - agent_execution_permission_id (int): The ID of the agent execution permission\n    - status (bool): The status of the agent execution permission, True for \"APPROVED\", False for \"REJECTED\"\n    - user_feedback (str): Optional user feedback on the status update\n    - Authorize (AuthJWT): Dependency function to check user authorization\n\n    :return:\n    - A dictionary containing a \"success\" key with the value True to indicate a successful update.\n    \"\"\"\n\n    agent_execution_permission = db.session.query(AgentExecutionPermission).get(agent_execution_permission_id)\n    print(agent_execution_permission)\n    if agent_execution_permission is None:\n        raise HTTPException(status_code=400, detail=\"Invalid Request\")\n    if status is None:\n        raise HTTPException(status_code=400, detail=\"Invalid Request status is required\")\n    agent_execution_permission.status = \"APPROVED\" if status else \"REJECTED\"\n    agent_execution_permission.user_feedback = user_feedback.strip() if len(user_feedback.strip()) > 0 else None\n    db.session.commit()\n\n    execute_agent.delay(agent_execution_permission.agent_execution_id, datetime.now())\n\n    return {\"success\": True}\n"
  },
  {
    "path": "superagi/controllers/agent_template.py",
    "content": "from datetime import datetime\n\nfrom fastapi import APIRouter\nfrom fastapi import HTTPException, Depends\nfrom fastapi_sqlalchemy import db\nfrom pydantic import BaseModel\n\nfrom main import get_config\nfrom superagi.controllers.types.agent_execution_config import AgentRunIn\nfrom superagi.controllers.types.agent_publish_config import AgentPublish\nfrom superagi.helper.auth import get_user_organisation\nfrom superagi.helper.auth import get_current_user\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_config import AgentExecutionConfiguration\nfrom superagi.models.agent_template import AgentTemplate\nfrom superagi.models.agent_template_config import AgentTemplateConfig\nfrom superagi.models.workflows.agent_workflow import AgentWorkflow\nfrom superagi.models.tool import Tool\nimport json\n# from superagi.types.db import AgentTemplateIn, AgentTemplateOut\n\nrouter = APIRouter()\n\n\nclass AgentTemplateOut(BaseModel):\n    id: int\n    organisation_id: int\n    agent_workflow_id: int\n    name: str\n    description: str\n    marketplace_template_id: int\n    created_at: datetime\n    updated_at: datetime\n\n    class Config:\n        orm_mode = True\n\n\nclass AgentTemplateIn(BaseModel):\n    organisation_id: int\n    agent_workflow_id: int\n    name: str\n    description: str\n    marketplace_template_id: int\n\n    class Config:\n        orm_mode = True\n\n\n@router.get(\"/get/{agent_template_id}\")\ndef get_agent_template(template_source, agent_template_id: int, organisation=Depends(get_user_organisation)):\n    \"\"\"\n        Get the details of a specific agent template.\n\n        Args:\n            template_source (str): The source of the agent template (\"local\" or \"marketplace\").\n            agent_template_id (int): The ID of the agent template.\n            organisation (Depends): Dependency to get the user organisation.\n\n        Returns:\n            dict: The details of the agent template.\n\n        Raises:\n            HTTPException (status_code=404): If the agent template is not found.\n    \"\"\"\n    if template_source == \"local\":\n        db_agent_template = db.session.query(AgentTemplate).filter(AgentTemplate.organisation_id == organisation.id,\n                                                                   AgentTemplate.id == agent_template_id).first()\n        if not db_agent_template:\n            raise HTTPException(status_code=404, detail=\"Agent execution not found\")\n        template = db_agent_template.to_dict()\n        configs = {}\n        agent_template_configs = db.session.query(AgentTemplateConfig).filter(\n            AgentTemplateConfig.agent_template_id == agent_template_id).all()\n        agent_workflow = AgentWorkflow.find_by_id(db_agent_template.agent_workflow_id)\n        for agent_template_config in agent_template_configs:\n            config_value = AgentTemplate.eval_agent_config(agent_template_config.key, agent_template_config.value)\n            configs[agent_template_config.key] = {\"value\": config_value}\n        template[\"configs\"] = configs\n        template[\"agent_workflow_name\"] = agent_workflow.name\n    else:\n        template = AgentTemplate.fetch_marketplace_detail(agent_template_id)\n\n    return template\n\n\n@router.put(\"/update_agent_template/{agent_template_id}\", status_code=200)\ndef edit_agent_template(agent_template_id: int,\n                        updated_agent_configs: dict,\n                        organisation=Depends(get_user_organisation)):\n\n    \"\"\"\n    Update the details of an agent template.\n\n    Args:\n        agent_template_id (int): The ID of the agent template to update.\n        updated_agent_configs (dict): The updated agent configurations.\n        organisation (Depends): Dependency to get the user organisation.\n\n    Returns:\n        HTTPException (status_code=200): If the agent gets successfully edited.\n\n    Raises:\n        HTTPException (status_code=404): If the agent template is not found.\n    \"\"\"\n\n    db_agent_template = db.session.query(AgentTemplate).filter(AgentTemplate.organisation_id == organisation.id,\n                                                               AgentTemplate.id == agent_template_id).first()\n    if db_agent_template is None:\n        raise HTTPException(status_code=404, detail=\"Agent Template not found\")\n\n    agent_workflow = AgentWorkflow.find_by_name(db.session, updated_agent_configs[\"agent_configs\"][\"agent_workflow\"])\n    db_agent_template.name = updated_agent_configs[\"name\"]\n    db_agent_template.description = updated_agent_configs[\"description\"]\n    db_agent_template.agent_workflow_id = agent_workflow.id\n\n    db.session.commit()\n\n    agent_config_values = updated_agent_configs.get('agent_configs', {})\n\n    for key, value in agent_config_values.items():\n        if isinstance(value, (list, dict)):\n            value = json.dumps(value)\n        config = db.session.query(AgentTemplateConfig).filter(\n            AgentTemplateConfig.agent_template_id == agent_template_id,\n            AgentTemplateConfig.key == key\n        ).first()\n\n        if config is not None:\n            config.value = value\n        else:\n            new_config = AgentTemplateConfig(\n                agent_template_id=agent_template_id,\n                key=key,\n                value= value\n            )\n            db.session.add(new_config)\n\n    db.session.commit()\n    db.session.flush()\n\n# @router.put(\"/update_agent_template/{agent_template_id}\", status_code=200)\n# def edit_agent_template(agent_template_id: int,\n#                         updated_agent_configs: dict,\n#                         organisation=Depends(get_user_organisation)):\n    \n#     \"\"\"\n#     Update the details of an agent template.\n\n#     Args:\n#         agent_template_id (int): The ID of the agent template to update.\n#         edited_agent_configs (dict): The updated agent configurations.\n#         organisation (Depends): Dependency to get the user organisation.\n\n#     Returns:\n#         HTTPException (status_code=200): If the agent gets successfully edited.\n\n#     Raises:\n#         HTTPException (status_code=404): If the agent template is not found.\n#     \"\"\"\n    \n#     db_agent_template = db.session.query(AgentTemplate).filter(AgentTemplate.organisation_id == organisation.id,\n#                                                                AgentTemplate.id == agent_template_id).first()\n#     if db_agent_template is None:\n#         raise HTTPException(status_code=404, detail=\"Agent Template not found\")\n    \n#     db_agent_template.name = updated_agent_configs[\"name\"]\n#     db_agent_template.description = updated_agent_configs[\"description\"]\n\n#     db.session.commit()\n\n#     agent_config_values = updated_agent_configs.get('agent_configs', {})\n\n#     for key, value in agent_config_values.items():\n#         if isinstance(value, (list, dict)):\n#             value = json.dumps(value)\n#         config = db.session.query(AgentTemplateConfig).filter(\n#             AgentTemplateConfig.agent_template_id == agent_template_id,\n#             AgentTemplateConfig.key == key\n#         ).first()\n\n#         if config is not None:\n#             config.value = value\n#         else:\n#             new_config = AgentTemplateConfig(\n#                 agent_template_id=agent_template_id,\n#                 key=key,\n#                 value= value\n#             )\n#             db.session.add(new_config)\n\n#     db.session.commit()\n#     db.session.flush()\n\n\n@router.post(\"/save_agent_as_template/agent_id/{agent_id}/agent_execution_id/{agent_execution_id}\")\ndef save_agent_as_template(agent_execution_id: str,\n                           agent_id: str,\n                           organisation=Depends(get_user_organisation)):\n    \"\"\"\n    Save an agent as a template.\n\n    Args:\n        agent_id (str): The ID of the agent to save as a template.\n        agent_execution_id (str): The ID of the agent execution to save as a template.\n        organisation (Depends): Dependency to get the user organisation.\n\n    Returns:\n        dict: The saved agent template.\n\n    Raises:\n        HTTPException (status_code=404): If the agent or agent execution configurations are not found.\n    \"\"\"\n\n    if agent_execution_id == 'undefined':\n        raise HTTPException(status_code = 404, detail = \"Agent Execution Id undefined\")\n    if agent_id == 'undefined':\n        raise HTTPException(status_code = 404, detail = \"Agent Id undefined\")\n\n    agent = db.session.query(Agent).filter(Agent.id == agent_id).first()\n    if agent is None:\n        raise HTTPException(status_code=404, detail=\"Agent not found\")\n\n    configs = None\n\n    if agent_execution_id == \"-1\":\n        configs = db.session.query(AgentConfiguration).filter(AgentConfiguration.agent_id == agent_id).all()\n        if not configs:\n            raise HTTPException(status_code=404, detail=\"Agent configurations not found\")    \n    else:\n        configs = db.session.query(AgentExecutionConfiguration).filter(AgentExecutionConfiguration.agent_execution_id == agent_execution_id).all()\n        if not configs:\n            raise HTTPException(status_code=404, detail=\"Agent execution configurations not found\")\n\n    if configs is None:\n        raise HTTPException(status_code=404, detail=\"Configurations not found\")\n    \n    agent_template = AgentTemplate(name=agent.name, description=agent.description,\n                                   agent_workflow_id=agent.agent_workflow_id,\n                                   organisation_id=organisation.id)\n    db.session.add(agent_template)\n    db.session.commit()\n\n    for config in configs:\n            config_value = config.value\n            if config.key not in AgentTemplate.main_keys():\n                continue\n            if config.key == \"tools\":\n                config_value = str(Tool.convert_tool_ids_to_names(db, eval(config.value)))\n            agent_template_config = AgentTemplateConfig(agent_template_id=agent_template.id, key=config.key,\n                                                        value=config_value)\n            db.session.add(agent_template_config)       \n        \n    db.session.commit()\n    db.session.flush()\n    return agent_template.to_dict()\n\n@router.get(\"/list\")\ndef list_agent_templates(template_source=\"local\", search_str=\"\", page=0, organisation=Depends(get_user_organisation)):\n    \"\"\"\n        List agent templates.\n\n        Args:\n            template_source (str, optional): The source of the templates (\"local\" or \"marketplace\"). Defaults to \"local\".\n            search_str (str, optional): The search string to filter templates. Defaults to \"\".\n            page (int, optional): The page number for paginated results. Defaults to 0.\n            organisation (Depends): Dependency to get the user organisation.\n\n        Returns:\n            list: A list of agent templates.\n    \"\"\"\n    output_json = []\n    if template_source == \"local\":\n        templates = db.session.query(AgentTemplate).filter(AgentTemplate.organisation_id == organisation.id).all()\n        for template in templates:\n            template.updated_at = template.updated_at.strftime('%d-%b-%Y').upper()\n            output_json.append(template)\n    else:\n        local_templates = db.session.query(AgentTemplate).filter(AgentTemplate.organisation_id == organisation.id,\n                                                                 AgentTemplate.marketplace_template_id != None).all()\n        local_templates_hash = {}\n        for local_template in local_templates:\n            local_templates_hash[local_template.marketplace_template_id] = True\n        print(local_templates_hash)\n        templates = AgentTemplate.fetch_marketplace_list(search_str, page)\n        print(templates)\n        for template in templates:\n            template[\"is_installed\"] = local_templates_hash.get(template[\"id\"], False)\n            template[\"organisation_id\"] = organisation.id\n            output_json.append(template)\n\n    return output_json\n\n\n@router.get(\"/marketplace/list\")\ndef list_marketplace_templates(page=0):\n    \"\"\"\n    Get all marketplace agent templates.\n\n    Args:\n        page (int, optional): The page number for paginated results. Defaults to 0.\n\n    Returns:\n        list: A list of marketplace agent templates.\n\n    \"\"\"\n\n    organisation_id = int(get_config(\"MARKETPLACE_ORGANISATION_ID\"))\n    page_size = 30\n    templates = db.session.query(AgentTemplate).filter(AgentTemplate.organisation_id == organisation_id).offset(\n        page * page_size).limit(page_size).all()\n    output_json = []\n    for template in templates:\n        template.updated_at = template.updated_at.strftime('%d-%b-%Y').upper()\n        output_json.append(template)\n    return output_json\n\n\n@router.get(\"/marketplace/template_details/{agent_template_id}\")\ndef marketplace_template_detail(agent_template_id):\n    \"\"\"\n    Get marketplace template details.\n\n    Args:\n        agent_template_id (int): The ID of the marketplace agent template.\n\n    Returns:\n        dict: A dictionary containing the marketplace template details.\n\n    \"\"\"\n\n    organisation_id = int(get_config(\"MARKETPLACE_ORGANISATION_ID\"))\n    template = db.session.query(AgentTemplate).filter(AgentTemplate.organisation_id == organisation_id,\n                                                      AgentTemplate.id == agent_template_id).first()\n    template_configs = db.session.query(AgentTemplateConfig).filter(\n        AgentTemplateConfig.agent_template_id == template.id).all()\n\n    workflow = db.session.query(AgentWorkflow).filter(AgentWorkflow.id == template.agent_workflow_id).first()\n    tool_configs = {}\n    for template_config in template_configs:\n        config_value = AgentTemplate.eval_agent_config(template_config.key, template_config.value)\n        tool_configs[template_config.key] = {\"value\": config_value}\n    output_json = {\n        \"id\": template.id,\n        \"name\": template.name,\n        \"description\": template.description,\n        \"agent_workflow_id\": template.agent_workflow_id,\n        \"agent_workflow_name\": workflow.name,\n        \"configs\": tool_configs\n    }\n    return output_json\n\n\n@router.post(\"/download\", status_code=201)\ndef download_template(agent_template_id: int,\n                      organisation=Depends(get_user_organisation)):\n    \"\"\"\n    Create a new agent with configurations.\n\n    Args:\n        agent_template_id (int): The ID of the agent template.\n        organisation: User's organisation.\n\n    Returns:\n        dict: A dictionary containing the details of the downloaded template.\n    \"\"\"\n    template = AgentTemplate.clone_agent_template_from_marketplace(db, organisation.id, agent_template_id)\n    return template.to_dict()\n\n\n@router.get(\"/agent_config\", status_code=201)\ndef fetch_agent_config_from_template(agent_template_id: int,\n                                     organisation=Depends(get_user_organisation)):\n    \"\"\"\n    Fetches agent configuration from a template.\n\n    Args:\n        agent_template_id (int): The ID of the agent template.\n        organisation: User's organisation.\n\n    Returns:\n        dict: A dictionary containing the agent configuration fetched from the template.\n\n    Raises:\n        HTTPException: If the template is not found.\n    \"\"\"\n\n    agent_template = db.session.query(AgentTemplate).filter(AgentTemplate.id == agent_template_id,\n                                                            AgentTemplate.organisation_id == organisation.id).first()\n    if not agent_template:\n        raise HTTPException(status_code=404, detail=\"Template not found\")\n\n    template_config = db.session.query(AgentTemplateConfig).filter(\n        AgentTemplateConfig.agent_template_id == agent_template_id).all()\n    template_config_dict = {}\n    main_keys = AgentTemplate.main_keys()\n    for config in template_config:\n        if config.key in main_keys:\n            template_config_dict[config.key] = AgentTemplate.eval_agent_config(config.key, config.value)\n\n    if \"instruction\" not in template_config_dict:\n        template_config_dict[\"instruction\"] = []\n\n    if \"constraints\" not in template_config_dict:\n        template_config_dict[\"constraints\"] = []\n\n    for key in main_keys:\n        if key not in template_config_dict:\n            template_config_dict[key] = \"\"\n\n    template_config_dict[\"agent_template_id\"] = agent_template.id\n    agent_workflow = AgentWorkflow.find_by_id(db.session, agent_template.agent_workflow_id)\n    template_config_dict[\"agent_workflow\"] = agent_workflow.name\n\n    return template_config_dict\n\n\n@router.post(\"/publish_template/agent_execution_id/{agent_execution_id}\", status_code=201)\ndef publish_template(agent_execution_id: str, organisation=Depends(get_user_organisation), user=Depends(get_current_user)):\n\n    \"\"\"\n    Publish an agent execution as a template.\n\n    Args:\n        agent_execution_id (str): The ID of the agent execution to save as a template.\n        organisation (Depends): Dependency to get the user organisation.\n        user (Depends): Dependency to get the user.\n\n    Returns:\n        dict: The saved agent template.\n\n    Raises:\n        HTTPException (status_code=404): If the agent or agent execution configurations are not found.\n    \"\"\"\n    \n    if agent_execution_id == 'undefined':\n        raise HTTPException(status_code = 404, detail = \"Agent Execution Id undefined\")\n\n    agent_executions = AgentExecution.get_agent_execution_from_id(db.session, agent_execution_id)\n    if agent_executions is None:\n        raise HTTPException(status_code = 404, detail = \"Agent Execution not found\")\n    agent_id = agent_executions.agent_id\n\n    agent = db.session.query(Agent).filter(Agent.id == agent_id).first()\n    if agent is None:\n        raise HTTPException(status_code=404, detail=\"Agent not found\")\n\n    agent_execution_configurations = db.session.query(AgentExecutionConfiguration).filter(AgentExecutionConfiguration.agent_execution_id == agent_execution_id).all()\n    if not agent_execution_configurations:\n        raise HTTPException(status_code=404, detail=\"Agent execution configurations not found\")\n\n    agent_template = AgentTemplate(name=agent.name, description=agent.description,\n                                   agent_workflow_id=agent.agent_workflow_id,\n                                   organisation_id=organisation.id)\n    db.session.add(agent_template)\n    db.session.commit()\n\n    main_keys = AgentTemplate.main_keys()\n    for agent_execution_configuration in agent_execution_configurations:\n        config_value = agent_execution_configuration.value\n        if agent_execution_configuration.key not in main_keys:\n            continue\n        if agent_execution_configuration.key == \"tools\":\n            config_value = str(Tool.convert_tool_ids_to_names(db, eval(agent_execution_configuration.value)))\n        agent_template_config = AgentTemplateConfig(agent_template_id=agent_template.id, key=agent_execution_configuration.key,\n                                                    value=config_value)\n        db.session.add(agent_template_config)\n\n    agent_template_configs = [\n    AgentTemplateConfig(agent_template_id=agent_template.id, key=\"status\", value=\"UNDER REVIEW\"),\n    AgentTemplateConfig(agent_template_id=agent_template.id, key=\"Contributor Name\", value=user.name),\n    AgentTemplateConfig(agent_template_id=agent_template.id, key=\"Contributor Email\", value=user.email)]\n    db.session.add_all(agent_template_configs)\n\n    db.session.commit()\n    db.session.flush()\n    return agent_template.to_dict()\n\n@router.post(\"/publish_template\", status_code=201)\ndef handle_publish_template(updated_details: AgentPublish, organisation=Depends(get_user_organisation), user=Depends(get_current_user)):\n    \n    \"\"\"\n    Publish a template from edit template page.\n\n    Args:\n        organisation (Depends): Dependency to get the user organisation.\n        user (Depends): Dependency to get the user.\n\n    Returns:\n        dict: The saved agent template.\n\n    Raises:\n        HTTPException (status_code=404): If the agent template or workflow are not found.\n    \"\"\"\n\n    old_template_id = updated_details.agent_template_id\n    old_agent_template = db.session.query(AgentTemplate).filter(AgentTemplate.id==old_template_id, AgentTemplate.organisation_id==organisation.id).first()\n    if old_agent_template is None:\n        raise HTTPException(status_code = 404, detail = \"Agent Template not found\")\n    agent_workflow_id = old_agent_template.agent_workflow_id\n    if agent_workflow_id is None:\n        raise HTTPException(status_code = 404, detail = \"Agent Workflow not found\")\n    \n    agent_template = AgentTemplate(name=updated_details.name, description=updated_details.description,\n                                   agent_workflow_id=agent_workflow_id,\n                                   organisation_id=organisation.id)\n    db.session.add(agent_template)\n    db.session.commit()\n\n    agent_template_configs = {\n        \"goal\": updated_details.goal,\n        \"instruction\": updated_details.instruction,\n        \"constraints\": updated_details.constraints,\n        \"toolkits\": updated_details.toolkits,\n        \"exit\": updated_details.exit,\n        \"tools\": updated_details.tools,\n        \"iteration_interval\": updated_details.iteration_interval,\n        \"model\": updated_details.model,\n        \"permission_type\": updated_details.permission_type,\n        \"LTM_DB\": updated_details.LTM_DB,\n        \"max_iterations\": updated_details.max_iterations,\n        \"user_timezone\": updated_details.user_timezone,\n        \"knowledge\": updated_details.knowledge\n    }\n\n    for key, value in agent_template_configs.items():\n        if key == \"tools\":\n            value = Tool.convert_tool_ids_to_names(db, value)\n        agent_template_config = AgentTemplateConfig(agent_template_id=agent_template.id, key=key, value=str(value))\n        db.session.add(agent_template_config)\n\n    agent_template_configs = [\n    AgentTemplateConfig(agent_template_id=agent_template.id, key=\"status\", value=\"UNDER REVIEW\"),\n    AgentTemplateConfig(agent_template_id=agent_template.id, key=\"Contributor Name\", value=user.name),\n    AgentTemplateConfig(agent_template_id=agent_template.id, key=\"Contributor Email\", value=user.email)]\n    db.session.add_all(agent_template_configs)\n\n    db.session.commit()\n    db.session.flush()\n    return agent_template.to_dict()"
  },
  {
    "path": "superagi/controllers/agent_workflow.py",
    "content": "from fastapi import APIRouter\nfrom fastapi import Depends\nfrom fastapi_sqlalchemy import db\n\nfrom superagi.helper.auth import get_user_organisation\nfrom superagi.models.workflows.agent_workflow import AgentWorkflow\n\nrouter = APIRouter()\n\n\n@router.get(\"/list\", status_code=201)\ndef list_workflows(organisation=Depends(get_user_organisation)):\n    \"\"\"\n    Lists agent workflows.\n\n    Args:\n        organisation: User's organisation.\n\n    Returns:\n        list: A list of dictionaries representing the agent workflows.\n\n    \"\"\"\n\n    workflows = db.session.query(AgentWorkflow).all()\n\n    output_json = []\n    for workflow in workflows:\n        output_json.append(workflow.to_dict())\n    return output_json\n"
  },
  {
    "path": "superagi/controllers/analytics.py",
    "content": "from fastapi import APIRouter, Depends, HTTPException\nfrom superagi.helper.auth import check_auth, get_user_organisation\nfrom superagi.apm.analytics_helper import AnalyticsHelper\nfrom superagi.apm.event_handler import EventHandler\nfrom superagi.apm.tools_handler import ToolsHandler\nfrom superagi.apm.knowledge_handler import KnowledgeHandler\nfrom fastapi_jwt_auth import AuthJWT\nfrom fastapi_sqlalchemy import db\nimport logging\n\nrouter = APIRouter()\n\n@router.get(\"/metrics\", status_code=200)\ndef get_metrics(organisation=Depends(get_user_organisation)):\n    \"\"\"\n    Get the total tokens, total calls, and the number of run completed.\n\n    Returns:\n        metrics: dictionary containing total tokens, total calls, and the number of runs completed.\n\n    \"\"\"\n    try:\n        return AnalyticsHelper(session=db.session, organisation_id=organisation.id).calculate_run_completed_metrics()\n    except Exception as e:\n        logging.error(f\"Error while calculating metrics: {str(e)}\")\n        raise HTTPException(status_code=500, detail=\"Internal Server Error\")\n\n\n@router.get(\"/agents/all\", status_code=200)\ndef get_agents(organisation=Depends(get_user_organisation)):\n    try:\n        return AnalyticsHelper(session=db.session, organisation_id=organisation.id).fetch_agent_data()\n    except Exception as e:\n        logging.error(f\"Error while fetching agent data: {str(e)}\")\n        raise HTTPException(status_code=500, detail=\"Internal Server Error\")\n\n\n@router.get(\"/agents/{agent_id}\", status_code=200)\ndef get_agent_runs(agent_id: int, organisation=Depends(get_user_organisation)):\n    try:\n        return AnalyticsHelper(session=db.session, organisation_id=organisation.id).fetch_agent_runs(agent_id)\n    except Exception as e:\n        logging.error(f\"Error while fetching agent runs: {str(e)}\")\n        raise HTTPException(status_code=500, detail=\"Internal Server Error\")\n\n\n@router.get(\"/runs/active\", status_code=200)\ndef get_active_runs(organisation=Depends(get_user_organisation)):\n    try:\n        return AnalyticsHelper(session=db.session, organisation_id=organisation.id).get_active_runs()\n    except Exception as e:\n        logging.error(f\"Error while getting active runs: {str(e)}\")\n        raise HTTPException(status_code=500, detail=\"Internal Server Error\")\n\n\n@router.get(\"/tools/used\", status_code=200)\ndef get_tools_used(organisation=Depends(get_user_organisation)):\n    try:\n        return ToolsHandler(session=db.session, organisation_id=organisation.id).calculate_tool_usage()\n    except Exception as e:\n        logging.error(f\"Error while calculating tool usage: {str(e)}\")\n        raise HTTPException(status_code=500, detail=\"Internal Server Error\")\n\n\n@router.get(\"/tools/{tool_name}/usage\", status_code=200)\ndef get_tool_usage(tool_name: str, organisation=Depends(get_user_organisation)):\n    try: \n        return ToolsHandler(session=db.session, organisation_id=organisation.id).get_tool_usage_by_name(tool_name)\n    except Exception as e:\n        if hasattr(e, 'status_code'):\n            raise HTTPException(status_code=e.status_code, detail=e.detail)\n        else:\n            raise HTTPException(status_code=500, detail=\"Internal Server Error\")\n\n\n@router.get(\"/knowledge/{knowledge_name}/usage\", status_code=200)\ndef get_knowledge_usage(knowledge_name:str, organisation=Depends(get_user_organisation)):\n    try: \n        return KnowledgeHandler(session=db.session, organisation_id=organisation.id).get_knowledge_usage_by_name(knowledge_name)\n    except Exception as e:\n        if hasattr(e, 'status_code'):\n            raise HTTPException(status_code=e.status_code, detail=e.detail)\n        else:\n            raise HTTPException(status_code=500, detail=\"Internal Server Error\")\n\n\n@router.get(\"/tools/{tool_name}/logs\", status_code=200)\ndef get_tool_logs(tool_name: str, organisation=Depends(get_user_organisation)):\n    try: \n        return ToolsHandler(session=db.session, organisation_id=organisation.id).get_tool_events_by_name(tool_name)\n    except Exception as e:\n        logging.error(f\"Error while getting tool event details: {str(e)}\")\n        if hasattr(e, 'status_code'):\n            raise HTTPException(status_code=e.status_code, detail=e.detail)\n        else:\n            raise HTTPException(status_code=500, detail=\"Internal Server Error\")\n\n@router.get(\"/knowledge/{knowledge_name}/logs\", status_code=200)\ndef get_knowledge_logs(knowledge_name: str, organisation=Depends(get_user_organisation)):\n    try: \n        return KnowledgeHandler(session=db.session, organisation_id=organisation.id).get_knowledge_events_by_name(knowledge_name)\n    except Exception as e:\n        logging.error(f\"Error while getting knowledge event details: {str(e)}\")\n        if hasattr(e, 'status_code'):\n            raise HTTPException(status_code=e.status_code, detail=e.detail)\n        else:\n            raise HTTPException(status_code=500, detail=\"Internal Server Error\")"
  },
  {
    "path": "superagi/controllers/api/agent.py",
    "content": "from fastapi import APIRouter\nfrom fastapi import HTTPException, Depends ,Security\n\nfrom fastapi_sqlalchemy import db\nfrom pydantic import BaseModel\n\nfrom superagi.worker import execute_agent\nfrom superagi.helper.auth import validate_api_key,get_organisation_from_api_key\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_execution_config import AgentExecutionConfiguration\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.models.agent_schedule import AgentSchedule\nfrom superagi.models.project import Project\nfrom superagi.models.workflows.agent_workflow import AgentWorkflow\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.organisation import Organisation\nfrom superagi.models.knowledges import Knowledges\nfrom superagi.models.resource import Resource\nfrom superagi.controllers.types.agent_with_config import AgentConfigExtInput,AgentConfigUpdateExtInput\nfrom superagi.models.workflows.iteration_workflow import IterationWorkflow\nfrom superagi.helper.s3_helper import S3Helper\nfrom datetime import datetime\nfrom typing import Optional,List\nfrom superagi.models.toolkit import Toolkit\nfrom superagi.apm.event_handler import EventHandler\nfrom superagi.config.config import get_config\nrouter = APIRouter()\n\nclass AgentExecutionIn(BaseModel):\n    name: Optional[str]\n    goal: Optional[List[str]]\n    instruction: Optional[List[str]]\n\n    class Config:\n        orm_mode = True\n\nclass RunFilterConfigIn(BaseModel):\n    run_ids:Optional[List[int]]\n    run_status_filter:Optional[str]\n\n    class Config:\n        orm_mode = True\n\nclass ExecutionStateChangeConfigIn(BaseModel):\n    run_ids:Optional[List[int]]\n\n    class Config:\n        orm_mode = True\n\nclass RunIDConfig(BaseModel):\n    run_ids:List[int]\n\n    class Config:\n        orm_mode = True\n\n@router.post(\"\", status_code=200)\ndef create_agent_with_config(agent_with_config: AgentConfigExtInput,\n                             api_key: str = Security(validate_api_key), organisation:Organisation = Depends(get_organisation_from_api_key)):\n    project=Project.find_by_org_id(db.session, organisation.id)\n    try:\n        tools_arr=Toolkit.get_tool_and_toolkit_arr(db.session,organisation.id,agent_with_config.tools)\n    except Exception as e:\n        raise HTTPException(status_code=404, detail=str(e))\n\n    agent_with_config.tools=tools_arr\n    agent_with_config.project_id=project.id\n    agent_with_config.exit=\"No exit criterion\"\n    agent_with_config.permission_type=\"God Mode\"\n    agent_with_config.LTM_DB=None\n    db_agent = Agent.create_agent_with_config(db, agent_with_config)\n\n    if agent_with_config.schedule is not None:\n        agent_schedule = AgentSchedule.save_schedule_from_config(db.session, db_agent, agent_with_config.schedule)\n        if agent_schedule is None:\n            raise HTTPException(status_code=500, detail=\"Failed to schedule agent\")\n        EventHandler(session=db.session).create_event('agent_created', {'agent_name': agent_with_config.name,\n                                                                            'model': agent_with_config.model}, db_agent.id,\n                                                        organisation.id if organisation else 0)\n        db.session.commit()\n        return {\n            \"agent_id\": db_agent.id\n        }\n    \n    start_step = AgentWorkflow.fetch_trigger_step_id(db.session, db_agent.agent_workflow_id)\n    iteration_step_id = IterationWorkflow.fetch_trigger_step_id(db.session,\n                                                                start_step.action_reference_id).id if start_step.action_type == \"ITERATION_WORKFLOW\" else -1\n    # Creating an execution with RUNNING status\n    execution = AgentExecution(status='CREATED', last_execution_time=datetime.now(), agent_id=db_agent.id,\n                               name=\"New Run\", current_agent_step_id=start_step.id, iteration_workflow_step_id=iteration_step_id)\n    agent_execution_configs = {\n        \"goal\": agent_with_config.goal,\n        \"instruction\": agent_with_config.instruction,\n        \"constraints\": agent_with_config.constraints,\n        \"exit\": agent_with_config.exit,\n        \"tools\": agent_with_config.tools,\n        \"iteration_interval\": agent_with_config.iteration_interval,\n        \"model\": agent_with_config.model,\n        \"permission_type\": agent_with_config.permission_type,\n        \"LTM_DB\": agent_with_config.LTM_DB,\n        \"max_iterations\": agent_with_config.max_iterations,\n        \"user_timezone\": agent_with_config.user_timezone,\n        \"knowledge\": agent_with_config.knowledge\n    }\n    db.session.add(execution)\n    db.session.commit()\n    db.session.flush()\n    AgentExecutionConfiguration.add_or_update_agent_execution_config(session=db.session, execution=execution,\n                                                                     agent_execution_configs=agent_execution_configs)\n\n    organisation = db_agent.get_agent_organisation(db.session)\n    EventHandler(session=db.session).create_event('agent_created', {'agent_name': agent_with_config.name,\n                                                                    'model': agent_with_config.model}, db_agent.id,\n                                                  organisation.id if organisation else 0)\n    # execute_agent.delay(execution.id, datetime.now())\n    db.session.commit()\n    return {\n        \"agent_id\": db_agent.id\n    }\n\n@router.post(\"/{agent_id}/run\",status_code=200)\ndef create_run(agent_id:int,agent_execution: AgentExecutionIn,api_key: str = Security(validate_api_key),organisation:Organisation = Depends(get_organisation_from_api_key)):\n    agent=Agent.get_agent_from_id(db.session,agent_id)\n    if not agent:\n        raise HTTPException(status_code=404, detail=\"Agent not found\")\n    project=Project.find_by_id(db.session, agent.project_id)\n    if project.organisation_id!=organisation.id:\n        raise HTTPException(status_code=404, detail=\"Agent not found\")\n    db_schedule=AgentSchedule.find_by_agent_id(db.session, agent_id)\n    if db_schedule is not None:\n        raise HTTPException(status_code=409, detail=\"Agent is already scheduled,cannot run\")\n    start_step = AgentWorkflow.fetch_trigger_step_id(db.session, agent.agent_workflow_id)\n    db_agent_execution=AgentExecution.get_execution_by_agent_id_and_status(db.session, agent_id, \"CREATED\")\n\n    if db_agent_execution is None:\n        db_agent_execution = AgentExecution(status=\"RUNNING\", last_execution_time=datetime.now(),\n                                            agent_id=agent_id, name=agent_execution.name, num_of_calls=0,\n                                            num_of_tokens=0,\n                                            current_agent_step_id=start_step.id)\n        db.session.add(db_agent_execution)\n    else:\n        db_agent_execution.status = \"RUNNING\"\n\n    db.session.commit()\n    db.session.flush()\n\n    agent_execution_configs = {}\n    if agent_execution.goal is not None:\n        agent_execution_configs = {\n            \"goal\": agent_execution.goal,\n        }\n\n    if agent_execution.instruction is not None:\n        agent_execution_configs[\"instructions\"] = agent_execution.instruction,\n\n    if agent_execution_configs != {}:\n        AgentExecutionConfiguration.add_or_update_agent_execution_config(session=db.session, execution=db_agent_execution,\n                                                                     agent_execution_configs=agent_execution_configs)\n    EventHandler(session=db.session).create_event('run_created', \n                                                  {'agent_execution_id': db_agent_execution.id,\n                                                   'agent_execution_name':db_agent_execution.name\n                                                   },\n                                                   agent_id, \n                                                   organisation.id if organisation else 0)\n    \n    agent_execution_knowledge = AgentConfiguration.get_agent_config_by_key_and_agent_id(session= db.session, key= 'knowledge', agent_id= agent_id)\n    if agent_execution_knowledge and agent_execution_knowledge.value != 'None':\n        knowledge_name = Knowledges.get_knowledge_from_id(db.session, int(agent_execution_knowledge.value)).name\n        if knowledge_name is not None:\n            EventHandler(session=db.session).create_event('knowledge_picked', \n                                                        {'knowledge_name': knowledge_name, \n                                                         'agent_execution_id': db_agent_execution.id},\n                                                        agent_id,\n                                                        organisation.id if organisation else 0\n                                                        )\n\n    if db_agent_execution.status == \"RUNNING\":\n      execute_agent.delay(db_agent_execution.id, datetime.now())\n    return {\n        \"run_id\":db_agent_execution.id\n    }\n\n@router.put(\"/{agent_id}\",status_code=200)\ndef update_agent(agent_id: int, agent_with_config: AgentConfigUpdateExtInput,api_key: str = Security(validate_api_key),\n                                        organisation:Organisation = Depends(get_organisation_from_api_key)):\n    \n    db_agent= Agent.get_active_agent_by_id(db.session, agent_id)\n    if not db_agent:\n        raise HTTPException(status_code=404, detail=\"agent not found\")\n    \n    project=Project.find_by_id(db.session, db_agent.project_id)\n    if project is None:\n        raise HTTPException(status_code=404, detail=\"Project not found\")\n    \n    if project.organisation_id!=organisation.id:\n        raise HTTPException(status_code=404, detail=\"Agent not found\")\n\n    # db_execution=AgentExecution.get_execution_by_agent_id_and_status(db.session, agent_id, \"RUNNING\")\n    # if db_execution is not None:\n    #     raise HTTPException(status_code=409, detail=\"Agent is already running,please pause and then update\")\n     \n    db_schedule=AgentSchedule.find_by_agent_id(db.session, agent_id)\n    if db_schedule is not None:\n        raise HTTPException(status_code=409, detail=\"Agent is already scheduled,cannot update\")\n    \n    try:\n        tools_arr=Toolkit.get_tool_and_toolkit_arr(db.session,organisation.id,agent_with_config.tools)\n    except Exception as e:\n        raise HTTPException(status_code=404,detail=str(e))\n\n    if agent_with_config.schedule is not None:\n        raise HTTPException(status_code=400,detail=\"Cannot schedule an existing agent\")\n    agent_with_config.tools=tools_arr\n    agent_with_config.project_id=project.id\n    agent_with_config.exit=\"No exit criterion\"\n    agent_with_config.permission_type=\"God Mode\"\n    agent_with_config.LTM_DB=None\n\n    for key,value in agent_with_config.dict().items():\n        if hasattr(db_agent,key) and value is not None:\n            setattr(db_agent,key,value)\n    db.session.commit()\n    db.session.flush()\n\n    start_step = AgentWorkflow.fetch_trigger_step_id(db.session, db_agent.agent_workflow_id)\n    iteration_step_id = IterationWorkflow.fetch_trigger_step_id(db.session,\n                                                                start_step.action_reference_id).id if start_step.action_type == \"ITERATION_WORKFLOW\" else -1\n    execution = AgentExecution(status='CREATED', last_execution_time=datetime.now(), agent_id=db_agent.id,\n                               name=\"New Run\", current_agent_step_id=start_step.id, iteration_workflow_step_id=iteration_step_id)\n    agent_execution_configs = {\n        \"goal\": agent_with_config.goal,\n        \"instruction\": agent_with_config.instruction,\n        \"tools\":agent_with_config.tools,\n        \"constraints\": agent_with_config.constraints,\n        \"iteration_interval\": agent_with_config.iteration_interval,\n        \"model\": agent_with_config.model,\n        \"max_iterations\": agent_with_config.max_iterations,\n        \"agent_workflow\": agent_with_config.agent_workflow,\n    }\n    agent_configurations = [\n        AgentConfiguration(agent_id=db_agent.id, key=key, value=str(value))\n        for key, value in agent_execution_configs.items()\n    ]\n    db.session.add_all(agent_configurations)\n    db.session.add(execution)\n    db.session.commit()\n    db.session.flush()\n    AgentExecutionConfiguration.add_or_update_agent_execution_config(session=db.session, execution=execution,\n                                                                     agent_execution_configs=agent_execution_configs)\n    db.session.commit()\n\n    return {\n        \"agent_id\":db_agent.id\n    }\n\n\n@router.post(\"/{agent_id}/run-status\")\ndef get_agent_runs(agent_id:int,filter_config:RunFilterConfigIn,api_key: str = Security(validate_api_key),organisation:Organisation = Depends(get_organisation_from_api_key)):\n    agent= Agent.get_active_agent_by_id(db.session, agent_id)\n    if not agent:\n        raise HTTPException(status_code=404, detail=\"Agent not found\")\n    \n    project=Project.find_by_id(db.session, agent.project_id)\n    if project.organisation_id!=organisation.id:\n        raise HTTPException(status_code=404, detail=\"Agent not found\")\n    \n    db_execution_arr=[]\n    if filter_config.run_status_filter is not None:\n        filter_config.run_status_filter=filter_config.run_status_filter.upper()\n\n    db_execution_arr=AgentExecution.get_all_executions_by_filter_config(db.session, agent.id, filter_config)\n    \n    response_arr=[]\n    for ind_execution in db_execution_arr:\n        response_arr.append({\"run_id\":ind_execution.id, \"status\":ind_execution.status})\n\n    return response_arr\n\n\n@router.post(\"/{agent_id}/pause\",status_code=200)\ndef pause_agent_runs(agent_id:int,execution_state_change_input:ExecutionStateChangeConfigIn,api_key: str = Security(validate_api_key),organisation:Organisation = Depends(get_organisation_from_api_key)):\n    agent= Agent.get_active_agent_by_id(db.session, agent_id)\n    if not agent:\n        raise HTTPException(status_code=404, detail=\"Agent not found\")\n    \n    project=Project.find_by_id(db.session, agent.project_id)\n    if project.organisation_id!=organisation.id:\n        raise HTTPException(status_code=404, detail=\"Agent not found\")\n    \n    #Checking if the run_ids whose output files are requested belong to the organisation \n    if execution_state_change_input.run_ids is not None:\n        try:\n            AgentExecution.validate_run_ids(db.session,execution_state_change_input.run_ids,organisation.id)\n        except Exception as e:\n            raise HTTPException(status_code=404, detail=\"One or more run id(s) not found\")\n    \n    db_execution_arr=AgentExecution.get_all_executions_by_status_and_agent_id(db.session, agent.id, execution_state_change_input, \"RUNNING\")\n\n    if db_execution_arr is not None and execution_state_change_input.run_ids is not None \\\n            and len(db_execution_arr) != len(execution_state_change_input.run_ids):\n        raise HTTPException(status_code=404, detail=\"One or more run id(s) not found\")\n\n    for ind_execution in db_execution_arr:\n        ind_execution.status=\"PAUSED\"\n    db.session.commit()\n    db.session.flush()\n    return {\n        \"result\":\"success\"\n    }\n\n@router.post(\"/{agent_id}/resume\",status_code=200)\ndef resume_agent_runs(agent_id:int,execution_state_change_input:ExecutionStateChangeConfigIn,api_key: str = Security(validate_api_key),organisation:Organisation = Depends(get_organisation_from_api_key)):\n    agent= Agent.get_active_agent_by_id(db.session, agent_id)\n    if not agent:\n        raise HTTPException(status_code=404, detail=\"Agent not found\")\n    \n    project=Project.find_by_id(db.session, agent.project_id)\n    if project.organisation_id!=organisation.id:\n        raise HTTPException(status_code=404, detail=\"Agent not found\")\n    \n    if execution_state_change_input.run_ids is not None:\n        try:\n            AgentExecution.validate_run_ids(db.session,execution_state_change_input.run_ids,organisation.id)\n        except Exception as e:\n            raise HTTPException(status_code=404, detail=\"One or more run id(s) not found\")\n    \n    db_execution_arr=AgentExecution.get_all_executions_by_status_and_agent_id(db.session, agent.id, execution_state_change_input, \"PAUSED\")\n\n    if db_execution_arr is not None and execution_state_change_input.run_ids is not None\\\n            and len(db_execution_arr) != len(execution_state_change_input.run_ids):\n        raise HTTPException(status_code=404, detail=\"One or more run id(s) not found\")\n\n    for ind_execution in db_execution_arr:\n        ind_execution.status=\"RUNNING\"\n        execute_agent.delay(ind_execution.id, datetime.now())\n        \n    db.session.commit()\n    db.session.flush()\n\n    return {\n        \"result\":\"success\"\n    }\n\n@router.post(\"/resources/output\",status_code=200)\ndef get_run_resources(run_id_config:RunIDConfig,api_key: str = Security(validate_api_key),organisation:Organisation = Depends(get_organisation_from_api_key)):\n    if get_config('STORAGE_TYPE') != \"S3\":\n        raise HTTPException(status_code=400,detail=\"This endpoint only works when S3 is configured\")\n    run_ids_arr=run_id_config.run_ids\n    if len(run_ids_arr)==0:  \n        raise HTTPException(status_code=404,\n                            detail=f\"No execution_id found\")\n    #Checking if the run_ids whose output files are requested belong to the organisation \n    try:\n        AgentExecution.validate_run_ids(db.session, run_ids_arr, organisation.id)\n    except Exception as e:\n        raise HTTPException(status_code=404, detail=\"One or more run id(s) not found\")\n    \n    db_resources_arr=Resource.find_by_run_ids(db.session, run_ids_arr)\n\n    try:\n        response_obj=S3Helper().get_download_url_of_resources(db_resources_arr)\n    except:\n        raise HTTPException(status_code=401,detail=\"Invalid S3 credentials\")\n    return response_obj\n\n"
  },
  {
    "path": "superagi/controllers/api_key.py",
    "content": "import json\nimport uuid\nfrom fastapi import APIRouter, Body\nfrom fastapi import HTTPException, Depends\nfrom fastapi_jwt_auth import AuthJWT\nfrom fastapi_sqlalchemy import db\nfrom pydantic import BaseModel\nfrom superagi.helper.auth import get_user_organisation, validate_api_key\nfrom superagi.helper.auth import check_auth\nfrom superagi.models.api_key import ApiKey\nfrom typing import Optional, Annotated\n\nrouter = APIRouter()\n\n\nclass ApiKeyIn(BaseModel):\n    id: int\n    name: str\n\n    class Config:\n        orm_mode = True\n\n\nclass ApiKeyDeleteIn(BaseModel):\n    id: int\n\n    class Config:\n        orm_mode = True\n\n\n@router.post(\"\")\ndef create_api_key(name: Annotated[str, Body(embed=True)], Authorize: AuthJWT = Depends(check_auth),\n                   organisation=Depends(get_user_organisation)):\n    api_key = str(uuid.uuid4())\n    obj = ApiKey(key=api_key, name=name, org_id=organisation.id)\n    db.session.add(obj)\n    db.session.commit()\n    db.session.flush()\n    return {\"api_key\": api_key}\n\n\n@router.get(\"/validate\")\ndef validate_api_key(api_key: str = Depends(validate_api_key)):\n    return {\"success\": True}\n\n\n@router.get(\"\")\ndef get_all(Authorize: AuthJWT = Depends(check_auth), organisation=Depends(get_user_organisation)):\n    api_keys = ApiKey.get_by_org_id(db.session, organisation.id)\n    return api_keys\n\n\n@router.delete(\"/{api_key_id}\")\ndef delete_api_key(api_key_id: int, Authorize: AuthJWT = Depends(check_auth)):\n    api_key = ApiKey.get_by_id(db.session, api_key_id)\n    if api_key is None:\n        raise HTTPException(status_code=404, detail=\"API key not found\")\n    ApiKey.delete_by_id(db.session, api_key_id)\n    return {\"success\": True}\n\n\n@router.put(\"\")\ndef edit_api_key(api_key_in: ApiKeyIn, Authorize: AuthJWT = Depends(check_auth)):\n    api_key = ApiKey.get_by_id(db.session, api_key_in.id)\n    if api_key is None:\n        raise HTTPException(status_code=404, detail=\"API key not found\")\n    ApiKey.update_api_key(db.session, api_key_in.id, api_key_in.name)\n    return {\"success\": True}\n"
  },
  {
    "path": "superagi/controllers/budget.py",
    "content": "from fastapi import APIRouter\nfrom fastapi import HTTPException, Depends\nfrom fastapi_jwt_auth import AuthJWT\nfrom fastapi_sqlalchemy import db\nfrom pydantic import BaseModel\n\nfrom superagi.helper.auth import check_auth\nfrom superagi.models.budget import Budget\n# from superagi.types.db import BudgetIn, BudgetOut\n\nrouter = APIRouter()\n\n\nclass BudgetOut(BaseModel):\n    id: int\n    budget: float\n    cycle: str\n\n    class Config:\n        orm_mode = True\n\n\nclass BudgetIn(BaseModel):\n    budget: float\n    cycle: str\n\n    class Config:\n        orm_mode = True\n\n@router.post(\"/add\", response_model=BudgetOut, status_code=201)\ndef create_budget(budget: BudgetIn,\n                  Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Create a new budget.\n\n    Args:\n        budget: Budget details.\n\n    Returns:\n        Budget: Created budget.\n\n    \"\"\"\n\n    new_budget = Budget(\n        budget=budget.budget,\n        cycle=budget.cycle\n    )\n    db.session.add(new_budget)\n    db.session.commit()\n\n    return new_budget\n\n\n@router.get(\"/get/{budget_id}\", response_model=BudgetOut)\ndef get_budget(budget_id: int,\n               Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Get a budget by budget_id.\n\n    Args:\n        budget_id: Budget ID.\n\n    Returns:\n        Budget: Retrieved budget.\n\n    \"\"\"\n\n    db_budget = db.session.query(Budget).filter(Budget.id == budget_id).first()\n    if not db_budget:\n        raise HTTPException(status_code=404, detail=\"budget not found\")\n    return db_budget\n\n\n@router.put(\"/update/{budget_id}\", response_model=BudgetOut)\ndef update_budget(budget_id: int, budget: BudgetIn,\n                  Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Update budget details by budget_id.\n\n    Args:\n        budget_id: Budget ID.\n        budget: Updated budget details.\n\n    Returns:\n        Budget: Updated budget.\n\n    \"\"\"\n\n    db_budget = db.session.query(Budget).filter(Budget.id == budget_id).first()\n    if not db_budget:\n        raise HTTPException(status_code=404, detail=\"budget not found\")\n\n    db_budget.budget = budget.budget\n    db_budget.cycle = budget.cycle\n    db.session.commit()\n\n    return db_budget\n"
  },
  {
    "path": "superagi/controllers/config.py",
    "content": "from datetime import datetime\nfrom typing import Optional\n\nfrom fastapi import APIRouter\nfrom pydantic import BaseModel\n\nfrom superagi.models.models_config import ModelsConfig\nfrom superagi.models.configuration import Configuration\nfrom superagi.models.organisation import Organisation\nfrom fastapi_sqlalchemy import db\nfrom fastapi import HTTPException, Depends, Request\nfrom superagi.config.config import get_config\nfrom superagi.helper.auth import check_auth\nfrom fastapi_jwt_auth import AuthJWT\nfrom superagi.helper.encyption_helper import encrypt_data,decrypt_data\nfrom superagi.lib.logger import logger\n# from superagi.types.db import ConfigurationIn, ConfigurationOut\n\nrouter = APIRouter()\n\n\nclass ConfigurationOut(BaseModel):\n    id: int\n    organisation_id: int\n    key: str\n    value: str\n    created_at: datetime\n    updated_at: datetime\n\n    class Config:\n        orm_mode = True\n\n\nclass ConfigurationIn(BaseModel):\n    organisation_id: Optional[int]\n    key: str\n    value: str\n\n    class Config:\n        orm_mode = True\n\n# CRUD Operations\n@router.post(\"/add/organisation/{organisation_id}\", status_code=201,\n             response_model=ConfigurationOut)\ndef create_config(config: ConfigurationIn, organisation_id: int,\n                  Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Creates a new Organisation level config.\n\n    Args:\n        config (Configuration): Configuration details.\n        organisation_id (int): ID of the organisation.\n\n    Returns:\n        Configuration: Created configuration.\n\n    \"\"\"\n\n    db_organisation = db.session.query(Organisation).filter(Organisation.id == organisation_id).first()\n    if not db_organisation:\n        raise HTTPException(status_code=404, detail=\"Organisation not found\")\n\n    existing_config = (\n        db.session.query(Configuration)\n        .filter(Configuration.organisation_id == organisation_id, Configuration.key == config.key)\n        .first()\n    )\n\n    # Encrypt the API key\n    if config.key == \"model_api_key\":\n        encrypted_value = encrypt_data(config.value)\n        config.value = encrypted_value\n\n    if existing_config:\n        existing_config.value = config.value\n        db.session.commit()\n        db.session.flush()\n        return existing_config\n\n    logger.info(\"NEW CONFIG\")\n    new_config = Configuration(organisation_id=organisation_id, key=config.key, value=config.value)\n    logger.info(new_config)\n    logger.info(\"ORGANISATION ID : \", organisation_id)\n    db.session.add(new_config)\n    db.session.commit()\n    db.session.flush()\n    return new_config\n\n\n@router.get(\"/get/organisation/{organisation_id}/key/{key}\", status_code=200)\ndef get_config_by_organisation_id_and_key(organisation_id: int, key: str,\n                                          Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Get a configuration by organisation ID and key.\n\n    Args:\n        organisation_id (int): ID of the organisation.\n        key (str): Key of the configuration.\n        Authorize (AuthJWT, optional): Authorization JWT token. Defaults to Depends(check_auth).\n\n    Returns:\n        Configuration: Retrieved configuration.\n\n    \"\"\"\n\n    db_organisation = db.session.query(Organisation).filter(Organisation.id == organisation_id).first()\n    if not db_organisation:\n        raise HTTPException(status_code=404, detail=\"Organisation not found\")\n\n    config = db.session.query(ModelsConfig).filter(ModelsConfig.org_id == organisation_id, ModelsConfig.provider == 'OpenAI').first()\n    if config is None:\n        api_key = get_config(\"OPENAI_API_KEY\") or get_config(\"PALM_API_KEY\")\n        if (api_key is not None and api_key != \"YOUR_OPEN_API_KEY\") or (\n                api_key is not None and api_key != \"YOUR_PALM_API_KEY\"):\n            encrypted_data = encrypt_data(api_key)\n            new_config = Configuration(organisation_id=organisation_id, key=\"model_api_key\",value=encrypted_data)\n            db.session.add(new_config)\n            db.session.commit()\n            db.session.flush()\n            return new_config\n    return config\n\n\n\n@router.get(\"/get/organisation/{organisation_id}\", status_code=201)\ndef get_config_by_organisation_id(organisation_id: int,\n                                  Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Get all configurations for a given organisation ID.\n\n    Args:\n        organisation_id (int): ID of the organisation.\n        Authorize (AuthJWT, optional): Authorization JWT token. Defaults to Depends(check_auth).\n\n    Returns:\n        List[Configuration]: List of configurations for the organisation.\n\n    \"\"\"\n\n    db_organisation = db.session.query(Organisation).filter(Organisation.id == organisation_id).first()\n    if not db_organisation:\n        raise HTTPException(status_code=404, detail=\"Organisation not found\")\n\n    configs = db.session.query(Configuration).filter(Configuration.organisation_id == organisation_id).all()\n\n    # Decrypt the API key if the key is \"model_api_key\"\n    for config in configs:\n        if config.key == \"model_api_key\":\n            decrypted_value = decrypt_data(config.value)\n            config.value = decrypted_value\n\n    return configs\n\n\n@router.get(\"/get/env\", status_code=200)\ndef current_env():\n    \"\"\"\n    Get the current environment.\n\n    Returns:\n        dict: Dictionary containing the current environment.\n\n    \"\"\"\n\n    env = get_config(\"ENV\", \"DEV\")\n    return {\n        \"env\": env\n    }\n"
  },
  {
    "path": "superagi/controllers/google_oauth.py",
    "content": "from fastapi import Depends, Query\nfrom fastapi import APIRouter\nfrom fastapi.responses import RedirectResponse\nfrom fastapi_jwt_auth import AuthJWT\nfrom fastapi_sqlalchemy import db\nfrom sqlalchemy.orm import sessionmaker\nfrom fastapi import HTTPException\n\nimport superagi\nimport json\nimport requests\nfrom datetime import datetime, timedelta\nfrom superagi.models.db import connect_db\nimport http.client as http_client\nfrom superagi.helper.auth import get_current_user, check_auth\nfrom superagi.models.tool_config import ToolConfig\nfrom superagi.models.toolkit import Toolkit\nfrom superagi.models.oauth_tokens import OauthTokens\nfrom superagi.config.config import get_config\nfrom superagi.helper.encyption_helper import decrypt_data, is_encrypted\n\nrouter = APIRouter()\n\n@router.get('/oauth-tokens')\nasync def google_auth_calendar(code: str = Query(...), state: str = Query(...)):\n    toolkit_id = int(state)\n    client_id = db.session.query(ToolConfig).filter(ToolConfig.key == \"GOOGLE_CLIENT_ID\", ToolConfig.toolkit_id == toolkit_id).first()\n    if(is_encrypted(client_id.value)):\n        client_id = decrypt_data(client_id.value)\n    else:\n        client_id = client_id.value\n    client_secret = db.session.query(ToolConfig).filter(ToolConfig.key == \"GOOGLE_CLIENT_SECRET\", ToolConfig.toolkit_id == toolkit_id).first()\n    if(is_encrypted(client_secret.value)):\n        client_secret = decrypt_data(client_secret.value)\n    else:\n        client_secret = client_secret.value\n    token_uri = 'https://oauth2.googleapis.com/token'\n    scope = 'https://www.googleapis.com/auth/calendar'\n    env = get_config(\"ENV\", \"DEV\")\n    if env == \"DEV\":\n        redirect_uri = \"http://localhost:3000/api/google/oauth-tokens\"\n    else:\n        redirect_uri = \"https://app.superagi.com/api/google/oauth-tokens\"\n    params = {\n        'client_id': client_id,\n        'client_secret': client_secret,\n        'redirect_uri': redirect_uri,\n        'scope': scope,\n        'grant_type': 'authorization_code',\n        'code': code,\n        'access_type': 'offline',\n        'approval_prompt': 'force'\n    }\n    response = requests.post(token_uri, data=params)\n    if response.status_code != 200:\n        raise HTTPException(status_code=400, detail=\"Invalid Client Secret\")\n    response = response.json()\n    expire_time = datetime.utcnow() + timedelta(seconds=response['expires_in'])\n    expire_time = expire_time - timedelta(minutes=5)\n    response['expiry'] = expire_time.strftime(\"%Y-%m-%dT%H:%M:%S.%fZ\")\n    response_data = json.dumps(response)\n    frontend_url = superagi.config.config.get_config(\"FRONTEND_URL\", \"http://localhost:3000\")\n    redirect_url_success = f\"{frontend_url}/google_calendar_creds/?{response_data}\"\n    return RedirectResponse(url=redirect_url_success)\n\n@router.post(\"/send_google_creds/toolkit_id/{toolkit_id}\")\ndef send_google_calendar_configs(google_creds: dict, toolkit_id: int, Authorize: AuthJWT = Depends(check_auth)):\n    engine = connect_db()\n    Session = sessionmaker(bind=engine)\n    session = Session()\n    current_user = get_current_user(Authorize)\n    user_id = current_user.id\n    toolkit = db.session.query(Toolkit).filter(Toolkit.id == toolkit_id).first()\n    google_creds = json.dumps(google_creds)\n    print(google_creds)\n    tokens = OauthTokens().add_or_update(session, toolkit_id, user_id, toolkit.organisation_id, \"GOOGLE_CALENDAR_OAUTH_TOKENS\", google_creds)\n    if tokens:\n        success = True\n    else:\n        success = False\n    return success\n\n\n@router.get(\"/get_google_creds/toolkit_id/{toolkit_id}\")\ndef get_google_calendar_tool_configs(toolkit_id: int):\n    google_calendar_config = db.session.query(ToolConfig).filter(ToolConfig.toolkit_id == toolkit_id,\n                                                                 ToolConfig.key == \"GOOGLE_CLIENT_ID\").first()\n    if is_encrypted(google_calendar_config.value):\n        google_calendar_config.value = decrypt_data(google_calendar_config.value)\n    return {\n        \"client_id\": google_calendar_config.value\n    }\n"
  },
  {
    "path": "superagi/controllers/knowledge_configs.py",
    "content": "from fastapi_sqlalchemy import db\nfrom fastapi import HTTPException, Depends, Query, status\nfrom fastapi import APIRouter\nfrom superagi.config.config import get_config\nfrom superagi.helper.auth import check_auth\nfrom superagi.models.knowledge_configs import KnowledgeConfigs\nfrom fastapi_jwt_auth import AuthJWT\n\nrouter = APIRouter()\n\n@router.get(\"/marketplace/details/{knowledge_id}\")\ndef get_marketplace_knowledge_configs(knowledge_id: int):\n    knowledge_configs = db.session.query(KnowledgeConfigs).filter(KnowledgeConfigs.knowledge_id == knowledge_id).all()\n    return knowledge_configs\n\n"
  },
  {
    "path": "superagi/controllers/knowledges.py",
    "content": "from fastapi_sqlalchemy import db\nfrom fastapi import HTTPException, Depends, Query, status\nfrom fastapi import APIRouter\nfrom datetime import datetime\nfrom superagi.config.config import get_config\nfrom superagi.helper.auth import get_user_organisation\nfrom superagi.models.knowledges import Knowledges\nfrom superagi.models.marketplace_stats import MarketPlaceStats\nfrom superagi.models.knowledge_configs import KnowledgeConfigs\nfrom superagi.models.vector_db_indices import VectordbIndices\nfrom superagi.models.vector_dbs import Vectordbs\nfrom superagi.helper.s3_helper import S3Helper\nfrom superagi.models.vector_db_configs import VectordbConfigs\nfrom superagi.vector_store.vector_factory import VectorFactory\nfrom superagi.vector_embeddings.vector_embedding_factory import VectorEmbeddingFactory\nfrom superagi.helper.time_helper import get_time_difference\n\nrouter = APIRouter()\n\n@router.get(\"/get/list\")\ndef get_knowledge_list(\n    page: int = Query(None, title=\"Page Number\"),\n    organisation = Depends(get_user_organisation)\n):\n    \"\"\"\n    Get Marketplace Knowledge list.\n\n    Args:\n        page (int, optional): The page number for pagination. Defaults to None.\n\n    Returns:\n        dict: The response containing the marketplace list.\n\n    \"\"\"\n    if page < 0:\n        page = 0\n    marketplace_knowledges = Knowledges.fetch_marketplace_list(page)\n    marketplace_knowledges_with_install = Knowledges.get_knowledge_install_details(db.session, marketplace_knowledges, organisation)\n    for knowledge in marketplace_knowledges_with_install:\n        knowledge[\"install_number\"] = MarketPlaceStats.get_knowledge_installation_number(knowledge[\"id\"])\n    return marketplace_knowledges_with_install    \n\n@router.get(\"/marketplace/list/{page}\")\ndef get_marketplace_knowledge_list(page: int = 0):\n    organisation_id = int(get_config(\"MARKETPLACE_ORGANISATION_ID\"))\n    page_size = 30\n\n    # Apply search filter if provided\n    query = db.session.query(Knowledges).filter(Knowledges.organisation_id == organisation_id)\n\n    if page < 0:\n        knowledges = query.all()\n    # Paginate the results\n    knowledges = query.offset(page * page_size).limit(page_size).all()\n\n    return knowledges\n\n@router.get(\"/user/list\")\ndef get_user_knowledge_list(organisation = Depends(get_user_organisation)):\n    marketplace_knowledges = Knowledges.fetch_marketplace_list(page=0)\n    user_knowledge_list = Knowledges.get_organisation_knowledges(db.session, organisation)\n    for user_knowledge in user_knowledge_list:\n        if user_knowledge[\"name\"] in [knowledge['name'] for knowledge in marketplace_knowledges]:\n            user_knowledge[\"is_marketplace\"] = True\n        else:\n            user_knowledge[\"is_marketplace\"] = False\n    return user_knowledge_list\n\n@router.get(\"/marketplace/get/details/{knowledge_name}\")\ndef get_knowledge_details(knowledge_name: str):\n    knowledge_data = Knowledges.fetch_knowledge_details_marketplace(knowledge_name)\n    knowledge_config_data = KnowledgeConfigs.fetch_knowledge_config_details_marketplace(knowledge_data[\"id\"])\n    knowledge_data_with_config = knowledge_data | knowledge_config_data\n    knowledge_data_with_config[\"install_number\"] = MarketPlaceStats.get_knowledge_installation_number(knowledge_data_with_config[\"id\"])\n    update_time = str(knowledge_data_with_config[\"updated_at\"])\n    update_time = datetime.strptime(update_time, \"%Y-%m-%dT%H:%M:%S.%f\")\n    knowledge_data_with_config[\"updated_at\"] = datetime.strftime(update_time, '%d %B %Y')\n    return knowledge_data_with_config\n\n@router.get(\"/marketplace/details/{knowledge_name}\")\ndef get_marketplace_knowledge_details(knowledge_name: str):\n    organisation_id = int(get_config(\"MARKETPLACE_ORGANISATION_ID\"))\n    knowledge_details = db.session.query(Knowledges).filter(Knowledges.name == knowledge_name, Knowledges.organisation_id == organisation_id).first()\n    return knowledge_details\n\n@router.get(\"/user/get/details/{knowledge_id}\")\ndef get_user_knowledge_details(knowledge_id: int):\n    knowledge_data = Knowledges.get_knowledge_from_id(db.session, knowledge_id)\n    vector_database_index = VectordbIndices.get_vector_index_from_id(db.session, knowledge_data.vector_db_index_id)\n    vector_database = Vectordbs.get_vector_db_from_id(db.session, vector_database_index.vector_db_id)\n    knowledge = {\n        \"name\": knowledge_data.name,\n        \"description\": knowledge_data.description,\n        \"vector_database_index\": {\n            \"id\": vector_database_index.id,\n            \"name\": vector_database_index.name\n        },\n        \"vector_database\": vector_database.name,\n        \"installation_type\": vector_database_index.state\n    }\n    knowledge_config = KnowledgeConfigs.get_knowledge_config_from_knowledge_id(db.session, knowledge_id)\n    knowledge_data_with_config = knowledge | knowledge_config\n    return knowledge_data_with_config\n\n@router.post(\"/add_or_update/data\")\ndef add_update_user_knowledge(knowledge_data: dict, organisation = Depends(get_user_organisation)):\n    knowledge_data[\"organisation_id\"] = organisation.id\n    knowledge_data[\"contributed_by\"] = organisation.name\n    knowledge = Knowledges.add_update_knowledge(db.session, knowledge_data)\n    if not knowledge:\n        raise HTTPException(status_code=404, detail=\"Knowledge not found\")\n    return {\"id\": knowledge.id}\n\n\n@router.post(\"/delete/{knowledge_id}\")\ndef delete_user_knowledge(knowledge_id: int):\n    try:\n        Knowledges.delete_knowledge(db.session, knowledge_id)\n    except:\n        raise HTTPException(status_code=404, detail=\"Knowledge not found\")\n\n@router.get(\"/install/{knowledge_name}/index/{vector_db_index_id}\")\ndef install_selected_knowledge(knowledge_name: str, vector_db_index_id: int, organisation = Depends(get_user_organisation)):\n    vector_db_index = VectordbIndices.get_vector_index_from_id(db.session, vector_db_index_id)\n    selected_knowledge = Knowledges.fetch_knowledge_details_marketplace(knowledge_name)\n    selected_knowledge_config = KnowledgeConfigs.fetch_knowledge_config_details_marketplace(selected_knowledge['id'])\n    file_chunks = S3Helper().get_json_file(selected_knowledge_config[\"file_path\"])\n    vector = Vectordbs.get_vector_db_from_id(db.session, vector_db_index.vector_db_id)\n    db_creds = VectordbConfigs.get_vector_db_config_from_db_id(db.session, vector.id)\n    upsert_data = VectorEmbeddingFactory.build_vector_storage(vector.db_type, file_chunks).get_vector_embeddings_from_chunks()\n    try:\n        vector_db_storage = VectorFactory.build_vector_storage(vector.db_type, vector_db_index.name, **db_creds)\n        vector_db_storage.add_embeddings_to_vector_db(upsert_data)\n    except Exception as err:\n        raise HTTPException(status_code=400, detail=err)\n    selected_knowledge_data = {\n        \"id\": -1,\n        \"name\": selected_knowledge[\"name\"],\n        \"description\": selected_knowledge[\"description\"],\n        \"index_id\": vector_db_index_id,\n        \"organisation_id\": organisation.id,\n        \"contributed_by\": selected_knowledge[\"contributed_by\"],\n    }\n    new_knowledge = Knowledges.add_update_knowledge(db.session, selected_knowledge_data)\n    removable_key = 'file_path'\n    selected_knowledge_config.pop(removable_key)\n    configs = selected_knowledge_config\n    KnowledgeConfigs.add_update_knowledge_config(db.session, new_knowledge.id, configs)\n    VectordbIndices.update_vector_index_state(db.session, vector_db_index_id, \"Marketplace\")\n    install_number = MarketPlaceStats.get_knowledge_installation_number(selected_knowledge[\"id\"])\n    MarketPlaceStats.update_knowledge_install_number(db.session, selected_knowledge[\"id\"], int(install_number) + 1)\n\n@router.post(\"/uninstall/{knowledge_name}\")\ndef uninstall_selected_knowledge(knowledge_name: str, organisation = Depends(get_user_organisation)):\n    knowledge = db.session.query(Knowledges).filter(Knowledges.name == knowledge_name, Knowledges.organisation_id == organisation.id).first()\n    knowledge_config = KnowledgeConfigs.get_knowledge_config_from_knowledge_id(db.session, knowledge.id)\n    vector_ids = eval(knowledge_config[\"vector_ids\"])\n    vector_db_index = VectordbIndices.get_vector_index_from_id(db.session, knowledge.vector_db_index_id)\n    vector = Vectordbs.get_vector_db_from_id(db.session, vector_db_index.vector_db_id)\n    db_creds = VectordbConfigs.get_vector_db_config_from_db_id(db.session, vector.id)\n    try:\n        vector_db_storage = VectorFactory.build_vector_storage(vector.db_type, vector_db_index.name, **db_creds)\n        vector_db_storage.delete_embeddings_from_vector_db(vector_ids)\n    except Exception as err:\n        raise HTTPException(status_code=400, detail=err)\n    KnowledgeConfigs.delete_knowledge_config(db.session, knowledge.id)\n    Knowledges.delete_knowledge(db.session, knowledge.id)"
  },
  {
    "path": "superagi/controllers/marketplace_stats.py",
    "content": "from fastapi_sqlalchemy import db\nfrom fastapi import HTTPException, Depends, Query, status\nfrom fastapi import APIRouter\nfrom superagi.config.config import get_config\nfrom superagi.models.marketplace_stats import MarketPlaceStats\nfrom superagi.models.vector_dbs import Vectordbs\n\nrouter = APIRouter()\n\n@router.get(\"/knowledge/downloads/{knowledge_id}\")\ndef count_knowledge_downloads(knowledge_id: int):\n    download_number = db.session.query(MarketPlaceStats).filter(MarketPlaceStats.reference_id == knowledge_id, MarketPlaceStats.reference_name == \"KNOWLEDGE\", MarketPlaceStats.key == \"download_count\").first()\n    if download_number is None:\n        downloads = 0\n    else:\n        downloads = download_number.value\n    return downloads"
  },
  {
    "path": "superagi/controllers/models_controller.py",
    "content": "from typing import Optional\nfrom fastapi import APIRouter, Depends, HTTPException, Query, Body\nfrom superagi.helper.auth import check_auth, get_user_organisation\nfrom superagi.helper.models_helper import ModelsHelper\nfrom superagi.apm.call_log_helper import CallLogHelper\nfrom superagi.lib.logger import logger\nfrom superagi.models.models import Models\nfrom superagi.models.models_config import ModelsConfig\nfrom superagi.config.config import get_config\nfrom superagi.controllers.types.models_types import ModelsTypes\nfrom fastapi_sqlalchemy import db\nimport logging\nfrom pydantic import BaseModel\nfrom superagi.helper.llm_loader import LLMLoader\n\nrouter = APIRouter()\n\n\nclass ValidateAPIKeyRequest(BaseModel):\n    model_provider: str\n    model_api_key: str\n\n\nclass StoreModelRequest(BaseModel):\n    model_name: str\n    description: str\n    end_point: str\n    model_provider_id: int\n    token_limit: int\n    type: str\n    version: str\n    context_length: Optional[int]\n\nclass ModelName (BaseModel):\n    model: str\n\n@router.post(\"/store_api_keys\", status_code=200)\nasync def store_api_keys(request: ValidateAPIKeyRequest, organisation=Depends(get_user_organisation)):\n    try:\n        return ModelsConfig.store_api_key(db.session, organisation.id, request.model_provider, request.model_api_key)\n    except Exception as e:\n        logging.error(f\"Error while storing API key: {str(e)}\")\n        raise HTTPException(status_code=500, detail=\"Internal Server Error\")\n\n\n@router.get(\"/get_api_keys\")\nasync def get_api_keys(organisation=Depends(get_user_organisation)):\n    try:\n        return ModelsConfig.fetch_api_keys(db.session, organisation.id)\n    except Exception as e:\n        logging.error(f\"Error while retrieving API Keys: {str(e)}\")\n        raise HTTPException(status_code=500, detail=\"Internal Server Error\")\n\n\n@router.get(\"/get_api_key\", status_code=200)\nasync def get_api_key(model_provider: str = None, organisation=Depends(get_user_organisation)):\n    try:\n        return ModelsConfig.fetch_api_key(db.session, organisation.id, model_provider)\n    except Exception as e:\n        logging.error(f\"Error while retrieving API Key: {str(e)}\")\n        raise HTTPException(status_code=500, detail=\"Internal Server Error\")\n\n\n@router.get(\"/verify_end_point\", status_code=200)\nasync def verify_end_point(model_api_key: str = None, end_point: str = None, model_provider: str = None):\n    try:\n        return ModelsHelper.validate_end_point(model_api_key, end_point, model_provider)\n    except Exception as e:\n        logging.error(f\"Error validating Endpoint: {str(e)}\")\n        raise HTTPException(status_code=500, detail=\"Internal Server Error\")\n\n\n@router.post(\"/store_model\", status_code=200)\nasync def store_model(request: StoreModelRequest, organisation=Depends(get_user_organisation)):\n    try:\n        #context_length = 4096\n        logger.info(request)\n        if 'context_length' in request.dict():\n            return Models.store_model_details(db.session, organisation.id, request.model_name, request.description, request.end_point, request.model_provider_id, request.token_limit, request.type, request.version, request.context_length)\n        else:\n            return Models.store_model_details(db.session, organisation.id, request.model_name, request.description, request.end_point, request.model_provider_id, request.token_limit, request.type, request.version, 0)\n    except Exception as e:\n        logging.error(f\"Error storing the Model Details: {str(e)}\")\n        raise HTTPException(status_code=500, detail=\"Internal Server Error\")\n\n\n@router.get(\"/fetch_models\", status_code=200)\nasync def fetch_models(organisation=Depends(get_user_organisation)):\n    try:\n        return Models.fetch_models(db.session, organisation.id,)\n    except Exception as e:\n        logging.error(f\"Error Fetching Models: {str(e)}\")\n        raise HTTPException(status_code=500, detail=\"Internal Server Error\")\n\n\n@router.get(\"/fetch_model/{model_id}\", status_code=200)\nasync def fetch_model_details(model_id: int, organisation=Depends(get_user_organisation)):\n    try:\n        return Models.fetch_model_details(db.session, organisation.id, model_id)\n    except Exception as e:\n        logging.error(f\"Error Fetching Model Details: {str(e)}\")\n        raise HTTPException(status_code=500, detail=\"Internal Server Error\")\n\n\n@router.post(\"/fetch_model_data\", status_code=200)\nasync def fetch_data(request: ModelName, organisation=Depends(get_user_organisation)):\n    try:\n        return CallLogHelper(session=db.session, organisation_id=organisation.id).fetch_data(request.model)\n    except Exception as e:\n        logging.error(f\"Error Fetching Model Details: {str(e)}\")\n        raise HTTPException(status_code=500, detail=\"Internal Server Error\")\n\n\n@router.get(\"/get/list\", status_code=200)\ndef get_models_list(page: int = 0, organisation=Depends(get_user_organisation)):\n    \"\"\"\n    Get Marketplace Model list.\n\n    Args:\n        page (int, optional): The page number for pagination. Defaults to None.\n\n    Returns:\n        dict: The response containing the marketplace list.\n\n    \"\"\"\n    if page < 0:\n        page = 0\n    marketplace_models = Models.fetch_marketplace_list(page)\n    marketplace_models_with_install = Models.get_model_install_details(db.session, marketplace_models, organisation.id)\n    return marketplace_models_with_install\n\n\n@router.get(\"/marketplace/list/{page}\", status_code=200)\ndef get_marketplace_models_list(page: int = 0):\n    organisation_id = get_config(\"MARKETPLACE_ORGANISATION_ID\")\n    if organisation_id is not None:\n        organisation_id = int(organisation_id)\n    page_size = 16\n\n    query = db.session.query(Models).filter(Models.org_id == organisation_id)\n    if page < 0:\n        models = query.all()\n    else:\n        models = query.offset(page * page_size).limit(page_size).all()\n\n    models_list = []\n    for model in models:\n        model_dict = model.__dict__\n        model_dict[\"provider\"] = db.session.query(ModelsConfig).filter(ModelsConfig.id == model.model_provider_id).first().provider\n        models_list.append(model_dict)\n\n    return models_list\n\n\n@router.get(\"/get/models_details\", status_code=200)\ndef get_models_details(page: int = 0):\n    \"\"\"\n        Get Marketplace Model list.\n\n        Args:\n            page (int, optional): The page number for pagination. Defaults to None.\n\n        Returns:\n            dict: The response containing the marketplace list.\n\n        \"\"\"\n    organisation_id = get_config(\"MARKETPLACE_ORGANISATION_ID\")\n    if organisation_id is not None:\n        organisation_id = int(organisation_id)\n\n    if page < 0:\n        page = 0\n    marketplace_models = Models.fetch_marketplace_list(page)\n    marketplace_models_with_install = Models.get_model_install_details(db.session, marketplace_models, organisation_id,\n                                                                       ModelsTypes.MARKETPLACE.value)\n    return marketplace_models_with_install\n\n@router.get(\"/test_local_llm\", status_code=200)\ndef test_local_llm():\n    try:\n        llm_loader = LLMLoader(context_length=4096)\n        llm_model = llm_loader.model\n        llm_grammar = llm_loader.grammar\n        if llm_model is None:\n            logger.error(\"Model not found.\")\n            raise HTTPException(status_code=404, detail=\"Error while loading the model. Please check your model path and try again.\")\n        if llm_grammar is None:\n            logger.error(\"Grammar not found.\")\n            raise HTTPException(status_code=404, detail=\"Grammar not found.\")\n\n        messages = [\n            {\"role\":\"system\",\n             \"content\":\"You are an AI assistant. Give response in a proper JSON format\"},\n             {\"role\":\"user\",\n             \"content\":\"Hi!\"}\n        ]\n        response = llm_model.create_chat_completion(messages=messages, grammar=llm_grammar)\n        content = response[\"choices\"][0][\"message\"][\"content\"]\n        logger.info(content)\n        return \"Model loaded successfully.\"\n        \n    except Exception as e:\n        logger.info(\"Error: \",e)\n        raise HTTPException(status_code=404, detail=\"Error while loading the model. Please check your model path and try again.\")"
  },
  {
    "path": "superagi/controllers/organisation.py",
    "content": "from datetime import datetime\n\nfrom fastapi import APIRouter\nfrom fastapi import HTTPException, Depends\nfrom fastapi_jwt_auth import AuthJWT\nfrom fastapi_sqlalchemy import db\nfrom pydantic import BaseModel\n\nfrom superagi.helper.auth import get_user_organisation\nfrom superagi.helper.auth import check_auth\nfrom superagi.helper.encyption_helper import decrypt_data\nfrom superagi.helper.tool_helper import register_toolkits\nfrom superagi.llms.google_palm import GooglePalm\nfrom superagi.llms.llm_model_factory import build_model_with_api_key\nfrom superagi.llms.openai import OpenAi\nfrom superagi.models.configuration import Configuration\nfrom superagi.models.organisation import Organisation\nfrom superagi.models.project import Project\nfrom superagi.models.user import User\nfrom superagi.lib.logger import logger\nfrom superagi.models.workflows.agent_workflow import AgentWorkflow\n\n# from superagi.types.db import OrganisationIn, OrganisationOut\n\nrouter = APIRouter()\n\n\nclass OrganisationOut(BaseModel):\n    id: int\n    name: str\n    description: str\n    created_at: datetime\n    updated_at: datetime\n\n    class Config:\n        orm_mode = True\n\n\nclass OrganisationIn(BaseModel):\n    name: str\n    description: str\n\n    class Config:\n        orm_mode = True\n\n\n# CRUD Operations\n@router.post(\"/add\", response_model=OrganisationOut, status_code=201)\ndef create_organisation(organisation: OrganisationIn,\n                        Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Create a new organisation.\n\n    Args:\n        organisation: Organisation data.\n\n    Returns:\n        dict: Dictionary containing the created organisation.\n\n    Raises:\n        HTTPException (status_code=400): If there is an issue creating the organisation.\n\n    \"\"\"\n\n    new_organisation = Organisation(\n        name=organisation.name,\n        description=organisation.description,\n    )\n    db.session.add(new_organisation)\n    db.session.commit()\n    db.session.flush()\n    register_toolkits(session=db.session, organisation=new_organisation)\n    logger.info(new_organisation)\n\n    return new_organisation\n\n\n@router.get(\"/get/{organisation_id}\", response_model=OrganisationOut)\ndef get_organisation(organisation_id: int, Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Get organisation details by organisation_id.\n\n    Args:\n        organisation_id: ID of the organisation.\n\n    Returns:\n        dict: Dictionary containing the organisation details.\n\n    Raises:\n        HTTPException (status_code=404): If the organisation with the specified ID is not found.\n\n    \"\"\"\n\n    db_organisation = db.session.query(Organisation).filter(Organisation.id == organisation_id).first()\n    if not db_organisation:\n        raise HTTPException(status_code=404, detail=\"organisation not found\")\n    return db_organisation\n\n\n@router.put(\"/update/{organisation_id}\", response_model=OrganisationOut)\ndef update_organisation(organisation_id: int, organisation: OrganisationIn,\n                        Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Update organisation details by organisation_id.\n\n    Args:\n        organisation_id: ID of the organisation.\n        organisation: Updated organisation data.\n\n    Returns:\n        dict: Dictionary containing the updated organisation details.\n\n    Raises:\n        HTTPException (status_code=404): If the organisation with the specified ID is not found.\n\n    \"\"\"\n\n    db_organisation = db.session.query(Organisation).filter(Organisation.id == organisation_id).first()\n    if not db_organisation:\n        raise HTTPException(status_code=404, detail=\"Organisation not found\")\n\n    db_organisation.name = organisation.name\n    db_organisation.description = organisation.description\n    db.session.commit()\n\n    return db_organisation\n\n\n@router.get(\"/get/user/{user_id}\", response_model=OrganisationOut, status_code=201)\ndef get_organisations_by_user(user_id: int):\n    \"\"\"\n    Get organisations associated with a user.If Organisation does not exists a new organisation is created\n\n    Args:\n        user_id: ID of the user.\n\n    Returns:\n        dict: Dictionary containing the organisation details.\n\n    Raises:\n        HTTPException (status_code=400): If the user with the specified ID is not found.\n\n    \"\"\"\n\n    user = db.session.query(User).filter(User.id == user_id).first()\n    if user is None:\n        raise HTTPException(status_code=400,\n                            detail=\"User not found\")\n\n    organisation = Organisation.find_or_create_organisation(db.session, user)\n    Project.find_or_create_default_project(db.session, organisation.id)\n    return organisation\n\n\n@router.get(\"/llm_models\")\ndef get_llm_models(organisation=Depends(get_user_organisation)):\n    \"\"\"\n    Get all the llm models associated with an organisation.\n\n    Args:\n        organisation: Organisation data.\n    \"\"\"\n\n    model_api_key = db.session.query(Configuration).filter(Configuration.organisation_id == organisation.id,\n                                                           Configuration.key == \"model_api_key\").first()\n    model_source = db.session.query(Configuration).filter(Configuration.organisation_id == organisation.id,\n                                                          Configuration.key == \"model_source\").first()\n\n    if model_api_key is None or model_source is None:\n        raise HTTPException(status_code=400,\n                            detail=\"Organisation not found\")\n\n    decrypted_api_key = decrypt_data(model_api_key.value)\n    model = build_model_with_api_key(model_source.value, decrypted_api_key)\n    models = model.get_models() if model is not None else []\n\n    return models\n\n\n@router.get(\"/agent_workflows\")\ndef agent_workflows(organisation=Depends(get_user_organisation)):\n    \"\"\"\n    Get all the agent workflows\n\n    Args:\n        organisation: Organisation data.\n    \"\"\"\n\n    agent_workflows = db.session.query(AgentWorkflow).all()\n    workflows = [workflow.name for workflow in agent_workflows]\n\n    return workflows\n\n\n"
  },
  {
    "path": "superagi/controllers/project.py",
    "content": "from fastapi_sqlalchemy import db\nfrom fastapi import HTTPException, Depends\nfrom fastapi_jwt_auth import AuthJWT\nfrom pydantic import BaseModel\n\nfrom superagi.models.project import Project\nfrom superagi.models.organisation import Organisation\nfrom fastapi import APIRouter\nfrom superagi.helper.auth import check_auth\nfrom superagi.lib.logger import logger\n# from superagi.types.db import ProjectIn, ProjectOut\n\nrouter = APIRouter()\n\n\nclass ProjectOut(BaseModel):\n    id: int\n    name: str\n    organisation_id: int\n    description: str\n\n    class Config:\n        orm_mode = True\n\n\nclass ProjectIn(BaseModel):\n    name: str\n    organisation_id: int\n    description: str\n\n    class Config:\n        orm_mode = True\n\n# CRUD Operations\n@router.post(\"/add\", response_model=ProjectOut, status_code=201)\ndef create_project(project: ProjectIn,\n                   Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Create a new project.\n\n    Args:\n        project (Project): Project data.\n\n    Returns:\n        dict: Dictionary containing the created project.\n\n    Raises:\n        HTTPException (status_code=404): If the organization with the specified ID is not found.\n\n    \"\"\"\n\n    logger.info(\"Organisation_id : \", project.organisation_id)\n    organisation = db.session.query(Organisation).get(project.organisation_id)\n\n    if not organisation:\n        raise HTTPException(status_code=404, detail=\"Organisation not found\")\n\n    project = Project(\n        name=project.name,\n        organisation_id=organisation.id,\n        description=project.description\n    )\n\n    db.session.add(project)\n    db.session.commit()\n\n    return project\n\n\n@router.get(\"/get/{project_id}\", response_model=ProjectOut)\ndef get_project(project_id: int, Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Get project details by project_id.\n\n    Args:\n        project_id (int): ID of the project.\n\n    Returns:\n        dict: Dictionary containing the project details.\n\n    Raises:\n        HTTPException (status_code=404): If the project with the specified ID is not found.\n\n    \"\"\"\n\n    db_project = db.session.query(Project).filter(Project.id == project_id).first()\n    if not db_project:\n        raise HTTPException(status_code=404, detail=\"project not found\")\n    return db_project\n\n\n@router.put(\"/update/{project_id}\", response_model=ProjectOut)\ndef update_project(project_id: int, project: ProjectIn,\n                   Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Update a project detail by project_id.\n\n    Args:\n        project_id (int): ID of the project.\n        project (Project): Updated project data.\n\n    Returns:\n        dict: Dictionary containing the updated project details.\n\n    Raises:\n        HTTPException (status_code=404): If the project with the specified ID is not found.\n        HTTPException (status_code=404): If the organization with the specified ID is not found.\n\n    \"\"\"\n\n    db_project = db.session.query(Project).get(project_id)\n    if not db_project:\n        raise HTTPException(status_code=404, detail=\"Project not found\")\n\n    if project.organisation_id:\n        organisation = db.session.query(Organisation).get(project.organisation_id)\n        if not organisation:\n            raise HTTPException(status_code=404, detail=\"Organisation not found\")\n        db_project.organisation_id = organisation.id\n    db_project.name = project.name\n    db_project.description = project.description\n    db.session.add(db_project)\n    db.session.commit()\n    return db_project\n\n\n@router.get(\"/get/organisation/{organisation_id}\")\ndef get_projects_organisation(organisation_id: int,\n                              Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Get all projects by organisation_id and create default if no project.\n\n    Args:\n        organisation_id (int): ID of the organisation.\n\n    Returns:\n        List[Project]: List of projects belonging to the organisation.\n\n    Raises:\n        HTTPException (status_code=404): If the organization with the specified ID is not found.\n\n    \"\"\"\n\n    Project.find_or_create_default_project(db.session, organisation_id)\n    projects = db.session.query(Project).filter(Project.organisation_id == organisation_id).all()\n    if len(projects) <= 0:\n        default_project = Project.find_or_create_default_project(db.session, organisation_id)\n        projects.append(default_project)\n\n    return projects\n"
  },
  {
    "path": "superagi/controllers/resources.py",
    "content": "import datetime\nimport os\nfrom pathlib import Path\n\nimport boto3\nfrom botocore.exceptions import NoCredentialsError\nfrom fastapi import APIRouter\nfrom fastapi import File, Form, UploadFile\nfrom fastapi import HTTPException, Depends\nfrom fastapi.responses import StreamingResponse\nfrom fastapi_jwt_auth import AuthJWT\nfrom fastapi_sqlalchemy import db\n\nfrom superagi.config.config import get_config\nfrom superagi.helper.auth import check_auth\nfrom superagi.helper.resource_helper import ResourceHelper\nfrom superagi.lib.logger import logger\nfrom superagi.models.agent import Agent\nfrom superagi.models.resource import Resource\nfrom superagi.worker import summarize_resource\nfrom superagi.types.storage_types import StorageType\n\nrouter = APIRouter()\n\ns3 = boto3.client(\n    's3',\n    aws_access_key_id=get_config(\"AWS_ACCESS_KEY_ID\"),\n    aws_secret_access_key=get_config(\"AWS_SECRET_ACCESS_KEY\"),\n)\n\n\n@router.post(\"/add/{agent_id}\", status_code=201)\nasync def upload(agent_id: int, file: UploadFile = File(...), name=Form(...), size=Form(...), type=Form(...),\n                 Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Upload a file as a resource for an agent.\n\n    Args:\n        agent_id (int): ID of the agent.\n        file (UploadFile): Uploaded file.\n        name (str): Name of the resource.\n        size (str): Size of the resource.\n        type (str): Type of the resource.\n\n    Returns:\n        Resource: Uploaded resource.\n\n    Raises:\n        HTTPException (status_code=400): If the agent with the specified ID does not exist.\n        HTTPException (status_code=400): If the file type is not supported.\n        HTTPException (status_code=500): If AWS credentials are not found or if there is an issue uploading to S3.\n\n    \"\"\"\n\n    agent = db.session.query(Agent).filter(Agent.id == agent_id).first()\n    if agent is None:\n        raise HTTPException(status_code=400, detail=\"Agent does not exists\")\n\n    # accepted_file_types is a tuple because endswith() expects a tuple\n    accepted_file_types = (\".pdf\", \".docx\", \".pptx\", \".csv\", \".txt\", \".epub\")\n    if not name.endswith(accepted_file_types):\n        raise HTTPException(status_code=400, detail=\"File type not supported!\")\n\n    storage_type = StorageType.get_storage_type(get_config(\"STORAGE_TYPE\", StorageType.FILE.value))\n    save_directory = ResourceHelper.get_root_input_dir()\n    if \"{agent_id}\" in save_directory:\n        save_directory = ResourceHelper.get_formatted_agent_level_path(agent=Agent\n                                                                       .get_agent_from_id(session=db.session,\n                                                                                    agent_id=agent_id),\n                                                                       path=save_directory)\n    file_path = os.path.join(save_directory, file.filename)\n    if storage_type == StorageType.FILE:\n        os.makedirs(save_directory, exist_ok=True)\n        with open(file_path, \"wb\") as f:\n            contents = await file.read()\n            f.write(contents)\n            file.file.close()\n    elif storage_type == StorageType.S3:\n        bucket_name = get_config(\"BUCKET_NAME\")\n        file_path = 'resources' + file_path\n        try:\n            s3.upload_fileobj(file.file, bucket_name, file_path)\n            logger.info(\"File uploaded successfully!\")\n        except NoCredentialsError:\n            raise HTTPException(status_code=500, detail=\"AWS credentials not found. Check your configuration.\")\n\n    resource = Resource(name=name, path=file_path, storage_type=storage_type.value, size=size, type=type, channel=\"INPUT\",\n                        agent_id=agent.id)\n\n    db.session.add(resource)\n    db.session.commit()\n    db.session.flush()\n\n    summarize_resource.delay(agent_id, resource.id)\n    logger.info(resource)\n\n    return resource\n\n\n@router.get(\"/get/all/{agent_id}\", status_code=200)\ndef get_all_resources(agent_id: int,\n                      Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Get all resources for an agent.\n\n    Args:\n        agent_id (int): ID of the agent.\n\n    Returns:\n        List[Resource]: List of resources belonging to the agent.\n\n    \"\"\"\n\n    resources = db.session.query(Resource).filter(Resource.agent_id == agent_id).all()\n    return resources\n\n\n@router.get(\"/get/{resource_id}\", status_code=200)\ndef download_file_by_id(resource_id: int,\n                        Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Download a particular resource by resource_id.\n\n    Args:\n        resource_id (int): ID of the resource.\n        Authorize (AuthJWT, optional): Authorization dependency.\n\n    Returns:\n        StreamingResponse: Streaming response for downloading the resource.\n\n    Raises:\n        HTTPException (status_code=400): If the resource with the specified ID is not found.\n        HTTPException (status_code=403): If the user doesn't have permission to access this resource.\n        HTTPException (status_code=404): If the file is not found.\n\n    \"\"\"\n    # Get current user's organization_id from JWT token\n    current_user_org_id = Authorize.get_jwt_subject()\n\n    # First check if resource exists\n    resource = db.session.query(Resource).filter(Resource.id == resource_id).first()\n    if not resource:\n        raise HTTPException(status_code=400, detail=\"Resource Not found!\")\n\n    # Get the agent that owns this resource\n    agent = db.session.query(Agent).filter(Agent.id == resource.agent_id).first()\n    if not agent:\n        raise HTTPException(status_code=400, detail=\"Associated agent not found!\")\n\n    # Verify the authenticated user belongs to the same organization as the agent\n    if str(agent.organisation_id) != str(current_user_org_id):\n        raise HTTPException(status_code=403, detail=\"You don't have permission to access this resource\")\n\n    download_file_path = resource.path\n    file_name = resource.name\n\n    if resource.storage_type == StorageType.S3.value:\n        bucket_name = get_config(\"BUCKET_NAME\")\n        file_key = resource.path\n        response = s3.get_object(Bucket=bucket_name, Key=file_key)\n        content = response[\"Body\"]\n    else:\n        abs_file_path = Path(download_file_path).resolve()\n        if not abs_file_path.is_file():\n            raise HTTPException(status_code=404, detail=\"File not found\")\n        content = open(str(abs_file_path), \"rb\")\n\n    return StreamingResponse(\n        content,\n        media_type=\"application/octet-stream\",\n        headers={\n            \"Content-Disposition\": f\"attachment; filename={file_name}\"\n        }\n    )\n"
  },
  {
    "path": "superagi/controllers/tool.py",
    "content": "from datetime import datetime\n\nfrom fastapi import APIRouter\nfrom fastapi import HTTPException, Depends\nfrom fastapi_jwt_auth import AuthJWT\nfrom fastapi_sqlalchemy import db\nfrom pydantic import BaseModel\n\nfrom superagi.helper.auth import check_auth, get_user_organisation\nfrom superagi.models.organisation import Organisation\nfrom superagi.models.tool import Tool\nfrom superagi.models.toolkit import Toolkit\n\nrouter = APIRouter()\n\n\nclass ToolOut(BaseModel):\n    id: int\n    name: str\n    folder_name: str\n    class_name: str\n    file_name: str\n    created_at: datetime\n    updated_at: datetime\n\n    class Config:\n        orm_mode = True\n\n\nclass ToolIn(BaseModel):\n    name: str\n    folder_name: str\n    class_name: str\n    file_name: str\n\n    class Config:\n        orm_mode = True\n\n# CRUD Operations\n@router.post(\"/add\", response_model=ToolOut, status_code=201)\ndef create_tool(\n        tool: ToolIn,\n        Authorize: AuthJWT = Depends(check_auth),\n):\n    \"\"\"\n    Create a new tool.\n\n    Args:\n        tool (ToolIn): Tool data.\n\n    Returns:\n        Tool: The created tool.\n\n    Raises:\n        HTTPException (status_code=400): If there is an issue creating the tool.\n\n    \"\"\"\n\n    db_tool = Tool(\n        name=tool.name,\n        folder_name=tool.folder_name,\n        class_name=tool.class_name,\n        file_name=tool.file_name,\n    )\n    db.session.add(db_tool)\n    db.session.commit()\n    return db_tool\n\n\n@router.get(\"/get/{tool_id}\", response_model=ToolOut)\ndef get_tool(\n        tool_id: int,\n        Authorize: AuthJWT = Depends(check_auth),\n):\n    \"\"\"\n    Get a particular tool details.\n\n    Args:\n        tool_id (int): ID of the tool.\n\n    Returns:\n        Tool: The tool details.\n\n    Raises:\n        HTTPException (status_code=404): If the tool with the specified ID is not found.\n\n    \"\"\"\n\n    db_tool = db.session.query(Tool).filter(Tool.id == tool_id).first()\n    if not db_tool:\n        raise HTTPException(status_code=404, detail=\"Tool not found\")\n    return db_tool\n\n\n@router.get(\"/list\")\ndef get_tools(\n        organisation: Organisation = Depends(get_user_organisation)):\n    \"\"\"Get all tools\"\"\"\n    toolkits = db.session.query(Toolkit).filter(Toolkit.organisation_id == organisation.id).all()\n    tools = []\n    for toolkit in toolkits:\n        db_tools = db.session.query(Tool).filter(Tool.toolkit_id == toolkit.id).all()\n        tools.extend(db_tools)\n    return tools\n\n\n@router.put(\"/update/{tool_id}\", response_model=ToolOut)\ndef update_tool(\n        tool_id: int,\n        tool: ToolIn,\n        Authorize: AuthJWT = Depends(check_auth),\n):\n    \"\"\"\n    Update a particular tool.\n\n    Args:\n        tool_id (int): ID of the tool.\n        tool (ToolIn): Updated tool data.\n\n    Returns:\n        Tool: The updated tool details.\n\n    Raises:\n        HTTPException (status_code=404): If the tool with the specified ID is not found.\n\n    \"\"\"\n\n    db_tool = db.session.query(Tool).filter(Tool.id == tool_id).first()\n    if not db_tool:\n        raise HTTPException(status_code=404, detail=\"Tool not found\")\n\n    db_tool.name = tool.name\n    db_tool.folder_name = tool.folder_name\n    db_tool.class_name = tool.class_name\n    db_tool.file_name = tool.file_name\n\n    db.session.add(db_tool)\n    db.session.commit()\n    return db_tool\n"
  },
  {
    "path": "superagi/controllers/tool_config.py",
    "content": "from fastapi import APIRouter, HTTPException, Depends\nfrom fastapi_jwt_auth import AuthJWT\nfrom fastapi_sqlalchemy import db\nfrom pydantic import BaseModel\n\nfrom superagi.helper.auth import check_auth\nfrom superagi.helper.auth import get_user_organisation\nfrom superagi.models.organisation import Organisation\nfrom superagi.models.tool_config import ToolConfig\nfrom superagi.models.toolkit import Toolkit\nfrom superagi.helper.encyption_helper import encrypt_data\nfrom superagi.helper.encyption_helper import decrypt_data, is_encrypted\nfrom superagi.types.key_type import ToolConfigKeyType\nimport json\n\nrouter = APIRouter()\n\nclass ToolConfigOut(BaseModel):\n    id = int\n    key = str\n    value = str\n    toolkit_id = int\n\n    class Config:\n        orm_mode = True\n\n@router.post(\"/add/{toolkit_name}\", status_code=201)\ndef update_tool_config(toolkit_name: str, configs: list, organisation: Organisation = Depends(get_user_organisation)):\n    \"\"\"\n    Update tool configurations for a specific tool kit.\n\n    Args:\n        toolkit_name (str): The name of the tool kit.\n        configs (list): A list of dictionaries containing the tool configurations.\n            Each dictionary should have the following keys:\n            - \"key\" (str): The key of the configuration.\n            - \"value\" (str): The new value for the configuration.\n\n    Returns:\n        dict: A dictionary with the message \"Tool configs updated successfully\".\n\n    Raises:\n        HTTPException (status_code=404): If the specified tool kit is not found.\n        HTTPException (status_code=500): If an unexpected error occurs during the update process.\n    \"\"\"\n\n    try:\n        # Check if the tool kit exists\n        toolkit = Toolkit.get_toolkit_from_name(db.session, toolkit_name,organisation)\n        if toolkit is None:\n            raise HTTPException(status_code=404, detail=\"Tool kit not found\")\n\n        # Update existing tool configs\n        for config in configs:\n            key = config.get(\"key\")\n            value = config.get(\"value\")\n            if value is None: \n                continue\n            if key is not None:\n                tool_config = db.session.query(ToolConfig).filter_by(toolkit_id=toolkit.id, key=key).first()\n                if tool_config:\n                    if tool_config.key_type ==  ToolConfigKeyType.FILE.value:\n                        value = json.dumps(value)\n                    # Update existing tool config\n                    # added encryption\n                    tool_config.value = encrypt_data(value)\n                    db.session.commit()\n\n        return {\"message\": \"Tool configs updated successfully\"}\n\n    except Exception as e:\n        # db.session.rollback()\n        raise HTTPException(status_code=500, detail=str(e))\n\n\n@router.post(\"/create-or-update/{toolkit_name}\", status_code=201, response_model=ToolConfigOut)\ndef create_or_update_tool_config(toolkit_name: str, tool_configs,\n                                 Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Create or update tool configurations for a specific tool kit.\n\n    Args:\n        toolkit_name (str): The name of the tool kit.\n        tool_configs (list): A list of tool configuration objects.\n\n    Returns:\n        Toolkit: The updated tool kit object.\n\n    Raises:\n        HTTPException (status_code=404): If the specified tool kit is not found.\n    \"\"\"\n    toolkit = db.session.query(Toolkit).filter_by(name=toolkit_name).first()\n    if not toolkit:\n        raise HTTPException(status_code=404, detail='ToolKit not found')\n\n    # Iterate over the tool_configs list\n    for tool_config in tool_configs:\n        existing_tool_config = db.session.query(ToolConfig).filter(\n            ToolConfig.toolkit_id == toolkit.id,\n            ToolConfig.key == tool_config.key\n        ).first()\n\n        if existing_tool_config.value:\n            # Update the existing tool config\n            if existing_tool_config.key_type == ToolConfigKeyType.FILE.value:\n                existing_tool_config.value = json.dumps(existing_tool_config.value)\n            existing_tool_config.value = encrypt_data(tool_config.value)\n        else:\n            # Create a new tool config\n            new_tool_config = ToolConfig(key=tool_config.key, value=encrypt_data(tool_config.value), toolkit_id=toolkit.id)\n            db.session.add(new_tool_config)\n    \n\n    db.session.commit()\n    db.session.refresh(toolkit)\n\n    return toolkit\n\n\n@router.get(\"/get/toolkit/{toolkit_name}\", status_code=200)\ndef get_all_tool_configs(toolkit_name: str, organisation: Organisation = Depends(get_user_organisation)):\n    \"\"\"\n    Get all tool configurations by Tool Kit Name.\n\n    Args:\n        toolkit_name (str): The name of the tool kit.\n        organisation (Organisation): The organization associated with the user.\n\n    Returns:\n        list: A list of tool configurations for the specified tool kit.\n\n    Raises:\n        HTTPException (status_code=404): If the specified tool kit is not found.\n        HTTPException (status_code=403): If the user is not authorized to access the tool kit.\n    \"\"\"\n\n    toolkit = db.session.query(Toolkit).filter(Toolkit.name == toolkit_name,\n                                               Toolkit.organisation_id == organisation.id).first()\n    \n    if not toolkit:\n        raise HTTPException(status_code=404, detail='ToolKit not found')\n\n    tool_configs = db.session.query(ToolConfig).filter(ToolConfig.toolkit_id == toolkit.id).all()\n    for tool_config in tool_configs:\n        if tool_config.value:\n            if(is_encrypted(tool_config.value)):\n                tool_config.value = decrypt_data(tool_config.value)\n            if tool_config.key_type == ToolConfigKeyType.FILE.value:\n                tool_config.value = json.loads(tool_config.value)\n    \n    return tool_configs\n\n\n@router.get(\"/get/toolkit/{toolkit_name}/key/{key}\", status_code=200)\ndef get_tool_config(toolkit_name: str, key: str, organisation: Organisation = Depends(get_user_organisation)):\n    \"\"\"\n    Get a specific tool configuration by tool kit name and key.\n\n    Args:\n        toolkit_name (str): The name of the tool kit.\n        key (str): The key of the tool configuration.\n        organisation (Organisation): The organization associated with the user.\n\n    Returns:\n        ToolConfig: The tool configuration with the specified key.\n\n    Raises:\n        HTTPException (status_code=403): If the user is not authorized to access the tool kit.\n        HTTPException (status_code=404): If the specified tool kit or tool configuration is not found.\n    \"\"\"\n\n    user_toolkits = db.session.query(Toolkit).filter(Toolkit.organisation_id == organisation.id).all()\n\n    toolkit = db.session.query(Toolkit).filter_by(name=toolkit_name)\n    if toolkit not in user_toolkits:\n        raise HTTPException(status_code=403, detail='Unauthorized')\n\n    tool_config = db.session.query(ToolConfig).filter(\n        ToolConfig.toolkit_id == toolkit.id,\n        ToolConfig.key == key\n    ).first()\n    if not tool_config:\n        raise HTTPException(status_code=404, detail=\"Tool configuration not found\")\n    if(is_encrypted(tool_config.value)):\n        tool_config.value = decrypt_data(tool_config.value)\n    if tool_config.key_type == ToolConfigKeyType.FILE.value:\n        tool_config.value = json.loads(tool_config.value)\n\n    return tool_config\n"
  },
  {
    "path": "superagi/controllers/toolkit.py",
    "content": "from typing import Optional\n\nimport requests\nfrom fastapi import APIRouter, Body\nfrom fastapi import HTTPException, Depends, Query\nfrom fastapi_sqlalchemy import db\nfrom superagi.config.config import get_config\nfrom superagi.helper.auth import get_user_organisation\nfrom superagi.helper.tool_helper import get_readme_content_from_code_link, download_tool, process_files, \\\n    add_tool_to_json\nfrom superagi.helper.github_helper import GithubHelper\nfrom superagi.models.organisation import Organisation\nfrom superagi.models.tool import Tool\nfrom superagi.models.tool_config import ToolConfig\nfrom superagi.models.toolkit import Toolkit\nfrom superagi.types.common import GitHubLinkRequest\nfrom superagi.helper.tool_helper import compare_toolkit\nfrom superagi.helper.encyption_helper import decrypt_data, is_encrypted\n\nrouter = APIRouter()\n\n\n# marketplace_url = \"https://app.superagi.com/api\"\n# marketplace_url = \"http://localhost:8001/\"\n\n\n# For internal use\n@router.get(\"/marketplace/list/{page}\")\ndef get_marketplace_toolkits(\n        page: int = 0,\n):\n    \"\"\"\n    Get marketplace tool kits.\n\n    Args:\n        page (int): The page number for pagination.\n\n    Returns:\n        list: A list of tool kits in the marketplace.\n\n    \"\"\"\n\n    organisation_id = int(get_config(\"MARKETPLACE_ORGANISATION_ID\"))\n    page_size = 30\n\n    # Apply search filter if provided\n    query = db.session.query(Toolkit).filter(Toolkit.organisation_id == organisation_id)\n\n    # Paginate the results\n    toolkits = query.offset(page * page_size).limit(page_size).all()\n\n    # Fetch tools for each tool kit\n    for toolkit in toolkits:\n        toolkit.tools = db.session.query(Tool).filter(Tool.toolkit_id == toolkit.id).all()\n        toolkit.updated_at = toolkit.updated_at.strftime('%d-%b-%Y').upper()\n    return toolkits\n\n\n# For internal use\n@router.get(\"/marketplace/details/{toolkit_name}\")\ndef get_marketplace_toolkit_detail(toolkit_name: str):\n    \"\"\"\n    Get tool kit details from the marketplace.\n\n    Args:\n        toolkit_name (str): The name of the tool kit.\n\n    Returns:\n        Toolkit: The tool kit details from the marketplace.\n\n    \"\"\"\n\n    organisation_id = int(get_config(\"MARKETPLACE_ORGANISATION_ID\"))\n    toolkit = db.session.query(Toolkit).filter(Toolkit.organisation_id == organisation_id,\n                                               Toolkit.name == toolkit_name).first()\n    toolkit.tools = db.session.query(Tool).filter(Tool.toolkit_id == toolkit.id).all()\n    toolkit.configs = db.session.query(ToolConfig).filter(ToolConfig.toolkit_id == toolkit.id).all()\n    for tool_configs in toolkit.configs:\n        if is_encrypted(tool_configs.value):\n            tool_configs.value = decrypt_data(tool_configs.value)\n    return toolkit\n\n\n# For internal use\n@router.get(\"/marketplace/readme/{toolkit_name}\")\ndef get_marketplace_toolkit_readme(toolkit_name: str):\n    \"\"\"\n    Get tool kit readme from the marketplace.\n\n    Args:\n        toolkit_name (str): The name of the tool kit.\n\n    Returns:\n        str: The content of the tool kit's readme file.\n\n    Raises:\n        HTTPException (status_code=404): If the specified tool kit is not found.\n\n    \"\"\"\n\n    organisation_id = int(get_config(\"MARKETPLACE_ORGANISATION_ID\"))\n    toolkit = db.session.query(Toolkit).filter(Toolkit.name == toolkit_name,\n                                               Toolkit.organisation_id == organisation_id).first()\n    if not toolkit:\n        raise HTTPException(status_code=404, detail='ToolKit not found')\n    return get_readme_content_from_code_link(toolkit.tool_code_link)\n\n\n# For internal use\n@router.get(\"/marketplace/tools/{toolkit_name}\")\ndef get_marketplace_toolkit_tools(toolkit_name: str):\n    \"\"\"\n    Get tools of a specific tool kit from the marketplace.\n\n    Args:\n        toolkit_name (str): The name of the tool kit.\n\n    Returns:\n        Tool: The tools associated with the tool kit.\n\n    Raises:\n        HTTPException (status_code=404): If the specified tool kit is not found.\n\n    \"\"\"\n\n    organisation_id = int(get_config(\"MARKETPLACE_ORGANISATION_ID\"))\n    toolkit = db.session.query(Toolkit).filter(Toolkit.name == toolkit_name,\n                                               Toolkit.organisation_id == organisation_id).first()\n    if not toolkit:\n        raise HTTPException(status_code=404, detail=\"ToolKit not found\")\n    tools = db.session.query(Tool).filter(Tool.toolkit_id == toolkit.id).first()\n    return tools\n\n\n@router.get(\"/get/install/{toolkit_name}\")\ndef install_toolkit_from_marketplace(toolkit_name: str,\n                                     organisation: Organisation = Depends(get_user_organisation)):\n    \"\"\"\n    Download and install a tool kit from the marketplace.\n\n    Args:\n        toolkit_name (str): The name of the tool kit.\n        organisation (Organisation): The user's organisation.\n\n    Returns:\n        dict: A message indicating the successful installation of the tool kit.\n\n    \"\"\"\n    # Check if the tool kit exists\n    toolkit = Toolkit.fetch_marketplace_detail(search_str=\"details\",\n                                               toolkit_name=toolkit_name)\n    db_toolkit = Toolkit.add_or_update(session=db.session, name=toolkit['name'], description=toolkit['description'],\n                                       tool_code_link=toolkit['tool_code_link'], organisation_id=organisation.id,\n                                       show_toolkit=toolkit['show_toolkit'])\n    for tool in toolkit['tools']:\n        Tool.add_or_update(session=db.session, tool_name=tool['name'], description=tool['description'],\n                           folder_name=tool['folder_name'], class_name=tool['class_name'], file_name=tool['file_name'],\n                           toolkit_id=db_toolkit.id)\n    for config in toolkit['configs']:\n        ToolConfig.add_or_update(session=db.session, toolkit_id=db_toolkit.id, key=config['key'], value=config['value'], key_type = config['key_type'], is_secret = config['is_secret'], is_required = config['is_required'])    \n    \n    return {\"message\": \"ToolKit installed successfully\"}\n\n\n@router.get(\"/get/toolkit_name/{toolkit_name}\")\ndef get_installed_toolkit_details(toolkit_name: str,\n                                  organisation: Organisation = Depends(get_user_organisation)):\n    \"\"\"\n    Get details of a locally installed tool kit by its name, including the details of its tools.\n\n    Args:\n        toolkit_name (str): The name of the tool kit.\n        organisation (Organisation): The user's organisation.\n\n    Returns:\n        Toolkit: The tool kit object with its associated tools.\n\n    Raises:\n        HTTPException (status_code=404): If the specified tool kit is not found.\n\n    \"\"\"\n\n    # Fetch the tool kit by its ID\n    toolkit = db.session.query(Toolkit).filter(Toolkit.name == toolkit_name,\n                                               Organisation.id == organisation.id).first()\n\n    if not toolkit:\n        # Return an appropriate response if the tool kit doesn't exist\n        raise HTTPException(status_code=404, detail='ToolKit not found')\n\n    # Fetch the tools associated with the tool kit\n    tools = db.session.query(Tool).filter(Tool.toolkit_id == toolkit.id).all()\n    # Add the tools to the tool kit object\n    toolkit.tools = tools\n    # readme_content = get_readme(toolkit.tool_code_link)\n    return toolkit\n\n\n@router.post(\"/get/local/install\", status_code=200)\ndef download_and_install_tool(github_link_request: GitHubLinkRequest = Body(...),\n                              organisation: Organisation = Depends(get_user_organisation)):\n    \"\"\"\n    Install a tool locally from a GitHub link.\n\n    Args:\n        github_link_request (GitHubLinkRequest): The GitHub link request object.\n        organisation (Organisation): The user's organisation.\n\n    Returns:\n        None\n\n    Raises:\n        HTTPException (status_code=400): If the GitHub link is invalid.\n\n    \"\"\"\n    github_link = github_link_request.github_link\n    if not GithubHelper.validate_github_link(github_link):\n        raise HTTPException(status_code=400, detail=\"Invalid Github link\")\n    # download_folder = get_config(\"TOOLS_DIR\")\n    # download_tool(github_link, download_folder)\n    # process_files(download_folder, db.session, organisation, code_link=github_link)\n    add_tool_to_json(github_link)\n\n\n@router.get(\"/get/readme/{toolkit_name}\")\ndef get_installed_toolkit_readme(toolkit_name: str, organisation: Organisation = Depends(get_user_organisation)):\n    \"\"\"\n    Get the readme content of a toolkit.\n\n    Args:\n        toolkit_name (str): The name of the toolkit.\n        organisation (Organisation): The user's organisation.\n\n    Returns:\n        str: The readme content of the toolkit.\n\n    Raises:\n        HTTPException (status_code=404): If the toolkit is not found.\n\n    \"\"\"\n\n    toolkit = db.session.query(Toolkit).filter(Toolkit.name == toolkit_name,\n                                               Organisation.id == organisation.id).first()\n    if not toolkit:\n        raise HTTPException(status_code=404, detail='ToolKit not found')\n    readme_content = get_readme_content_from_code_link(toolkit.tool_code_link)\n    return readme_content\n\n\n# Following APIs will be used to get marketplace related information\n@router.get(\"/get\")\ndef handle_marketplace_operations(\n        search_str: str = Query(None, title=\"Search String\"),\n        toolkit_name: str = Query(None, title=\"Tool Kit Name\")\n):\n    \"\"\"\n    Handle marketplace operations.\n\n    Args:\n        search_str (str, optional): The search string to filter toolkits. Defaults to None.\n        toolkit_name (str, optional): The name of the toolkit. Defaults to None.\n\n    Returns:\n        dict: The response containing the marketplace details.\n\n    \"\"\"\n    response = Toolkit.fetch_marketplace_detail(search_str, toolkit_name)\n    return response\n\n\n@router.get(\"/get/list\")\ndef handle_marketplace_operations_list(\n        page: int = Query(None, title=\"Page Number\"),\n        organisation: Organisation = Depends(get_user_organisation)\n):\n    \"\"\"\n    Handle marketplace operation list.\n\n    Args:\n        page (int, optional): The page number for pagination. Defaults to None.\n\n    Returns:\n        dict: The response containing the marketplace list.\n\n    \"\"\"\n\n    marketplace_toolkits = Toolkit.fetch_marketplace_list(page=page)\n    marketplace_toolkits_with_install = Toolkit.get_toolkit_installed_details(db.session, marketplace_toolkits,\n                                                                              organisation)\n    return marketplace_toolkits_with_install\n\n\n@router.get(\"/get/local/list\")\ndef get_installed_toolkit_list(organisation: Organisation = Depends(get_user_organisation)):\n    \"\"\"\n    Get the list of installed tool kits.\n\n    Args:\n        organisation (Organisation): The organisation associated with the tool kits.\n\n    Returns:\n        list: The list of installed tool kits.\n\n    \"\"\"\n\n    toolkits = db.session.query(Toolkit).filter(Toolkit.organisation_id == organisation.id).all()\n    for toolkit in toolkits:\n        toolkit_tools = db.session.query(Tool).filter(Tool.toolkit_id == toolkit.id).all()\n        toolkit.tools = toolkit_tools\n\n    return toolkits\n\n\n@router.get(\"/check_update/{toolkit_name}\")\ndef check_toolkit_update(toolkit_name: str, organisation: Organisation = Depends(get_user_organisation)):\n    \"\"\"\n    Check if there is an update available for the installed tool kits.\n\n    Returns:\n        dict: The response containing the update details.\n\n    \"\"\"\n    marketplace_toolkit = Toolkit.fetch_marketplace_detail(search_str=\"details\",\n                                                           toolkit_name=toolkit_name)\n    if marketplace_toolkit is None:\n        raise HTTPException(status_code=404, detail=\"Toolkit not found in marketplace\")\n    installed_toolkit = Toolkit.get_toolkit_from_name(db.session, toolkit_name, organisation)\n    if installed_toolkit is None:\n        return True\n    installed_toolkit = installed_toolkit.to_dict()\n    tools = Tool.get_toolkit_tools(db.session, installed_toolkit[\"id\"])\n    configs = ToolConfig.get_toolkit_tool_config(db.session, installed_toolkit[\"id\"])\n    installed_toolkit[\"configs\"] = []\n    installed_toolkit[\"tools\"] = []\n\n    for config in configs:\n        installed_toolkit[\"configs\"].append(config.to_dict())\n    for tool in tools:\n        installed_toolkit[\"tools\"].append(tool.to_dict())\n\n    return compare_toolkit(marketplace_toolkit, installed_toolkit)\n\n\n@router.put(\"/update/{toolkit_name}\")\ndef update_toolkit(toolkit_name: str, organisation: Organisation = Depends(get_user_organisation)):\n    \"\"\"\n        Update the toolkit with the latest version from the marketplace.\n    \"\"\"\n    marketplace_toolkit = Toolkit.fetch_marketplace_detail(search_str=\"details\",\n                                                           toolkit_name=toolkit_name)\n\n    update_toolkit = Toolkit.add_or_update(\n        db.session,\n        name=marketplace_toolkit[\"name\"],\n        description=marketplace_toolkit[\"description\"],\n        show_toolkit=True if len(marketplace_toolkit[\"tools\"]) > 1 else False,\n        organisation_id=organisation.id,\n        tool_code_link=marketplace_toolkit[\"tool_code_link\"]\n    )\n\n    for tool in marketplace_toolkit[\"tools\"]:\n        Tool.add_or_update(db.session, tool_name=tool[\"name\"], folder_name=tool[\"folder_name\"],\n                           class_name=tool[\"class_name\"], file_name=tool[\"file_name\"],\n                           toolkit_id=update_toolkit.id, description=tool[\"description\"])\n\n    for tool_config_key in marketplace_toolkit[\"configs\"]:\n        ToolConfig.add_or_update(db.session, toolkit_id=update_toolkit.id, key=tool_config_key[\"key\"], key_type = tool_config_key['key_type'], is_secret = tool_config_key['is_secret'], is_required = tool_config_key['is_required'])\n"
  },
  {
    "path": "superagi/controllers/twitter_oauth.py",
    "content": "import http.client as http_client\nimport json\n\nfrom fastapi import APIRouter\nfrom fastapi import Depends, Query\nfrom fastapi.responses import RedirectResponse\nfrom fastapi_jwt_auth import AuthJWT\nfrom fastapi_sqlalchemy import db\n\nimport superagi\nfrom superagi.helper.auth import get_current_user, check_auth\nfrom superagi.helper.twitter_tokens import TwitterTokens\nfrom superagi.models.oauth_tokens import OauthTokens\nfrom superagi.models.tool_config import ToolConfig\nfrom superagi.models.toolkit import Toolkit\nfrom superagi.helper.encyption_helper import decrypt_data, is_encrypted\n\nrouter = APIRouter()\n\n@router.get('/oauth-tokens')\nasync def twitter_oauth(oauth_token: str = Query(...),oauth_verifier: str = Query(...), Authorize: AuthJWT = Depends()):\n    token_uri = f'https://api.twitter.com/oauth/access_token?oauth_verifier={oauth_verifier}&oauth_token={oauth_token}'\n    conn = http_client.HTTPSConnection(\"api.twitter.com\")\n    conn.request(\"POST\", token_uri, \"\")\n    res = conn.getresponse()\n    response_data = res.read().decode('utf-8')\n    frontend_url = superagi.config.config.get_config(\"FRONTEND_URL\", \"http://localhost:3000\")\n    redirect_url_success = f\"{frontend_url}/twitter_creds/?{response_data}\"\n    return RedirectResponse(url=redirect_url_success)\n\n@router.post(\"/send_twitter_creds/{twitter_creds}\")\ndef send_twitter_tool_configs(twitter_creds: str, Authorize: AuthJWT = Depends(check_auth)):\n    current_user = get_current_user(Authorize)\n    user_id = current_user.id\n    credentials = json.loads(twitter_creds)\n    credentials[\"user_id\"] = user_id\n    toolkit = db.session.query(Toolkit).filter(Toolkit.id == credentials[\"toolkit_id\"]).first()\n    api_key = db.session.query(ToolConfig).filter(ToolConfig.key == \"TWITTER_API_KEY\", ToolConfig.toolkit_id == credentials[\"toolkit_id\"]).first()\n    if is_encrypted(api_key.value):\n        api_key.value = decrypt_data(api_key.value)\n    api_key_secret = db.session.query(ToolConfig).filter(ToolConfig.key == \"TWITTER_API_SECRET\", ToolConfig.toolkit_id == credentials[\"toolkit_id\"]).first()\n    if is_encrypted(api_key_secret.value):\n        api_key_secret.value = decrypt_data(api_key_secret.value)\n\n    final_creds = {\n        \"api_key\": api_key.value,\n        \"api_key_secret\": api_key_secret.value,\n        \"oauth_token\": credentials[\"oauth_token\"],\n        \"oauth_token_secret\": credentials[\"oauth_token_secret\"]\n    }\n    tokens = OauthTokens().add_or_update(db.session, credentials[\"toolkit_id\"], user_id, toolkit.organisation_id, \"TWITTER_OAUTH_TOKENS\", str(final_creds))\n    if tokens:\n        success = True\n    else:\n        success = False\n    return success\n\n@router.get(\"/get_twitter_creds/toolkit_id/{toolkit_id}\")\ndef get_twitter_tool_configs(toolkit_id: int):\n    twitter_config_key = db.session.query(ToolConfig).filter(ToolConfig.toolkit_id == toolkit_id,ToolConfig.key == \"TWITTER_API_KEY\").first()\n    twitter_config_secret = db.session.query(ToolConfig).filter(ToolConfig.toolkit_id == toolkit_id,ToolConfig.key == \"TWITTER_API_SECRET\").first()\n    if is_encrypted(twitter_config_key.value):\n        twitter_config_key.value = decrypt_data(twitter_config_key.value)\n    if is_encrypted(twitter_config_secret.value):\n        twitter_config_secret.value = decrypt_data(twitter_config_secret.value)\n    api_data =  {\n        \"api_key\": twitter_config_key.value,\n        \"api_secret\": twitter_config_secret.value\n    }\n    response = TwitterTokens(db.session).get_request_token(api_data)\n    return response\n"
  },
  {
    "path": "superagi/controllers/types/agent_execution_config.py",
    "content": "import datetime\nfrom typing import List, Optional\nfrom pydantic import BaseModel\nfrom datetime import datetime\n\n\nclass AgentRunIn(BaseModel):\n    status: Optional[str]\n    name: Optional[str]\n    agent_id: Optional[int]\n    last_execution_time: Optional[datetime]\n    num_of_calls: Optional[int]\n    num_of_tokens: Optional[int]\n    current_step_id: Optional[int]\n    permission_id: Optional[int]\n    goal: Optional[List[str]]\n    instruction: Optional[List[str]]\n    agent_workflow: str\n    constraints: List[str]\n    toolkits: List[int]\n    tools: List[int]\n    exit: str\n    iteration_interval: int\n    model: str\n    permission_type: str\n    LTM_DB: str\n    max_iterations: int\n    user_timezone: Optional[str]\n    knowledge: Optional[int]\n\n    class Config:\n        orm_mode = True"
  },
  {
    "path": "superagi/controllers/types/agent_publish_config.py",
    "content": "from typing import List, Optional\nfrom pydantic import BaseModel\n\nclass AgentPublish(BaseModel):\n    name: str\n    description: str\n    agent_template_id: int\n    goal: Optional[List[str]]\n    instruction: Optional[List[str]]\n    constraints: List[str]\n    toolkits: List[int]\n    tools: List[int]\n    exit: str\n    iteration_interval: int\n    model: str\n    permission_type: str\n    LTM_DB: str\n    max_iterations: int\n    user_timezone: Optional[str]\n    knowledge: Optional[int]\n\n    class Config:\n        orm_mode = True"
  },
  {
    "path": "superagi/controllers/types/agent_schedule.py",
    "content": "from pydantic import BaseModel\nfrom typing import Optional\nfrom datetime import datetime\n\nclass AgentScheduleInput(BaseModel):\n    agent_id: Optional[int]\n    start_time: datetime\n    recurrence_interval: Optional[str] = None\n    expiry_date: Optional[datetime] = None\n    expiry_runs: Optional[int] = -1\n"
  },
  {
    "path": "superagi/controllers/types/agent_with_config.py",
    "content": "from pydantic import BaseModel\nfrom typing import List, Optional\nfrom superagi.controllers.types.agent_schedule import AgentScheduleInput\n\nclass AgentConfigInput(BaseModel):\n    name: str\n    project_id: int\n    description: str\n    goal: List[str]\n    instruction: List[str]\n    agent_workflow: str\n    constraints: List[str]\n    toolkits: List[int]\n    tools: List[int]\n    exit: str\n    iteration_interval: int\n    model: str\n    permission_type: str\n    LTM_DB: str\n    max_iterations: int\n    user_timezone: Optional[str]\n    knowledge: Optional[int]\n\n\n\nclass AgentConfigExtInput(BaseModel):\n    name: str\n    description: str\n    project_id: Optional[int]\n    goal: List[str]\n    instruction: List[str]\n    agent_workflow: str\n    constraints: List[str]\n    tools: List[dict]\n    LTM_DB:Optional[str]\n    exit: Optional[str]\n    permission_type: Optional[str]\n    iteration_interval: int\n    model: str\n    schedule: Optional[AgentScheduleInput]\n    max_iterations: int\n    user_timezone: Optional[str]\n    knowledge: Optional[int]\n\nclass AgentConfigUpdateExtInput(BaseModel):\n    name: Optional[str]\n    description: Optional[str]\n    project_id: Optional[int]\n    goal: Optional[List[str]]\n    instruction: Optional[List[str]]\n    agent_workflow: Optional[str]\n    constraints: Optional[List[str]]\n    tools: Optional[List[dict]]\n    LTM_DB:Optional[str]\n    exit: Optional[str]\n    permission_type: Optional[str]\n    iteration_interval: Optional[int]\n    model: Optional[str]\n    schedule: Optional[AgentScheduleInput]\n    max_iterations: Optional[int]\n    user_timezone: Optional[str]\n    knowledge: Optional[int]\n\n\n"
  },
  {
    "path": "superagi/controllers/types/agent_with_config_schedule.py",
    "content": "from pydantic import BaseModel\nfrom superagi.controllers.types.agent_schedule import AgentScheduleInput\nfrom superagi.controllers.types.agent_with_config import AgentConfigInput\n\n\nclass AgentConfigSchedule(BaseModel):\n    agent_config: AgentConfigInput\n    schedule: AgentScheduleInput"
  },
  {
    "path": "superagi/controllers/types/models_types.py",
    "content": "from enum import Enum\n\nclass ModelsTypes(Enum):\n    MARKETPLACE = \"Marketplace\"\n    CUSTOM = \"Custom\"\n\n    @classmethod\n    def get_models_types(cls, model_type):\n        if model_type is None:\n            raise ValueError(\"Queue status type cannot be None.\")\n        model_type = model_type.upper()\n        if model_type in cls.__members__:\n            return cls[model_type]\n        raise ValueError(f\"{model_type} is not a valid storage name.\")"
  },
  {
    "path": "superagi/controllers/user.py",
    "content": "from datetime import datetime\nfrom typing import Optional\n\nfrom fastapi_sqlalchemy import db\nfrom fastapi import HTTPException, Depends, Request\nfrom fastapi_jwt_auth import AuthJWT\nfrom pydantic import BaseModel\n\nfrom superagi.models.organisation import Organisation\nfrom superagi.models.project import Project\nfrom superagi.models.user import User\nfrom fastapi import APIRouter\n\nfrom superagi.helper.auth import check_auth, get_current_user\nfrom superagi.lib.logger import logger\n\nfrom superagi.models.models_config import ModelsConfig\n\n# from superagi.types.db import UserBase, UserIn, UserOut\n\nrouter = APIRouter()\n\n\nclass UserBase(BaseModel):\n    name: str\n    email: str\n    password: str\n\n    class Config:\n        orm_mode = True\n\n\nclass UserOut(UserBase):\n    id: int\n    organisation_id: int\n    created_at: datetime\n    updated_at: datetime\n\n    class Config:\n        orm_mode = True\n\n\nclass UserIn(UserBase):\n    organisation_id: Optional[int]\n\n    class Config:\n        orm_mode = True\n\n\n# CRUD Operations\n@router.post(\"/add\", response_model=UserOut, status_code=201)\ndef create_user(user: UserIn, Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Create a new user.\n\n    Args:\n        user (UserIn): User data.\n\n    Returns:\n        User: The created user.\n\n    Raises:\n        HTTPException (status_code=400): If there is an issue creating the user.\n        HTTPException (status_code=422): If required fields are missing or incorrectly formatted.\n    \"\"\"\n    logger.info(\"Received user data: %s\", user)\n    \n    # Validate incoming request data\n    if not user.name or not user.email or not user.password:\n        logger.error(\"Missing required fields: name, email, or password\")\n        raise HTTPException(status_code=422, detail=\"Missing required fields: name, email, or password\")\n    \n    db_user = db.session.query(User).filter(User.email == user.email).first()\n    if db_user:\n        return db_user\n    \n    db_user = User(name=user.name, email=user.email, password=user.password, organisation_id=user.organisation_id)\n    db.session.add(db_user)\n    db.session.commit()\n    db.session.flush()\n    \n    organisation = Organisation.find_or_create_organisation(db.session, db_user)\n    Project.find_or_create_default_project(db.session, organisation.id)\n    logger.info(\"User created: %s\", db_user)\n    \n    # Adding local LLM configuration\n    ModelsConfig.add_llm_config(db.session, organisation.id)\n    \n    return db_user\n\n\n@router.get(\"/get/{user_id}\", response_model=UserOut)\ndef get_user(user_id: int,\n             Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Get a particular user details.\n\n    Args:\n        user_id (int): ID of the user.\n\n    Returns:\n        User: The user details.\n\n    Raises:\n        HTTPException (status_code=404): If the user with the specified ID is not found.\n\n    \"\"\"\n\n    # Authorize.jwt_required()\n    db_user = db.session.query(User).filter(User.id == user_id).first()\n    if not db_user:\n        raise HTTPException(status_code=404, detail=\"User not found\")\n    return db_user\n\n\n@router.put(\"/update/{user_id}\", response_model=UserOut)\ndef update_user(user_id: int,\n                user: UserBase,\n                Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Update a particular user.\n\n    Args:\n        user_id (int): ID of the user.\n        user (UserIn): Updated user data.\n\n    Returns:\n        User: The updated user details.\n\n    Raises:\n        HTTPException (status_code=404): If the user with the specified ID is not found.\n\n    \"\"\"\n\n    db_user = db.session.query(User).filter(User.id == user_id).first()\n    if not db_user:\n        raise HTTPException(status_code=404, detail=\"User not found\")\n\n    db_user.name = user.name\n    db_user.email = user.email\n    db_user.password = user.password\n\n    db.session.commit()\n    return db_user\n\n\n@router.post(\"/first_login_source/{source}\")\ndef update_first_login_source(source: str, Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\" Update first login source of the user \"\"\"\n    user = get_current_user(Authorize)\n    # valid_sources = ['google', 'github', 'email']\n    if user.first_login_source is None or user.first_login_source == '':\n        user.first_login_source = source\n    db.session.commit()\n    db.session.flush()\n    logger.info(\"User : \",user)\n    return user\n"
  },
  {
    "path": "superagi/controllers/vector_db_indices.py",
    "content": "from fastapi_sqlalchemy import db\nfrom fastapi import HTTPException, Depends, Query\nfrom fastapi import APIRouter\nfrom superagi.helper.auth import get_user_organisation\nfrom superagi.models.vector_dbs import Vectordbs\nfrom superagi.models.vector_db_indices import VectordbIndices\nfrom superagi.models.knowledges import Knowledges\nfrom superagi.models.knowledge_configs import KnowledgeConfigs\n\nrouter = APIRouter()\n\n@router.get(\"/marketplace/valid_indices/{knowledge_name}\")\ndef get_marketplace_valid_indices(knowledge_name: str, organisation = Depends(get_user_organisation)):\n    vector_dbs = Vectordbs.get_vector_db_from_organisation(db.session, organisation)\n    knowledge = Knowledges.fetch_knowledge_details_marketplace(knowledge_name)\n    knowledge_with_config = KnowledgeConfigs.fetch_knowledge_config_details_marketplace(knowledge['id'])\n    pinecone = []\n    qdrant = []\n    weaviate = []\n    for vector_db in vector_dbs:\n        indices =  VectordbIndices.get_vector_indices_from_vectordb(db.session, vector_db.id)\n        for index in indices:\n            data = {\"id\": index.id, \"name\": index.name}\n            data[\"is_valid_dimension\"] = True if index.dimensions == int(knowledge_with_config[\"dimensions\"]) else False\n            data[\"is_valid_state\"] = True if index.state != \"Custom\" else False\n            if vector_db.db_type == \"Pinecone\":\n                pinecone.append(data)\n            if vector_db.db_type == \"Qdrant\":\n                qdrant.append(data)\n            if vector_db.db_type == \"Weaviate\":\n                data[\"is_valid_dimension\"] = True\n                weaviate.append(data)\n    return {\"pinecone\": pinecone, \"qdrant\": qdrant, \"weaviate\": weaviate}\n\n@router.get(\"/user/valid_indices\")\ndef get_user_valid_indices(organisation = Depends(get_user_organisation)):\n    vector_dbs = Vectordbs.get_vector_db_from_organisation(db.session, organisation)\n    pinecone = []\n    qdrant = []\n    weaviate = []\n    for vector_db in vector_dbs:\n        indices =  VectordbIndices.get_vector_indices_from_vectordb(db.session, vector_db.id)\n        for index in indices:\n            data = {\"id\": index.id, \"name\": index.name}\n            data[\"is_valid_state\"] = True if index.state == \"Custom\" else False\n            if vector_db.db_type == \"Pinecone\":\n                pinecone.append(data)\n            if vector_db.db_type == \"Qdrant\":\n                qdrant.append(data)\n            if vector_db.db_type == \"Weaviate\":\n                weaviate.append(data)\n    return {\"pinecone\": pinecone, \"qdrant\": qdrant, \"weaviate\": weaviate}"
  },
  {
    "path": "superagi/controllers/vector_dbs.py",
    "content": "from fastapi_sqlalchemy import db\nfrom fastapi import HTTPException, Depends\nfrom fastapi import APIRouter\nfrom superagi.config.config import get_config\nfrom datetime import datetime\nfrom superagi.helper.time_helper import get_time_difference\nfrom superagi.models.vector_dbs import Vectordbs\nfrom superagi.helper.auth import get_user_organisation\nfrom superagi.models.vector_db_configs import VectordbConfigs\nfrom superagi.models.vector_db_indices import VectordbIndices\nfrom superagi.vector_store.vector_factory import VectorFactory\nfrom superagi.models.knowledges import Knowledges\n\nrouter = APIRouter()\n\n@router.get(\"/get/list\")\ndef get_vector_db_list():\n    marketplace_vector_dbs = Vectordbs.fetch_marketplace_list()\n    return marketplace_vector_dbs\n\n@router.get(\"/marketplace/list\")\ndef get_marketplace_vectordb_list():\n    organisation_id = int(get_config(\"MARKETPLACE_ORGANISATION_ID\"))\n    vector_dbs = db.session.query(Vectordbs).filter(Vectordbs.organisation_id == organisation_id).all()\n    return vector_dbs\n\n@router.get(\"/user/list\")\ndef get_user_connected_vector_db_list(organisation = Depends(get_user_organisation)):\n    vector_db_list = Vectordbs.get_vector_db_from_organisation(db.session, organisation)\n    if vector_db_list:\n        for vector in vector_db_list:\n            vector.updated_at = get_time_difference(vector.updated_at, str(datetime.now()))\n    return vector_db_list\n\n@router.get(\"/db/details/{vector_db_id}\")\ndef get_vector_db_details(vector_db_id: int):\n    vector_db = Vectordbs.get_vector_db_from_id(db.session, vector_db_id)\n    vector_db_data = {\n        \"id\": vector_db.id,\n        \"name\": vector_db.name,\n        \"db_type\": vector_db.db_type\n    }\n    vector_db_config = VectordbConfigs.get_vector_db_config_from_db_id(db.session, vector_db_id)\n    vector_db_with_config = vector_db_data | vector_db_config\n    indices = db.session.query(VectordbIndices).filter(VectordbIndices.vector_db_id == vector_db_id).all()\n    vector_indices = []\n    for index in indices:\n        vector_indices.append(index.name)\n    vector_db_with_config[\"indices\"] = vector_indices\n    return vector_db_with_config\n\n@router.post(\"/delete/{vector_db_id}\")\ndef delete_vector_db(vector_db_id: int):\n    try:\n        vector_indices = VectordbIndices.get_vector_indices_from_vectordb(db.session, vector_db_id)\n        for vector_index in vector_indices:\n            Knowledges.delete_knowledge_from_vector_index(db.session, vector_index.id)\n            VectordbIndices.delete_vector_db_index(db.session, vector_index.id)\n        VectordbConfigs.delete_vector_db_configs(db.session, vector_db_id)\n        Vectordbs.delete_vector_db(db.session, vector_db_id)\n    except:\n        raise HTTPException(status_code=404, detail=\"VectorDb not found\")\n    \n@router.post(\"/connect/pinecone\")\ndef connect_pinecone_vector_db(data: dict, organisation = Depends(get_user_organisation)):\n    db_creds = {\n        \"api_key\": data[\"api_key\"],\n        \"environment\": data[\"environment\"]\n    }\n    for collection in data[\"collections\"]:\n        try:\n            vector_db_storage = VectorFactory.build_vector_storage(\"pinecone\", collection, **db_creds)\n            db_connect_for_index = vector_db_storage.get_index_stats()\n            index_state = \"Custom\" if db_connect_for_index[\"vector_count\"] > 0 else \"None\"\n        except:\n            raise HTTPException(status_code=400, detail=\"Unable to connect Pinecone\")\n    pinecone_db = Vectordbs.add_vector_db(db.session, data[\"name\"], \"Pinecone\", organisation)\n    VectordbConfigs.add_vector_db_config(db.session, pinecone_db.id, db_creds)\n    for collection in data[\"collections\"]:\n        VectordbIndices.add_vector_index(db.session, collection, pinecone_db.id, index_state, db_connect_for_index[\"dimensions\"])\n    return {\"id\": pinecone_db.id, \"name\": pinecone_db.name}\n\n@router.post(\"/connect/qdrant\")\ndef connect_qdrant_vector_db(data: dict, organisation = Depends(get_user_organisation)):\n    db_creds = {\n        \"api_key\": data[\"api_key\"],\n        \"url\": data[\"url\"],\n        \"port\": data[\"port\"]\n    }\n    for collection in data[\"collections\"]:\n        try:\n            vector_db_storage = VectorFactory.build_vector_storage(\"qdrant\", collection, **db_creds)\n            db_connect_for_index = vector_db_storage.get_index_stats()\n            index_state = \"Custom\" if db_connect_for_index[\"vector_count\"] > 0 else \"None\"\n        except:\n            raise HTTPException(status_code=400, detail=\"Unable to connect Qdrant\")\n    qdrant_db = Vectordbs.add_vector_db(db.session, data[\"name\"], \"Qdrant\", organisation)\n    VectordbConfigs.add_vector_db_config(db.session, qdrant_db.id, db_creds)\n    for collection in data[\"collections\"]:\n        VectordbIndices.add_vector_index(db.session, collection, qdrant_db.id, index_state, db_connect_for_index[\"dimensions\"])\n    \n    return {\"id\": qdrant_db.id, \"name\": qdrant_db.name}\n\n@router.post(\"/connect/weaviate\")\ndef connect_weaviate_vector_db(data: dict, organisation = Depends(get_user_organisation)):\n    db_creds = {\n        \"api_key\": data[\"api_key\"],\n        \"url\": data[\"url\"]\n    }\n    for collection in data[\"collections\"]:\n        try:\n            vector_db_storage = VectorFactory.build_vector_storage(\"weaviate\", collection, **db_creds)\n            db_connect_for_index = vector_db_storage.get_index_stats()\n            index_state = \"Custom\" if db_connect_for_index[\"vector_count\"] > 0 else \"None\"\n        except:\n            raise HTTPException(status_code=400, detail=\"Unable to connect Weaviate\")\n    weaviate_db = Vectordbs.add_vector_db(db.session, data[\"name\"], \"Weaviate\", organisation)\n    VectordbConfigs.add_vector_db_config(db.session, weaviate_db.id, db_creds)\n    for collection in data[\"collections\"]:\n        VectordbIndices.add_vector_index(db.session, collection, weaviate_db.id, index_state)\n\n    return {\"id\": weaviate_db.id, \"name\": weaviate_db.name}\n\n@router.put(\"/update/vector_db/{vector_db_id}\")\ndef update_vector_db(new_indices: list, vector_db_id: int):\n    vector_db = Vectordbs.get_vector_db_from_id(db.session, vector_db_id)\n    existing_indices = VectordbIndices.get_vector_indices_from_vectordb(db.session, vector_db_id)\n    existing_index_names = []\n    for index in existing_indices:\n        if index.name not in new_indices:\n            VectordbIndices.delete_vector_db_index(db.session, vector_index_id=index.id)\n        existing_index_names.append(index.name)\n    existing_index_names = set(existing_index_names)\n    new_indices_names = set(new_indices)\n    added_indices = new_indices_names - existing_index_names\n    for index in added_indices:\n        db_creds = VectordbConfigs.get_vector_db_config_from_db_id(db.session, vector_db_id)\n        try:\n            vector_db_storage  = VectorFactory.build_vector_storage(vector_db.db_type, index, **db_creds)\n            vector_db_index_stats = vector_db_storage.get_index_stats()\n            index_state = \"Custom\" if vector_db_index_stats[\"vector_count\"] > 0 else \"None\"\n            dimensions = vector_db_index_stats[\"dimensions\"] if 'dimensions' in vector_db_index_stats else None\n        except:\n           raise HTTPException(status_code=400, detail=\"Unable to update vector db\")\n        VectordbIndices.add_vector_index(db.session, index, vector_db_id, index_state, dimensions)\n\n\n\n        "
  },
  {
    "path": "superagi/controllers/webhook.py",
    "content": "from datetime import datetime\nfrom typing import Optional\nfrom fastapi import APIRouter, HTTPException\nfrom fastapi import Depends\nfrom fastapi_jwt_auth import AuthJWT\nfrom fastapi_sqlalchemy import db\nfrom pydantic import BaseModel\n\n# from superagi.types.db import AgentOut, AgentIn\nfrom superagi.helper.auth import check_auth, get_user_organisation\nfrom superagi.models.webhooks import Webhooks\n\nrouter = APIRouter()\n\n\nclass WebHookIn(BaseModel):\n    name: str\n    url: str\n    headers: dict\n    filters: dict\n\n    class Config:\n        orm_mode = True\n\n\nclass WebHookOut(BaseModel):\n    id: int\n    org_id: int\n    name: str\n    url: str\n    headers: dict\n    is_deleted: bool\n    created_at: datetime\n    updated_at: datetime\n    filters: dict\n\n    class Config:\n        orm_mode = True\n\nclass WebHookEdit(BaseModel):\n    url: str\n    filters: dict\n\n    class Config:\n        orm_mode = True\n\n\n\n# CRUD Operations`\n@router.post(\"/add\", response_model=WebHookOut, status_code=201)\ndef create_webhook(webhook: WebHookIn, Authorize: AuthJWT = Depends(check_auth),\n                   organisation=Depends(get_user_organisation)):\n    \"\"\"\n        Creates a new webhook\n\n        Args:\n            \n        Returns:\n            Agent: An object of Agent representing the created Agent.\n\n        Raises:\n            HTTPException (Status Code=404): If the associated project is not found.\n    \"\"\"\n    db_webhook = Webhooks(name=webhook.name, url=webhook.url, headers=webhook.headers, org_id=organisation.id,\n                          is_deleted=False, filters=webhook.filters)\n    db.session.add(db_webhook)\n    db.session.commit()\n    db.session.flush()\n    return db_webhook\n\n@router.get(\"/get\", response_model=Optional[WebHookOut])\ndef get_all_webhooks(\n    Authorize: AuthJWT = Depends(check_auth),\n    organisation=Depends(get_user_organisation),\n):\n    \"\"\"\n    Retrieves a single webhook for the authenticated user's organisation.\n\n    Returns:\n        JSONResponse: A JSON response containing the retrieved webhook.\n\n    Raises:\n    \"\"\"\n    webhook = db.session.query(Webhooks).filter(Webhooks.org_id == organisation.id, Webhooks.is_deleted == False).first()\n    return webhook\n\n@router.post(\"/edit/{webhook_id}\", response_model=WebHookOut)\ndef edit_webhook(\n    updated_webhook: WebHookEdit,\n    webhook_id: int,\n    Authorize: AuthJWT = Depends(check_auth),\n    organisation=Depends(get_user_organisation),\n):\n    \"\"\"\n    Soft-deletes a webhook by setting the value of is_deleted to True.\n\n    Args:\n        webhook_id (int): The ID of the webhook to delete.\n\n    Returns:\n        WebHookOut: The deleted webhook.\n\n    Raises:\n        HTTPException (Status Code=404): If the webhook is not found.\n    \"\"\"\n    webhook = db.session.query(Webhooks).filter(Webhooks.org_id == organisation.id, Webhooks.id == webhook_id, Webhooks.is_deleted == False).first()\n    if webhook is None:\n        raise HTTPException(status_code=404, detail=\"Webhook not found\")\n    \n    webhook.url = updated_webhook.url\n    webhook.filters = updated_webhook.filters\n\n    db.session.commit()\n\n    return webhook"
  },
  {
    "path": "superagi/helper/agent_schedule_helper.py",
    "content": "from superagi.models.db import connect_db\nfrom sqlalchemy.orm import sessionmaker\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.models.agent_schedule import AgentSchedule\nfrom datetime import datetime, timedelta\nfrom superagi.helper.time_helper import parse_interval_to_seconds\nimport pytz\n\nengine = connect_db()\nSession = sessionmaker(bind=engine)\n\n\nclass AgentScheduleHelper:\n    AGENT_SCHEDULE_TIME_INTERVAL = 300\n\n    def run_scheduled_agents(self):\n        \"\"\"\n        Execute all eligible scheduled agent tasks since last five minutes.\n        \"\"\"\n\n        now = datetime.now()\n        last_five_minutes = now - timedelta(minutes=5)\n\n        session = Session()\n        scheduled_agents = session.query(AgentSchedule).filter(\n            AgentSchedule.next_scheduled_time.between(last_five_minutes, now), AgentSchedule.status == \"SCHEDULED\").all()\n\n        for agent in scheduled_agents:\n            interval = agent.recurrence_interval\n            interval_in_seconds = 0  # default value\n            if interval is not None:\n                interval_in_seconds = parse_interval_to_seconds(interval)\n            agent_id = agent.agent_id\n            agent_execution_name = self.__create_execution_name_for_scheduling(agent_id)\n\n            should_execute_agent = self.__should_execute_agent(agent, interval)\n\n            self.__execute_schedule(should_execute_agent, interval_in_seconds, session, agent,\n                                   agent_execution_name)\n\n        for agent in scheduled_agents:\n            if self.__can_remove_agent(agent, interval):\n                agent.status = \"COMPLETED\"\n                session.commit()\n\n        session.close()\n\n    def update_next_scheduled_time(self):\n        \"\"\"\n        Update the next scheduled time of each agent and terminate those who have finished their schedule, in case of any miss.\n        \"\"\"\n        now = datetime.now()\n\n        session = Session()\n        scheduled_agents = session.query(AgentSchedule).filter(\n            AgentSchedule.start_time <= now, AgentSchedule.next_scheduled_time <= now,\n            AgentSchedule.status == \"SCHEDULED\").all()\n\n        for agent in scheduled_agents:\n            if (now - agent.next_scheduled_time).total_seconds() < AgentScheduleHelper.AGENT_SCHEDULE_TIME_INTERVAL:\n                continue\n            if agent.recurrence_interval is not None:\n                interval_in_seconds = parse_interval_to_seconds(agent.recurrence_interval)\n                time_diff = now - agent.start_time\n                num_intervals_passed = time_diff.total_seconds() // interval_in_seconds\n                updated_next_scheduled_time = agent.start_time + timedelta(\n                    seconds=(interval_in_seconds * (num_intervals_passed + 1)))\n                agent.next_scheduled_time = updated_next_scheduled_time\n            else:\n                agent.status = \"TERMINATED\"\n            session.commit()\n        session.close()\n        \n    def __create_execution_name_for_scheduling(self, agent_id) -> str:\n        \"\"\"\n        Create name for an agent execution based on current time.\n\n        Args:\n            agent_id (str): The id of the agent job to be scheduled.\n\n        Returns:\n            str: Execution name of the agent in the format \"Run <timestamp>\"\n        \"\"\"\n        session = Session()\n        user_timezone = session.query(AgentConfiguration).filter(AgentConfiguration.key == \"user_timezone\",\n                                                                 AgentConfiguration.agent_id == agent_id).first()\n\n        if user_timezone and user_timezone.value != \"None\":\n            current_time = datetime.now().astimezone(pytz.timezone(user_timezone.value))\n        else:\n            current_time = datetime.now().astimezone(pytz.timezone('GMT'))\n\n        timestamp = current_time.strftime(\" %d %B %Y %H:%M\")\n        return f\"Run{timestamp}\"\n\n    def __should_execute_agent(self, agent, interval):\n        \"\"\"\n        Determine if an agent should be executed based on its scheduling.\n\n        Args:\n            agent (object): The agent job to evaluate.\n            interval (int): Recurrence interval of the scheduled agent in seconds.\n\n        Returns:\n            bool: True if the agent should be executed, False otherwise.\n        \"\"\"\n        expiry_date = agent.expiry_date\n        expiry_runs = agent.expiry_runs\n        current_runs = agent.current_runs\n\n        # If there's no interval or there are no restrictions on when or how many times an agent can run\n        if not interval or (expiry_date is None and expiry_runs == -1):\n            return True\n\n        # Check if the agent's expiry date has not passed yet\n        if expiry_date and datetime.now() < expiry_date:\n            return True\n\n        # Check if the agent has not yet run as many times as allowed\n        if expiry_runs != -1 and current_runs < expiry_runs:\n            return True\n\n        # If none of the conditions to run the agent is met, return False (i.e., do not run the agent)\n        return False\n\n\n    def __can_remove_agent(self, agent, interval):\n        \"\"\"\n        Determine if an agent can be removed based on its scheduled expiry.\n\n        Args:\n            agent (object): The agent job to evaluate.\n            interval (int): Recurrence interval of the scheduled agent in seconds.\n\n        Returns:\n            bool: True if the agent can be removed, False otherwise.\n        \"\"\"\n        expiry_date = agent.expiry_date\n        expiry_runs = agent.expiry_runs\n        current_runs = agent.current_runs\n\n        # Calculate the next scheduled time only if an interval exists.\n        next_scheduled = agent.next_scheduled_time + timedelta(seconds=parse_interval_to_seconds(interval)) if interval else None\n\n        # If there's no interval, the agent can be removed\n        if not interval:\n            return True\n\n        # If the agent's expiry date has not come yet and next schedule is before expiry date, it cannot be removed\n        if expiry_date and datetime.now() < expiry_date and (next_scheduled is None or next_scheduled <= expiry_date):\n            return False\n\n        # If agent has not yet run as many times as allowed, it cannot be removed\n        if expiry_runs != -1 and current_runs < expiry_runs:\n            return False\n\n        # If there are no restrictions on when or how many times an agent can run, it cannot be removed\n        if expiry_date is None and expiry_runs == -1:\n            return False\n\n        # If none of the conditions to keep the agent is met, we return True (i.e., the agent can be removed)\n        return True\n\n    def __execute_schedule(self, should_execute_agent, interval_in_seconds, session, agent, agent_execution_name):\n        \"\"\"\n        Executes a scheduled job, if it should be executed.\n        Args:\n            should_execute_agent (bool): Whether agent should be executed.\n            interval_in_seconds (int): The interval in seconds for the schedule.\n            session (Session): The database session.\n            agent (object): The agent to be scheduled.\n            agent_execution_name (str): The name for the execution.\n        \"\"\"\n        from superagi.jobs.scheduling_executor import ScheduledAgentExecutor\n        if should_execute_agent:\n            executor = ScheduledAgentExecutor()\n            executor.execute_scheduled_agent(agent.agent_id, agent_execution_name)\n            agent.current_runs = agent.current_runs + 1\n\n            if agent.recurrence_interval:\n                next_scheduled_time = agent.next_scheduled_time + timedelta(seconds=interval_in_seconds)\n                agent.next_scheduled_time = next_scheduled_time\n\n            session.commit()"
  },
  {
    "path": "superagi/helper/auth.py",
    "content": "from fastapi import Depends, HTTPException, Header, Security, status\nfrom fastapi.security import APIKeyHeader\nfrom fastapi_jwt_auth import AuthJWT\nfrom fastapi_sqlalchemy import db\nfrom fastapi.security.api_key import APIKeyHeader\nfrom superagi.config.config import get_config\nfrom superagi.models.organisation import Organisation\nfrom superagi.models.user import User\nfrom superagi.models.api_key import ApiKey\nfrom typing import Optional\nfrom sqlalchemy import or_\n\n\ndef check_auth(Authorize: AuthJWT = Depends()):\n    \"\"\"\n    Function to check if the user is authenticated or not based on the environment.\n\n    Args:\n        Authorize (AuthJWT, optional): Instance of AuthJWT class to authorize the user. Defaults to Depends().\n\n    Returns:\n        AuthJWT: Instance of AuthJWT class if the user is authenticated.\n    \"\"\"\n    env = get_config(\"ENV\", \"DEV\")\n    if env == \"PROD\":\n        Authorize.jwt_required()\n    return Authorize\n\n\ndef get_user_organisation(Authorize: AuthJWT = Depends(check_auth)):\n    \"\"\"\n    Function to get the organisation of the authenticated user based on the environment.\n\n    Args:\n        Authorize (AuthJWT, optional): Instance of AuthJWT class to authorize the user. Defaults to Depends on check_auth().\n\n    Returns:\n        Organisation: Instance of Organisation class to which the authenticated user belongs.\n    \"\"\"\n    user = get_current_user(Authorize)\n    if user is None:\n        raise HTTPException(status_code=401, detail=\"Unauthenticated\")\n    organisation = db.session.query(Organisation).filter(Organisation.id == user.organisation_id).first()\n    return organisation\n\n\ndef get_current_user(Authorize: AuthJWT = Depends(check_auth), request: Request = Depends()):\n    env = get_config(\"ENV\", \"DEV\")\n\n    if env == \"DEV\":\n        email = \"super6@agi.com\"\n    else:\n        # Check for HTTP basic auth headers\n        auth_header = request.headers.get('Authorization')\n        if auth_header and auth_header.startswith('Basic '):\n            import base64\n            auth_decoded = base64.b64decode(auth_header.split(' ')[1]).decode('utf-8')\n            username, password = auth_decoded.split(':')\n            # Assuming username is the email\n            email = username\n        else:\n            # Retrieve the email of the logged-in user from the JWT token payload\n            email = Authorize.get_jwt_subject()\n\n    # Query the User table to find the user by their email\n    user = db.session.query(User).filter(User.email == email).first()\n    return user\n\napi_key_header = APIKeyHeader(name=\"X-API-Key\")\n\n\ndef validate_api_key(api_key: str = Security(api_key_header)) -> str:\n    query_result = db.session.query(ApiKey).filter(ApiKey.key == api_key,\n                                                   or_(ApiKey.is_expired == False, ApiKey.is_expired == None)).first()\n    if query_result is None:\n        raise HTTPException(\n            status_code=status.HTTP_401_UNAUTHORIZED,\n            detail=\"Invalid or missing API Key\",\n        )\n\n    return query_result.key\n\n\ndef get_organisation_from_api_key(api_key: str = Security(api_key_header)) -> Organisation:\n    query_result = db.session.query(ApiKey).filter(ApiKey.key == api_key,\n                                                   or_(ApiKey.is_expired == False, ApiKey.is_expired == None)).first()\n    if query_result is None:\n        raise HTTPException(\n            status_code=status.HTTP_401_UNAUTHORIZED,\n            detail=\"Invalid or missing API Key\",\n        )\n\n    organisation = db.session.query(Organisation).filter(Organisation.id == query_result.org_id).first()\n    return  organisation\n"
  },
  {
    "path": "superagi/helper/calendar_date.py",
    "content": "from datetime import datetime, timedelta, timezone\n\nimport pytz\n\n\nclass CalendarDate:\n    def create_event_dates(self, service, start_date, start_time, end_date, end_time):\n        local_tz = pytz.timezone(self._get_time_zone(service))\n        start_datetime, end_datetime = self._localize_daterange(start_date, end_date, start_time, end_time, local_tz)\n        date_utc = {\n            \"start_datetime_utc\": self._datetime_to_string(start_datetime, \"%Y-%m-%dT%H:%M:%S.%fZ\"),\n            \"end_datetime_utc\": self._datetime_to_string(end_datetime, \"%Y-%m-%dT%H:%M:%S.%fZ\"),\n            \"timeZone\": self._get_time_zone(service)\n        }\n        return date_utc\n\n    def get_date_utc(self, start_date, end_date, start_time, end_time, service):\n        local_tz = pytz.timezone(self._get_time_zone(service))\n        start_datetime, end_datetime = self._localize_daterange(start_date, end_date, start_time, end_time, local_tz)\n        date_utc = {\n            \"start_datetime_utc\": self._datetime_to_string(start_datetime, \"%Y-%m-%dT%H:%M:%S.%fZ\"),\n            \"end_datetime_utc\": self._datetime_to_string(end_datetime, \"%Y-%m-%dT%H:%M:%S.%fZ\")\n        }\n        return date_utc\n\n    def _get_time_zone(self, service):\n        calendar = service.calendars().get(calendarId='primary').execute()\n        time_detail = calendar['timeZone']\n        return time_detail\n\n    def _convert_to_utc(self, date_time, local_tz):\n        local_datetime = local_tz.localize(date_time)\n        gmt_tz = pytz.timezone(\"GMT\")\n        return local_datetime.astimezone(gmt_tz)\n\n    def _string_to_datetime(self, date_str, date_format):\n        return datetime.strptime(date_str, date_format) if date_str else None\n\n    def _localize_daterange(self, start_date, end_date, start_time, end_time, local_tz):\n        start_datetime = self._string_to_datetime(start_date, \"%Y-%m-%d\") if start_date != 'None' else datetime.now(\n            timezone.utc)\n        end_datetime = self._string_to_datetime(end_date,\n                                                \"%Y-%m-%d\") if end_date != 'None' else start_datetime + timedelta(\n            days=30) - timedelta(microseconds=1)\n        time_obj_start = self._string_to_datetime(start_time, \"%H:%M:%S\")\n        time_obj_end = self._string_to_datetime(end_time, \"%H:%M:%S\")\n        start_datetime = start_datetime.replace(hour=time_obj_start.hour, minute=time_obj_start.minute,\n                                                second=time_obj_start.second,\n                                                microsecond=0) if time_obj_start else start_datetime.replace(hour=0,\n                                                                                                             minute=0,\n                                                                                                             second=0,\n                                                                                                             microsecond=0)\n        end_datetime = end_datetime.replace(hour=time_obj_end.hour, minute=time_obj_end.minute,\n                                            second=time_obj_end.second) if time_obj_end else end_datetime.replace(\n            hour=23, minute=59, second=59, microsecond=999999)\n        return self._convert_to_utc(start_datetime, local_tz), self._convert_to_utc(end_datetime, local_tz)\n\n    def _datetime_to_string(self, date_time, date_format):\n        return date_time.strftime(date_format) if date_time else None\n"
  },
  {
    "path": "superagi/helper/encyption_helper.py",
    "content": "import base64\n\nfrom cryptography.fernet import Fernet, InvalidToken, InvalidSignature\nfrom superagi.config.config import get_config\nfrom superagi.lib.logger import logger\n# Generate a key\n# key = Fernet.generate_key()\n\nkey = get_config(\"ENCRYPTION_KEY\")\nif key is None:\n    raise Exception(\"Encryption key not found in config file.\")\n\nif len(key) != 32:\n    raise ValueError(\"Encryption key must be 32 bytes long.\")\n\n# Encode the key to UTF-8\nkey = key.encode(\n    \"utf-8\"\n)\n\n# base64 encode the key\nkey = base64.urlsafe_b64encode(key)\n\n# Create a cipher suite\ncipher_suite = Fernet(key)\n\n\ndef encrypt_data(data):\n    \"\"\"\n    Encrypts the given data using the Fernet cipher suite.\n\n    Args:\n        data (str): The data to be encrypted.\n\n    Returns:\n        str: The encrypted data, decoded as a string.\n    \"\"\"\n    encrypted_data = cipher_suite.encrypt(data.encode())\n    return encrypted_data.decode()\n\n\ndef decrypt_data(encrypted_data):\n    \"\"\"\n    Decrypts the given encrypted data using the Fernet cipher suite.\n\n    Args:\n        encrypted_data (str): The encrypted data to be decrypted.\n\n    Returns:\n        str: The decrypted data, decoded as a string.\n    \"\"\"\n    decrypted_data = cipher_suite.decrypt(encrypted_data.encode())\n    return decrypted_data.decode()\n\n\ndef is_encrypted(value):\n    #key = get_config(\"ENCRYPTION_KEY\")\n    try:\n        f = Fernet(key)\n        f.decrypt(value)\n        return True\n    except (InvalidToken, InvalidSignature):\n        return False\n    except (ValueError, TypeError):\n        return False\n"
  },
  {
    "path": "superagi/helper/error_handler.py",
    "content": "from superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\n\nclass ErrorHandler:\n\n    def handle_openai_errors(session, agent_id, agent_execution_id, error_message):\n        execution = session.query(AgentExecution).filter(AgentExecution.id == agent_execution_id).first()\n        agent_feed = AgentExecutionFeed(agent_execution_id=agent_execution_id, agent_id=agent_id, role=\"system\", feed=\"\", error_message=error_message, feed_group_id=execution.current_feed_group_id)\n        session.add(agent_feed)\n        session.commit()"
  },
  {
    "path": "superagi/helper/feed_parser.py",
    "content": "import json\nfrom datetime import datetime\n\nfrom superagi.helper.time_helper import get_time_difference\nfrom superagi.lib.logger import logger\n\n\ndef parse_feed(feed):\n    \"\"\"\n    Helper function to parse the feed.\n\n    Args:\n        feed (AgentExecutionFeed): The feed to be parsed.\n\n    Returns:\n        dict: Parsed feed information with role, feed content, and updated timestamp.\n              If parsing fails, the original feed is returned.\n    \"\"\"\n\n    # Get the current time\n    feed.time_difference = get_time_difference(feed.updated_at, str(datetime.now()))\n\n    # Check if the feed belongs to an assistant role\n    if feed.role == \"assistant\":\n        try:\n            # Parse the feed as JSON\n            parsed = json.loads(feed.feed, strict=False)\n\n            final_output = \"\"\n            if \"reasoning\" in parsed[\"thoughts\"]:\n                final_output = \"Thoughts: \" + parsed[\"thoughts\"][\"reasoning\"] + \"\\n\"\n            if \"plan\" in parsed[\"thoughts\"]:\n                final_output += \"Plan: \" + str(parsed[\"thoughts\"][\"plan\"]) + \"\\n\"\n            if \"criticism\" in parsed[\"thoughts\"]:\n                final_output += \"Criticism: \" + parsed[\"thoughts\"][\"criticism\"] + \"\\n\"\n            if \"tool\" in parsed:\n                final_output += \"Tool: \" + parsed[\"tool\"][\"name\"] + \"\\n\"\n            if \"command\" in parsed:\n                final_output += \"Tool: \" + parsed[\"command\"][\"name\"] + \"\\n\"\n\n            return {\"role\": \"assistant\", \"feed\": final_output, \"updated_at\": feed.updated_at,\n                    \"time_difference\": feed.time_difference}\n        except Exception:\n            return {\"role\": \"assistant\", \"feed\": feed.feed, \"updated_at\": feed.updated_at,\n                \"time_difference\": feed.time_difference}\n\n    if feed.role == \"system\":\n        final_output = feed.feed\n        if \"json-schema.org\" in feed.feed:\n            final_output = feed.feed.split(\"TOOLS:\")[0]\n        return {\"role\": \"system\", \"feed\": final_output, \"updated_at\": feed.updated_at,\n                \"time_difference\": feed.time_difference}\n    \n    if feed.role == \"user\":\n        return {\"role\": \"user\", \"feed\": feed.feed, \"updated_at\": feed.updated_at,\n                \"time_difference\": feed.time_difference}\n    \n    return feed\n"
  },
  {
    "path": "superagi/helper/github_helper.py",
    "content": "import base64\nimport re\n\nimport requests\nfrom superagi.lib.logger import logger\nfrom superagi.helper.resource_helper import ResourceHelper\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.types.storage_types import StorageType\nfrom superagi.config.config import get_config\nfrom superagi.helper.s3_helper import S3Helper\nfrom datetime import timedelta, datetime\nimport json\n\nclass GithubHelper:\n    def __init__(self, github_access_token, github_username):\n        \"\"\"\n        Initializes the GithubHelper with the provided access token and username.\n\n        Args:\n            github_access_token (str): Personal GitHub access token.\n            github_username (str): GitHub username.\n        \"\"\"\n        self.github_access_token = github_access_token\n        self.github_username = github_username\n\n    def get_file_path(self, file_name, folder_path):\n        \"\"\"\n        Returns the path of the given file with respect to the specified folder.\n\n        Args:\n            file_name (str): Name of the file.\n            folder_path (str): Path to the folder.\n\n        Returns:\n            str: Combined file path.\n        \"\"\"\n        file_path = f'{folder_path}'\n        if folder_path:\n            file_path += '/'\n        file_path += file_name\n        return file_path\n\n    def check_repository_visibility(self, repository_owner, repository_name):\n        \"\"\"\n        Checks the visibility (public/private) of a given repository.\n\n\n        Args:\n            repository_owner (str): Owner of the repository.\n            repository_name (str): Name of the repository.\n\n        Returns:\n            bool: True if the repository is private, False if it's public.\n        \"\"\"\n        url = f\"https://api.github.com/repos/{repository_owner}/{repository_name}\"\n        headers = {\n            \"Authorization\": f\"Token {self.github_access_token}\",\n            \"Accept\": \"application/vnd.github.v3+json\"\n        }\n        response = requests.get(url, headers=headers)\n        if response.status_code == 200:\n            repository_data = response.json()\n            return repository_data['private']\n        else:\n            logger.info(f\"Failed to fetch repository information: {response.status_code} - {response.text}\")\n            return None\n\n    def search_repo(self, repository_owner, repository_name, file_name, folder_path=None):\n        \"\"\"\n        Searches for a file in the given repository and returns the file's metadata.\n\n        Args:\n            repository_owner (str): Owner of the repository.\n            repository_name (str): Name of the repository.\n            file_name (str): Name of the file to search for.\n            folder_path (str, optional): Path to the folder containing the file. Defaults to None.\n\n        Returns:\n            dict: File metadata.\n        \"\"\"\n        headers = {\n            \"Authorization\": f\"token {self.github_access_token}\" if self.github_access_token else None,\n            \"Content-Type\": \"application/vnd.github+json\"\n        }\n        file_path = self.get_file_path(file_name, folder_path)\n        url = f'https://api.github.com/repos/{repository_owner}/{repository_name}/contents/{file_path}'\n        r = requests.get(url, headers=headers)\n        r.raise_for_status()\n        data = r.json()\n\n        return data\n\n    def sync_branch(self, repository_owner, repository_name, base_branch, head_branch, headers):\n        \"\"\"\n        Syncs the head branch with the base branch.\n\n        Args:\n            repository_owner (str): Owner of the repository.\n            repository_name (str): Name of the repository.\n            base_branch (str): Base branch to sync with.\n            head_branch (str): Head branch to sync.\n            headers (dict): Request headers.\n\n        Returns:\n            None\n        \"\"\"\n        base_branch_url = f'https://api.github.com/repos/{repository_owner}/{repository_name}/branches/{base_branch}'\n        response = requests.get(base_branch_url, headers=headers)\n        response_json = response.json()\n        base_commit_sha = response_json['commit']['sha']\n        head_branch_url = f'https://api.github.com/repos/{self.github_username}/{repository_name}/git/refs/heads/{head_branch}'\n        data = {\n            'sha': base_commit_sha,\n            'force': True\n        }\n        response = requests.patch(head_branch_url, json=data, headers=headers)\n        if response.status_code == 200:\n            logger.info(\n                f'Successfully synced {self.github_username}:{head_branch} branch with {repository_owner}:{base_branch}')\n        else:\n            logger.info('Failed to sync the branch. Check your inputs and permissions.')\n\n    def make_fork(self, repository_owner, repository_name, base_branch, headers):\n        \"\"\"\n        Creates a fork of the given repository.\n\n        Args:\n            repository_owner (str): Owner of the repository.\n            repository_name (str): Name of the repository.\n            base_branch (str): Base branch to sync with.\n            headers (dict): Request headers.\n\n        Returns:\n            int: Status code of the fork request.\n        \"\"\"\n        fork_url = f'https://api.github.com/repos/{repository_owner}/{repository_name}/forks'\n        fork_response = requests.post(fork_url, headers=headers)\n        if fork_response.status_code == 202:\n            logger.info('Fork created successfully.')\n            self.sync_branch(repository_owner, repository_name, base_branch, base_branch, headers)\n        else:\n            logger.info('Failed to create the fork:', fork_response.json()['message'])\n\n        return fork_response.status_code\n\n    def create_branch(self, repository_name, base_branch, head_branch, headers):\n        \"\"\"\n        Creates a new branch in the given repository.\n\n        Args:\n            repository_name (str): Name of the repository.\n            base_branch (str): Base branch to sync with.\n            head_branch (str): Head branch to sync.\n            headers (dict): Request headers.\n\n        Returns:\n            int: Status code of the branch creation request.\n        \"\"\"\n        branch_url = f'https://api.github.com/repos/{self.github_username}/{repository_name}/git/refs'\n        branch_params = {\n            'ref': f'refs/heads/{head_branch}',\n            'sha': requests.get(\n                f'https://api.github.com/repos/{self.github_username}/{repository_name}/git/refs/heads/{base_branch}',\n                headers=headers).json()['object']['sha']\n        }\n        branch_response = requests.post(branch_url, json=branch_params, headers=headers)\n        if branch_response.status_code == 201:\n            logger.info('Branch created successfully.')\n        elif branch_response.status_code == 422:\n            logger.info('Branch new-file already exists, making commits to new-file branch')\n        else:\n            logger.info('Failed to create branch:', branch_response.json()['message'])\n\n        return branch_response.status_code\n\n    def delete_file(self, repository_name, file_name, folder_path, commit_message, head_branch, headers):\n        \"\"\"\n        Deletes a file or folder from the given repository.\n\n        Args:\n            repository_name (str): Name of the repository.\n            file_name (str): Name of the file to delete.\n            folder_path (str): Path to the folder containing the file.\n            commit_message (str): Commit message.\n            head_branch (str): Head branch to sync.\n            headers (dict): Request headers.\n\n        Returns:\n            int: Status code of the file deletion request.\n        \"\"\"\n        file_path = self.get_file_path(file_name, folder_path)\n        file_url = f'https://api.github.com/repos/{self.github_username}/{repository_name}/contents/{file_path}'\n        file_params = {\n            'message': commit_message,\n            'sha': self.get_sha(self.github_username, repository_name, file_name, folder_path),\n            'branch': head_branch\n        }\n        file_response = requests.delete(file_url, json=file_params, headers=headers)\n        if file_response.status_code == 200:\n            logger.info('File or folder delete successfully.')\n        else:\n            logger.info('Failed to Delete file or folder:', file_response.json())\n\n        return file_response.status_code\n\n    def add_file(self, repository_owner, repository_name, file_name, folder_path, head_branch, base_branch, headers, commit_message, agent_id, agent_execution_id, session):\n        \"\"\"\n        Adds a file to the given repository.\n\n        Args:\n            repository_owner (str): Owner of the repository.\n            repository_name (str): Name of the repository.\n            file_name (str): Name of the file to add.\n            folder_path (str): Path to the folder containing the file.\n            head_branch (str): Head branch to sync.\n            base_branch (str): Base branch to sync with.\n\n        Returns:\n            None\n        \"\"\"\n        body = self._get_file_contents(file_name, agent_id, agent_execution_id, session)\n        body_bytes = body.encode(\"ascii\")\n        base64_bytes = base64.b64encode(body_bytes)\n        file_content = base64_bytes.decode(\"ascii\")\n        file_path = self.get_file_path(file_name, folder_path)\n        file_url = f'https://api.github.com/repos/{repository_owner}/{repository_name}/contents/{file_path}'\n        file_params = {\n            'message': commit_message,\n            'content': file_content,\n            'branch': head_branch\n        }\n        file_response = requests.put(file_url, json=file_params, headers=headers)\n        if file_response.status_code == 201:\n            logger.info('File content uploaded successfully.')\n        elif file_response.status_code == 422:\n            logger.info('File already exists')\n        else:\n            logger.info('Failed to upload file content:', file_response.json()['message'])\n        return file_response.status_code\n\n\n    def create_pull_request(self, repository_owner, repository_name, head_branch, base_branch, headers):\n        \"\"\"\n        Creates a pull request in the given repository.\n\n        Args:\n            repository_owner (str): Owner of the repository.\n            repository_name (str): Name of the repository.\n            head_branch (str): Head branch to sync.\n            base_branch (str): Base branch to sync with.\n            headers (dict): Request headers.\n\n        Returns:\n            int: Status code of the pull request creation request.\n        \"\"\"\n        pull_request_url = f'https://api.github.com/repos/{repository_owner}/{repository_name}/pulls'\n        pull_request_params = {\n            'title': f'Pull request by {self.github_username}',\n            'body': 'Please review and merge this change.',\n            'head': f'{self.github_username}:{head_branch}',  # required for cross repository only\n            'head_repo': repository_name,  # required for cross repository only\n            'base': base_branch\n        }\n        pr_response = requests.post(pull_request_url, json=pull_request_params, headers=headers)\n\n        if pr_response.status_code == 201:\n            logger.info('Pull request created successfully.')\n        elif pr_response.status_code == 422:\n            logger.info('Added changes to already existing pull request')\n        else:\n            logger.info('Failed to create pull request:', pr_response.json()['message'])\n\n        return pr_response.status_code\n\n    def get_sha(self, repository_owner, repository_name, file_name, folder_path=None):\n        \"\"\"\n        Gets the sha of the file to be deleted.\n\n        Args:\n            repository_owner (str): Owner of the repository.\n            repository_name (str): Name of the repository.\n            file_name (str): Name of the file to delete.\n            folder_path (str): Path to the folder containing the file.\n\n        Returns:\n            str: Sha of the file to be deleted.\n        \"\"\"\n        data = self.search_repo(repository_owner, repository_name, file_name, folder_path)\n        return data['sha']\n\n    def get_content_in_file(self, repository_owner, repository_name, file_name, folder_path=None):\n        \"\"\"\n        Gets the content of the file.\n\n        Args:\n            repository_owner (str): Owner of the repository.\n            repository_name (str): Name of the repository.\n            file_name (str): Name of the file to delete.\n            folder_path (str): Path to the folder containing the file.\n\n        Returns:\n            str: Content of the file.\n        \"\"\"\n        data = self.search_repo(repository_owner, repository_name, file_name, folder_path)\n        file_content = data['content']\n        file_content_encoding = data.get('encoding')\n        if file_content_encoding == 'base64':\n            file_content = base64.b64decode(file_content).decode()\n\n        return file_content\n\n    @classmethod\n    def validate_github_link(cls, link: str) -> bool:\n        \"\"\"\n        Validate a GitHub link.\n        Returns True if the link is valid, False otherwise.\n        \"\"\"\n        # Regular expression pattern to match a GitHub link\n        pattern = r'^https?://(?:www\\.)?github\\.com/[\\w\\-]+/[\\w\\-]+$'\n\n        # Check if the link matches the pattern\n        if re.match(pattern, link):\n            return True\n\n        return False\n\n    def _get_file_contents(self, file_name, agent_id, agent_execution_id, session):\n        final_path = ResourceHelper().get_agent_read_resource_path(file_name,\n                                                                    agent=Agent.get_agent_from_id(session, agent_id),\n                                                                    agent_execution=AgentExecution.get_agent_execution_from_id(\n                                                                  session, agent_execution_id))\n\n        if StorageType.get_storage_type(get_config(\"STORAGE_TYPE\", StorageType.FILE.value)) == StorageType.S3:\n                attachment_data = S3Helper().read_from_s3(final_path)\n        else:\n            with open(final_path, \"r\") as file:\n                attachment_data = file.read().decode('utf-8')\n        return attachment_data\n\n\n    def get_pull_request_content(self, repository_owner, repository_name, pull_request_number):\n        \"\"\"\n        Gets the content of a specific pull request from a GitHub repository.\n\n        Args:\n            repository_owner (str): Owner of the repository.\n            repository_name (str): Name of the repository.\n            pull_request_number (int): pull request id.\n            headers (dict): Dictionary containing the headers, usually including the Authorization token.\n\n        Returns:\n            dict: Dictionary containing the pull request content or None if not found.\n        \"\"\"\n        pull_request_url = f'https://api.github.com/repos/{repository_owner}/{repository_name}/pulls/{pull_request_number}'\n        headers = {\n            \"Authorization\": f\"token {self.github_access_token}\" if self.github_access_token else None,\n            \"Content-Type\": \"application/vnd.github+json\",\n            \"Accept\": \"application/vnd.github.v3.diff\",\n        }\n\n        response = requests.get(pull_request_url, headers=headers)\n\n        if response.status_code == 200:\n            logger.info('Successfully fetched pull request content.')\n            return response.text\n        elif response.status_code == 404:\n            logger.warning('Pull request not found.')\n        else:\n            logger.warning('Failed to fetch pull request content: ', response.text)\n\n        return None\n\n    def get_latest_commit_id_of_pull_request(self, repository_owner, repository_name, pull_request_number):\n        \"\"\"\n        Gets the latest commit id of a specific pull request from a GitHub repository.\n        :param repository_owner: owner\n        :param repository_name: repository name\n        :param pull_request_number: pull request id\n\n        :return:\n        latest commit id of the pull request\n        \"\"\"\n        url = f'https://api.github.com/repos/{repository_owner}/{repository_name}/pulls/{pull_request_number}/commits'\n        headers = {\n            \"Authorization\": f\"token {self.github_access_token}\" if self.github_access_token else None,\n            \"Content-Type\": \"application/json\",\n        }\n        response = requests.get(url, headers=headers)\n        if response.status_code == 200:\n            commits = response.json()\n            latest_commit = commits[-1]  # Assuming the last commit is the latest\n            return latest_commit.get('sha')\n        else:\n            logger.warning(f'Failed to fetch commits for pull request: {response.json()[\"message\"]}')\n            return None\n\n\n    def add_line_comment_to_pull_request(self, repository_owner, repository_name, pull_request_number,\n                                         commit_id, file_path, position, comment_body):\n        \"\"\"\n        Adds a line comment to a specific pull request from a GitHub repository.\n\n        :param repository_owner: owner\n        :param repository_name: repository name\n        :param pull_request_number: pull request id\n        :param commit_id: commit id\n        :param file_path: file path\n        :param position: position\n        :param comment_body: comment body\n\n        :return:\n        dict: Dictionary containing the comment content or None if not found.\n        \"\"\"\n        comments_url = f'https://api.github.com/repos/{repository_owner}/{repository_name}/pulls/{pull_request_number}/comments'\n        headers = {\n            \"Authorization\": f\"token {self.github_access_token}\",\n            \"Content-Type\": \"application/json\",\n            \"Accept\": \"application/vnd.github.v3+json\"\n        }\n        data = {\n            \"commit_id\": commit_id,\n            \"path\": file_path,\n            \"position\": position,\n            \"body\": comment_body\n        }\n        response = requests.post(comments_url, headers=headers, json=data)\n        if response.status_code == 201:\n            logger.info('Successfully added line comment to pull request.')\n            return response.json()\n        else:\n            logger.warning(f'Failed to add line comment: {response.json()[\"message\"]}')\n            return None\n\n    def get_pull_requests_created_in_last_x_seconds(self, repository_owner, repository_name, x_seconds):\n        \"\"\"\n        Gets the pull requests created in the last x seconds.\n\n        Args:\n            repository_owner (str): Owner of the repository\n            repository_name (str): Repository name\n            x_seconds (int): The number of seconds in the past to look for PRs\n\n        Returns:\n            list: List of pull request objects that were created in the last x seconds\n        \"\"\"\n        # Calculate the time x seconds ago\n        time_x_seconds_ago = datetime.utcnow() - timedelta(seconds=x_seconds)\n\n        # Convert to the ISO8601 format GitHub expects, remove milliseconds\n        time_x_seconds_ago_str = time_x_seconds_ago.strftime('%Y-%m-%dT%H:%M:%SZ')\n\n        # Search query\n        query = f'repo:{repository_owner}/{repository_name} type:pr created:>{time_x_seconds_ago_str}'\n\n        url = f'https://api.github.com/search/issues?q={query}'\n        headers = {\n            \"Authorization\": f\"token {self.github_access_token}\",\n            \"Content-Type\": \"application/json\",\n        }\n\n        response = requests.get(url, headers=headers)\n\n        if response.status_code == 200:\n            pull_request_urls = []\n            for pull_request in response.json()['items']:\n                pull_request_urls.append(pull_request['html_url'])\n            return pull_request_urls\n        else:\n            logger.warning(f'Failed to fetch PRs: {response.json()[\"message\"]}')\n            return []\n"
  },
  {
    "path": "superagi/helper/google_calendar_creds.py",
    "content": "import pickle\nimport os\nimport json\nimport ast\nfrom  datetime import datetime\nfrom google.oauth2.credentials import Credentials\nfrom google_auth_oauthlib.flow import Flow\nfrom google.auth.transport.requests import Request\nfrom superagi.config.config import get_config\nfrom googleapiclient.discovery import build\nfrom sqlalchemy.orm import sessionmaker\nfrom superagi.models.db import connect_db\nfrom sqlalchemy.orm import Session\nfrom superagi.models.tool_config import ToolConfig\nfrom superagi.resource_manager.file_manager import FileManager\nfrom superagi.models.toolkit import Toolkit\nfrom superagi.models.oauth_tokens import OauthTokens\nfrom superagi.helper.encyption_helper import decrypt_data, is_encrypted\n\nclass GoogleCalendarCreds:\n\n    def __init__(self, session: Session):\n        self.session = session\n\n    def get_credentials(self, toolkit_id):\n        toolkit = self.session.query(Toolkit).filter(Toolkit.id == toolkit_id).first()\n        organisation_id = toolkit.organisation_id\n        google_creds = self.session.query(OauthTokens).filter(OauthTokens.toolkit_id == toolkit_id, OauthTokens.organisation_id == organisation_id).first()\n        if google_creds:\n            user_id = google_creds.user_id\n            final_creds = json.loads(google_creds.value)\n            final_creds[\"refresh_token\"] = self.fix_refresh_token(final_creds[\"refresh_token\"])\n            expire_time = datetime.strptime(final_creds[\"expiry\"], \"%Y-%m-%dT%H:%M:%S.%fZ\")\n            google_creds = self.session.query(ToolConfig).filter(ToolConfig.toolkit_id == toolkit_id).all()\n            client_id = \"\"\n            client_secret = \"\"\n            for credentials in google_creds:\n                credentials = credentials.__dict__\n                if credentials[\"key\"] == \"GOOGLE_CLIENT_ID\":\n                    if is_encrypted(credentials[\"value\"]):\n                        client_id = decrypt_data(credentials[\"value\"])\n                    else:\n                        client_id = credentials[\"value\"]\n                if credentials[\"key\"] == \"GOOGLE_CLIENT_SECRET\":\n                    if is_encrypted(credentials[\"value\"]):\n                        client_secret = decrypt_data(credentials[\"value\"])\n                    else:\n                        client_secret = credentials[\"value\"]\n            creds = Credentials.from_authorized_user_info(info={\n                \"client_id\": client_id,\n                \"client_secret\": client_secret,\n                \"refresh_token\": final_creds[\"refresh_token\"],\n                \"scopes\": \"https://www.googleapis.com/auth/calendar\"\n            })\n            if expire_time > datetime.utcnow():\n                creds.refresh(Request())\n                creds_json = creds.to_json()\n                tokens = OauthTokens().add_or_update(self.session, toolkit_id, user_id, toolkit.organisation_id, \"GOOGLE_CALENDAR_OAUTH_TOKENS\", str(creds_json))\n        else:\n            return {\"success\": False}\n        service = build('calendar','v3',credentials=creds)\n        return {\"success\": True, \"service\": service}\n    \n    def fix_refresh_token(self, refresh_token):\n        if refresh_token.count('/') == 1:\n            # Find the position of '/'\n            slash_index = refresh_token.index('/')\n            # Insert one more '/' at the position\n            refresh_token = refresh_token[:slash_index+1] + '/' + refresh_token[slash_index+1:]\n        return refresh_token"
  },
  {
    "path": "superagi/helper/google_search.py",
    "content": "import requests\nimport time\nfrom pydantic import BaseModel\nfrom superagi.lib.logger import logger\n\nfrom superagi.helper.webpage_extractor import WebpageExtractor\n\n\nclass GoogleSearchWrap:\n\n    def __init__(self, api_key, search_engine_id, num_results=3, num_pages=1, num_extracts=3):\n        \"\"\"\n        Initialize the GoogleSearchWrap class.\n\n        Args:\n            api_key (str): Google API key\n            search_engine_id (str): Google Search Engine ID\n            num_results (int): Number of results per page\n            num_pages (int): Number of pages to search\n            num_extracts (int): Number of extracts to extract from each webpage\n        \"\"\"\n\n        self.api_key = api_key\n        self.search_engine_id = search_engine_id\n        self.num_results = num_results\n        self.num_pages = num_pages\n        self.num_extracts = num_extracts\n        self.extractor = WebpageExtractor()\n\n    def search_run(self, query):\n        \"\"\"\n        Run the Google search.\n\n        Args:\n            query (str): The query to search for.\n\n        Returns:\n            list: A list of extracts from the search results.\n        \"\"\"\n        all_snippets = []\n        links = []\n        for page in range(1, self.num_pages * self.num_results, self.num_results):\n            url = \"https://www.googleapis.com/customsearch/v1\"\n            params = {\n                \"key\": self.api_key,\n                \"cx\": self.search_engine_id,\n                \"q\": query,\n                \"num\": self.num_results,\n                \"start\": page\n            }\n            response = requests.get(url, params=params, timeout=100)\n\n            if response.status_code == 200:\n                try:\n                    json_data = response.json()\n                    if \"items\" in json_data:\n                        for item in json_data[\"items\"]:\n                            all_snippets.append(item[\"snippet\"])\n                            links.append(item[\"link\"])\n                    else:\n                        logger.info(\"No items found in the response.\")\n                except ValueError as e:\n                    logger.error(f\"Error while parsing JSON data: {e}\")\n            else:\n                logger.error(f\"Error: {response.status_code}\")\n\n        return all_snippets, links, response.status_code\n\n    def get_result(self, query):\n        \"\"\"\n        Get the result of the Google search.\n\n        Args:\n            query (str): The query to search for.\n\n        Returns:\n            list: A list of extracts from the search results.\n        \"\"\"\n        snippets, links, error_code = self.search_run(query)\n\n        webpages = []\n        attempts = 0\n        while snippets == [] and attempts < 2:\n            attempts += 1\n            logger.info(\"Google blocked the request. Trying again...\")\n            time.sleep(3)\n            snippets, links, error_code = self.search_run(query)\n\n        if links:\n            for i in range(0, self.num_extracts):\n                time.sleep(3)\n                content = \"\"\n                # content = self.extractor.extract_with_3k(links[i])\n                # attempts = 0\n                # while content == \"\" and attempts < 2:\n                #     attempts += 1\n                #     content = self.extractor.extract_with_3k(links[i])\n                content = self.extractor.extract_with_bs4(links[i])\n                max_length = len(' '.join(content.split(\" \")[:500]))\n                content = content[:max_length]\n                attempts = 0\n                while content == \"\" and attempts < 2:\n                    attempts += 1\n                    content = self.extractor.extract_with_bs4(links[i])\n                    content = content[:max_length]\n                webpages.append(content)\n        else:\n            snippets = []\n            links = []\n            webpages = []\n\n        return snippets, webpages, links"
  },
  {
    "path": "superagi/helper/google_serp.py",
    "content": "import asyncio\nfrom typing import Any, List\n\nimport aiohttp\n\nfrom superagi.config.config import get_config\nfrom superagi.helper.webpage_extractor import WebpageExtractor\n\n\nclass GoogleSerpApiWrap:\n    def __init__(self, api_key, num_results=10, num_pages=1, num_extracts=3):\n        \"\"\"\n        Initialize the GoogleSerpApiWrap class.\n\n        Args:\n            api_key (str): Google API key\n            num_results (int): Number of results per page\n            num_pages (int): Number of pages to search\n            num_extracts (int): Number of extracts to extract from each webpage\n        \"\"\"\n        self.api_key = api_key\n        self.num_results = num_results\n        self.num_pages = num_pages\n        self.num_extracts = num_extracts\n        self.extractor = WebpageExtractor()\n\n    def search_run(self, query):\n        \"\"\"\n        Run the Google search.\n\n        Args:\n            query (str): The query to search for.\n\n        Returns:\n            list: A list of extracts from the search results.\n        \"\"\"\n        results = asyncio.run(self.fetch_serper_results(query=query))\n        response = self.process_response(results)\n        return response\n\n    async def fetch_serper_results(self,\n                                   query: str, search_type: str = \"search\"\n                                   ) -> dict[str, Any]:\n        \"\"\"\n        Fetch the search results from the SerpApi.\n\n        Args:\n            query (str): The query to search for.\n            search_type (str): The type of search to perform.\n\n        Returns:\n            dict: The search results.\n        \"\"\"\n        headers = {\n            \"X-API-KEY\": self.api_key or \"\",\n            \"Content-Type\": \"application/json\",\n        }\n        params = {\"q\": query,}\n        async with aiohttp.ClientSession() as session:\n            async with session.post(\n                    f\"https://google.serper.dev/{search_type}\", headers=headers, params=params\n            ) as response:\n                response.raise_for_status()\n                search_results = await response.json()\n                return search_results\n\n    def process_response(self, results) -> str:\n        \"\"\"\n        Process the search results.\n\n        Args:\n            results (dict): The search results.\n\n        Returns:\n            str: The processed search results.\n        \"\"\"\n        snippets: List[str] = []\n        links: List[str] = []\n\n        if results.get(\"answerBox\"):\n            answer_values = []\n            answer_box = results.get(\"answerBox\", {})\n            if answer_box.get(\"answer\"):\n                answer_values.append(answer_box.get(\"answer\"))\n            elif answer_box.get(\"snippet\"):\n                answer_values.append(answer_box.get(\"snippet\").replace(\"\\n\", \" \"))\n            elif answer_box.get(\"snippetHighlighted\"):\n                answer_values.append(\", \".join(answer_box.get(\"snippetHighlighted\")))\n\n            if len(answer_values) > 0:\n                snippets.append(\"\\n\".join(answer_values))\n\n        if results.get(\"knowledgeGraph\"):\n            knowledge_graph = results.get(\"knowledgeGraph\", {})\n            title = knowledge_graph.get(\"title\")\n            entity_type = knowledge_graph.get(\"type\")\n            if entity_type:\n                snippets.append(f\"{title}: {entity_type}.\")\n            description = knowledge_graph.get(\"description\")\n            if description:\n                snippets.append(description)\n            for attribute, value in knowledge_graph.get(\"attributes\", {}).items():\n                snippets.append(f\"{title} {attribute}: {value}.\")\n\n        for result in results[\"organic\"][:self.num_results]:\n            if \"snippet\" in result:\n                snippets.append(result[\"snippet\"])\n            if \"link\" in result and len(links) < self.num_results:\n                links.append(result[\"link\"])\n            for attribute, value in result.get(\"attributes\", {}).items():\n                snippets.append(f\"{attribute}: {value}.\")\n\n        if len(snippets) == 0:\n            return {\"snippets\": \"No good Google Search Result was found\", \"links\": []}\n\n        return {\"links\": links, \"snippets\": snippets}\n"
  },
  {
    "path": "superagi/helper/imap_email.py",
    "content": "import imaplib\n\n\nclass ImapEmail:\n\n    def imap_open(self, imap_folder, email_sender, email_password, imap_server) -> imaplib.IMAP4_SSL:\n        \"\"\"\n        Function to open an IMAP connection to the email server.\n\n        Args:\n            imap_folder (str): The folder to open.\n            email_sender (str): The email address of the sender.\n            email_password (str): The password of the sender.\n\n        Returns:\n            imaplib.IMAP4_SSL: The IMAP connection.\n        \"\"\"\n        conn = imaplib.IMAP4_SSL(imap_server)\n        conn.login(email_sender, email_password)\n        conn.select(imap_folder)\n        return conn\n\n    def adjust_imap_folder(self, imap_folder, email_sender) -> str:\n        \"\"\"\n        Function to adjust the IMAP folder based on the email address of the sender.\n\n        Args:\n            imap_folder (str): The folder to open.\n            email_sender (str): The email address of the sender.\n\n        Returns:\n            str: The adjusted IMAP folder.\n        \"\"\"\n        if \"@gmail\" in email_sender.lower():\n            if \"sent\" in imap_folder.lower():\n                return '\"[Gmail]/Sent Mail\"'\n            if \"draft\" in imap_folder.lower():\n                return '\"[Gmail]/Drafts\"'\n        return imap_folder\n"
  },
  {
    "path": "superagi/helper/json_cleaner.py",
    "content": "import json\nimport re\nfrom superagi.lib.logger import logger\n\nimport json5\n\n\nclass JsonCleaner:\n\n    @classmethod\n    def clean_boolean(cls, input_str: str = \"\"):\n        \"\"\"\n        Clean the boolean values in the given string.\n\n        Args:\n            input_str (str): The string from which the json section is to be extracted.\n\n        Returns:\n            str: The extracted json section.\n        \"\"\"\n        input_str = re.sub(r':\\s*false', ': False', input_str)\n        input_str = re.sub(r':\\s*true', ': True', input_str)\n        return input_str\n\n\n    @classmethod\n    def extract_json_section(cls, input_str: str = \"\"):\n        \"\"\"\n        Extract the json section from the given string.\n\n        Args:\n            input_str (str): The string from which the json section is to be extracted.\n\n        Returns:\n            str: The extracted json section.\n        \"\"\"\n        try:\n            first_brace_index = input_str.index(\"{\")\n            final_json = input_str[first_brace_index:]\n            last_brace_index = final_json.rindex(\"}\")\n            final_json = final_json[: last_brace_index + 1]\n            return final_json\n        except ValueError:\n            pass\n        return input_str\n\n    @classmethod\n    def extract_json_array_section(cls, input_str: str = \"\"):\n        \"\"\"\n        Extract the json section from the given string.\n\n        Args:\n            input_str (str): The string from which the json section is to be extracted.\n\n        Returns:\n            str: The extracted json section.\n        \"\"\"\n        try:\n            first_brace_index = input_str.index(\"[\")\n            final_json = input_str[first_brace_index:]\n            last_brace_index = final_json.rindex(\"]\")\n            final_json = final_json[: last_brace_index + 1]\n            return final_json\n        except ValueError:\n            pass\n        return input_str\n\n    @classmethod\n    def remove_escape_sequences(cls, string):\n        \"\"\"\n        Remove escape sequences from the given string.\n\n        Args:\n            string (str): The string from which the escape sequences are to be removed.\n\n        Returns:\n            str: The string with escape sequences removed.\n        \"\"\"\n        return string.encode('utf-8').decode('unicode_escape').encode('raw_unicode_escape').decode('utf-8')\n\n    @classmethod\n    def balance_braces(cls, json_string: str) -> str:\n        \"\"\"\n        Balance the braces in the given json string.\n\n        Args:\n            json_string (str): The json string to be processed.\n\n        Returns:\n            str: The json string with balanced braces.\n        \"\"\"\n        open_braces_count = json_string.count('{')\n        closed_braces_count = json_string.count('}')\n\n        while closed_braces_count > open_braces_count:\n            json_string = json_string.rstrip(\"}\")\n            closed_braces_count -= 1\n\n        open_braces_count = json_string.count('{')\n        closed_braces_count = json_string.count('}')\n\n        if open_braces_count > closed_braces_count:\n            json_string += '}' * (open_braces_count - closed_braces_count)\n\n        return json_string\n\n\n"
  },
  {
    "path": "superagi/helper/llm_loader.py",
    "content": "from llama_cpp import Llama\nfrom llama_cpp import LlamaGrammar\nfrom superagi.config.config import get_config\nfrom superagi.lib.logger import logger\n\n\nclass LLMLoader:\n    _instance = None\n    _model = None\n    _grammar = None\n\n    def __new__(cls, *args, **kwargs):\n        if cls._instance is None:\n            cls._instance = super(LLMLoader, cls).__new__(cls)\n        return cls._instance\n\n    def __init__(self, context_length):\n        self.context_length = context_length\n\n    @property\n    def model(self):\n        if self._model is None:\n            try:\n                self._model = Llama(\n                    model_path=\"/app/local_model_path\", n_ctx=self.context_length, n_gpu_layers=int(get_config('GPU_LAYERS', '-1')))\n            except Exception as e:\n                logger.error(e)\n        return self._model\n\n    @property\n    def grammar(self):\n        if self._grammar is None:\n            try:\n                self._grammar = LlamaGrammar.from_file(\n                    \"superagi/llms/grammar/json.gbnf\")\n            except Exception as e:\n                logger.error(e)\n        return self._grammar\n"
  },
  {
    "path": "superagi/helper/models_helper.py",
    "content": "from superagi.llms.hugging_face import HuggingFace\n\nclass ModelsHelper:\n    @staticmethod\n    def validate_end_point(model_api_key, end_point, model_provider):\n        response = {\"success\": True}\n\n        if (model_provider == 'Hugging Face'):\n            try:\n                result = HuggingFace(api_key=model_api_key, end_point=end_point).verify_end_point()\n            except Exception as e:\n                response['success'] = False\n                response['error'] = str(e)\n            else:\n                response['result'] = result\n\n        return response\n\n\n"
  },
  {
    "path": "superagi/helper/prompt_reader.py",
    "content": "from pathlib import Path\n\n\nclass PromptReader:\n    @staticmethod\n    def read_tools_prompt(current_file: str, prompt_file: str) -> str:\n        file_path = str(Path(current_file).resolve().parent) + \"/prompts/\" + prompt_file\n        try:\n            f = open(file_path, \"r\")\n            file_content = f.read()\n            f.close()\n        except FileNotFoundError as e:\n            print(e.__str__())\n            raise e\n        return file_content\n\n    @staticmethod\n    def read_agent_prompt(current_file: str, prompt_file: str) -> str:\n        file_path = str(Path(current_file).resolve().parent) + \"/prompts/\" + prompt_file\n        try:\n            f = open(file_path, \"r\")\n            file_content = f.read()\n            f.close()\n        except FileNotFoundError as e:\n            print(e.__str__())\n            raise e\n        return file_content\n"
  },
  {
    "path": "superagi/helper/read_email.py",
    "content": "import os\nimport re\nfrom email.header import decode_header\n\nfrom bs4 import BeautifulSoup\n\n\nclass ReadEmail:\n    def clean_email_body(self, email_body):\n        \"\"\"\n        Function to clean the email body.\n\n        Args:\n            email_body (str): The email body to be cleaned.\n\n        Returns:\n            str: The cleaned email body.\n        \"\"\"\n        if email_body is None: email_body = \"\"\n        email_body = BeautifulSoup(email_body, \"html.parser\")\n        email_body = email_body.get_text()\n        email_body = \"\".join(email_body.splitlines())\n        email_body = \" \".join(email_body.split())\n        email_body = email_body.encode(\"ascii\", \"ignore\")\n        email_body = email_body.decode(\"utf-8\", \"ignore\")\n        email_body = re.sub(r\"http\\S+\", \"\", email_body)\n        return email_body\n\n    def clean(self, text):\n        \"\"\"\n        Function to clean the text.\n\n        Args:\n            text (str): The text to be cleaned.\n\n        Returns:\n            str: The cleaned text.\n        \"\"\"\n        return \"\".join(c if c.isalnum() else \"_\" for c in text)\n\n    def obtain_header(self, msg):\n        \"\"\"\n        Function to obtain the header of the email.\n\n        Args:\n            msg (email.message.Message): The email message.\n\n        Returns:\n            str: The From field of the email.\n        \"\"\"\n        if msg[\"Subject\"] is not None:\n            Subject, encoding = decode_header(msg[\"Subject\"])[0]\n        else:\n            Subject = \"\"\n            encoding = \"\"\n        if isinstance(Subject, bytes):\n            try:\n                if encoding is not None:\n                    Subject = Subject.decode(encoding)\n                else:\n                    Subject = \"\"\n            except[LookupError] as err:\n                pass\n        From = msg[\"From\"]\n        To = msg[\"To\"]\n        Date = msg[\"Date\"]\n        return From, To, Date, Subject\n\n    def download_attachment(self, part, subject):\n        \"\"\"\n        Function to download the attachment from the email.\n\n        Args:\n            part (email.message.Message): The email message.\n            subject (str): The subject of the email.\n\n        Returns:\n            None\n        \"\"\"\n        filename = part.get_filename()\n        if filename:\n            folder_name = self.clean(subject)\n            if not os.path.isdir(folder_name):\n                os.mkdir(folder_name)\n                filepath = os.path.join(folder_name, filename)\n                open(filepath, \"wb\").write(part.get_payload(decode=True))\n"
  },
  {
    "path": "superagi/helper/resource_helper.py",
    "content": "import os\n\nfrom superagi.config.config import get_config\nfrom superagi.helper.s3_helper import S3Helper\nfrom superagi.lib.logger import logger\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.resource import Resource\nfrom superagi.types.storage_types import StorageType\n\n\nclass ResourceHelper:\n    @classmethod\n    def make_written_file_resource(cls, file_name: str, agent: Agent, agent_execution: AgentExecution, session):\n        \"\"\"\n        Function to create a Resource object for a written file.\n\n        Args:\n            file_name (str): The name of the file.\n            agent (Agent): Agent related to resource.\n            agent_execution(AgentExecution): Agent Execution related to a resource\n            session (Session): The database session.\n\n        Returns:\n            Resource: The Resource object.\n        \"\"\"\n        storage_type = StorageType.get_storage_type(get_config(\"STORAGE_TYPE\", StorageType.FILE.value))\n        file_parts = os.path.splitext(file_name)\n        if len(file_parts) <= 1:\n            file_name = file_name + \".txt\"\n        file_extension = os.path.splitext(file_name)[1][1:]\n\n        if file_extension in [\"png\", \"jpg\", \"jpeg\"]:\n            file_type = \"image/\" + file_extension\n        elif file_extension == \"txt\":\n            file_type = \"application/txt\"\n        else:\n            file_type = \"application/misc\"\n\n        if agent is not None:\n            final_path = ResourceHelper.get_agent_write_resource_path(file_name, agent, agent_execution)\n        else:\n            final_path = ResourceHelper.get_resource_path(file_name)\n        file_size = os.path.getsize(final_path)\n\n        file_path = ResourceHelper.get_agent_write_resource_path(file_name, agent, agent_execution)\n\n        logger.info(\"make_written_file_resource:\", final_path)\n        if StorageType.get_storage_type(get_config(\"STORAGE_TYPE\", StorageType.FILE.value)) == StorageType.S3:\n            file_path = \"resources\" + file_path\n        existing_resource = session.query(Resource).filter_by(\n            name=file_name,\n            path=file_path,\n            storage_type=storage_type.value,\n            type=file_type,\n            channel=\"OUTPUT\",\n            agent_id=agent.id,\n            agent_execution_id=agent_execution.id\n        ).first()\n\n        if existing_resource:\n            # Update the existing resource attributes\n            existing_resource.size = file_size\n            session.commit()\n            session.flush()\n            return existing_resource\n        else:\n            resource = Resource(\n                name=file_name,\n                path=file_path,\n                storage_type=storage_type.value,\n                size=file_size,\n                type=file_type,\n                channel=\"OUTPUT\",\n                agent_id=agent.id,\n                agent_execution_id=agent_execution.id\n            )\n            session.add(resource)\n            session.commit()\n            return resource\n\n    @classmethod\n    def get_formatted_agent_level_path(cls, agent: Agent, path) -> object:\n        formatted_agent_name = agent.name.replace(\" \", \"\")\n        return path.replace(\"{agent_id}\", formatted_agent_name + '_' + str(agent.id))\n\n    @classmethod\n    def get_formatted_agent_execution_level_path(cls, agent_execution: AgentExecution, path):\n        formatted_agent_execution_name = agent_execution.name.replace(\" \", \"\")\n        return path.replace(\"{agent_execution_id}\", (formatted_agent_execution_name + '_' + str(agent_execution.id)))\n\n    @classmethod\n    def get_resource_path(cls, file_name: str):\n        \"\"\"Get final path of the resource.\n\n        Args:\n            file_name (str): The name of the file.\n        \"\"\"\n        return ResourceHelper.get_root_output_dir() + file_name\n\n    @classmethod\n    def get_root_output_dir(cls):\n        \"\"\"Get root dir of the resource.\n        \"\"\"\n        root_dir = get_config('RESOURCES_OUTPUT_ROOT_DIR')\n\n        if root_dir is not None:\n            root_dir = root_dir if root_dir.startswith(\"/\") else os.getcwd() + \"/\" + root_dir\n            root_dir = root_dir if root_dir.endswith(\"/\") else root_dir + \"/\"\n        else:\n            root_dir = os.getcwd() + \"/\"\n        return root_dir\n\n    @classmethod\n    def get_root_input_dir(cls):\n        \"\"\"Get root dir of the resource.\n        \"\"\"\n        root_dir = get_config('RESOURCES_INPUT_ROOT_DIR')\n\n        if root_dir is not None:\n            root_dir = root_dir if root_dir.startswith(\"/\") else os.getcwd() + \"/\" + root_dir\n            root_dir = root_dir if root_dir.endswith(\"/\") else root_dir + \"/\"\n        else:\n            root_dir = os.getcwd() + \"/\"\n        return root_dir\n\n    @classmethod\n    def get_agent_write_resource_path(cls, file_name: str, agent: Agent, agent_execution: AgentExecution):\n        \"\"\"Get agent resource path to write files\n\n        Args:\n            file_name (str): The name of the file.\n            agent (Agent): The unique identifier of the agent.\n            agent_execution (AgentExecution): The unique identifier of the agent.\n        \"\"\"\n        root_dir = ResourceHelper.get_root_output_dir()\n        if agent is not None and \"{agent_id}\" in root_dir:\n            root_dir = ResourceHelper.get_formatted_agent_level_path(agent, root_dir)\n            if agent_execution is not None and \"{agent_execution_id}\" in root_dir:\n                root_dir = ResourceHelper.get_formatted_agent_execution_level_path(agent_execution, root_dir)\n            directory = os.path.dirname(root_dir)\n            os.makedirs(directory, exist_ok=True)\n        final_path = root_dir + file_name\n        return final_path\n\n    @staticmethod\n    def __check_file_path_exists(path):\n        return (StorageType.get_storage_type(get_config(\"STORAGE_TYPE\",\n                                                        StorageType.FILE.value)) is StorageType.S3 and\n                not S3Helper().check_file_exists_in_s3(path)) or (\n                StorageType.get_storage_type(\n                    get_config(\"STORAGE_TYPE\", StorageType.FILE.value)) is StorageType.FILE\n                and not os.path.exists(path))\n\n    @classmethod\n    def get_agent_read_resource_path(cls, file_name, agent: Agent, agent_execution: AgentExecution):\n        \"\"\"Get agent resource path to read files i.e. both input and output directory\n            at agent level.\n\n        Args:\n            file_name (str): The name of the file.\n            agent (Agent): The agent corresponding to resource.\n            agent_execution (AgentExecution): The agent execution corresponding to the resource.\n        \"\"\"\n        final_path = ResourceHelper.get_root_input_dir() + file_name\n        if \"{agent_id}\" in final_path:\n            final_path = ResourceHelper.get_formatted_agent_level_path(\n                agent=agent,\n                path=final_path)\n        output_root_dir = ResourceHelper.get_root_output_dir()\n        if final_path is None or cls.__check_file_path_exists(final_path):\n            if output_root_dir is not None:\n                final_path = ResourceHelper.get_root_output_dir() + file_name\n                if \"{agent_id}\" in final_path:\n                    final_path = ResourceHelper.get_formatted_agent_level_path(\n                        agent=agent,\n                        path=final_path)\n                    if \"{agent_execution_id}\" in final_path:\n                        final_path = ResourceHelper.get_formatted_agent_execution_level_path(\n                            agent_execution=agent_execution,\n                            path=final_path)\n        return final_path\n"
  },
  {
    "path": "superagi/helper/s3_helper.py",
    "content": "import json\n\nimport boto3\nfrom fastapi import HTTPException\n\nfrom superagi.config.config import get_config\nfrom superagi.lib.logger import logger\nfrom urllib.parse import unquote\nimport json\n\n\nclass S3Helper:\n    def __init__(self, bucket_name=get_config(\"BUCKET_NAME\")):\n        \"\"\"\n        Initialize the S3Helper class.\n        Using the AWS credentials from the configuration file, create a boto3 client.\n        \"\"\"\n        self.s3 = S3Helper.__get_s3_client()\n        self.bucket_name = bucket_name\n\n    @classmethod\n    def __get_s3_client(cls):\n        \"\"\"\n        Get an S3 client.\n\n        Returns:\n            s3 (S3Helper): The S3Helper object.\n        \"\"\"\n        return boto3.client(\n            's3',\n            aws_access_key_id=get_config(\"AWS_ACCESS_KEY_ID\"),\n            aws_secret_access_key=get_config(\"AWS_SECRET_ACCESS_KEY\"),\n        )\n\n    def upload_file(self, file, path):\n        \"\"\"\n        Upload a file to S3.\n\n        Args:\n            file (FileStorage): The file to upload.\n            path (str): The path to upload the file to.\n\n        Raises:\n            HTTPException: If the AWS credentials are not found.\n\n        Returns:\n            None\n        \"\"\"\n        try:\n            self.s3.upload_fileobj(file, self.bucket_name, path)\n            logger.info(\"File uploaded to S3 successfully!\")\n        except Exception:\n            raise HTTPException(status_code=500, detail=\"AWS credentials not found. Check your configuration.\")\n\n    def check_file_exists_in_s3(self, file_path):\n        response = self.s3.list_objects_v2(Bucket=get_config(\"BUCKET_NAME\"), Prefix=\"resources\" + file_path)\n        return 'Contents' in response\n\n    def read_from_s3(self, file_path):\n        file_path = \"resources\" + file_path\n        logger.info(f\"Reading file from s3: {file_path}\")\n        response = self.s3.get_object(Bucket=get_config(\"BUCKET_NAME\"), Key=file_path)\n        if response['ResponseMetadata']['HTTPStatusCode'] == 200:\n            return response['Body'].read().decode('utf-8')\n        raise Exception(f\"Error read_from_s3: {response}\")\n\n    def read_binary_from_s3(self, file_path):\n        file_path = \"resources\" + file_path\n        logger.info(f\"Reading file from s3: {file_path}\")\n        response = self.s3.get_object(Bucket=get_config(\"BUCKET_NAME\"), Key=file_path)\n        if response['ResponseMetadata']['HTTPStatusCode'] == 200:\n            return response['Body'].read()\n        raise Exception(f\"Error read_from_s3: {response}\")\n\n    def get_json_file(self, path):\n        \"\"\"\n        Get a JSON file from S3.\n        Args:\n            path (str): The path to the JSON file.\n        Raises:\n            HTTPException: If the AWS credentials are not found.\n        Returns:\n            dict: The JSON file.\n        \"\"\"\n        try:\n            obj = self.s3.get_object(Bucket=self.bucket_name, Key=path)\n            s3_response = obj['Body'].read().decode('utf-8')\n            return json.loads(s3_response)\n        except:\n            raise HTTPException(status_code=500, detail=\"AWS credentials not found. Check your configuration.\")\n\n    def delete_file(self, path):\n        \"\"\"\n        Delete a file from S3.\n\n        Args:\n            path (str): The path to the file to delete.\n\n        Raises:\n            HTTPException: If the AWS credentials are not found.\n\n        Returns:\n            None\n        \"\"\"\n        try:\n            path = \"resources\" + path\n            self.s3.delete_object(Bucket=self.bucket_name, Key=path)\n            logger.info(\"File deleted from S3 successfully!\")\n        except:\n            raise HTTPException(status_code=500, detail=\"AWS credentials not found. Check your configuration.\")\n\n    def upload_file_content(self, content, file_path):\n        try:\n            self.s3.put_object(Bucket=self.bucket_name, Key=file_path, Body=content)\n        except:\n            raise HTTPException(status_code=500, detail=\"AWS credentials not found. Check your configuration.\")\n\n    def get_download_url_of_resources(self, db_resources_arr):\n        s3 = boto3.client(\n            's3',\n            aws_access_key_id=get_config(\"AWS_ACCESS_KEY_ID\"),\n            aws_secret_access_key=get_config(\"AWS_SECRET_ACCESS_KEY\"),\n        )\n        response_obj = {}\n        for db_resource in db_resources_arr:\n            response = self.s3.get_object(Bucket=get_config(\"BUCKET_NAME\"), Key=db_resource.path)\n            content = response[\"Body\"].read()\n            bucket_name = get_config(\"INSTAGRAM_TOOL_BUCKET_NAME\")\n            file_name = db_resource.path.split('/')[-1]\n            file_name = ''.join(char for char in file_name if char != \"`\")\n            object_key = f\"public_resources/run_id{db_resource.agent_execution_id}/{file_name}\"\n            s3.put_object(Bucket=bucket_name, Key=object_key, Body=content)\n            file_url = f\"https://{bucket_name}.s3.amazonaws.com/{object_key}\"\n            resource_execution_id = db_resource.agent_execution_id\n            if resource_execution_id in response_obj:\n                response_obj[resource_execution_id].append(file_url)\n            else:\n                response_obj[resource_execution_id] = [file_url]\n        return response_obj\n\n    def list_files_from_s3(self, file_path):\n        try:\n            file_path = \"resources\" + file_path\n            logger.info(f\"Listing files from s3 with prefix: {file_path}\")\n            response = self.s3.list_objects_v2(Bucket=get_config(\"BUCKET_NAME\"), Prefix=file_path)\n            if 'Contents' in response:\n                logger.info(response['Contents'])\n                file_list = [obj['Key'] for obj in response['Contents']]\n                return file_list\n            else:\n                raise Exception(f\"No contents in S3 response\")\n        except:\n            raise Exception(f\"Error listing files from s3\")\n"
  },
  {
    "path": "superagi/helper/time_helper.py",
    "content": "from datetime import datetime\n\n\ndef get_time_difference(timestamp1, timestamp2):\n    time_format = \"%Y-%m-%d %H:%M:%S.%f\"\n\n    # Parse the given timestamp\n    parsed_timestamp1 = datetime.strptime(str(timestamp1), time_format)\n    parsed_timestamp2 = datetime.strptime(timestamp2, time_format)\n\n    # Calculate the time difference\n    time_difference = parsed_timestamp2 - parsed_timestamp1\n\n    # Convert time difference to total seconds\n    total_seconds = int(time_difference.total_seconds())\n\n    # Calculate years, months, days, hours, and minutes\n    years, seconds_remainder = divmod(total_seconds, (365 * 24 * 60 * 60))  # 1 year = 365 days * 24 hours * 60 minutes * 60 seconds\n    months, seconds_remainder = divmod(seconds_remainder,\n                                       (30 * 24 * 60 * 60))  # 1 month = 30 days * 24 hours * 60 minutes * 60 seconds\n    days, seconds_remainder = divmod(seconds_remainder, 24 * 60 * 60)  # 1 day = 24 hours * 60 minutes * 60 seconds\n    hours, seconds_remainder = divmod(seconds_remainder, 60 * 60)  # 1 hour = 60 minutes * 60 seconds\n    minutes, _ = divmod(seconds_remainder, 60)  # 1 minute = 60 seconds\n\n    # Create a dictionary to store the time difference\n    time_difference_dict = {\n        \"years\": years,\n        \"months\": months,\n        \"days\": days,\n        \"hours\": hours,\n        \"minutes\": minutes\n    }\n    return time_difference_dict\n\n\ndef parse_interval_to_seconds(interval: str) -> int:\n    units = {\"Minutes\": 60, \"Hours\": 3600, \"Days\": 86400, \"Weeks\": 604800, \"Months\": 2592000}\n    interval = ' '.join(interval.split())\n    value, unit = interval.split(\" \")\n\n    return int(value) * units[unit]\n\n\n"
  },
  {
    "path": "superagi/helper/token_counter.py",
    "content": "from typing import List\n\nimport tiktoken\n\nfrom superagi.types.common import BaseMessage\nfrom superagi.lib.logger import logger\nfrom superagi.models.models import Models\nfrom sqlalchemy.orm import Session\n\n\nclass TokenCounter:\n\n    def __init__(self, session:Session=None, organisation_id: int=None):\n        self.session = session\n        self.organisation_id = organisation_id\n\n    def token_limit(self, model: str = \"gpt-3.5-turbo-0301\") -> int:\n        \"\"\"\n        Function to return the token limit for a given model.\n\n        Args:\n            model (str): The model to return the token limit for.\n\n        Raises:\n            KeyError: If the model is not found.\n\n        Returns:\n            int: The token limit.\n        \"\"\"\n        try:\n            model_token_limit_dict = (Models.fetch_model_tokens(self.session, self.organisation_id))\n            return model_token_limit_dict[model]\n        except KeyError:\n            logger.warning(\"Warning: model not found. Using cl100k_base encoding.\")\n            return 8092\n\n    @staticmethod\n    def count_message_tokens(messages: List[BaseMessage], model: str = \"gpt-3.5-turbo-0301\") -> int:\n        \"\"\"\n        Function to count the number of tokens in a list of messages.\n\n        Args:\n            messages (List[BaseMessage]): The list of messages to count the tokens for.\n            model (str): The model to count the tokens for.\n\n        Raises:\n            KeyError: If the model is not found.\n\n        Returns:\n            int: The number of tokens in the messages.\n        \"\"\"\n        try:\n            default_tokens_per_message = 4\n            model_token_per_message_dict = {\"gpt-3.5-turbo-0301\": 4, \"gpt-4-0314\": 3, \"gpt-3.5-turbo\": 4, \"gpt-4\": 3,\n                                            \"gpt-3.5-turbo-16k\": 4, \"gpt-4-32k\": 3, \"gpt-4-32k-0314\": 3,\n                                            \"models/chat-bison-001\": 4}\n            encoding = tiktoken.encoding_for_model(model)\n        except KeyError:\n            logger.warning(\"Warning: model not found. Using cl100k_base encoding.\")\n            encoding = tiktoken.get_encoding(\"cl100k_base\")\n\n        if model in model_token_per_message_dict.keys():\n            tokens_per_message = model_token_per_message_dict[model]\n        else:\n            tokens_per_message = default_tokens_per_message\n\n        if tokens_per_message is None:\n            raise NotImplementedError(\n                f\"num_tokens_from_messages() is not implemented for model {model}.\\n\"\n                \" See https://github.com/openai/openai-python/blob/main/chatml.md for\"\n                \" information on how messages are converted to tokens.\"\n            )\n\n        num_tokens = 0\n        for message in messages:\n            if isinstance(message, str):\n                message = {'content': message}\n            num_tokens += tokens_per_message\n            num_tokens += len(encoding.encode(message['content']))\n\n        num_tokens += 3\n        print(\"tokens\",num_tokens)\n        return num_tokens\n\n    @staticmethod\n    def count_text_tokens(message: str) -> int:\n        \"\"\"\n        Function to count the number of tokens in a text.\n\n        Args:\n            message (str): The text to count the tokens for.\n\n        Returns:\n            int: The number of tokens in the text.\n        \"\"\"\n        encoding = tiktoken.get_encoding(\"cl100k_base\")\n        num_tokens = len(encoding.encode(message)) + 4\n        return num_tokens\n"
  },
  {
    "path": "superagi/helper/tool_helper.py",
    "content": "import importlib.util\nimport inspect\nimport json\nimport os\nimport sys\nimport zipfile\nfrom urllib.parse import urlparse\n\nimport requests\n\nfrom superagi.config.config import get_config\nfrom superagi.lib.logger import logger\nfrom superagi.models.tool import Tool\nfrom superagi.models.tool_config import ToolConfig\nfrom superagi.models.toolkit import Toolkit\nfrom superagi.tools.base_tool import BaseTool, ToolConfiguration\nfrom superagi.tools.base_tool import BaseToolkit\n\n\ndef parse_github_url(github_url):\n    parts = github_url.split('/')\n    owner = parts[3]\n    repo = parts[4]\n    branch = \"main\"\n    return f\"{owner}/{repo}/{branch}\"\n\n\ndef download_tool(tool_url, target_folder):\n    parsed_url = parse_github_url(tool_url)\n    parts = parsed_url.split(\"/\")\n    path = \"/\"\n    owner, repo, branch = parts[0], parts[1], parts[2]\n    archive_url = f\"https://api.github.com/repos/{owner}/{repo}/zipball/{branch}\"\n    response = requests.get(archive_url)\n    tool_zip_file_path = os.path.join(target_folder, 'tool.zip')\n\n    with open(tool_zip_file_path, 'wb') as f:\n        f.write(response.content)\n\n    logger.info(\"Reading Zip\")\n    with zipfile.ZipFile(tool_zip_file_path, 'r') as z:\n        members = [m for m in z.namelist() if m.startswith(f\"{owner}-{repo}\") and f\"{path}\" in m]\n\n        # Extract only folders in the root directory\n        root_folders = [member for member in members if member.count('/') > 1]\n        for member in root_folders:\n            archive_folder = f\"{owner}-{repo}\"\n            target_name = member.replace(f\"{archive_folder}/\", \"\", 1)\n\n            # Skip the unique hash folder while extracting:\n            segments = target_name.split('/', 1)\n            if len(segments) > 1:\n                target_name = segments[1]\n            else:\n                continue\n\n            target_path = os.path.join(target_folder, target_name)\n\n            if not target_name:\n                continue\n\n            if member.endswith('/'):\n                os.makedirs(target_path, exist_ok=True)\n            else:\n                with open(target_path, 'wb') as outfile, z.open(member) as infile:\n                    outfile.write(infile.read())\n    logger.info(\"Donwload Success!\")\n    os.remove(tool_zip_file_path)\n\n\ndef get_classes_in_file(file_path, clazz):\n    classes = []\n\n    module = load_module_from_file(file_path)\n\n    for name, member in inspect.getmembers(module):\n        if inspect.isclass(member) and issubclass(member, clazz) and member != clazz:\n            class_dict = {}\n            class_dict['class_name'] = member.__name__\n\n            class_obj = getattr(module, member.__name__)\n            try:\n                obj = class_obj()\n                if clazz == BaseToolkit:\n                    get_toolkit_info(class_dict, classes, obj)\n                elif clazz == BaseTool:\n                    get_tool_info(class_dict, classes, obj)\n            except:\n                class_dict = None\n    return classes\n\n\ndef get_tool_info(class_dict, classes, obj):\n    \"\"\"\n        Get tool information from an object.\n    \"\"\"\n    class_dict['tool_name'] = obj.name\n    class_dict['tool_description'] = obj.description\n    classes.append(class_dict)\n\n\ndef get_toolkit_info(class_dict, classes, obj):\n    \"\"\"\n        Get toolkit information from an object.\n    \"\"\"\n    class_dict['toolkit_name'] = obj.name\n    class_dict['toolkit_description'] = obj.description\n    class_dict['toolkit_tools'] = obj.get_tools()\n    class_dict['toolkit_keys'] = obj.get_env_keys()\n    classes.append(class_dict)\n\n\ndef load_module_from_file(file_path):\n    spec = importlib.util.spec_from_file_location(\"module_name\", file_path)\n    module = importlib.util.module_from_spec(spec)\n    spec.loader.exec_module(module)\n\n    return module\n\n\ndef init_tools(folder_paths, session, tool_name_to_toolkit):\n    # Iterate over all subfolders\n    for folder_path in folder_paths:\n        if not os.path.exists(folder_path):\n            continue\n        for folder_name in os.listdir(folder_path):\n            folder_dir = os.path.join(folder_path, folder_name)\n            # Iterate over all files in the subfolder\n            if not os.path.isdir(folder_dir):\n                continue\n                # sys.path.append(os.path.abspath('superagi/tools/email'))\n            sys.path.append(folder_dir)\n            for file_name in os.listdir(folder_dir):\n                file_path = os.path.join(folder_dir, file_name)\n                if file_name.endswith(\".py\") and not file_name.startswith(\"__init__\"):\n                    # Get classes\n                    classes = get_classes_in_file(file_path=file_path, clazz=BaseTool)\n                    update_base_tool_class_info(classes, file_name, folder_name, session, tool_name_to_toolkit)\n\n\ndef update_base_tool_class_info(classes, file_name, folder_name, session, tool_name_to_toolkit):\n    for clazz in classes:\n        if clazz[\"class_name\"] is not None:\n            tool_name = clazz['tool_name']\n            tool_description = clazz['tool_description']\n            toolkit_id = tool_name_to_toolkit.get((tool_name, folder_name), None)\n            if toolkit_id is not None:\n                new_tool = Tool.add_or_update(session, tool_name=tool_name, folder_name=folder_name,\n                                              class_name=clazz['class_name'], file_name=file_name,\n                                              toolkit_id=tool_name_to_toolkit[(tool_name, folder_name)],\n                                              description=tool_description)\n\n\ndef init_toolkits(code_link, existing_toolkits, folder_paths, organisation, session):\n    tool_name_to_toolkit = {}\n    new_toolkits = []\n    # Iterate over all subfolders\n    for folder_path in folder_paths:\n        if not os.path.exists(folder_path):\n            continue\n        for folder_name in os.listdir(folder_path):\n            folder_dir = os.path.join(folder_path, folder_name)\n\n            if not os.path.isdir(folder_dir):\n                continue\n                # sys.path.append(os.path.abspath('superagi/tools/email'))\n            sys.path.append(folder_dir)\n            # Iterate over all files in the subfolder\n            for file_name in os.listdir(folder_dir):\n                file_path = os.path.join(folder_dir, file_name)\n                if file_name.endswith(\".py\") and not file_name.startswith(\"__init__\"):\n                    # Get classes\n                    classes = get_classes_in_file(file_path=file_path, clazz=BaseToolkit)\n                    tool_name_to_toolkit = update_base_toolkit_info(classes, code_link, folder_name, new_toolkits,\n                                                                    organisation, session, tool_name_to_toolkit)\n    # Delete toolkits that are not present in the updated toolkits\n    delete_extra_toolkit(existing_toolkits, new_toolkits, session)\n    return tool_name_to_toolkit\n\n\ndef delete_extra_toolkit(existing_toolkits, new_toolkits, session):\n    for toolkit in existing_toolkits:\n        if toolkit.name not in [new_toolkit.name for new_toolkit in new_toolkits]:\n            session.query(Tool).filter(Tool.toolkit_id == toolkit.id).delete()\n            session.query(ToolConfig).filter(ToolConfig.toolkit_id == toolkit.id).delete()\n            session.delete(toolkit)\n    # Commit the changes to the database\n    session.commit()\n\n\ndef update_base_toolkit_info(classes, code_link, folder_name, new_toolkits, organisation, session,\n                             tool_name_to_toolkit):\n    for clazz in classes:\n        if clazz[\"class_name\"] is not None:\n            toolkit_name = clazz[\"toolkit_name\"]\n            toolkit_description = clazz[\"toolkit_description\"]\n            tools = clazz[\"toolkit_tools\"]\n            tool_config_keys = clazz[\"toolkit_keys\"]\n            # Create a new ToolKit object\n            new_toolkit = Toolkit.add_or_update(\n                session,\n                name=toolkit_name,\n                description=toolkit_description,\n                show_toolkit=True if len(tools) > 1 else False,\n                organisation_id=organisation.id,\n                tool_code_link=code_link\n            )\n            new_toolkits.append(new_toolkit)\n            tool_mapping = {}\n            # Store the tools in the database\n            for tool in tools:\n                new_tool = Tool.add_or_update(session, tool_name=tool.name, folder_name=folder_name,\n                                              class_name=None, file_name=None,\n                                              toolkit_id=new_toolkit.id, description=tool.description)\n                tool_mapping[tool.name, folder_name] = new_toolkit.id\n            tool_name_to_toolkit = {**tool_mapping, **tool_name_to_toolkit}\n\n            # Store the tools config in the database\n            for tool_config_key in tool_config_keys:\n                if isinstance(tool_config_key, ToolConfiguration):\n                    new_config = ToolConfig.add_or_update(session, toolkit_id=new_toolkit.id,\n                                                      key=tool_config_key.key,\n                                                      key_type=tool_config_key.key_type,\n                                                      is_required=tool_config_key.is_required,\n                                                      is_secret=tool_config_key.is_secret)\n                else:\n                    ToolConfig.add_or_update(session, toolkit_id=new_toolkit.id,\n                                                          key = tool_config_key)\n    return tool_name_to_toolkit\n\n\ndef process_files(folder_paths, session, organisation, code_link=None):\n    existing_toolkits = session.query(Toolkit).filter(Toolkit.organisation_id == organisation.id).all()\n\n    tool_name_to_toolkit = init_toolkits(code_link, existing_toolkits, folder_paths, organisation, session)\n    init_tools(folder_paths, session, tool_name_to_toolkit)\n\n\ndef get_readme_content_from_code_link(tool_code_link):\n    if tool_code_link is None:\n        return None\n    parsed_url = urlparse(tool_code_link)\n    path_parts = parsed_url.path.split(\"/\")\n\n    # Extract username, repository, and branch from the URL\n    username = path_parts[1]\n    repository = path_parts[2]\n    branch = path_parts[4] if len(path_parts) > 4 else \"main\"\n\n    readme_url = f\"https://raw.githubusercontent.com/{username}/{repository}/{branch}/README.MD\"\n    response = requests.get(readme_url)\n    if response.status_code == 404:\n        readme_url = f\"https://raw.githubusercontent.com/{username}/{repository}/{branch}/README.md\"\n        response = requests.get(readme_url)\n    readme_content = response.text\n    return readme_content\n\n\ndef register_toolkits(session, organisation):\n    tool_paths = [\"superagi/tools\", \"superagi/tools/external_tools\"]\n    # if get_config(\"ENV\", \"DEV\") == \"PROD\":\n    #     tool_paths.append(\"superagi/tools/marketplace_tools\")\n    if organisation is not None:\n        process_files(tool_paths, session, organisation)\n        logger.info(f\"Toolkits Registered Successfully for Organisation ID : {organisation.id}!\")\n\ndef register_marketplace_toolkits(session, organisation):\n    tool_paths = [\"superagi/tools\", \"superagi/tools/external_tools\",\"superagi/tools/marketplace_tools\"]\n    if organisation is not None:\n        process_files(tool_paths, session, organisation)\n        logger.info(f\"Marketplace Toolkits Registered Successfully for Organisation ID : {organisation.id}!\")\n\ndef extract_repo_name(repo_link):\n    # Extract the repository name from the link\n    # Assuming the GitHub link format: https://github.com/username/repoName\n    repo_name = repo_link.rsplit('/', 1)[-1]\n\n    return repo_name\n\n\ndef add_tool_to_json(repo_link):\n    # Read the content of the tools.json file\n    with open('tools.json', 'r') as file:\n        tools_data = json.load(file)\n\n    # Extract the repository name from the link\n    repo_name = extract_repo_name(repo_link)\n\n    # Add a new key-value pair to the tools object\n    tools_data['tools'][repo_name] = repo_link\n\n    # Write the updated JSON object back to tools.json\n    with open('tools.json', 'w') as file:\n        json.dump(tools_data, file, indent=2)\n\n\ndef handle_tools_import():\n    print(\"Handling tools import\")\n    tool_paths = [\"superagi/tools\", \"superagi/tools/marketplace_tools\", \"superagi/tools/external_tools\"]\n    for tool_path in tool_paths:\n        if not os.path.exists(tool_path):\n            continue\n        for folder_name in os.listdir(tool_path):\n            folder_dir = os.path.join(tool_path, folder_name)\n            if os.path.isdir(folder_dir):\n                sys.path.append(folder_dir)\n\ndef compare_tools(tool1, tool2):\n    fields = [\"name\", \"description\"]\n    return any(tool1.get(field) != tool2.get(field) for field in fields)\n\n\ndef compare_configs(config1, config2):\n    fields = [\"key\"]\n    return any(config1.get(field) != config2.get(field) for field in fields)\n\n\ndef compare_toolkit(toolkit1, toolkit2):\n    main_toolkit_fields = [\"description\", \"show_toolkit\", \"name\", \"tool_code_link\"]\n    toolkit_diff = any(toolkit1.get(field) != toolkit2.get(field) for field in main_toolkit_fields)\n\n    tools1 = sorted(toolkit1.get(\"tools\", []), key=lambda tool: tool.get(\"name\", \"\"))\n    tools2 = sorted(toolkit2.get(\"tools\", []), key=lambda tool: tool.get(\"name\", \"\"))\n\n    if len(tools1) != len(tools2):\n        tools_diff = True\n    else:\n        tools_diff = any(compare_tools(tool1, tool2) for tool1, tool2 in zip(tools1, tools2))\n\n    tool_configs1 = sorted(toolkit1.get(\"configs\", []), key=lambda config: config.get(\"key\", \"\"))\n    tool_configs2 = sorted(toolkit2.get(\"configs\", []), key=lambda config: config.get(\"key\", \"\"))\n    if len(tool_configs1) != len(tool_configs2):\n        tool_configs_diff = True\n    else:\n        tool_configs_diff = any(compare_configs(config1, config2) for config1, config2 in zip(tool_configs1,\n                                                                                              tool_configs2))\n\n    print(\"toolkit_diff : \", toolkit_diff)\n    print(\"tools_diff : \", tools_diff)\n    print(\"tool_configs_diff : \", tool_configs_diff)\n    return toolkit_diff or tools_diff or tool_configs_diff\n"
  },
  {
    "path": "superagi/helper/twitter_helper.py",
    "content": "import os\nimport json\nimport base64\nimport requests\nfrom requests_oauthlib import OAuth1\nfrom requests_oauthlib import OAuth1Session\nfrom superagi.helper.resource_helper import ResourceHelper\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.types.storage_types import StorageType\nfrom superagi.config.config import get_config\nfrom superagi.helper.s3_helper import S3Helper\n\n\nclass TwitterHelper:\n\n    def get_media_ids(self, session, media_files, creds, agent_id, agent_execution_id):\n        media_ids = []\n        oauth = OAuth1(creds.api_key,\n                       client_secret=creds.api_key_secret,\n                       resource_owner_key=creds.oauth_token,\n                       resource_owner_secret=creds.oauth_token_secret)\n        for file in media_files:\n            file_path = self.get_file_path(session, file, agent_id, agent_execution_id)\n            image_data = self._get_image_data(file_path)\n            b64_image = base64.b64encode(image_data)\n            upload_endpoint = 'https://upload.twitter.com/1.1/media/upload.json'\n            headers = {'Authorization': 'application/octet-stream'}\n            response = requests.post(upload_endpoint, headers=headers,\n                                     data={'media_data': b64_image},\n                                     auth=oauth)\n            ids = json.loads(response.text)['media_id']\n            media_ids.append(str(ids))\n        return media_ids\n\n    def get_file_path(self, session, file_name, agent_id, agent_execution_id):\n        final_path = ResourceHelper().get_agent_read_resource_path(file_name,\n                                                                    agent=Agent.get_agent_from_id(session, agent_id),\n                                                                    agent_execution=AgentExecution.get_agent_execution_from_id(\n                                                                  session, agent_execution_id))\n        return final_path\n\n    def _get_image_data(self, file_path):\n        if StorageType.get_storage_type(get_config(\"STORAGE_TYPE\", StorageType.FILE.value)) == StorageType.S3:\n                attachment_data = S3Helper().read_binary_from_s3(file_path)\n        else:\n            with open(file_path, \"rb\") as file:\n                attachment_data = file.read()\n        return attachment_data\n\n    def send_tweets(self, params, creds):\n        tweet_endpoint = \"https://api.twitter.com/2/tweets\"\n        oauth = OAuth1Session(creds.api_key,\n                              client_secret=creds.api_key_secret,\n                              resource_owner_key=creds.oauth_token,\n                              resource_owner_secret=creds.oauth_token_secret)\n\n        response = oauth.post(tweet_endpoint, json=params)\n        return response\n\n    def _get_image_data(self, file_path):\n        if get_config(\"STORAGE_TYPE\") == StorageType.S3:\n            return S3Helper().read_binary_from_s3(file_path)\n        else:\n            with open(file_path, \"rb\") as image_file:\n                return image_file.read()\n            "
  },
  {
    "path": "superagi/helper/twitter_tokens.py",
    "content": "import hmac\nimport time\nimport random\nimport base64\nimport hashlib\nimport urllib.parse\nimport ast\nimport http.client as http_client\nfrom sqlalchemy.orm import Session\nfrom superagi.models.toolkit import Toolkit\nfrom superagi.models.oauth_tokens import OauthTokens\nfrom superagi.config.config import get_config\n\nclass Creds:\n\n    def __init__(self,api_key, api_key_secret, oauth_token, oauth_token_secret):\n        self.api_key = api_key\n        self.api_key_secret = api_key_secret\n        self.oauth_token = oauth_token\n        self.oauth_token_secret = oauth_token_secret\n\nclass TwitterTokens:\n\n    def __init__(self, session: Session):\n        self.session = session\n\n    def get_request_token(self,api_data):\n        api_key = api_data[\"api_key\"]\n        api_secret_key = api_data[\"api_secret\"]\n        http_method = 'POST'\n        base_url = 'https://api.twitter.com/oauth/request_token'\n\n        env = get_config(\"ENV\", \"DEV\")\n        if env == \"DEV\":\n            oauth_callback = \"http://localhost:3000/api/twitter/oauth-tokens\"\n        else:\n            oauth_callback = \"https://app.superagi.com/api/twitter/oauth-tokens\"\n        params = {\n            'oauth_callback': oauth_callback,\n            'oauth_consumer_key': api_key,\n            'oauth_nonce': self.gen_nonce(),\n            'oauth_signature_method': 'HMAC-SHA1',\n            'oauth_timestamp': int(time.time()),\n            'oauth_version': '1.0'\n        }\n\n        params_sorted = sorted(params.items())\n        params_qs = '&'.join([f'{k}={self.percent_encode(str(v))}' for k, v in params_sorted])\n\n        base_string = f'{http_method}&{self.percent_encode(base_url)}&{self.percent_encode(params_qs)}'\n\n        signing_key = f'{self.percent_encode(api_secret_key)}&'\n        signature = hmac.new(signing_key.encode(), base_string.encode(), hashlib.sha1)\n        params['oauth_signature'] = base64.b64encode(signature.digest()).decode()\n\n        auth_header = 'OAuth ' + ', '.join([f'{k}=\"{self.percent_encode(str(v))}\"' for k, v in params.items()])\n\n        headers = {\n            'Content-Type': 'application/x-www-form-urlencoded',\n            'Authorization': auth_header\n        }\n        conn = http_client.HTTPSConnection(\"api.twitter.com\")\n        conn.request(\"POST\", \"/oauth/request_token\", \"\", headers)\n        res = conn.getresponse()\n        response_data = res.read().decode('utf-8')\n        conn.close()\n        request_token_resp = dict(urllib.parse.parse_qsl(response_data))\n        return request_token_resp\n\n    def percent_encode(self, val):\n        return urllib.parse.quote(val, safe='')\n\n    def gen_nonce(self):\n        nonce = ''.join([str(random.randint(0, 9)) for i in range(32)])\n        return nonce\n\n    def get_twitter_creds(self, toolkit_id):\n        toolkit = self.session.query(Toolkit).filter(Toolkit.id == toolkit_id).first()\n        organisation_id = toolkit.organisation_id\n        twitter_creds = self.session.query(OauthTokens).filter(OauthTokens.toolkit_id == toolkit_id, OauthTokens.organisation_id == organisation_id).first()\n        twitter_creds = ast.literal_eval(twitter_creds.value)\n        final_creds = Creds(twitter_creds['api_key'], twitter_creds['api_key_secret'], twitter_creds['oauth_token'], twitter_creds['oauth_token_secret'])\n        return final_creds"
  },
  {
    "path": "superagi/helper/validate_csv.py",
    "content": "import csv\nimport pandas as pd\nimport chardet\nfrom superagi.lib.logger import logger\n\ndef correct_csv_encoding(file_path):\n    with open(file_path, 'rb') as f:\n        result = chardet.detect(f.read())\n        encoding = result['encoding']\n\n    if encoding != 'utf-8':\n        data = []\n        with open(file_path, 'r', encoding=encoding) as f:\n            reader = csv.reader(f, delimiter=',', quotechar='\"')\n            for row in reader:\n                try:\n                    data.append(row)\n                except Exception as e:\n                    logger.error(f\"An error occurred while processing the file: {e}\")\n                    continue\n\n        df = pd.DataFrame(data)\n        df.to_csv(file_path, encoding='utf-8', index=False)\n        logger.info(\"File is converted to utf-8 encoding.\")\n    else:\n        logger.info(\"File is already in utf-8 encoding.\")"
  },
  {
    "path": "superagi/helper/webhook_manager.py",
    "content": "from superagi.models.agent import Agent\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.webhooks import Webhooks\nfrom superagi.models.webhook_events import WebhookEvents\nimport requests\nimport json\nfrom superagi.lib.logger import logger\n\nclass WebHookManager:\n    def __init__(self,session):\n        self.session=session\n\n    def agent_status_change_callback(self, agent_execution_id, curr_status, old_status):\n        if curr_status==\"CREATED\" or agent_execution_id is None:\n            return\n        agent_id=AgentExecution.get_agent_execution_from_id(self.session,agent_execution_id).agent_id\n        agent=Agent.get_agent_from_id(self.session,agent_id)\n        org=agent.get_agent_organisation(self.session)\n        org_webhooks=self.session.query(Webhooks).filter(Webhooks.org_id == org.id).all()\n\n        for webhook_obj in org_webhooks:\n            if \"status\" in webhook_obj.filters and curr_status in webhook_obj.filters[\"status\"]:\n                webhook_obj_body={\"agent_id\":agent_id,\"org_id\":org.id,\"event\":f\"{old_status} to {curr_status}\"}\n                error=None\n                request=None\n                status='sent'\n                try:\n                    request = requests.post(webhook_obj.url.strip(), data=json.dumps(webhook_obj_body), headers=webhook_obj.headers)\n                except Exception as e:\n                    logger.error(f\"Exception occured in webhooks {e}\")\n                    error=str(e)\n                if request is not None and request.status_code not in [200,201] and error is None:\n                    error=request.text\n                if error is not None:\n                    status='Error'\n                webhook_event=WebhookEvents(agent_id=agent_id, run_id=agent_execution_id, event=f\"{old_status} to {curr_status}\", status=status, errors=error)\n                self.session.add(webhook_event)\n                self.session.commit()\n\n"
  },
  {
    "path": "superagi/helper/webpage_extractor.py",
    "content": "from io import BytesIO\nfrom PyPDF2 import PdfFileReader\nfrom PyPDF2 import PdfReader\nimport requests\nimport re\nfrom requests.exceptions import RequestException\nfrom bs4 import BeautifulSoup\nfrom newspaper import Article, ArticleException, Config\nfrom requests_html import HTMLSession\nimport time\nimport random\nfrom lxml import html\nfrom superagi.lib.logger import logger\n\nUSER_AGENTS = [\n    \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3\",\n    \"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0\",\n    \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.1 Safari/605.1.15\",\n    \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.0\",\n    \"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0\",\n    \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36\",\n    \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Safari/605.1.15\",\n    \"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0\",\n    \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36\",\n    \"Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.4 Mobile/15E148 Safari/604.1\",\n    \"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:73.0) Gecko/20100101 Firefox/73.0\",\n    \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36\"\n]\n\nclass WebpageExtractor:\n\n    def __init__(self, num_extracts=3):\n        \"\"\"\n        Initialize the WebpageExtractor class.\n        \"\"\"\n        self.num_extracts = num_extracts\n\n    def extract_with_3k(self, url):\n        \"\"\"\n        Extract the text from a webpage using the 3k method.\n\n        Args:\n            url (str): The URL of the webpage to extract from.\n\n        Returns:\n            str: The extracted text.\n        \"\"\"\n        try:\n            if url.lower().endswith(\".pdf\"):\n                response = requests.get(url)\n                response.raise_for_status()\n\n                with BytesIO(response.content) as pdf_data:\n                    reader = PdfReader(pdf_data)\n                    content = \" \".join([reader.getPage(i).extract_text() for i in range(reader.getNumPages())])\n\n            else:\n                config = Config()\n                config.browser_user_agent = random.choice(USER_AGENTS)\n                config.request_timeout = 10\n                session = HTMLSession()\n\n                response = session.get(url)\n                response.html.render(timeout=config.request_timeout)\n                html_content = response.html.html\n\n                article = Article(url, config=config)\n                article.set_html(html_content)\n                article.parse()\n                content = article.text.replace('\\t', ' ').replace('\\n', ' ').strip()\n\n            return content[:1500]\n\n        except ArticleException as ae:\n            logger.error(f\"Error while extracting text from HTML (newspaper3k): {str(ae)}\")\n            return f\"Error while extracting text from HTML (newspaper3k): {str(ae)}\"\n\n        except RequestException as re:\n            logger.error(f\"Error while making the request to the URL (newspaper3k): {str(re)}\")\n            return f\"Error while making the request to the URL (newspaper3k): {str(re)}\"\n\n        except Exception as e:\n            logger.error(f\"Unknown error while extracting text from HTML (newspaper3k): {str(e)}\")\n            return \"\"\n\n    def extract_with_bs4(self, url):\n        \"\"\"\n        Extract the text from a webpage using the BeautifulSoup4 method.\n\n        Args:\n            url (str): The URL of the webpage to extract from.\n\n        Returns:\n            str: The extracted text.\n        \"\"\"\n        headers = {\n            \"User-Agent\": random.choice(USER_AGENTS)\n        }\n\n        try:\n            response = requests.get(url, headers=headers, timeout=10)\n            if response.status_code == 200:\n                soup = BeautifulSoup(response.text, 'html.parser')\n                for tag in soup(['script', 'style', 'nav', 'footer', 'head', 'link', 'meta', 'noscript']):\n                    tag.decompose()\n\n                main_content_areas = soup.find_all(['main', 'article', 'section', 'div'])\n                if main_content_areas:\n                    main_content = max(main_content_areas, key=lambda x: len(x.text))\n                    content_tags = ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']\n                    content = ' '.join([tag.text.strip() for tag in main_content.find_all(content_tags)])\n                else:\n                    content = ' '.join([tag.text.strip() for tag in soup.find_all(['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'])])\n\n                content = re.sub(r'\\t', ' ', content)\n                content = re.sub(r'\\s+', ' ', content)\n                return content\n            elif response.status_code == 404:\n                return f\"Error: 404. Url is invalid or does not exist. Try with valid url...\"\n            else:\n                logger.error(f\"Error while extracting text from HTML (bs4): {response.status_code}\")\n                return f\"Error while extracting text from HTML (bs4): {response.status_code}\"\n\n        except Exception as e:\n            logger.error(f\"Unknown error while extracting text from HTML (bs4): {str(e)}\")\n            return \"\"\n\n    def extract_with_lxml(self, url):\n        \"\"\"\n        Extract the text from a webpage using the lxml method.\n\n        Args:\n            url (str): The URL of the webpage to extract from.\n\n        Returns:\n            str: The extracted text.\n        \"\"\"\n        try:\n            config = Config()\n            config.browser_user_agent = random.choice(USER_AGENTS)\n            config.request_timeout = 10\n            session = HTMLSession()\n\n            response = session.get(url)\n            response.html.render(timeout=config.request_timeout)\n            html_content = response.html.html\n\n            tree = html.fromstring(html_content)\n            paragraphs = tree.cssselect('p, h1, h2, h3, h4, h5, h6')\n            content = ' '.join([para.text_content() for para in paragraphs if para.text_content()])\n            content = content.replace('\\t', ' ').replace('\\n', ' ').strip()\n\n            return content\n\n        except ArticleException as ae:\n            logger.error(\"Error while extracting text from HTML (lxml): {str(ae)}\")\n            return \"\"\n\n        except RequestException as re:\n            logger.error(f\"Error while making the request to the URL (lxml): {str(re)}\")\n            return \"\"\n\n        except Exception as e:\n            logger.error(f\"Unknown error while extracting text from HTML (lxml): {str(e)}\")\n            return \"\"\n    "
  },
  {
    "path": "superagi/image_llms/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/image_llms/base_image_llm.py",
    "content": "from abc import ABC, abstractmethod\n\n\nclass BaseImageLlm(ABC):\n    @abstractmethod\n    def get_image_model(self):\n        pass\n\n    @abstractmethod\n    def generate_image(self, prompt: str, size: int = 512, num: int = 2):\n        pass\n"
  },
  {
    "path": "superagi/image_llms/openai_dalle.py",
    "content": "import openai\n\nfrom superagi.config.config import get_config\nfrom superagi.image_llms.base_image_llm import BaseImageLlm\n\n\nclass OpenAiDalle(BaseImageLlm):\n    def __init__(self, api_key, image_model=None, number_of_results=1):\n        \"\"\"\n        Args:\n            api_key (str): The OpenAI API key.\n            image_model (str): The image model.\n            number_of_results (int): The number of results.\n        \"\"\"\n        self.number_of_results = number_of_results\n        self.api_key = api_key\n        self.image_model = image_model\n        openai.api_key = api_key\n        openai.api_base = get_config(\"OPENAI_API_BASE\", \"https://api.openai.com/v1\")\n\n    def get_image_model(self):\n        \"\"\"\n        Returns:\n            str: The image model.\n        \"\"\"\n        return self.image_model\n\n    def generate_image(self, prompt: str, size: int = 512):\n        \"\"\"\n        Call the OpenAI image API.\n\n        Args:\n            prompt (str): The prompt.\n            size (int): The size.\n            num (int): The number of images.\n\n        Returns:\n            dict: The response.\n        \"\"\"\n        response = openai.Image.create(\n            prompt=prompt,\n            n=self.number_of_results,\n            size=f\"{size}x{size}\"\n        )\n        return response\n"
  },
  {
    "path": "superagi/jobs/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/jobs/agent_executor.py",
    "content": "from datetime import datetime, timedelta\n\nfrom sqlalchemy.orm import sessionmaker\nfrom superagi.llms.local_llm import LocalLLM\n\nimport superagi.worker\nfrom superagi.agent.agent_iteration_step_handler import AgentIterationStepHandler\nfrom superagi.agent.agent_tool_step_handler import AgentToolStepHandler\nfrom superagi.agent.agent_workflow_step_wait_handler import AgentWaitStepHandler\nfrom superagi.agent.types.wait_step_status import AgentWorkflowStepWaitStatus\nfrom superagi.apm.event_handler import EventHandler\nfrom superagi.config.config import get_config\nfrom superagi.lib.logger import logger\nfrom superagi.llms.google_palm import GooglePalm\nfrom superagi.llms.hugging_face import HuggingFace\nfrom superagi.llms.llm_model_factory import get_model\nfrom superagi.llms.replicate import Replicate\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.db import connect_db\nfrom superagi.models.workflows.agent_workflow_step import AgentWorkflowStep\nfrom superagi.models.workflows.agent_workflow_step_wait import AgentWorkflowStepWait\nfrom superagi.types.vector_store_types import VectorStoreType\nfrom superagi.vector_store.embedding.openai import OpenAiEmbedding\nfrom superagi.vector_store.vector_factory import VectorFactory\nfrom superagi.worker import execute_agent\nfrom superagi.agent.types.agent_workflow_step_action_types import AgentWorkflowStepAction\nfrom superagi.agent.types.agent_execution_status import AgentExecutionStatus\n\n# from superagi.helper.tool_helper import get_tool_config_by_key\n\nengine = connect_db()\nSession = sessionmaker(bind=engine)\n\n\nclass AgentExecutor:\n\n    def execute_next_step(self, agent_execution_id):\n        global engine\n        # try:\n        engine.dispose()\n        session = Session()\n        try:\n            agent_execution = session.query(AgentExecution).filter(AgentExecution.id == agent_execution_id).first()\n            '''Avoiding running old agent executions'''\n            if agent_execution and agent_execution.created_at < datetime.utcnow() - timedelta(days=1):\n                logger.error(\"Older agent execution found, skipping execution\")\n                return\n\n            agent = session.query(Agent).filter(Agent.id == agent_execution.agent_id).first()\n            agent_config = Agent.fetch_configuration(session, agent.id)\n            if agent.is_deleted or (\n                    agent_execution.status != AgentExecutionStatus.RUNNING.value and agent_execution.status != AgentExecutionStatus.WAITING_FOR_PERMISSION.value):\n                logger.error(f\"Agent execution stopped. {agent.id}: {agent_execution.status}\")\n                return\n\n            organisation = Agent.find_org_by_agent_id(session, agent_id=agent.id)\n            if self._check_for_max_iterations(session, organisation.id, agent_config, agent_execution_id):\n                logger.error(f\"Agent execution stopped. Max iteration exceeded. {agent.id}: {agent_execution.status}\")\n                return\n\n            try:\n                model_config = AgentConfiguration.get_model_api_key(session, agent_execution.agent_id,\n                                                                    agent_config[\"model\"])\n                model_api_key = model_config['api_key']\n                model_llm_source = model_config['provider']\n            except Exception as e:\n                logger.info(f\"Unable to get model config...{e}\")\n                return\n\n            try:\n                memory = None\n                if \"OpenAI\" in model_llm_source:\n                    vector_store_type = VectorStoreType.get_vector_store_type(get_config(\"LTM_DB\", \"Redis\"))\n                    memory = VectorFactory.get_vector_storage(vector_store_type, \"super-agent-index1\",\n                                                              AgentExecutor.get_embedding(model_llm_source,\n                                                                                          model_api_key))\n            except Exception as e:\n                logger.info(f\"Unable to setup the connection...{e}\")\n                memory = None\n\n            agent_workflow_step = session.query(AgentWorkflowStep).filter(\n                AgentWorkflowStep.id == agent_execution.current_agent_step_id).first()\n            try:\n                self.__execute_workflow_step(agent, agent_config, agent_execution_id, agent_workflow_step, memory,\n                                             model_api_key, organisation, session)\n\n            except Exception as e:\n                logger.info(\"Exception in executing the step: {}\".format(e))\n                superagi.worker.execute_agent.apply_async((agent_execution_id, datetime.now()), countdown=15)\n                return\n\n            agent_execution = session.query(AgentExecution).filter(AgentExecution.id == agent_execution_id).first()\n            if agent_execution.status == \"COMPLETED\" or agent_execution.status == \"WAITING_FOR_PERMISSION\":\n                logger.info(\"Agent Execution is completed or waiting for permission\")\n                session.close()\n                return\n            superagi.worker.execute_agent.apply_async((agent_execution_id, datetime.now()), countdown=2)\n            # superagi.worker.execute_agent.delay(agent_execution_id, datetime.now())\n        finally:\n            session.close()\n            engine.dispose()\n\n    def __execute_workflow_step(self, agent, agent_config, agent_execution_id, agent_workflow_step, memory,\n                                model_api_key, organisation, session):\n        logger.info(\"Executing Workflow step : \", agent_workflow_step.action_type)\n        if agent_workflow_step.action_type == AgentWorkflowStepAction.TOOL.value:\n            tool_step_handler = AgentToolStepHandler(session,\n                                                     llm=get_model(model=agent_config[\"model\"], api_key=model_api_key,\n                                                                   organisation_id=organisation.id)\n                                                     , agent_id=agent.id, agent_execution_id=agent_execution_id,\n                                                     memory=memory)\n            tool_step_handler.execute_step()\n        elif agent_workflow_step.action_type == AgentWorkflowStepAction.ITERATION_WORKFLOW.value:\n            iteration_step_handler = AgentIterationStepHandler(session,\n                                                               llm=get_model(model=agent_config[\"model\"],\n                                                                             api_key=model_api_key,\n                                                                             organisation_id=organisation.id)\n                                                               , agent_id=agent.id,\n                                                               agent_execution_id=agent_execution_id, memory=memory)\n            print(get_model(model=agent_config[\"model\"], api_key=model_api_key, organisation_id=organisation.id))\n            iteration_step_handler.execute_step()\n        elif agent_workflow_step.action_type == AgentWorkflowStepAction.WAIT_STEP.value:\n            (AgentWaitStepHandler(session=session, agent_id=agent.id,\n                                  agent_execution_id=agent_execution_id)\n             .execute_step())\n\n    @classmethod\n    def get_embedding(cls, model_source, model_api_key):\n        if \"OpenAI\" in model_source:\n            return OpenAiEmbedding(api_key=model_api_key)\n        if \"Google\" in model_source:\n            return GooglePalm(api_key=model_api_key)\n        if \"Hugging\" in model_source:\n            return HuggingFace(api_key=model_api_key)\n        if \"Replicate\" in model_source:\n            return Replicate(api_key=model_api_key)\n        if \"Custom\" in model_source:\n            return LocalLLM()\n        return None\n\n    def _check_for_max_iterations(self, session, organisation_id, agent_config, agent_execution_id):\n        db_agent_execution = session.query(AgentExecution).filter(AgentExecution.id == agent_execution_id).first()\n        if agent_config[\"max_iterations\"] <= db_agent_execution.num_of_calls:\n            db_agent_execution.status = AgentExecutionStatus.ITERATION_LIMIT_EXCEEDED.value\n\n            EventHandler(session=session).create_event('run_iteration_limit_crossed',\n                                                       {'agent_execution_id': db_agent_execution.id,\n                                                        'name': db_agent_execution.name,\n                                                        'tokens_consumed': db_agent_execution.num_of_tokens,\n                                                        \"calls\": db_agent_execution.num_of_calls},\n                                                       db_agent_execution.agent_id, organisation_id)\n            session.commit()\n            logger.info(\"ITERATION_LIMIT_CROSSED\")\n            return True\n        return False\n\n    def execute_waiting_workflows(self):\n        \"\"\"Check if wait time of wait workflow step is over and can be resumed.\"\"\"\n\n        session = Session()\n        waiting_agent_executions = session.query(AgentExecution).filter(\n            AgentExecution.status == AgentExecutionStatus.WAIT_STEP.value,\n        ).all()\n        for agent_execution in waiting_agent_executions:\n            workflow_step = session.query(AgentWorkflowStep).filter(\n                AgentWorkflowStep.id == agent_execution.current_agent_step_id).first()\n            step_wait = AgentWorkflowStepWait.find_by_id(session, workflow_step.action_reference_id)\n            if step_wait is not None:\n                wait_time = step_wait.delay if not None else 0\n                logger.info(f\"Agent Execution ID: {agent_execution.id}\")\n                logger.info(f\"Wait time: {wait_time}\")\n                logger.info(f\"Wait begin time: {step_wait.wait_begin_time}\")\n                logger.info(f\"Current time: {datetime.now()}\")\n                logger.info(f\"Wait Difference : {(datetime.now() - step_wait.wait_begin_time).total_seconds()}\")\n                if ((datetime.now() - step_wait.wait_begin_time).total_seconds() > wait_time\n                        and step_wait.status == AgentWorkflowStepWaitStatus.WAITING.value):\n                    agent_execution.status = AgentExecutionStatus.RUNNING.value\n                    step_wait.status = AgentWorkflowStepWaitStatus.COMPLETED.value\n                    session.commit()\n                    session.flush()\n                    AgentWaitStepHandler(session=session, agent_id=agent_execution.agent_id,\n                                         agent_execution_id=agent_execution.id).handle_next_step()\n                    execute_agent.delay(agent_execution.id, datetime.now())\n        session.close()"
  },
  {
    "path": "superagi/jobs/scheduling_executor.py",
    "content": "import ast\nfrom datetime import datetime\n\nfrom fastapi import HTTPException\nfrom sqlalchemy.orm import sessionmaker\nfrom superagi.models.tool import Tool\n\nfrom superagi.models.workflows.iteration_workflow import IterationWorkflow\nfrom superagi.worker import execute_agent\nfrom superagi.models.workflows.agent_workflow import AgentWorkflow\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_config import AgentExecutionConfiguration\nfrom superagi.apm.event_handler import EventHandler\nfrom superagi.models.knowledges import Knowledges\nfrom superagi.models.db import connect_db\n\n\nengine = connect_db()\nSession = sessionmaker(bind=engine)\n\nclass ScheduledAgentExecutor:\n\n    def execute_scheduled_agent(self, agent_id: int, name: str):\n        \"\"\"\n        Performs the execution of scheduled agents\n\n        Args:\n            agent_id: Identifier of the agent\n            name: Name of the agent\n        \"\"\"\n        session = Session()\n        agent = session.query(Agent).get(agent_id)\n\n        if not agent:\n            raise HTTPException(status_code=404, detail=\"Agent not found\")\n\n\n\n        start_step = AgentWorkflow.fetch_trigger_step_id(session, agent.agent_workflow_id)\n        iteration_step_id = IterationWorkflow.fetch_trigger_step_id(session,\n                                                                    start_step.action_reference_id).id if start_step.action_type == \"ITERATION_WORKFLOW\" else -1\n\n        db_agent_execution = AgentExecution(status=\"CREATED\", last_execution_time=datetime.now(),\n                                            agent_id=agent_id, name=name, num_of_calls=0,\n                                            num_of_tokens=0,\n                                            current_agent_step_id=start_step.id,\n                                            iteration_workflow_step_id=iteration_step_id)\n\n        session.add(db_agent_execution)\n        session.commit()\n\n        #update status from CREATED to RUNNING\n        db_agent_execution.status = \"RUNNING\"\n        session.commit()\n\n        agent_execution_id = db_agent_execution.id\n        agent_configurations = session.query(AgentConfiguration).filter(AgentConfiguration.agent_id == agent_id).all()\n        for agent_config in agent_configurations:\n            agent_execution_config = AgentExecutionConfiguration(agent_execution_id=agent_execution_id, key=agent_config.key, value=agent_config.value)\n            session.add(agent_execution_config)\n        organisation = agent.get_agent_organisation(session)\n        model = session.query(AgentConfiguration.value).filter(AgentConfiguration.agent_id == agent_id).filter(AgentConfiguration.key == 'model').first()[0]\n\n        EventHandler(session=session).create_event('run_created',\n                                                   {'agent_execution_id': db_agent_execution.id,\n                                                    'agent_execution_name':db_agent_execution.name},\n                                                    agent_id,\n                                                    organisation.id if organisation else 0)\n        agent_execution_knowledge = AgentConfiguration.get_agent_config_by_key_and_agent_id(session= session, key= 'knowledge', agent_id= agent_id)\n        if agent_execution_knowledge and agent_execution_knowledge.value != 'None':\n            knowledge_name = Knowledges.get_knowledge_from_id(session, int(agent_execution_knowledge.value)).name\n            if knowledge_name is not None:\n                EventHandler(session=session).create_event('knowledge_picked',\n                                                        {'knowledge_name': knowledge_name,\n                                                         'agent_execution_id': db_agent_execution.id},\n                                                        agent_id,\n                                                        organisation.id if organisation else 0)\n        session.commit()\n\n        if db_agent_execution.status == \"RUNNING\":\n            execute_agent.delay(db_agent_execution.id, datetime.now())\n\n        session.close()"
  },
  {
    "path": "superagi/lib/logger.py",
    "content": "import logging\nimport inspect\n\n\nclass CustomLogRecord(logging.LogRecord):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\n        frame = inspect.currentframe().f_back\n        while frame:\n            if frame.f_globals['__name__'] != __name__ and frame.f_globals['__name__'] != 'logging':\n                break\n            frame = frame.f_back\n\n        if frame:\n            self.filename = frame.f_code.co_filename\n            self.lineno = frame.f_lineno\n        else:\n            self.filename = \"unknown\"\n            self.lineno = 0\n\n\nclass SingletonMeta(type):\n    _instances = {}\n\n    def __call__(cls, *args, **kwargs):\n        if cls not in cls._instances:\n            instance = super().__call__(*args, **kwargs)\n            cls._instances[cls] = instance\n        return cls._instances[cls]\n\n\nclass Logger(metaclass=SingletonMeta):\n    def __init__(self, logger_name='Super AGI', log_level=logging.DEBUG):\n        if not hasattr(self, 'logger'):\n            self.logger = logging.getLogger(logger_name)\n            self.logger.setLevel(log_level)\n            self.logger.makeRecord = self._make_custom_log_record\n\n            console_handler = logging.StreamHandler()\n            console_handler.setLevel(log_level)\n\n            formatter = logging.Formatter(\n                '%(asctime)s - %(name)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s',\n                datefmt='%Y-%m-%d %H:%M:%S %Z')\n\n            console_handler.setFormatter(formatter)\n            self.logger.addHandler(console_handler)\n\n    def _make_custom_log_record(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None, sinfo=None):\n        return CustomLogRecord(name, level, fn, lno, msg, args, exc_info, func=func, extra=extra, sinfo=sinfo)\n\n    def debug(self, message, *args):\n        self.logger.debug(message)\n        if args:\n            self.logger.debug(*args)\n\n    def info(self, message, *args):\n        self.logger.info(message)\n        if args:\n            self.logger.info(*args)\n\n    def warning(self, message, *args):\n        self.logger.warning(message)\n        if args:\n            self.logger.warning(*args)\n\n    def error(self, message, *args):\n        self.logger.error(message)\n        if args:\n            self.logger.error(*args)\n\n    def critical(self, message, *args):\n        self.logger.critical(message)\n        if args:\n            self.logger.critical(*args)\n\n\nlogger = Logger('Super AGI')\n"
  },
  {
    "path": "superagi/llms/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/llms/base_llm.py",
    "content": "from abc import ABC, abstractmethod\n\n\nclass BaseLlm(ABC):\n    @abstractmethod\n    def chat_completion(self, prompt):\n        pass\n\n    @abstractmethod\n    def get_source(self):\n        pass\n\n    @abstractmethod\n    def get_api_key(self):\n        pass\n\n    @abstractmethod\n    def get_model(self):\n        pass\n\n    @abstractmethod\n    def get_models(self):\n        pass\n\n    @abstractmethod\n    def verify_access_key(self):\n        pass\n"
  },
  {
    "path": "superagi/llms/google_palm.py",
    "content": "import google.generativeai as palm\n\nfrom superagi.config.config import get_config\nfrom superagi.lib.logger import logger\nfrom superagi.llms.base_llm import BaseLlm\n\n\nclass GooglePalm(BaseLlm):\n    def __init__(self, api_key, model='models/chat-bison-001', temperature=0.6, candidate_count=1, top_k=40,\n                 top_p=0.95):\n        \"\"\"\n        Args:\n            api_key (str): The Google PALM API key.\n            model (str): The model.\n            temperature (float): The temperature.\n            candidate_count (int): The number of candidates.\n            top_k (int): The top k.\n            top_p (float): The top p.\n        \"\"\"\n        self.model = model\n        self.temperature = temperature\n        self.candidate_count = candidate_count\n        self.top_k = top_k\n        self.top_p = top_p\n        self.api_key = api_key\n        palm.configure(api_key=api_key)\n\n    def get_source(self):\n        return \"google palm\"\n\n    def get_api_key(self):\n        \"\"\"\n        Returns:\n            str: The API key.\n        \"\"\"\n        return self.api_key\n\n    def get_model(self):\n        \"\"\"\n        Returns:\n            str: The model.\n        \"\"\"\n        return self.model\n\n    def chat_completion(self, messages, max_tokens=get_config(\"MAX_MODEL_TOKEN_LIMIT\") or 800, examples=[], context=\"\"):\n        \"\"\"\n        Call the Google PALM chat API.\n\n        Args:\n            context (str): The context.\n            examples (list): The examples.\n            messages (list): The messages.\n\n        Returns:\n            dict: The response.\n        \"\"\"\n\n        prompt = \"\\n\".join([\"`\" + message[\"role\"] + \"`: \" + message[\"content\"] + \"\" for message in messages])\n        # role does not yield right results in case of single step prompt\n        if len(messages) == 1:\n            prompt = messages[0]['content']\n        try:\n            # NOTE: Default chat based palm bison model has different issues. We will switch to it once it gets fixed.\n            final_model = \"models/text-bison-001\" if self.model == \"models/chat-bison-001\" else self.model\n            completion = palm.generate_text(\n                model=final_model,\n                temperature=self.temperature,\n                candidate_count=self.candidate_count,\n                top_k=self.top_k,\n                top_p=self.top_p,\n                prompt=prompt,\n                max_output_tokens=int(max_tokens),\n            )\n            # print(completion.result)\n            return {\"response\": completion, \"content\": completion.result}\n        except Exception as exception:\n            logger.info(\"Google palm Exception:\", exception)\n            return {\"error\": \"ERROR_GOOGLE_PALM\", \"message\": \"Google palm exception\"}\n\n    def verify_access_key(self):\n        \"\"\"\n        Verify the access key is valid.\n\n        Returns:\n            bool: True if the access key is valid, False otherwise.\n        \"\"\"\n        try:\n            models = palm.list_models()\n            return True\n        except Exception as exception:\n            logger.info(\"Google palm Exception:\", exception)\n            return False\n\n    def get_models(self):\n        \"\"\"\n        Get the models.\n\n        Returns:\n            list: The models.\n        \"\"\"\n        try:\n            models_supported = [\"chat-bison-001\"]\n            return models_supported\n        except Exception as exception:\n            logger.info(\"Google palm Exception:\", exception)\n            return []\n"
  },
  {
    "path": "superagi/llms/grammar/json.gbnf",
    "content": "root   ::= object\nvalue  ::= object | array | string | number | (\"true\" | \"false\" | \"null\") ws\n\nobject ::=\n  \"{\" ws (\n            string \":\" ws value\n    (\",\" ws string \":\" ws value)*\n  )? \"}\" ws\n\narray  ::=\n  \"[\" ws (\n            value\n    (\",\" ws value)*\n  )? \"]\" ws\n\nstring ::=\n  \"\\\"\" (\n    [^\"\\\\] |\n    \"\\\\\" ([\"\\\\/bfnrt] | \"u\" [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F]) # escapes\n  )* \"\\\"\" ws\n\nnumber ::= (\"-\"? ([0-9] | [1-9] [0-9]*)) (\".\" [0-9]+)? ([eE] [-+]? [0-9]+)? ws\n\n# Optional space: by convention, applied in this grammar after literal chars when allowed\nws ::= ([ \\t\\n] ws)?\n"
  },
  {
    "path": "superagi/llms/hugging_face.py",
    "content": "import os\nimport requests\nimport json\nfrom superagi.config.config import get_config\nfrom superagi.lib.logger import logger\nfrom superagi.llms.base_llm import BaseLlm\nfrom superagi.llms.utils.huggingface_utils.tasks import Tasks, TaskParameters\nfrom superagi.llms.utils.huggingface_utils.public_endpoints import ACCOUNT_VERIFICATION_URL\n\nclass HuggingFace(BaseLlm):\n    def __init__(\n        self,\n        api_key,\n        model = None ,\n        end_point = None,\n        task=Tasks.TEXT_GENERATION,\n        **kwargs\n    ):\n        self.api_key = api_key\n        self.model = model\n        self.end_point = end_point\n        self.task = task\n        self.task_params = TaskParameters().get_params(self.task, **kwargs)\n        self.headers = {\n            \"Authorization\": f\"Bearer {self.api_key}\",\n            \"Content-Type\": \"application/json\",\n        }\n\n    def get_source(self):\n            return \"hugging face\"\n\n    def get_api_key(self):\n        \"\"\"\n        Returns:\n            str: The API key.\n        \"\"\"\n        return self.api_key\n\n    def get_model(self):\n        \"\"\"\n        The API needs a POST request with the parameter \"inputs\".\n\n        Returns:\n            response from the endpoint\n        \"\"\"\n\n        return self.model\n\n    def get_models(self):\n        \"\"\"\n        Returns:\n            str: The model.\n        \"\"\"\n        return self.model\n\n    def verify_access_key(self):\n        \"\"\"\n        Verify the access key is valid.\n\n        Returns:\n            bool: True if the access key is valid, False otherwise.\n        \"\"\"\n        response = requests.get(ACCOUNT_VERIFICATION_URL, headers=self.headers)\n\n        # A more sophisticated check could be done here.\n        # Ideally we should be checking the response from the endpoint along with the status code.\n        # If the desired response is not received, we should return False and log the response.\n        return response.status_code == 200\n\n    def chat_completion(self, messages, max_tokens=get_config(\"MAX_MODEL_TOKEN_LIMIT\")):\n        \"\"\"\n        Call the HuggingFace inference API.\n        Args:\n            messages (list): The messages.\n            max_tokens (int): The maximum number of tokens.\n        Returns:\n            dict: The response.\n        \"\"\"\n        try:\n            if isinstance(messages, list):\n                messages = messages[0][\"content\"] + \"\\nThe response in json schema:\"\n            params = self.task_params\n            if self.task == Tasks.TEXT_GENERATION:\n                params[\"max_new_tokens\"] = max_tokens\n            params['return_full_text'] = False\n            payload = {\n                \"inputs\": messages,\n                \"parameters\": self.task_params,\n                \"options\": {\n                    \"use_cache\": False,\n                    \"wait_for_model\": True,\n                }\n            }\n            response = requests.post(self.end_point, headers=self.headers, data=json.dumps(payload))\n            completion = json.loads(response.content.decode(\"utf-8\"))\n            logger.info(f\"{completion=}\")\n            if self.task == Tasks.TEXT_GENERATION:\n                content = completion[0][\"generated_text\"]\n            else:\n                content = completion[0][\"answer\"]\n\n            return {\"response\": completion, \"content\": content}\n        except Exception as exception:\n            logger.error(f\"HF Exception: {exception}\")\n            return {\"error\": \"ERROR_HUGGINGFACE\", \"message\": \"HuggingFace Inference exception\", \"details\": exception}\n\n    def verify_end_point(self):\n        data = json.dumps({\"inputs\": \"validating end_point\"})\n        response = requests.post(self.end_point, headers=self.headers, data=data)\n\n        return response.json()"
  },
  {
    "path": "superagi/llms/llm_model_factory.py",
    "content": "from superagi.llms.google_palm import GooglePalm\nfrom superagi.llms.local_llm import LocalLLM\nfrom superagi.llms.openai import OpenAi\nfrom superagi.llms.replicate import Replicate\nfrom superagi.llms.hugging_face import HuggingFace\nfrom superagi.models.models_config import ModelsConfig\nfrom superagi.models.models import Models\nfrom sqlalchemy.orm import sessionmaker\nfrom superagi.models.db import connect_db\n\n\ndef get_model(organisation_id, api_key, model=\"gpt-3.5-turbo\", **kwargs):\n    print(\"Fetching model details from database...\")\n    engine = connect_db()\n    Session = sessionmaker(bind=engine)\n    session = Session()\n\n    model_instance = session.query(Models).filter(Models.org_id == organisation_id, Models.model_name == model).first()\n    response = session.query(ModelsConfig.provider).filter(ModelsConfig.org_id == organisation_id,\n                                                                   ModelsConfig.id == model_instance.model_provider_id).first()\n    provider_name = response.provider\n\n    session.close()\n\n    if provider_name == 'OpenAI':\n        print(\"Provider is OpenAI\")\n        return OpenAi(model=model_instance.model_name, api_key=api_key, **kwargs)\n    elif provider_name == 'Replicate':\n        print(\"Provider is Replicate\")\n        return Replicate(model=model_instance.model_name, version=model_instance.version, api_key=api_key, **kwargs)\n    elif provider_name == 'Google Palm':\n        print(\"Provider is Google Palm\")\n        return GooglePalm(model=model_instance.model_name, api_key=api_key, **kwargs)\n    elif provider_name == 'Hugging Face':\n        print(\"Provider is Hugging Face\")\n        return HuggingFace(model=model_instance.model_name, end_point=model_instance.end_point, api_key=api_key, **kwargs)\n    elif provider_name == 'Local LLM':\n        print(\"Provider is Local LLM\")\n        return LocalLLM(model=model_instance.model_name, context_length=model_instance.context_length)\n    else:\n        print('Unknown provider.')\n\ndef build_model_with_api_key(provider_name, api_key):\n    if provider_name.lower() == 'openai':\n        return OpenAi(api_key=api_key)\n    elif provider_name.lower() == 'replicate':\n        return Replicate(api_key=api_key)\n    elif provider_name.lower() == 'google palm':\n        return GooglePalm(api_key=api_key)\n    elif provider_name.lower() == 'hugging face':\n        return HuggingFace(api_key=api_key)\n    elif provider_name.lower() == 'local llm':\n        return LocalLLM(api_key=api_key)\n    else:\n        print('Unknown provider.')"
  },
  {
    "path": "superagi/llms/local_llm.py",
    "content": "from superagi.config.config import get_config\nfrom superagi.lib.logger import logger\nfrom superagi.llms.base_llm import BaseLlm\nfrom superagi.helper.llm_loader import LLMLoader\n\n\nclass LocalLLM(BaseLlm):\n    def __init__(self, temperature=0.6, max_tokens=get_config(\"MAX_MODEL_TOKEN_LIMIT\"), top_p=1,\n                 frequency_penalty=0,\n                 presence_penalty=0, number_of_results=1, model=None, api_key='EMPTY', context_length=4096):\n        \"\"\"\n        Args:\n            model (str): The model.\n            temperature (float): The temperature.\n            max_tokens (int): The maximum number of tokens.\n            top_p (float): The top p.\n            frequency_penalty (float): The frequency penalty.\n            presence_penalty (float): The presence penalty.\n            number_of_results (int): The number of results.\n        \"\"\"\n        self.model = model\n        self.api_key = api_key\n        self.temperature = temperature\n        self.max_tokens = max_tokens\n        self.top_p = top_p\n        self.frequency_penalty = frequency_penalty\n        self.presence_penalty = presence_penalty\n        self.number_of_results = number_of_results\n        self.context_length = context_length\n\n        llm_loader = LLMLoader(self.context_length)\n        self.llm_model = llm_loader.model\n        self.llm_grammar = llm_loader.grammar\n\n    def chat_completion(self, messages, max_tokens=get_config(\"MAX_MODEL_TOKEN_LIMIT\")):\n        \"\"\"\n        Call the chat completion.\n\n        Args:\n            messages (list): The messages.\n            max_tokens (int): The maximum number of tokens.\n\n        Returns:\n            dict: The response.\n        \"\"\"\n        try:\n            if self.llm_model is None or self.llm_grammar is None:\n                logger.error(\"Model not found.\")\n                return {\"error\": \"Model loading error\", \"message\": \"Model not found. Please check your model path and try again.\"}\n            else:\n                response = self.llm_model.create_chat_completion(messages=messages, functions=None, function_call=None, temperature=self.temperature, top_p=self.top_p,\n                                                                 max_tokens=int(max_tokens), presence_penalty=self.presence_penalty, frequency_penalty=self.frequency_penalty, grammar=self.llm_grammar)\n                content = response[\"choices\"][0][\"message\"][\"content\"]\n                logger.info(content)\n                return {\"response\": response, \"content\": content}\n\n        except Exception as exception:\n            logger.info(\"Exception:\", exception)\n            return {\"error\": \"ERROR\", \"message\": \"Error: \"+str(exception)}\n\n    def get_source(self):\n        \"\"\"\n        Get the source.\n\n        Returns:\n            str: The source.\n        \"\"\"\n        return \"Local LLM\"\n\n    def get_api_key(self):\n        \"\"\"\n        Returns:\n            str: The API key.\n        \"\"\"\n        return self.api_key\n\n    def get_model(self):\n        \"\"\"\n        Returns:\n            str: The model.\n        \"\"\"\n        return self.model\n\n    def get_models(self):\n        \"\"\"\n        Returns:\n            list: The models.\n        \"\"\"\n        return self.model\n\n    def verify_access_key(self, api_key):\n        return True"
  },
  {
    "path": "superagi/llms/openai.py",
    "content": "import openai\nfrom openai import APIError, InvalidRequestError\nfrom openai.error import RateLimitError, AuthenticationError, Timeout, TryAgain\nfrom tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_random_exponential\n\nfrom superagi.config.config import get_config\nfrom superagi.lib.logger import logger\nfrom superagi.llms.base_llm import BaseLlm\n\nMAX_RETRY_ATTEMPTS = 5\nMIN_WAIT = 30 # Seconds\nMAX_WAIT = 300 # Seconds\n\ndef custom_retry_error_callback(retry_state):\n    logger.info(\"OpenAi Exception:\", retry_state.outcome.exception())\n    return {\"error\": \"ERROR_OPENAI\", \"message\": \"Open ai exception: \"+str(retry_state.outcome.exception())}\n\n\nclass OpenAi(BaseLlm):\n    def __init__(self, api_key, model=\"gpt-4\", temperature=0.6, max_tokens=get_config(\"MAX_MODEL_TOKEN_LIMIT\"), top_p=1,\n                 frequency_penalty=0,\n                 presence_penalty=0, number_of_results=1):\n        \"\"\"\n        Args:\n            api_key (str): The OpenAI API key.\n            model (str): The model.\n            temperature (float): The temperature.\n            max_tokens (int): The maximum number of tokens.\n            top_p (float): The top p.\n            frequency_penalty (float): The frequency penalty.\n            presence_penalty (float): The presence penalty.\n            number_of_results (int): The number of results.\n        \"\"\"\n        self.model = model\n        self.temperature = temperature\n        self.max_tokens = max_tokens\n        self.top_p = top_p\n        self.frequency_penalty = frequency_penalty\n        self.presence_penalty = presence_penalty\n        self.number_of_results = number_of_results\n        self.api_key = api_key\n        openai.api_key = api_key\n        openai.api_base = get_config(\"OPENAI_API_BASE\", \"https://api.openai.com/v1\")\n\n    def get_source(self):\n        return \"openai\"\n\n    def get_api_key(self):\n        \"\"\"\n        Returns:\n            str: The API key.\n        \"\"\"\n        return self.api_key\n\n    def get_model(self):\n        \"\"\"\n        Returns:\n            str: The model.\n        \"\"\"\n        return self.model\n\n    @retry(\n        retry=(\n            retry_if_exception_type(RateLimitError) |\n            retry_if_exception_type(Timeout) |\n            retry_if_exception_type(TryAgain)\n        ),\n        stop=stop_after_attempt(MAX_RETRY_ATTEMPTS), # Maximum number of retry attempts\n        wait=wait_random_exponential(min=MIN_WAIT, max=MAX_WAIT),\n        before_sleep=lambda retry_state: logger.info(f\"{retry_state.outcome.exception()} (attempt {retry_state.attempt_number})\"),\n        retry_error_callback=custom_retry_error_callback\n    )\n    def chat_completion(self, messages, max_tokens=get_config(\"MAX_MODEL_TOKEN_LIMIT\")):\n        \"\"\"\n        Call the OpenAI chat completion API.\n\n        Args:\n            messages (list): The messages.\n            max_tokens (int): The maximum number of tokens.\n\n        Returns:\n            dict: The response.\n        \"\"\"\n        try:\n            # openai.api_key = get_config(\"OPENAI_API_KEY\")\n            response = openai.ChatCompletion.create(\n                n=self.number_of_results,\n                model=self.model,\n                messages=messages,\n                temperature=self.temperature,\n                max_tokens=max_tokens,\n                top_p=self.top_p,\n                frequency_penalty=self.frequency_penalty,\n                presence_penalty=self.presence_penalty\n            )\n            content = response.choices[0].message[\"content\"]\n            return {\"response\": response, \"content\": content}\n        except RateLimitError as api_error:\n            logger.info(\"OpenAi RateLimitError:\", api_error)\n            raise RateLimitError(str(api_error))\n        except Timeout as timeout_error:\n            logger.info(\"OpenAi Timeout:\", timeout_error)\n            raise Timeout(str(timeout_error))\n        except TryAgain as try_again_error:\n            logger.info(\"OpenAi TryAgain:\", try_again_error)\n            raise TryAgain(str(try_again_error))\n        except AuthenticationError as auth_error:\n            logger.info(\"OpenAi AuthenticationError:\", auth_error)\n            return {\"error\": \"ERROR_AUTHENTICATION\", \"message\": \"Authentication error please check the api keys: \"+str(auth_error)}\n        except InvalidRequestError as invalid_request_error:\n            logger.info(\"OpenAi InvalidRequestError:\", invalid_request_error)\n            return {\"error\": \"ERROR_INVALID_REQUEST\", \"message\": \"Openai invalid request error: \"+str(invalid_request_error)}\n        except Exception as exception:\n            logger.info(\"OpenAi Exception:\", exception)\n            return {\"error\": \"ERROR_OPENAI\", \"message\": \"Open ai exception: \"+str(exception)}\n\n    def verify_access_key(self):\n        \"\"\"\n        Verify the access key is valid.\n\n        Returns:\n            bool: True if the access key is valid, False otherwise.\n        \"\"\"\n        try:\n            models = openai.Model.list()\n            return True\n        except Exception as exception:\n            logger.info(\"OpenAi Exception:\", exception)\n            return False\n\n    def get_models(self):\n        \"\"\"\n        Get the models.\n\n        Returns:\n            list: The models.\n        \"\"\"\n        try:\n            models = openai.Model.list()\n            models = [model[\"id\"] for model in models[\"data\"]]\n            models_supported = ['gpt-4', 'gpt-3.5-turbo', 'gpt-3.5-turbo-16k', 'gpt-4-32k']\n            models = [model for model in models if model in models_supported]\n            return models\n        except Exception as exception:\n            logger.info(\"OpenAi Exception:\", exception)\n            return []\n"
  },
  {
    "path": "superagi/llms/replicate.py",
    "content": "import os\nimport requests\nfrom superagi.config.config import get_config\nfrom superagi.lib.logger import logger\nfrom superagi.llms.base_llm import BaseLlm\n\n\nclass Replicate(BaseLlm):\n    def __init__(self, api_key, model: str = None, version: str = None, max_length=1000, temperature=0.7,\n                 candidate_count=1, top_k=40, top_p=0.95):\n        \"\"\"\n        Args:\n            api_key (str): The Replicate API key.\n            model (str): The model.\n            version (str): The version.\n            temperature (float): The temperature.\n            candidate_count (int): The number of candidates.\n            top_k (int): The top k.\n            top_p (float): The top p.\n        \"\"\"\n        self.model = model\n        self.version = version\n        self.temperature = temperature\n        self.candidate_count = candidate_count\n        self.top_k = top_k\n        self.top_p = top_p\n        self.api_key = api_key\n        self.max_length = max_length\n\n    def get_source(self):\n        return \"replicate\"\n\n    def get_api_key(self):\n        \"\"\"\n        Returns:\n            str: The API key.\n        \"\"\"\n        return self.api_key\n\n    def get_model(self):\n            \"\"\"\n            Returns:\n                str: The model.\n            \"\"\"\n            return self.model\n\n    def get_models(self):\n        \"\"\"\n        Returns:\n            str: The model.\n        \"\"\"\n        return self.model\n\n    def chat_completion(self, messages, max_tokens=get_config(\"MAX_MODEL_TOKEN_LIMIT\") or 800):\n        \"\"\"\n        Call the Replicate model API.\n\n        Args:\n            context (str): The context.\n            messages (list): The messages.\n\n        Returns:\n            dict: The response.\n        \"\"\"\n        prompt = \"\\n\".join([message[\"role\"] + \": \" + message[\"content\"] + \"\" for message in messages])\n\n        if len(messages) == 1:\n            prompt = \"System:\" + messages[0]['content'] + \"\\nResponse:\"\n        else:\n            prompt = prompt + \"\\nResponse:\"\n        try:\n            os.environ[\"REPLICATE_API_TOKEN\"] = self.api_key\n            import replicate\n            output_generator = replicate.run(\n                self.model + \":\" + self.version,\n                input={\"prompt\": prompt, \"max_length\": 40000, \"temperature\": self.temperature,\n                       \"top_p\": self.top_p}\n            )\n\n            final_output = \"\"\n            temp_output = []\n            for item in output_generator:\n                final_output += item\n                temp_output.append(item)\n\n            if not final_output:\n                logger.error(\"Replicate model didn't return any output.\")\n                return {\"error\": \"Replicate model didn't return any output.\"}\n            print(final_output)\n            print(temp_output)\n            logger.info(\"Replicate response:\", final_output)\n\n            return {\"response\": temp_output, \"content\": final_output}\n        except Exception as exception:\n            logger.error('Replicate model ' + self.model + ' Exception:', exception)\n            return {\"error\": exception}\n\n    def verify_access_key(self):\n        \"\"\"\n        Verify the access key is valid.\n\n        Returns:\n            bool: True if the access key is valid, False otherwise.\n        \"\"\"\n        headers = {\"Authorization\": \"Token \" + self.api_key}\n        response = requests.get(\"https://api.replicate.com/v1/collections\", headers=headers)\n\n        # If the request is successful, status code will be 200\n        if response.status_code == 200:\n            return True\n        else:\n            return False\n\n"
  },
  {
    "path": "superagi/llms/utils/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/llms/utils/huggingface_utils/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/llms/utils/huggingface_utils/public_endpoints.py",
    "content": "ACCOUNT_VERIFICATION_URL = \"https://huggingface.co/api/whoami-v2\""
  },
  {
    "path": "superagi/llms/utils/huggingface_utils/tasks.py",
    "content": "from enum import Enum\nfrom dataclasses import dataclass\nfrom typing import List, Dict, Union, Optional\n\n\n# Define an Enum for the different tasks\nclass Tasks(Enum):\n    TEXT_GENERATION = \"text-generation\"\n\n\nclass TaskParameters:\n    def __init__(self) -> None:\n        self.params = self._generate_params()\n        self._validate_params()\n\n    def get_params(self, task, **kwargs) -> Dict[str, Union[int, float, bool, str]]:\n        # Return the task parameters and override with any kwargs\n        # This allows us to override the default parameters\n        # Ignore any parameters that are not defined for the task\n        params = self.params[task]\n        for param in kwargs:\n            if param in params:\n                params[param] = kwargs[param]\n        return params\n\n    def _generate_params(self):\n        return {\n            Tasks.TEXT_GENERATION: TextGenerationParameters().__dict__,\n        }\n\n    def _validate_params(self):\n        assert len(self.params) == len(Tasks), \"Not all tasks have parameters defined\"\n\n        for task in Tasks:\n            assert task in self.params, f\"Task {task} does not have parameters defined\"\n            # params = self.params[task]\n            # assert isinstance(params, dict), f\"Task {task} parameters are not a dictionary\"\n            # for param in params:\n            #     assert isinstance(param, str), f\"Task {task} parameter {param} is not a string\"\n            #     assert isinstance(params[param], (int, float, bool, str)), f\"Task {task} parameter {param} is not a valid type\"\n\n\n@dataclass\nclass TextGenerationParameters():\n    \"\"\"\n    top_k: (Default: None).\n    Integer to define the top tokens considered within the sample operation to create new text.\n\n    top_p: (Default: None).\n    Float to define the tokens that are within the sample operation of text generation.\n    Add tokens in the sample for more probable to least probable until the sum of  the probabilities is greater than top_p.\n\n    temperature: (Default: 1.0). Float (0.0-100.0).\n    The temperature of the sampling operation.\n    1 means regular sampling, 0 means always take the highest score, 100.0 is getting closer to uniform probability.\n\n    repetition_penalty: (Default: None). Float (0.0-100.0).\n    The more a token is used within generation the more it is penalized to not be picked in successive generation passes.\n\n    max_new_tokens: (Default: None). Int (0-250).\n    The amount of new tokens to be generated, this does not include the input length it is a estimate of the size of generated text you want. Each new tokens slows down the request, so look for balance between response times and length of text generated.\n\n    max_time: (Default: None). Float (0-120.0).\n    The amount of time in seconds that the query should take maximum.\n    Network can cause some overhead so it will be a soft limit.\n    Use that in combination with max_new_tokens for best results.\n\n    return_full_text: (Default: True). Bool.\n    If set to False, the return results will not contain the original query making it easier for prompting.\n\n    num_return_sequences: (Default: 1). Integer.\n    The number of proposition you want to be returned.\n\n    do_sample: (Optional: True). Bool.\n    Whether or not to use sampling, use greedy decoding otherwise.\n    \"\"\"\n    top_k: Optional[int] = None\n    top_p: Optional[float] = None\n    temperature: float = 1.0\n    repetition_penalty: Optional[float] = None\n    max_new_tokens: Optional[int] = None\n    max_time: Optional[float] = None\n    return_full_text: bool = True\n    num_return_sequences: int = 1\n    do_sample: bool = True"
  },
  {
    "path": "superagi/models/__init__.py",
    "content": "import glob\nfrom os.path import basename, dirname, isfile, join\n\nmodules = glob.glob(join(dirname(__file__), \"*.py\"))\n__all__ = [basename(f)[:-3] for f in modules if isfile(f) and not f.endswith(\"__init__.py\")]"
  },
  {
    "path": "superagi/models/agent.py",
    "content": "from __future__ import annotations\nimport ast\n\nimport json\n\nfrom sqlalchemy import Column, Integer, String, Boolean\nfrom sqlalchemy import or_\n\nfrom superagi.lib.logger import logger\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.models.agent_template import AgentTemplate\nfrom superagi.models.agent_template_config import AgentTemplateConfig\n# from superagi.models import AgentConfiguration\nfrom superagi.models.base_model import DBBaseModel\nfrom superagi.models.organisation import Organisation\nfrom superagi.models.project import Project\nfrom superagi.models.workflows.agent_workflow import AgentWorkflow\n\n\nclass Agent(DBBaseModel):\n    \"\"\"\n    Represents an agent entity.\n\n    Attributes:\n        id (int): The unique identifier of the agent.\n        name (str): The name of the agent.\n        project_id (int): The identifier of the associated project.\n        description (str): The description of the agent.\n        agent_workflow_id (int): The identifier of the associated agent workflow.\n        is_deleted (bool): The flag associated for agent deletion\n    \"\"\"\n\n    __tablename__ = 'agents'\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    name = Column(String)\n    project_id = Column(Integer)\n    description = Column(String)\n    agent_workflow_id = Column(Integer)\n    is_deleted = Column(Boolean, default=False)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the Agent object.\n\n        Returns:\n            str: String representation of the Agent.\n\n        \"\"\"\n        return f\"Agent(id={self.id}, name='{self.name}', project_id={self.project_id}, \" \\\n               f\"description='{self.description}', agent_workflow_id={self.agent_workflow_id},\" \\\n               f\"is_deleted='{self.is_deleted}')\"\n\n    @classmethod\n    def fetch_configuration(cls, session, agent_id: int):\n        \"\"\"\n        Fetches the configuration of an agent.\n\n        Args:\n            session: The database session object.\n            agent_id (int): The ID of the agent.\n\n        Returns:\n            dict: Parsed agent configuration.\n\n        \"\"\"\n\n        agent = session.query(Agent).filter_by(id=agent_id).first()\n        agent_configurations = session.query(AgentConfiguration).filter_by(\n            agent_id=agent_id).all()\n        parsed_config = {\n            \"agent_id\": agent.id,\n            \"name\": agent.name,\n            \"project_id\": agent.project_id,\n            \"description\": agent.description,\n            \"goal\": [],\n            \"instruction\": [],\n            \"constraints\": [],\n            \"tools\": [],\n            \"exit\": None,\n            \"iteration_interval\": None,\n            \"model\": None,\n            \"permission_type\": None,\n            \"LTM_DB\": None,\n            \"memory_window\": None,\n            \"max_iterations\": None,\n            \"is_deleted\": agent.is_deleted,\n            \"knowledge\": None\n        }\n        if not agent_configurations:\n            return parsed_config\n        for item in agent_configurations:\n            parsed_config[item.key] = cls.eval_agent_config(item.key, item.value)\n        return parsed_config\n\n    @classmethod\n    def eval_agent_config(cls, key, value):\n        \"\"\"\n        Evaluates the value of an agent configuration setting based on its key.\n\n        Args:\n            key (str): The key of the configuration setting.\n            value (str): The value of the configuration setting.\n\n        Returns:\n            object: The evaluated value of the configuration setting.\n\n        \"\"\"\n\n        if key in [\"name\", \"description\", \"agent_type\", \"exit\", \"model\", \"permission_type\", \"LTM_DB\",\n                   \"resource_summary\", \"knowledge\"]:\n            return value\n        elif key in [\"project_id\", \"memory_window\", \"max_iterations\", \"iteration_interval\"]:\n            return int(value)\n        elif key in [\"goal\", \"constraints\", \"instruction\", \"is_deleted\"]:\n            return eval(value)\n        elif key == \"tools\":\n            return list(ast.literal_eval(value))\n\n    @classmethod\n    def create_agent_with_config(cls, db, agent_with_config):\n        \"\"\"\n        Creates a new agent with the provided configuration.\n\n        Args:\n            db: The database object.\n            agent_with_config: The object containing the agent and configuration details.\n\n        Returns:\n            Agent: The created agent.\n\n        \"\"\"\n        db_agent = Agent(name=agent_with_config.name, description=agent_with_config.description,\n                         project_id=agent_with_config.project_id)\n        db.session.add(db_agent)\n        db.session.flush()  # Flush pending changes to generate the agent's ID\n        db.session.commit()\n\n        agent_workflow = AgentWorkflow.find_by_name(session=db.session, name=agent_with_config.agent_workflow)\n        logger.info(\"Agent workflow:\", str(agent_workflow))\n        db_agent.agent_workflow_id = agent_workflow.id\n        #\n        # if agent_with_config.agent_type == \"Don't Maintain Task Queue\":\n        #     agent_workflow = db.session.query(AgentWorkflow).filter(AgentWorkflow.name == \"Goal Based Agent\").first()\n        #     logger.info(agent_workflow)\n        #     db_agent.agent_workflow_id = agent_workflow.id\n        # elif agent_with_config.agent_type == \"Maintain Task Queue\":\n        #     agent_workflow = db.session.query(AgentWorkflow).filter(\n        #         AgentWorkflow.name == \"Task Queue Agent With Seed\").first()\n        #     db_agent.agent_workflow_id = agent_workflow.id\n        # elif agent_with_config.agent_type == \"Fixed Task Queue\":\n        #     agent_workflow = db.session.query(AgentWorkflow).filter(\n        #         AgentWorkflow.name == \"Fixed Task Queue\").first()\n        #     db_agent.agent_workflow_id = agent_workflow.id\n\n        db.session.commit()\n\n        # Create Agent Configuration\n        agent_config_values = {\n            \"goal\": agent_with_config.goal,\n            \"instruction\": agent_with_config.instruction,\n            \"constraints\": agent_with_config.constraints,\n            \"tools\": agent_with_config.tools,\n            \"exit\": agent_with_config.exit,\n            \"iteration_interval\": agent_with_config.iteration_interval,\n            \"model\": agent_with_config.model,\n            \"permission_type\": agent_with_config.permission_type,\n            \"LTM_DB\": agent_with_config.LTM_DB,\n            \"max_iterations\": agent_with_config.max_iterations,\n            \"user_timezone\": agent_with_config.user_timezone,\n            \"knowledge\": agent_with_config.knowledge,\n        }\n\n        agent_configurations = [\n            AgentConfiguration(agent_id=db_agent.id, key=key, value=str(value))\n            for key, value in agent_config_values.items()\n        ]\n\n        db.session.add_all(agent_configurations)\n        db.session.commit()\n        db.session.flush()\n        return db_agent\n\n    @classmethod\n    def create_agent_with_template_id(cls, db, project_id, agent_template):\n        \"\"\"\n        Creates a new agent using the provided agent template ID.\n\n        Args:\n            db: The database object.\n            project_id (int): The ID of the project.\n            agent_template: The agent template object.\n\n        Returns:\n            Agent: The created agent.\n\n        \"\"\"\n\n        db_agent = Agent(name=agent_template.name, description=agent_template.description,\n                         project_id=project_id,\n                         agent_workflow_id=agent_template.agent_workflow_id)\n        db.session.add(db_agent)\n        db.session.flush()  # Flush pending changes to generate the agent's ID\n        db.session.commit()\n\n        configs = db.session.query(AgentTemplateConfig).filter(\n            AgentTemplateConfig.agent_template_id == agent_template.id).all()\n\n        agent_configurations = [\n            AgentConfiguration(\n                agent_id=db_agent.id, key=config.key, value=config.value\n            )\n            for config in configs\n        ]\n        db.session.add_all(agent_configurations)\n        db.session.commit()\n        db.session.flush()\n        return db_agent\n\n    @classmethod\n    def create_agent_with_marketplace_template_id(cls, db, project_id, agent_template_id):\n        \"\"\"\n        Creates a new agent using the agent template ID from the marketplace.\n\n        Args:\n            db: The database object.\n            project_id (int): The ID of the project.\n            agent_template_id (int): The ID of the agent template from the marketplace.\n\n        Returns:\n            Agent: The created agent.\n\n        \"\"\"\n\n        agent_template = AgentTemplate.fetch_marketplace_detail(agent_template_id)\n        # we need to create agent workflow if not present. Add it once we get org id in agent workflow\n        db_agent = Agent(name=agent_template[\"name\"], description=agent_template[\"description\"],\n                         project_id=project_id,\n                         agent_workflow_id=agent_template[\"agent_workflow_id\"])\n        db.session.add(db_agent)\n        db.session.flush()  # Flush pending changes to generate the agent's ID\n        db.session.commit()\n\n        agent_configurations = [\n            AgentConfiguration(agent_id=db_agent.id, key=key, value=value[\"value\"])\n            for key, value in agent_template[\"configs\"].items()\n        ]\n        db.session.add_all(agent_configurations)\n        db.session.commit()\n        db.session.flush()\n        return db_agent\n\n    def get_agent_organisation(self, session):\n        \"\"\"\n        Get the organization of the agent.\n\n        Args:\n            session: The database session.\n\n        Returns:\n            Organization: The organization of the agent.\n\n        \"\"\"\n        project = session.query(Project).filter(Project.id == self.project_id).first()\n        return session.query(Organisation).filter(Organisation.id == project.organisation_id).first()\n\n    @classmethod\n    def get_agent_from_id(cls, session, agent_id):\n        \"\"\"\n            Get Agent from agent_id\n\n            Args:\n                session: The database session.\n                agent_id(int) : Unique identifier of an Agent.\n\n            Returns:\n                Agent: Agent object is returned.\n        \"\"\"\n        return session.query(Agent).filter(Agent.id == agent_id).first()\n\n    @classmethod\n    def find_org_by_agent_id(cls, session: object, agent_id: int):\n        \"\"\"\n        Finds the organization for the given agent.\n\n        Args:\n            session: The database session.\n            agent_id: The agent id.\n\n        Returns:\n            Organisation: The found organization.\n        \"\"\"\n        assert session, \"Session cannot be None\"\n        agent = session.query(Agent).filter_by(id=agent_id).first()\n        project = session.query(Project).filter(Project.id == agent.project_id).first()\n        return session.query(Organisation).filter(Organisation.id == project.organisation_id).first()\n\n    @classmethod\n    def get_active_agent_by_id(cls, session, agent_id: int):\n        db_agent = session.query(Agent).filter(Agent.id == agent_id,\n                                               or_(Agent.is_deleted == False, Agent.is_deleted is None)).first()\n        return db_agent\n"
  },
  {
    "path": "superagi/models/agent_config.py",
    "content": "from fastapi import HTTPException\nfrom sqlalchemy import Column, Integer, Text, String\nfrom typing import Union\n\nfrom superagi.config.config import get_config\nfrom superagi.helper.encyption_helper import decrypt_data\nfrom superagi.models.base_model import DBBaseModel\nfrom superagi.models.configuration import Configuration\nfrom superagi.models.models_config import ModelsConfig\nfrom superagi.types.model_source_types import ModelSourceType\nfrom superagi.models.tool import Tool\nfrom superagi.controllers.types.agent_execution_config import AgentRunIn\n\n\nclass AgentConfiguration(DBBaseModel):\n    \"\"\"\n    Agent related configurations like goals, instructions, constraints and tools are stored here\n\n    Attributes:\n        id (int): The unique identifier of the agent configuration.\n        agent_id (int): The identifier of the associated agent.\n        key (str): The key of the configuration setting.\n        value (str): The value of the configuration setting.\n    \"\"\"\n\n    __tablename__ = 'agent_configurations'\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    agent_id = Column(Integer)\n    key = Column(String)\n    value = Column(Text)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the Agent Configuration object.\n\n        Returns:\n            str: String representation of the Agent Configuration.\n\n        \"\"\"\n        return f\"AgentConfiguration(id={self.id}, key={self.key}, value={self.value})\"    \n\n    @classmethod\n    def update_agent_configurations_table(cls, session, agent_id: Union[int, None], updated_details: AgentRunIn):\n\n        updated_details_dict = updated_details.dict()\n\n        # Fetch existing 'toolkits' agent configuration for the given agent_id\n        agent_toolkits_config = session.query(AgentConfiguration).filter(\n            AgentConfiguration.agent_id == agent_id,\n            AgentConfiguration.key == 'toolkits'\n        ).first()\n\n        if agent_toolkits_config:\n            agent_toolkits_config.value = str(updated_details_dict['toolkits'])\n        else:\n            agent_toolkits_config = AgentConfiguration(\n                agent_id=agent_id,\n                key='toolkits',\n                value=str(updated_details_dict['toolkits'])\n            )\n            session.add(agent_toolkits_config)\n        \n        #Fetch existing knowledge for the given agent id and update it accordingly\n        knowledge_config = session.query(AgentConfiguration).filter(\n            AgentConfiguration.agent_id == agent_id,\n            AgentConfiguration.key == 'knowledge'\n        ).first()\n\n        if knowledge_config:\n            knowledge_config.value = str(updated_details_dict['knowledge'])\n        else:\n            knowledge_config = AgentConfiguration(\n                agent_id=agent_id,\n                key='knowledge',\n                value=str(updated_details_dict['knowledge'])\n            )\n            session.add(knowledge_config)\n            \n        # Fetch agent configurations\n        agent_configs = session.query(AgentConfiguration).filter(AgentConfiguration.agent_id == agent_id).all()\n\n        for agent_config in agent_configs:\n            if agent_config.key in updated_details_dict:\n                agent_config.value = str(updated_details_dict[agent_config.key])\n\n        # Commit the changes to the database\n        session.commit()\n\n        return \"Details updated successfully\"\n    \n    @classmethod\n    def get_model_api_key(cls, session, agent_id: int, model: str):\n        \"\"\"\n        Get the model API key from the agent id.\n\n        Args:\n            session (Session): The database session\n            agent_id (int): The agent identifier\n            model (str): The model name\n\n        Returns:\n            str: The model API key.\n        \"\"\"\n        config_model = ModelsConfig.fetch_value_by_agent_id(session, agent_id, model)\n        return config_model\n#         selected_model_source = ModelSourceType.get_model_source_from_model(model)\n#         if selected_model_source.value == config_model_source:\n#             config_value = Configuration.fetch_value_by_agent_id(session, agent_id, \"model_api_key\")\n#             model_api_key = decrypt_data(config_value)\n#             return model_api_key\n#\n#         if selected_model_source == ModelSourceType.GooglePalm:\n#             return get_config(\"PALM_API_KEY\")\n#\n#         if selected_model_source == ModelSourceType.Replicate:\n#             return get_config(\"REPLICATE_API_TOKEN\")\n#         return get_config(\"OPENAI_API_KEY\")\n\n    @classmethod\n    def get_agent_config_by_key_and_agent_id(cls, session, key: str, agent_id: int):\n        agent_config = session.query(AgentConfiguration).filter(\n            AgentConfiguration.agent_id == agent_id,\n            AgentConfiguration.key == key\n        ).first()\n\n        return agent_config"
  },
  {
    "path": "superagi/models/agent_execution.py",
    "content": "import json\nfrom datetime import datetime\n\nfrom sqlalchemy import Column, Integer, String, DateTime\n\nfrom superagi.models.base_model import DBBaseModel\nfrom superagi.models.workflows.agent_workflow_step import AgentWorkflowStep\nfrom superagi.models.workflows.iteration_workflow import IterationWorkflow\n\n\nclass AgentExecution(DBBaseModel):\n    \"\"\"\n    Represents single agent run\n\n    Attributes:\n        id (int): The unique identifier of the agent execution.\n        status (str): The status of the agent execution. Possible values: 'CREATED', 'RUNNING', 'PAUSED',\n            'COMPLETED', 'TERMINATED'.\n        name (str): The name of the agent execution.\n        agent_id (int): The identifier of the associated agent.\n        last_execution_time (datetime): The timestamp of the last execution time.\n        num_of_calls (int): The number of calls made during the execution.\n        num_of_tokens (int): The number of tokens used during the execution.\n        current_agent_step_id (int): The identifier of the current step in the execution.\n    \"\"\"\n\n    __tablename__ = 'agent_executions'\n\n    id = Column(Integer, primary_key=True)\n    status = Column(String)  # like ('CREATED', 'RUNNING', 'PAUSED', 'COMPLETED', 'TERMINATED')\n    name = Column(String)\n    agent_id = Column(Integer)\n    last_execution_time = Column(DateTime)\n    num_of_calls = Column(Integer, default=0)\n    num_of_tokens = Column(Integer, default=0)\n    current_agent_step_id = Column(Integer)\n    permission_id = Column(Integer)\n    iteration_workflow_step_id = Column(Integer)\n    current_feed_group_id = Column(String)\n    last_shown_error_id = Column(Integer)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the AgentExecution object.\n\n        Returns:\n            str: String representation of the AgentExecution.\n        \"\"\"\n\n        return (\n            f\"AgentExecution(id={self.id}, name={self.name}, status='{self.status}', \"\n            f\"last_execution_time='{self.last_execution_time}', current_agent_step_id={self.current_agent_step_id}, \"\n            f\"agent_id={self.agent_id}, num_of_calls={self.num_of_calls}, num_of_tokens={self.num_of_tokens},\"\n            f\"permission_id={self.permission_id}, iteration_workflow_step_id={self.iteration_workflow_step_id})\"\n        )\n\n    def to_dict(self):\n        \"\"\"\n        Converts the AgentExecution object to a dictionary.\n\n        Returns:\n            dict: Dictionary representation of the AgentExecution.\n        \"\"\"\n\n        return {\n            'id': self.id,\n            'status': self.status,\n            'name': self.name,\n            'agent_id': self.agent_id,\n            'last_execution_time': self.last_execution_time.isoformat(),\n            'num_of_calls': self.num_of_calls,\n            'num_of_tokens': self.num_of_tokens,\n            'current_agent_step_id': self.current_agent_step_id,\n            'permission_id': self.permission_id,\n            'iteration_workflow_step_id': self.iteration_workflow_step_id\n        }\n\n    def to_json(self):\n        \"\"\"\n        Converts the AgentExecution object to a JSON string.\n\n        Returns:\n            str: JSON string representation of the AgentExecution.\n        \"\"\"\n\n        return json.dumps(self.to_dict())\n\n    @classmethod\n    def from_json(cls, json_data):\n        \"\"\"\n        Creates an AgentExecution object from a JSON string.\n\n        Args:\n            json_data (str): JSON string representing the AgentExecution object.\n\n        Returns:\n            AgentExecution: The created AgentExecution object.\n        \"\"\"\n\n        data = json.loads(json_data)\n        last_execution_time = datetime.fromisoformat(data['last_execution_time'])\n        return cls(\n            id=data['id'],\n            status=data['status'],\n            name=data['name'],\n            agent_id=data['agent_id'],\n            last_execution_time=last_execution_time,\n            num_of_calls=data['num_of_calls'],\n            num_of_tokens=data['num_of_tokens'],\n            current_agent_step_id=data['current_agent_step_id'],\n            permission_id=data['permission_id'],\n            iteration_workflow_step_id=data['iteration_workflow_step_id']\n        )\n\n    @classmethod\n    def get_agent_execution_from_id(cls, session, agent_execution_id):\n        \"\"\"\n            Get Agent from agent_id\n\n            Args:\n                session: The database session.\n                agent_execution_id(int) : Unique identifier of an Agent Execution.\n\n            Returns:\n                AgentExecution: AgentExecution object is returned.\n        \"\"\"\n        return session.query(AgentExecution).filter(AgentExecution.id == agent_execution_id).first()\n\n    @classmethod\n    def find_by_id(cls, session, execution_id: int):\n        \"\"\"\n        Finds an AgentExecution by its id.\n\n        Args:\n            session: The database session.\n            id (int): The id of the AgentExecution.\n\n        Returns:\n            AgentExecution: The AgentExecution object.\n        \"\"\"\n\n        return session.query(AgentExecution).filter(AgentExecution.id == execution_id).first()\n\n    @classmethod\n    def update_tokens(self, session, agent_execution_id: int, total_tokens: int, new_llm_calls: int = 1):\n        agent_execution = session.query(AgentExecution).filter(\n            AgentExecution.id == agent_execution_id).first()\n        agent_execution.num_of_calls += new_llm_calls\n        agent_execution.num_of_tokens += total_tokens\n        session.commit()\n\n\n    @classmethod\n    def assign_next_step_id(cls, session, agent_execution_id: int, next_step_id: int):\n        \"\"\"Assigns next agent workflow step id to agent execution\n\n        Args:\n            session: The database session.\n            agent_execution_id (int): The id of the agent execution.\n            next_step_id (int): The id of the next agent workflow step.\n        \"\"\"\n        agent_execution = session.query(AgentExecution).filter(AgentExecution.id == agent_execution_id).first()\n        agent_execution.current_agent_step_id = next_step_id\n        next_step = AgentWorkflowStep.find_by_id(session, next_step_id)\n        if next_step.action_type == \"ITERATION_WORKFLOW\":\n            trigger_step = IterationWorkflow.fetch_trigger_step_id(session, next_step.action_reference_id)\n            agent_execution.iteration_workflow_step_id = trigger_step.id\n        session.commit()\n\n    @classmethod\n    def get_execution_by_agent_id_and_status(cls, session, agent_id: int, status_filter: str):\n        db_agent_execution = session.query(AgentExecution).filter(AgentExecution.agent_id == agent_id, AgentExecution.status == status_filter).first()\n        return db_agent_execution\n\n\n    @classmethod\n    def get_all_executions_by_status_and_agent_id(cls, session, agent_id, execution_state_change_input, current_status: str):\n        db_execution_arr = []\n        if  execution_state_change_input.run_ids is not None:\n            db_execution_arr = session.query(AgentExecution).filter(AgentExecution.agent_id == agent_id, AgentExecution.status == current_status,AgentExecution.id.in_(execution_state_change_input.run_ids)).all()\n        else:\n            db_execution_arr = session.query(AgentExecution).filter(AgentExecution.agent_id == agent_id, AgentExecution.status == current_status).all()\n        return db_execution_arr\n    \n    @classmethod\n    def get_all_executions_by_filter_config(cls, session, agent_id: int, filter_config):\n        db_execution_query = session.query(AgentExecution).filter(AgentExecution.agent_id == agent_id)\n        if filter_config.run_ids is not None:\n            db_execution_query = db_execution_query.filter(AgentExecution.id.in_(filter_config.run_ids))\n\n        if filter_config.run_status_filter is not None and filter_config.run_status_filter in [\"CREATED\", \"RUNNING\",\n                                                                                               \"PAUSED\", \"COMPLETED\",\n                                                                                               \"TERMINATED\"]:\n            db_execution_query = db_execution_query.filter(AgentExecution.status == filter_config.run_status_filter)\n\n        db_execution_arr = db_execution_query.all()\n        return db_execution_arr\n\n    @classmethod\n    def validate_run_ids(cls, session, run_ids: list, organisation_id: int):\n        from superagi.models.agent import Agent\n        from superagi.models.project import Project\n\n        run_ids=list(set(run_ids))\n        agent_ids=session.query(AgentExecution.agent_id).filter(AgentExecution.id.in_(run_ids)).distinct().all()\n        agent_ids = [id for (id,) in agent_ids]\n        project_ids=session.query(Agent.project_id).filter(Agent.id.in_(agent_ids)).distinct().all()\n        project_ids = [id for (id,) in project_ids]\n        org_ids=session.query(Project.organisation_id).filter(Project.id.in_(project_ids)).distinct().all()\n        org_ids = [id for (id,) in org_ids]\n\n        if len(org_ids) > 1 or org_ids[0] != organisation_id:\n            raise Exception(f\"one or more run IDs not found\")\n"
  },
  {
    "path": "superagi/models/agent_execution_config.py",
    "content": "from sqlalchemy import Column, Integer, String, Text\n\nfrom superagi.models.base_model import DBBaseModel\n\nimport ast\nimport json\nfrom superagi.models.knowledges import Knowledges\n\nfrom superagi.models.tool import Tool\nfrom superagi.models.workflows.agent_workflow import AgentWorkflow\n\n\nclass AgentExecutionConfiguration(DBBaseModel):\n    \"\"\"\n    Agent Execution related configurations like goals, instructions are stored here\n\n    Attributes:\n        id (int): The unique identifier of the agent execution config.\n        agent_execution_id (int): The identifier of the associated agent execution.\n        key (str): The key of the configuration setting.\n        value (str): The value of the configuration setting.\n    \"\"\"\n\n    __tablename__ = 'agent_execution_configs'\n\n    id = Column(Integer, primary_key=True)\n    agent_execution_id = Column(Integer)\n    key = Column(String)\n    value = Column(Text)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the AgentExecutionConfig object.\n\n        Returns:\n            str: String representation of the AgentTemplateConfig.\n        \"\"\"\n\n        return f\"AgentExecutionConfig(id={self.id}, agent_execution_id='{self.agent_execution_id}', \" \\\n               f\"key='{self.key}', value='{self.value}')\"\n\n    @classmethod\n    def add_or_update_agent_execution_config(cls, session, execution, agent_execution_configs):\n        agent_execution_configurations = [\n            AgentExecutionConfiguration(agent_execution_id=execution.id, key=key, value=str(value))\n            for key, value in agent_execution_configs.items()\n        ]\n        for agent_execution in agent_execution_configurations:\n            agent_execution_config = (\n                session.query(AgentExecutionConfiguration)\n                .filter(\n                    AgentExecutionConfiguration.agent_execution_id == execution.id,\n                    AgentExecutionConfiguration.key == agent_execution.key\n                )\n                .first()\n            )\n\n            if agent_execution_config:\n                agent_execution_config.value = str(agent_execution.value)\n            else:\n                agent_execution_config = AgentExecutionConfiguration(\n                    agent_execution_id=execution.id,\n                    key=agent_execution.key,\n                    value=str(agent_execution.value)\n                )\n                session.add(agent_execution_config)\n            session.commit()\n\n    @classmethod\n    def fetch_configuration(cls, session, execution_id):\n        \"\"\"\n        Fetches the execution configuration of an agent.\n\n        Args:\n            session: The database session object.\n            execution (AgentExecution): The AgentExecution of the agent.\n\n        Returns:\n            dict: Parsed agent configuration.\n\n        \"\"\"\n        agent_configurations = session.query(AgentExecutionConfiguration).filter_by(\n            agent_execution_id=execution_id).all()\n        parsed_config = {\n            \"goal\": [],\n            \"instruction\": [],\n            \"tools\": []\n        }\n        if not agent_configurations:\n            return parsed_config\n        for item in agent_configurations:\n            parsed_config[item.key] = cls.eval_agent_config(item.key, item.value)\n        return parsed_config\n\n    @classmethod\n    def eval_agent_config(cls, key, value):\n        \"\"\"\n        Evaluates the value of an agent execution configuration setting based on its key.\n\n        Args:\n            key (str): The key of the execution configuration setting.\n            value (str): The value of execution configuration setting.\n\n        Returns:\n            object: The evaluated value of the execution configuration setting.\n\n        \"\"\"\n\n        if key == \"goal\" or key == \"instruction\" or key == \"tools\":\n            return eval(value)\n\n    @classmethod\n    def build_agent_execution_config(cls, session, agent, results_agent, results_agent_execution, total_calls, total_tokens):\n        results_agent_dict = {result.key: result.value for result in results_agent}\n        results_agent_execution_dict = {result.key: result.value for result in results_agent_execution}\n\n        for key, value in results_agent_execution_dict.items():\n            if key in results_agent_dict and value is not None:\n                results_agent_dict[key] = value\n\n        # Construct the response\n        if 'goal' in results_agent_dict:\n            results_agent_dict['goal'] = eval(results_agent_dict['goal'])\n\n        if \"toolkits\" in results_agent_dict:\n            results_agent_dict[\"toolkits\"] = list(ast.literal_eval(results_agent_dict[\"toolkits\"]))\n\n        if 'tools' in results_agent_dict:\n            results_agent_dict[\"tools\"] = list(ast.literal_eval(results_agent_dict[\"tools\"]))\n            tools = session.query(Tool).filter(Tool.id.in_(results_agent_dict[\"tools\"])).all()\n            results_agent_dict[\"tools\"] = tools\n        if 'instruction' in results_agent_dict:\n            results_agent_dict['instruction'] = eval(results_agent_dict['instruction'])\n\n        if 'constraints' in results_agent_dict:\n            results_agent_dict['constraints'] = eval(results_agent_dict['constraints'])\n\n        results_agent_dict[\"name\"] = agent.name\n        agent_workflow = AgentWorkflow.find_by_id(session, agent.agent_workflow_id)\n        results_agent_dict[\"agent_workflow\"] = agent_workflow.name\n        results_agent_dict[\"description\"] = agent.description\n        results_agent_dict[\"calls\"] = total_calls\n        results_agent_dict[\"tokens\"] = total_tokens\n\n        knowledge_name = \"\"\n        if 'knowledge' in results_agent_dict and results_agent_dict['knowledge'] != 'None':\n            if type(results_agent_dict['knowledge'])==int:\n                results_agent_dict['knowledge'] = int(results_agent_dict['knowledge'])\n            knowledge = session.query(Knowledges).filter(Knowledges.id == results_agent_dict['knowledge']).first()\n            knowledge_name = knowledge.name if knowledge is not None else \"\"\n        results_agent_dict['knowledge_name'] = knowledge_name\n\n        return results_agent_dict\n\n    @classmethod\n    def build_scheduled_agent_execution_config(cls, session, agent, results_agent, total_calls, total_tokens):\n        results_agent_dict = {result.key: result.value for result in results_agent}\n            \n        # Construct the response\n        if 'goal' in results_agent_dict:\n            results_agent_dict['goal'] = eval(results_agent_dict['goal'])\n\n        if \"toolkits\" in results_agent_dict:\n            results_agent_dict[\"toolkits\"] = list(ast.literal_eval(results_agent_dict[\"toolkits\"]))\n\n        if 'tools' in results_agent_dict:\n            results_agent_dict[\"tools\"] = list(ast.literal_eval(results_agent_dict[\"tools\"]))\n            tools = session.query(Tool).filter(Tool.id.in_(results_agent_dict[\"tools\"])).all()\n            results_agent_dict[\"tools\"] = tools\n        if 'instruction' in results_agent_dict:\n            results_agent_dict['instruction'] = eval(results_agent_dict['instruction'])\n\n        if 'constraints' in results_agent_dict:\n            results_agent_dict['constraints'] = eval(results_agent_dict['constraints'])\n\n        results_agent_dict[\"name\"] = agent.name\n        agent_workflow = AgentWorkflow.find_by_id(session, agent.agent_workflow_id)\n        results_agent_dict[\"agent_workflow\"] = agent_workflow.name\n        results_agent_dict[\"description\"] = agent.description\n        results_agent_dict[\"calls\"] = total_calls\n        results_agent_dict[\"tokens\"] = total_tokens\n\n        knowledge_name = \"\"\n        if 'knowledge' in results_agent_dict and results_agent_dict['knowledge'] != 'None':\n            if type(results_agent_dict['knowledge'])==int:\n                results_agent_dict['knowledge'] = int(results_agent_dict['knowledge'])\n            knowledge = session.query(Knowledges).filter(Knowledges.id == results_agent_dict['knowledge']).first()\n            knowledge_name = knowledge.name if knowledge is not None else \"\"\n        results_agent_dict['knowledge_name'] = knowledge_name \n\n        return results_agent_dict\n    \n    @classmethod\n    def fetch_value(cls, session, execution_id: int, key: str):\n        \"\"\"\n           Fetches the value of a specific execution configuration setting for an agent.\n\n           Args:\n               session: The database session object.\n               execution_id (int): The ID of the agent execution.\n               key (str): The key of the execution configuration setting.\n\n           Returns:\n               AgentExecutionConfiguration: The execution configuration setting object if found, else None.\n\n       \"\"\"\n\n        return session.query(AgentExecutionConfiguration).filter(\n            AgentExecutionConfiguration.agent_execution_id == execution_id,\n            AgentExecutionConfiguration.key == key).first()"
  },
  {
    "path": "superagi/models/agent_execution_feed.py",
    "content": "from sqlalchemy import Column, Integer, Text, String, asc\nfrom sqlalchemy.orm import Session\n\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.base_model import DBBaseModel\n\n\nclass AgentExecutionFeed(DBBaseModel):\n    \"\"\"\n    Feed of the agent execution.\n\n    Attributes:\n        id (int): The unique identifier of the agent execution feed.\n        agent_execution_id (int): The identifier of the associated agent execution.\n        agent_id (int): The identifier of the associated agent.\n        feed (str): The feed content.\n        role (str): The role of the feed entry. Possible values: 'system', 'user', or 'assistant'.\n        extra_info (str): Additional information related to the feed entry.\n    \"\"\"\n\n    __tablename__ = 'agent_execution_feeds'\n\n    id = Column(Integer, primary_key=True)\n    agent_execution_id = Column(Integer)\n    agent_id = Column(Integer)\n    feed = Column(Text)\n    role = Column(String)\n    extra_info = Column(String)\n    feed_group_id = Column(String)\n    error_message = Column(String)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the AgentExecutionFeed object.\n\n        Returns:\n            str: String representation of the AgentExecutionFeed.\n        \"\"\"\n\n        return f\"AgentExecutionFeed(id={self.id}, \" \\\n               f\"agent_execution_id={self.agent_execution_id}, \" \\\n               f\"feed='{self.feed}', role='{self.role}', extra_info='{self.extra_info}', feed_group_id='{self.feed_group_id}')\"\n\n    @classmethod\n    def get_last_tool_response(cls, session: Session, agent_execution_id: int, tool_name: str = None):\n        agent_execution_feeds = session.query(AgentExecutionFeed).filter(\n            AgentExecutionFeed.agent_execution_id == agent_execution_id,\n            AgentExecutionFeed.role == \"system\").order_by(AgentExecutionFeed.created_at.desc()).all()\n\n        for agent_execution_feed in agent_execution_feeds:\n            if tool_name and not agent_execution_feed.feed.startswith(\"Tool \" + tool_name):\n                continue\n            if agent_execution_feed.feed.startswith(\"Tool\"):\n                return agent_execution_feed.feed\n        return \"\"\n\n    @classmethod\n    def fetch_agent_execution_feeds(cls, session, agent_execution_id: int):\n        agent_execution = AgentExecution.find_by_id(session, agent_execution_id)\n        agent_feeds = session.query(AgentExecutionFeed.role, AgentExecutionFeed.feed, AgentExecutionFeed.id) \\\n            .filter(AgentExecutionFeed.agent_execution_id == agent_execution_id,\n                    AgentExecutionFeed.feed_group_id == agent_execution.current_feed_group_id) \\\n            .order_by(asc(AgentExecutionFeed.created_at)) \\\n            .all()\n        # return entire feed if it is not default feed. Default feed has prompt in the first 2 entries.\n        if agent_execution.current_feed_group_id != \"DEFAULT\":\n            return agent_feeds\n        else:\n            return agent_feeds[2:]\n"
  },
  {
    "path": "superagi/models/agent_execution_permission.py",
    "content": "from sqlalchemy import Column, Integer, Text, String, Boolean, ForeignKey\nfrom sqlalchemy.orm import relationship\nfrom superagi.models.base_model import DBBaseModel\nfrom superagi.models.agent_execution import AgentExecution\n\n\nclass AgentExecutionPermission(DBBaseModel):\n    \"\"\"\n    Agent Execution Permissions at each step to be approved or rejected by the user.\n\n    Attributes:\n        id (Integer): The primary key of the agent execution permission record.\n        agent_execution_id (Integer): The ID of the agent execution this permission record is associated with.\n        agent_id (Integer): The ID of the agent this permission record is associated with.\n        status (String): The status of the agent execution permission, APPROVED, REJECTED, or PENDING.\n        tool_name (String): The name of the tool or service that requires the permission.\n        user_feedback (Text): Any feedback provided by the user regarding the agent execution permission.\n        assistant_reply (Text): The reply or message sent back to the user by the assistant.\n\n    Methods:\n        __repr__: Returns a string representation of the AgentExecutionPermission instance.\n    \"\"\"\n    __tablename__ = 'agent_execution_permissions'\n\n    id = Column(Integer, primary_key=True)\n    agent_execution_id = Column(Integer)\n    agent_id = Column(Integer)\n    status = Column(String)\n    tool_name = Column(String)\n    user_feedback = Column(Text)\n    question = Column(Text)\n    assistant_reply = Column(Text)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the AgentExecutionPermission instance.\n        \"\"\"\n        return f\"AgentExecutionPermission(id={self.id}, \" \\\n               f\"agent_execution_id={self.agent_execution_id}, \" \\\n               f\"agent_id={self.agent_id}, \" \\\n               f\"status={self.status}, \" \\\n               f\"tool_name={self.tool_name}, \" \\\n               f\"question={self.question}, \" \\\n               f\"response={self.user_feedback})\"\n"
  },
  {
    "path": "superagi/models/agent_schedule.py",
    "content": "from sqlalchemy import Column, Integer, String, Date, DateTime\nfrom superagi.models.base_model import DBBaseModel\nfrom superagi.controllers.types.agent_schedule import AgentScheduleInput\n\nclass AgentSchedule(DBBaseModel):\n    \"\"\"\n    Represents an Agent Scheduler record in the database.\n\n    Attributes:\n        id (Integer): The primary key of the agent scheduler record.\n        agent_id (Integer): The ID of the agent being scheduled.\n        start_time (DateTime): The date and time from which the agent is scheduled.\n        recurrence_interval (String): Stores \"none\" if not recurring,\n            or a time interval like '2 Weeks', '1 Month', '2 Minutes' based on input.\n        expiry_date (DateTime): The date and time when the agent is scheduled to stop runs.\n        expiry_runs (Integer): The number of runs before the agent expires.\n        current_runs (Integer): Number of runs executed in that schedule.\n        status: state in which the schedule is, \"SCHEDULED\" or \"STOPPED\" or \"COMPLETED\" or \"TERMINATED\"\n\n    Methods:\n        __repr__: Returns a string representation of the AgentSchedule instance.\n\n    \"\"\"\n    __tablename__ = 'agent_schedule'\n\n    id = Column(Integer, primary_key=True)\n    agent_id = Column(Integer)\n    start_time = Column(DateTime)\n    next_scheduled_time =  Column(DateTime)\n    recurrence_interval = Column(String)\n    expiry_date = Column(DateTime)\n    expiry_runs = Column(Integer)\n    current_runs = Column(Integer)\n    status = Column(String)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the AgentSchedule instance.\n        \"\"\"\n        return f\"AgentSchedule(id={self.id}, \" \\\n               f\"agent_id={self.agent_id}, \" \\\n               f\"start_time={self.start_time}, \" \\\n               f\"next_scheduled_time={self.next_scheduled_time}, \" \\\n               f\"recurrence_interval={self.recurrence_interval}, \" \\\n               f\"expiry_date={self.expiry_date}, \" \\\n               f\"expiry_runs={self.expiry_runs}), \" \\\n               f\"current_runs={self.expiry_runs}), \" \\\n               f\"status={self.status}), \" \n    \n    @classmethod\n    def save_schedule_from_config(cls, session, db_agent, schedule_config: AgentScheduleInput):\n        agent_schedule = AgentSchedule(\n            agent_id=db_agent.id,\n            start_time=schedule_config.start_time,\n            next_scheduled_time=schedule_config.start_time,\n            recurrence_interval=schedule_config.recurrence_interval,\n            expiry_date=schedule_config.expiry_date,\n            expiry_runs=schedule_config.expiry_runs,\n            current_runs=0,\n            status=\"SCHEDULED\"\n        )\n\n        agent_schedule.agent_id = db_agent.id\n        session.add(agent_schedule)\n        session.commit()\n        return agent_schedule\n    \n    @classmethod\n    def find_by_agent_id(cls, session, agent_id: int):\n        db_schedule=session.query(AgentSchedule).filter(AgentSchedule.agent_id == agent_id).first()\n        return db_schedule\n"
  },
  {
    "path": "superagi/models/agent_template.py",
    "content": "import json\n\nimport requests\nfrom sqlalchemy import Column, Integer, String, Text\n\nfrom superagi.lib.logger import logger\nfrom superagi.models.agent_template_config import AgentTemplateConfig\nfrom superagi.models.workflows.agent_workflow import AgentWorkflow\nfrom superagi.models.base_model import DBBaseModel\nfrom superagi.models.workflows.iteration_workflow import IterationWorkflow\n\nmarketplace_url = \"https://app.superagi.com/api/\"\n# marketplace_url = \"http://localhost:8001/\"\n\n\nclass AgentTemplate(DBBaseModel):\n    \"\"\"\n    Preconfigured agent templates that can be used to create agents.\n\n    Attributes:\n        id (int): The unique identifier of the agent template.\n        organisation_id (int): The organization ID of the user or -1 if the template is public.\n        agent_workflow_id (int): The identifier of the workflow that the agent will use.\n        name (str): The name of the agent template.\n        description (str): The description of the agent template.\n        marketplace_template_id (int): The ID of the template in the marketplace.\n    \"\"\"\n\n    __tablename__ = 'agent_templates'\n\n    id = Column(Integer, primary_key=True)\n    organisation_id = Column(Integer)\n    agent_workflow_id = Column(Integer)\n    name = Column(String)\n    description = Column(Text)\n    marketplace_template_id = Column(Integer)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the AgentTemplate object.\n\n        Returns:\n            str: String representation of the AgentTemplate.\n        \"\"\"\n\n        return f\"AgentTemplate(id={self.id}, name='{self.name}', \" \\\n               f\"description='{self.description}')\"\n\n    def to_dict(self):\n        \"\"\"\n        Converts the AgentTemplate object to a dictionary.\n\n        Returns:\n            dict: Dictionary representation of the AgentTemplate.\n        \"\"\"\n\n        return {\n            'id': self.id,\n            'name': self.name,\n            'description': self.description\n        }\n\n    def to_json(self):\n        \"\"\"\n        Converts the AgentTemplate object to a JSON string.\n\n        Returns:\n            str: JSON string representation of the AgentTemplate.\n        \"\"\"\n\n        return json.dumps(self.to_dict())\n\n    @classmethod\n    def from_json(cls, json_data):\n        \"\"\"\n        Creates an AgentTemplate object from a JSON string.\n\n        Args:\n            json_data (str): JSON string representing the AgentTemplate.\n\n        Returns:\n            AgentTemplate: AgentTemplate object created from the JSON string.\n        \"\"\"\n\n        data = json.loads(json_data)\n        return cls(\n            id=data['id'],\n            name=data['name'],\n            description=data['description']\n        )\n\n    @classmethod\n    def main_keys(cls):\n        \"\"\"\n        Returns the main keys for fetching agent templates.\n\n        Returns:\n            list: List of main keys.\n        \"\"\"\n\n        keys_to_fetch = [\"goal\", \"instruction\", \"constraints\", \"tools\", \"exit\", \"iteration_interval\", \"model\",\n                         \"permission_type\", \"LTM_DB\", \"max_iterations\", \"knowledge\"]\n        return keys_to_fetch\n\n    @classmethod\n    def fetch_marketplace_list(cls, search_str, page):\n        \"\"\"\n        Fetches a list of agent templates from the marketplace.\n\n        Args:\n            search_str (str): The search string to filter agent templates.\n            page (int): The page number of the result set.\n\n        Returns:\n            list: List of agent templates fetched from the marketplace.\n        \"\"\"\n\n        headers = {'Content-Type': 'application/json'}\n        response = requests.get(\n            marketplace_url + \"agent_templates/marketplace/list?search=\" + search_str + \"&page=\" + str(page),\n            headers=headers, timeout=10)\n        if response.status_code == 200:\n            return response.json()\n        else:\n            return []\n\n    @classmethod\n    def fetch_marketplace_detail(cls, agent_template_id):\n        \"\"\"\n        Fetches the details of an agent template from the marketplace.\n\n        Args:\n            agent_template_id (int): The ID of the agent template.\n\n        Returns:\n            dict: Details of the agent template fetched from the marketplace.\n        \"\"\"\n\n        headers = {'Content-Type': 'application/json'}\n        response = requests.get(\n            marketplace_url + \"agent_templates/marketplace/template_details/\" + str(agent_template_id),\n            headers=headers, timeout=10)\n        if response.status_code == 200:\n            return response.json()\n        else:\n            return {}\n\n    @classmethod\n    def clone_agent_template_from_marketplace(cls, db, organisation_id: int, agent_template_id: int):\n        \"\"\"\n        Clones an agent template from the marketplace and saves it in the database.\n\n        Args:\n            db: The database object.\n            organisation_id (int): The organization ID.\n            agent_template_id (int): The ID of the agent template in the marketplace.\n\n        Returns:\n            AgentTemplate: The cloned agent template object.\n        \"\"\"\n\n        agent_template = AgentTemplate.fetch_marketplace_detail(agent_template_id)\n        agent_workflow = db.session.query(AgentWorkflow).filter(\n            AgentWorkflow.name == agent_template[\"agent_workflow_name\"]).first()\n        # keeping it backward compatible\n        logger.info(\"agent_workflow:\" + str(agent_template[\"agent_workflow_name\"]))\n        if not agent_workflow:\n            workflow_id = AgentTemplate.fetch_iteration_agent_template_mapping(db.session, agent_template[\"agent_workflow_name\"])\n            agent_workflow = db.session.query(AgentWorkflow).filter(AgentWorkflow.id == workflow_id).first()\n\n        template = AgentTemplate(organisation_id=organisation_id, agent_workflow_id=agent_workflow.id,\n                                 name=agent_template[\"name\"], description=agent_template[\"description\"],\n                                 marketplace_template_id=agent_template[\"id\"])\n        db.session.add(template)\n        db.session.commit()\n        db.session.flush()\n\n        agent_configurations = []\n        for key, value in agent_template[\"configs\"].items():\n            # Converting tool names to ids and saving it in agent configuration\n            agent_configurations.append(\n                AgentTemplateConfig(agent_template_id=template.id, key=key, value=str(value[\"value\"])))\n\n        db.session.add_all(agent_configurations)\n        db.session.commit()\n        db.session.flush()\n        return template\n\n    @classmethod\n    def fetch_iteration_agent_template_mapping(cls, session, name):\n        if name == \"Fixed Task Queue\":\n            agent_workflow = AgentWorkflow.find_by_name(session, \"Fixed Task Workflow\")\n            return agent_workflow.id\n\n        if name == \"Maintain Task Queue\":\n            agent_workflow = AgentWorkflow.find_by_name(session, \"Dynamic Task Workflow\")\n            return agent_workflow.id\n\n        if name == \"Don't Maintain Task Queue\" or name == \"Goal Based Agent\":\n            agent_workflow = AgentWorkflow.find_by_name(session, \"Goal Based Workflow\")\n            return agent_workflow.id\n\n    @classmethod\n    def eval_agent_config(cls, key, value):\n        \"\"\"\n        Evaluates the value of an agent configuration key.\n\n        Args:\n            key (str): The key of the agent configuration.\n            value (str): The value of the agent configuration.\n\n        Returns:\n            object: The evaluated value of the agent configuration.\n        \"\"\"\n\n        if key in [\"name\", \"description\", \"exit\", \"model\", \"permission_type\", \"LTM_DB\"]:\n            return value\n        elif key in [\"project_id\", \"memory_window\", \"max_iterations\", \"iteration_interval\", \"knowledge\"]:\n            if value is not None and value != 'None':\n                return int(value)\n            else:\n                return None\n        elif key == \"goal\" or key == \"constraints\" or key == \"instruction\":\n            return eval(value)\n        elif key == \"tools\":\n            return [str(x) for x in eval(value)]"
  },
  {
    "path": "superagi/models/agent_template_config.py",
    "content": "import json\n\nfrom sqlalchemy import Column, Integer, String, Text\n\nfrom superagi.models.base_model import DBBaseModel\n\n\nclass AgentTemplateConfig(DBBaseModel):\n    \"\"\"\n    Agent template related configurations like goals, instructions, constraints and tools are stored here\n\n    Attributes:\n        id (int): The unique identifier of the agent template config.\n        agent_template_id (int): The identifier of the associated agent template.\n        key (str): The key of the configuration setting.\n        value (str): The value of the configuration setting.\n    \"\"\"\n\n    __tablename__ = 'agent_template_configs'\n\n    id = Column(Integer, primary_key=True)\n    agent_template_id = Column(Integer)\n    key = Column(String)\n    value = Column(Text)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the AgentTemplateConfig object.\n\n        Returns:\n            str: String representation of the AgentTemplateConfig.\n        \"\"\"\n\n        return f\"AgentTemplateConfig(id={self.id}, agent_template_id='{self.agent_template_id}', \" \\\n               f\"key='{self.key}', value='{self.value}')\"\n\n    def to_dict(self):\n        \"\"\"\n        Converts the AgentTemplateConfig object to a dictionary.\n\n        Returns:\n            dict: Dictionary representation of the AgentTemplateConfig.\n        \"\"\"\n\n        return {\n            'id': self.id,\n            'agent_template_id': self.agent_template_id,\n            'key': self.key,\n            'value': self.value\n        }\n\n    def to_json(self):\n        \"\"\"\n        Converts the AgentTemplateConfig object to a JSON string.\n\n        Returns:\n            str: JSON string representation of the AgentTemplateConfig.\n        \"\"\"\n\n        return json.dumps(self.to_dict())\n\n    @classmethod\n    def from_json(cls, json_data):\n        \"\"\"\n        Creates an AgentTemplateConfig object from a JSON string.\n\n        Args:\n            json_data (str): JSON string representing the AgentTemplateConfig.\n\n        Returns:\n            AgentTemplateConfig: AgentTemplateConfig object created from the JSON string.\n        \"\"\"\n\n        data = json.loads(json_data)\n        return cls(\n            id=data['id'],\n            agent_template_id=data['agent_template_id'],\n            key=data['key'],\n            value=data['value']\n        )\n"
  },
  {
    "path": "superagi/models/api_key.py",
    "content": "from sqlalchemy import Column, Integer, String, Boolean\nfrom superagi.models.base_model import DBBaseModel\nfrom sqlalchemy import or_\n\nclass ApiKey(DBBaseModel):\n    \"\"\"\n\n    Attributes:\n        \n\n    Methods:\n    \"\"\"\n    __tablename__ = 'api_keys'\n\n    id = Column(Integer, primary_key=True)\n    org_id = Column(Integer)\n    name = Column(String)\n    key = Column(String)\n    is_expired= Column(Boolean)\n\n    @classmethod\n    def get_by_org_id(cls, session, org_id: int):\n        db_api_keys=session.query(ApiKey).filter(ApiKey.org_id==org_id,or_(ApiKey.is_expired == False, ApiKey.is_expired == None)).all()\n        return db_api_keys\n\n    @classmethod\n    def get_by_id(cls, session, id: int):\n        db_api_key=session.query(ApiKey).filter(ApiKey.id==id,or_(ApiKey.is_expired == False, ApiKey.is_expired == None)).first()\n        return db_api_key\n\n    @classmethod\n    def delete_by_id(cls, session,id: int):\n        db_api_key = session.query(ApiKey).filter(ApiKey.id == id).first()\n        db_api_key.is_expired = True\n        session.commit()\n        session.flush()\n\n    @classmethod\n    def update_api_key(cls, session, id: int, name: str):\n        db_api_key = session.query(ApiKey).filter(ApiKey.id == id).first()\n        db_api_key.name = name\n        session.commit()\n        session.flush()\n    \n"
  },
  {
    "path": "superagi/models/base_model.py",
    "content": "import json\n\nfrom sqlalchemy import Column, DateTime, INTEGER\nfrom sqlalchemy.orm import declarative_base\nfrom datetime import datetime\n\nBase = declarative_base()\n\n\nclass DBBaseModel(Base):\n    \"\"\"\n    DBBaseModel is an abstract base class for all SQLAlchemy ORM models ,\n    providing common columns and functionality.\n\n    Attributes:\n        created_at: Datetime column to store the timestamp about when a row is created.\n        updated_at: Datetime column to store the timestamp about when a row is updated.\n\n    Methods:\n        to_dict: Converts the current object to a dictionary.\n        to_json: Converts the current object to a JSON string.\n        from_json: Creates a new object of the class using the provided JSON data.\n        __repr__: Returns a string representation of the current object.\n    \"\"\"\n    __abstract__ = True\n    # id  = Column(INTEGER,primary_key=True,autoincrement=True)\n    created_at = Column(DateTime, default=datetime.utcnow)\n    updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)\n\n    def to_dict(self):\n        \"\"\"\n        Converts the current SQLAlchemy ORM object to a dictionary representation.\n\n        Returns:\n            A dictionary mapping column names to their corresponding values.\n        \"\"\"\n        return {column.name: getattr(self, column.name) for column in self.__table__.columns}\n\n    def to_json(self):\n        \"\"\"\n            Converts the current SQLAlchemy ORM object to a JSON string representation.\n\n            Returns:\n                A JSON string representing the object with column names as keys and their corresponding values.\n        \"\"\"\n        return json.dumps(self.to_dict())\n\n    @classmethod\n    def from_json(cls, json_data):\n        \"\"\"\n            Creates a new SQLAlchemy ORM object of the class using the provided JSON data.\n\n            Args: json_data (str): A JSON string representing the object with column names as keys and their\n            corresponding values.\n\n            Returns:\n                A new SQLAlchemy ORM object of the class.\n        \"\"\"\n        return cls(**json.loads(json_data))\n\n    def __repr__(self):\n        \"\"\"\n            Returns a string representation of the current SQLAlchemy ORM object.\n\n            Returns:\n                A string with the format \"<Class Name> (<dictionary representation of the object>)\".\n        \"\"\"\n        return f\"{self.__class__.__name__} ({self.to_dict()})\"\n"
  },
  {
    "path": "superagi/models/budget.py",
    "content": "from sqlalchemy import Column, Integer, String, Float\nfrom superagi.models.base_model import DBBaseModel\n\n\nclass Budget(DBBaseModel):\n    \"\"\"\n    Model representing a budget.\n\n    Attributes:\n        id (Integer): The primary key of the budget.\n        budget (Float): The budget value.\n        cycle (String): The cycle of the budget.\n    \"\"\"\n\n    __tablename__ = 'budgets'\n\n    id = Column(Integer, primary_key=True)\n    budget = Column(Float)\n    cycle = Column(String)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the Budget object.\n\n        Returns:\n            str: String representation of the Budget object.\n        \"\"\"\n\n        return (f\"Budget(id={self.id}, budget={self.budget}, \"\n                f\"cycle='{self.cycle}')\")\n"
  },
  {
    "path": "superagi/models/call_logs.py",
    "content": "from sqlalchemy import Column, Integer, String\nfrom superagi.models.base_model import DBBaseModel\n\nclass CallLogs(DBBaseModel):\n    \"\"\"\n    Represents a Model record in the database\n\n    Attributes:\n        id (Integer): The unique identifier of the event.\n        agent_execution_name (String): The name of the agent_execution.\n        agent_id (Integer): The unique id of the model_provider from the models_config table.\n        tokens_consumed (Integer): The number of tokens for a call.\n        tool_used (String): The tool_used for the call.\n        model (String): The model used for the Agent call.\n        org_id (Integer): The ID of the organisation.\n    \"\"\"\n\n    __tablename__ = 'call_logs'\n\n    id = Column(Integer, primary_key=True)\n    agent_execution_name = Column(String, nullable=False)\n    agent_id = Column(Integer, nullable=False)\n    tokens_consumed = Column(Integer, nullable=False)\n    tool_used = Column(String, nullable=False)\n    model = Column(String, nullable=True)\n    org_id = Column(Integer, nullable=False)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the CallLogs instance.\n        \"\"\"\n        return f\"CallLogs(id={self.id}, agent_execution_name={self.agent_execution_name}, \" \\\n               f\"agent_id={self.agent_id}, tokens_consumed={self.tokens_consumed}, \" \\\n               f\"tool_used={self.tool_used}, \" \\\n               f\"model={self.model}, \" \\\n               f\"org_id={self.org_id})\""
  },
  {
    "path": "superagi/models/configuration.py",
    "content": "from fastapi import HTTPException\nfrom sqlalchemy import Column, Integer, String,Text\n\nfrom superagi.helper.encyption_helper import decrypt_data\nfrom superagi.models.base_model import DBBaseModel\nfrom superagi.models.organisation import Organisation\nfrom superagi.models.project import Project\nfrom superagi.models.models_config import ModelsConfig\nfrom superagi.models.models import Models\nfrom superagi.helper.encyption_helper import decrypt_data\n\nclass Configuration(DBBaseModel):\n    \"\"\"\n    General org level configurations are stored here\n\n    Attributes:\n        id (Integer): The primary key of the configuration.\n        organisation_id (Integer): The ID of the organization associated with the configuration.\n        key (String): The configuration key.\n        value (Text): The configuration value.\n    \"\"\"\n\n    __tablename__ = 'configurations'\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    organisation_id = Column(Integer)\n    key = Column(String)\n    value = Column(Text)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the Configuration object.\n\n        Returns:\n            str: String representation of the Configuration object.\n        \"\"\"\n\n        return f\"Config(id={self.id}, organisation_id={self.organisation_id}, key={self.key}, value={self.value})\"\n\n\n    @classmethod\n    def fetch_configuration(cls, session, organisation_id: int, key: str, default_value=None) -> str:\n        \"\"\"\n        Fetches the configuration of an agent.\n\n        Args:\n            session: The database session object.\n            organisation_id (int): The ID of the organisation.\n            key (str): The key of the configuration.\n            default_value (str): The default value of the configuration.\n\n        Returns:\n            dict: Parsed configuration.\n\n        \"\"\"\n\n        configuration = session.query(Configuration).filter_by(organisation_id=organisation_id, key=key).first()\n        if key == \"model_api_key\":\n            return decrypt_data(configuration.value) if configuration else default_value\n        else:\n            return configuration.value if configuration else default_value\n\n    @classmethod\n    def fetch_configurations(cls, session, organisation_id: int, key: str, model: str, default_value=None) -> str:\n        \"\"\"\n        Fetches the configuration of an agent.\n\n        Args:\n            session: The database session object.\n            organisation_id (int): The ID of the organisation.\n            key (str): The key of the configuration.\n            default_value (str): The default value of the configuration.\n\n        Returns:\n            dict: Parsed configuration.\n\n        \"\"\"\n        model_provider = session.query(Models).filter(Models.org_id == organisation_id, Models.model_name == model).first()\n        if not model_provider:\n            raise HTTPException(status_code=404, detail=\"Model provider not found\")\n\n        configuration = session.query(ModelsConfig.provider, ModelsConfig.api_key).filter(ModelsConfig.org_id == organisation_id, ModelsConfig.id == model_provider.model_provider_id).first()\n        if key == \"model_api_key\":\n            return decrypt_data(configuration.api_key) if configuration else default_value\n        else:\n            return configuration.provider if configuration else default_value\n\n    @classmethod\n    def fetch_value_by_agent_id(cls, session, agent_id: int, key: str):\n        \"\"\"\n        Fetches the configuration of an agent.\n\n        Args:\n            session: The database session object.\n            agent_id (int): The ID of the agent.\n            key (str): The key of the configuration.\n\n        Returns:\n            dict: Parsed configuration.\n\n        \"\"\"\n        from superagi.models.agent import Agent\n        agent = session.query(Agent).filter(Agent.id == agent_id).first()\n        if not agent:\n            raise HTTPException(status_code=404, detail=\"Agent not found\")\n        project = session.query(Project).filter(Project.id == agent.project_id).first()\n        if not project:\n            raise HTTPException(status_code=404, detail=\"Project not found\")\n        organisation = session.query(Organisation).filter(Organisation.id == project.organisation_id).first()\n        if not organisation:\n            raise HTTPException(status_code=404, detail=\"Organisation not found\")\n        config = session.query(Configuration).filter(Configuration.organisation_id == organisation.id,\n                                                     Configuration.key == key).first()\n        if not config:\n            return None\n        return config.value if config else None\n"
  },
  {
    "path": "superagi/models/db.py",
    "content": "from sqlalchemy import create_engine\nfrom superagi.config.config import get_config\nfrom urllib.parse import urlparse\nfrom superagi.lib.logger import logger\n\nengine = None\n\n\ndef connect_db():\n    \"\"\"\n    Connects to the PostgreSQL database using SQLAlchemy.\n\n    Returns:\n        engine: The SQLAlchemy engine object representing the database connection.\n    \"\"\"\n\n    global engine\n    if engine is not None:\n        return engine\n\n    # Create the connection URL\n    db_host = get_config('DB_HOST', 'super__postgres')\n    db_username = get_config('DB_USERNAME')\n    db_password = get_config('DB_PASSWORD')\n    db_name = get_config('DB_NAME')\n    db_url = get_config('DB_URL', None)\n\n    if db_url is None:\n        if db_username is None:\n            db_url = f'postgresql://{db_host}/{db_name}'\n        else:\n            db_url = f'postgresql://{db_username}:{db_password}@{db_host}/{db_name}'\n    else:\n        db_url = urlparse(db_url)\n        db_url = db_url.scheme + \"://\" + db_url.netloc + db_url.path\n    # Create the SQLAlchemy engine\n    engine = create_engine(db_url,\n                           pool_size=20,  # Maximum number of database connections in the pool\n                           max_overflow=50,  # Maximum number of connections that can be created beyond the pool_size\n                           pool_timeout=30,  # Timeout value in seconds for acquiring a connection from the pool\n                           pool_recycle=1800,  # Recycle connections after this number of seconds (optional)\n                           pool_pre_ping=False,  # Enable connection health checks (optional)\n                           )\n\n    # Test the connection\n    try:\n        connection = engine.connect()\n        logger.info(\"Connected to the database! @ \" + db_url)\n        connection.close()\n    except Exception as e:\n        logger.error(f\"Unable to connect to the database:{e}\")\n    return engine\n"
  },
  {
    "path": "superagi/models/events.py",
    "content": "from sqlalchemy import Column, Integer, String, DateTime, Sequence\nfrom sqlalchemy.dialects.postgresql import JSONB\nfrom superagi.models.base_model import DBBaseModel\nfrom sqlalchemy.ext.declarative import declarative_base\n\nBase = declarative_base()\n\nclass Event(DBBaseModel):\n    \"\"\"\n    Represents an Event record in the database.\n\n    Attributes:\n        id (Integer): The unique identifier of the event.\n        event_name (String): The name of the event.\n        event_value (Integer): The value of the event.\n        event_property (JSONB): The JSON object representing additional attributes of the event.\n        agent_id (Integer): The ID of the agent.\n        org_id (Integer): The ID of the organisation.\n    \"\"\"\n    __tablename__ = 'events'\n\n    id = Column(Integer, primary_key=True)\n    event_name = Column(String, nullable=False)\n    event_value = Column(Integer, nullable=False)\n    event_property = Column(JSONB, nullable=True)\n    agent_id = Column(Integer, nullable=True)\n    org_id = Column(Integer, nullable=True)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the Event instance.\n        \"\"\"\n        return f\"Event(id={self.id}, event_name={self.event_name}, \" \\\n               f\"event_value={self.event_value}, \" \\\n               f\"agent_id={self.agent_id}, \" \\\n               f\"org_id={self.org_id})\""
  },
  {
    "path": "superagi/models/knowledge_configs.py",
    "content": "from sqlalchemy import Column, Integer, Text, String\nimport requests\nfrom superagi.models.base_model import DBBaseModel\nmarketplace_url = \"https://app.superagi.com/api\"\n# marketplace_url = \"http://localhost:8001\"\n\n\nclass KnowledgeConfigs(DBBaseModel):\n    \"\"\"\n    Knowledge related configurations such as model, data_type, tokenizer, chunk_size, chunk_overlap, text_splitter, etc. are stored here.\n    Attributes:\n        id (int): The unique identifier of the knowledge configuration.\n        knowledge_id (int): The identifier of the associated knowledge.\n        key (str): The key of the configuration setting.\n        value (str): The value of the configuration setting.\n    \"\"\"\n\n    __tablename__ = 'knowledge_configs'\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    knowledge_id = Column(Integer)\n    key = Column(String)\n    value = Column(Text)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the Knowledge Configuration object.\n        Returns:\n            str: String representation of the Knowledge Configuration.\n        \"\"\"\n        return f\"KnowledgeConfiguration(id={self.id}, knowledge_id={self.knowledge_id}, key={self.key}, value={self.value})\"\n    \n    @classmethod\n    def fetch_knowledge_config_details_marketplace(cls, knowledge_id: int):\n        headers = {'Content-Type': 'application/json'}\n        response = requests.get(\n            marketplace_url + f\"/knowledge_configs/marketplace/details/{str(knowledge_id)}\",\n            headers=headers, timeout=10)\n        if response.status_code == 200:\n            knowledge_config_data = response.json()\n            configs = {}\n            for knowledge_config in knowledge_config_data:\n                configs[knowledge_config[\"key\"]] = knowledge_config[\"value\"]\n            return configs\n        else:\n            return []\n        \n    @classmethod\n    def add_update_knowledge_config(cls, session, knowledge_id, knowledge_configs):\n        for key, value in knowledge_configs.items():\n            config = KnowledgeConfigs(knowledge_id=knowledge_id, key=key, value=value)\n            session.add(config)\n            session.commit()\n    \n    @classmethod\n    def get_knowledge_config_from_knowledge_id(cls, session, knowledge_id):\n        knowledge_configs = session.query(KnowledgeConfigs).filter(KnowledgeConfigs.knowledge_id == knowledge_id).all()\n        configs = {}\n        for knowledge_config in knowledge_configs:\n            configs[knowledge_config.key] = knowledge_config.value\n        return configs\n    \n    @classmethod\n    def delete_knowledge_config(cls, session, knowledge_id):\n        session.query(KnowledgeConfigs).filter(KnowledgeConfigs.knowledge_id == knowledge_id).delete()\n        session.commit()\n    \n    @classmethod\n    def get_knowledge_config_from_knowledge_id(cls, session, knowledge_id):\n        knowledge_configs = session.query(KnowledgeConfigs).filter(KnowledgeConfigs.knowledge_id == knowledge_id).all()\n        configs = {}\n        for knowledge_config in knowledge_configs:\n            configs[knowledge_config.key] = knowledge_config.value\n        return configs\n"
  },
  {
    "path": "superagi/models/knowledges.py",
    "content": "from __future__ import annotations\n\nfrom sqlalchemy import Column, Integer, String\nimport requests\n\n# from superagi.models import AgentConfiguration\nfrom superagi.models.base_model import DBBaseModel\n\nmarketplace_url = \"https://app.superagi.com/api\"\n# marketplace_url = \"http://localhost:8001\"\n\nclass Knowledges(DBBaseModel):\n    \"\"\"\n    Represents an knowledge entity.\n\n    Attributes:\n        id (int): The unique identifier of the knowledge.\n        name (str): The name of the knowledge.\n        description (str): The description of the knowledge.\n        vector_db_index_id (int): The index associated with the knowledge.\n        is_deleted (int): The flag for deletion/uninstallation of a knowledge.\n        organisation_id (int): The identifier of the associated organisation.\n    \"\"\"\n\n    __tablename__ = 'knowledges'\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    name = Column(String)\n    description = Column(String)\n    vector_db_index_id = Column(Integer)\n    organisation_id = Column(Integer)\n    contributed_by = Column(String)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the Knowledge object.\n\n        Returns:\n            str: String representation of the Knowledge.\n\n        \"\"\"\n        return f\"Knowledge(id={self.id}, name='{self.name}', description='{self.description}', \" \\\n               f\"vector_db_index_id={self.vector_db_index_id}), organisation_id={self.organisation_id}, contributed_by={self.contributed_by})\"\n\n    @classmethod\n    def fetch_marketplace_list(cls, page):\n        headers = {'Content-Type': 'application/json'}\n        response = requests.get(\n            marketplace_url + f\"/knowledges/marketplace/list/{str(page)}\",\n            headers=headers, timeout=10)\n        if response.status_code == 200:\n            return response.json()\n        else:\n            return []\n    \n    @classmethod\n    def get_knowledge_install_details(cls, session, marketplace_knowledges, organisation):\n        installed_knowledges = session.query(Knowledges).filter(Knowledges.organisation_id == organisation.id).all()\n        for knowledge in marketplace_knowledges:\n            if knowledge[\"name\"] in [installed_knowledge.name for installed_knowledge in installed_knowledges]:\n                knowledge[\"is_installed\"] = True\n            else:\n                knowledge[\"is_installed\"] = False\n        return marketplace_knowledges\n    \n    @classmethod\n    def get_organisation_knowledges(cls, session, organisation):\n        knowledges = session.query(Knowledges).filter(Knowledges.organisation_id == organisation.id).all()\n        knowledge_data = []\n        for knowledge in knowledges:\n            data = {\n                \"id\": knowledge.id,\n                \"name\": knowledge.name,\n                \"contributed_by\": knowledge.contributed_by\n            }\n            knowledge_data.append(data)\n        return knowledge_data\n    \n    @classmethod\n    def fetch_knowledge_details_marketplace(cls, knowledge_name):\n        headers = {'Content-Type': 'application/json'}\n        response = requests.get(\n            marketplace_url + f\"/knowledges/marketplace/details/{knowledge_name}\",\n            headers=headers, timeout=10)\n        if response.status_code == 200:\n            return response.json()\n        else:\n            return []\n    \n    @classmethod\n    def get_knowledge_from_id(cls, session, knowledge_id):\n        knowledge = session.query(Knowledges).filter(Knowledges.id == knowledge_id).first()\n        return knowledge\n    \n    @classmethod\n    def add_update_knowledge(cls, session, knowledge_data):\n        knowledge = session.query(Knowledges).filter(Knowledges.id == knowledge_data[\"id\"], Knowledges.organisation_id == knowledge_data[\"organisation_id\"]).first()\n        if knowledge:\n            knowledge.name = knowledge_data[\"name\"]\n            knowledge.description = knowledge_data[\"description\"]\n            knowledge.vector_db_index_id = knowledge_data[\"index_id\"]\n        else:\n            knowledge = Knowledges(name=knowledge_data[\"name\"], description=knowledge_data[\"description\"], vector_db_index_id=knowledge_data[\"index_id\"], organisation_id=knowledge_data[\"organisation_id\"], contributed_by=knowledge_data[\"contributed_by\"])\n            session.add(knowledge)\n        session.commit()\n        return knowledge\n    \n    @classmethod\n    def delete_knowledge(cls, session, knowledge_id):\n        session.query(Knowledges).filter(Knowledges.id == knowledge_id).delete()\n        session.commit()\n\n    @classmethod\n    def delete_knowledge_from_vector_index(cls, session, vector_db_index_id):\n        session.query(Knowledges).filter(Knowledges.vector_db_index_id == vector_db_index_id).delete()\n        session.commit()"
  },
  {
    "path": "superagi/models/marketplace_stats.py",
    "content": "from __future__ import annotations\n\nfrom sqlalchemy import Column, Integer, String\nimport requests\n# from superagi.models import AgentConfiguration\nfrom superagi.models.base_model import DBBaseModel\n\nmarketplace_url = \"https://app.superagi.com/api\"\n# marketplace_url = \"http://localhost:8001\"\n\nclass MarketPlaceStats(DBBaseModel):\n    \"\"\"\n    Represents an knowledge entity.\n    Attributes:\n        id (int): The unique identifier of the marketplace stats.\n        reference_id (int): The unique identifier of the reference.\n        reference_name (str): The name of the reference used.\n        key (str): The key for the statistical value.\n        value (int): The value for the specified key.\n    \"\"\"\n\n    __tablename__ = 'marketplace_stats'\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    reference_id = Column(Integer)\n    reference_name = Column(String)\n    key = Column(String)\n    value = Column(Integer)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the MarketplaceStats object.\n        \"\"\"\n        return f\"Knowledge(id={self.id}, reference_id='{self.reference_id}', reference_name='{self.reference_name}', \" \\\n               f\"key='{self.key}', value='{self.value}'\"\n\n    @classmethod\n    def get_knowledge_installation_number(cls, knowledge_id: int):\n        headers = {'Content-Type': 'application/json'}\n        response = requests.get(\n            marketplace_url + f\"/marketplace/knowledge/downloads/{str(knowledge_id)}\",\n            headers=headers, timeout=10)\n        if response.status_code == 200:\n            return response.json()\n        else:\n            return []\n    \n    @classmethod\n    def update_knowledge_install_number(cls, session, knowledge_id, install_number):\n        knowledge_install_number = session.query(MarketPlaceStats).filter(MarketPlaceStats.reference_id == knowledge_id, MarketPlaceStats.reference_name == \"KNOWLEDGE\", MarketPlaceStats.key == \"download_count\").first()\n        if knowledge_install_number is None:\n            knowledge_install_number = MarketPlaceStats(reference_id=knowledge_id, reference_name=\"KNOWLEDGE\", key=\"download_count\", value=str(install_number))\n            session.add(knowledge_install_number)\n        else:\n            knowledge_install_number.value = str(install_number)\n        session.commit()"
  },
  {
    "path": "superagi/models/models.py",
    "content": "import yaml\nfrom sqlalchemy import Column, Integer, String, and_\nfrom sqlalchemy.sql import func\nfrom typing import List, Dict, Union\nfrom superagi.models.base_model import DBBaseModel\nfrom superagi.controllers.types.models_types import ModelsTypes\nfrom superagi.helper.encyption_helper import decrypt_data\nimport requests, logging\nfrom superagi.lib.logger import logger\n\nmarketplace_url = \"https://app.superagi.com/api\"\n# marketplace_url = \"http://localhost:8001\"\n\n\nclass Models(DBBaseModel):\n    \"\"\"\n    Represents a Model record in the database\n\n    Attributes:\n        id (Integer): The unique identifier of the event.\n        model_name (String): The name of the model.\n        description (String): The description for the model.\n        end_point (String): The end_point for the model.3001\n        model_provider_id (Integer): The unique id of the model_provider from the models_config table.\n        token_limit (Integer): The maximum number of tokens for a model.\n        type (Strng): The place it is added from.\n        version (String): The version of the replicate model.\n        org_id (Integer): The ID of the organisation.\n        model_features (String): The Features of the Model.\n    \"\"\"\n\n    __tablename__ = 'models'\n\n    id = Column(Integer, primary_key=True)\n    model_name = Column(String, nullable=False)\n    description = Column(String, nullable=True)\n    end_point = Column(String, nullable=False)\n    model_provider_id = Column(Integer, nullable=False)\n    token_limit = Column(Integer, nullable=False)\n    type = Column(String, nullable=False)\n    version = Column(String, nullable=False)\n    org_id = Column(Integer, nullable=False)\n    model_features = Column(String, nullable=False)\n    context_length = Column(Integer, nullable=True)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the Models instance.\n        \"\"\"\n        return f\"Models(id={self.id}, model_name={self.model_name}, \" \\\n               f\"end_point={self.end_point}, model_provider_id={self.model_provider_id}, \" \\\n               f\"token_limit={self.token_limit}, \" \\\n               f\"type={self.type}, \" \\\n               f\"version={self.version}, \" \\\n               f\"org_id={self.org_id}, \" \\\n               f\"model_features={self.model_features})\"\n\n    @classmethod\n    def fetch_marketplace_list(cls, page):\n        headers = {'Content-Type': 'application/json'}\n        response = requests.get(\n            marketplace_url + f\"/models_controller/marketplace/list/{str(page)}\",\n            headers=headers, timeout=10)\n        if response.status_code == 200:\n            return response.json()\n        else:\n            return []\n\n    @classmethod\n    def get_model_install_details(cls, session, marketplace_models, organisation_id, type=ModelsTypes.CUSTOM.value):\n        from superagi.models.models_config import ModelsConfig\n        installed_models = session.query(Models).filter(Models.org_id == organisation_id).all()\n        model_counts_dict = dict(\n            session.query(Models.model_name, func.count(Models.org_id)).group_by(Models.model_name).all()\n        )\n        installed_models_dict = {model.model_name: True for model in installed_models}\n\n        for model in marketplace_models:\n            try:\n                if type == ModelsTypes.MARKETPLACE.value:\n                    model[\"is_installed\"] = False\n                else:\n                    model[\"is_installed\"] = installed_models_dict.get(model[\"model_name\"], False)\n                model[\"installs\"] = model_counts_dict.get(model[\"model_name\"], 0)\n            except TypeError as e:\n                logging.error(\"Error Occurred: %s\", e)\n\n        return marketplace_models\n\n    @classmethod\n    def fetch_model_tokens(cls, session, organisation_id) -> Dict[str, int]:\n        try:\n            models = session.query(\n                Models.model_name, Models.token_limit\n            ).filter(\n                Models.org_id == organisation_id\n            ).all()\n\n            if models:\n                return dict(models)\n            else:\n                return {\"error\": \"No models found for the given organisation ID.\"}\n\n        except Exception as e:\n            logging.error(f\"Unexpected Error Occured: {e}\")\n            return {\"error\": \"Unexpected Error Occured\"}\n\n    @classmethod\n    def store_model_details(cls, session, organisation_id, model_name, description, end_point, model_provider_id, token_limit, type, version, context_length):\n        from superagi.models.models_config import ModelsConfig\n        if not model_name:\n            return {\"error\": \"Model Name is empty or undefined\"}\n        if not description:\n            return {\"error\": \"Description is empty or undefined\"}\n        if not model_provider_id:\n            return {\"error\": \"Model Provider Id is null or undefined or 0\"}\n        if not token_limit:\n            return {\"error\": \"Token Limit is null or undefined or 0\"}\n\n        # Check if model_name already exists in the database\n        existing_model = session.query(Models).filter(Models.model_name == model_name, Models.org_id == organisation_id).first()\n        if existing_model:\n            return {\"error\": \"Model Name already exists\"}\n\n        # Get the provider of the model\n        if type == 'Marketplace':\n            model = ModelsConfig.fetch_model_by_id_marketplace(session, model_provider_id)\n        else:\n            model = ModelsConfig.fetch_model_by_id(session, organisation_id, model_provider_id)\n\n        if \"error\" in model:\n            return model  # Return error message if model not found\n\n        # Check the 'provider' from ModelsConfig table\n        if not end_point and model[\"provider\"] not in ['OpenAI', 'Google Palm', 'Replicate','Local LLM']:\n            return {\"error\": \"End Point is empty or undefined\"}\n\n        if context_length is None: \n            context_length = 0\n\n        try:\n            model = Models(\n                model_name=model_name,\n                description=description,\n                end_point=end_point,\n                token_limit=token_limit,\n                model_provider_id=model_provider_id,\n                type=type,\n                version=version,\n                org_id=organisation_id,\n                model_features='',\n                context_length=context_length\n            )\n            session.add(model)\n            session.commit()\n            session.flush()\n\n        except Exception as e:\n            logging.error(f\"Unexpected Error Occured: {e}\")\n            return {\"error\": \"Unexpected Error Occured\"}\n\n        return {\"success\": \"Model Details stored successfully\", \"model_id\": model.id}\n\n    @classmethod\n    def api_key_from_configurations(cls, session, organisation_id):\n        try:\n            from superagi.models.models_config import ModelsConfig\n            from superagi.models.configuration import Configuration\n\n            model_provider = session.query(ModelsConfig).filter(ModelsConfig.provider == \"OpenAI\",\n                                                                ModelsConfig.org_id == organisation_id).first()\n            if model_provider is None:\n                configurations = session.query(Configuration).filter(Configuration.key == 'model_api_key',\n                                                                     Configuration.organisation_id == organisation_id).first()\n\n                if configurations is None:\n                    return {\"error\": \"API Key is Missing\"}\n                else:\n                    model_api_key = decrypt_data(configurations.value)\n                    model_details = ModelsConfig.store_api_key(session, organisation_id, \"OpenAI\", model_api_key)\n        except Exception as e:\n            logging.error(f\"Exception has been raised while checking API Key:: {e}\")\n\n\n    @classmethod\n    def fetch_models(cls, session, organisation_id) -> Union[Dict[str, str], List[Dict[str, Union[str, int]]]]:\n        try:\n            from superagi.models.models_config import ModelsConfig\n            cls.api_key_from_configurations(session, organisation_id)\n\n            models = session.query(Models.id, Models.model_name, Models.description, ModelsConfig.provider).join(\n                ModelsConfig, Models.model_provider_id == ModelsConfig.id).filter(\n                Models.org_id == organisation_id).all()\n\n            result = []\n            for model in models:\n                result.append({\n                    \"id\": model[0],\n                    \"name\": model[1],\n                    \"description\": model[2],\n                    \"model_provider\": model[3]\n                })\n\n        except Exception as e:\n            logging.error(f\"Unexpected Error Occurred: {e}\")\n            return {\"error\": \"Unexpected Error Occurred\"}\n\n        return result\n\n    @classmethod\n    def fetch_model_details(cls, session, organisation_id, model_id: int) -> Dict[str, Union[str, int]]:\n        try:\n            from superagi.models.models_config import ModelsConfig\n            model = session.query(\n                Models.id, Models.model_name, Models.description, Models.end_point, Models.token_limit, Models.type,\n                ModelsConfig.provider,\n            ).join(\n                ModelsConfig, Models.model_provider_id == ModelsConfig.id\n            ).filter(\n                and_(Models.org_id == organisation_id, Models.id == model_id)\n            ).first()\n\n            if model:\n                return {\n                    \"id\": model[0],\n                    \"name\": model[1],\n                    \"description\": model[2],\n                    \"end_point\": model[3],\n                    \"token_limit\": model[4],\n                    \"type\": model[5],\n                    \"model_provider\": model[6]\n                }\n            else:\n                return {\"error\": \"Model with the given ID doesn't exist.\"}\n\n        except Exception as e:\n            logging.error(f\"Unexpected Error Occured: {e}\")\n            return {\"error\": \"Unexpected Error Occured\"}"
  },
  {
    "path": "superagi/models/models_config.py",
    "content": "from sqlalchemy import Column, Integer, String, and_, distinct\nfrom superagi.lib.logger import logger\nfrom superagi.models.base_model import DBBaseModel\nfrom superagi.models.organisation import Organisation\nfrom superagi.models.project import Project\nfrom superagi.models.models import Models\nfrom superagi.llms.openai import OpenAi\nfrom superagi.helper.encyption_helper import encrypt_data, decrypt_data\nfrom fastapi import HTTPException\nimport logging\n\nclass ModelsConfig(DBBaseModel):\n    \"\"\"\n    Represents a Model Config record in the database.\n\n    Attributes:\n        id (Integer): The unique identifier of the event.\n        provider (String): The name of the model provider.\n        api_key (String): The api_key for individual model providers for every Organisation\n        org_id (Integer): The ID of the organisation.\n    \"\"\"\n\n    __tablename__ = 'models_config'\n\n    id = Column(Integer, primary_key=True)\n    provider = Column(String, nullable=False)\n    api_key = Column(String, nullable=False)\n    org_id = Column(Integer, nullable=False)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the ModelsConfig instance.\n        \"\"\"\n        return f\"ModelsConfig(id={self.id}, provider={self.provider}, \" \\\n               f\"org_id={self.org_id})\"\n\n    @classmethod\n    def fetch_value_by_agent_id(cls, session, agent_id: int, model: str):\n        \"\"\"\n        Fetches the configuration of an agent.\n\n        Args:\n            session: The database session object.\n            agent_id (int): The ID of the agent.\n            model (str): The model of the configuration.\n\n        Returns:\n            dict: Parsed configuration.\n\n        \"\"\"\n        from superagi.models.agent import Agent\n        agent = session.query(Agent).filter(Agent.id == agent_id).first()\n        if not agent:\n            raise HTTPException(status_code=404, detail=\"Agent not found\")\n\n        project = session.query(Project).filter(Project.id == agent.project_id).first()\n        if not project:\n            raise HTTPException(status_code=404, detail=\"Project not found\")\n\n        organisation = session.query(Organisation).filter(Organisation.id == project.organisation_id).first()\n        if not organisation:\n            raise HTTPException(status_code=404, detail=\"Organisation not found\")\n\n        model_provider = session.query(Models).filter(Models.org_id == organisation.id, Models.model_name == model).first()\n        if not model_provider:\n            raise HTTPException(status_code=404, detail=\"Model provider not found\")\n\n        config = session.query(ModelsConfig.provider, ModelsConfig.api_key).filter(ModelsConfig.org_id == organisation.id, ModelsConfig.id == model_provider.model_provider_id).first()\n\n        if not config:\n            return None\n\n        if config.provider == 'Local LLM':\n            return {\"provider\": config.provider, \"api_key\": config.api_key} if config else None\n\n        return {\"provider\": config.provider, \"api_key\": decrypt_data(config.api_key)} if config else None\n\n    @classmethod\n    def store_api_key(cls, session, organisation_id, model_provider, model_api_key):\n        existing_entry = session.query(ModelsConfig).filter(and_(ModelsConfig.org_id == organisation_id,\n                                                                 ModelsConfig.provider == model_provider)).first()\n        if existing_entry:\n            existing_entry.api_key = encrypt_data(model_api_key)\n            session.commit()\n            session.flush()\n            if model_provider == 'OpenAI':\n                cls.storeGptModels(session, organisation_id, existing_entry.id, model_api_key)\n            result = {'message': 'The API key was successfully updated'}\n        else:\n            new_entry = ModelsConfig(org_id=organisation_id, provider=model_provider,\n                                     api_key=encrypt_data(model_api_key))\n            session.add(new_entry)\n            session.commit()\n            session.flush()\n            if model_provider == 'OpenAI':\n                cls.storeGptModels(session, organisation_id, new_entry.id, model_api_key)\n            result = {'message': 'The API key was successfully stored', 'model_provider_id': new_entry.id}\n\n        return result\n\n    @classmethod\n    def storeGptModels(cls, session, organisation_id, model_provider_id, model_api_key):\n        default_models = {\"gpt-3.5-turbo\": 4032, \"gpt-4\": 8092, \"gpt-3.5-turbo-16k\": 16184}\n        models = OpenAi(api_key=model_api_key).get_models()\n        installed_models = [model[0] for model in session.query(Models.model_name).filter(Models.org_id == organisation_id).all()]\n        for model in models:\n            if model not in installed_models and model in default_models:\n                result = Models.store_model_details(session, organisation_id, model, model, '',\n                                                 model_provider_id, default_models[model], 'Custom', '', 0)\n\n    @classmethod\n    def fetch_api_keys(cls, session, organisation_id):\n        api_key_info = session.query(ModelsConfig.provider, ModelsConfig.api_key).filter(\n            ModelsConfig.org_id == organisation_id).all()\n\n        if not api_key_info:\n            logging.error(\"No API key found for the provided model provider\")\n            return []\n\n        api_keys = [{\"provider\": provider, \"api_key\": decrypt_data(api_key)} for provider, api_key in api_key_info if api_key != 'EMPTY']\n\n        return api_keys\n\n    @classmethod\n    def fetch_api_key(cls, session, organisation_id, model_provider):\n        api_key_data = session.query(ModelsConfig.id, ModelsConfig.provider, ModelsConfig.api_key).filter(\n            and_(ModelsConfig.org_id == organisation_id, ModelsConfig.provider == model_provider)).first()\n\n        logger.info(api_key_data)\n        if api_key_data is None:\n            return []\n        elif api_key_data.provider == 'Local LLM':\n            api_key = [{'id': api_key_data.id, 'provider': api_key_data.provider,\n                        'api_key': api_key_data.api_key}]\n            return api_key\n        else:\n            api_key = [{'id': api_key_data.id, 'provider': api_key_data.provider,\n                        'api_key': decrypt_data(api_key_data.api_key)}]\n            return api_key\n\n    @classmethod\n    def fetch_model_by_id(cls, session, organisation_id, model_provider_id):\n        model = session.query(ModelsConfig.provider).filter(ModelsConfig.id == model_provider_id,\n                                                            ModelsConfig.org_id == organisation_id).first()\n        if model is None:\n            return {\"error\": \"Model not found\"}\n        else:\n            return {\"provider\": model.provider}\n\n    @classmethod\n    def fetch_model_by_id_marketplace(cls, session, model_provider_id):\n        model = session.query(ModelsConfig.provider).filter(ModelsConfig.id == model_provider_id).first()\n        if model is None:\n            return {\"error\": \"Model not found\"}\n        else:\n            return {\"provider\": model.provider}\n    \n    @classmethod\n    def add_llm_config(cls, session, organisation_id):\n        existing_models_config = session.query(ModelsConfig).filter(ModelsConfig.org_id == organisation_id, ModelsConfig.provider == 'Local LLM').first()\n        if existing_models_config is None:\n            models_config = ModelsConfig(org_id=organisation_id, provider='Local LLM', api_key=\"EMPTY\")\n            session.add(models_config)\n            session.commit()"
  },
  {
    "path": "superagi/models/oauth_tokens.py",
    "content": "from sqlalchemy import Column, Integer, String, Text\nfrom sqlalchemy.orm import Session\n\nfrom superagi.models.base_model import DBBaseModel\nimport json\nimport yaml\n\n\n\nclass OauthTokens(DBBaseModel):\n    \"\"\"\n    Model representing a OauthTokens.\n\n    Attributes:\n        id (Integer): The primary key of the oauth token.\n        user_id (Integer): The ID of the user associated with the Tokens.\n        toolkit_id (Integer): The ID of the toolkit associated with the Tokens.\n        key (String): The Token Key.\n        value (Text): The Token value.\n    \"\"\"\n\n    __tablename__ = 'oauth_tokens'\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    user_id = Column(Integer)\n    organisation_id = Column(Integer)\n    toolkit_id = Column(Integer)\n    key = Column(String)\n    value = Column(Text)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the OauthTokens object.\n\n        Returns:\n            str: String representation of the OauthTokens object.\n        \"\"\"\n\n        return f\"Tokens(id={self.id}, user_id={self.user_id}, organisation_id={self.organisation_id} toolkit_id={self.toolkit_id}, key={self.key}, value={self.value})\"\n    \n    @classmethod\n    def add_or_update(self, session: Session, toolkit_id: int, user_id: int, organisation_id: int, key: str, value: Text = None):\n        oauth_tokens = session.query(OauthTokens).filter_by(toolkit_id=toolkit_id, user_id=user_id).first()\n        if oauth_tokens:\n            # Update existing oauth tokens\n            if value is not None:\n                oauth_tokens.value = value\n        else:\n            # Create new oauth tokens\n            oauth_tokens = OauthTokens(toolkit_id=toolkit_id, user_id=user_id, organisation_id=organisation_id, key=key, value=value)\n            session.add(oauth_tokens)\n\n        session.commit()"
  },
  {
    "path": "superagi/models/organisation.py",
    "content": "from sqlalchemy import Column, Integer, String\n\nfrom superagi.helper.tool_helper import register_toolkits\nfrom superagi.models.base_model import DBBaseModel\n\n\nclass Organisation(DBBaseModel):\n    \"\"\"\n    Model representing an organization.\n\n    Attributes:\n        id (Integer): The primary key of the organization.\n        name (String): The name of the organization.\n        description (String): The description of the organization.\n    \"\"\"\n\n    __tablename__ = 'organisations'\n\n    id = Column(Integer, primary_key=True)\n    name = Column(String)\n    description = Column(String)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the Organisation object.\n\n        Returns:\n            str: String representation of the Organisation object.\n        \"\"\"\n\n        return f\"Organisation(id={self.id}, name='{self.name}')\"\n\n    @classmethod\n    def find_or_create_organisation(cls, session, user):\n        \"\"\"\n        Finds or creates an organization for the given user.\n\n        Args:\n            session: The database session.\n            user: The user object.\n\n        Returns:\n            Organisation: The found or created organization.\n        \"\"\"\n\n        if user.organisation_id is not None:\n            organisation = session.query(Organisation).filter(Organisation.id == user.organisation_id).first()\n            return organisation\n\n        existing_organisation = session.query(Organisation).filter(\n            Organisation.name == \"Default Organization - \" + str(user.id)).first()\n\n        if existing_organisation is not None:\n            user.organisation_id = existing_organisation.id\n            session.commit()\n            return existing_organisation\n        new_organisation = Organisation(\n            name=\"Default Organization - \" + str(user.id),\n            description=\"New default organiztaion\",\n        )\n\n        session.add(new_organisation)\n        session.commit()\n        session.flush()\n        user.organisation_id = new_organisation.id\n        session.commit()\n        register_toolkits(session=session, organisation=new_organisation)\n        return new_organisation\n"
  },
  {
    "path": "superagi/models/project.py",
    "content": "from sqlalchemy import Column, Integer, String,ForeignKey\nfrom superagi.models.base_model import DBBaseModel\n\n\nclass Project(DBBaseModel):\n    \"\"\"\n    Model representing a project.\n\n    Attributes:\n        id (Integer): The primary key of the project.\n        name (String): The name of the project.\n        organisation_id (Integer): The ID of the organization to which the project belongs.\n        description (String): The description of the project.\n    \"\"\"\n\n    __tablename__ = 'projects'\n\n    id = Column(Integer, primary_key=True)\n    name = Column(String)\n    organisation_id = Column(Integer)\n    description = Column(String)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the Project object.\n\n        Returns:\n            str: String representation of the Project object.\n        \"\"\"\n\n        return f\"Project(id={self.id}, name='{self.name}')\"\n\n    @classmethod\n    def find_or_create_default_project(cls, session, organisation_id):\n        \"\"\"\n            Finds or creates the default project for the given organization.\n\n            Args:\n                session: The database session.\n                organisation_id (int): The ID of the organization.\n\n            Returns:\n                Project: The found or created default project.\n        \"\"\"\n        project = session.query(Project).filter(Project.organisation_id == organisation_id, Project.name == \"Default Project\").first()\n        if project is None:\n            default_project = Project(\n                name=\"Default Project\",\n                organisation_id=organisation_id,\n                description=\"New Default Project\"\n            )\n            session.add(default_project)\n            session.commit()\n            session.flush()\n        else:\n            default_project = project\n        return default_project\n\n    @classmethod\n    def find_by_org_id(cls, session, org_id: int):\n        project = session.query(Project).filter(Project.organisation_id == org_id).first()\n        return project\n    \n    @classmethod\n    def find_by_id(cls, session, project_id: int):\n        project = session.query(Project).filter(Project.id == project_id).first()\n        return project"
  },
  {
    "path": "superagi/models/resource.py",
    "content": "from sqlalchemy import Column, Integer, String, Float, Text\nfrom superagi.models.base_model import DBBaseModel\nfrom sqlalchemy.orm import sessionmaker\n\n\nclass Resource(DBBaseModel):\n    \"\"\"\n    Model representing a resource.\n\n    Attributes:\n        id (Integer): The primary key of the resource.\n        name (String): The name of the resource.\n        storage_type (String): The storage type of the resource (FILESERVER, S3).\n        path (String): The path of the resource (required for S3 storage type).\n        size (Integer): The size of the resource.\n        type (String): The type of the resource (e.g., application/pdf).\n        channel (String): The channel of the resource (INPUT, OUTPUT).\n        agent_id (Integer): The ID of the agent associated with the resource.\n        agent_execution_id (Integer) : The ID of the agent execution corresponding to resource\n    \"\"\"\n\n    __tablename__ = 'resources'\n\n    id = Column(Integer, primary_key=True)\n    name = Column(String)\n    storage_type = Column(String)  # FILESERVER,S3\n    path = Column(String)  # need for S3\n    size = Column(Integer)\n    type = Column(String)  # application/pdf etc\n    channel = Column(String)  # INPUT,OUTPUT\n    agent_id = Column(Integer)\n    agent_execution_id = Column(Integer)\n    summary = Column(Text)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the Resource object.\n\n        Returns:\n            str: String representation of the Resource object.\n        \"\"\"\n\n        return f\"Resource(id={self.id}, name='{self.name}', storage_type='{self.storage_type}', path='{self.path}, size='{self.size}', type='{self.type}', channel={self.channel}, agent_id={self.agent_id}, agent_execution_id={self.agent_execution_id})\"\n\n    @staticmethod\n    def validate_resource_type(storage_type):\n        \"\"\"\n        Validates the resource type.\n\n        Args:\n            storage_type (str): The storage type to validate.\n\n        Raises:\n            InvalidResourceType: If the storage type is invalid.\n        \"\"\"\n\n        valid_types = [\"FILE\", \"S3\"]\n\n        if storage_type not in valid_types:\n            raise InvalidResourceType(\"Invalid resource type\")\n    \n    @classmethod\n    def find_by_run_ids(cls, session, run_ids: list):\n        db_resources_arr=session.query(Resource).filter(Resource.agent_execution_id.in_(run_ids)).all()\n        return db_resources_arr\n    \nclass InvalidResourceType(Exception):\n    \"\"\"Custom exception for invalid resource type\"\"\"\n"
  },
  {
    "path": "superagi/models/tool.py",
    "content": "from sqlalchemy import Column, Integer, String\n\nfrom superagi.models.base_model import DBBaseModel\n\n\n# from pydantic import BaseModel\n\nclass Tool(DBBaseModel):\n    \"\"\"\n    Model representing a tool.\n\n    Attributes:\n        id (Integer): The primary key of the tool.\n        name (String): The name of the tool.\n        folder_name (String): The folder name of the tool.\n        class_name (String): The class name of the tool.\n        file_name (String): The file name of the tool.\n    \"\"\"\n\n    __tablename__ = 'tools'\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    name = Column(String)\n    description = Column(String)\n    folder_name = Column(String)\n    class_name = Column(String)\n    file_name = Column(String)\n    toolkit_id = Column(Integer)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the Tool object.\n\n        Returns:\n            str: String representation of the Tool object.\n        \"\"\"\n\n        return f\"Tool(id={self.id}, name='{self.name}',description='{self.description}' folder_name='{self.folder_name}',\" \\\n               f\" file_name = {self.file_name}, class_name='{self.class_name}, toolkit_id={self.toolkit_id}')\"\n\n    def to_dict(self):\n        \"\"\"\n        Convert the Tool instance to a dictionary.\n\n        Returns:\n            dict: A dictionary representation of the Tool instance.\n        \"\"\"\n        return {\n            \"id\": self.id,\n            \"name\": self.name,\n            \"description\": self.description,\n            \"folder_name\": self.folder_name,\n            \"class_name\": self.class_name,\n            \"file_name\": self.file_name,\n            \"toolkit_id\": self.toolkit_id\n        }\n    @staticmethod\n    def add_or_update(session, tool_name: str, description: str, folder_name: str, class_name: str, file_name: str,\n                      toolkit_id: int):\n        # Check if a record with the given tool name already exists inside a toolkit\n        tool = session.query(Tool).filter_by(name=tool_name,\n                                             toolkit_id=toolkit_id).first()\n        if tool is not None:\n            # Update the attributes of the existing tool record\n            tool.folder_name = folder_name\n            tool.class_name = class_name\n            tool.file_name = file_name\n            tool.description = description\n        else:\n            # Create a new tool record\n            tool = Tool(name=tool_name, description=description, folder_name=folder_name, class_name=class_name,\n                        file_name=file_name,\n                        toolkit_id=toolkit_id)\n            session.add(tool)\n\n        session.commit()\n        session.flush()\n        return tool\n\n    @staticmethod\n    def delete_tool(session, tool_name):\n        tool = session.query(Tool).filter(Tool.name == tool_name).first()\n        if tool:\n            session.delete(tool)\n            session.commit()\n            session.flush()\n\n    @classmethod\n    def convert_tool_names_to_ids(cls, db, tool_names):\n        \"\"\"\n        Converts a list of tool names to their corresponding IDs.\n\n        Args:\n            db: The database session.\n            tool_names (list): List of tool names.\n\n        Returns:\n            list: List of tool IDs.\n        \"\"\"\n\n        tools = db.session.query(Tool).filter(Tool.name.in_(tool_names)).all()\n        return [tool.id for tool in tools]\n\n    @classmethod\n    def convert_tool_ids_to_names(cls, db, tool_ids):\n        \"\"\"\n        Converts a list of tool IDs to their corresponding names.\n\n        Args:\n            db: The database session.\n            tool_ids (list): List of tool IDs.\n\n        Returns:\n            list: List of tool names.\n        \"\"\"\n\n        tools = db.session.query(Tool).filter(Tool.id.in_(tool_ids)).all()\n        return [str(tool.name) for tool in tools]\n\n    @classmethod\n    def get_invalid_tools(cls, tool_ids, session):\n        invalid_tool_ids = []\n        for tool_id in tool_ids:\n            tool = session.query(Tool).get(tool_id)\n            if tool is None:\n                invalid_tool_ids.append(tool_id)\n        return invalid_tool_ids\n\n    @classmethod\n    def get_toolkit_tools(cls, session, toolkit_id : int):\n        return session.query(Tool).filter(Tool.toolkit_id == toolkit_id).all()"
  },
  {
    "path": "superagi/models/tool_config.py",
    "content": "from sqlalchemy import Column, Integer, String, Boolean\nfrom sqlalchemy.orm import Session, sessionmaker\nfrom superagi.types.key_type import ToolConfigKeyType\nfrom superagi.models.base_model import DBBaseModel\nfrom superagi.helper.encyption_helper import encrypt_data\nimport json\nimport yaml\n\n\nclass ToolConfig(DBBaseModel):\n    \"\"\"\n        Model representing a tool configuration.\n\n        Attributes:\n            id (Integer): The primary key of the tool configuration.\n            key (String): The key of the tool configuration.\n            value (String): The value of the tool configuration.\n            toolkit_id (Integer): The identifier of the associated toolkit.\n            key_type (String): the type of key used.\n            is_secret (Boolean): Whether the tool configuration is a secret.\n            is_required (Boolean): Whether the tool configuration is a required field.\n    \"\"\"\n    __tablename__ = 'tool_configs'\n\n\n    id = Column(Integer, primary_key=True)\n    key = Column(String)\n    value = Column(String)\n    toolkit_id = Column(Integer)\n    key_type = Column(String)\n    is_secret = Column(Boolean)\n    is_required = Column(Boolean)\n\n    def __repr__(self):\n        return f\"ToolConfig(id={self.id}, key='{self.key}', value='{self.value}, toolkit_id={self.toolkit_id}')\"\n\n    def to_dict(self):\n        return {\n            'id': self.id,\n            'key': self.key,\n            'value': self.value,\n            'toolkit_id': {self.toolkit_id},\n            'key_type': self.key_type,\n            'is_secret': self.is_secret,\n            'is_required': self.is_required\n        }\n\n    def to_json(self):\n        return json.dumps(self.to_dict())\n\n    @classmethod\n    def from_json(cls, json_data):\n        data = json.loads(json_data)\n        return cls(\n            id=data['id'],\n            key=data['key'],\n            value=data['value'],\n            toolkit_id=data['toolkit_id'],\n            key_type=data['key_type'],\n            is_secret=data['is_secret'],\n            is_required=data['is_required']\n        )\n\n    @staticmethod\n    def add_or_update(session: Session, toolkit_id: int, key: str, value: str = None, key_type: str = None, is_secret: bool = False, is_required: bool = False):\n        tool_config = session.query(ToolConfig).filter_by(toolkit_id=toolkit_id, key=key).first()\n        if tool_config:\n            # Update existing tool config\n            if value is not None:\n                tool_config.value = (value)\n\n            if is_required is None:\n                tool_config.is_required = False\n            elif isinstance(is_required, bool):\n                tool_config.is_required = is_required\n            else:\n                raise ValueError(\"is_required should be a boolean value\")\n\n            if is_secret is None:\n                tool_config.is_secret = False\n            elif isinstance(is_secret, bool):\n                tool_config.is_secret = is_secret\n            else:\n                raise ValueError(\"is_secret should be a boolean value\")\n\n            if key_type is None:\n                tool_config.key_type = ToolConfigKeyType.STRING.value\n            elif isinstance(key_type,ToolConfigKeyType):\n                tool_config.key_type = key_type.value\n            else:\n                tool_config.key_type = key_type\n\n        else:\n            # Create new tool config\n            if key_type is None:\n                key_type = ToolConfigKeyType.STRING.value\n            if isinstance(key_type,ToolConfigKeyType):\n                key_type = key_type.value    \n            tool_config = ToolConfig(toolkit_id=toolkit_id, key=key, value=value, key_type=key_type, is_secret=is_secret, is_required=is_required)\n            session.add(tool_config)\n\n        session.commit()\n\n    @classmethod\n    def get_toolkit_tool_config(cls, session: Session, toolkit_id: int):\n        return session.query(ToolConfig).filter_by(toolkit_id=toolkit_id).all()\n"
  },
  {
    "path": "superagi/models/toolkit.py",
    "content": "import json\n\nimport requests\nfrom sqlalchemy import Column, Integer, String, Boolean\n\nfrom superagi.models.base_model import DBBaseModel\nfrom superagi.models.tool import Tool\n\nmarketplace_url = \"https://app.superagi.com/api\"\n# marketplace_url = \"http://localhost:8001\"\n\n\nclass Toolkit(DBBaseModel):\n    \"\"\"\n        ToolKit - Used to group tools together\n        Attributes:\n            id(int) : id of the tool kit\n            name(str) : name of the tool kit\n            description(str) : description of the tool kit\n            show_toolkit(boolean) : indicates whether the tool kit should be shown based on the count of tools in the toolkit\n            organisation_id(int) : org id of the to which tool config is related\n            tool_code_link(str) : stores Github link for toolkit\n    \"\"\"\n    __tablename__ = 'toolkits'\n\n    id = Column(Integer, primary_key=True)\n    name = Column(String)\n    description = Column(String)\n    show_toolkit = Column(Boolean)\n    organisation_id = Column(Integer)\n    tool_code_link = Column(String)\n\n    def __repr__(self):\n        return f\"ToolKit(id={self.id}, name='{self.name}', description='{self.description}', \" \\\n               f\"show_toolkit={self.show_toolkit},\" \\\n               f\"organisation_id = {self.organisation_id}\"\n\n    def to_dict(self):\n        return {\n            'id': self.id,\n            'name': self.name,\n            'description': self.description,\n            'show_toolkit': self.show_toolkit,\n            'organisation_id': self.organisation_id\n        }\n\n    def to_json(self):\n        return json.dumps(self.to_dict())\n\n    @classmethod\n    def from_json(cls, json_data):\n        data = json.loads(json_data)\n        return cls(\n            id=data['id'],\n            name=data['name'],\n            description=data['description'],\n            show_toolkit=data['show_toolkit'],\n            organisation_id=data['organisation_id']\n        )\n\n    @staticmethod\n    def add_or_update(session, name, description, show_toolkit, organisation_id, tool_code_link):\n        # Check if the toolkit exists\n        toolkit = session.query(Toolkit).filter(Toolkit.name == name,\n                                                Toolkit.organisation_id == organisation_id).first()\n\n        if toolkit:\n            # Update the existing toolkit\n            toolkit.name = name\n            toolkit.description = description\n            toolkit.show_toolkit = show_toolkit\n            toolkit.organisation_id = organisation_id\n            toolkit.tool_code_link = tool_code_link\n        else:\n            # Create a new toolkit\n            toolkit = Toolkit(\n                name=name,\n                description=description,\n                show_toolkit=show_toolkit,\n                organisation_id=organisation_id,\n                tool_code_link=tool_code_link\n            )\n\n            session.add(toolkit)\n\n        session.commit()\n        session.flush()\n        return toolkit\n\n    @classmethod\n    def fetch_marketplace_list(cls, page):\n        headers = {'Content-Type': 'application/json'}\n        response = requests.get(\n            marketplace_url + f\"/toolkits/marketplace/list/{str(page)}\",\n            headers=headers, timeout=10)\n        if response.status_code == 200:\n            return response.json()\n        else:\n            return []\n\n    @classmethod\n    def fetch_marketplace_detail(cls, search_str, toolkit_name):\n        headers = {'Content-Type': 'application/json'}\n        search_str = search_str.replace(' ', '%20')\n        toolkit_name = toolkit_name.replace(' ', '%20')\n        response = requests.get(\n            marketplace_url + f\"/toolkits/marketplace/{search_str}/{toolkit_name}\",\n            headers=headers, timeout=10)\n        if response.status_code == 200:\n            return response.json()\n        else:\n            return None\n\n    @staticmethod\n    def get_toolkit_from_name(session, toolkit_name, organisation):\n        toolkit = session.query(Toolkit).filter_by(name=toolkit_name, organisation_id=organisation.id).first()\n        if toolkit:\n            return toolkit\n        return None\n\n    @classmethod\n    def get_toolkit_installed_details(cls, session, marketplace_toolkits, organisation):\n        installed_toolkits = session.query(Toolkit).filter(Toolkit.organisation_id == organisation.id).all()\n        for toolkit in marketplace_toolkits:\n            if toolkit['name'] in [installed_toolkit.name for installed_toolkit in installed_toolkits]:\n                toolkit[\"is_installed\"] = True\n            else:\n                toolkit[\"is_installed\"] = False\n        return marketplace_toolkits\n\n    @classmethod\n    def fetch_tool_ids_from_toolkit(cls, session, toolkit_ids):\n        agent_toolkit_tools = []\n        for toolkit_id in toolkit_ids:\n            toolkit_tools = session.query(Tool).filter(Tool.toolkit_id == toolkit_id).all()\n            for tool in toolkit_tools:\n                tool = session.query(Tool).filter(Tool.id == tool.id).first()\n                if tool is not None:\n                    agent_toolkit_tools.append(tool.id)\n        return agent_toolkit_tools\n\n    @classmethod\n    def get_tool_and_toolkit_arr(cls, session, organisation_id :int,agent_config_tools_arr: list):\n        from superagi.models.tool import Tool\n        toolkits_arr= set()\n        tools_arr= set()\n        for tool_obj in agent_config_tools_arr:\n            toolkit=session.query(Toolkit).filter(Toolkit.name == tool_obj[\"name\"].strip(), Toolkit.organisation_id == organisation_id).first()\n            if toolkit is None:\n                raise Exception(\"One or more of the Tool(s)/Toolkit(s) does not exist.\")\n            toolkits_arr.add(toolkit.id)\n            if tool_obj.get(\"tools\"):\n                for tool_name_str in tool_obj[\"tools\"]:\n                    tool_db_obj = session.query(Tool).filter(Tool.name == tool_name_str.strip(),\n                                                             Tool.toolkit_id == toolkit.id).first()\n                    if tool_db_obj is None:\n                            raise Exception(\"One or more of the Tool(s)/Toolkit(s) does not exist.\")\n\n                    tools_arr.add(tool_db_obj.id)\n            else:\n                tools=Tool.get_toolkit_tools(session, toolkit.id)\n                for tool_db_obj in tools:\n                    tools_arr.add(tool_db_obj.id)\n        return list(tools_arr)\n"
  },
  {
    "path": "superagi/models/types/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/models/types/agent_config.py",
    "content": "from typing import Union\nfrom pydantic import BaseModel\n\nclass AgentConfig(BaseModel):\n    agent_id: int\n    key: str\n    value: Union[str, list]\n\n    def __repr__(self):\n        return f\"AgentConfiguration(id={self.id}, key={self.key}, value={self.value})\"\n\n"
  },
  {
    "path": "superagi/models/types/login_request.py",
    "content": "from pydantic import BaseModel\n\n\nclass LoginRequest(BaseModel):\n    email: str\n    password: str\n"
  },
  {
    "path": "superagi/models/types/validate_llm_api_key_request.py",
    "content": "from pydantic import BaseModel\n\n\nclass ValidateAPIKeyRequest(BaseModel):\n    model_source: str\n    model_api_key: str\n"
  },
  {
    "path": "superagi/models/user.py",
    "content": "from sqlalchemy import Column, Integer, String\n\nfrom superagi.models.base_model import DBBaseModel\n\n\n# from pydantic import BaseModel\n\nclass User(DBBaseModel):\n    \"\"\"\n    Model representing a user.\n\n    Attributes:\n        id (Integer): The primary key of the user.\n        name (String): The name of the user.\n        email (String): The email of the user.\n        password (String): The password of the user.\n        organisation_id (Integer): The ID of the associated organisation.\n    \"\"\"\n\n    __tablename__ = 'users'\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    name = Column(String)\n    email = Column(String, unique=True)\n    password = Column(String)\n    organisation_id = Column(Integer)\n    first_login_source = Column(String)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the User object.\n\n        Returns:\n            str: String representation of the User object.\n        \"\"\"\n\n        return f\"User(id={self.id}, name='{self.name}', email='{self.email}', password='{self.password}',\" \\\n               f\"organisation_id={self.organisation_id}, first_login_source={self.first_login_source})\"\n"
  },
  {
    "path": "superagi/models/vector_db_configs.py",
    "content": "from sqlalchemy import Column, Integer, Text, String\n\nfrom superagi.models.base_model import DBBaseModel\n\n\nclass VectordbConfigs(DBBaseModel):\n    \"\"\"\n    Vector db related configurations like api_key, environment, and url are stored here\n    Attributes:\n        id (int): The unique identifier of the vector db configuration.\n        vector_db_id (int): The identifier of the associated vector db.\n        key (str): The key of the configuration setting.\n        value (str): The value of the configuration setting.\n    \"\"\"\n\n    __tablename__ = 'vector_db_configs'\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    vector_db_id = Column(Integer)\n    key = Column(String)\n    value = Column(Text)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the Agent Configuration object.\n        Returns:\n            str: String representation of the Agent Configuration.\n        \"\"\"\n        return f\"VectorConfiguration(id={self.id}, key={self.key}, value={self.value})\"\n\n    @classmethod\n    def get_vector_db_config_from_db_id(cls, session, vector_db_id):\n        vector_db_configs = session.query(VectordbConfigs).filter(VectordbConfigs.vector_db_id == vector_db_id).all()\n        config_data = {}\n        for config in vector_db_configs:\n            config_data[config.key] = config.value\n        return config_data\n\n    @classmethod\n    def add_vector_db_config(cls, session, vector_db_id, db_creds):\n        for key, value in db_creds.items():\n            vector_db_config = VectordbConfigs(vector_db_id=vector_db_id, key=key, value=value)\n            session.add(vector_db_config)\n            session.commit()\n\n    @classmethod\n    def delete_vector_db_configs(cls, session, vector_db_id):\n        session.query(VectordbConfigs).filter(VectordbConfigs.vector_db_id == vector_db_id).delete()\n        session.commit()"
  },
  {
    "path": "superagi/models/vector_db_indices.py",
    "content": "from __future__ import annotations\n\nfrom sqlalchemy import Column, Integer, String\n\n# from superagi.models import AgentConfiguration\nfrom superagi.models.base_model import DBBaseModel\n\n\nclass VectordbIndices(DBBaseModel):\n    \"\"\"\n    Represents an vector db index.\n    Attributes:\n        id (int): The unique identifier of the index/collection also referred to as class in Weaviate.\n        name (str): The name of the index/collection.\n        vector_db_id (int): The identifier of the associated vector db.\n    \"\"\"\n\n    __tablename__ = 'vector_db_indices'\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    name = Column(String)\n    vector_db_id = Column(Integer)\n    dimensions = Column(Integer)\n    state = Column(String)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the Vector db index object.\n        Returns:\n            str: String representation of the Vector db index.\n        \"\"\"\n        return f\"VectordbIndices(id={self.id}, name='{self.name}', vector_db_id={self.vector_db_id}, dimensions={self.dimensions}, state={self.state})\"\n\n    @classmethod\n    def get_vector_index_from_id(cls, session, vector_db_index_id):\n        vector_db_index = session.query(VectordbIndices).filter(VectordbIndices.id == vector_db_index_id).first()\n        return vector_db_index\n\n    @classmethod\n    def get_vector_indices_from_vectordb(cls, session, vector_db_id):\n        vector_indices = session.query(VectordbIndices).filter(VectordbIndices.vector_db_id == vector_db_id).all()\n        return vector_indices\n\n    @classmethod\n    def delete_vector_db_index(cls, session, vector_index_id):\n        session.query(VectordbIndices).filter(VectordbIndices.id == vector_index_id).delete()\n        session.commit()\n\n    @classmethod\n    def add_vector_index(cls, session, index_name, vector_db_id, state, dimensions = None): #will be none only in the case of weaviate\n        vector_index = VectordbIndices(name=index_name, vector_db_id=vector_db_id, dimensions=dimensions, state=state)\n        session.add(vector_index)\n        session.commit()\n\n    @classmethod\n    def update_vector_index_state(cls, session, index_id, state):\n        vector_index = session.query(VectordbIndices).filter(VectordbIndices.id == index_id).first()\n        vector_index.state = state\n        session.commit()"
  },
  {
    "path": "superagi/models/vector_dbs.py",
    "content": "from __future__ import annotations\nimport requests\n\nfrom sqlalchemy import Column, Integer, String\n\n# from superagi.models import AgentConfiguration\nfrom superagi.models.base_model import DBBaseModel\n\nmarketplace_url = \"https://app.superagi.com/api\"\n# marketplace_url = \"http://localhost:8001\"\n\nclass Vectordbs(DBBaseModel):\n    \"\"\"\n    Represents an vector db entity.\n    Attributes:\n        id (int): The unique identifier of the agent.\n        name (str): The name of the database.\n        db_type (str): The name of the db agent.\n        organisation_id (int): The identifier of the associated organisation.\n    \"\"\"\n\n    __tablename__ = 'vector_dbs'\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    name = Column(String)\n    db_type = Column(String)\n    organisation_id = Column(Integer)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the Vector db object.\n        Returns:\n            str: String representation of the Vector db.\n        \"\"\"\n        return f\"Vector(id={self.id}, name='{self.name}', db_type='{self.db_type}' organisation_id={self.organisation_id}, updated_at={self.updated_at})\"\n\n    @classmethod\n    def get_vector_db_from_id(cls, session, vector_db_id):\n        vector_db = session.query(Vectordbs).filter(Vectordbs.id == vector_db_id).first()\n        return vector_db\n\n    @classmethod\n    def fetch_marketplace_list(cls):\n        headers = {'Content-Type': 'application/json'}\n        response = requests.get(\n            marketplace_url + f\"/vector_dbs/marketplace/list\",\n            headers=headers, timeout=10)\n        if response.status_code == 200:\n            return response.json()\n        else:\n            return []\n\n    @classmethod\n    def get_vector_db_from_organisation(cls, session, organisation):\n        vector_db_list = session.query(Vectordbs).filter(Vectordbs.organisation_id == organisation.id).all()\n        return vector_db_list\n\n    @classmethod\n    def add_vector_db(cls, session, name, db_type, organisation):\n        vector_db = Vectordbs(name=name, db_type=db_type, organisation_id=organisation.id)\n        session.add(vector_db)\n        session.commit()\n        return vector_db\n\n    @classmethod\n    def delete_vector_db(cls, session, vector_db_id):\n        session.query(Vectordbs).filter(Vectordbs.id == vector_db_id).delete()\n        session.commit()"
  },
  {
    "path": "superagi/models/webhook_events.py",
    "content": "from sqlalchemy import Column, Integer, Text, String, Boolean, ForeignKey\nfrom sqlalchemy.orm import relationship\nfrom superagi.models.base_model import DBBaseModel\nfrom superagi.models.agent_execution import AgentExecution\n\n\nclass WebhookEvents(DBBaseModel):\n    \"\"\"\n\n    Attributes:\n        \n\n    Methods:\n    \"\"\"\n    __tablename__ = 'webhook_events'\n\n    id = Column(Integer, primary_key=True)\n    agent_id=Column(Integer)\n    run_id = Column(Integer)\n    event = Column(String)\n    status = Column(String)\n    errors= Column(Text)\n    \n\n    \n"
  },
  {
    "path": "superagi/models/webhooks.py",
    "content": "from sqlalchemy import Column, Integer, Text, String, Boolean, ForeignKey,JSON\nfrom sqlalchemy.orm import relationship\nfrom sqlalchemy.dialects.postgresql import JSONB\nfrom superagi.models.base_model import DBBaseModel\nfrom superagi.models.agent_execution import AgentExecution\n\nclass Webhooks(DBBaseModel):\n    \"\"\"\n\n    Attributes:\n        \n\n    Methods:\n    \"\"\"\n    __tablename__ = 'webhooks'\n\n    id = Column(Integer, primary_key=True)\n    name=Column(String)\n    org_id = Column(Integer)\n    url = Column(String)\n    headers=Column(JSON)\n    is_deleted=Column(Boolean)\n    filters=Column(JSON)\n"
  },
  {
    "path": "superagi/models/workflows/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/models/workflows/agent_workflow.py",
    "content": "import json\n\nfrom sqlalchemy import Column, Integer, String, Text\n\nfrom superagi.models.workflows.agent_workflow_step import AgentWorkflowStep\nfrom superagi.models.base_model import DBBaseModel\n\n\nclass AgentWorkflow(DBBaseModel):\n    \"\"\"\n    Agent workflows which runs part of each agent execution step\n\n    Attributes:\n        id (int): The unique identifier of the agent workflow.\n        name (str): The name of the agent workflow.\n        description (str): The description of the agent workflow.\n    \"\"\"\n\n    __tablename__ = 'agent_workflows'\n\n    id = Column(Integer, primary_key=True)\n    name = Column(String)\n    description = Column(Text)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the AgentWorkflow object.\n\n        Returns:\n            str: String representation of the AgentWorkflow.\n        \"\"\"\n\n        return f\"AgentWorkflow(id={self.id}, name='{self.name}', \" \\\n               f\"description='{self.description}')\"\n\n    def to_dict(self):\n        \"\"\"\n            Converts the AgentWorkflow object to a dictionary.\n\n            Returns:\n                dict: Dictionary representation of the AgentWorkflow.\n        \"\"\"\n\n        return {\n            'id': self.id,\n            'name': self.name,\n            'description': self.description\n        }\n\n    def to_json(self):\n        \"\"\"\n        Converts the AgentWorkflow object to a JSON string.\n\n        Returns:\n            str: JSON string representation of the AgentWorkflow.\n        \"\"\"\n\n        return json.dumps(self.to_dict())\n\n    @classmethod\n    def from_json(cls, json_data):\n        \"\"\"\n        Creates an AgentWorkflow object from a JSON string.\n\n        Args:\n            json_data (str): JSON string representing the AgentWorkflow.\n\n        Returns:\n            AgentWorkflow: AgentWorkflow object created from the JSON string.\n        \"\"\"\n\n        data = json.loads(json_data)\n        return cls(\n            id=data['id'],\n            name=data['name'],\n            description=data['description']\n        )\n\n    @classmethod\n    def fetch_trigger_step_id(cls, session, workflow_id):\n        \"\"\"\n        Fetches the trigger step ID of the specified agent workflow.\n\n        Args:\n            session: The session object used for database operations.\n            workflow_id (int): The ID of the agent workflow.\n\n        Returns:\n            int: The ID of the trigger step.\n\n        \"\"\"\n        trigger_step = session.query(AgentWorkflowStep).filter(AgentWorkflowStep.agent_workflow_id == workflow_id,\n                                                               AgentWorkflowStep.step_type == 'TRIGGER').first()\n        return trigger_step\n\n    @classmethod\n    def find_by_id(cls, session, id: int):\n        \"\"\"Create or find an agent workflow by name.\"\"\"\n        return session.query(AgentWorkflow).filter(AgentWorkflow.id == id).first()\n\n\n    @classmethod\n    def find_by_name(cls, session, name: str):\n        \"\"\"Create or find an agent workflow by name.\"\"\"\n        return session.query(AgentWorkflow).filter(AgentWorkflow.name == name).first()\n\n    @classmethod\n    def find_or_create_by_name(cls, session, name: str, description: str):\n        \"\"\"Create or find an agent workflow by name.\"\"\"\n        agent_workflow = session.query(AgentWorkflow).filter(AgentWorkflow.name == name).first()\n        if agent_workflow is None:\n            agent_workflow = AgentWorkflow(name=name, description=description)\n            session.add(agent_workflow)\n            session.commit()\n        return agent_workflow\n"
  },
  {
    "path": "superagi/models/workflows/agent_workflow_step.py",
    "content": "import json\n\nfrom sqlalchemy import Column, Integer, String\nfrom sqlalchemy.dialects.postgresql import JSONB\n\nfrom superagi.lib.logger import logger\nfrom superagi.models.base_model import DBBaseModel\nfrom superagi.models.workflows.agent_workflow_step_tool import AgentWorkflowStepTool\nfrom superagi.models.workflows.agent_workflow_step_wait import AgentWorkflowStepWait\nfrom superagi.models.workflows.iteration_workflow import IterationWorkflow\n\n\nclass AgentWorkflowStep(DBBaseModel):\n    \"\"\"\n    Step of an agent workflow\n\n    Attributes:\n        id (int): The unique identifier of the agent workflow step.\n        agent_workflow_id (int): The ID of the agent workflow to which this step belongs.\n        unique_id (str): The unique identifier of the step.\n        step_type (str): The type of the step (TRIGGER, NORMAL).\n        action_type (str): The type of the action (TOOL, ITERATION_WORKFLOW, LLM).\n        action_reference_id: Reference id of the tool/iteration workflow/llm\n        next_steps: Next steps output and step id.\n    \"\"\"\n\n    __tablename__ = 'agent_workflow_steps'\n\n    id = Column(Integer, primary_key=True)\n    agent_workflow_id = Column(Integer)\n    unique_id = Column(String)\n    step_type = Column(String)  # TRIGGER, NORMAL\n    action_type = Column(String)  # TOOL, ITERATION_WORKFLOW, LLM, WAIT_STEP\n    action_reference_id = Column(Integer)  # id of the action\n    next_steps = Column(JSONB)  # edge_ref_id, response, step_id\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the AgentWorkflowStep object.\n\n        Returns:\n            str: String representation of the AgentWorkflowStep.\n        \"\"\"\n\n        return f\"AgentWorkflowStep(id={self.id}, status='{self.agent_workflow_id}', \" \\\n               f\"prompt='{self.unique_id}', agent_id={self.step_type}, action_type={self.action_type}, \" \\\n               f\"action_reference_id={self.action_reference_id}, next_steps={self.next_steps})\"\n\n    def to_dict(self):\n        \"\"\"\n        Converts the AgentWorkflowStep object to a dictionary.\n\n        Returns:\n            dict: Dictionary representation of the AgentWorkflowStep.\n        \"\"\"\n\n        return {\n            'id': self.id,\n            'agent_workflow_id': self.agent_workflow_id,\n            'unique_id': self.unique_id,\n            'step_type': self.step_type,\n            'next_steps': self.next_steps,\n            'action_type': self.action_type,\n            'action_reference_id': self.action_reference_id\n        }\n\n    def to_json(self):\n        \"\"\"\n        Converts the AgentWorkflowStep object to a JSON string.\n\n        Returns:\n            str: JSON string representation of the AgentWorkflowStep.\n        \"\"\"\n\n        return json.dumps(self.to_dict())\n\n    @classmethod\n    def from_json(cls, json_data):\n        \"\"\"\n        Creates an AgentWorkflowStep object from a JSON string.\n\n        Args:\n            json_data (str): JSON string representing the AgentWorkflowStep.\n\n        Returns:\n            AgentWorkflowStep: AgentWorkflowStep object created from the JSON string.\n        \"\"\"\n\n        data = json.loads(json_data)\n        return cls(\n            id=data['id'],\n            agent_workflow_id=data['agent_workflow_id'],\n            unique_id=data['unique_id'],\n            step_type=data['step_type'],\n            action_type=data['action_type'],\n            action_reference_id=data['action_reference_id'],\n            next_steps=data['next_steps'],\n        )\n\n    @classmethod\n    def find_by_unique_id(cls, session, unique_id: str):\n        \"\"\" Adds a workflows step in the next_steps column\"\"\"\n        return session.query(AgentWorkflowStep).filter(AgentWorkflowStep.unique_id == unique_id).first()\n\n    @classmethod\n    def find_by_id(cls, session, step_id: int):\n        \"\"\" Find the workflow step by id\"\"\"\n        return session.query(AgentWorkflowStep).filter(AgentWorkflowStep.id == step_id).first()\n\n    @classmethod\n    def find_or_create_tool_workflow_step(cls, session, agent_workflow_id: int, unique_id: str,\n                                          tool_name: str, input_instruction: str,\n                                          output_instruction: str = \"\", step_type=\"NORMAL\",\n                                          history_enabled: bool = True, completion_prompt: str = None):\n        \"\"\" Find or create a tool workflow step\n\n        Args:\n            session: db session\n            agent_workflow_id: id of the agent workflow\n            unique_id: unique id of the step\n            tool_name: name of the tool\n            input_instruction: input instruction of the tool\n            output_instruction: output instruction of the tool\n            step_type: type of the step\n            history_enabled: whether to enable history for the step\n            completion_prompt: completion prompt in the llm\n\n        Returns:\n            AgentWorkflowStep.\n        \"\"\"\n        workflow_step = session.query(AgentWorkflowStep).filter(\n            AgentWorkflowStep.agent_workflow_id == agent_workflow_id, AgentWorkflowStep.unique_id == unique_id).first()\n        if completion_prompt is None:\n            completion_prompt = f\"Respond with only valid JSON conforming to the given json schema. Response should contain tool name and tool arguments to achieve the given instruction.\"\n        step_tool = AgentWorkflowStepTool.find_or_create_tool(session, unique_id, tool_name,\n                                                              input_instruction, output_instruction,\n                                                              history_enabled, completion_prompt)\n\n        if workflow_step is None:\n            workflow_step = AgentWorkflowStep(unique_id=unique_id, step_type=step_type,\n                                              agent_workflow_id=agent_workflow_id)\n            session.add(workflow_step)\n            session.commit()\n        workflow_step.step_type = step_type\n        workflow_step.agent_workflow_id = agent_workflow_id\n        workflow_step.action_reference_id = step_tool.id\n        workflow_step.action_type = \"TOOL\"\n        workflow_step.next_steps = []\n        workflow_step.completion_prompt = completion_prompt\n        session.commit()\n        return workflow_step\n\n    @classmethod\n    def find_or_create_wait_workflow_step(cls, session, agent_workflow_id: int, unique_id: str,\n                                          wait_description: str, delay: int, step_type=\"NORMAL\"):\n        \"\"\" Find or create a wait workflow step\"\"\"\n        logger.info(\"Finding or creating wait step\")\n        workflow_step = session.query(AgentWorkflowStep).filter(\n            AgentWorkflowStep.agent_workflow_id == agent_workflow_id, AgentWorkflowStep.unique_id == unique_id).first()\n\n        step_wait = AgentWorkflowStepWait.find_or_create_wait(session=session, step_unique_id=unique_id,\n                                                              description=wait_description, delay=delay)\n        if workflow_step is None:\n            workflow_step = AgentWorkflowStep(unique_id=unique_id, step_type=step_type,\n                                              agent_workflow_id=agent_workflow_id)\n            session.add(workflow_step)\n            session.commit()\n        workflow_step.step_type = step_type\n        workflow_step.agent_workflow_id = agent_workflow_id\n        workflow_step.action_reference_id = step_wait.id\n        workflow_step.action_type = \"WAIT_STEP\"\n        workflow_step.next_steps = []\n        session.commit()\n        return workflow_step\n\n    @classmethod\n    def find_or_create_iteration_workflow_step(cls, session, agent_workflow_id: int, unique_id: str,\n                                               iteration_workflow_name: str, step_type=\"NORMAL\"):\n        \"\"\" Find or create a iteration workflow step\n\n        Args:\n            session: db session\n            agent_workflow_id: id of the agent workflow\n            unique_id: unique id of the step\n            iteration_workflow_name: name of the iteration workflow\n            step_type: type of the step\n\n        Returns:\n            AgentWorkflowStep.\n        \"\"\"\n        workflow_step = session.query(AgentWorkflowStep).filter(\n            AgentWorkflowStep.agent_workflow_id == agent_workflow_id, AgentWorkflowStep.unique_id == unique_id).first()\n\n        iteration_workflow = IterationWorkflow.find_workflow_by_name(session, iteration_workflow_name)\n\n        if workflow_step is None:\n            workflow_step = AgentWorkflowStep(unique_id=unique_id, step_type=step_type,\n                                              agent_workflow_id=agent_workflow_id)\n            session.add(workflow_step)\n            session.commit()\n        workflow_step.step_type = step_type\n        workflow_step.agent_workflow_id = agent_workflow_id\n        workflow_step.action_reference_id = iteration_workflow.id\n        workflow_step.action_type = \"ITERATION_WORKFLOW\"\n        workflow_step.next_steps = []\n        session.commit()\n        return workflow_step\n\n    @classmethod\n    def add_next_workflow_step(cls, session, current_agent_step_id: int, next_step_id: int,\n                               step_response: str = \"default\"):\n        \"\"\" Add Next workflow steps in the next_steps column\n\n        Args:\n            session: db session\n            current_agent_step_id: id of the current agent step\n            next_step_id: id of the next agent step\n            step_response: response of the current step\n\n        \"\"\"\n        next_unique_id = \"-1\"\n        if next_step_id != -1:\n            next_workflow_step = AgentWorkflowStep.find_by_id(session, next_step_id)\n            next_unique_id = next_workflow_step.unique_id\n        current_step = session.query(AgentWorkflowStep).filter(AgentWorkflowStep.id == current_agent_step_id).first()\n        next_steps = json.loads(json.dumps(current_step.next_steps))\n        existing_steps = [step for step in next_steps if step[\"step_id\"] == next_unique_id]\n        if existing_steps:\n            existing_steps[0][\"step_response\"] = step_response\n            current_step.next_steps = next_steps\n        else:\n            next_steps.append({\"step_response\": str(step_response), \"step_id\": str(next_unique_id)})\n            current_step.next_steps = next_steps\n        session.commit()\n        return current_step\n\n    @classmethod\n    def fetch_default_next_step(cls, session, current_agent_step_id: int):\n        \"\"\" Fetches the default next step\n\n        Args:\n            session: db session\n            current_agent_step_id: id of the current agent step\n        \"\"\"\n        current_step = AgentWorkflowStep.find_by_id(session, current_agent_step_id)\n        next_steps = current_step.next_steps\n        default_steps = [step for step in next_steps if step[\"step_response\"] == \"default\"]\n        if default_steps:\n            return AgentWorkflowStep.find_by_unique_id(session, default_steps[0][\"step_id\"])\n        return None\n\n    @classmethod\n    def fetch_next_step(cls, session, current_agent_step_id: int, step_response: str):\n        \"\"\" Fetch the next step based on the step response\n\n        Args:\n            session: db session\n            current_agent_step_id: id of the current agent step\n            step_response: response of the current step\n        \"\"\"\n        current_step = AgentWorkflowStep.find_by_id(session, current_agent_step_id)\n        next_steps = current_step.next_steps\n        matching_steps = [step for step in next_steps if str(step[\"step_response\"]).lower() == step_response.lower()]\n\n        if matching_steps:\n            if str(matching_steps[0][\"step_id\"]) == \"-1\":\n                return \"COMPLETE\"\n            return AgentWorkflowStep.find_by_unique_id(session, matching_steps[0][\"step_id\"])\n\n        logger.info(f\"Could not find next step for step_id: {current_agent_step_id} and step_response: {step_response}\")\n        default_steps = [step for step in next_steps if str(step[\"step_response\"]).lower() == \"default\"]\n\n        if default_steps:\n            if str(default_steps[0][\"step_id\"]) == \"-1\":\n                return \"COMPLETE\"\n            return AgentWorkflowStep.find_by_unique_id(session, default_steps[0][\"step_id\"])\n        return None\n"
  },
  {
    "path": "superagi/models/workflows/agent_workflow_step_tool.py",
    "content": "import json\n\nfrom sqlalchemy import Column, Integer, String, Text, Boolean\nfrom sqlalchemy.dialects.postgresql import JSONB\n\nfrom superagi.models.base_model import DBBaseModel\n\n\nclass AgentWorkflowStepTool(DBBaseModel):\n    \"\"\"\n    Step of an agent workflow\n\n    Attributes:\n        id (int): The unique identifier of the agent workflow step\n        tool_name (str): Tool name\n        input_instruction (str): Input Instruction to the tool\n        output_instruction (str): Output Instruction to the tool\n        history_enabled: whether history enabled in the step\n        completion_prompt: completion prompt in the llm conversations\n    \"\"\"\n\n    __tablename__ = 'agent_workflow_step_tools'\n\n    id = Column(Integer, primary_key=True)\n    tool_name = Column(String)\n    unique_id = Column(String)\n    input_instruction = Column(Text)\n    output_instruction = Column(Text)\n    history_enabled = Column(Boolean)\n    completion_prompt = Column(Text)\n    \n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the AgentWorkflowStep object.\n\n        Returns:\n            str: String representation of the AgentWorkflowStep.\n        \"\"\"\n\n        return f\"AgentWorkflowStep(id={self.id}, \" \\\n               f\"prompt='{self.tool_name}', agent_id={self.tool_instruction})\"\n    \n    def to_dict(self):\n        \"\"\"\n        Converts the AgentWorkflowStep object to a dictionary.\n\n        Returns:\n            dict: Dictionary representation of the AgentWorkflowStep.\n        \"\"\"\n\n        return {\n            'id': self.id,\n            'tool_name': self.tool_name,\n            'input_instruction': self.input_instruction,\n            'output_instruction': self.output_instruction,\n            'history_enabled': self.history_enabled,\n            'completion_prompt': self.completion_prompt,\n        }\n\n    def to_json(self):\n        \"\"\"\n        Converts the AgentWorkflowStep object to a JSON string.\n\n        Returns:\n            str: JSON string representation of the AgentWorkflowStep.\n        \"\"\"\n\n        return json.dumps(self.to_dict())\n\n    @classmethod\n    def from_json(cls, json_data):\n        \"\"\"\n        Creates an AgentWorkflowStep object from a JSON string.\n\n        Args:\n            json_data (str): JSON string representing the AgentWorkflowStep.\n\n        Returns:\n            AgentWorkflowStep: AgentWorkflowStep object created from the JSON string.\n        \"\"\"\n\n        data = json.loads(json_data)\n        return cls(\n            id=data['id'],\n            tool_name=data['tool_name'],\n            input_instruction=data['input_instruction'],\n            output_instruction=data['output_instruction'],\n            history_enabled=data['history_enabled'],\n            completion_prompt=data['completion_prompt'],\n        )\n\n    @classmethod\n    def find_by_id(cls, session, step_id: int):\n        return session.query(AgentWorkflowStepTool).filter(AgentWorkflowStepTool.id == step_id).first()\n\n    @classmethod\n    def find_or_create_tool(cls, session, step_unique_id: str, tool_name: str,\n                            input_instruction: str, output_instruction: str,\n                            history_enabled: bool = False, completion_prompt: str = None):\n        \"\"\"\n        Finds or creates a tool in the database.\n\n        Args:\n            session (Session): SQLAlchemy session object.\n            step_unique_id (str): Unique ID of the step.\n            tool_name (str): Name of the tool.\n            input_instruction (str): Tool input instructions.\n            output_instruction (str): Tool output instructions.\n            history_enabled (bool): Whether history is enabled for the tool.\n            completion_prompt (str): Completion prompt for the tool.\n\n        Returns:\n            AgentWorkflowStepTool: The AgentWorkflowStepTool object.\n        \"\"\"\n        unique_id = f\"{step_unique_id}_{tool_name}\"\n        tool = session.query(AgentWorkflowStepTool).filter_by(\n            unique_id=unique_id\n        ).first()\n\n        if tool is None:\n            tool = AgentWorkflowStepTool(tool_name=tool_name, unique_id=unique_id,\n                                         input_instruction=input_instruction,\n                                         output_instruction=output_instruction,\n                                         history_enabled=history_enabled,\n                                         completion_prompt=completion_prompt)\n            session.add(tool)\n        else:\n            tool.tool_name = tool_name\n            tool.input_instruction = input_instruction\n            tool.output_instruction = output_instruction\n            tool.history_enabled = history_enabled\n            tool.completion_prompt = completion_prompt\n        session.commit()\n        return tool\n\n"
  },
  {
    "path": "superagi/models/workflows/agent_workflow_step_wait.py",
    "content": "import json\n\nfrom sqlalchemy import Column, Integer, String, DateTime\n\nfrom superagi.models.base_model import DBBaseModel\n\n\nclass AgentWorkflowStepWait(DBBaseModel):\n    \"\"\"\n    Step for a Agent Workflow to wait\n\n    Attributes:\n        id (int): The unique identifier of the wait block step.\n        name (str): The name of the wait block step.\n        description (str): The description of the wait block step.\n        delay (int): The delay time in seconds.\n        wait_begin_time (DateTime): The start time of the wait block.\n    \"\"\"\n\n    __tablename__ = 'agent_workflow_step_waits'\n\n    id = Column(Integer, primary_key=True)\n    name = Column(String)\n    description = Column(String)\n    unique_id = Column(String)\n    delay = Column(Integer)  # Delay is stored in seconds\n    wait_begin_time = Column(DateTime)\n    status = Column(String)  # 'PENDING', 'WAITING', 'COMPLETED'\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the WaitBlockStep object.\n\n        Returns:\n            str: String representation of the WaitBlockStep.\n        \"\"\"\n\n        return f\"WaitBlockStep(id={self.id}, name='{self.name}', delay='{self.delay}', \" \\\n               f\"wait_begin_time='{self.wait_begin_time}'\"\n\n    def to_dict(self):\n        \"\"\"\n        Converts the WaitBlockStep object to a dictionary.\n\n        Returns:\n            dict: Dictionary representation of the WaitBlockStep.\n        \"\"\"\n\n        return {\n            'id': self.id,\n            'name': self.name,\n            'delay': self.delay,\n            'wait_begin_time': self.wait_begin_time\n        }\n\n    def to_json(self):\n        \"\"\"\n        Converts the WaitBlockStep object to a JSON string.\n\n        Returns:\n            str: JSON string representation of the WaitBlockStep.\n        \"\"\"\n\n        return json.dumps(self.to_dict())\n\n    @classmethod\n    def find_by_id(cls, session, step_id: int):\n        return session.query(AgentWorkflowStepWait).filter(AgentWorkflowStepWait.id == step_id).first()\n\n    @classmethod\n    def find_or_create_wait(cls, session, step_unique_id: str, description: str, delay: int):\n        unique_id = f\"{step_unique_id}_wait\"\n        wait = session.query(AgentWorkflowStepWait).filter(AgentWorkflowStepWait.unique_id == unique_id).first()\n        if wait is None:\n            wait = AgentWorkflowStepWait(\n                unique_id=unique_id,\n                name=unique_id,\n                delay=delay,\n                description=description,\n                status='PENDING'\n            )\n            session.add(wait)\n        else:\n            wait.delay = delay\n            wait.description = description\n            wait.status = 'PENDING'\n        session.commit()\n        session.flush()\n        return wait\n"
  },
  {
    "path": "superagi/models/workflows/iteration_workflow.py",
    "content": "import json\n\nfrom sqlalchemy import Column, Integer, String, Text, Boolean\n\nfrom superagi.models.base_model import DBBaseModel\nfrom superagi.models.workflows.iteration_workflow_step import IterationWorkflowStep\n\n\nclass IterationWorkflow(DBBaseModel):\n    \"\"\"\n    Agent workflows which runs part of each agent execution step\n\n    Attributes:\n        id (int): The unique identifier of the agent workflow.\n        name (str): The name of the agent workflow.\n        description (str): The description of the agent workflow.\n    \"\"\"\n\n    __tablename__ = 'iteration_workflows'\n\n    id = Column(Integer, primary_key=True)\n    name = Column(String)\n    description = Column(Text)\n    has_task_queue = Column(Boolean, default=False)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the AgentWorkflow object.\n\n        Returns:\n            str: String representation of the AgentWorkflow.\n        \"\"\"\n\n        return f\"AgentWorkflow(id={self.id}, name='{self.name}', \" \\\n               f\"description='{self.description}')\"\n\n    def to_dict(self):\n        \"\"\"\n            Converts the AgentWorkflow object to a dictionary.\n\n            Returns:\n                dict: Dictionary representation of the AgentWorkflow.\n        \"\"\"\n\n        return {\n            'id': self.id,\n            'name': self.name,\n            'description': self.description\n        }\n\n    def to_json(self):\n        \"\"\"\n        Converts the AgentWorkflow object to a JSON string.\n\n        Returns:\n            str: JSON string representation of the AgentWorkflow.\n        \"\"\"\n\n        return json.dumps(self.to_dict())\n\n    @classmethod\n    def from_json(cls, json_data):\n        \"\"\"\n        Creates an AgentWorkflow object from a JSON string.\n\n        Args:\n            json_data (str): JSON string representing the AgentWorkflow.\n\n        Returns:\n            AgentWorkflow: AgentWorkflow object created from the JSON string.\n        \"\"\"\n\n        data = json.loads(json_data)\n        return cls(\n            id=data['id'],\n            name=data['name'],\n            description=data['description']\n        )\n\n    @classmethod\n    def fetch_trigger_step_id(cls, session, workflow_id):\n        \"\"\"\n        Fetches the trigger step ID of the specified iteration workflow.\n\n        Args:\n            session: The session object used for database operations.\n            workflow_id (int): The ID of the agent workflow.\n\n        Returns:\n            int: The ID of the trigger step.\n\n        \"\"\"\n\n        trigger_step = session.query(IterationWorkflowStep).filter(\n            IterationWorkflowStep.iteration_workflow_id == workflow_id,\n            IterationWorkflowStep.step_type == 'TRIGGER').first()\n        return trigger_step\n\n    @classmethod\n    def find_workflow_by_name(cls, session, name: str):\n        \"\"\"\n        Finds an IterationWorkflow by name.\n\n        Args:\n            session (Session): SQLAlchemy session object.\n            name (str): Name of the AgentWorkflow.\n\n        Returns:\n            AgentWorkflow: AgentWorkflow object with the given name.\n        \"\"\"\n        return session.query(IterationWorkflow).filter(IterationWorkflow.name == name).first()\n\n    @classmethod\n    def find_or_create_by_name(cls, session, name: str, description: str, has_task_queue: bool = False):\n        \"\"\"\n        Finds an IterationWorkflow by name or creates it if it does not exist.\n        Args:\n            session (Session): SQLAlchemy session object.\n            name (str): Name of the AgentWorkflow.\n            description (str): Description of the AgentWorkflow.\n        \"\"\"\n        iteration_workflow = session.query(IterationWorkflow).filter(\n            IterationWorkflow.name == name).first()\n        if iteration_workflow is None:\n            iteration_workflow = IterationWorkflow(name=name, description=description)\n            session.add(iteration_workflow)\n            session.commit()\n        iteration_workflow.has_task_queue = has_task_queue\n        session.commit()\n\n        return iteration_workflow\n\n    @classmethod\n    def find_by_id(cls, session, id: int):\n        \"\"\" Find the workflow step by id\"\"\"\n        return session.query(IterationWorkflow).filter(IterationWorkflow.id == id).first()"
  },
  {
    "path": "superagi/models/workflows/iteration_workflow_step.py",
    "content": "import json\n\nfrom sqlalchemy import Column, Integer, String, Text, Boolean\nfrom sqlalchemy.dialects.postgresql import JSONB\n\nfrom superagi.models.base_model import DBBaseModel\n\n\nclass IterationWorkflowStep(DBBaseModel):\n    \"\"\"\n    Step of an iteration workflow\n\n    Attributes:\n        id (int): The unique identifier of the agent workflow step.\n        iteration_workflow_id (int): The ID of the agent workflow to which this step belongs.\n        unique_id (str): The unique identifier of the step.\n        prompt (str): The prompt for the step.\n        variables (str): The variables associated with the step.\n        output_type (str): The output type of the step.\n        step_type (str): The type of the step (TRIGGER, NORMAL).\n        next_step_id (int): The ID of the next step in the workflow.\n        history_enabled (bool): Indicates whether history is enabled for the step.\n        completion_prompt (str): The completion prompt for the step.\n    \"\"\"\n\n    __tablename__ = 'iteration_workflow_steps'\n\n    id = Column(Integer, primary_key=True)\n    iteration_workflow_id = Column(Integer)\n    unique_id = Column(String)\n    prompt = Column(Text)\n    variables = Column(Text)\n    output_type = Column(String)\n    step_type = Column(String)  # TRIGGER, NORMAL\n    next_step_id = Column(Integer)\n    history_enabled = Column(Boolean)\n    completion_prompt = Column(Text)\n\n    def __repr__(self):\n        \"\"\"\n        Returns a string representation of the AgentWorkflowStep object.\n\n        Returns:\n            str: String representation of the AgentWorkflowStep.\n        \"\"\"\n\n        return f\"AgentWorkflowStep(id={self.id}, status='{self.next_step_id}', \" \\\n               f\"prompt='{self.prompt}'\"\n    \n    def to_dict(self):\n        \"\"\"\n        Converts the AgentWorkflowStep object to a dictionary.\n\n        Returns:\n            dict: Dictionary representation of the AgentWorkflowStep.\n        \"\"\"\n\n        return {\n            'id': self.id,\n            'next_step_id': self.next_step_id,\n            'agent_id': self.agent_id,\n            'prompt': self.prompt\n        }\n\n    def to_json(self):\n        \"\"\"\n        Converts the AgentWorkflowStep object to a JSON string.\n\n        Returns:\n            str: JSON string representation of the AgentWorkflowStep.\n        \"\"\"\n\n        return json.dumps(self.to_dict())\n\n    @classmethod\n    def from_json(cls, json_data):\n        \"\"\"\n        Creates an AgentWorkflowStep object from a JSON string.\n\n        Args:\n            json_data (str): JSON string representing the AgentWorkflowStep.\n\n        Returns:\n            AgentWorkflowStep: AgentWorkflowStep object created from the JSON string.\n        \"\"\"\n\n        data = json.loads(json_data)\n        return cls(\n            id=data['id'],\n            prompt=data['prompt'],\n            agent_id=data['agent_id'],\n            next_step_id=data['next_step_id']\n        )\n\n    @classmethod\n    def find_by_id(cls, session, step_id: int):\n        return session.query(IterationWorkflowStep).filter(IterationWorkflowStep.id == step_id).first()\n\n    @classmethod\n    def find_or_create_step(self, session, iteration_workflow_id: int, unique_id: str,\n                            prompt: str, variables: str, step_type: str, output_type: str,\n                            completion_prompt: str = \"\", history_enabled: bool = False):\n        workflow_step = session.query(IterationWorkflowStep).filter(IterationWorkflowStep.unique_id == unique_id).first()\n        if workflow_step is None:\n            workflow_step = IterationWorkflowStep(unique_id=unique_id)\n            session.add(workflow_step)\n            session.commit()\n\n        workflow_step.prompt = prompt\n        workflow_step.variables = variables\n        workflow_step.step_type = step_type\n        workflow_step.output_type = output_type\n        workflow_step.iteration_workflow_id = iteration_workflow_id\n        workflow_step.next_step_id = -1\n        workflow_step.history_enabled = history_enabled\n        if completion_prompt:\n            workflow_step.completion_prompt = completion_prompt\n        session.commit()\n        return workflow_step\n\n\n\n"
  },
  {
    "path": "superagi/resource_manager/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/resource_manager/file_manager.py",
    "content": "import csv\nfrom sqlalchemy.orm import Session\nfrom superagi.config.config import get_config\nimport os\nfrom superagi.helper.resource_helper import ResourceHelper\nfrom superagi.helper.s3_helper import S3Helper\nfrom superagi.lib.logger import logger\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.types.storage_types import StorageType\nclass FileManager:\n    def __init__(self, session: Session, agent_id: int = None, agent_execution_id: int = None):\n        self.session = session\n        self.agent_id = agent_id\n        self.agent_execution_id = agent_execution_id\n    def write_binary_file(self, file_name: str, data):\n        if self.agent_id is not None:\n            final_path = ResourceHelper.get_agent_write_resource_path(file_name,\n                                                                      Agent.get_agent_from_id(self.session,\n                                                                                              self.agent_id),\n                                                                      AgentExecution.get_agent_execution_from_id(\n                                                                          self.session,\n                                                                          self.agent_execution_id))\n        else:\n            final_path = ResourceHelper.get_resource_path(file_name)\n        try:\n            with open(final_path, mode=\"wb\") as img:\n                img.write(data)\n                img.close()\n            self.write_to_s3(file_name, final_path)\n            logger.info(f\"Binary {file_name} saved successfully\")\n            return f\"Binary {file_name} saved successfully\"\n        except Exception as err:\n            return f\"Error write_binary_file: {err}\"\n    def write_to_s3(self, file_name, final_path):\n        with open(final_path, 'rb') as img:\n            resource = ResourceHelper.make_written_file_resource(file_name=file_name,\n                                                                 agent=Agent.get_agent_from_id(self.session,\n                                                                                               self.agent_id),\n                                                                 agent_execution=AgentExecution\n                                                                 .get_agent_execution_from_id(self.session,\n                                                                                              self.agent_execution_id),\n                                                                 session=self.session)\n            if resource.storage_type == StorageType.S3.value:\n                s3_helper = S3Helper()\n                s3_helper.upload_file(img, path=resource.path)\n\n    def write_file(self, file_name: str, content):\n        if self.agent_id is not None:\n            final_path = ResourceHelper.get_agent_write_resource_path(file_name,\n                                                                      agent=Agent.get_agent_from_id(self.session,\n                                                                                                    self.agent_id),\n                                                                      agent_execution=AgentExecution\n                                                                      .get_agent_execution_from_id(self.session,\n                                                                                                   self.agent_execution_id))\n        else:\n            final_path = ResourceHelper.get_resource_path(file_name)\n        try:\n            with open(final_path, mode=\"w\") as file:\n                file.write(content)\n                file.close()\n            self.write_to_s3(file_name, final_path)\n            logger.info(f\"{file_name} - File written successfully\")\n            return f\"{file_name} - File written successfully\"\n        except Exception as err:\n            return f\"Error write_file: {err}\"\n    def write_csv_file(self, file_name: str, csv_data):\n        if self.agent_id is not None:\n            final_path = ResourceHelper.get_agent_write_resource_path(file_name,\n                                                                      agent=Agent.get_agent_from_id(self.session,\n                                                                                                    self.agent_id),\n                                                                      agent_execution=AgentExecution\n                                                                      .get_agent_execution_from_id(self.session,\n                                                                                                   self.agent_execution_id))\n        else:\n            final_path = ResourceHelper.get_resource_path(file_name)\n        try:\n            with open(final_path, mode=\"w\", newline=\"\") as file:\n                writer = csv.writer(file, lineterminator=\"\\n\")\n                writer.writerows(csv_data)\n            self.write_to_s3(file_name, final_path)\n            logger.info(f\"{file_name} - File written successfully\")\n            return f\"{file_name} - File written successfully\"\n        except Exception as err:\n            return f\"Error write_csv_file: {err}\"\n        \n\n    def get_agent_resource_path(self, file_name: str):\n        return ResourceHelper.get_agent_write_resource_path(file_name, agent=Agent.get_agent_from_id(self.session,\n                                                                                                     self.agent_id),\n                                                            agent_execution=AgentExecution\n                                                            .get_agent_execution_from_id(self.session,\n                                                                                         self.agent_execution_id))\n    def read_file(self, file_name: str):\n        if self.agent_id is not None:\n            final_path = self.get_agent_resource_path(file_name)\n        else:\n            final_path = ResourceHelper.get_resource_path(file_name)\n\n        try:\n            with open(final_path, mode=\"r\") as file:\n                content = file.read()\n            logger.info(f\"{file_name} - File read successfully\")\n            return content\n        except Exception as err:\n            return f\"Error while reading file {file_name}: {err}\"\n    def get_files(self):\n        \"\"\"\n        Gets all file names generated by the CodingTool.\n        Returns:\n            A list of file names.\n        \"\"\"\n        \n        if self.agent_id is not None:\n            final_path = self.get_agent_resource_path(\"\")\n        else:\n            final_path = ResourceHelper.get_resource_path(\"\")\n        try:\n            # List all files in the directory\n            files = os.listdir(final_path)\n        except Exception as err:\n            logger.error(f\"Error while accessing files in {final_path}: {err}\")\n            files = []\n        return files\n"
  },
  {
    "path": "superagi/resource_manager/llama_document_summary.py",
    "content": "import os\n\nfrom llama_index.indices.response import ResponseMode\nfrom llama_index.schema import Document\n\nfrom superagi.config.config import get_config\n\n\nclass LlamaDocumentSummary:\n    def __init__(self, model_name=get_config(\"RESOURCES_SUMMARY_MODEL_NAME\", \"gpt-3.5-turbo\"), model_source=\"OpenAi\", model_api_key: str = None):\n        self.model_name = model_name\n        self.model_api_key = model_api_key\n        self.model_source = model_source\n\n    def generate_summary_of_document(self, documents: list[Document]):\n        \"\"\"\n        Generates summary of the documents\n\n        :param documents: list of Document objects\n        :return: summary of the documents\n        \"\"\"\n        if documents is None or not documents:\n            return\n        from llama_index import LLMPredictor, ServiceContext, ResponseSynthesizer, DocumentSummaryIndex\n        os.environ[\"OPENAI_API_KEY\"] = get_config(\"OPENAI_API_KEY\", \"\") or self.model_api_key\n        llm_predictor_chatgpt = LLMPredictor(llm=self._build_llm())\n        service_context = ServiceContext.from_defaults(llm_predictor=llm_predictor_chatgpt, chunk_size=1024)\n        response_synthesizer = ResponseSynthesizer.from_args(response_mode=ResponseMode.TREE_SUMMARIZE, use_async=True)\n        doc_summary_index = DocumentSummaryIndex.from_documents(\n            documents=documents,\n            service_context=service_context,\n            response_synthesizer=response_synthesizer\n        )\n\n        return doc_summary_index.get_document_summary(documents[0].doc_id)\n\n    def generate_summary_of_texts(self, texts: list[str]):\n        \"\"\"\n        Generates summary of the texts\n\n        :param texts: list of texts\n        :return: summary of the texts\n        \"\"\"\n        from llama_index import Document\n        if texts is not None and len(texts) > 0:\n            documents = [Document(doc_id=f\"doc_id_{i}\", text=text) for i, text in enumerate(texts)]\n            return self.generate_summary_of_document(documents)\n        raise ValueError(\"texts must be provided\")\n\n    def _build_llm(self):\n        \"\"\"\n        Builds the LLM model\n\n        :return: LLM model object\n        \"\"\"\n        open_ai_models = ['gpt-4', 'gpt-3.5-turbo', 'gpt-3.5-turbo-16k', 'gpt-4-32k']\n        if self.model_name in open_ai_models:\n            from langchain.chat_models import ChatOpenAI\n\n            openai_api_key = get_config(\"OPENAI_API_KEY\") or self.model_api_key\n            return ChatOpenAI(temperature=0, model_name=self.model_name,\n                              openai_api_key=openai_api_key)\n\n        raise Exception(f\"Model name {self.model_name} not supported for document summary\")\n"
  },
  {
    "path": "superagi/resource_manager/llama_vector_store_factory.py",
    "content": "from llama_index.vector_stores.types import VectorStore\n\nfrom superagi.config.config import get_config\nfrom superagi.types.vector_store_types import VectorStoreType\n\n\nclass LlamaVectorStoreFactory:\n    \"\"\"\n    Factory class to create vector stores based on the vector_store_name\n\n    :param vector_store_name: VectorStoreType\n    :param index_name: str\n\n    :return: VectorStore object\n    \"\"\"\n    def __init__(self, vector_store_name: VectorStoreType, index_name: str):\n        self.vector_store_name = vector_store_name\n        self.index_name = index_name\n\n    def get_vector_store(self) -> VectorStore:\n        \"\"\"\n        Returns the vector store based on the vector_store_name\n\n        :return: VectorStore object\n        \"\"\"\n        if self.vector_store_name == VectorStoreType.PINECONE:\n            from llama_index.vector_stores import PineconeVectorStore\n            return PineconeVectorStore(self.index_name)\n\n        if self.vector_store_name == VectorStoreType.REDIS:\n            redis_url = get_config(\"REDIS_VECTOR_STORE_URL\") or \"redis://super__redis:6379\"\n            from llama_index.vector_stores import RedisVectorStore\n            return RedisVectorStore(\n                index_name=self.index_name,\n                redis_url=redis_url,\n                metadata_fields=[\"agent_id\", \"resource_id\"]\n            )\n\n        if self.vector_store_name == VectorStoreType.CHROMA:\n            from llama_index.vector_stores import ChromaVectorStore\n            import chromadb\n            from chromadb.config import Settings\n            chroma_host_name = get_config(\"CHROMA_HOST_NAME\") or \"localhost\"\n            chroma_port = get_config(\"CHROMA_PORT\") or 8000\n            chroma_client = chromadb.Client(\n                Settings(chroma_api_impl=\"rest\", chroma_server_host=chroma_host_name,\n                         chroma_server_http_port=chroma_port))\n            chroma_collection = chroma_client.get_or_create_collection(self.index_name)\n            return ChromaVectorStore(chroma_collection)\n\n        if self.vector_store_name == VectorStoreType.QDRANT:\n            from llama_index.vector_stores import QdrantVectorStore\n            qdrant_host_name = get_config(\"QDRANT_HOST_NAME\") or \"localhost\"\n            qdrant_port = get_config(\"QDRANT_PORT\") or 6333\n            from qdrant_client import QdrantClient\n            qdrant_client = QdrantClient(host=qdrant_host_name, port=qdrant_port)\n            return QdrantVectorStore(client=qdrant_client, collection_name=self.index_name)\n\n        raise ValueError(str(self.vector_store_name) + \" vector store is not supported yet.\")\n"
  },
  {
    "path": "superagi/resource_manager/resource_manager.py",
    "content": "import os\n\nfrom llama_index import SimpleDirectoryReader\nfrom sqlalchemy.orm import Session\n\nfrom superagi.config.config import get_config\nfrom superagi.helper.resource_helper import ResourceHelper\nfrom superagi.lib.logger import logger\nfrom superagi.resource_manager.llama_vector_store_factory import LlamaVectorStoreFactory\nfrom superagi.types.model_source_types import ModelSourceType\nfrom superagi.types.vector_store_types import VectorStoreType\nfrom superagi.models.agent import Agent\n\n\nclass ResourceManager:\n    \"\"\"\n    Resource Manager handles creation of resources and saving them to the vector store.\n\n    :param agent_id: The agent id to use when saving resources to the vector store.\n    \"\"\"\n\n    def __init__(self, agent_id: str = None):\n        self.agent_id = agent_id\n\n    def create_llama_document(self, file_path: str):\n        \"\"\"\n        Creates a document index from a given file path.\n\n        :param file_path: The file path to create the document index from.\n        :return: A list of documents.\n        \"\"\"\n        if file_path is None:\n            raise Exception(\"file_path must be provided\")\n        if os.path.exists(file_path):\n            documents = SimpleDirectoryReader(input_files=[file_path]).load_data()\n            return documents\n\n    def create_llama_document_s3(self, file_path: str):\n        \"\"\"\n        Creates a document index from a given file path.\n\n        :param file_path: The file path to create the document index from.\n        :return: A list of documents.\n        \"\"\"\n        if file_path is None:\n            raise Exception(\"file_path must be provided\")\n        temporary_file_path = \"\"\n        try:\n            import boto3\n            s3 = boto3.client(\n                's3',\n                aws_access_key_id=get_config(\"AWS_ACCESS_KEY_ID\"),\n                aws_secret_access_key=get_config(\"AWS_SECRET_ACCESS_KEY\"),\n            )\n            bucket_name = get_config(\"BUCKET_NAME\")\n            file = s3.get_object(Bucket=bucket_name, Key=file_path)\n            file_name = file_path.split(\"/\")[-1]\n            save_directory = \"/\"\n            temporary_file_path = save_directory + file_name\n            with open(temporary_file_path, \"wb\") as f:\n                contents = file['Body'].read()\n                f.write(contents)\n\n            documents = SimpleDirectoryReader(input_files=[temporary_file_path]).load_data()\n            return documents\n        except Exception as e:\n            logger.error(\"superagi/resource_manager/resource_manager.py - create_llama_document_s3 threw : \", e)\n        finally:\n            if os.path.exists(temporary_file_path):\n                os.remove(temporary_file_path)\n\n    def save_document_to_vector_store(self, documents: list, resource_id: str, mode_api_key: str = None,\n                                      model_source: str = \"\"):\n        \"\"\"\n        Saves a document to the vector store.\n\n        :param documents: The documents to save to the vector store.\n        :param resource_id: The resource id to use when saving the documents to the vector store.\n        :param mode_api_key: The mode api key to use when creating embedding to the vector store.\n        \"\"\"\n        from llama_index import VectorStoreIndex, StorageContext\n        if ModelSourceType.GooglePalm.value in model_source or ModelSourceType.Replicate.value in model_source:\n            logger.info(\"Resource embedding not supported for Google Palm..\")\n            return\n        import openai\n        openai.api_key = get_config(\"OPENAI_API_KEY\") or mode_api_key\n        os.environ[\"OPENAI_API_KEY\"] = get_config(\"OPENAI_API_KEY\", \"\") or mode_api_key\n        for docs in documents:\n            if docs.metadata is None:\n                docs.metadata = {}\n            docs.metadata[\"agent_id\"] = str(self.agent_id)\n            docs.metadata[\"resource_id\"] = resource_id\n        vector_store = None\n        storage_context = None\n        vector_store_name = VectorStoreType.get_vector_store_type(get_config(\"RESOURCE_VECTOR_STORE\") or \"Redis\")\n        vector_store_index_name = get_config(\"RESOURCE_VECTOR_STORE_INDEX_NAME\") or \"super-agent-index\"\n        try:\n            vector_store = LlamaVectorStoreFactory(vector_store_name, vector_store_index_name).get_vector_store()\n            storage_context = StorageContext.from_defaults(vector_store=vector_store)\n        except ValueError as e:\n            logger.error(f\"Vector store not found{e}\")\n        try:\n            index = VectorStoreIndex.from_documents(documents, storage_context=storage_context)\n            index.set_index_id(f'Agent {self.agent_id}')\n        except Exception as e:\n            logger.error(\"save_document_to_vector_store - unable to create documents from vector\", e)\n        # persisting the data in case of redis\n        if vector_store_name == VectorStoreType.REDIS:\n            vector_store.persist(persist_path=\"\")\n"
  },
  {
    "path": "superagi/resource_manager/resource_summary.py",
    "content": "from datetime import datetime\nimport logging\nfrom superagi.lib.logger import logger\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.models.configuration import Configuration\nfrom superagi.models.resource import Resource\nfrom superagi.resource_manager.llama_document_summary import LlamaDocumentSummary\nfrom superagi.resource_manager.resource_manager import ResourceManager\nfrom superagi.types.model_source_types import ModelSourceType\n\n\nclass ResourceSummarizer:\n    \"\"\"Class to summarize a resource.\"\"\"\n\n    def __init__(self, session, agent_id: int, model: str):\n        self.session = session\n        self.agent_id = agent_id\n        self.organisation_id = self.__get_organisation_id()\n        self.model = model\n\n    def __get_organisation_id(self):\n        agent = self.session.query(Agent).filter(Agent.id == self.agent_id).first()\n        organisation = agent.get_agent_organisation(self.session)\n        return organisation.id\n\n    def __get_model_api_key(self):\n        return Configuration.fetch_configurations(self.session, self.organisation_id, \"model_api_key\", self.model)\n\n    def __get_model_source(self):\n        return Configuration.fetch_configurations(self.session, self.organisation_id, \"model_source\", self.model)\n\n    def add_to_vector_store_and_create_summary(self, resource_id: int, documents: list):\n        \"\"\"\n        Add a file to the vector store and generate a summary for it.\n\n        Args:\n            agent_id (str): ID of the agent.\n            resource_id (int): ID of the resource.\n            openai_api_key (str): OpenAI API key.\n            documents (list): List of documents.\n        \"\"\"\n        model_api_key = self.__get_model_api_key()\n        try:\n            ResourceManager(str(self.agent_id)).save_document_to_vector_store(documents, str(resource_id), model_api_key,\n                                                                         self.__get_model_source())\n        except Exception as e:\n            logger.error(\"add_to_vector_store_and_create_summary: Unable to save document to vector store.\", e)\n\n    def generate_agent_summary(self, generate_all: bool = False) -> str:\n        \"\"\"Generate a summary of all resources for an agent.\"\"\"\n        agent_config_resource_summary = self.session.query(AgentConfiguration). \\\n            filter(AgentConfiguration.agent_id == self.agent_id,\n                   AgentConfiguration.key == \"resource_summary\").first()\n        resources = self.session.query(Resource).filter(Resource.agent_id == self.agent_id,\n                                                        Resource.channel == 'INPUT').all()\n        if not resources:\n            return\n\n        resource_summary = \" \".join([resource.name for resource in resources])\n        agent_last_resource = self.session.query(AgentConfiguration). \\\n            filter(AgentConfiguration.agent_id == self.agent_id,\n                   AgentConfiguration.key == \"last_resource_time\").first()\n\n\n        if agent_config_resource_summary is not None:\n            agent_config_resource_summary.value = resource_summary\n        else:\n            agent_config_resource_summary = AgentConfiguration(agent_id=self.agent_id, key=\"resource_summary\",\n                                                               value=resource_summary)\n            self.session.add(agent_config_resource_summary)\n        if agent_last_resource is not None:\n            agent_last_resource.value = str(resources[-1].updated_at)\n        else:\n            agent_last_resource = AgentConfiguration(agent_id=self.agent_id, key=\"last_resource_time\",\n                                                     value=str(resources[-1].updated_at))\n            self.session.add(agent_last_resource)\n        self.session.commit()\n\n    def fetch_or_create_agent_resource_summary(self, default_summary: str):\n        print(self.__get_model_source())\n        if ModelSourceType.GooglePalm.value in self.__get_model_source():\n            return\n        self.generate_agent_summary(generate_all=True)\n        agent_config_resource_summary = self.session.query(AgentConfiguration). \\\n            filter(AgentConfiguration.agent_id == self.agent_id,\n                   AgentConfiguration.key == \"resource_summary\").first()\n        resource_summary = agent_config_resource_summary.value if agent_config_resource_summary is not None else default_summary\n        return resource_summary\n\n"
  },
  {
    "path": "superagi/tool_manager.py",
    "content": "import os\nfrom pathlib import Path\n\nimport requests\nimport zipfile\nimport json\n\n\ndef parse_github_url(github_url):\n    parts = github_url.split('/')\n    owner = parts[3]\n    repo = parts[4]\n    branch = \"main\"\n    return f\"{owner}/{repo}/{branch}\"\n\n\ndef download_tool(tool_url, target_folder):\n    parsed_url = parse_github_url(tool_url)\n    parts = parsed_url.split(\"/\")\n    owner, repo, branch, path = parts[0], parts[1], parts[2], \"/\".join(parts[3:])\n    archive_url = f\"https://api.github.com/repos/{owner}/{repo}/zipball/{branch}\"\n\n    response = requests.get(archive_url)\n\n    tool_zip_file_path = os.path.join(target_folder, 'tool.zip')\n\n    with open(tool_zip_file_path, 'wb') as f:\n        f.write(response.content)\n\n    with zipfile.ZipFile(tool_zip_file_path, 'r') as z:\n        members = [m for m in z.namelist() if m.startswith(f\"{owner}-{repo}\") and f\"{path}\" in m]\n        for member in members:\n            archive_folder = f\"{owner}-{repo}\"\n            target_name = member.replace(f\"{archive_folder}/\", \"\", 1)\n            # Skip the unique hash folder while extracting:\n            segments = target_name.split('/', 1)\n            if len(segments) > 1:\n                target_name = segments[1]\n            else:\n                continue\n            target_path = os.path.join(target_folder, target_name)\n            if not target_name:\n                continue\n            if member.endswith('/'):\n                os.makedirs(target_path, exist_ok=True)\n            else:\n                with open(target_path, 'wb') as outfile, z.open(member) as infile:\n                    outfile.write(infile.read())\n\n    os.remove(tool_zip_file_path)\n\n\ndef download_marketplace_tool(tool_url, target_folder):\n    parsed_url = tool_url.split(\"/\")\n    owner, repo = parsed_url[3], parsed_url[4]\n    archive_url = f\"https://api.github.com/repos/{owner}/{repo}/zipball/main\"\n    response = requests.get(archive_url)\n    tool_zip_file_path = os.path.join(target_folder, 'tool.zip')\n\n    with open(tool_zip_file_path, 'wb') as f:\n        f.write(response.content)\n\n    with zipfile.ZipFile(tool_zip_file_path, 'r') as z:\n        for member in z.namelist():\n            archive_folder, target_name = member.split('/', 1)\n            target_name = os.path.join(target_folder, target_name)\n            if member.endswith('/'):\n                os.makedirs(target_name, exist_ok=True)\n            elif not target_name.endswith('.md'):\n                with open(target_name, 'wb') as outfile, z.open(member) as infile:\n                    outfile.write(infile.read())\n\n    os.remove(tool_zip_file_path)\n\n\ndef get_marketplace_tool_links(repo_url):\n    folder_links = {}\n    api_url = f\"https://api.github.com/repos/{repo_url}/contents\"\n    response = requests.get(api_url)\n    contents = response.json()\n\n    for content in contents:\n        if content[\"type\"] == \"dir\":\n            folder_name = content[\"name\"]\n            folder_link = f\"https://github.com/{repo_url}/tree/main/{folder_name}\"\n            folder_links[folder_name] = folder_link\n\n    return folder_links\n\n\ndef update_tools_json(existing_tools_json_path, folder_links):\n    with open(existing_tools_json_path, \"r\") as file:\n        tools_data = json.load(file)\n    if \"tools\" not in tools_data:\n        tools_data[\"tools\"] = {}\n    tools_data[\"tools\"].update(folder_links)\n    with open(existing_tools_json_path, \"w\") as file:\n        json.dump(tools_data, file, indent=4)\n\n\ndef load_tools_config():\n    tool_config_path = str(Path(__file__).parent.parent)\n    with open(tool_config_path + \"/tools.json\", \"r\") as f:\n        config = json.load(f)\n        return config[\"tools\"]\n\n\ndef load_marketplace_tools():\n    marketplace_url = \"TransformerOptimus/SuperAGI-Tools\"\n    tools_config_path = str(Path(__file__).parent.parent)\n    tools_json_path = tools_config_path + \"/tools.json\"\n    # Get folder links from the repository\n    marketplace_tool_urls = get_marketplace_tool_links(marketplace_url)\n    # Update existing tools.json file\n    update_tools_json(tools_json_path, marketplace_tool_urls)\n\n\ndef is_marketplace_url(url):\n    return url.startswith(\"https://github.com/TransformerOptimus/SuperAGI-Tools/tree\")\n\ndef download_and_extract_tools():\n    tools_config = load_tools_config()\n\n    for tool_name, tool_url in tools_config.items():\n        if is_marketplace_url(tool_url):\n            tool_folder = os.path.join(\"superagi/tools/marketplace_tools\")\n            if not os.path.exists(tool_folder):\n                os.makedirs(tool_folder)\n            download_marketplace_tool(tool_url, tool_folder)\n        else:\n            tool_folder = os.path.join(\"superagi/tools/external_tools\", tool_name)\n            if not os.path.exists(tool_folder):\n                os.makedirs(tool_folder)\n            download_tool(tool_url, tool_folder)\n\n\nif __name__ == \"__main__\":\n    load_marketplace_tools()\n    download_and_extract_tools()\n"
  },
  {
    "path": "superagi/tools/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/tools/apollo/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/tools/apollo/apollo_search.py",
    "content": "import json\nfrom typing import Type\n\nimport requests\nfrom pydantic import BaseModel, Field\n\nfrom superagi.lib.logger import logger\nfrom superagi.tools.base_tool import BaseTool\n\n\nclass ApolloSearchSchema(BaseModel):\n    person_titles: list[str] = Field(\n        ...,\n        description=\"The titles of the people to search for.\",\n    )\n    page: int = Field(\n        1,\n        description=\"The page of results to retrieve. Default value is 1.\",\n    )\n    per_page: int = Field(\n        25,\n        description=\"The number of results to retrieve per page. Default value is 25.\",\n    )\n    num_of_employees: list[int] = Field(\n        [],\n        description=\"The number of employees to filter by in format [start_range, end_range]. Default value is empty array.\",\n    )\n    organization_domains: str = Field(\n        \"\",\n        description=\"The organization domains to search within. It is optional field.\",\n    )\n    person_location: str = Field(\n        \"\",\n        description=\"Region country/state/city filter to search for. It is optional field.\",\n    )\n\n\nclass ApolloSearchTool(BaseTool):\n    \"\"\"\n    Apollo Search tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    name = \"ApolloSearch\"\n    description = (\n        \"A tool for performing a Apollo search and extracting people data.\"\n        \"Input should include API key, organization domains, page number, and person titles.\"\n    )\n    args_schema: Type[BaseModel] = ApolloSearchSchema\n\n    class Config:\n        arbitrary_types_allowed = True\n\n    def _execute(self, person_titles: list[str], page: int = 1, per_page: int = 25, num_of_employees: list[int] = [],\n                 person_location: str = \"\", organization_domains: str = \"\") -> str:\n        \"\"\"\n        Execute the Apollo search tool.\n\n        Args:\n            person_titles : The titles of the people to search for.\n            page : The page of results to retrieve.\n            num_of_employees : The number of employees to filter by in format [start_range, end_range]. It is optional.\n            person_location : Region country/state/city filter to search for. It is optional.\n            organization_domains : The organization domains to search within.\n\n        Returns:\n            People data from the Apollo search.\n        \"\"\"\n        people_data = self.apollo_search_results(page, per_page, person_titles,\n                                                 num_of_employees, person_location, organization_domains)\n        logger.info(people_data)\n        people_list = []\n        if people_data and 'people' in people_data and len(people_data['people']) > 0:\n            for person in people_data['people']:\n                people_list.append({'first_name': person['first_name'],\n                                    'last_name': person['last_name'],\n                                    'name': person['name'],\n                                    'linkedin_url': person['linkedin_url'],\n                                    'email': person['email'],\n                                    'headline': person['headline'],\n                                    'title': person['title'],\n                                    })\n\n        return people_list\n\n    def apollo_search_results(self, page, per_page, person_titles, num_of_employees = [],\n                              person_location = \"\", organization_domains = \"\"):\n        \"\"\"\n        Execute the Apollo search tool.\n\n        Args:\n            page : The page of results to retrieve.\n            person_titles : The titles of the people to search for.\n            num_of_employees : The number of employees to filter by in format [start_range, end_range]. It is optional.\n            person_location: Region country/state/city filter to search for. It is optional.\n\n        Returns:\n            People data from the Apollo search.\n        \"\"\"\n        url = \"https://api.apollo.io/v1/mixed_people/search\"\n        headers = {\n            \"Content-Type\": \"application/json\",\n            \"Cache-Control\": \"no-cache\"\n        }\n        data = {\n            \"api_key\": self.get_tool_config(\"APOLLO_SEARCH_KEY\"),\n            \"page\": page,\n            \"per_page\": per_page,\n            \"person_titles\": person_titles,\n            \"contact_email_status\": [\"verified\"]\n        }\n\n        if organization_domains:\n            data[\"q_organization_domains\"] = organization_domains\n\n        if num_of_employees:\n            if num_of_employees[1] == num_of_employees[0]:\n                data[\"num_of_employees\"] = [str(num_of_employees[0]) + \",\"]\n            else:\n                data[\"num_of_employees\"] = [str(num_of_employees[0]) + \",\"+ str(num_of_employees[1])]\n        if person_location:\n            data[\"person_locations\"] = [person_location]\n\n        response = requests.post(url, headers=headers, data=json.dumps(data))\n        print(response)\n        if response.status_code == 200:\n            return response.json()\n        else:\n            return None\n\n"
  },
  {
    "path": "superagi/tools/apollo/apollo_toolkit.py",
    "content": "from abc import ABC\nfrom typing import List\n\nfrom superagi.tools.apollo.apollo_search import ApolloSearchTool\nfrom superagi.tools.base_tool import BaseToolkit, BaseTool, ToolConfiguration\nfrom superagi.types.key_type import ToolConfigKeyType\n\n\nclass ApolloToolkit(BaseToolkit, ABC):\n    name: str = \"ApolloToolkit\"\n    description: str = \"Apollo Tool kit contains all tools related to apollo.io tasks\"\n\n    def get_tools(self) -> List[BaseTool]:\n        return [ApolloSearchTool()]\n\n    def get_env_keys(self) -> List[str]:\n        return [ToolConfiguration(key=\"APOLLO_SEARCH_KEY\", key_type=ToolConfigKeyType.STRING, is_required=True)]\n"
  },
  {
    "path": "superagi/tools/base_tool.py",
    "content": "from abc import abstractmethod\nfrom functools import wraps\nfrom inspect import signature\nfrom typing import List\nfrom typing import Optional, Type, Callable, Any, Union, Dict, Tuple\nimport yaml\nfrom pydantic import BaseModel, create_model, validate_arguments, Extra\nfrom superagi.models.tool_config import ToolConfig\nfrom sqlalchemy import Column, Integer, String, Boolean\nfrom superagi.types.key_type import ToolConfigKeyType\n\n\nfrom superagi.config.config import get_config\n\n\nclass SchemaSettings:\n    \"\"\"Configuration for the pydantic model.\"\"\"\n    extra = Extra.forbid\n    arbitrary_types_allowed = True\n\n\ndef extract_valid_parameters(\n        inferred_type: Type[BaseModel],\n        function: Callable,\n) -> dict:\n    \"\"\"Get the arguments from a function's signature.\"\"\"\n    schema = inferred_type.schema()[\"properties\"]\n    valid_params = signature(function).parameters\n    return {param: schema[param] for param in valid_params if param != \"run_manager\"}\n\n\ndef _construct_model_subset(\n        model_name: str, original_model: BaseModel, required_fields: list\n) -> Type[BaseModel]:\n    \"\"\"Create a pydantic model with only a subset of model's fields.\"\"\"\n    fields = {\n        field: (\n            original_model.__fields__[field].type_,\n            original_model.__fields__[field].default,\n        )\n        for field in required_fields\n        if field in original_model.__fields__\n    }\n    return create_model(model_name, **fields)  # type: ignore\n\n\ndef create_function_schema(\n        schema_name: str,\n        function: Callable,\n) -> Type[BaseModel]:\n    \"\"\"Create a pydantic schema from a function's signature.\"\"\"\n    validated = validate_arguments(function, config=SchemaSettings)  # type: ignore\n    inferred_type = validated.model  # type: ignore\n    if \"run_manager\" in inferred_type.__fields__:\n        del inferred_type.__fields__[\"run_manager\"]\n    valid_parameters = extract_valid_parameters(inferred_type, function)\n    return _construct_model_subset(\n        f\"{schema_name}Schema\", inferred_type, list(valid_parameters)\n    )\n\n\nclass BaseToolkitConfiguration:\n\n    def __init__(self):\n        self.session = None\n\n    def get_tool_config(self, key: str):\n        # Default implementation of the tool configuration retrieval logic\n        with open(\"config.yaml\") as file:\n            config = yaml.safe_load(file)\n\n        # Retrieve the value associated with the given key\n        return config.get(key)\n\n\nclass BaseTool(BaseModel):\n    name: str = None\n    description: str\n    args_schema: Type[BaseModel] = None\n    permission_required: bool = True\n    toolkit_config: BaseToolkitConfiguration = BaseToolkitConfiguration()\n\n    class Config:\n        arbitrary_types_allowed = True\n\n    @property\n    def args(self):\n        if self.args_schema is not None:\n            return self.args_schema.schema()[\"properties\"]\n        else:\n            name = self.name\n            args_schema = create_function_schema(f\"{name}Schema\", self.execute)\n            return args_schema.schema()[\"properties\"]\n\n    @abstractmethod\n    def _execute(self, *args: Any, **kwargs: Any):\n        pass\n\n    @property\n    def max_token_limit(self):\n        return int(get_config(\"MAX_TOOL_TOKEN_LIMIT\", 600))\n\n    def _parse_input(\n            self,\n            tool_input: Union[str, Dict],\n    ) -> Union[str, Dict[str, Any]]:\n        \"\"\"Convert tool input to pydantic model.\"\"\"\n        input_args = self.args_schema\n        if isinstance(tool_input, str):\n            if input_args is not None:\n                key_ = next(iter(input_args.__fields__.keys()))\n                input_args.validate({key_: tool_input})\n            return tool_input\n        else:\n            if input_args is not None:\n                result = input_args.parse_obj(tool_input)\n                return {k: v for k, v in result.dict().items() if k in tool_input}\n        return tool_input\n\n    def _to_args_and_kwargs(self, tool_input: Union[str, Dict]) -> Tuple[Tuple, Dict]:\n        # For backwards compatibility, if run_input is a string,\n        # pass as a positional argument.\n        if isinstance(tool_input, str):\n            return (tool_input,), {}\n        else:\n            return (), tool_input\n\n    def execute(\n            self,\n            tool_input: Union[str, Dict],\n            **kwargs: Any\n    ) -> Any:\n        \"\"\"Run the tool.\"\"\"\n        parsed_input = self._parse_input(tool_input)\n\n        try:\n            tool_args, tool_kwargs = self._to_args_and_kwargs(parsed_input)\n            observation = (\n                self._execute(*tool_args, **tool_kwargs)\n            )\n        except (Exception, KeyboardInterrupt) as e:\n            raise e\n        return observation\n\n    @classmethod\n    def from_function(cls, func: Callable, args_schema: Type[BaseModel] = None):\n        if args_schema:\n            return cls(description=func.__doc__, args_schema=args_schema)\n        else:\n            return cls(description=func.__doc__)\n\n    def get_tool_config(self, key):\n        return self.toolkit_config.get_tool_config(key=key)\n\n\nclass FunctionalTool(BaseTool):\n    name: str = None\n    description: str\n    func: Callable\n    args_schema: Type[BaseModel] = None\n\n    @property\n    def args(self):\n        if self.args_schema is not None:\n            return self.args_schema.schema()[\"properties\"]\n        else:\n            name = self.name\n            args_schema = create_function_schema(f\"{name}Schema\", self.execute)\n            return args_schema.schema()[\"properties\"]\n\n    def _execute(self, *args: Any, **kwargs: Any):\n        return self.func(*args, kwargs)\n\n    @classmethod\n    def from_function(cls, func: Callable, args_schema: Type[BaseModel] = None):\n        if args_schema:\n            return cls(description=func.__doc__, args_schema=args_schema)\n        else:\n            return cls(description=func.__doc__)\n\n    def registerTool(cls):\n        cls.__registerTool__ = True\n        return cls\n\n\ndef tool(*args: Union[str, Callable], return_direct: bool = False,\n         args_schema: Optional[Type[BaseModel]] = None) -> Callable:\n    def decorator(func: Callable) -> Callable:\n        nonlocal args_schema\n\n        tool_instance = FunctionalTool.from_function(func, args_schema)\n\n        @wraps(func)\n        def wrapper(*tool_args, **tool_kwargs):\n            if return_direct:\n                return tool_instance._exec(*tool_args, **tool_kwargs)\n            else:\n                return tool_instance\n\n        return wrapper\n\n    if len(args) == 1 and callable(args[0]):\n        return decorator(args[0])\n    else:\n        return decorator\n    \nclass ToolConfiguration:\n\n    def __init__(self, key: str, key_type: str = None, is_required: bool = False, is_secret: bool = False):\n        self.key = key\n        if is_secret is None:\n            self.is_secret = False\n        elif isinstance(is_secret, bool):\n            self.is_secret = is_secret\n        else:\n            raise ValueError(\"is_secret should be a boolean value\")\n        if is_required is None:\n            self.is_required = False\n        elif isinstance(is_required, bool):\n            self.is_required = is_required\n        else:\n            raise ValueError(\"is_required should be a boolean value\")\n        \n        if key_type is None:\n            self.key_type = ToolConfigKeyType.STRING\n        elif isinstance(key_type,ToolConfigKeyType):\n            self.key_type = key_type\n        else:\n            raise ValueError(\"key_type should be string/file/integer\")\n\n\nclass BaseToolkit(BaseModel):\n    name: str\n    description: str\n\n    @abstractmethod\n    def get_tools(self) -> List[BaseTool]:\n        # Add file related tools object here\n        pass\n\n    @abstractmethod\n    def get_env_keys(self) -> List[str]:\n        # Add file related config keys here\n        pass\n"
  },
  {
    "path": "superagi/tools/code/README.MD",
    "content": "<p align=center>\n<a href=\"https://superagi.co\"><img src=https://superagi.co/wp-content/uploads/2023/05/SuperAGI_icon.png></a>\n</p>\n\n# SuperAGI Coding Tool\n\nThe robust SuperAGI Coding Tool lets help with their coding tasks like writing, reviewing, refactoring code, fixing bugs, and understanding programming concepts.\n\n## 💡 Features\n1. **Write Code:** With SuperAGI's Coding Tool, writing new code is a streamlined and effortless process, making your programming tasks much simpler.\n\n2. **Review Code:** SuperAGI's Coding Tool allows comprehensive code reviews, ensuring your code maintains quality standards and adheres to best practices.\n\n3. **Refactor Code:** Refactoring your code is a breeze with SuperAGI's Coding Tool, allowing you to improve your code structure without changing its functionality.\n\n4. **Debugging:** The Coding Tool is equipped to identify and fix bugs efficiently, ensuring your code performs as intended.\n\n5. **Concept Explanation:** This feature provides clear explanations for various programming concepts, enhancing your understanding and making complex coding problems easier to solve.\n\n## ⚙️ Installation\n\n### 🛠 **Setting Up of SuperAGI**\nSet up the SuperAGI by following the instructions given (https://github.com/TransformerOptimus/SuperAGI/blob/main/README.MD)\n\nYou'll be able to use the Coding Tool on the fly once you have setup SuperAGI.\n\n## Running SuperAGI Coding Tool\n\nYou can simply ask your agent to read or go through your coding files in the Resource Manager, and it'll be able to do any coding feature as mentioned above.\n"
  },
  {
    "path": "superagi/tools/code/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/tools/code/coding_toolkit.py",
    "content": "from abc import ABC\nfrom typing import List\n\nfrom superagi.tools.base_tool import BaseToolkit, BaseTool, ToolConfiguration\nfrom superagi.tools.code.improve_code import ImproveCodeTool\nfrom superagi.tools.code.write_code import CodingTool\nfrom superagi.tools.code.write_spec import WriteSpecTool\nfrom superagi.tools.code.write_test import WriteTestTool\n\n\nclass CodingToolkit(BaseToolkit, ABC):\n    name: str = \"CodingToolkit\"\n    description: str = \"Coding Tool kit contains all tools related to coding tasks\"\n\n    def get_tools(self) -> List[BaseTool]:\n        return [CodingTool(), WriteSpecTool(), WriteTestTool(), ImproveCodeTool()]\n\n    def get_env_keys(self) -> List[ToolConfiguration]:\n        return []\n"
  },
  {
    "path": "superagi/tools/code/improve_code.py",
    "content": "import re\nfrom typing import Type, Optional, List\n\nfrom pydantic import BaseModel, Field\n\nfrom superagi.agent.agent_prompt_builder import AgentPromptBuilder\nfrom superagi.helper.error_handler import ErrorHandler\nfrom superagi.helper.prompt_reader import PromptReader\nfrom superagi.helper.token_counter import TokenCounter\nfrom superagi.lib.logger import logger\nfrom superagi.llms.base_llm import BaseLlm\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nfrom superagi.resource_manager.file_manager import FileManager\nfrom superagi.tools.base_tool import BaseTool\nfrom superagi.tools.tool_response_query_manager import ToolResponseQueryManager\n\n\nclass ImproveCodeSchema(BaseModel):\n    pass\n\n\nclass ImproveCodeTool(BaseTool):\n    \"\"\"\n    Used to improve the already generated code by reading the code from the files\n\n    Attributes:\n        llm: LLM used for code generation.\n        name : The name of the tool.\n        description : The description of the tool.\n        resource_manager: Manages the file resources.\n    \"\"\"\n    llm: Optional[BaseLlm] = None\n    agent_id: int = None\n    agent_execution_id: int = None\n    name = \"ImproveCodeTool\"\n    description = (\n        \"This tool improves the generated code.\"\n    )\n    args_schema: Type[ImproveCodeSchema] = ImproveCodeSchema\n    resource_manager: Optional[FileManager] = None\n    tool_response_manager: Optional[ToolResponseQueryManager] = None\n    goals: List[str] = []\n\n    class Config:\n        arbitrary_types_allowed = True\n\n    def _execute(self) -> str:\n        \"\"\"\n        Execute the improve code tool.\n\n        Returns:\n            Improved code or error message.\n        \"\"\"\n        # Get all file names that the CodingTool has written\n        file_names = self.resource_manager.get_files()\n        logger.info(file_names)\n        # Loop through each file\n        for file_name in file_names:\n            if '.txt' not in file_name and '.sh' not in file_name and '.json' not in file_name:\n                # Read the file content\n                content = self.resource_manager.read_file(file_name)\n\n                # Generate a prompt from improve_code.txt\n                prompt = PromptReader.read_tools_prompt(__file__, \"improve_code.txt\")\n\n                # Combine the hint from the file, goals, and content\n                prompt = prompt.replace(\"{goals}\", AgentPromptBuilder.add_list_items_to_string(self.goals))\n                prompt = prompt.replace(\"{content}\", content)\n\n                # Add the file content to the chat completion prompt\n                prompt = prompt + \"\\nOriginal Code:\\n```\\n\" + content + \"\\n```\"\n\n\n\n                # Use LLM to generate improved code\n                result = self.llm.chat_completion([{'role': 'system', 'content': prompt}])\n                \n                if result is not None and 'error' in result and result['message'] is not None:\n                   ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message'])\n\n                # Extract the response first\n                response = result.get('response')\n                if not response: \n                    logger.info(\"RESPONSE NOT AVAILABLE\")\n\n                # Now extract the choices from response\n                choices = response.get('choices')\n                if not choices: \n                    logger.info(\"CHOICES NOT AVAILABLE\")\n\n                # Now you can safely extract the message content\n                improved_content = choices[0][\"message\"][\"content\"]\n                # improved_content = result[\"messages\"][0][\"content\"]\n                parsed_content = re.findall(\"```(?:\\w*\\n)?(.*?)```\", improved_content, re.DOTALL)\n                parsed_content_code = \"\\n\".join(parsed_content)\n\n                # Rewrite the file with the improved content\n                save_result = self.resource_manager.write_file(file_name, parsed_content_code)\n\n                if save_result.startswith(\"Error\"):\n                    return save_result\n            else:\n                continue\n\n        return f\"All codes improved and saved successfully in: \" + \" \".join(file_names)"
  },
  {
    "path": "superagi/tools/code/prompts/generate_logic.txt",
    "content": "You typically always place distinct classes in separate files.\nAlways create a run.sh file which act as the entrypoint of the program, create it intellligently after analyzing the file types\nFor Python, always generate a suitable requirements.txt file.\nFor NodeJS, consistently produce an appropriate package.json file.\nAlways include a brief comment that describes the purpose of the function definition.\nAttempt to provide comments that explain complicated logic.\nConsistently adhere to best practices for the specified languages, ensuring code is defined as a package or project.\n\nPreferred Python toolbelt:\n- pytest\n- dataclasses"
  },
  {
    "path": "superagi/tools/code/prompts/improve_code.txt",
    "content": "You are a super smart developer. You have been tasked with fixing and filling the function and classes where only the description of code is written without the actual code . There might be placeholders in the code you have to fill in.\nYou provide fully functioning, well formatted code with few comments, that works and has no bugs.\nIf the code is already correct and doesn't need change, just return the same code\nHowever, make sure that you only return the improved code, without any additional content.\n\n\nPlease structure the improved code as follows:\n\n```\nCODE\n```\n\nPlease return the full new code in same format as the original code\nDon't write any explanation or description in your response other than the actual code\n\nYour high-level goal is:\n{goals}\n\nThe content of the file you need to improve is:\n{content}\n\nOnly return the code and not any other line\n\nTo start, first analyze the existing code. Check for any function with missing logic inside it and fill the function. \nMake sure, that not a single function is empty or contains just comments, there should be function logic inside it\nReturn fully completed functions by filling the placeholders"
  },
  {
    "path": "superagi/tools/code/prompts/write_code.txt",
    "content": "You are a super smart developer who practices good Development for writing code according to a specification.\nPlease note that the code should be fully functional. There should be no placeholder in functions or classes in any file.\n\nYour high-level goal is:\n{goals}\n\nCoding task description:\n{code_description}\n\n{spec}\n\nYou will get instructions for code to write.\nYou need to write a detailed answer. Make sure all parts of the architecture are turned into code.\nThink carefully about each step and make good choices to get it right. First, list the main classes,\nfunctions, methods you'll use and a quick comment on their purpose.\n\nThen you will output the content of each file including ALL code.\nEach file must strictly follow a markdown code block format, where the following tokens must be replaced such that\nFILENAME is the lowercase file name including the file extension,\n[LANG] is the markup code block language for the code's language, and [CODE] is the code:\nFILENAME\n```[LANG]\n[CODE]\n```\n\nYou will start with the \"entrypoint\" file, then go to the ones that are imported by that file, and so on.\n\nFollow a language and framework appropriate best practice file naming convention.\nMake sure that files contain all imports, types etc. Make sure that code in different files are compatible with each other.\nEnsure to implement all code, if you are unsure, write a plausible implementation.\nInclude module dependency or package manager dependency definition file.\nBefore you finish, double check that all parts of the architecture is present in the files."
  },
  {
    "path": "superagi/tools/code/prompts/write_spec.txt",
    "content": "You are a super smart developer who has been asked to make a specification for a program.\n\nYour high-level goal is:\n{goals}\n\nPlease keep in mind the following when creating the specification:\n1. Be super explicit about what the program should do, which features it should have, and give details about anything that might be unclear.\n2. Lay out the names of the core classes, functions, methods that will be necessary, as well as a quick comment on their purpose.\n3. List all non-standard dependencies that will have to be used.\n\nWrite a specification for the following task:\n{task}"
  },
  {
    "path": "superagi/tools/code/prompts/write_test.txt",
    "content": "You are a super smart developer who practices Test Driven Development for writing tests according to a specification.\n\nYour high-level goal is:\n{goals}\n\nTest Description:\n{test_description}\n\n{spec}\n\nTest should follow the following format:\nFILENAME is the lowercase file name including the file extension,\n[LANG] is the markup code block language for the code's language, and [UNIT_TEST_CODE] is the code:\n\nFILENAME\n```[LANG]\n[UNIT_TEST_CODE]\n```\n\nThe tests should be as simple as possible, but still cover all the functionality described in the specification.\n\n"
  },
  {
    "path": "superagi/tools/code/write_code.py",
    "content": "import re\nfrom typing import Type, Optional, List\n\nfrom pydantic import BaseModel, Field\n\nfrom superagi.agent.agent_prompt_builder import AgentPromptBuilder\nfrom superagi.helper.error_handler import ErrorHandler\nfrom superagi.helper.prompt_reader import PromptReader\nfrom superagi.helper.token_counter import TokenCounter\nfrom superagi.lib.logger import logger\nfrom superagi.llms.base_llm import BaseLlm\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nfrom superagi.resource_manager.file_manager import FileManager\nfrom superagi.tools.base_tool import BaseTool\nfrom superagi.tools.tool_response_query_manager import ToolResponseQueryManager\nfrom superagi.models.agent import Agent\n\nclass CodingSchema(BaseModel):\n    code_description: str = Field(\n        ...,\n        description=\"Description of the coding task\",\n    )\n\n\nclass CodingTool(BaseTool):\n    \"\"\"\n    Used to generate code.\n\n    Attributes:\n        llm: LLM used for code generation.\n        name : The name of tool.\n        description : The description of tool.\n        args_schema : The args schema.\n        goals : The goals.\n        resource_manager: Manages the file resources\n    \"\"\"\n    llm: Optional[BaseLlm] = None\n    agent_id: int = None\n    agent_execution_id: int = None\n    name = \"CodingTool\"\n    description = (\n        \"You will get instructions for code to write. You will write a very long answer. \"\n        \"Make sure that every detail of the architecture is, in the end, implemented as code. \"\n        \"Think step by step and reason yourself to the right decisions to make sure we get it right. \"\n        \"You will first lay out the names of the core classes, functions, methods that will be necessary, \"\n        \"as well as a quick comment on their purpose. Then you will output the content of each file including each function and class and ALL code.\"\n    )\n    args_schema: Type[CodingSchema] = CodingSchema\n    goals: List[str] = []\n    resource_manager: Optional[FileManager] = None\n    tool_response_manager: Optional[ToolResponseQueryManager] = None\n\n    class Config:\n        arbitrary_types_allowed = True\n\n    def _execute(self, code_description: str) -> str:\n        \"\"\"\n        Execute the write_code tool.\n\n        Args:\n            code_description : The coding task description.\n            code_file_name: The name of the file where the generated codes will be saved.\n\n        Returns:\n            Generated code with where the code is being saved or error message.\n        \"\"\"\n        prompt = PromptReader.read_tools_prompt(__file__, \"write_code.txt\") + \"\\nUseful to know:\\n\" + PromptReader.read_tools_prompt(__file__, \"generate_logic.txt\")\n        prompt = prompt.replace(\"{goals}\", AgentPromptBuilder.add_list_items_to_string(self.goals))\n        prompt = prompt.replace(\"{code_description}\", code_description)\n        spec_response = self.tool_response_manager.get_last_response(\"WriteSpecTool\")\n        if spec_response != \"\":\n            prompt = prompt.replace(\"{spec}\", \"Use this specs for generating the code:\\n\" + spec_response)\n        logger.info(prompt)\n        messages = [{\"role\": \"system\", \"content\": prompt}]\n\n        organisation = Agent.find_org_by_agent_id(session=self.toolkit_config.session, agent_id=self.agent_id)\n        total_tokens = TokenCounter.count_message_tokens(messages, self.llm.get_model())\n        token_limit = TokenCounter(session=self.toolkit_config.session, organisation_id=organisation.id).token_limit(self.llm.get_model())\n\n        result = self.llm.chat_completion(messages, max_tokens=(token_limit - total_tokens - 100))\n        \n        if 'error' in result and result['message'] is not None:\n            ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message'])\n\n        # Get all filenames and corresponding code blocks\n        regex = r\"(\\S+?)\\n```\\S*\\n(.+?)```\"\n        matches = re.finditer(regex, result[\"content\"], re.DOTALL)\n\n        file_names = []\n        # Save each file\n\n        for match in matches:\n            # Get the filename\n            file_name = re.sub(r'[<>\"|?*]', \"\", match.group(1))\n            if not file_name[0].isalnum():\n                file_name = file_name[1:-1]\n\n            # Get the code\n            code = match.group(2)\n\n            # Ensure file_name is not empty\n            if not file_name.strip():\n                continue\n\n            file_names.append(file_name)\n            save_result = self.resource_manager.write_file(file_name, code)\n            if save_result.startswith(\"Error\"):\n                return save_result\n\n        # Get README contents and save\n        split_result = result[\"content\"].split(\"```\")\n        if split_result:\n            readme = split_result[0]\n            save_readme_result = self.resource_manager.write_file(\"README.md\", readme)\n            if save_readme_result.startswith(\"Error\"):\n                return save_readme_result\n\n        return result[\"content\"] + \"\\n Codes generated and saved successfully in \" + \", \".join(file_names)\n"
  },
  {
    "path": "superagi/tools/code/write_spec.py",
    "content": "from typing import Type, Optional, List\n\nfrom pydantic import BaseModel, Field\n\nfrom superagi.agent.agent_prompt_builder import AgentPromptBuilder\nfrom superagi.helper.error_handler import ErrorHandler\nfrom superagi.helper.prompt_reader import PromptReader\nfrom superagi.helper.token_counter import TokenCounter\nfrom superagi.lib.logger import logger\nfrom superagi.llms.base_llm import BaseLlm\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nfrom superagi.resource_manager.file_manager import FileManager\nfrom superagi.tools.base_tool import BaseTool\nfrom superagi.models.agent import Agent\n\nclass WriteSpecSchema(BaseModel):\n    task_description: str = Field(\n        ...,\n        description=\"Specification task description.\",\n    )\n\n    spec_file_name: str = Field(\n        ...,\n        description=\"Name of the file to write. Only include the file name. Don't include path.\"\n    )\n\n\nclass WriteSpecTool(BaseTool):\n    \"\"\"\n    Used to generate program specification.\n\n    Attributes:\n        llm: LLM used for specification generation.\n        name : The name of tool.\n        description : The description of tool.\n        args_schema : The args schema.\n        goals : The goals.\n        resource_manager: Manages the file resources\n    \"\"\"\n    llm: Optional[BaseLlm] = None\n    agent_id: int = None\n    agent_execution_id: int = None\n    name = \"WriteSpecTool\"\n    description = (\n        \"A tool to write the spec of a program.\"\n    )\n    args_schema: Type[WriteSpecSchema] = WriteSpecSchema\n    goals: List[str] = []\n    resource_manager: Optional[FileManager] = None\n\n    class Config:\n        arbitrary_types_allowed = True\n\n    def _execute(self, task_description: str, spec_file_name: str) -> str:\n        \"\"\"\n        Execute the write_spec tool.\n\n        Args:\n            task_description : The task description.\n            spec_file_name: The name of the file where the generated specification will be saved.\n\n        Returns:\n            Generated specification or error message.\n        \"\"\"\n        prompt = PromptReader.read_tools_prompt(__file__, \"write_spec.txt\")\n        prompt = prompt.replace(\"{goals}\", AgentPromptBuilder.add_list_items_to_string(self.goals))\n        prompt = prompt.replace(\"{task}\", task_description)\n        messages = [{\"role\": \"system\", \"content\": prompt}]\n\n        organisation = Agent.find_org_by_agent_id(self.toolkit_config.session, agent_id=self.agent_id)\n        total_tokens = TokenCounter.count_message_tokens(messages, self.llm.get_model())\n        token_limit = TokenCounter(session=self.toolkit_config.session, organisation_id=organisation.id).token_limit(self.llm.get_model())\n\n        result = self.llm.chat_completion(messages, max_tokens=(token_limit - total_tokens - 100))\n        \n        if 'error' in result and result['message'] is not None:\n            ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message'])\n\n        # Save the specification to a file\n        write_result = self.resource_manager.write_file(spec_file_name, result[\"content\"])\n        if not write_result.startswith(\"Error\"):\n            return result[\"content\"] + \"\\nSpecification generated and saved successfully\"\n        else:\n            return write_result\n"
  },
  {
    "path": "superagi/tools/code/write_test.py",
    "content": "import re\nfrom typing import Type, Optional, List\n\nfrom pydantic import BaseModel, Field\n\nfrom superagi.agent.agent_prompt_builder import AgentPromptBuilder\nfrom superagi.helper.error_handler import ErrorHandler\nfrom superagi.helper.prompt_reader import PromptReader\nfrom superagi.helper.token_counter import TokenCounter\nfrom superagi.lib.logger import logger\nfrom superagi.llms.base_llm import BaseLlm\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nfrom superagi.resource_manager.file_manager import FileManager\nfrom superagi.tools.base_tool import BaseTool\nfrom superagi.tools.tool_response_query_manager import ToolResponseQueryManager\nfrom superagi.models.agent import Agent\n\nclass WriteTestSchema(BaseModel):\n    test_description: str = Field(\n        ...,\n        description=\"Description of the testing task\",\n    )\n    test_file_name: str = Field(\n        ...,\n        description=\"Name of the file to write. Only include the file name. Don't include path.\"\n    )\n\n\nclass WriteTestTool(BaseTool):\n    \"\"\"\n    Used to generate unit tests based on the specification.\n\n    Attributes:\n        llm: LLM used for test generation.\n        name : The name of tool.\n        description : The description of tool.\n        args_schema : The args schema.\n        goals : The goals.\n        resource_manager: Manages the file resources\n    \"\"\"\n    llm: Optional[BaseLlm] = None\n    agent_id: int = None\n    agent_execution_id: int = None\n    name = \"WriteTestTool\"\n    description = (\n        \"You are a super smart developer using Test Driven Development to write tests according to a specification.\\n\"\n        \"Please generate tests based on the above specification. The tests should be as simple as possible, \"\n        \"but still cover all the functionality.\\n\"\n        \"Write it in the file\"\n    )\n    args_schema: Type[WriteTestSchema] = WriteTestSchema\n    goals: List[str] = []\n    resource_manager: Optional[FileManager] = None\n    tool_response_manager: Optional[ToolResponseQueryManager] = None\n\n    class Config:\n        arbitrary_types_allowed = True\n\n    def _execute(self, test_description: str, test_file_name: str) -> str:\n        \"\"\"\n        Execute the write_test tool.\n\n        Args:\n            test_description : The specification description.\n            test_file_name: The name of the file where the generated tests will be saved.\n\n        Returns:\n            Generated unit tests or error message.\n        \"\"\"\n        prompt = PromptReader.read_tools_prompt(__file__, \"write_test.txt\")\n        prompt = prompt.replace(\"{goals}\", AgentPromptBuilder.add_list_items_to_string(self.goals))\n        prompt = prompt.replace(\"{test_description}\", test_description)\n\n        spec_response = self.tool_response_manager.get_last_response(\"WriteSpecTool\")\n        if spec_response != \"\":\n            prompt = prompt.replace(\"{spec}\",\n                                    \"Please generate unit tests based on the following specification description:\\n\" + spec_response)\n        else:\n            spec_response = self.tool_response_manager.get_last_response()\n            if spec_response != \"\":\n                prompt = prompt.replace(\"{spec}\",\n                                        \"Please generate unit tests based on the following specification description:\\n\" + spec_response)\n\n        messages = [{\"role\": \"system\", \"content\": prompt}]\n        logger.info(prompt)\n\n        organisation = Agent.find_org_by_agent_id(self.toolkit_config.session, agent_id=self.agent_id)\n        total_tokens = TokenCounter.count_message_tokens(messages, self.llm.get_model())\n        token_limit = TokenCounter(session=self.toolkit_config.session, organisation_id=organisation.id).token_limit(self.llm.get_model())\n\n        result = self.llm.chat_completion(messages, max_tokens=(token_limit - total_tokens - 100))\n        \n        if 'error' in result and result['message'] is not None:\n            ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message'])\n\n        regex = r\"(\\S+?)\\n```\\S*\\n(.+?)```\"\n        matches = re.finditer(regex, result[\"content\"], re.DOTALL)\n\n        file_names = []\n        # Save each file\n\n        for match in matches:\n            # Get the filename\n            file_name = re.sub(r'[<>\"|?*]', \"\", match.group(1))\n            code = match.group(2)\n            if not file_name.strip():\n                continue\n\n            file_names.append(file_name)\n            save_result = self.resource_manager.write_file(file_name, code)\n            if save_result.startswith(\"Error\"):\n                return save_result\n\n        # Save the tests to a file\n        # save_result = self.resource_manager.write_file(test_file_name, code_content)\n        if not result[\"content\"].startswith(\"Error\"):\n            return result[\"content\"] + \" \\n Tests generated and saved successfully in \" + test_file_name\n        else:\n            return save_result\n"
  },
  {
    "path": "superagi/tools/duck_duck_go/README.md",
    "content": "<p align=center>\n<a href=\"https://superagi.co\"><img src=https://superagi.co/wp-content/uploads/2023/05/SuperAGI_icon.png></a>\n</p>\n\n# SuperAGI DuckDuckGo Search Tool\n\nThe SuperAGI DuckDuckGo Search Tool helps users perform a DuckDuckGo search and extract snippets and webpages.\n\n## ⚙️ Installation\n\n### 🛠 **Setting Up of SuperAGI**\n\nSet up the SuperAGI by following the instructions given (https://github.com/TransformerOptimus/SuperAGI/blob/main/README.MD)\n\n## Running SuperAGI DuckDuckGo Search Tool\n\nYou can simply ask your agent about latest information regarding anything in the world and your agent will be able to browse the internet to get that information for you.\n"
  },
  {
    "path": "superagi/tools/duck_duck_go/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/tools/duck_duck_go/duck_duck_go_search.py",
    "content": "import json\nimport requests\nfrom typing import Type, Optional,Union\nimport time\nfrom superagi.helper.error_handler import ErrorHandler\nfrom superagi.lib.logger import logger\nfrom pydantic import BaseModel, Field\nfrom duckduckgo_search import DDGS\nfrom itertools import islice\nfrom superagi.helper.token_counter import TokenCounter\nfrom superagi.llms.base_llm import BaseLlm\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nfrom superagi.tools.base_tool import BaseTool\nfrom superagi.helper.webpage_extractor import WebpageExtractor\n\n#Const variables\nDUCKDUCKGO_MAX_ATTEMPTS = 3\nWEBPAGE_EXTRACTOR_MAX_ATTEMPTS=2\nMAX_LINKS_TO_SCRAPE=3\nNUM_RESULTS_TO_USE=10\nclass DuckDuckGoSearchSchema(BaseModel):\n    query: str = Field(\n        ...,\n        description=\"The search query for duckduckgo search.\",\n    )\n\nclass DuckDuckGoSearchTool(BaseTool):\n    \"\"\"\n    Duck Duck Go Search tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    llm: Optional[BaseLlm] = None\n    name = \"DuckDuckGoSearch\"\n    agent_id: int = None\n    agent_execution_id: int = None\n    description = (\n        \"A tool for performing a DuckDuckGo search and extracting snippets and webpages.\"\n        \"Input should be a search query.\"\n    )\n    args_schema: Type[DuckDuckGoSearchSchema] = DuckDuckGoSearchSchema\n\n    class Config:\n        arbitrary_types_allowed = True\n\n    def _execute(self, query: str) -> tuple:\n        \n        \"\"\"\n        Execute the DuckDuckGo search tool.\n\n        Args:\n            query : The query to search for.\n\n        Returns:\n            Search result summary along with related links\n        \"\"\"\n\n        search_results = self.get_raw_duckduckgo_results(query)\n        links=[]                                                                        \n        \n        for result in search_results:                                                       \n            links.append(result[\"href\"])\n        \n        webpages=self.get_content_from_url(links)\n\n        results=self.get_formatted_webpages(search_results,webpages)                        #array to store objects with keys :{\"title\":snippet , \"body\":webpage content, \"links\":link URL}\n        \n        summary = self.summarise_result(query, results)                                     #summarize the content gathered using the function\n        links = [result[\"links\"] for result in results if len(result[\"links\"]) > 0]\n\n        if len(links) > 0:\n            return summary + \"\\n\\nLinks:\\n\" + \"\\n\".join(\"- \" + link for link in links[:3])\n\n        return summary\n\n\n    def get_formatted_webpages(self,search_results,webpages):\n        \"\"\"\n        Generate an array of formatted webpages which can be passed to the summarizer function (summarise_result).\n\n        Args:\n            search_results : The array of objects which were fetched by DuckDuckGo.\n\n        Returns:\n            Returns the result array which is an array of objects\n        \"\"\"\n\n        results=[]                                                                          #array to store objects with keys :{\"title\":snippet , \"body\":webpage content, \"links\":link URL}\n        i = 0\n        \n        for webpage in webpages:\n            results.append({\"title\": search_results[i][\"title\"], \"body\": webpage, \"links\": search_results[i][\"href\"]})\n            i += 1\n            if TokenCounter.count_text_tokens(json.dumps(results)) > 3000:\n                break    \n\n        return results\n\n    def get_content_from_url(self,links):\n        \"\"\"\n        Generates a webpage array which stores the content fetched from the links\n        Args:\n            links : The array of URLs which were fetched by DuckDuckGo.\n\n        Returns:\n            Returns a webpage array which stores the content fetched from the links\n        \"\"\"\n\n        webpages=[]                                                                         #webpages array for storing the contents extracted from the links\n        \n        if links:\n            for i in range(0, MAX_LINKS_TO_SCRAPE):                                         #using first 3 (Value of MAX_LINKS_TO_SCRAPE) links\n                time.sleep(3)\n                content = WebpageExtractor().extract_with_bs4(links[i])                     #takes in the link and returns content extracted from Webpage extractor\n                max_length = len(' '.join(content.split(\" \")[:500]))    \n                content = content[:max_length]                                              #formatting the content\n                attempts = 0\n                while content == \"\" and attempts < WEBPAGE_EXTRACTOR_MAX_ATTEMPTS:\n                    attempts += 1\n                    content = WebpageExtractor().extract_with_bs4(links[i])\n                    content = content[:max_length]\n                webpages.append(content)\n\n        return webpages\n\n    def get_raw_duckduckgo_results(self,query):\n        \"\"\"\n        Gets raw search results from the duckduckgosearch python package\n        Args:\n            query : The query to search for.\n\n        Returns:\n            Returns raw search results from the duckduckgosearch python package\n        \"\"\"\n        search_results = []\n        attempts = 0\n\n        while attempts < DUCKDUCKGO_MAX_ATTEMPTS:\n            if not query:                                                                   #checking if string is empty, if it is empty-> convert array to JSON object and return it;\n                return json.dumps(search_results)\n\n            results = DDGS().text(query)                                                    #text() method from DDGS takes in query (String) as input and returns the results \n            search_results = list(islice(results, NUM_RESULTS_TO_USE))                      #gets first 10 results from results and stores them in search_results\n            if search_results:                                                              #if search result is populated,break as there is no need to attempt the search again\n                break\n\n            # time.sleep(1)\n            attempts += 1\n        \n        return search_results\n\n    def summarise_result(self, query, snippets):\n        \"\"\"\n        Summarise the result of a DuckDuckGo search.\n\n        Args:\n            query : The query to search for.\n            snippets (list): A list of snippets from the search.\n\n        Returns:\n            A summary of the search result.\n        \"\"\"\n        summarize_prompt =\"\"\"Summarize the following text `{snippets}`\n            Write a concise or as descriptive as necessary and attempt to\n            answer the query: `{query}` as best as possible. Use markdown formatting for\n            longer responses.\"\"\"\n\n        summarize_prompt = summarize_prompt.replace(\"{snippets}\", str(snippets))\n        summarize_prompt = summarize_prompt.replace(\"{query}\", query)\n\n        messages = [{\"role\": \"system\", \"content\": summarize_prompt}]\n        result = self.llm.chat_completion(messages, max_tokens=self.max_token_limit)\n        \n        if 'error' in result and result['message'] is not None:\n            ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message'])\n        return result[\"content\"]\n"
  },
  {
    "path": "superagi/tools/duck_duck_go/duck_duck_go_search_toolkit.py",
    "content": "from abc import ABC\nfrom typing import List\nfrom superagi.tools.base_tool import BaseTool, BaseToolkit, ToolConfiguration\nfrom superagi.tools.duck_duck_go.duck_duck_go_search import DuckDuckGoSearchTool\nfrom superagi.types.key_type import ToolConfigKeyType\nfrom superagi.models.tool_config import ToolConfig\n\nclass DuckDuckGoToolkit(BaseToolkit, ABC):\n    name: str = \"DuckDuckGo Search Toolkit\"\n    description: str = \"Toolkit containing tools for performing DuckDuckGo search and extracting snippets and webpages\"\n\n    def get_tools(self) -> List[BaseTool]:\n        return [DuckDuckGoSearchTool()]\n\n    def get_env_keys(self) -> List[ToolConfiguration]:\n        return [\n            # Add more config keys specific to your project\n        ]\n"
  },
  {
    "path": "superagi/tools/email/README.md",
    "content": "<p align=\"center\">\n<a href=\"https://superagi.com//#gh-light-mode-only\">\n<img src=\"https://superagi.com/wp-content/uploads/2023/05/Logo-dark.svg\" width=\"318px\" alt=\"SuperAGI logo\" />\n</a>\n<a href=\"https://superagi.com//#gh-dark-mode-only\">\n<img src=\"https://superagi.com/wp-content/uploads/2023/05/Logo-light.svg\" width=\"318px\" alt=\"SuperAGI logo\" />\n</a>\n</p>\n\n# SuperAGI Email Tool\n\nThe robust SuperAGI Email Tool lets users send and read emails while providing a foundation for other fascinating use cases.\n\n## 💡 Features\n\n1.**Read Emails:** With SuperAGI's Email Tool, you can effortlessly manage your inbox and ensure that you never overlook a critical detail.\n\n2. **Send Emails:** SuperAGI's Email Tool uses its comprehensive language model capabilities to create personalised, context-aware emails, sparing you effort and time.\n\n3. **Save Emails to Drafts Folder:** By allowing SuperAGI to develop email draughts that you can examine and modify before sending, you'll gain greater control and make sure your messages are tailored to your tastes.\n\n4. **Send Emails with Attachments:** Send attachments in emails with ease to enrich and expand the scope of your message.\n\n5. **Custom Email Signature:** Create a unique signature for each email you send to add a touch of customization and automation.\n\n6. **Auto-Reply and Answer Questions:** Allow SuperAGI to read, analyse, and respond to incoming emails with precise answers to streamline your email responses.\n\n## ⚙️ Installation\n\n### 🛠 **Setting Up of SuperAGI**\nSet up the SuperAGI by following the instructions given (https://github.com/TransformerOptimus/SuperAGI/blob/main/README.MD)\n\n### 🔧 **Add Email configuration settings SuperAGI's Dashboard**\n\n![Config_Page](https://github.com/Phoenix2809/SuperAGI/assets/133874957/6abe8f84-370e-4512-8374-e7eebe5f836d)\n\nAdd the following configuration in the Email Toolkit Page:\n\n1. _Email address and password:_\n - Set 'EMAIL_ADDRESS' to sender's email address\n - Set 'EMAIL_PASSWORD' to your Password. If using Gmail, use App Password (Follow the steps given below to obtain your app password.)\n \n2. _Provider-specific settings:_\n - If not using Gmail, modify 'EMAIL_SMTP_HOST', 'EMAIL_SMTP_PORT', AND 'EMAIL_IMAP_HOST' according to your email service provider.\n\n3. _Sending and Drafts:_\n\t- You can set the EMAIL_DRAFT_MODE to \"FALSE\" if you'd like your email to be directly sent and \"TRUE\" if you'd like to save your emails in Draft.\n\t- If you're setting Draft Mode to True, Make sure to add the draft folder for your email service provider to prevent it from being sent.\n\n4. _Optional Settings:_\n - Change the 'EMAIL_SIGNATURE' to your personalize signature.\n \n\n## Obtain your App Password\n\nTo obtain App password for your Gmail Account follow the steps:\n\n- Navigate to the link (https://myaccount.google.com/apppasswords)\n\n![app_password](https://github.com/TransformerOptimus/SuperAGI/assets/97586318/ec1e6222-e5d4-4b88-a69c-1fd5774ae0ea)\n\n- To get the App Password ensure that you have set up 2-Step Verification for your email address.\n\n- Generate the password by creating a custom app\n \n![password](https://github.com/TransformerOptimus/SuperAGI/assets/97586318/32219756-8715-4f5a-bb1c-0b2cae4e73a3)\n\n- Copy the password generated and use it for 'EMAIL_PASSWORD'\n\n- Also make sure IMAP Access is enabled for your Gmail Address (Settings > See all settings > Forwarding and POP/IMAP > Enable IMAP)\n\n![imap_enable](https://github.com/TransformerOptimus/SuperAGI/assets/97586318/50ef3e0c-c2ff-4848-aba7-8a6bd4a800ab)\n\n## Running SuperAGI Email Tool\n\n1. **Read an email**\n\nBy default SuperAGI's email tool reads last 10 emails from your inbox, to change the limit you can modify the default limit in read_email.py \n\n2. **Send an email**\n\nTo send an email to a particular receiver, mention the receiver's ID in your goal. Email will be stored in drafts if in case receiver's email address is not mentioned.\n\n![send_email](https://github.com/TransformerOptimus/SuperAGI/assets/97586318/c4dc52b9-ab68-4db3-b1f9-3431c00710c4)\n\n3. **Send an email with attachment**\n\nSuperAGI can send Emails with Attachments if you have uploaded the file in the Resource Manager, or if your file is in the Input or the Output of your SuperAGI Workspace. \n\n![attachment](https://github.com/TransformerOptimus/SuperAGI/assets/97586318/de112910-a623-469d-a0db-99063fb8572e)\n```\n"
  },
  {
    "path": "superagi/tools/email/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/tools/email/email_toolkit.py",
    "content": "from abc import ABC\nfrom superagi.tools.base_tool import BaseToolkit, BaseTool, ToolConfiguration\nfrom typing import Type, List\nfrom superagi.tools.email.read_email import ReadEmailTool\nfrom superagi.tools.email.send_email import SendEmailTool\nfrom superagi.tools.email.send_email_attachment import SendEmailAttachmentTool\nfrom superagi.types.key_type import ToolConfigKeyType\n\n\nclass EmailToolkit(BaseToolkit, ABC):\n    name: str = \"Email Toolkit\"\n    description: str = \"Email Tool kit contains all tools related to sending email\"\n\n    def get_tools(self) -> List[BaseTool]:\n        return [ReadEmailTool(), SendEmailTool(), SendEmailAttachmentTool()]\n\n    def get_env_keys(self) -> List[ToolConfiguration]:\n        return [\n            ToolConfiguration(key=\"EMAIL_ADDRESS\", key_type=ToolConfigKeyType.STRING, is_required= True, is_secret = False),\n            ToolConfiguration(key=\"EMAIL_PASSWORD\", key_type=ToolConfigKeyType.STRING, is_required=True, is_secret=True),\n            ToolConfiguration(key=\"EMAIL_SIGNATURE\", key_type=ToolConfigKeyType.STRING, is_required=False, is_secret=False),\n            ToolConfiguration(key=\"EMAIL_DRAFT_MODE\", key_type=ToolConfigKeyType.STRING, is_required=True, is_secret=False),\n            ToolConfiguration(key=\"EMAIL_DRAFT_FOLDER\", key_type=ToolConfigKeyType.STRING, is_required=True, is_secret=False),\n            ToolConfiguration(key=\"EMAIL_SMTP_HOST\", key_type=ToolConfigKeyType.STRING, is_required=True, is_secret=False),\n            ToolConfiguration(key=\"EMAIL_SMTP_PORT\", key_type=ToolConfigKeyType.STRING, is_required=True, is_secret=False),\n            ToolConfiguration(key=\"EMAIL_IMAP_SERVER\", key_type=ToolConfigKeyType.STRING, is_required=True, is_secret=False)\n        ]"
  },
  {
    "path": "superagi/tools/email/read_email.py",
    "content": "import email\nimport json\nfrom typing import Type\n\nfrom pydantic import BaseModel, Field\n\nfrom superagi.helper.imap_email import ImapEmail\nfrom superagi.helper.read_email import ReadEmail\nfrom superagi.helper.token_counter import TokenCounter\nfrom superagi.tools.base_tool import BaseTool\n\n\nclass ReadEmailInput(BaseModel):\n    imap_folder: str = Field(..., description=\"Email folder to read from. default value is \\\"INBOX\\\"\")\n    page: int = Field(...,\n                      description=\"The index of the page result the function should resturn. Defaults to 0, the first page.\")\n    limit: int = Field(..., description=\"Number of emails to fetch in one cycle. Defaults to 5.\")\n\n\nclass ReadEmailTool(BaseTool):\n    \"\"\"\n    Read emails from an IMAP mailbox\n\n    Attributes:\n        name : The name of the tool.\n        description : The description of the tool.\n        args_schema : The args schema.\n    \"\"\"\n    name: str = \"Read Email\"\n    args_schema: Type[BaseModel] = ReadEmailInput\n    description: str = \"Read emails from an IMAP mailbox\"\n\n    def _execute(self, imap_folder: str = \"INBOX\", page: int = 0, limit: int = 5) -> str:\n        \"\"\"\n        Execute the read email tool.\n\n        Args:\n            imap_folder : The email folder to read from. Defaults to \"INBOX\".\n            page : The index of the page result the function should return. Defaults to 0, the first page.\n            limit : Number of emails to fetch in one cycle. Defaults to 5.\n\n        Returns:\n            email contents or error message.\n        \"\"\"\n        email_sender = self.get_tool_config('EMAIL_ADDRESS')\n        email_password = self.get_tool_config('EMAIL_PASSWORD')\n        if email_sender == \"\":\n            return \"Error: Email Not Sent. Enter a valid Email Address.\"\n        if email_password == \"\":\n            return \"Error: Email Not Sent. Enter a valid Email Password.\"\n        imap_server = self.get_tool_config('EMAIL_IMAP_SERVER')\n        conn = ImapEmail().imap_open(imap_folder, email_sender, email_password, imap_server)\n        status, messages = conn.select(\"INBOX\")\n        num_of_messages = int(messages[0])\n        messages = []\n        for i in range(num_of_messages, num_of_messages - limit, -1):\n            res, msg = conn.fetch(str(i), \"(RFC822)\")\n            email_msg = {}\n            for response in msg:\n                self._process_message(email_msg, response)\n            messages.append(email_msg)\n            if TokenCounter.count_text_tokens(json.dumps(messages)) > self.max_token_limit:\n                break\n\n        conn.logout()\n        if not messages:\n            return f\"There are no Email in your folder {imap_folder}\"\n        else:\n            return messages\n\n    def _process_message(self, email_msg, response):\n        if isinstance(response, tuple):\n            msg = email.message_from_bytes(response[1])\n            email_msg[\"From\"], email_msg[\"To\"], email_msg[\"Date\"], email_msg[\n                \"Subject\"] = ReadEmail().obtain_header(msg)\n            if msg.is_multipart():\n                for part in msg.walk():\n                    content_type = part.get_content_type()\n                    content_disposition = str(part.get(\"Content-Disposition\"))\n                    try:\n                        body = part.get_payload(decode=True).decode()\n                    except:\n                        pass\n                    if content_type == \"text/plain\" and \"attachment\" not in content_disposition:\n                        email_msg[\"Message Body\"] = ReadEmail().clean_email_body(body)\n                    elif \"attachment\" in content_disposition:\n                        ReadEmail().download_attachment(part, email_msg[\"Subject\"])\n            else:\n                content_type = msg.get_content_type()\n                body = msg.get_payload(decode=True).decode()\n                if content_type == \"text/plain\":\n                    email_msg[\"Message Body\"] = ReadEmail().clean_email_body(body)\n"
  },
  {
    "path": "superagi/tools/email/send_email.py",
    "content": "import imaplib\nimport smtplib\nimport time\nfrom email.message import EmailMessage\nfrom typing import Type\n\nfrom pydantic import BaseModel, Field\nfrom superagi.helper.imap_email import ImapEmail\nfrom superagi.tools.base_tool import BaseTool\n\n\nclass SendEmailInput(BaseModel):\n    to: str = Field(..., description=\"Email Address of the Receiver, default email address is 'example@example.com'\")\n    subject: str = Field(..., description=\"Subject of the Email to be sent\")\n    body: str = Field(..., description=\"Email Body to be sent. Escape special characters in the body. Do not add senders details and end it with Warm Regards without entering any name.\")\n\n\nclass SendEmailTool(BaseTool):\n    \"\"\"\n    Send an Email tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    name: str = \"Send Email\"\n    args_schema: Type[BaseModel] = SendEmailInput\n    description: str = \"Send an Email\"\n    \n    def _execute(self, to: str, subject: str, body: str) -> str:\n        \"\"\"\n        Execute the send email tool.\n\n        Args:\n            to : The email address of the receiver.\n            subject : The subject of the email.\n            body : The body of the email.\n\n        Returns:\n            success or error message.\n        \"\"\"\n        email_sender = self.get_tool_config('EMAIL_ADDRESS')\n        email_password = self.get_tool_config('EMAIL_PASSWORD')\n        if email_sender is None or email_sender == \"\" or email_sender.isspace():\n            return \"Error: Email Not Sent. Enter a valid Email Address.\"\n        if email_password is None or email_password == \"\" or email_password.isspace():\n            return \"Error: Email Not Sent. Enter a valid Email Password.\"\n        message = EmailMessage()\n        message[\"Subject\"] = subject\n        message[\"From\"] = email_sender\n        message[\"To\"] = to\n        signature = self.get_tool_config('EMAIL_SIGNATURE')\n        if signature:\n            body += f\"\\n{signature}\"\n        message.set_content(body.replace('\\\\n', '\\n'))\n        send_to_draft = self.get_tool_config('EMAIL_DRAFT_MODE') or \"FALSE\"\n        if send_to_draft.upper() == \"TRUE\":\n            send_to_draft = True\n        else:\n            send_to_draft = False\n\n        if send_to_draft:\n            draft_folder = self.get_tool_config('EMAIL_DRAFT_FOLDER') or \"Drafts\"\n            imap_server = self.get_tool_config('EMAIL_IMAP_SERVER')\n            conn = ImapEmail().imap_open(draft_folder, email_sender, email_password, imap_server)\n            conn.append(\n                draft_folder,\n                \"\",\n                imaplib.Time2Internaldate(time.time()),\n                str(message).encode(\"UTF-8\")\n            )\n            return f\"Email went to {draft_folder}\"\n        \n        if message[\"To\"] == \"example@example.com\":\n            return \"Error: Email Not Sent. Enter an Email Address.\"\n        \n        else:\n            smtp_host = self.get_tool_config('EMAIL_SMTP_HOST')\n            smtp_port = self.get_tool_config('EMAIL_SMTP_PORT')\n            with smtplib.SMTP(smtp_host, smtp_port) as smtp:\n                smtp.ehlo()\n                smtp.starttls()\n                smtp.login(email_sender, email_password)\n                smtp.send_message(message)\n                smtp.quit()\n            return f\"Email was sent to {to}\"\n"
  },
  {
    "path": "superagi/tools/email/send_email_attachment.py",
    "content": "import imaplib\nimport mimetypes\nimport os\nimport smtplib\nimport time\nfrom email.message import EmailMessage\nfrom email.mime.application import MIMEApplication\nfrom email.mime.multipart import MIMEMultipart\nfrom email.mime.text import MIMEText\nfrom typing import Type\n\nfrom pydantic import BaseModel, Field\n\nfrom superagi.config.config import get_config\nfrom superagi.helper.imap_email import ImapEmail\nfrom superagi.helper.resource_helper import ResourceHelper\nfrom superagi.helper.s3_helper import S3Helper\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.tools.base_tool import BaseTool\nfrom superagi.config.config import get_config\nfrom superagi.types.storage_types import StorageType\n\n\nclass SendEmailAttachmentInput(BaseModel):\n    to: str = Field(..., description=\"Email Address of the Receiver, default email address is 'example@example.com'\")\n    subject: str = Field(..., description=\"Subject of the Email to be sent\")\n    body: str = Field(..., description=\"Email Body to be sent, Do not add senders details in the email body and end it with Warm Regards without entering any name.\")\n    filename: str = Field(..., description=\"Name of the file to be sent as an Attachment with Email\")\n\n\nclass SendEmailAttachmentTool(BaseTool):\n    \"\"\"\n    Send an Email with Attachment tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    name: str = \"Send Email with Attachment\"\n    args_schema: Type[BaseModel] = SendEmailAttachmentInput\n    description: str = \"Send an Email with a file attached to it\"\n    agent_id: int = None\n    agent_execution_id: int = None\n\n    def _execute(self, to: str, subject: str, body: str, filename: str) -> str:\n        \"\"\"\n        Execute the send email tool with attachment.\n\n        Args:\n            to : The email address of the receiver.\n            subject : The subject of the email.\n            body : The body of the email.\n            filename : The name of the file to be sent as an attachment with the email.\n\n        Returns:\n            success or failure message\n        \"\"\"\n        final_path = ResourceHelper.get_agent_read_resource_path(file_name=filename,\n                                                                 agent=Agent.get_agent_from_id(\n                                                                     self.toolkit_config.session,\n                                                                     self.agent_id),\n                                                                 agent_execution=AgentExecution.get_agent_execution_from_id(\n                                                                     session=self.toolkit_config.session,\n                                                                     agent_execution_id=self.agent_execution_id)\n                                                                 )\n        ctype, encoding = mimetypes.guess_type(final_path)\n        if ctype is None or encoding is not None:\n            ctype = \"application/octet-stream\"\n        maintype, subtype = ctype.split(\"/\", 1)\n        if StorageType.get_storage_type(get_config(\"STORAGE_TYPE\", StorageType.FILE.value)) == StorageType.S3:\n            attachment_data = S3Helper().read_binary_from_s3(final_path)\n        else:\n            if final_path is None or not os.path.exists(final_path):\n                raise FileNotFoundError(f\"File '{filename}' not found.\")\n            with open(final_path, \"rb\") as file:\n                attachment_data = file.read()\n        attachment = MIMEApplication(attachment_data)\n        attachment.add_header('Content-Disposition', 'attachment', filename=final_path.split('/')[-1])\n\n        return self.send_email_with_attachment(to, subject, body, attachment)\n\n    def send_email_with_attachment(self, to, subject, body, attachment) -> str:\n        \"\"\"\n        Send an email with attachment.\n\n        Args:\n            to : The email address of the receiver.\n            subject : The subject of the email.\n            body : The body of the email.\n            attachment : The data of the file to be sent as an attachment with the email.\n\n        Returns:\n            \n        \"\"\"\n        email_sender = self.get_tool_config('EMAIL_ADDRESS')\n        email_password = self.get_tool_config('EMAIL_PASSWORD')\n        if email_sender is None or email_sender == \"\" or email_sender.isspace():\n            return \"Error: Email Not Sent. Enter a valid Email Address.\"\n        if email_password is None or email_password == \"\" or email_password.isspace():\n            return \"Error: Email Not Sent. Enter a valid Email Password.\"\n        message = MIMEMultipart()\n        message[\"Subject\"] = subject\n        message[\"From\"] = email_sender\n        message[\"To\"] = to\n        signature = self.get_tool_config('EMAIL_SIGNATURE')\n        if signature:\n            body += f\"\\n{signature}\"\n        message.attach(MIMEText(body, 'plain'))\n        if attachment:\n            message.attach(attachment)\n\n        send_to_draft = self.get_tool_config('EMAIL_DRAFT_MODE') or \"FALSE\"\n        if send_to_draft.upper() == \"TRUE\":\n            send_to_draft = True\n        else:\n            send_to_draft = False\n        if send_to_draft:\n            draft_folder = self.get_tool_config('EMAIL_DRAFT_FOLDER')\n            imap_server = self.get_tool_config('EMAIL_IMAP_SERVER')\n            conn = ImapEmail().imap_open(draft_folder, email_sender, email_password, imap_server)\n            conn.append(\n                draft_folder,\n                \"\",\n                imaplib.Time2Internaldate(time.time()),\n                str(message).encode(\"UTF-8\")\n            )\n            return f\"Email went to {draft_folder}\"\n        \n        if message[\"To\"] == \"example@example.com\":\n            return \"Error: Email Not Sent. Enter an Email Address.\"\n        \n        else:\n            smtp_host = self.get_tool_config('EMAIL_SMTP_HOST')\n            smtp_port = self.get_tool_config('EMAIL_SMTP_PORT')\n            with smtplib.SMTP(smtp_host, smtp_port) as smtp:\n                smtp.ehlo()\n                smtp.starttls()\n                smtp.login(email_sender, email_password)\n                smtp.send_message(message)\n                smtp.quit()\n            return f\"Email was sent to {to}\"\n"
  },
  {
    "path": "superagi/tools/file/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/tools/file/append_file.py",
    "content": "import os\nfrom typing import Type, Optional\n\nfrom pydantic import BaseModel, Field\n\nfrom superagi.helper.resource_helper import ResourceHelper\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.tools.base_tool import BaseTool\nfrom superagi.models.agent import Agent\nfrom superagi.types.storage_types import StorageType\nfrom superagi.config.config import get_config\nfrom superagi.helper.s3_helper import S3Helper\nfrom superagi.resource_manager.file_manager import FileManager\n\nclass AppendFileInput(BaseModel):\n    \"\"\"Input for CopyFileTool.\"\"\"\n    file_name: str = Field(..., description=\"Name of the file to write\")\n    content: str = Field(..., description=\"The text to append to the file\")\n\n\nclass AppendFileTool(BaseTool):\n    \"\"\"\n    Append File tool\n\n    Attributes:\n        name : The name.\n        agent_id: The agent id.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    name: str = \"Append File\"\n    agent_id: int = None\n    agent_execution_id: int = None\n    args_schema: Type[BaseModel] = AppendFileInput\n    description: str = \"Append text to a file\"\n    resource_manager: Optional[FileManager] = None\n\n    def _execute(self, file_name: str, content: str):\n        \"\"\"\n        Execute the append file tool.\n\n        Args:\n            file_name : The name of the file to write.\n            content : The text to append to the file.\n\n        Returns:\n            success or error message.\n        \"\"\"\n        \n        final_path = ResourceHelper.get_agent_write_resource_path(file_name, Agent.get_agent_from_id(\n            session=self.toolkit_config.session,\n            agent_id=self.agent_id),\n          AgentExecution.get_agent_execution_from_id(\n              session=self.toolkit_config.session,\n              agent_execution_id=self.agent_execution_id))\n        \n        if StorageType.get_storage_type(get_config(\"STORAGE_TYPE\", StorageType.FILE.value)) == StorageType.S3:\n            previous_content = self.get_previous_content(final_path)\n            if previous_content is None:\n                return \"Append file only supported for .txt Files.\"\n            if not previous_content:\n                return \"File not Found.\"\n            S3Helper().delete_file(final_path)\n            new_content = previous_content + content\n            return self.resource_manager.write_file(file_name, new_content)\n\n        try:\n            directory = os.path.dirname(final_path)\n            os.makedirs(directory, exist_ok=True)\n            with open(final_path, 'a+', encoding=\"utf-8\") as file:\n                file.write(content)\n            return \"File written to successfully.\"\n        except Exception as err:\n            return f\"Error: {err}\"\n    \n    def get_previous_content(self, final_path):\n        if final_path.split('/')[-1].lower().endswith('.txt'):\n            try:\n                return S3Helper().read_from_s3(final_path)\n            except Exception:\n                return False"
  },
  {
    "path": "superagi/tools/file/delete_file.py",
    "content": "import os\nfrom typing import Type\n\nfrom pydantic import BaseModel, Field\n\nfrom superagi.helper.resource_helper import ResourceHelper\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent import Agent\nfrom superagi.tools.base_tool import BaseTool\nfrom superagi.types.storage_types import StorageType\nfrom superagi.config.config import get_config\nfrom superagi.helper.s3_helper import S3Helper\n\n\nclass DeleteFileInput(BaseModel):\n    \"\"\"Input for CopyFileTool.\"\"\"\n    file_name: str = Field(..., description=\"Name of the file to delete\")\n\n\nclass DeleteFileTool(BaseTool):\n    \"\"\"\n    Delete File tool\n\n    Attributes:\n        name : The name.\n        agent_id: The agent id.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    name: str = \"Delete File\"\n    agent_id: int = None\n    agent_execution_id:int = None\n    args_schema: Type[BaseModel] = DeleteFileInput\n    description: str = \"Delete a file\"\n\n    def _execute(self, file_name: str):\n        \"\"\"\n        Execute the delete file tool.\n\n        Args:\n            file_name : The name of the file to delete.\n\n        Returns:\n            success or error message.\n        \"\"\"\n        final_path = ResourceHelper.get_agent_write_resource_path(file_name, Agent.get_agent_from_id(\n            session=self.toolkit_config.session,\n            agent_id=self.agent_id),\n          AgentExecution.get_agent_execution_from_id(\n              session=self.toolkit_config.session,\n              agent_execution_id=self.agent_execution_id))\n        \n        if StorageType.get_storage_type(get_config(\"STORAGE_TYPE\", StorageType.FILE.value)) == StorageType.S3:\n            try:\n                S3Helper().delete_file(final_path)\n                return \"File deleted successfully.\"\n            except Exception as err:\n                return f\"Error: {err}\"\n        else:\n            try:\n                os.remove(final_path)\n                return \"File deleted successfully.\"\n            except Exception as err:\n                return f\"Error: {err}\""
  },
  {
    "path": "superagi/tools/file/file_toolkit.py",
    "content": "from abc import ABC\nfrom typing import List\nfrom superagi.tools.base_tool import BaseTool, BaseToolkit, ToolConfiguration\nfrom superagi.tools.file.append_file import AppendFileTool\nfrom superagi.tools.file.delete_file import DeleteFileTool\nfrom superagi.tools.file.list_files import ListFileTool\nfrom superagi.tools.file.read_file import ReadFileTool\nfrom superagi.tools.file.write_file import WriteFileTool\nfrom superagi.types.key_type import ToolConfigKeyType\nfrom superagi.models.tool_config import ToolConfig\n\n\nclass FileToolkit(BaseToolkit, ABC):\n    name: str = \"File Toolkit\"\n    description: str = \"File Tool kit contains all tools related to file operations\"\n\n    def get_tools(self) -> List[BaseTool]:\n        return [AppendFileTool(), DeleteFileTool(), ListFileTool(), ReadFileTool(), WriteFileTool()]\n\n    def get_env_keys(self) -> List[ToolConfiguration]:\n        return []\n"
  },
  {
    "path": "superagi/tools/file/list_files.py",
    "content": "import os\nfrom typing import Type\n\nfrom pydantic import BaseModel, Field\n\nfrom superagi.helper.resource_helper import ResourceHelper\nfrom superagi.helper.s3_helper import S3Helper\nfrom superagi.tools.base_tool import BaseTool\nfrom superagi.models.agent import Agent\nfrom superagi.types.storage_types import StorageType\nfrom superagi.config.config import get_config\n\n\nclass ListFileInput(BaseModel):\n    pass\n\n\nclass ListFileTool(BaseTool):\n    \"\"\"\n    List File tool\n\n    Attributes:\n        name : The name.\n        agent_id: The agent id.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    name: str = \"List File\"\n    agent_id: int = None\n    args_schema: Type[BaseModel] = ListFileInput\n    description: str = \"lists files in a directory recursively\"\n\n    def _execute(self):\n        \"\"\"\n        Execute the list file tool.\n\n        Args:\n            directory : The directory to list files in.\n\n        Returns:\n            list of files in directory.\n        \"\"\"\n        input_directory = ResourceHelper.get_root_input_dir()\n        #output_directory = ResourceHelper.get_root_output_dir()\n        if \"{agent_id}\" in input_directory:\n            input_directory = ResourceHelper.get_formatted_agent_level_path(agent=Agent\n                                                                            .get_agent_from_id(session=self\n                                                                                               .toolkit_config.session,\n                                                                                               agent_id=self.agent_id),\n                                                                            path=input_directory)\n        # if \"{agent_id}\" in output_directory:\n        #     output_directory = output_directory.replace(\"{agent_id}\", str(self.agent_id))\n        input_files = self.list_files(input_directory)\n        # output_files = self.list_files(output_directory)\n        return input_files #+ output_files\n\n    def list_files(self, directory):\n        if StorageType.get_storage_type(get_config(\"STORAGE_TYPE\", StorageType.FILE.value)) == StorageType.S3:\n            return S3Helper().list_files_from_s3(directory)\n        found_files = []\n        for root, dirs, files in os.walk(directory):\n            for file in files:\n                if file.startswith(\".\") or \"__pycache__\" in root:\n                    continue\n                # relative_path = os.path.join(root, file)\n                # input_directory = ResourceHelper.get_root_input_dir()\n                # relative_path = relative_path.split(input_directory)[1]\n                found_files.append(file)\n        return found_files\n"
  },
  {
    "path": "superagi/tools/file/read_file.py",
    "content": "import os\nfrom typing import Type, Optional\nimport ebooklib\nimport bs4 \nfrom bs4 import BeautifulSoup\n\nfrom pydantic import BaseModel, Field\nfrom ebooklib import epub\nfrom superagi.helper.validate_csv import correct_csv_encoding\n\nfrom superagi.helper.resource_helper import ResourceHelper\nfrom superagi.helper.s3_helper import S3Helper\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.resource_manager.file_manager import FileManager\nfrom superagi.tools.base_tool import BaseTool\nfrom superagi.models.agent import Agent\nfrom superagi.types.storage_types import StorageType\nfrom superagi.config.config import get_config\nfrom unstructured.partition.auto import partition\nfrom superagi.lib.logger import logger\n\nclass ReadFileSchema(BaseModel):\n    \"\"\"Input for CopyFileTool.\"\"\"\n    file_name: str = Field(..., description=\"Path of the file to read\")\n\n\nclass ReadFileTool(BaseTool):\n    \"\"\"\n    Read File tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    name: str = \"Read File\"\n    agent_id: int = None\n    agent_execution_id: int = None\n    args_schema: Type[BaseModel] = ReadFileSchema\n    description: str = \"Reads the file content in a specified location\"\n    resource_manager: Optional[FileManager] = None\n\n    def _execute(self, file_name: str):\n        \"\"\"\n        Execute the read file tool.\n\n        Args:\n            file_name : The name of the file to read.\n\n        Returns:\n            The file content and the file name\n        \"\"\"\n        final_path = ResourceHelper.get_agent_read_resource_path(file_name, agent=Agent.get_agent_from_id(\n            session=self.toolkit_config.session, agent_id=self.agent_id), agent_execution=AgentExecution\n                                                                 .get_agent_execution_from_id(session=self\n                                                                                              .toolkit_config.session,\n                                                                                              agent_execution_id=self\n                                                                                              .agent_execution_id))\n\n        temporary_file_path = None\n        final_name = final_path.split('/')[-1]\n        if StorageType.get_storage_type(get_config(\"STORAGE_TYPE\", StorageType.FILE.value)) == StorageType.S3:\n            if final_path.split('/')[-1].lower().endswith('.txt'):\n                return S3Helper().read_from_s3(final_path)\n            else:\n                save_directory = \"/\"\n                temporary_file_path = save_directory + file_name\n                with open(temporary_file_path, \"wb\") as f:\n                    contents = S3Helper().read_binary_from_s3(final_path)\n                    f.write(contents)\n\n        if final_path is None or not os.path.exists(final_path) and temporary_file_path is None:\n            raise FileNotFoundError(f\"File '{file_name}' not found.\")\n        directory = os.path.dirname(final_path)\n        os.makedirs(directory, exist_ok=True)\n\n        if temporary_file_path is not None:\n            final_path = temporary_file_path\n\n        \n        # Check if the file is an .epub file\n        if final_path.lower().endswith('.epub'):\n            # Use ebooklib to read the epub file\n            book = epub.read_epub(final_path)\n            # Get the text content from each item in the book\n            content = []\n            for item in book.get_items_of_type(ebooklib.ITEM_DOCUMENT):\n                soup = BeautifulSoup(item.get_content(), 'html.parser')\n                content.append(soup.get_text())\n\n            content = \"\\n\".join(content)\n        else:\n            if final_path.endswith('.csv'):\n                correct_csv_encoding(final_path)\n            elements = partition(final_path)\n            content = \"\\n\\n\".join([str(el) for el in elements])\n\n        if temporary_file_path is not None:\n            os.remove(temporary_file_path)\n   \n        return content"
  },
  {
    "path": "superagi/tools/file/write_file.py",
    "content": "from typing import Type, Optional\n\nfrom pydantic import BaseModel, Field\n\n# from superagi.helper.s3_helper import upload_to_s3\nfrom superagi.resource_manager.file_manager import FileManager\nfrom superagi.tools.base_tool import BaseTool\n\n\n# from superagi.helper.s3_helper import upload_to_s3\n\n\nclass WriteFileInput(BaseModel):\n    \"\"\"Input for CopyFileTool.\"\"\"\n    file_name: str = Field(..., description=\"Name of the file to write. Only include the file name. Don't include path.\")\n    content: str = Field(..., description=\"File content to write\")\n\n\nclass WriteFileTool(BaseTool):\n    \"\"\"\n    Write File tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        agent_id: The agent id.\n        args_schema : The args schema.\n        resource_manager: File resource manager.\n    \"\"\"\n    name: str = \"Write File\"\n    args_schema: Type[BaseModel] = WriteFileInput\n    description: str = \"Writes text to a file\"\n    agent_id: int = None\n    resource_manager: Optional[FileManager] = None\n\n    class Config:\n        arbitrary_types_allowed = True\n\n    def _execute(self, file_name: str, content: str):\n        \"\"\"\n        Execute the write file tool.\n\n        Args:\n            file_name : The name of the file to write.\n            content : The text to write to the file.\n\n        Returns:\n            success message if message is file written successfully or failure message if writing file fails.\n        \"\"\"\n        return self.resource_manager.write_file(file_name, content)\n"
  },
  {
    "path": "superagi/tools/github/README.MD",
    "content": "<p align=\"center\">\n  <a href=\"https://superagi.com//#gh-light-mode-only\">\n    <img src=\"https://superagi.com/wp-content/uploads/2023/05/Logo-dark.svg\" width=\"318px\" alt=\"SuperAGI logo\" />\n  </a>\n  <a href=\"https://superagi.com//#gh-dark-mode-only\">\n    <img src=\"https://superagi.com/wp-content/uploads/2023/05/Logo-light.svg\" width=\"318px\" alt=\"SuperAGI logo\" />\n  </a>\n</p>\n\n# SuperAGI GitHub Tool\n\nThe SuperAGI GitHub Tool enables users to perform various operations on GitHub repositories which include adding files or folders, deleting files, and searching for files or folders within a repository.\n\n## 💡 Features\n\n1. **Add Files or Folders:** With SuperAGI's GitHub Tool, you can easily add files or folders to a GitHub repository\n2. **Delete Files:** Remove files from a GitHub repository effortlessly using SuperAGI's GitHub Tool. \n3. **Search for Files or Folders:** Find specific files or folders within a GitHub repository using SuperAGI's GitHub Tool. \n\n## ⚙️ Installation\n\n### 🛠 **Setting Up SuperAGI**\n\nSet up SuperAGI by following the instructions provided in the [SuperAGI repository's README file](https://github.com/TransformerOptimus/SuperAGI/blob/main/README.md).\n\n### 🔧 **Add GitHub Configuration Settings in SuperAGI Dashboard**\n\nAdd the following configuration settings to the GitHub Toolkit Page:\n\n1. _GitHub Access Token:_\n   - Obtain a GitHub access token with the necessary permissions for accessing and modifying repositories.\n    - Go to Settings in your GitHub Account. Then go to Developer Settings.\n    - Click on \"Personal access tokens\". Then click on \"Tokens (classic)\".\n    ![personal-access-token](https://github.com/TransformerOptimus/SuperAGI/assets/43145646/ee646cdd-fa04-400b-ae84-e9aee7b46c36)\n    - Click on \"Generate new token\". Then choose \"Generate new token (classic)\".\n    ![generate-new-token](https://github.com/TransformerOptimus/SuperAGI/assets/43145646/64f1d681-236a-4008-a5d9-93bb368caaaf)\n    - Write a Note about what the token is for and choose an appropriate expiration date.\n    ![github-permissions](https://github.com/TransformerOptimus/SuperAGI/assets/43145646/757b02e8-0b49-47b8-bfef-5469c0d070eb)\n    - Select all the scopes (In this way, users won't have to create new Access Tokens every time we add new scopes to the code).\n    - Click on Generate New Token.\n    - Copy the token and save it as a separate file. \n\n2. _Github User Name:_\n   - You can find your GitHub username on your GitHub Profile.\n\n3. _Configuring in SuperAGI Dashboard:_\n   -You can add your Generated Token and your Username to the GitHub Toolkit Page.\n\n## Running SuperAGI GitHub Tool\n\n1. **Add Files or Folders:**\n\n   To add a file or folder to a GitHub repository, specify the repository and the owner's UserName and the path where the file/folder should be added to your goal. SuperAGI will upload it to the repository and automatically raise a PR for it. By default, it'll pick the main branch, if you want to add it to any other branch you have to mention it in the goal.\n\n2. **Delete Files:**\n\n   To delete a file from a GitHub repository, mention the repository, owner's UserName and provide the path to the file you want to delete in your goal. SuperAGI will handle the deletion process and raise a PR for it. By default, it'll pick the main branch, if you want to delete it to any other branch you have to mention it in the goal.\n\n3. **Search for Files or Folders**\n\n   To search for files or folders within a GitHub repository, specify the repository, and owner's UserName and provide the name or path of the file/folder you're looking for in your goal. SuperAGI will provide you with the search results. By default, it'll pick the main branch, if you want to search in any other branch you have to mention it in the goal.\n \n"
  },
  {
    "path": "superagi/tools/github/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/tools/github/add_file.py",
    "content": "from typing import Type\n\nfrom pydantic import BaseModel, Field\n\nfrom superagi.helper.github_helper import GithubHelper\nfrom superagi.tools.base_tool import BaseTool\n\n\nclass GithubAddFileSchema(BaseModel):\n    # \"\"\"Input for CopyFileTool.\"\"\"\n    repository_name: str = Field(\n        ...,\n        description=\"Repository name in which file hase to be added\",\n    )\n    base_branch: str = Field(\n        ...,\n        description=\"branch to interact with\",\n    )\n    file_name: str = Field(\n        ...,\n        description=\"file name to be added to repository\",\n    )\n    folder_path: str = Field(\n        ...,\n        description=\"folder path for the file to be stored\",\n    )\n    commit_message: str = Field(\n        ...,\n        description=\"clear description of the contents of file\",\n    )\n    repository_owner: str = Field(\n        ...,\n        description=\"Owner of the github repository\",\n    )\n\n\nclass GithubAddFileTool(BaseTool):\n    \"\"\"\n    Add File tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    name: str = \"Github Add File\"\n    args_schema: Type[BaseModel] = GithubAddFileSchema\n    description: str = \"Add a file or folder to a particular github repository\"\n    agent_id: int = None\n    agent_execution_id: int = None\n\n    def _execute(self, repository_name: str, base_branch: str, commit_message: str, repository_owner: str,\n                 file_name='.gitkeep', folder_path=None) -> str:\n        \"\"\"\n        Execute the add file tool.\n\n        Args:\n            repository_name : The name of the repository to add file to.\n            base_branch : The branch to interact with.\n            commit_message : Clear description of the contents of file.\n            repository_owner : Owner of the GitHub repository.\n            file_name : The name of the file to add.\n            folder_path : The path of the folder to add the file to.\n\n        Returns:\n            Pull request success message if pull request is created successfully else error message.\n        \"\"\"\n        session = self.toolkit_config.session\n        try:\n            github_access_token = self.get_tool_config(\"GITHUB_ACCESS_TOKEN\")\n            github_username = self.get_tool_config(\"GITHUB_USERNAME\")\n            github_helper = GithubHelper(github_access_token, github_username)\n            head_branch = 'new-file'\n            headers = {\n                \"Authorization\": f\"token {github_access_token}\" if github_access_token else None,\n                \"Content-Type\": \"application/vnd.github+json\"\n            }\n            if repository_owner != github_username:\n                fork_response = github_helper.make_fork(repository_owner, repository_name, base_branch, headers)\n\n            branch_response = github_helper.create_branch(repository_name, base_branch, head_branch, headers)\n            file_response = github_helper.add_file(repository_owner, repository_name, file_name, folder_path,\n                                                   head_branch, base_branch, headers, commit_message, self.agent_id, self.agent_execution_id, session)\n            pr_response = github_helper.create_pull_request(repository_owner, repository_name, head_branch, base_branch,\n                                                            headers)\n            if (pr_response == 201 or pr_response == 422) and (file_response == 201 or file_response == 422):\n                return \"Pull request to add file/folder has been created\"\n            else:\n                return \"Error while adding file.\"\n        except Exception as err:\n            return f\"Error: Unable to add file/folder to repository {err}\""
  },
  {
    "path": "superagi/tools/github/delete_file.py",
    "content": "from typing import Type\n\nfrom pydantic import BaseModel, Field\nfrom superagi.tools.base_tool import BaseTool\nfrom superagi.helper.github_helper import GithubHelper\nfrom superagi.lib.logger import logger\n\n\nclass GithubDeleteFileSchema(BaseModel):\n    # \"\"\"Input for CopyFileTool.\"\"\"\n    repository_name: str = Field(\n        ...,\n        description=\"Repository name in which file hase to be deleted\",\n    )\n    base_branch: str = Field(\n        ...,\n        description=\"branch to interact with\",\n    )\n    file_name: str = Field(\n        ...,\n        description=\"file name to be deleted in the repository\",\n    )\n    folder_path: str = Field(\n        ...,\n        description=\"folder path in which file to be deleted is present\",\n    )\n    commit_message: str = Field(\n        ...,\n        description=\"clear description of files that are being deleted\",\n    )\n    repository_owner: str = Field(\n        ...,\n        description=\"Owner of the github repository\",\n    )\n\n\nclass GithubDeleteFileTool(BaseTool):\n    \"\"\"\n    Delete File tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    name: str = \"Github Delete File\"\n    args_schema: Type[BaseModel] = GithubDeleteFileSchema\n    description: str = \"Delete a file or folder inside a particular github repository\"\n\n    def _execute(self, repository_name: str, base_branch: str, file_name: str, commit_message: str,\n                 repository_owner: str, folder_path=None) -> str:\n        \"\"\"\n        Execute the delete file tool.\n\n        Args:\n            repository_name : The name of the repository to delete file from.\n            base_branch : The branch to interact with.\n            file_name : The name of the file to delete.\n            commit_message : Clear description of the contents of file.\n            repository_owner : Owner of the GitHub repository.\n            folder_path : The path of the folder to delete the file from.\n\n        Returns:\n            success message mentioning the pull request name for the delete file operation. or error message.\n        \"\"\"\n\n        try:\n            github_access_token = self.get_tool_config(\"GITHUB_ACCESS_TOKEN\")\n            github_username = self.get_tool_config(\"GITHUB_USERNAME\")\n            github_helper = GithubHelper(github_access_token, github_username)\n            head_branch = 'new-file'\n            headers = {\n                \"Authorization\": f\"token {github_access_token}\" if github_access_token else None,\n                \"Content-Type\": \"application/vnd.github+json\"\n            }\n            if repository_owner != github_username:\n                fork_response = github_helper.make_fork(repository_owner, repository_name, base_branch, headers)\n            branch_response = github_helper.create_branch(repository_name, base_branch, head_branch, headers)\n            logger.info(\"branch_response\", branch_response)\n            if branch_response == 201 or branch_response == 422:\n                github_helper.sync_branch(github_username, repository_name, base_branch, head_branch, headers)\n\n            file_response = github_helper.delete_file(repository_name, file_name, folder_path, commit_message,\n                                                      head_branch, headers)\n            pr_response = github_helper.create_pull_request(repository_owner, repository_name, head_branch, base_branch,\n                                                            headers)\n            if (pr_response == 201 or pr_response == 422) and (file_response == 200):\n                return f\"Pull request to Delete {file_name} has been created\"\n            else:\n                return \"Error while deleting file\"\n        except Exception as err:\n            return f\"Error: Unable to delete file {file_name} in {repository_name} repository\"\n"
  },
  {
    "path": "superagi/tools/github/fetch_pull_request.py",
    "content": "from typing import Type, Optional\n\nfrom pydantic import BaseModel, Field\n\nfrom superagi.helper.github_helper import GithubHelper\nfrom superagi.llms.base_llm import BaseLlm\nfrom superagi.tools.base_tool import BaseTool\n\n\nclass GithubFetchPullRequestSchema(BaseModel):\n    repository_name: str = Field(\n        ...,\n        description=\"Repository name in which file hase to be added\",\n    )\n    repository_owner: str = Field(\n        ...,\n        description=\"Owner of the github repository\",\n    )\n    time_in_seconds: int = Field(\n        ...,\n        description=\"Gets pull requests from last `time_in_seconds` seconds\",\n    )\n\n\nclass GithubFetchPullRequest(BaseTool):\n    \"\"\"\n    Fetch pull request tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n        agent_id: The agent id.\n        agent_execution_id: The agent execution id.\n    \"\"\"\n    llm: Optional[BaseLlm] = None\n    name: str = \"Github Fetch Pull Requests\"\n    args_schema: Type[BaseModel] = GithubFetchPullRequestSchema\n    description: str = \"Fetch pull requests from github\"\n    agent_id: int = None\n    agent_execution_id: int = None\n\n    def _execute(self, repository_name: str, repository_owner: str, time_in_seconds: int = 86400) -> str:\n        \"\"\"\n        Execute the add file tool.\n\n        Args:\n            repository_name: The name of the repository to add file to.\n            repository_owner: Owner of the GitHub repository.\n            time_in_seconds: Gets pull requests from last `time_in_seconds` seconds\n\n        Returns:\n            List of all pull request ids\n        \"\"\"\n        try:\n            github_access_token = self.get_tool_config(\"GITHUB_ACCESS_TOKEN\")\n            github_username = self.get_tool_config(\"GITHUB_USERNAME\")\n            github_helper = GithubHelper(github_access_token, github_username)\n\n            pull_request_urls = github_helper.get_pull_requests_created_in_last_x_seconds(repository_owner,\n                                                                                          repository_name,\n                                                                                          time_in_seconds)\n\n            return \"Pull requests: \" + str(pull_request_urls)\n        except Exception as err:\n            return f\"Error: Unable to fetch pull requests {err}\"\n"
  },
  {
    "path": "superagi/tools/github/github_toolkit.py",
    "content": "from abc import ABC\nfrom typing import List\nfrom superagi.tools.base_tool import BaseTool, BaseToolkit, ToolConfiguration\nfrom superagi.tools.github.add_file import GithubAddFileTool\nfrom superagi.tools.github.delete_file import GithubDeleteFileTool\nfrom superagi.tools.github.fetch_pull_request import GithubFetchPullRequest\nfrom superagi.tools.github.search_repo import GithubRepoSearchTool\nfrom superagi.tools.github.review_pull_request import GithubReviewPullRequest\nfrom superagi.types.key_type import ToolConfigKeyType\n\n\nclass GitHubToolkit(BaseToolkit, ABC):\n    name: str = \"GitHub Toolkit\"\n    description: str = \"GitHub Tool Kit contains all github related to tool\"\n\n    def get_tools(self) -> List[BaseTool]:\n        return [GithubAddFileTool(), GithubDeleteFileTool(), GithubRepoSearchTool(), GithubReviewPullRequest(),\n                GithubFetchPullRequest()]\n\n    def get_env_keys(self) -> List[ToolConfiguration]:\n        return [\n            ToolConfiguration(key=\"GITHUB_ACCESS_TOKEN\", key_type=ToolConfigKeyType.STRING, is_required= True, is_secret = True),\n            ToolConfiguration(key=\"GITHUB_USERNAME\", key_type=ToolConfigKeyType.STRING, is_required=True, is_secret=False)\n        ]\n\n\n"
  },
  {
    "path": "superagi/tools/github/prompts/code_review.txt",
    "content": "Your purpose is to act as a highly experienced software engineer and provide a thorough review of the code chunks and suggest code snippets to improve key areas such as:\n- Logic\n- Modularity\n- Maintainability\n- Complexity\n\nDo not comment on minor code style issues, missing comments/documentation. Identify and resolve significant concerns to improve overall code quality while deliberately disregarding minor issues\n\nFollowing is the github pull request diff content:\n```\n{{DIFF_CONTENT}}\n```\n\nInstructions:\n1. Do not comment on existing lines and deleted lines.\n2. Ignore the lines start with '-'.\n3. Only consider lines starting with '+' for review.\n4. Do not comment on frontend and graphql code.\n\nRespond with only valid JSON conforming to the following schema:\n{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"comments\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"file_path\": {\n            \"type\": \"string\",\n            \"description\": \"The path to the file where the comment should be added.\"\n          },\n          \"line\": {\n            \"type\": \"integer\",\n            \"description\": \"The line number where the comment should be added. \"\n          },\n          \"comment\": {\n            \"type\": \"string\",\n            \"description\": \"The content of the comment.\"\n          }\n        },\n        \"required\": [\"file_name\", \"line\", \"comment\"]\n      }\n    }\n  },\n  \"required\": [\"comments\"]\n}\n\nEnsure response is valid JSON conforming to the following schema."
  },
  {
    "path": "superagi/tools/github/review_pull_request.py",
    "content": "import ast\nfrom typing import Type, Optional\n\nfrom pydantic import BaseModel, Field\nfrom superagi.helper.error_handler import ErrorHandler\n\nfrom superagi.helper.github_helper import GithubHelper\nfrom superagi.helper.json_cleaner import JsonCleaner\nfrom superagi.helper.prompt_reader import PromptReader\nfrom superagi.helper.token_counter import TokenCounter\nfrom superagi.llms.base_llm import BaseLlm\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nfrom superagi.tools.base_tool import BaseTool\n\n\nclass GithubReviewPullRequestSchema(BaseModel):\n    repository_name: str = Field(\n        ...,\n        description=\"Repository name in which file hase to be added\",\n    )\n    repository_owner: str = Field(\n        ...,\n        description=\"Owner of the github repository\",\n    )\n    pull_request_number: int = Field(\n        ...,\n        description=\"Pull request number\",\n    )\n\n\nclass GithubReviewPullRequest(BaseTool):\n    \"\"\"\n    Reviews the github pull request and adds comments inline\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    llm: Optional[BaseLlm] = None\n    name: str = \"Github Review Pull Request\"\n    args_schema: Type[BaseModel] = GithubReviewPullRequestSchema\n    description: str = \"Add pull request for the github repository\"\n    agent_id: int = None\n    agent_execution_id: int = None\n\n    def _execute(self, repository_name: str, repository_owner: str, pull_request_number: int) -> str:\n        \"\"\"\n        Execute the add file tool.\n\n        Args:\n            repository_name: The name of the repository to add file to.\n            repository_owner: Owner of the GitHub repository.\n            pull_request_number: pull request number\n\n        Returns:\n            Pull request success message if pull request is created successfully else error message.\n        \"\"\"\n        try:\n            github_access_token = self.get_tool_config(\"GITHUB_ACCESS_TOKEN\")\n            github_username = self.get_tool_config(\"GITHUB_USERNAME\")\n            github_helper = GithubHelper(github_access_token, github_username)\n\n            pull_request_content = github_helper.get_pull_request_content(repository_owner, repository_name,\n                                                                          pull_request_number)\n            latest_commit_id = github_helper.get_latest_commit_id_of_pull_request(repository_owner, repository_name,\n                                                                                  pull_request_number)\n\n            pull_request_arr = pull_request_content.split(\"diff --git\")\n            organisation = Agent.find_org_by_agent_id(session=self.toolkit_config.session, agent_id=self.agent_id)\n\n            model_token_limit = TokenCounter(session=self.toolkit_config.session,\n                                       organisation_id=organisation.id).token_limit(self.llm.get_model())\n            pull_request_arr_parts = self.split_pull_request_content_into_multiple_parts(model_token_limit, pull_request_arr)\n            for content in pull_request_arr_parts:\n                self.run_code_review(github_helper, content, latest_commit_id, organisation, pull_request_number,\n                                     repository_name, repository_owner)\n            return \"Added comments to the pull request:\" + str(pull_request_number)\n        except Exception as err:\n            return f\"Error: Unable to add comments to the pull request {err}\"\n\n    def run_code_review(self, github_helper, content, latest_commit_id, organisation, pull_request_number,\n                        repository_name, repository_owner):\n        prompt = PromptReader.read_tools_prompt(__file__, \"code_review.txt\")\n        prompt = prompt.replace(\"{{DIFF_CONTENT}}\", content)\n        messages = [{\"role\": \"system\", \"content\": prompt}]\n        total_tokens = TokenCounter.count_message_tokens(messages, self.llm.get_model())\n        token_limit = TokenCounter(session=self.toolkit_config.session,\n                                   organisation_id=organisation.id).token_limit(self.llm.get_model())\n        result = self.llm.chat_completion(messages, max_tokens=(token_limit - total_tokens - 100))\n        \n        if 'error' in result and result['message'] is not None:\n            ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message'])\n        response = result[\"content\"]\n        if response.startswith(\"```\") and response.endswith(\"```\"):\n            response = \"```\".join(response.split(\"```\")[1:-1])\n        response = JsonCleaner.extract_json_section(response)\n        comments = ast.literal_eval(response)\n\n        # Add comments in the pull request\n        for comment in comments['comments']:\n            line_number = self.get_exact_line_number(content, comment[\"file_path\"], comment[\"line\"])\n            github_helper.add_line_comment_to_pull_request(repository_owner, repository_name, pull_request_number,\n                                                           latest_commit_id, comment[\"file_path\"], line_number,\n                                                           comment[\"comment\"])\n\n    def split_pull_request_content_into_multiple_parts(self, model_token_limit: int, pull_request_arr):\n        pull_request_arr_parts = []\n        current_part = \"\"\n        for part in pull_request_arr:\n            total_tokens = TokenCounter.count_message_tokens([{\"role\": \"user\", \"content\": current_part}],\n                                                             self.llm.get_model())\n            # we are using 60% of the model token limit\n            if total_tokens >= model_token_limit * 0.6:\n                # Add the current part to pull_request_arr_parts and reset current_sum and current_part\n                pull_request_arr_parts.append(current_part)\n                current_part = \"diff --git\" + part\n            else:\n                current_part += \"diff --git\" + part\n\n        pull_request_arr_parts.append(current_part)\n        return pull_request_arr_parts\n\n    def get_exact_line_number(self, diff_content, file_path, line_number):\n        last_content = diff_content[diff_content.index(file_path):]\n        last_content = last_content[last_content.index('@@'):]\n        return self.find_position_in_diff(last_content, line_number)\n\n    def find_position_in_diff(self, diff_content, target_line):\n        # Split the diff by lines and initialize variables\n        diff_lines = diff_content.split('\\n')\n        position = 0\n        current_file_line_number = 0\n\n        # Loop through each line in the diff\n        for line in diff_lines:\n            position += 1  # Increment position for each line\n            if line.startswith('@@'):\n                # Reset the current file line number when encountering a new hunk\n                current_file_line_number = int(line.split('+')[1].split(',')[0]) - 1\n            elif not line.startswith('-'):\n                # Increment the current file line number for lines that are not deletions\n                current_file_line_number += 1\n            if current_file_line_number >= target_line:\n                # Return the position when the target line number is reached\n                return position\n        return position\n"
  },
  {
    "path": "superagi/tools/github/search_repo.py",
    "content": "from typing import Type\n\nfrom pydantic import BaseModel, Field\nfrom superagi.helper.github_helper import GithubHelper\nfrom superagi.tools.base_tool import BaseTool\n\n\nclass GithubSearchRepoSchema(BaseModel):\n    repository_name: str = Field(\n        ...,\n        description=\"Repository name in which we have to search\",\n    )\n    repository_owner: str = Field(\n        ...,\n        description=\"Owner of the github repository\",\n    )\n    file_name: str = Field(\n        ...,\n        description=\"Name of the file we need to fetch from the repository\",\n    )\n    folder_path: str = Field(\n        ...,\n        description=\"folder path in which file is present\",\n    )\n\n\nclass GithubRepoSearchTool(BaseTool):\n    \"\"\"\n    Search File tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    name = \"GithubRepo Search\"\n    description = (\n        \"Search for a file inside a Github repository\"\n    )\n    args_schema: Type[GithubSearchRepoSchema] = GithubSearchRepoSchema\n\n    def _execute(self, repository_owner: str, repository_name: str, file_name: str, folder_path=None) -> str:\n        \"\"\"\n        Execute the search file tool.\n\n        Args:\n            repository_owner : The owner of the repository to search file in.\n            repository_name : The name of the repository to search file in.\n            file_name : The name of the file to search.\n            folder_path : The path of the folder to search the file in.\n\n        Returns:\n            The content of the github file.\n        \"\"\"\n        github_access_token = self.get_tool_config(\"GITHUB_ACCESS_TOKEN\")\n        github_username = self.get_tool_config(\"GITHUB_USERNAME\")\n        github_repo_search = GithubHelper(github_access_token, github_username)\n        try:\n            content = github_repo_search.get_content_in_file(repository_owner, repository_name, file_name, folder_path)\n            return content\n        except:\n            return \"File not found\"\n"
  },
  {
    "path": "superagi/tools/google_calendar/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://superagi.com//#gh-light-mode-only\">\n    <img src=\"https://superagi.com/wp-content/uploads/2023/05/Logo-dark.svg\" width=\"318px\" alt=\"SuperAGI logo\" />\n  </a>\n  <a href=\"https://superagi.com//#gh-dark-mode-only\">\n    <img src=\"https://superagi.com/wp-content/uploads/2023/05/Logo-light.svg\" width=\"318px\" alt=\"SuperAGI logo\" />\n  </a>\n</p>\n\n# SuperAGI - Google Calendar Toolkit\n\nIntroducing the Google Calendar Toolkit, a powerful integration for SuperAGI. With the Google Calendar toolkit, you have the ability to do the following:\n\n1. **Create Calendar Events**\n2. **List your Calendar Events**\n3. **Fetch an event from your Calendar**\n4. **Delete Calendar Events**\n\n## ⚙️ Installation\n\n### ⚒️ Setting up of SuperAGI\n\nSet up SuperAGI by following the instructions given [here](https://github.com/TransformerOptimus/SuperAGI/blob/main/README.MD)\n\n# ✅ Quickstart Guide:\n\nIn order to get started with integrating Google Calendar with SuperAGI, you need to do the following:\n\n## API Creation and OAuth Consent Screen\n\n1. Go to Google Developer Console:\n[https://console.cloud.google.com/](https://console.cloud.google.com/) & Create a new project. If you’re having an existing project, you can proceed with that as well:\n\n![GC1](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/9cd9040c-84ac-425b-8aa2-2cf6ea33fd43)\n\n2. After the project is created/you’re in your selected project, head to “APIs and Services”\n\n![GC2](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/18763990-5cd2-476d-8b41-ce195e218bd2)\n\n3. Click on “ENABLED APIS AND SERVICES” and search for “Google Calendar”\n\n![GC3](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/b88fcf5d-793d-4add-af98-ef8457239b03)\n![GC4](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/35480885-7b2e-4bb6-842b-68a00117b02d)\n\n4. Enable the API\n   \n![GC5](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/ad0dbec0-0177-484a-985d-c8c7f48fe667)\n\n5. Once the API is Enabled, go to “OAuth Consent Screen” \n\n![GC6](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/b0eb2e92-b837-4d46-82fc-5c392529c676)\n\n6. Select your User Type as “External” and click on \"Create\"\n\n![GC7](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/866553cd-d670-4dea-988b-222ca4577b71)\n\n7. Fill in the required details such as the App Information, App Domain, Authorized Domain, and Developer contact information. Once filled in, click “Save and Continue” \n\n![GC8](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/d06b0f19-8a3c-4d61-b03a-c15a8df678da)\n\n8. On the next page, you don’t need to select the scopes. Proceed to “save and continue” and at the final page, review the process and click “Back to Dashboard”.  With this, you’ve created your OAuth Consent Screen for Google Calendar.\n   \n9. You can go ahead and click the “Publish App” \n\n![GC9](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/5f75c29b-90fa-4879-bc32-0373f748e0dd)\n\n## 🔧 Configuring endpoints & obtaining Client ID and Client Secret Key\n\nIn order to obtain the Client ID and Secret ID, you need to do the following steps: \n\n1. Go to “Credentials” Page\n\n![GC10](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/4a28b0fe-9fd4-444f-8456-f07cf9df5f45)\n\n2. Click on “Create Credentials” and click on “OAuth Client ID”\n\n![GC11](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/389dc30a-0468-48a2-8056-1dd989e3021c)\n\n![GC12](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/7798d795-1773-4b3f-b955-6bf93f827613)\n\n3. Once you click on OAuth Client ID, choose the type of application as “Web Application” and give it a name of your choice\n\n![GC13](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/ee171a3c-2036-4969-a1d0-2af4d7b4010f)\n\n4. Create JavaScript Origins and add the following details as shown in the image: \n\n![GC14](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/d2292b25-ce32-4d3d-903c-1ca9341163fb)\n\n5. Go to Authorized redirect URIs and add the following URIs: \n`https://app.superagi.com/api/google/oauth-tokens`\n`http://localhost:3000/api/google/oauth-tokens`\n\n![Google_OAuth_URI](https://github.com/Phoenix2809/SuperAGI/assets/133874957/9f7bd411-7173-4550-9bfd-0f3cf95dad54)\n\n6. Once you have added the Authorized redirect URIs, you can click “Create” to obtain the Client ID and Client Secret Key\n\n![GC16](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/46c106aa-2ad6-470c-bbd5-c1c1a4f64205)\n\n7. Copy the Client ID and Secret Key and save it in a file. \n\n## Configuring your Client ID, Secret Key and Authenticating Calendar with SuperAGI\n\nOnce the ClientID and Secret Key are obtained, you can configure and authorize Calendar to be used with SuperAGI by following these steps: \n\n1. Add your Client ID and Client Secret Key on the toolkit page and click on “Update Changes”\n\n![GC_17](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/911f57b7-c977-45d6-bcaf-ee77430e8628)\n\n2. Click on “Authenticate Tool” - which will now take you to the OAuth Flow. \n\nOnce the OAuth Authentication is complete, you can now start using SuperAGI Agents with Google Calendar!\n"
  },
  {
    "path": "superagi/tools/google_calendar/create_calendar_event.py",
    "content": "from typing import Any, Type\nfrom pydantic import BaseModel, Field\nfrom superagi.tools.base_tool import BaseTool\nfrom sqlalchemy.orm import sessionmaker\nfrom superagi.models.db import connect_db\nfrom superagi.helper.google_calendar_creds import GoogleCalendarCreds\nfrom superagi.helper.calendar_date import CalendarDate\n\nclass CreateEventCalendarInput(BaseModel):\n    event_name: str = Field(..., description=\"Name of the event/meeting to be scheduled, if not given craete a name depending on description.\")\n    description: str = Field(..., description=\"Description of the event/meeting to be scheduled.\")\n    start_date: str = Field(..., description=\"Start date of the event to be scheduled in format 'yyyy-mm-dd', if no value is given keep the default value as 'None'.\")\n    start_time: str = Field(..., description=\"Start time of the event to be scheduled in format 'hh:mm:ss', if no value is given keep the default value as 'None'.\")\n    end_date: str = Field(..., description=\"End Date of the event to be scheduled in format 'yyyy-mm-dd', if no value is given keep the default value as 'None'.\")\n    end_time: str = Field(..., description=\"End Time of the event to be scheduled in format 'hh:mm:ss', if no value is given keep the default value as 'None'.\")\n    attendees: list = Field(..., description=\"List of attendees email ids to be invited for the event.\")\n    location: str = Field(..., description=\"Geographical location of the event. if no value is given keep the default value as 'None'\")\n\nclass CreateEventCalendarTool(BaseTool):\n    name: str = \"Create Google Calendar Event\"\n    args_schema: Type[BaseModel] = CreateEventCalendarInput\n    description: str = \"Create an event for Google Calendar\"\n\n    def _execute(self, event_name: str, description: str, attendees: list, start_date: str = 'None', start_time: str = 'None', end_date: str = 'None', end_time: str = 'None', location: str = 'None'):\n        session = self.toolkit_config.session\n        toolkit_id = self.toolkit_config.toolkit_id\n        service = GoogleCalendarCreds(session).get_credentials(toolkit_id)\n        if service[\"success\"]:\n            service = service[\"service\"]\n        else:\n            return f\"Kindly connect to Google Calendar\"\n        date_utc = CalendarDate().create_event_dates(service, start_date, start_time, end_date, end_time)\n        attendees_list = []\n        for attendee in attendees:\n            email_id = {\n                \"email\": attendee\n            }\n            attendees_list.append(email_id)\n        event = {\n            \"summary\": event_name,\n            \"description\": description,\n            \"start\": {\n                \"dateTime\": date_utc[\"start_datetime_utc\"],\n                \"timeZone\": date_utc[\"timeZone\"]\n            },\n            \"end\": {\n                \"dateTime\": date_utc[\"end_datetime_utc\"],\n                \"timeZone\": date_utc[\"timeZone\"]\n            },\n            \"attendees\": attendees_list\n        }\n        if location != \"None\":\n            event[\"location\"] = location\n        else:\n            event[\"conferenceData\"] = {\n                \"createRequest\": {\n                    \"requestId\": f\"meetSample123\",\n                    \"conferenceSolutionKey\": {\n                        \"type\": \"hangoutsMeet\"\n                    },\n                },\n            }\n        event = service.events().insert(calendarId=\"primary\", body=event, conferenceDataVersion=1).execute()\n        output_str = f\"Event {event_name} at {date_utc['start_datetime_utc']} created successfully, link for the event {event.get('htmlLink')}\"\n        return output_str\n"
  },
  {
    "path": "superagi/tools/google_calendar/delete_calendar_event.py",
    "content": "import base64\nfrom typing import Any, Type\nfrom pydantic import BaseModel, Field\nfrom superagi.tools.base_tool import BaseTool\nfrom sqlalchemy.orm import sessionmaker\nfrom superagi.models.db import connect_db\nfrom superagi.helper.google_calendar_creds import GoogleCalendarCreds\n\nclass DeleteCalendarEventInput(BaseModel):\n    event_id: str = Field(..., description=\"The id of event to be deleted from Google Calendar. default value is None\")\n\nclass DeleteCalendarEventTool(BaseTool):\n    name: str = \"Delete Google Calendar Event\"\n    args_schema: Type[BaseModel] = DeleteCalendarEventInput\n    description: str = \"Delete an event from Google Calendar\"\n\n\n\n    def _execute(self, event_id: str):\n        service = GoogleCalendarCreds(self.toolkit_config.session).get_credentials(self.toolkit_config.toolkit_id)\n        if service[\"success\"]:\n            service = service[\"service\"]\n        else:\n            return f\"Kindly connect to Google Calendar\"\n        if event_id == \"None\":\n            return f\"Add Event ID to delete an event from Google Calendar\"\n        else:\n            if len(event_id) % 4 != 0:  \n                event_id += \"=\" * (4 - (len(event_id) % 4))  \n            decoded_id = base64.b64decode(event_id)\n            eid = decoded_id.decode(\"utf-8\")\n            eid  = eid.split(\" \", 1)[0]\n            result = service.events().delete(\n                calendarId = \"primary\",\n                eventId = eid\n            ).execute()\n            return f\"Event Successfully deleted from your Google Calendar\"\n"
  },
  {
    "path": "superagi/tools/google_calendar/event_details_calendar.py",
    "content": "import base64\nfrom typing import Any, Type\nfrom pydantic import BaseModel, Field\nfrom sqlalchemy.orm import sessionmaker\nfrom superagi.models.db import connect_db\nfrom superagi.tools.base_tool import BaseTool\nfrom superagi.helper.google_calendar_creds import GoogleCalendarCreds\n\nclass EventDetailsCalendarInput(BaseModel):\n    event_id: str = Field(..., description=\"The id of event to be fetched from Google Calendar. if no value is given keep default value is None\")\n\nclass EventDetailsCalendarTool(BaseTool):\n    name: str = \"Fetch Google Calendar Event\"\n    args_schema: Type[BaseModel] = EventDetailsCalendarInput\n    description: str = \"Fetch an event from Google Calendar\"\n\n    def _execute(self, event_id: str):\n        service = GoogleCalendarCreds(self.toolkit_config.session).get_credentials(self.toolkit_config.toolkit_id)\n        if service[\"success\"]:\n            service = service[\"service\"]\n        else:\n            return f\"Kindly connect to Google Calendar\"\n        if event_id == \"None\":\n            return f\"Add Event ID to fetch details of an event from Google Calendar\"\n        else:\n            if len(event_id) % 4 != 0:  \n                event_id += \"=\" * (4 - (len(event_id) % 4))  \n            decoded_id = base64.b64decode(event_id)\n            eid = decoded_id.decode(\"utf-8\")\n            eid  = eid.split(\" \", 1)[0]\n            result = service.events().get(\n                calendarId = \"primary\",\n                eventId = eid\n            ).execute()\n            if \"summary\" in result:\n                summary = result['summary']\n            if result['start'] and result['end']:\n                start_date = result['start']['dateTime']\n                end_date = result['end']['dateTime']\n            attendees = []\n            if \"attendees\" in result:\n                for attendee in result['attendees']:\n                    attendees.append(attendee['email'])\n            attendees_str = ','.join(attendees)\n            output_str = f\"Event details for the event id '{event_id}' is - \\nSummary : {summary}\\nStart Date and Time : {start_date}\\nEnd Date and Time : {end_date}\\nAttendees : {attendees_str}\"\n            return output_str"
  },
  {
    "path": "superagi/tools/google_calendar/google_calendar_toolkit.py",
    "content": "from abc import ABC\nfrom superagi.tools.base_tool import BaseToolkit, BaseTool, ToolConfiguration\nfrom typing import Type, List\nfrom superagi.tools.google_calendar.create_calendar_event import CreateEventCalendarTool\nfrom superagi.tools.google_calendar.delete_calendar_event import DeleteCalendarEventTool\nfrom superagi.tools.google_calendar.list_calendar_events import ListCalendarEventsTool\nfrom superagi.tools.google_calendar.event_details_calendar import EventDetailsCalendarTool\nfrom superagi.types.key_type import ToolConfigKeyType\n\nclass GoogleCalendarToolKit(BaseToolkit, ABC):\n    name: str = \"Google Calendar Toolkit\"\n    description: str = \"Google Calendar Tool kit contains all tools related to Google Calendar\"\n\n    def get_tools(self) -> List[BaseTool]:\n        return [CreateEventCalendarTool(), DeleteCalendarEventTool(), ListCalendarEventsTool(), EventDetailsCalendarTool()]\n\n    def get_env_keys(self) -> List[ToolConfiguration]:\n        return [\n            ToolConfiguration(key=\"GOOGLE_CLIENT_ID\", key_type=ToolConfigKeyType.STRING, is_required= True, is_secret = False),\n            ToolConfiguration(key=\"GOOGLE_CLIENT_SECRET\", key_type=ToolConfigKeyType.STRING, is_required= True, is_secret= True)\n        ]\n    "
  },
  {
    "path": "superagi/tools/google_calendar/list_calendar_events.py",
    "content": "import os\nimport csv\nfrom datetime import datetime\nfrom typing import Type\nfrom superagi.config.config import get_config\nfrom pydantic import BaseModel, Field\nfrom superagi.tools.base_tool import BaseTool\nfrom superagi.helper.google_calendar_creds import GoogleCalendarCreds\nfrom superagi.helper.calendar_date import CalendarDate\nfrom superagi.resource_manager.file_manager import FileManager\nfrom superagi.helper.s3_helper import S3Helper\nfrom urllib.parse import urlparse, parse_qs\nfrom sqlalchemy.orm import sessionmaker\nfrom superagi.models.db import connect_db\nfrom superagi.lib.logger import logger\n\n\nclass ListCalendarEventsInput(BaseModel):\n    start_time: str = Field(..., description=\"A string variable storing the start time to return events from the calendar in format 'HH:MM:SS'. if no value is given keep default value as 'None'\")\n    start_date: str = Field(..., description=\"A string variable storing the start date to return events from the calendar in format 'yyyy-mm-dd' in a string variable, if no value is given keep default value as 'None'.\")\n    end_date: str = Field(..., description=\"A string variable storing the end date to return events from the calendar in format 'yyyy-mm-dd' in a string variable, if no value is given keep default value as 'None'.\")\n    end_time: str = Field(..., description=\"A string variable storing the end time to return events from the calendar in format 'HH:MM:SS'. if no value is given keep default value as 'None'\")\n\n\nclass ListCalendarEventsTool(BaseTool):\n    name: str = \"List Google Calendar Events\"\n    args_schema: Type[BaseModel] = ListCalendarEventsInput\n    description: str = \"Get the list of all the events from Google Calendar\"\n    agent_id: int  = None\n    resource_manager: FileManager = None\n\n    def _execute(self, start_time: str = 'None', start_date: str = 'None', end_date: str = 'None', end_time: str = 'None'):\n        service = self.get_google_calendar_service()\n        if not service[\"success\"]:\n            return f\"Kindly connect to Google Calendar\"\n        \n        date_utc = CalendarDate().get_date_utc(start_date, end_date, start_time, end_time, service[\"service\"])\n        event_results = self.get_event_results(service[\"service\"], date_utc)\n        if not event_results:\n            return f\"No events found for the given date and time range.\"\n        \n        csv_data = self.generate_csv_data(event_results)\n        file_name = self.create_output_file()\n        if file_name is not None:\n            self.resource_manager.write_csv_file(file_name, csv_data)\n        return f\"List of Google Calendar Events month successfully stored in {file_name}.\"\n\n    def get_google_calendar_service(self):\n        return GoogleCalendarCreds(self.toolkit_config.session).get_credentials(self.toolkit_config.toolkit_id)\n\n    def get_event_results(self, service, date_utc):\n        return (\n            service.events().list(\n            calendarId=\"primary\",\n            timeMin=date_utc['start_datetime_utc'],\n            timeMax=date_utc['end_datetime_utc'],\n            singleEvents=True,\n            orderBy=\"startTime\",\n            ).execute()\n        )\n\n    def generate_csv_data(self, event_results):\n        csv_data = [['Event ID', 'Event Name', 'Start Time', 'End Time', 'Attendees']]\n        for item in event_results['items']:\n            event_id, summary, start_date, end_date, attendees_str = self.parse_event_data(item)\n            csv_data.append([event_id, summary, start_date, end_date, attendees_str])\n        return csv_data\n\n    def parse_event_data(self, item):\n        eid_url = item[\"htmlLink\"]\n        parsed_url = urlparse(eid_url)\n        query_parameters = parse_qs(parsed_url.query)\n        event_id = query_parameters.get('eid', [None])[0]\n        summary = item.get('summary', '')\n        start_date = item['start'].get('dateTime', '')\n        end_date = item['end'].get('dateTime', '')\n        attendees = [attendee['email'] for attendee in item.get('attendees', [])]\n        attendees_str = ','.join(attendees)\n        return event_id, summary, start_date, end_date, attendees_str\n\n    def create_output_file(self):\n        file = datetime.now()\n        file = file.strftime(\"%Y-%m-%dT%H:%M:%S.%fZ\")\n        file_name = \"Google_Calendar_\" + file + \".csv\"\n        return file_name\n"
  },
  {
    "path": "superagi/tools/google_search/README.MD",
    "content": "<p align=center>\n<a href=\"https://superagi.co\"><img src=https://superagi.co/wp-content/uploads/2023/05/SuperAGI_icon.png></a>\n</p>\n\n# SuperAGI Google Search Tool\n\nThe SuperAGI Google Search Tool helps users perform a Google search and extract snippets and webpages.\n\n## ⚙️ Installation\n\n### 🛠 **Setting Up of SuperAGI**\nSet up the SuperAGI by following the instructions given (https://github.com/TransformerOptimus/SuperAGI/blob/main/README.MD)\n\nIf you've put the correct Google API key and Custom Search Engine ID, you'll be able to use the Google Search Tool as well.\n\n## Running SuperAGI Google Search Tool\n\nYou can simply ask your agent about latest information regarding anything in the world and your agent will be able to browse the internet to get that information for you. "
  },
  {
    "path": "superagi/tools/google_search/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/tools/google_search/google_search.py",
    "content": "import json\nfrom typing import Type, Optional\n\nfrom pydantic import BaseModel, Field\nfrom superagi.helper.error_handler import ErrorHandler\n\nfrom superagi.helper.google_search import GoogleSearchWrap\nfrom superagi.helper.token_counter import TokenCounter\nfrom superagi.llms.base_llm import BaseLlm\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nfrom superagi.tools.base_tool import BaseTool\n\nclass GoogleSearchSchema(BaseModel):\n    query: str = Field(\n        ...,\n        description=\"The search query for Google search.\",\n    )\n\nclass GoogleSearchTool(BaseTool):\n    \"\"\"\n    Google Search tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    llm: Optional[BaseLlm] = None\n    name = \"GoogleSearch\"\n    agent_id: int = None\n    agent_execution_id: int = None\n    description = (\n        \"A tool for performing a Google search and extracting snippets and webpages.\"\n        \"Input should be a search query.\"\n    )\n    args_schema: Type[GoogleSearchSchema] = GoogleSearchSchema\n\n    class Config:\n        arbitrary_types_allowed = True\n\n    def _execute(self, query: str) -> tuple:\n        \"\"\"\n        Execute the Google search tool.\n\n        Args:\n            query : The query to search for.\n\n        Returns:\n            Search result summary along with related links\n        \"\"\"\n        api_key = self.get_tool_config(\"GOOGLE_API_KEY\")\n        search_engine_id = self.get_tool_config(\"SEARCH_ENGINE_ID\")\n        num_results = 10\n        num_pages = 1\n        num_extracts = 3\n\n        google_search = GoogleSearchWrap(api_key, search_engine_id, num_results, num_pages, num_extracts)\n        snippets, webpages, links = google_search.get_result(query)\n\n        results = []\n        i = 0\n        for webpage in webpages:\n            results.append({\"title\": snippets[i], \"body\": webpage, \"links\": links[i]})\n            i += 1\n            if TokenCounter.count_text_tokens(json.dumps(results)) > 3000:\n                break\n        summary = self.summarise_result(query, results)\n        links = [result[\"links\"] for result in results if len(result[\"links\"]) > 0]\n        if len(links) > 0:\n            return summary + \"\\n\\nLinks:\\n\" + \"\\n\".join(\"- \" + link for link in links[:3])\n        return summary\n\n    def summarise_result(self, query, snippets):\n        \"\"\"\n        Summarise the result of a Google search.\n\n        Args:\n            query : The query to search for.\n            snippets (list): A list of snippets from the search.\n\n        Returns:\n            A summary of the search result.\n        \"\"\"\n        summarize_prompt =\"\"\"Summarize the following text `{snippets}`\n            Write a concise or as descriptive as necessary and attempt to\n            answer the query: `{query}` as best as possible. Use markdown formatting for\n            longer responses.\"\"\"\n\n        summarize_prompt = summarize_prompt.replace(\"{snippets}\", str(snippets))\n        summarize_prompt = summarize_prompt.replace(\"{query}\", query)\n\n        messages = [{\"role\": \"system\", \"content\": summarize_prompt}]\n        result = self.llm.chat_completion(messages, max_tokens=self.max_token_limit)\n        \n        if 'error' in result and result['message'] is not None:\n            ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message'])\n        return result[\"content\"]\n"
  },
  {
    "path": "superagi/tools/google_search/google_search_toolkit.py",
    "content": "from abc import ABC\nfrom typing import List\nfrom superagi.tools.base_tool import BaseTool, BaseToolkit, ToolConfiguration\nfrom superagi.tools.google_search.google_search import GoogleSearchTool\nfrom superagi.models.tool_config import ToolConfig\nfrom superagi.types.key_type import ToolConfigKeyType\n\n\nclass GoogleSearchToolkit(BaseToolkit, ABC):\n    name: str = \"Google Search Toolkit\"\n    description: str = \"Toolkit containing tools for performing Google search and extracting snippets and webpages\"\n\n    def get_tools(self) -> List[BaseTool]:\n        return [GoogleSearchTool()]\n\n    def get_env_keys(self) -> List[ToolConfiguration]:\n        return [\n            ToolConfiguration(key=\"GOOGLE_API_KEY\", key_type=ToolConfigKeyType.STRING, is_required= True, is_secret = True),\n            ToolConfiguration(key=\"SEARCH_ENGINE_ID\", key_type=ToolConfigKeyType.STRING, is_required=True, is_secret=True)\n        ]\n"
  },
  {
    "path": "superagi/tools/google_serp_search/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://superagi.com//#gh-light-mode-only\">\n    <img src=\"https://superagi.com/wp-content/uploads/2023/05/Logo-dark.svg\" width=\"318px\" alt=\"SuperAGI logo\" />\n  </a>\n  <a href=\"https://superagi.com//#gh-dark-mode-only\">\n    <img src=\"https://superagi.com/wp-content/uploads/2023/05/Logo-light.svg\" width=\"318px\" alt=\"SuperAGI logo\" />\n  </a>\n</p>\n\n# SuperAGI Google SERP Search Toolkit\n\nThe SuperAGI Google Search Toolkit helps users perform a Google search and extract snippets and webpages.\n\n## ⚙️ Installation\n\n### 🛠 **Setting Up of SuperAGI**\nSet up the SuperAGI by following the instructions given (https://github.com/TransformerOptimus/SuperAGI/blob/main/README.MD)\n\n### 🔧 **Add Google Serp Search API Key in SuperAGI Dashboard**\n\n1. Register an account at [https://serper.dev/](https://serper.dev/) with your Email ID. \n\n2. Your Private API Key would be made. Copy that and save it in a separate text file.\n\n![Serper_Key](https://github.com/Phoenix2809/SuperAGI/assets/133874957/dfe70b4f-11e2-483b-aa33-07b15150103d)\n\n\n3. Open up the Google SERP Toolkit page in SuperAGI's Dashboard and paste your Private API Key. \n\n## Running SuperAGI Google Search Serp Tool\n\nYou can simply ask your agent about the latest information regarding anything and your agent will be able to browse the internet to get that information for you. \n"
  },
  {
    "path": "superagi/tools/google_serp_search/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/tools/google_serp_search/google_serp_search.py",
    "content": "from typing import Type, Optional, Any\nfrom pydantic import BaseModel, Field\nimport aiohttp\nfrom superagi.helper.error_handler import ErrorHandler\nfrom superagi.helper.google_serp import GoogleSerpApiWrap\nfrom superagi.llms.base_llm import BaseLlm\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nfrom superagi.tools.base_tool import BaseTool\nimport os\n\nimport json\n\n\nclass GoogleSerpSchema(BaseModel):\n    query: str = Field(\n        ...,\n        description=\"The search query for Google SERP.\",\n    )\n\n\n'''Google search using serper.dev. Use server.dev api keys'''\nclass GoogleSerpTool(BaseTool):\n    \"\"\"\n    Google Search tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    llm: Optional[BaseLlm] = None\n    name = \"GoogleSerp\"\n    agent_id: int = None\n    agent_execution_id: int = None\n    description = (\n        \"A tool for performing a Google SERP search and extracting snippets and webpages.\"\n        \"Input should be a search query.\"\n    )\n    args_schema: Type[GoogleSerpSchema] = GoogleSerpSchema\n\n    class Config:\n        arbitrary_types_allowed = True\n\n    def _execute(self, query: str) -> tuple:\n        \"\"\"\n        Execute the Google search tool.\n\n        Args:\n            query : The query to search for.\n\n        Returns:\n            Search result summary along with related links\n        \"\"\"\n        api_key = self.get_tool_config(\"SERP_API_KEY\")\n        serp_api = GoogleSerpApiWrap(api_key)\n        response = serp_api.search_run(query)\n        summary = self.summarise_result(query, response[\"snippets\"])\n        if response[\"links\"]:\n            return summary + \"\\n\\nLinks:\\n\" + \"\\n\".join(\"- \" + link for link in response[\"links\"][:3])\n        return summary\n\n    def summarise_result(self, query, snippets):\n        summarize_prompt = \"\"\"Summarize the following text `{snippets}`\n            Write a concise or as descriptive as necessary and attempt to\n            answer the query: `{query}` as best as possible. Use markdown formatting for\n            longer responses.\"\"\"\n\n        summarize_prompt = summarize_prompt.replace(\"{snippets}\", str(snippets))\n        summarize_prompt = summarize_prompt.replace(\"{query}\", query)\n\n        messages = [{\"role\": \"system\", \"content\": summarize_prompt}]\n        result = self.llm.chat_completion(messages, max_tokens=self.max_token_limit)\n        \n        if 'error' in result and result['message'] is not None:\n            ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message'])\n        return result[\"content\"]\n"
  },
  {
    "path": "superagi/tools/google_serp_search/google_serp_search_toolkit.py",
    "content": "from abc import ABC\nfrom typing import List\nfrom superagi.tools.base_tool import BaseTool, BaseToolkit, ToolConfiguration\nfrom superagi.tools.google_serp_search.google_serp_search import GoogleSerpTool\nfrom superagi.models.tool_config import ToolConfig\nfrom superagi.types.key_type import ToolConfigKeyType\n\nclass GoogleSerpToolkit(BaseToolkit, ABC):\n    name: str = \"Google SERP Toolkit\"\n    description: str = \"Toolkit containing tools for performing Google SERP search and extracting snippets and webpages\"\n\n    def get_tools(self) -> List[BaseTool]:\n        return [GoogleSerpTool()]\n\n    def get_env_keys(self) -> List[ToolConfiguration]:\n        return [\n            ToolConfiguration(key=\"SERP_API_KEY\", key_type=ToolConfigKeyType.STRING, is_required= True, is_secret = True)\n        ]\n"
  },
  {
    "path": "superagi/tools/image_generation/README.MD",
    "content": "<p align=center>\n<a href=\"https://superagi.co\"><img src=https://superagi.co/wp-content/uploads/2023/05/SuperAGI_icon.png></a>\n</p>\n\n# SuperAGI Image Generation Tool\n\nThe SuperAGI Image Generation Tool helps you generate an image with a prompt using DALL-E.\n\n## ⚙️ Installation\n\n### 🛠 **Setting Up of SuperAGI**\nSet up the SuperAGI by following the instructions given (https://github.com/TransformerOptimus/SuperAGI/blob/main/README.MD)\n\nIf you've put the correct OpenAI key during the installation, you'd be able to use the Image Generation tool as well.\n\n## Running SuperAGI Image Generation Tool\n\nYou can simply put one of the goals of your agent to create an image and the agent will pick up the Image Generation Tool and will place it in the Output folder of the Resource Manager, from where you'll be able to download it.\n\n"
  },
  {
    "path": "superagi/tools/image_generation/README.STABLE_DIFFUSION.md",
    "content": "<p align=\"center\">\n  <a href=\"https://superagi.com//#gh-light-mode-only\">\n    <img src=\"https://superagi.com/wp-content/uploads/2023/05/Logo-dark.svg\" width=\"318px\" alt=\"SuperAGI logo\" />\n  </a>\n  <a href=\"https://superagi.com//#gh-dark-mode-only\">\n    <img src=\"https://superagi.com/wp-content/uploads/2023/05/Logo-light.svg\" width=\"318px\" alt=\"SuperAGI logo\" />\n  </a>\n</p>\n\n## SuperAGI Stable Diffusion Toolkit\n\nIntroducing Stable Diffusion Integration with SuperAGI\n\nYou can now use SuperAGI to summon Stable Diffusion to create true-to-life images which opens up a whole new range of possibilities. \n\n# ⚙️ Installation\n\n## 🛠️ Setting up SuperAGI\n\nSet up SuperAGI by following the instruction given [here](https://github.com/TransformerOptimus/SuperAGI/blob/main/README.MD)\n\n## 🔧Configuring API from DreamStudio\n\nYou can now get your API Key from Dream Studio to use Stable Diffusion by following the instructions below: \n\n1. Create an Account/Login with [DreamStudio.ai](http://DreamStudio.ai)\n\n![SD_1](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/39d8ab86-a989-4dfb-a281-1da6a835007e)\n\n2. Click on the Profile Icon at the top right which will take you to the settings page. Once you have reached the settings page, you can now get your API keys \n\n![SD_5](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/f02c5d3f-6201-42ec-9acb-230010393214)\n\n3. Copy the API Key and save it in a separate file\n\n## 🛠️Configuring Stable Diffusion with SuperAGI\n\nYou can configure SuperAGI with Stable Diffusion using the following steps:\n\n1. Navigate to the “****************Toolkit”**************** Page in SuperAGI’s Dashboard and select “****************Image Generation Toolkit”**************** \n\n![SD_4](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/cc9cc93a-08a2-4613-b010-c685079e0ed3)\n\n2. Once you’ve clicked Image Generation Toolkit, it will open a page asking you for the API Key and the Model Engine. You can enter the generated API key from Dream Studio here\n\n![SD_2](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/79c667a6-ee91-4405-9b05-37d076208172)\n\n3. If you would like to go in-depth with the model of Stable Diffusion, you can choose between the following engine IDs: \n\n- 'stable-diffusion-v1'\n- 'stable-diffusion-v1-5'\n- 'stable-diffusion-512-v2-0'\n- 'stable-diffusion-768-v2-0'\n- 'stable-diffusion-512-v2-1'\n- ’stable-diffusion-768-v2-1'\n- 'stable-diffusion-xl-beta-v2-2-2’\n\nYou have now successfully configured Stable Diffusion with SuperAGI!\n"
  },
  {
    "path": "superagi/tools/image_generation/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/tools/image_generation/dalle_image_gen.py",
    "content": "from typing import Type, Optional\n\nimport requests\nfrom pydantic import BaseModel, Field\n\nfrom superagi.image_llms.openai_dalle import OpenAiDalle\nfrom superagi.llms.base_llm import BaseLlm\nfrom superagi.resource_manager.file_manager import FileManager\nfrom superagi.models.toolkit import Toolkit\nfrom superagi.models.configuration import Configuration\nfrom superagi.tools.base_tool import BaseTool\n\nclass DalleImageGenInput(BaseModel):\n    prompt: str = Field(..., description=\"Prompt for Image Generation to be used by Dalle.\")\n    size: int = Field(..., description=\"Size of the image to be Generated. default size is 512\")\n    num: int = Field(..., description=\"Number of Images to be generated. default num is 2\")\n    image_names: list = Field(..., description=\"Image Names for the generated images, example 'image_1.png'. Only include the image name. Don't include path.\")\n\n\nclass DalleImageGenTool(BaseTool):\n    \"\"\"\n    Dalle Image Generation tool\n\n    Attributes:\n        name : Name of the tool\n        description : The description\n        args_schema : The args schema\n        agent_id : The agent id\n        resource_manager : Manages the file resources\n    \"\"\"\n    name: str = \"DalleImageGeneration\"\n    args_schema: Type[BaseModel] = DalleImageGenInput\n    description: str = \"Generate Images using Dalle\"\n    agent_id: int = None\n    agent_execution_id: int = None\n    resource_manager: Optional[FileManager] = None\n\n    # class Config:\n    #     arbitrary_types_allowed = True\n\n    def _execute(self, prompt: str, image_names: list, size: int = 512, num: int = 2):\n        \"\"\"\n        Execute the Dalle Image Generation tool.\n\n        Args:\n            prompt : The prompt for image generation.\n            size : The size of the image to be generated.\n            num : The number of images to be generated.\n            image_names (list): The name of the image to be generated.\n\n        Returns:\n            Image generated successfully message if image is generated or error message.\n        \"\"\"\n        session = self.toolkit_config.session\n        toolkit = session.query(Toolkit).filter(Toolkit.id == self.toolkit_config.toolkit_id).first()\n        organisation_id = toolkit.organisation_id\n        if size not in [256, 512, 1024]:\n            size = min([256, 512, 1024], key=lambda x: abs(x - size))\n\n        api_key = self.get_tool_config(\"OPENAI_API_KEY\")\n        if api_key is None:\n            return \"Enter your OpenAi api key in the configuration\"\n\n        response = OpenAiDalle(api_key=api_key, number_of_results=num).generate_image(\n            prompt, size)\n        response = response.__dict__\n        response = response['_previous']['data']\n        for i in range(num):\n            data = requests.get(response[i]['url']).content\n            self.resource_manager.write_binary_file(image_names[i], data)\n        return \"Images downloaded successfully\"\n"
  },
  {
    "path": "superagi/tools/image_generation/image_generation_toolkit.py",
    "content": "from abc import ABC\nfrom typing import List\n\nfrom superagi.tools.base_tool import BaseTool, BaseToolkit, ToolConfiguration\nfrom superagi.tools.image_generation.dalle_image_gen import DalleImageGenTool\nfrom superagi.tools.image_generation.stable_diffusion_image_gen import StableDiffusionImageGenTool\nfrom superagi.types.key_type import ToolConfigKeyType\n\nclass ImageGenToolkit(BaseToolkit, ABC):\n    name: str = \"Image Generation Toolkit\"\n    description: str = \"Toolkit containing a tool for generating images\"\n\n    def get_tools(self) -> List[BaseTool]:\n        return [DalleImageGenTool(), StableDiffusionImageGenTool()]\n\n    def get_env_keys(self) -> List[ToolConfiguration]:\n        return [\n            ToolConfiguration(key=\"STABILITY_API_KEY\", key_type=ToolConfigKeyType.STRING, is_required=False, is_secret = True),\n            ToolConfiguration(key=\"ENGINE_ID\", key_type=ToolConfigKeyType.STRING, is_required=False, is_secret=False),\n            ToolConfiguration(key=\"OPENAI_API_KEY\", key_type=ToolConfigKeyType.STRING, is_required=False, is_secret=True)\n        ]\n"
  },
  {
    "path": "superagi/tools/image_generation/stable_diffusion_image_gen.py",
    "content": "import base64\nfrom io import BytesIO\nfrom typing import Type, Optional\n\nimport requests\nfrom PIL import Image\nfrom pydantic import BaseModel, Field\nfrom superagi.helper.resource_helper import ResourceHelper\nfrom superagi.resource_manager.file_manager import FileManager\nfrom superagi.tools.base_tool import BaseTool\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent import Agent\n\n\nclass StableDiffusionImageGenInput(BaseModel):\n    prompt: str = Field(..., description=\"Prompt for Image Generation to be used by Stable Diffusion. The prompt should be as descriptive as possible and mention all the details of the image to be generated\")\n    height: int = Field(..., description=\"Height of the image to be Generated. default height is 512\")\n    width: int = Field(..., description=\"Width of the image to be Generated. default width is 512\")\n    num: int = Field(..., description=\"Number of Images to be generated. default num is 2\")\n    steps: int = Field(..., description=\"Number of diffusion steps to run. default steps are 50\")\n    image_names: list = Field(...,\n                              description=\"Image Names for the generated images, example 'image_1.png'. Only include the image name. Don't include path.\")\n\n\nclass StableDiffusionImageGenTool(BaseTool):\n    \"\"\"\n        Stable diffusion Image Generation tool\n\n        Attributes:\n            name : Name of the tool\n            description : The description\n            args_schema : The args schema\n            agent_id : The agent id\n            resource_manager : Manages the file resources\n        \"\"\"\n    name: str = \"Stable Diffusion Image Generation\"\n    args_schema: Type[BaseModel] = StableDiffusionImageGenInput\n    description: str = \"Generate Images using Stable Diffusion\"\n    agent_id: int = None\n    agent_execution_id: int = None\n    resource_manager: Optional[FileManager] = None\n\n    class Config:\n        arbitrary_types_allowed = True\n\n    def _execute(self, prompt: str, image_names: list, width: int = 512, height: int = 512, num: int = 2,\n                 steps: int = 50):\n        api_key = self.get_tool_config(\"STABILITY_API_KEY\")\n\n        if api_key is None:\n            return \"Error: Missing Stability API key.\"\n        response = self.call_stable_diffusion(api_key, width, height, num, prompt, steps)\n\n        if response.status_code != 200:\n            return f\"Non-200 response: {str(response.text)}\"\n\n        data = response.json()\n\n        artifacts = data['artifacts']\n        base64_strings = []\n        for artifact in artifacts:\n            base64_strings.append(artifact['base64'])\n\n        for i in range(num):\n            image_base64 = base64_strings[i]\n            img_data = base64.b64decode(image_base64)\n            final_img = Image.open(BytesIO(img_data))\n            image_format = final_img.format\n            img_byte_arr = BytesIO()\n            final_img.save(img_byte_arr, format=image_format)\n\n            self.resource_manager.write_binary_file(image_names[i], img_byte_arr.getvalue())\n\n        return f\"Images downloaded and saved successfully!!\"\n\n    def call_stable_diffusion(self, api_key, width, height, num, prompt, steps):\n        engine_id = self.get_tool_config(\"ENGINE_ID\")\n        if \"768\" in engine_id:\n            if height < 768:\n                height = 768\n            if width < 768:\n                width = 768\n        response = requests.post(\n            f\"https://api.stability.ai/v1/generation/{engine_id}/text-to-image\",\n            headers={\n                \"Content-Type\": \"application/json\",\n                \"Accept\": \"application/json\",\n                \"Authorization\": f\"Bearer {api_key}\"\n            },\n            json={\n                \"text_prompts\": [{\"text\": prompt}],\n                \"height\": height,\n                \"width\": width,\n                \"samples\": num,\n                \"steps\": steps,\n            },\n        )\n        return response\n"
  },
  {
    "path": "superagi/tools/instagram_tool/README.MD",
    "content": "<p align=center>\n<a href=\"https://superagi.co\"><img src=https://superagi.co/wp-content/uploads/2023/05/SuperAGI_icon.png></a>\n</p>\n\n# SuperAGI Instagram Tool\n\nThe SuperAGI Instagram Tool works with the stable diffusion tool, generates an image & caption based on the goals defined by the user and posts it on their instagram business account.Currently will only work on the webapp\n\n## ⚙️ Installation\n\n### 🛠 **Setting Up of SuperAGI**\nSet up the SuperAGI by following the instructions given (https://github.com/TransformerOptimus/SuperAGI/blob/main/README.MD)\n\nIf you've put the correct Google API key and Custom Search Engine ID, you'll be able to use the Google Search Tool as well.\n\n### 🔧 **Instagram tool requirements**\n\nSince the tool uses the official instagram graph API's to post media on user accounts, There are a few requirements:\n\nYou will need access to the following:\n\n    1. An Instagram Business Account or Instagram Creator Account\n    2. A Facebook Page connected to that account\n    3. A Facebook Developer account that can perform Tasks on that Page\n    4. A registered Facebook App with Basic settings configured\n\nOnce everything is set up, add the meta user access token (to be generated from facebook developer account), Facebook page ID (can be found on the facebook page connected to the instagram account under 'Page transparency' in 'About' section of the page ) and the stability API key to the correspponding toolkits.\n\nFollow the steps given in the link to set up meta requirements: (https://developers.facebook.com/docs/instagram-api/getting-started)\nFollow the link to generate stability API key: (https://dreamstudio.com/api/)\n\n### 🔧 **Configuring in SuperAGI Dashboard:**\n\n-You can add your meta user access token and facebook ID to the Instagram Toolkit Page and stability API key to the Image Generation Toolkit Page\n\n## Running SuperAGI Instagram Tool\n\nOnce everything has been set up just run/schedule an agent with the goal explaining the media to be published and add instagram tool (which will automatically add stable diffusion tool)\n\n## Warning\n\nIt is advised to run the instagram tool in restricted mode since it allows you to validate the photos generated. You can schedule agent runs (recurring runs are supported as well). Also, only one photo will be posted to your account in a run. To post multiple photos use recurring runs."
  },
  {
    "path": "superagi/tools/instagram_tool/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/tools/instagram_tool/instagram.py",
    "content": "import json\nimport urllib\nimport boto3\nimport os\nfrom superagi.config.config import get_config\nfrom superagi.helper.error_handler import ErrorHandler\nfrom superagi.helper.resource_helper import ResourceHelper\nfrom typing import Type, Optional\nfrom pydantic import BaseModel, Field\nfrom superagi.helper.token_counter import TokenCounter\nfrom superagi.llms.base_llm import BaseLlm\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nfrom superagi.tools.base_tool import BaseTool\nimport os\nimport requests\nfrom superagi.tools.tool_response_query_manager import ToolResponseQueryManager\nimport random\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.helper.s3_helper import S3Helper\nfrom superagi.types.storage_types import StorageType\n\nclass InstagramSchema(BaseModel):\n    photo_description: str = Field(\n        ...,\n        description=\"description of the photo\",\n    )\n    filename: str = Field(..., description=\"Name of the file to be posted. Only one file can be posted at a time.\")\n\n\nclass InstagramTool(BaseTool):\n    \"\"\"\n    Instagram tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    llm: Optional[BaseLlm] = None\n    name = \"Instagram tool\"\n    description = (\n        \"A tool for posting an AI generated photo on Instagram\"\n    )\n    args_schema: Type[InstagramSchema] = InstagramSchema\n    tool_response_manager: Optional[ToolResponseQueryManager] = None\n    agent_id:int =None\n    agent_execution_id:int =None\n    \n    class Config:\n        arbitrary_types_allowed = True\n\n    def _execute(self, photo_description: str, filename: str) -> str:\n        \"\"\"\n        Execute the Instagram tool.\n\n        Args:\n            photo_description : description of the photo to be posted\n\n        Returns:\n            Image posted successfully message if image has been posted on instagram or error message.\n        \"\"\"\n        session = self.toolkit_config.session\n        meta_user_access_token = self.get_tool_config(\"META_USER_ACCESS_TOKEN\")\n        facebook_page_id=self.get_tool_config(\"FACEBOOK_PAGE_ID\")\n\n        if meta_user_access_token is None:\n            return \"Error: Missing meta user access token.\"\n\n        if facebook_page_id is None:\n            return \"Error: Missing facebook page id.\"\n        #create caption for the instagram\n        caption=self.create_caption(photo_description)   \n\n        #get request for fetching the instagram_business_account_id\n        root_api_url=\"https://graph.facebook.com/v17.0/\"\n        response=self.get_req_insta_id(root_api_url,facebook_page_id,meta_user_access_token)\n        \n        if response.status_code != 200:\n            return f\"Non-200 response: {str(response.text)}\"\n\n        data = response.json()\n        insta_business_account_id=data[\"instagram_business_account\"][\"id\"]\n        file_path=self.get_file_path(session, filename, self.agent_id, self.agent_execution_id)    \n        #handling case where image generation generates multiple images\n        \n        image_url,encoded_caption=self.get_img_url_and_encoded_caption(photo_description,file_path, filename)\n        #post request for getting the media container ID\n        response=self.post_media_container_id(root_api_url,insta_business_account_id,image_url,encoded_caption,meta_user_access_token)\n        \n        if response.status_code != 200:\n            return f\"Non-200 response: {str(response.text)}\"\n\n        data = response.json()\n        container_ID=data[\"id\"]\n        #post request to post the media container on instagram account\n        response=self.post_media(root_api_url,insta_business_account_id,container_ID,meta_user_access_token)\n        if response.status_code != 200:\n            return f\"Non-200 response: {str(response.text)}\"\n        return \"Photo posted successfully!\"\n\n    def create_caption(self, photo_description: str) -> str:\n        \"\"\"\n        Create a caption for the instagram post based on the photo description\n\n        Args:\n            photo_description : Description of the photo to be posted\n\n        Returns:\n            Description of the photo to be posted\n        \"\"\"\n        caption_prompt =\"\"\"Generate an instagram post caption for the following text `{photo_description}`\n            Attempt to make it as relevant as possible to the description and should be different and unique everytime. Add relevant emojis and hashtags.\"\"\"\n\n        caption_prompt = caption_prompt.replace(\"{photo_description}\", str(photo_description))\n\n        messages = [{\"role\": \"system\", \"content\": caption_prompt}]\n        result = self.llm.chat_completion(messages, max_tokens=self.max_token_limit)\n        if 'error' in result and result['message'] is not None:\n            ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message'])\n        caption=result[\"content\"]\n        \n        encoded_caption=urllib. parse. quote(caption)     \n\n        return encoded_caption\n    \n    def get_file_path(self, session, file_name, agent_id, agent_execution_id):\n        \"\"\"\n        Gets the path of the image file\n\n        Args:\n            media_files: Name of the media files to be posted\n\n        Returns:\n            The path of the image file\n        \"\"\"\n        \n        final_path = ResourceHelper().get_agent_read_resource_path(file_name,\n                                                                    agent=Agent.get_agent_from_id(session, agent_id),\n                                                                    agent_execution=AgentExecution.get_agent_execution_from_id(\n                                                                  session, agent_execution_id))\n        return final_path\n        \n    def get_img_public_url(self,filename,content):\n        \"\"\"\n        Puts the image generated by image generation tool in the s3 bucket and returns the public url of the same\n        Args:\n            s3 : S3 bucket\n            file_path: Path of the image file in s3\n            content: Image file\n\n        Returns:\n            The public url of the image put in s3 bucket\n        \"\"\"\n        \n        bucket_name = get_config(\"INSTAGRAM_TOOL_BUCKET_NAME\")\n        object_key=f\"instagram_upload_images/{filename}\"\n        S3Helper(get_config(\"INSTAGRAM_TOOL_BUCKET_NAME\")).upload_file_content(content, object_key)\n        image_url = f\"https://{bucket_name}.s3.amazonaws.com/{object_key}\"\n        return image_url\n\n    def get_img_url_and_encoded_caption(self,photo_description,file_path,filename):\n\n        #fetching the image from the s3 using the file_path\n        content = self._get_image_content(file_path)\n        #storing the image in a public bucket and getting the image url\n        image_url = self.get_img_public_url(filename,content)       \n        #encoding the caption with possible emojis and hashtags and removing the starting and ending double quotes \n        encoded_caption=self.create_caption(photo_description)    \n\n        print(image_url, encoded_caption)\n\n        return image_url,encoded_caption\n\n    def get_req_insta_id(self,root_api_url,facebook_page_id,meta_user_access_token):\n        url_to_get_acc_id=f\"{root_api_url}{facebook_page_id}?fields=instagram_business_account&access_token={meta_user_access_token}\"\n        response=requests.get(\n            url_to_get_acc_id\n        )\n\n        return response\n    \n    def post_media_container_id(self,root_api_url,insta_business_account_id,image_url,encoded_caption,meta_user_access_token):\n        url_to_create_media_container=f\"{root_api_url}{insta_business_account_id}/media?image_url={image_url}&caption={encoded_caption}&access_token={meta_user_access_token}\"\n        response = requests.post(       \n            url_to_create_media_container\n        )\n\n        return response\n\n    def post_media(self,root_api_url,insta_business_account_id,container_ID,meta_user_access_token):\n        url_to_post_media_container=f\"{root_api_url}{insta_business_account_id}/media_publish?creation_id={container_ID}&access_token={meta_user_access_token}\"\n        response = requests.post(\n            url_to_post_media_container\n        )\n\n        return response\n\n    def _get_image_content(self, file_path):\n        if StorageType.get_storage_type(get_config(\"STORAGE_TYPE\", StorageType.FILE.value)) == StorageType.S3:\n                attachment_data = S3Helper().read_binary_from_s3(file_path)\n        else:\n            with open(file_path, \"rb\") as file:\n                attachment_data = file.read()\n        return attachment_data"
  },
  {
    "path": "superagi/tools/instagram_tool/instagram_toolkit.py",
    "content": "from abc import ABC\nfrom typing import List\nfrom superagi.tools.base_tool import BaseTool, BaseToolkit, ToolConfiguration\nfrom superagi.tools.instagram_tool.instagram import InstagramTool\nfrom superagi.types.key_type import ToolConfigKeyType\n\nclass InstagramToolkit(BaseToolkit, ABC):\n    name: str = \"Instagram Toolkit\"\n    description: str = \"Toolkit containing tools for posting AI generated photo on Instagram. Posts only one photo in a run \"\n\n    def get_tools(self) -> List[BaseTool]:\n        return [InstagramTool()]\n\n    def get_env_keys(self) -> List[ToolConfiguration]:\n        return [\n            ToolConfiguration(key=\"META_USER_ACCESS_TOKEN\", key_type=ToolConfigKeyType.STRING, is_required=True, is_secret=True),\n            ToolConfiguration(key=\"FACEBOOK_PAGE_ID\", key_type=ToolConfigKeyType.STRING, is_required=True, is_secret=False)\n        ]"
  },
  {
    "path": "superagi/tools/jira/README.MD",
    "content": "<p align=\"center\">\n  <a href=\"https://superagi.com//#gh-light-mode-only\">\n    <img src=\"https://superagi.com/wp-content/uploads/2023/05/Logo-dark.svg\" width=\"318px\" alt=\"SuperAGI logo\" />\n  </a>\n  <a href=\"https://superagi.com//#gh-dark-mode-only\">\n    <img src=\"https://superagi.com/wp-content/uploads/2023/05/Logo-light.svg\" width=\"318px\" alt=\"SuperAGI logo\" />\n  </a>\n</p>\n\n# SuperAGI Jira Tool\n\nThe SuperAGI Jira Tool lets users create, edit and search issues while providing a foundation for other great use cases.\n\n## 💡 Features\n\n1.**Create Issue:** SuperAGI's JIRA tool lets you seamlessly create new tasks in your project by defining the task's details such as its summary, description, type, and priority. \n\n2. **Edit Issue:** Modify existing tasks quickly with SuperAGI's JIRA tool, which allows you to change any task details like summary, description, type, and priority.\n\n3. **Search Issues:** Use the powerful 'Search Issues' feature to find specific tasks within your projects by defining your search criteria in terms of project, assignee, or keywords in the task summary.\n\n4. **Get Projects:** Discover and access all your projects with ease using the 'Get Projects' feature, providing a bird's eye view of your workload and streamlining project-based searches.\n\n## ⚙️ Installation\n\n### 🛠 **Setting Up of SuperAGI**\nSet up the SuperAGI by following the instructions given (https://github.com/TransformerOptimus/SuperAGI/blob/main/README.MD)\n\n### 🔧 **Add Jira configuration settings in SuperAGI Dashboard**\nAdd the following configuration settings in the file:\n\n1. _JIRA API TOKEN:_\n - Login into your Jira Account. Go to \"Manage Account\".\n - Go to Security and click on \"Create and Manage API Tokens\".\n\n<img src=\"https://github.com/TransformerOptimus/SuperAGI/assets/43145646/b9a535be-0f44-40f8-aec5-4f09bd223c9e\" width=600px>\n\n - Click on \"Create API Token\" and choose an appropriate label name.\n - Copy the API Token and save it in a text file.\n\n2. _JIRA INSTANCE URL:_\n - Your instance profile is the section at the start of your URL. It should look something like \"https://mycompany.atlassian.net/\".\n\n3. _JIRA USERNAME:_\n - Your Jira UserName is the Email Address with which you signed up in Jira.\n\n4. _CONFIGURING JIRA IN SUPERAGI DASHBOARD:_ \n - Open the Jira Toolkit Page in SuperAGI Add your Jira API Token, your Instance URL, and your Jira Username and click \"Update Changes\"\n\n## Running SuperAGI Jira Tool\n\n1. **Create an Issue:** The SuperAGI JIRA Create Issue tool allows you to create issues in your project. By default, it creates a task with predefined settings. To create a task with different details, modify the relevant fields in the create_issue.py script.\n\n2. **Edit an Issue:** To edit a particular issue, specify the issue ID in your goal. The modifications can be made by changing the relevant fields in the edit_issue.py script.\n\n3. **Search for Issues:** You can simply search for a particular issue in your agent's goals and your agent performs a search based on the JIRA Query Language (JQL) query you define. Modify the JQL query according to your requirements in the search_issues.py script.\n\n4. **Fetch Project Details:** Use the 'Get Projects' feature to retrieve a list of your accessible projects. The get_projects.py script can be modified to adjust the parameters of this operation.\n"
  },
  {
    "path": "superagi/tools/jira/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/tools/jira/create_issue.py",
    "content": "from typing import Type\n\nfrom pydantic import BaseModel, Field\n\nfrom superagi.tools.jira.tool import JiraTool, JiraIssueSchema\n\n\nclass CreateIssueSchema(BaseModel):\n    fields: dict = Field(\n        ...,\n        description='Dictionary of fields to create the Jira issue with. Format: {{\"summary\": \"test issue\", \"project\": \"project_id\", \"description\": \"test description\", \"issuetype\": {{\"name\": \"Task\"}}, \"priority\": {{\"name\": \"Low\"}}}}',\n    )\n\n\nclass CreateIssueTool(JiraTool):\n    \"\"\"\n    Create Jira Issue tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    name = \"CreateJiraIssue\"\n    description = \"Create a new Jira issue.\"\n    args_schema: Type[CreateIssueSchema] = CreateIssueSchema\n\n    def _execute(self, fields: dict):\n        \"\"\"\n        Execute the create issue tool.\n\n        Args: fields (dict): Dictionary of fields to create the Jira issue with. Format: {\"summary\": \"test issue\",\n        \"project\": \"project_id\", \"description\": \"test description\", \"issuetype\": {\"name\": \"Task\"}, \"priority\": {\n        \"name\": \"Low\"}}\n\n        Returns:\n            The success message mentioning the key of the created issue.\n        \"\"\"\n        jira = self.build_jira_instance()\n        new_issue = jira.create_issue(fields=fields)\n        return f\"Issue '{new_issue.key}' created successfully!\"\n"
  },
  {
    "path": "superagi/tools/jira/edit_issue.py",
    "content": "from typing import Type\n\nfrom pydantic import Field, BaseModel\n\nfrom superagi.tools.jira.tool import JiraTool, JiraIssueSchema\n\n\nclass EditIssueSchema(BaseModel):\n    key: str = Field(\n        ...,\n        description=\"Issue key or id in Jira\",\n    )\n    fields: dict = Field(\n        ...,\n        description='Dictionary of fields to create the Jira issue with. Format: {{\"summary\": \"test issue\", \"project\": \"project_id\", \"description\": \"test description\", \"issuetype\": {{\"name\": \"Task\"}}, \"priority\": {{\"name\": \"Low\"}}}}',\n    )\n\n\nclass EditIssueTool(JiraTool):\n    \"\"\"\n    Edit Jira Issue tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    name = \"EditJiraIssue\"\n    description = \"Edit a Jira issue.\"\n    args_schema: Type[EditIssueSchema] = EditIssueSchema\n\n    def _execute(self, key: str, fields: dict):\n        \"\"\"\n        Execute the edit issue tool.\n\n        Args:\n            key : Issue key or id in Jira\n            fields (dict): Dictionary of fields to create the Jira issue with. Format: {\"summary\": \"test issue\",\n            \"project\": \"project_id\", \"description\": \"test description\", \"issuetype\": {\"name\": \"Task\"}, \"priority\": {\n            \"name\": \"Low\"}}\n\n        Returns:\n            The success message mentioning key of the edited issue or Issue not found!\n        \"\"\"\n        jira = self.build_jira_instance()\n        issues = jira.search_issues(f\"key={key}\")\n        if issues:\n            issues[0].update(fields=fields)\n            return f\"Issue '{issues[0].key}' created successfully!\"\n        return f\"Issue not found!\"\n"
  },
  {
    "path": "superagi/tools/jira/get_projects.py",
    "content": "from typing import Type, List\n\nfrom pydantic import BaseModel, Field\n\nfrom superagi.tools.jira.tool import JiraIssueSchema, JiraTool\n\nclass GetProjectsSchema(BaseModel):\n    pass\n\n\nclass GetProjectsTool(JiraTool):\n    \"\"\"\n    Get Jira Projects tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    name = \"GetJiraProjects\"\n    description = \"This tool is a wrapper around atlassian-python-api's Jira project API. Useful in fetching all the projects accessible to the user, discovering the total count of projects, or utilizing it as an interim step during project-based searches.\"\n    args_schema: Type[GetProjectsSchema] = GetProjectsSchema\n\n    def parse_projects(self, projects: List[dict]) -> List[dict]:\n        parsed = []\n        for project in projects:\n            parsed.append({\"id\": project.id, \"key\": project.key, \"name\": project.name})\n        return parsed\n\n    def _execute(self) -> str:\n        \"\"\"\n        Execute the get projects tool.\n\n        Returns:\n            Found <count> projects: <projects>\n        \"\"\"\n        jira = self.build_jira_instance()\n        projects = jira.projects()\n        parsed_projects = self.parse_projects(projects)\n        parsed_projects_str = (\n                \"Found \" + str(len(parsed_projects)) + \" projects:\\n\" + str(parsed_projects)\n        )\n        return parsed_projects_str"
  },
  {
    "path": "superagi/tools/jira/jira_toolkit.py",
    "content": "from abc import ABC\nfrom typing import List\nfrom superagi.tools.base_tool import BaseTool, BaseToolkit, ToolConfiguration\nfrom superagi.tools.jira.create_issue import CreateIssueTool\nfrom superagi.tools.jira.edit_issue import EditIssueTool\nfrom superagi.tools.jira.get_projects import GetProjectsTool\nfrom superagi.tools.jira.search_issues import SearchJiraTool\nfrom superagi.types.key_type import ToolConfigKeyType\nfrom superagi.models.tool_config import ToolConfig\n\n\nclass JiraToolkit(BaseToolkit, ABC):\n    name: str = \"Jira Toolkit\"\n    description: str = \"Toolkit containing tools for Jira integration\"\n\n    def get_tools(self) -> List[BaseTool]:\n        return [\n            CreateIssueTool(),\n            EditIssueTool(),\n            GetProjectsTool(),\n            SearchJiraTool(),\n        ]\n\n    def get_env_keys(self) -> List[ToolConfiguration]:\n        return [\n            ToolConfiguration(key=\"JIRA_INSTANCE_URL\", key_type=ToolConfigKeyType.STRING, is_required= True, is_secret = False),\n            ToolConfiguration(key=\"JIRA_USERNAME\", key_type=ToolConfigKeyType.STRING, is_required=True, is_secret=False),\n            ToolConfiguration(key=\"JIRA_API_TOKEN\", key_type=ToolConfigKeyType.STRING, is_required=True, is_secret=True)\n        ]\n"
  },
  {
    "path": "superagi/tools/jira/search_issues.py",
    "content": "import json\nfrom typing import Type, Dict, List\n\nfrom pydantic import Field, BaseModel\n\nfrom superagi.helper.token_counter import TokenCounter\nfrom superagi.tools.jira.tool import JiraTool\n\n\nclass SearchIssueSchema(BaseModel):\n    query: str = Field(\n        ...,\n        description=\"JQL query string to search issues. For example, to find all the issues in project \\\"Test\\\" assigned to the me, you would pass in the following string: project = Test AND assignee = currentUser() or to find issues with summaries that contain the word \\\"test\\\", you would pass in the following string: summary ~ 'test'.\",\n    )\n\n\nclass SearchJiraTool(JiraTool):\n    \"\"\"\n    Search Jira Issues tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    name = \"SearchJiraIssues\"\n    description = \"This tool is a wrapper around atlassian-python-api's Jira jql API, useful when you need to search for Jira issues.\"\n    args_schema: Type[SearchIssueSchema] = SearchIssueSchema\n\n    def _execute(self, query: str) -> str:\n        \"\"\"\n        Execute the search issues tool.\n\n        Args:\n            query : JQL query string to search issues. For example, to find all the issues in project \"Test\"\n        assigned to, you would pass in the following string: project = Test AND assignee = currentUser() or to\n        find issues with summaries that contain the word \"test\", you would pass in the following string: summary ~\n        'test'.\n\n        Returns:\n            The list of issues matching the query.\n        \"\"\"\n        jira = self.build_jira_instance()\n        issues = jira.search_issues(query)\n        parsed_issues = self.parse_issues(issues)\n        parsed_issues_str = (\n                \"Found \" + str(len(parsed_issues)) + \" issues:\\n\" + str(parsed_issues)\n        )\n        return parsed_issues_str\n\n    def parse_issues(self, issues: List) -> List[dict]:\n        \"\"\"\n        Parse the issues returned by the Jira API.\n\n        Args:\n            issues : List of issues returned by the Jira API.\n\n        Returns:\n            List of parsed issues.\n        \"\"\"\n        parsed = []\n        for issue in issues:\n            key = issue.key\n            summary = issue.fields.summary\n            created = issue.fields.created[0:10]\n            priority = issue.fields.priority.name\n            status = issue.fields.status.name\n            try:\n                assignee = issue.fields.assignee.displayName\n            except Exception:\n                assignee = \"None\"\n            rel_issues = {}\n            for related_issue in issue.fields.issuelinks:\n                if \"inwardIssue\" in related_issue.keys():\n                    rel_type = related_issue.type.inward\n                    rel_key = related_issue.inwardIssue.key\n                    rel_summary = related_issue.inwardIssue.fields.summary\n                if \"outwardIssue\" in related_issue.keys():\n                    rel_type = related_issue.type.outward\n                    rel_key = related_issue.outwardIssue.key\n                    rel_summary = related_issue.outwardIssue.fields.summary\n                rel_issues = {\"type\": rel_type, \"key\": rel_key, \"summary\": rel_summary}\n            parsed.append(\n                {\n                    \"key\": key,\n                    \"summary\": summary,\n                    \"created\": created,\n                    \"assignee\": assignee,\n                    \"priority\": priority,\n                    \"status\": status,\n                    \"related_issues\": rel_issues,\n                }\n            )\n            if TokenCounter.count_text_tokens(json.dumps(parsed)) > self.max_token_limit:\n                break\n        return parsed\n"
  },
  {
    "path": "superagi/tools/jira/tool.py",
    "content": "import os\n\nimport requests\nfrom typing import List, Type\nfrom pydantic import BaseModel, Field\n\nfrom superagi.config.config import get_config\nfrom superagi.tools.base_tool import BaseTool\nfrom jira import JIRA\n\nclass JiraIssueSchema(BaseModel):\n    issue_key: str = Field(\n        ...,\n        description=\"The key of the Jira issue.\",\n    )\n    fields: dict = Field(\n        ...,\n        description=\"The fields to update for the Jira issue.\",\n    )\n\n\nclass JiraTool(BaseTool):\n    \"\"\"\n    Jira tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    def build_jira_instance(self) -> dict:\n        \"\"\"\n        Build a Jira instance.\n\n        Returns:\n            The Jira instance.\n        \"\"\"\n        jira_instance_url = self.get_tool_config(\"JIRA_INSTANCE_URL\")\n        jira_username = self.get_tool_config(\"JIRA_USERNAME\")\n        jira_api_token = self.get_tool_config(\"JIRA_API_TOKEN\")\n        jira = JIRA(\n            server=jira_instance_url,\n            basic_auth=(jira_username, jira_api_token)\n        )\n        return jira\n"
  },
  {
    "path": "superagi/tools/knowledge_search/knowledge_search.py",
    "content": "from superagi.models.agent_config import AgentConfiguration\n\nfrom superagi.models.knowledges import Knowledges\nfrom superagi.models.vector_db_indices import VectordbIndices\nfrom superagi.models.vector_dbs import Vectordbs\nfrom superagi.models.vector_db_configs import VectordbConfigs\nfrom superagi.models.toolkit import Toolkit\nfrom superagi.vector_store.vector_factory import VectorFactory\nfrom superagi.models.configuration import Configuration\nfrom superagi.jobs.agent_executor import AgentExecutor\n\nfrom typing import Any, Type, List\nfrom pydantic import BaseModel, Field\n\nfrom superagi.tools.base_tool import BaseTool\n\n# from superagi.tools.file.read_file import ReadFileTool\n\n\nclass KnowledgeSearchSchema(BaseModel):\n    query: str = Field(..., description=\"The query to search required from knowledge search\")\n\n\nclass KnowledgeSearchTool(BaseTool):\n    name: str = \"Knowledge Search\"\n    args_schema: Type[BaseModel] = KnowledgeSearchSchema\n    agent_id: int = None\n    description = (\n        \"A tool for performing a Knowledge search on knowledge base which might have knowledge of the task you are pursuing.\"\n        \"To find relevant info, use this tool first before using other tools.\"\n        \"If you don't find sufficient info using Knowledge tool, you may use other tools.\"\n        \"If a question is being asked, responding with context from info returned by knowledge tool is prefered.\"\n        \"Input should be a search query.\"\n    )\n\n    def _execute(self, query: str):\n        session = self.toolkit_config.session\n        toolkit = session.query(Toolkit).filter(Toolkit.id == self.toolkit_config.toolkit_id).first()\n        organisation_id = toolkit.organisation_id\n        knowledge_id = session.query(AgentConfiguration).filter(AgentConfiguration.agent_id == self.agent_id, AgentConfiguration.key == \"knowledge\").first().value\n        knowledge = Knowledges.get_knowledge_from_id(session, knowledge_id)\n        if knowledge is None:\n            return \"Selected Knowledge not found\"\n        vector_db_index = VectordbIndices.get_vector_index_from_id(session, knowledge.vector_db_index_id)\n        vector_db = Vectordbs.get_vector_db_from_id(session, vector_db_index.vector_db_id)\n        db_creds = VectordbConfigs.get_vector_db_config_from_db_id(session, vector_db.id)\n        model_api_key = self.get_tool_config('OPENAI_API_KEY')\n        model_source = 'OpenAI'\n        embedding_model = AgentExecutor.get_embedding(model_source, model_api_key)\n        try:\n            if vector_db_index.state == \"Custom\":\n                filters = None\n            if vector_db_index.state == \"Marketplace\":\n                filters = {\"knowledge_name\": knowledge.name}\n            vector_db_storage = VectorFactory.build_vector_storage(vector_db.db_type, vector_db_index.name, embedding_model, **db_creds)\n            search_result = vector_db_storage.get_matching_text(query, metadata=filters)\n            return f\"Result: \\n{search_result['search_res']}\"\n        except Exception as err:\n            return f\"Error fetching text: {err}\"\n        "
  },
  {
    "path": "superagi/tools/knowledge_search/knowledge_search_toolkit.py",
    "content": "from abc import ABC\nfrom typing import List\nfrom superagi.tools.base_tool import BaseTool, BaseToolkit, ToolConfiguration\nfrom superagi.tools.knowledge_search.knowledge_search import KnowledgeSearchTool\nfrom superagi.types.key_type import ToolConfigKeyType\n\nclass KnowledgeSearchToolkit(BaseToolkit, ABC):\n    name: str = \"Knowledge Search Toolkit\"\n    description: str = \"Toolkit containing tools for performing search on the knowledge base.\"\n\n    def get_tools(self) -> List[BaseTool]:\n        return [KnowledgeSearchTool()]\n\n    def get_env_keys(self) -> List[ToolConfiguration]:\n        return [\n            ToolConfiguration(key=\"OPENAI_API_KEY\", key_type=ToolConfigKeyType.STRING, is_required=False, is_secret=True)\n        ]"
  },
  {
    "path": "superagi/tools/resource/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/tools/resource/query_resource.py",
    "content": "import logging\nimport os\nfrom typing import Optional\nfrom typing import Type\n\nimport openai\nfrom langchain.chat_models import ChatOpenAI\nfrom llama_index import VectorStoreIndex, LLMPredictor, ServiceContext\nfrom llama_index.vector_stores.types import ExactMatchFilter, MetadataFilters\nfrom pydantic import BaseModel, Field\n\nfrom superagi.config.config import get_config\nfrom superagi.llms.base_llm import BaseLlm\nfrom superagi.resource_manager.llama_vector_store_factory import LlamaVectorStoreFactory\nfrom superagi.tools.base_tool import BaseTool\nfrom superagi.types.vector_store_types import VectorStoreType\nfrom superagi.vector_store.chromadb import ChromaDB\n\n\nclass QueryResource(BaseModel):\n    \"\"\"Input for QueryResource tool.\"\"\"\n    query: str = Field(..., description=\"the search query to search resources\")\n\n\nclass QueryResourceTool(BaseTool):\n    \"\"\"\n    Read File tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    name: str = \"QueryResource\"\n    args_schema: Type[BaseModel] = QueryResource\n    description: str = \"Tool searches resources content and extracts relevant information to perform the given task.\" \\\n                       \"Tool is given preference over other search/read file tools for relevant data.\" \\\n                       \"Resources content is taken from the files: {summary}\"\n    agent_id: int = None\n    llm: Optional[BaseLlm] = None\n\n    def _execute(self, query: str):\n        openai.api_key = self.llm.get_api_key()\n        os.environ[\"OPENAI_API_KEY\"] = self.llm.get_api_key()\n        llm_predictor_chatgpt = LLMPredictor(llm=ChatOpenAI(temperature=0, model_name=self.llm.get_model(),\n                                                            openai_api_key=get_config(\"OPENAI_API_KEY\")))\n\n        service_context = ServiceContext.from_defaults(llm_predictor=llm_predictor_chatgpt)\n        vector_store_name = VectorStoreType.get_vector_store_type(\n            self.get_tool_config(key=\"RESOURCE_VECTOR_STORE\") or \"Redis\")\n        vector_store_index_name = self.get_tool_config(key=\"RESOURCE_VECTOR_STORE_INDEX_NAME\") or \"super-agent-index\"\n        logging.info(f\"vector_store_name {vector_store_name}\")\n        logging.info(f\"vector_store_index_name {vector_store_index_name}\")\n        vector_store = LlamaVectorStoreFactory(vector_store_name, vector_store_index_name).get_vector_store()\n        logging.info(f\"vector_store {vector_store}\")\n        as_query_engine_args = dict(\n            filters=MetadataFilters(\n                filters=[\n                    ExactMatchFilter(\n                        key=\"agent_id\",\n                        value=str(self.agent_id)\n                    )\n                ]\n            )\n        )\n        if vector_store_name == VectorStoreType.CHROMA:\n            as_query_engine_args[\"chroma_collection\"] = ChromaDB.create_collection(\n                collection_name=vector_store_index_name)\n        index = VectorStoreIndex.from_vector_store(vector_store=vector_store, service_context=service_context)\n        query_engine = index.as_query_engine(\n            **as_query_engine_args\n        )\n        try:\n            response = query_engine.query(query)\n        except ValueError as e:\n            logging.error(f\"ValueError {e}\")\n            response = \"Document not found\"\n        return response\n"
  },
  {
    "path": "superagi/tools/resource/resource_toolkit.py",
    "content": "from abc import ABC\nfrom typing import List\nfrom superagi.tools.base_tool import BaseTool, BaseToolkit, ToolConfiguration\nfrom superagi.tools.resource.query_resource import QueryResourceTool\nfrom superagi.types.key_type import ToolConfigKeyType\n\n\nclass JiraToolkit(BaseToolkit, ABC):\n    name: str = \"Resource Toolkit\"\n    description: str = \"Toolkit containing tools for Resource integration\"\n\n    def get_tools(self) -> List[BaseTool]:\n        return [\n            QueryResourceTool(),\n        ]\n\n    def get_env_keys(self) -> List[ToolConfiguration]:\n        return [\n            ToolConfiguration(key=\"RESOURCE_VECTOR_STORE\", key_type=ToolConfigKeyType.STRING, is_required= True, is_secret = True),\n            ToolConfiguration(key=\"RESOURCE_VECTOR_STORE_INDEX_NAME\", key_type=ToolConfigKeyType.STRING, is_required=True, is_secret=True)\n        ]\n"
  },
  {
    "path": "superagi/tools/searx/README.MD",
    "content": "<p align=center>\n<a href=\"https://superagi.co\"><img src=https://superagi.co/wp-content/uploads/2023/05/SuperAGI_icon.png></a>\n</p>\n\n# SuperAGI Searx Search Tool\n\nThe SuperAGI Searx Search Tool helps users perform a Searx search and extract snippets and webpages. We parse the HTML response pages because most Searx instances do not support the JSON response format without an API key.\n\n## ⚙️ Installation\n\n### 🛠 **Setting Up of SuperAGI**\nSet up the SuperAGI by following the instructions given (https://github.com/TransformerOptimus/SuperAGI/blob/main/README.MD)\n\n## Running SuperAGI Searx Search Serp Tool\n\nYou can simply ask your agent about latest information regarding anything in the world and your agent will be able to browse the internet to get that information for you. \n"
  },
  {
    "path": "superagi/tools/searx/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/tools/searx/search_scraper.py",
    "content": "import random\nfrom typing import List\nimport httpx\nfrom bs4 import BeautifulSoup\nfrom pydantic import BaseModel\nfrom superagi.lib.logger import logger\n\n\nsearx_hosts = [\"https://search.ononoki.org\", \"https://searx.be\", \"https://search.us.projectsegfau.lt\"]\n\nclass SearchResult(BaseModel):\n    \"\"\"\n    Represents a single search result from Searx\n\n    Attributes:\n        id : The ID of the search result.\n        title : The title of the search result.\n        link : The link of the search result.\n        description : The description of the search result.\n        sources : The sources of the search result.\n    \"\"\"\n    id: int\n    title: str\n    link: str\n    description: str\n    sources: List[str]\n\n    def __str__(self):\n        return f\"\"\"{self.id}. {self.title} - {self.link} \n{self.description}\"\"\"\n\ndef search(query):\n    \"\"\"\n    Gets the raw HTML of a searx search result page\n\n    Args:\n        query : The query to search for.\n    \"\"\"\n    # TODO: use a better strategy for choosing hosts. Could use this list: https://searx.space/data/instances.json\n    searx_url = random.choice(searx_hosts)\n    res = httpx.get(\n        searx_url + \"/search\", params={\"q\": query}, headers={\"User-Agent\": \"Mozilla/5.0 (X11; Linux i686; rv:109.0) Gecko/20100101 Firefox/114.0\"}\n    )\n    if res.status_code != 200:\n        logger.info(res.status_code, searx_url)\n        raise Exception(f\"Searx returned {res.status_code} status code\")\n\n    return res.text\n\ndef clean_whitespace(s: str):\n    \"\"\"\n    Cleans up whitespace in a string\n\n    Args:\n        s : The string to clean up.\n\n    Returns:\n        The cleaned up string.\n    \"\"\"\n    return \" \".join(s.split())\n\n\ndef scrape_results(html):\n    \"\"\"\n    Converts raw HTML into a list of SearchResult objects\n\n    Args:\n        html : The raw HTML to convert.\n\n    Returns:\n        A list of SearchResult objects.\n    \"\"\"\n    soup = BeautifulSoup(html, \"html.parser\")\n    result_divs = soup.find_all(attrs={\"class\": \"result\"})\n    \n    result_list = []\n    n = 1\n    for result_div in result_divs:\n        if result_div is None:\n            continue\n        # Needed to work on multiple versions of Searx\n        header = result_div.find([\"h4\", \"h3\"])\n        if header is None:\n            continue\n        link = header.find(\"a\")[\"href\"]\n        title = header.text.strip()\n\n        description = clean_whitespace(result_div.find(\"p\").text)\n\n        # Needed to work on multiple versions of Searx\n        sources_container = result_div.find(\n            attrs={\"class\": \"pull-right\"}\n        ) or result_div.find(attrs={\"class\": \"engines\"}) \n        source_spans = sources_container.find_all(\"span\")\n        sources = []\n        for s in source_spans:\n            sources.append(s.text.strip())\n\n        result = SearchResult(\n            id=n, title=title, link=link, description=description, sources=sources\n        )\n        result_list.append(result)\n        n += 1\n\n    return result_list\n\n\ndef search_results(query):\n    '''Returns a text summary of the search results via the SearchResult.__str__ method'''\n    return \"\\n\\n\".join(list(map(lambda x: str(x), scrape_results(search(query)))))\n"
  },
  {
    "path": "superagi/tools/searx/searx.py",
    "content": "from typing import Type, Optional\nfrom pydantic import BaseModel, Field\nfrom superagi.helper.error_handler import ErrorHandler\nfrom superagi.llms.base_llm import BaseLlm\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nfrom superagi.tools.base_tool import BaseTool\nfrom superagi.tools.searx.search_scraper import search_results\n\n\nclass SearxSearchSchema(BaseModel):\n    query: str = Field(\n        ...,\n        description=\"The search query for the Searx search engine.\",\n    )\n\nclass SearxSearchTool(BaseTool):\n    \"\"\"\n    Searx Search tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    llm: Optional[BaseLlm] = None\n    name = \"SearxSearch\"\n    agent_id:int =None\n    agent_execution_id:int =None\n    description = (\n        \"A tool for performing a Searx search and extracting snippets and webpages.\"\n        \"Input should be a search query.\"\n    )\n    args_schema: Type[SearxSearchSchema] = SearxSearchSchema\n\n    class Config:\n        arbitrary_types_allowed = True\n\n    def _execute(self, query: str) -> tuple:\n        \"\"\"\n        Execute the Searx search tool.\n\n        Args:\n            query : The query to search for.\n\n        Returns:\n            Snippets from the Searx search.\n        \"\"\"\n        snippets = search_results(query)\n        summary = self.summarise_result(query, snippets)\n\n        return summary\n\n    def summarise_result(self, query, snippets):\n        \"\"\"\n        Summarise the result of the Searx search.\n\n        Args:\n            query : The query to search for.\n            snippets : The snippets from the Searx search.\n\n        Returns:\n            A summary of the result.\n        \"\"\"\n        summarize_prompt = \"\"\"Summarize the following text `{snippets}`\n            Write a concise or as descriptive as necessary and attempt to\n            answer the query: `{query}` as best as possible. Use markdown formatting for\n            longer responses.\"\"\"\n\n        summarize_prompt = summarize_prompt.replace(\"{snippets}\", str(snippets))\n        summarize_prompt = summarize_prompt.replace(\"{query}\", query)\n\n        messages = [{\"role\": \"system\", \"content\": summarize_prompt}]\n        result = self.llm.chat_completion(messages, max_tokens=self.max_token_limit)\n        \n        if 'error' in result and result['message'] is not None:\n            ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message'])\n        return result[\"content\"]\n"
  },
  {
    "path": "superagi/tools/searx/searx_toolkit.py",
    "content": "from abc import ABC\nfrom typing import List\n\nfrom superagi.tools.base_tool import BaseToolkit, BaseTool, ToolConfiguration\nfrom superagi.tools.searx.searx import SearxSearchTool\nfrom superagi.types.key_type import ToolConfigKeyType\n\nclass SearxSearchToolkit(BaseToolkit, ABC):\n    name: str = \"Searx Toolkit\"\n    description: str = \"Toolkit containing tools for performing Google search and extracting snippets and webpages \" \\\n                       \"using Searx\"\n\n    def get_tools(self) -> List[BaseTool]:\n        return [SearxSearchTool()]\n\n    def get_env_keys(self) -> List[ToolConfiguration]:\n        return []\n"
  },
  {
    "path": "superagi/tools/slack/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://superagi.com//#gh-light-mode-only\">\n    <img src=\"https://superagi.com/wp-content/uploads/2023/05/Logo-dark.svg\" width=\"318px\" alt=\"SuperAGI logo\" />\n  </a>\n  <a href=\"https://superagi.com//#gh-dark-mode-only\">\n    <img src=\"https://superagi.com/wp-content/uploads/2023/05/Logo-light.svg\" width=\"318px\" alt=\"SuperAGI logo\" />\n  </a>\n</p>\n\n# SuperAGI Slack Toolkit\n\nThis SuperAGI Tool lets users send messages to Slack Channels and provides a strong foundation for use cases to come.\n\n**Features:**\n\n1. Send Message - This tool gives SuperAGI the ability to send messages to Slack Channels that you have specified\n\n## 🛠️ Installation\n\n### Setting up of SuperAGI:\n\nSet up the SuperAGI by following the instructions given (https://github.com/TransformerOptimus/SuperAGI/blob/main/README.MD)\n\n### 🔧 **Slack Configuration:**\n\n1. Create an Application on SlackAPI Portal\n    \n![Slack_1](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/c05100b7-ca04-4da7-ad38-6ca539d5ee1d)\n\n2. Select \"from scratch\"\n    \n![Slack_2](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/8f3ce630-8483-40e3-9026-402933eb47f7)\n\n3. Add your application's name and the workspace for which you'd like to use your Slack Application\n    \n![Slack_3](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/e871e954-a4fb-4ae3-8ade-1022cdb6a613)\n\n4. Once the app creation process is done, head to the \"OAuth and Permissions\" tab\n\n![Slack_4](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/710a640c-0312-4085-a46e-1b19a13ef85f)\n\n5. Find the “**bot token scopes”** and define the following scopes:\n    \n    **\"chat:write\",**  and save it\n\n![Slack_5](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/48142090-00bc-4de6-9dc9-dab2e6b8ca92)\n\n6. Once you've defined the scope, install the application to your workspace\n\n![Slack_6](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/e348b3db-daa8-43a7-ab02-159bb12686b8)\n\n7. Post installation, you will get the bot token code\n\n![Slack_7](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/79e5fbc2-1554-4907-a13e-a0103793e3cb)\n\n8. Once the installation is done, you'll get the Bot User OAuth Token, which needs to be added to the Slack Toolkit Page\n\n![Slack_8](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/d8574ffc-06d3-4099-bc07-1e16a287c192)\n\nOnce the configuration is complete, you can install the app in the channel of your choice and create an agent on SuperAGI which can now send messages to the Slack Channel.\n"
  },
  {
    "path": "superagi/tools/slack/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/tools/slack/send_message.py",
    "content": "from typing import Type\n\nfrom pydantic import Field, BaseModel\n\nfrom superagi.tools.base_tool import BaseTool\nfrom superagi.config.config import get_config\nfrom slack_sdk import WebClient\n\n\nclass SlackMessageSchema(BaseModel):\n    channel: str = Field(\n        ...,\n        description=\"Slack Channel/Group Name\"\n    )\n    message: str = Field(\n        ...,\n        description=\"Text Message to be sent to a person or a group or people\"\n    )\n\n\nclass SlackMessageTool(BaseTool):\n    \"\"\"\n    Slack Message Tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n\n    This Tool works for both Individual and Group messages\n    - Individual Texting - Provide user-id\n    - Group Texting - Provide group-id\n    \"\"\"\n    name = \"SendSlackMessage\"\n    description = \"Send text message in Slack\"\n    args_schema: Type[SlackMessageSchema] = SlackMessageSchema\n\n    def _execute(self, channel: str, message: str):\n        \"\"\"\n        Execute the Slack Message Tool.\n\n        Args:\n            channel : The channel name.\n            message : The message to be sent.\n\n        Returns:\n            success message if message is sent successfully or failure message if message sending fails.\n        \"\"\"\n        slack = self.build_slack_web_client()\n        response = slack.chat_postMessage(channel=channel, text=message)\n\n        if response['ok']:\n            return f'Message sent to {channel} Successfully'\n        else:\n            return 'Message sending failed!'\n\n    def build_slack_web_client(self):\n        slack_bot_token = self.get_tool_config(\"SLACK_BOT_TOKEN\")\n        return WebClient(token=slack_bot_token)\n"
  },
  {
    "path": "superagi/tools/slack/slack_toolkit.py",
    "content": "from abc import ABC\nfrom typing import List\nfrom superagi.tools.base_tool import BaseTool, BaseToolkit, ToolConfiguration\nfrom superagi.tools.slack.send_message import SlackMessageTool\nfrom superagi.types.key_type import ToolConfigKeyType\n\n\nclass SlackToolkit(BaseToolkit, ABC):\n    name: str = \"Slack Toolkit\"\n    description: str = \"Toolkit containing tools for Slack integration\"\n\n    def get_tools(self) -> List[BaseTool]:\n        return [\n            SlackMessageTool(),\n        ]\n\n    def get_env_keys(self) -> List[ToolConfiguration]:\n        return [\n            ToolConfiguration(key=\"SLACK_BOT_TOKEN\", key_type=ToolConfigKeyType.STRING, is_required= True, is_secret = True)\n        ]\n"
  },
  {
    "path": "superagi/tools/thinking/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/tools/thinking/prompts/thinking.txt",
    "content": "Given the following overall objective\nObjective:\n{goals}\n\nand the following task, `{task_description}`.\n\nBelow is last tool response:\n`{last_tool_response}`\n\nBelow is the relevant tool response:\n`{relevant_tool_response}`\n\nPerform the task by understanding the problem, extracting variables, and being smart\nand efficient. Provide a descriptive response, make decisions yourself when\nconfronted with choices and provide reasoning for ideas / decisions."
  },
  {
    "path": "superagi/tools/thinking/thinking_toolkit.py",
    "content": "from abc import ABC\nfrom typing import List\nfrom superagi.tools.base_tool import BaseTool, BaseToolkit, ToolConfiguration\nfrom superagi.tools.thinking.tools import ThinkingTool\nfrom superagi.types.key_type import ToolConfigKeyType\n\n\nclass ThinkingToolkit(BaseToolkit, ABC):\n    name: str = \"Thinking Toolkit\"\n    description: str = \"Toolkit containing tools for intelligent problem-solving\"\n\n    def get_tools(self) -> List[BaseTool]:\n        return [\n            ThinkingTool(),\n        ]\n\n    def get_env_keys(self) -> List[ToolConfiguration]:\n        return []\n"
  },
  {
    "path": "superagi/tools/thinking/tools.py",
    "content": "from typing import Type, Optional, List\n\nfrom pydantic import BaseModel, Field\n\nfrom superagi.agent.agent_prompt_builder import AgentPromptBuilder\nfrom superagi.helper.error_handler import ErrorHandler\nfrom superagi.helper.prompt_reader import PromptReader\nfrom superagi.lib.logger import logger\nfrom superagi.llms.base_llm import BaseLlm\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nfrom superagi.tools.base_tool import BaseTool\nfrom superagi.tools.tool_response_query_manager import ToolResponseQueryManager\n\n\nclass ThinkingSchema(BaseModel):\n    task_description: str = Field(\n        ...,\n        description=\"Task description which needs reasoning.\",\n    )\n\nclass ThinkingTool(BaseTool):\n    \"\"\"\n    Thinking tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n        llm: LLM used for thinking.\n    \"\"\"\n    llm: Optional[BaseLlm] = None\n    name = \"ThinkingTool\"\n    description = (\n        \"Intelligent problem-solving assistant that comprehends tasks, identifies key variables, and makes efficient decisions, all while providing detailed, self-driven reasoning for its choices. Do not assume anything, take the details from given data only.\"\n    )\n    args_schema: Type[ThinkingSchema] = ThinkingSchema\n    goals: List[str] = []\n    agent_execution_id:int=None\n    agent_id:int = None\n    permission_required: bool = False\n    tool_response_manager: Optional[ToolResponseQueryManager] = None\n\n    class Config:\n        arbitrary_types_allowed = True\n\n\n    def _execute(self, task_description: str):\n        \"\"\"\n        Execute the Thinking tool.\n\n        Args:\n            task_description : The task description.\n\n        Returns:\n            Thought process of llm for the task\n        \"\"\"\n        try:\n            prompt = PromptReader.read_tools_prompt(__file__, \"thinking.txt\")\n            prompt = prompt.replace(\"{goals}\", AgentPromptBuilder.add_list_items_to_string(self.goals))\n            prompt = prompt.replace(\"{task_description}\", task_description)\n            last_tool_response = self.tool_response_manager.get_last_response()\n            prompt = prompt.replace(\"{last_tool_response}\", last_tool_response)\n            metadata = {\"agent_execution_id\":self.agent_execution_id}\n            relevant_tool_response = self.tool_response_manager.get_relevant_response(query=task_description,metadata=metadata)\n            prompt = prompt.replace(\"{relevant_tool_response}\",relevant_tool_response)\n            messages = [{\"role\": \"system\", \"content\": prompt}]\n            result = self.llm.chat_completion(messages, max_tokens=self.max_token_limit)\n            \n            if 'error' in result and result['message'] is not None:\n                ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message'])\n            return result[\"content\"]\n        except Exception as e:\n            logger.error(e)\n            return f\"Error generating text: {e}\""
  },
  {
    "path": "superagi/tools/tool_response_query_manager.py",
    "content": "from sqlalchemy.orm import Session\n\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nfrom superagi.vector_store.base import VectorStore\n\nclass ToolResponseQueryManager:\n    def __init__(self, session: Session, agent_execution_id: int,memory:VectorStore):\n        self.session = session\n        self.agent_execution_id = agent_execution_id\n        self.memory=memory\n\n    def get_last_response(self, tool_name: str = None):\n        return AgentExecutionFeed.get_last_tool_response(self.session, self.agent_execution_id, tool_name)\n\n    def get_relevant_response(self, query: str,metadata:dict, top_k: int = 5):\n        if self.memory is None:\n            return \"\"\n        documents = self.memory.get_matching_text(query, metadata=metadata)\n        relevant_responses = \"\"\n        for document in documents[\"documents\"]:\n            relevant_responses += document.text_content\n        return relevant_responses\n"
  },
  {
    "path": "superagi/tools/twitter/README.md",
    "content": "<p align=\"center\">\n<a href=\"https://superagi.com//#gh-light-mode-only\">\n<img src=\"https://superagi.com/wp-content/uploads/2023/05/Logo-dark.svg\" width=\"318px\" alt=\"SuperAGI logo\" />\n</a>\n<a href=\"https://superagi.com//#gh-dark-mode-only\">\n<img src=\"https://superagi.com/wp-content/uploads/2023/05/Logo-light.svg\" width=\"318px\" alt=\"SuperAGI logo\" />\n</a>\n</p>\n\n# SuperAGI Twitter Toolkit\n\nIntroducing Twitter Toolkit for SuperAGI. With Twitter Integrated into SuperAGI, you can now deploy agents to\n\n1. Send Tweets\n2. Send Tweets with Images\n\n## Installation\n\n### 🛠️ Setting up SuperAGI:\n\nSet up SuperAGI by following the instructions given [here](https://github.com/TransformerOptimus/SuperAGI/blob/main/README.MD)\n\n### 🔐 Obtaining API Key and Secret from Twitter Developer Portal\n\n1. Log in to your Twitter Developer Portal Account and select your project under the “Projects & Apps” section.\n\n![TW1](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/7ee7be42-2e20-4b44-beee-92b754031967)\n  \n2. Proceed with creating a new app. Once you have created the app by adding a name, you will get an API Key and an API Secret, copy that and keep it in a separate text file.\n\n![TW2](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/4d0d91ec-d22c-4027-b472-d1bc1c692ac7)\n![TW3](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/caf265e7-60ac-4a5e-be8b-4b2b9d0fdd15)\n\n\n### 🚪 Configuring OAuth\n\n3. Once you have saved the key and the secret, click on “App Settings”\n4. Once you are on the App Settings Page, start setting up the User Authentication Settings. \n\n![TW4](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/5db07a1e-3104-4a83-8de8-2394d41268ca)\n\n5. Fill in the details as shown in the below image. Give “Read and Write Permissions” and make it a “Web Application\"\n    \n![TW5](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/08d322f3-b248-49e6-8e5c-85f8d84b9a5f)\n    \n6. Add the Callback URI and the Website URL as shown in the image below\n\n![TW_OAUTH_URI](https://github.com/Phoenix2809/SuperAGI/assets/133874957/66c555f5-0546-4961-acbd-acd393c52ecf)\n\n7. Save the settings. you have now configured OAuth Authentication for Twitter.\n\n ### ✅ Configuring Keys and Authenticating in SuperAGI.\n\n1. In the SuperAGI’s Dashboard, navigate to the Twitter Toolkit Page, add the API Key and API Secret you’ve saved, and click on ‘Update Changes’\n\n![TW7](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/cab23842-e515-495a-b697-14587d832abc)\n\n2. After you’ve updated the changes, click on Authenticate. This will take you to the OAuth Flow. Authorize the app through the flow. \n\n![TW8](https://github.com/TransformerOptimus/SuperAGI/assets/133874957/62f877ac-dc1f-475d-9c5c-52040a197762)\n\nOnce you have followed the above steps, you have successfully integrated Twitter with SuperAGI. \n"
  },
  {
    "path": "superagi/tools/twitter/send_tweets.py",
    "content": "from typing import Type\n\nfrom pydantic import BaseModel, Field\n\nfrom superagi.helper.twitter_helper import TwitterHelper\nfrom superagi.helper.twitter_tokens import TwitterTokens\nfrom superagi.tools.base_tool import BaseTool\n\n\nclass SendTweetsInput(BaseModel):\n    tweet_text: str = Field(...,\n                            description=\"Tweet text to be posted from twitter handle, if no value is given keep the default value as 'None'\")\n    is_media: bool = Field(..., description=\"'True' if there is any media to be posted with Tweet else 'False'.\")\n    media_files: list = Field(..., description=\"Name of the media files to be uploaded.\")\n\n\nclass SendTweetsTool(BaseTool):\n    name: str = \"Send Tweets Tool\"\n    args_schema: Type[BaseModel] = SendTweetsInput\n    description: str = \"Send and Schedule Tweets for your Twitter Handle\"\n    agent_id: int = None\n    agent_execution_id: int = None\n\n    def _execute(self, is_media: bool, tweet_text: str = 'None', media_files: list = []):\n        toolkit_id = self.toolkit_config.toolkit_id\n        session = self.toolkit_config.session\n        creds = TwitterTokens(session).get_twitter_creds(toolkit_id)\n        params = {}\n        if is_media:\n            media_ids = TwitterHelper().get_media_ids(session, media_files, creds, self.agent_id,\n                                                      self.agent_execution_id)\n            params[\"media\"] = {\"media_ids\": media_ids}\n        if tweet_text is not None:\n            params[\"text\"] = tweet_text\n        tweet_response = TwitterHelper().send_tweets(params, creds)\n        if tweet_response.status_code == 201:\n            return \"Tweet posted successfully!!\"\n        else:\n            return \"Error posting tweet. (Status code: {})\".format(tweet_response.status_code)\n"
  },
  {
    "path": "superagi/tools/twitter/twitter_toolkit.py",
    "content": "from abc import ABC\nfrom superagi.tools.base_tool import BaseToolkit, BaseTool, ToolConfiguration\nfrom typing import Type, List\nfrom superagi.tools.twitter.send_tweets import SendTweetsTool\nfrom superagi.types.key_type import ToolConfigKeyType\n\nclass TwitterToolkit(BaseToolkit, ABC):\n    name: str = \"Twitter Toolkit\"\n    description: str = \"Twitter Tool kit contains all tools related to Twitter\"\n\n    def get_tools(self) -> List[BaseTool]:\n        return [SendTweetsTool()]\n\n    def get_env_keys(self) -> List[ToolConfiguration]:\n        return [\n            ToolConfiguration(key=\"TWITTER_API_KEY\", key_type=ToolConfigKeyType.STRING, is_required= True, is_secret = True),\n            ToolConfiguration(key=\"TWITTER_API_SECRET\", key_type=ToolConfigKeyType.STRING, is_required=True, is_secret= True)\n        ]\n"
  },
  {
    "path": "superagi/tools/webscaper/README.MD",
    "content": "<p align=center>\n<a href=\"https://superagi.co\"><img src=https://superagi.co/wp-content/uploads/2023/05/SuperAGI_icon.png></a>\n</p>\n\n# SuperAGI Web Scraper Tool\n\nThe SuperAGI Webscraper Tool lets users perform web scraping, extracting URLs and retrieving the textual content from websites.\n\n## ⚙️ Installation\n\n### 🛠 **Setting Up of SuperAGI**\nSet up the SuperAGI by following the instructions given (https://github.com/TransformerOptimus/SuperAGI/blob/main/README.MD)\n\nYou'll be able to use the Web Scraper Tool on the fly once you have setup SuperAGI.\n\n## Running SuperAGI Web Scraper Tool\n\nYou can simply ask your agent to read or go through a certain website or URL, and it'll be able to retrieve it's textual information from there."
  },
  {
    "path": "superagi/tools/webscaper/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/tools/webscaper/tools.py",
    "content": "from typing import Type, Optional\n\nfrom pydantic import BaseModel, Field\n\nfrom superagi.helper.webpage_extractor import WebpageExtractor\nfrom superagi.llms.base_llm import BaseLlm\nfrom superagi.tools.base_tool import BaseTool\n\n\nclass WebScraperSchema(BaseModel):\n    website_url: str = Field(\n        ...,\n        description=\"Valid website url without any quotes.\",\n    )\n\n\nclass WebScraperTool(BaseTool):\n    \"\"\"\n    Web Scraper tool\n\n    Attributes:\n        name : The name.\n        description : The description.\n        args_schema : The args schema.\n    \"\"\"\n    llm: Optional[BaseLlm] = None\n    name = \"WebScraperTool\"\n    description = (\n        \"Used to scrape website urls and extract text content\"\n    )\n    args_schema: Type[WebScraperSchema] = WebScraperSchema\n\n    class Config:\n        arbitrary_types_allowed = True\n\n    def _execute(self, website_url: str) -> tuple:\n        \"\"\"\n        Execute the Web Scraper tool.\n\n        Args:\n            website_url : The website url to scrape.\n\n        Returns:\n            The text content of the website.\n        \"\"\"\n        content = WebpageExtractor().extract_with_bs4(website_url)\n        max_length = len(' '.join(content.split(\" \")[:600]))\n        return content[:max_length]"
  },
  {
    "path": "superagi/tools/webscaper/web_scraper_toolkit.py",
    "content": "from abc import ABC\nfrom typing import List\nfrom superagi.tools.base_tool import BaseTool, BaseToolkit, ToolConfiguration\nfrom superagi.tools.webscaper.tools import WebScraperTool\nfrom superagi.types.key_type import ToolConfigKeyType\n\nclass WebScrapperToolkit(BaseToolkit, ABC):\n    name: str = \"Web Scrapper Toolkit\"\n    description: str = \"Web Scrapper tool kit is used to scrape web\"\n\n    def get_tools(self) -> List[BaseTool]:\n        return [\n            WebScraperTool(),\n        ]\n\n    def get_env_keys(self) -> List[ToolConfiguration]:\n        return []\n"
  },
  {
    "path": "superagi/types/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/types/common.py",
    "content": "from abc import abstractmethod\nfrom pydantic import BaseModel, Field\n\n\nclass BaseMessage(BaseModel):\n    \"\"\"Base message object.\"\"\"\n\n    content: str\n    additional_kwargs: dict = Field(default_factory=dict)\n\n    @property\n    @abstractmethod\n    def type(self) -> str:\n        \"\"\"Message type used.\"\"\"\n\n\nclass HumanMessage(BaseMessage):\n    \"\"\"Message by human.\"\"\"\n\n    example: bool = False\n\n    @property\n    def type(self) -> str:\n        return \"user\"\n\n\nclass AIMessage(BaseMessage):\n    \"\"\"Type of message that is spoken by the AI.\"\"\"\n\n    example: bool = False\n\n    @property\n    def type(self) -> str:\n        return \"assistant\"\n\n\nclass SystemMessage(BaseMessage):\n    \"\"\"Used when message is system message.\"\"\"\n\n    @property\n    def type(self) -> str:\n        return \"system\"\n\n\nclass GitHubLinkRequest(BaseModel):\n    \"\"\"Used for Request body in install API\"\"\"\n    github_link: str\n"
  },
  {
    "path": "superagi/types/key_type.py",
    "content": "from enum import Enum\n\nclass ToolConfigKeyType(Enum):\n    STRING = 'string'\n    FILE = 'file'\n    INT = 'int'\n\n    @classmethod\n    def get_key_type(cls, store):\n        store = store.upper()\n        if store in cls.__members__:\n            return cls[store]\n        raise ValueError(f\"{store} is not a valid key type.\")\n\n    def __str__(self):\n        return self.value\n"
  },
  {
    "path": "superagi/types/model_source_types.py",
    "content": "from enum import Enum\n\n\nclass ModelSourceType(Enum):\n    GooglePalm = 'Google Palm'\n    OpenAI = 'OpenAi'\n    Replicate = 'Replicate'\n    HuggingFace = 'Hugging Face'\n    LocalLLM = 'Local LLM'\n\n    @classmethod\n    def get_model_source_type(cls, name):\n        name = name.upper().replace(\" \", \"\")\n        for member in cls.__members__:\n            if name == member.upper():\n                return cls[member]\n        raise ValueError(f\"{name} is not a valid vector store name.\")\n\n    @classmethod\n    def get_model_source_from_model(cls, model_name: str):\n        open_ai_models = ['gpt-4', 'gpt-3.5-turbo', 'gpt-3.5-turbo-16k', 'gpt-4-32k']\n        google_models = ['google-palm-bison-001', 'models/chat-bison-001']\n        replicate_models = ['replicate-llama13b-v2-chat']\n        if model_name in open_ai_models:\n            return ModelSourceType.OpenAI\n        if model_name in google_models:\n            return ModelSourceType.GooglePalm\n        if model_name in replicate_models:\n            return ModelSourceType.Replicate\n        return ModelSourceType.OpenAI\n\n    def __str__(self):\n        return self.value"
  },
  {
    "path": "superagi/types/queue_status.py",
    "content": "from enum import Enum\n\n\nclass QueueStatus(Enum):\n    INITIATED = 'INITIATED'\n    PROCESSING = 'PROCESSING'\n    COMPLETE = 'COMPLETE'\n\n    @classmethod\n    def get_queue_type(cls, store):\n        if store is None:\n            raise ValueError(\"Queue status type cannot be None.\")\n        store = store.upper()\n        if store in cls.__members__:\n            return cls[store]\n        raise ValueError(f\"{store} is not a valid storage name.\")\n"
  },
  {
    "path": "superagi/types/storage_types.py",
    "content": "from enum import Enum\n\n\nclass StorageType(Enum):\n    FILE = 'FILE'\n    S3 = 'S3'\n\n    @classmethod\n    def get_storage_type(cls, store):\n        if store is None:\n            raise ValueError(\"Storage type cannot be None.\")\n        store = store.upper()\n        if store in cls.__members__:\n            return cls[store]\n        raise ValueError(f\"{store} is not a valid storage name.\")\n"
  },
  {
    "path": "superagi/types/vector_store_types.py",
    "content": "from enum import Enum\n\n\nclass VectorStoreType(Enum):\n    REDIS = 'redis'\n    PINECONE = 'pinecone'\n    CHROMA = 'chroma'\n    WEAVIATE = 'weaviate'\n    QDRANT = 'qdrant'\n    LANCEDB = 'LanceDB'\n\n    @classmethod\n    def get_vector_store_type(cls, store):\n        store = store.upper()\n        if store in cls.__members__:\n            return cls[store]\n        raise ValueError(f\"{store} is not a valid vector store name.\")\n\n    def __str__(self):\n        return self.value\n"
  },
  {
    "path": "superagi/vector_embeddings/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/vector_embeddings/base.py",
    "content": "import warnings\nfrom abc import ABC, abstractmethod\nfrom typing import Any, Iterable, List, Optional, Tuple\n\nclass VectorEmbeddings(ABC):\n\n    @abstractmethod\n    def get_vector_embeddings_from_chunks(\n        self,\n        final_chunks: Any\n    ):\n        \"\"\" Returns embeddings for vector dbs from final chunks\"\"\""
  },
  {
    "path": "superagi/vector_embeddings/pinecone.py",
    "content": "from typing import Any\nfrom superagi.vector_embeddings.base import VectorEmbeddings\n\nclass Pinecone(VectorEmbeddings):\n\n    def __init__(self, uuid, embeds, metadata):\n        self.uuid = uuid\n        self.embeds = embeds\n        self.metadata = metadata\n        \n    def get_vector_embeddings_from_chunks(self):\n        \"\"\" Returns embeddings for vector dbs from final chunks\"\"\"\n        result = {}\n        vectors = list(zip(self.uuid, self.embeds, self.metadata))\n        result['vectors'] = vectors\n        return result"
  },
  {
    "path": "superagi/vector_embeddings/qdrant.py",
    "content": "from typing import Any\nfrom superagi.vector_embeddings.base import VectorEmbeddings\n\nclass Qdrant(VectorEmbeddings):\n\n    def __init__(self, uuid, embeds, metadata):\n        self.uuid = uuid\n        self.embeds = embeds\n        self.metadata = metadata\n\n    def get_vector_embeddings_from_chunks(self):\n        \"\"\" Returns embeddings for vector dbs from final chunks\"\"\"\n        result = {}\n        result['ids'] = self.uuid\n        result['payload'] = self.metadata\n        result['vectors'] = self.embeds\n\n        return result"
  },
  {
    "path": "superagi/vector_embeddings/vector_embedding_factory.py",
    "content": "\nimport pinecone\nfrom typing import Optional\nfrom pinecone import UnauthorizedException\nfrom superagi.vector_embeddings.pinecone import Pinecone\nfrom superagi.vector_embeddings.qdrant import Qdrant\nfrom superagi.vector_embeddings.weaviate import Weaviate\nfrom superagi.types.vector_store_types import VectorStoreType\n\nclass VectorEmbeddingFactory:\n\n    @classmethod\n    def build_vector_storage(cls, vector_store: VectorStoreType, chunk_json: Optional[dict] = None):\n        \"\"\"\n        Get the vector embeddings from final chunks.\n        Args:\n            vector_store : The vector store name.\n        Returns:\n            The vector storage object\n        \"\"\"\n        final_chunks = []\n        uuid = []\n        embeds = []\n        metadata = []\n        vector_store = VectorStoreType.get_vector_store_type(vector_store)\n        if chunk_json is not None:\n            for key in chunk_json.keys():\n                final_chunks.append(chunk_json[key])\n\n            for i in range(0, len(final_chunks)):\n                uuid.append(final_chunks[i][\"id\"])\n                embeds.append(final_chunks[i][\"embeds\"])\n                data = {\n                    'text': final_chunks[i]['text'],\n                    'chunk': final_chunks[i]['chunk'],\n                    'knowledge_name': final_chunks[i]['knowledge_name']\n                }\n                metadata.append(data)\n\n        if vector_store == VectorStoreType.PINECONE:\n            return Pinecone(uuid, embeds, metadata)\n\n        if vector_store == VectorStoreType.QDRANT:\n            return Qdrant(uuid, embeds, metadata)\n        \n        if vector_store == VectorStoreType.WEAVIATE:\n            return Weaviate(uuid, embeds, metadata)"
  },
  {
    "path": "superagi/vector_embeddings/weaviate.py",
    "content": "from typing import Any\nfrom superagi.vector_embeddings.base import VectorEmbeddings\n\nclass Weaviate(VectorEmbeddings):\n\n    def __init__(self, uuid, embeds, metadata):\n        self.uuid = uuid\n        self.embeds = embeds\n        self.metadata = metadata\n\n    def get_vector_embeddings_from_chunks(self):\n        \"\"\" Returns embeddings for vector dbs from final chunks\"\"\"\n\n        return {'ids': self.uuid, 'data_object': self.metadata, 'vectors': self.embeds}\n"
  },
  {
    "path": "superagi/vector_store/__init__.py",
    "content": ""
  },
  {
    "path": "superagi/vector_store/base.py",
    "content": "import warnings\nfrom abc import ABC, abstractmethod\nfrom typing import Any, Iterable, List, Optional, Tuple\nfrom superagi.vector_store.document import Document\n\n\nclass VectorStore(ABC):\n    @abstractmethod\n    def add_texts(\n            self,\n            texts: Iterable[str],\n            metadatas: Optional[List[dict]] = None,\n            **kwargs: Any,\n    ) -> List[str]:\n        \"\"\"Add texts to the vector store.\"\"\"\n\n    @abstractmethod\n    def get_matching_text(self, query: str, top_k: int, metadata: Optional[dict], **kwargs: Any) -> List[Document]:\n        \"\"\"Return docs most similar to query using specified search type.\"\"\"\n\n    def add_documents(self, documents: List[Document], **kwargs: Any) -> List[str]:\n        \"\"\"Run more documents through the embeddings and add to the vectorstore.\n        \"\"\"\n        texts = [doc.text_content for doc in documents]\n        metadatas = [doc.metadata for doc in documents]\n        return self.add_texts(texts, metadatas, **kwargs)\n    \n    @abstractmethod\n    def get_index_stats(self) -> dict:\n        \"\"\"Returns stats or information of an index\"\"\"\n    \n    @abstractmethod\n    def add_embeddings_to_vector_db(self, embeddings: dict) -> None:\n        \"\"\"Add embeddings to the vector store.\"\"\"\n    \n    @abstractmethod\n    def delete_embeddings_from_vector_db(self,ids: List[str]) -> None:\n        \"\"\"Delete embeddings from the vector store.\"\"\""
  },
  {
    "path": "superagi/vector_store/chromadb.py",
    "content": "import uuid\nfrom typing import Any, Optional, Iterable, List\n\nimport chromadb\nfrom chromadb import Settings\n\nfrom superagi.config.config import get_config\nfrom superagi.vector_store.base import VectorStore\nfrom superagi.vector_store.document import Document\nfrom superagi.vector_store.embedding.base import BaseEmbedding\n\ndef _build_chroma_client():\n    chroma_host_name = get_config(\"CHROMA_HOST_NAME\") or \"localhost\"\n    chroma_port = get_config(\"CHROMA_PORT\") or 8000\n    return chromadb.Client(Settings(chroma_api_impl=\"rest\", chroma_server_host=chroma_host_name,\n                                    chroma_server_http_port=chroma_port))\n\n\nclass ChromaDB(VectorStore):\n    def __init__(\n            self,\n            collection_name: str,\n            embedding_model: BaseEmbedding,\n            text_field: str,\n            namespace: Optional[str] = \"\",\n    ):\n        self.client = _build_chroma_client()\n        self.collection_name = collection_name\n        self.embedding_model = embedding_model\n        self.text_field = text_field\n        self.namespace = namespace\n\n    @classmethod\n    def create_collection(cls, collection_name):\n        \"\"\"Create a Chroma Collection.\n        Args:\n        collection_name: The name of the collection to create.\n        \"\"\"\n        chroma_client = _build_chroma_client()\n        return chroma_client.get_or_create_collection(name=collection_name)\n\n    def add_texts(\n            self,\n            texts: Iterable[str],\n            metadatas: Optional[List[dict]] = None,\n            ids: Optional[List[str]] = None,\n            namespace: Optional[str] = None,\n            batch_size: int = 32,\n            **kwargs: Any,\n    ) -> List[str]:\n        \"\"\"Add texts to the vector store.\"\"\"\n        if namespace is None:\n            namespace = self.namespace\n\n        metadatas = []\n        ids = ids or [str(uuid.uuid4()) for _ in texts]\n        if len(ids) < len(texts):\n            raise ValueError(\"Number of ids must match number of texts.\")\n\n        for text, id in zip(texts, ids):\n            metadata = metadatas.pop(0) if metadatas else {}\n            metadata[self.text_field] = text\n            metadatas.append(metadata)\n        collection = self.client.get_collection(name=self.collection_name)\n        collection.add(\n            documents=texts,\n            metadatas=metadatas,\n            ids=ids\n        )\n\n        return ids\n\n    def get_matching_text(self, query: str, top_k: int = 5, metadata: Optional[dict] = {}, **kwargs: Any) -> List[\n        Document]:\n        \"\"\"Return docs most similar to query using specified search type.\"\"\"\n        embedding_vector = self.embedding_model.get_embedding(query)\n        collection = self.client.get_collection(name=self.collection_name)\n        filters = {}\n        for key in metadata.keys():\n            filters[key] = metadata[key]\n        results = collection.query(\n            query_embeddings=embedding_vector,\n            include=[\"documents\"],\n            n_results=top_k,\n            where=filters\n        )\n\n        documents = []\n\n        for node_id, text, metadata in zip(\n                results[\"ids\"][0],\n                results[\"documents\"][0],\n                results[\"metadatas\"][0]):\n            documents.append(\n                Document(\n                    text_content=text,\n                    metadata=metadata\n                )\n            )\n\n        return documents\n\n    def get_index_stats(self) -> dict:\n        pass\n\n    def add_embeddings_to_vector_db(self, embeddings: dict) -> None:\n        pass\n\n    def delete_embeddings_from_vector_db(self, ids: List[str]) -> None:\n        pass"
  },
  {
    "path": "superagi/vector_store/document.py",
    "content": "from pydantic import BaseModel, Field\n\n\nclass Document(BaseModel):\n    \"\"\"Interface for interacting with a document.\"\"\"\n\n    text_content: str = None\n    metadata: dict = Field(default_factory=dict)\n\n    def __init__(self, text_content, *args, **kwargs):\n        super().__init__(text_content=text_content, *args, **kwargs)"
  },
  {
    "path": "superagi/vector_store/embedding/__init__.py",
    "content": "from superagi.vector_store.embedding.openai import OpenAiEmbedding\nfrom superagi.vector_store.embedding.palm import PalmEmbedding\n\n__all__ = ['OpenAiEmbedding', 'PalmEmbedding']"
  },
  {
    "path": "superagi/vector_store/embedding/base.py",
    "content": "from abc import ABC, abstractmethod\n\n\nclass BaseEmbedding(ABC):\n\n    @abstractmethod\n    def get_embedding(self, text):\n        pass\n"
  },
  {
    "path": "superagi/vector_store/embedding/openai.py",
    "content": "import openai\n\n\nclass OpenAiEmbedding:\n    def __init__(self, api_key, model=\"text-embedding-ada-002\"):\n        self.model = model\n        self.api_key = api_key\n        \n    async def get_embedding_async(self, text: str):\n        try:\n            openai.api_key = self.api_key\n            response = await openai.Embedding.create(\n                                input=[text],\n                engine=self.model\n            )\n            return response['data'][0]['embedding']\n        except Exception as exception:\n            return {\"error\": exception}    \n\n               \n    def get_embedding(self, text):\n        try:\n            # openai.api_key = get_config(\"OPENAI_API_KEY\")\n            response = openai.Embedding.create(\n                api_key=self.api_key,\n                input=[text],\n                engine=self.model\n            )\n            return response['data'][0]['embedding']\n        except Exception as exception:\n            return {\"error\": exception}\n"
  },
  {
    "path": "superagi/vector_store/embedding/palm.py",
    "content": "import openai\nimport google.generativeai as palm\n\n\nclass PalmEmbedding:\n    def __init__(self, api_key, model=\"models/embedding-gecko-001\"):\n        self.model = model\n        self.api_key = api_key\n\n    def get_embedding(self, text):\n        try:\n            response = palm.generate_embeddings(model=self.model, text=text)\n            return response['embedding']\n        except Exception as exception:\n            return {\"error\": exception}\n"
  },
  {
    "path": "superagi/vector_store/pinecone.py",
    "content": "import uuid\n\nfrom superagi.vector_store.document import Document\nfrom superagi.vector_store.base import VectorStore\nfrom typing import Any, Callable, Optional, Iterable, List\n\nfrom superagi.vector_store.embedding.base import BaseEmbedding\n\n\nclass Pinecone(VectorStore):\n    \"\"\"\n    Pinecone vector store.\n\n    Attributes:\n        index : The pinecone index.\n        embedding_model : The embedding model.\n        text_field : The text field is the name of the field where the corresponding text for an embedding is stored.\n        namespace : The namespace.\n    \"\"\"\n    def __init__(\n            self,\n            index: Any,\n            embedding_model: Optional[Any] = None,\n            text_field: Optional[str] = 'text',\n            namespace: Optional[str] = '',\n    ):\n        try:\n            import pinecone\n        except ImportError:\n            raise ValueError(\"Please install pinecone to use this vector store.\")\n\n        if not isinstance(index, pinecone.index.Index):\n            raise ValueError(\"Please provide a valid pinecone index.\")\n\n        self.index = index\n        self.embedding_model = embedding_model\n        self.text_field = text_field\n        self.namespace = namespace\n\n    def add_texts(\n            self,\n            texts: Iterable[str],\n            metadatas: Optional[list[dict]] = None,\n            ids: Optional[list[str]] = None,\n            namespace: Optional[str] = None,\n            batch_size: int = 32,\n            **kwargs: Any,\n    ) -> list[str]:\n        \"\"\"\n        Add texts to the vector store.\n\n        Args:\n            texts : The texts to add.\n            metadatas : The metadatas to add.\n            ids : The ids to add.\n            namespace : The namespace to add.\n            batch_size : The batch size to add.\n            **kwargs : The keyword arguments to add.\n\n        Returns:\n            The list of ids vectors stored in pinecone.\n        \"\"\"\n        if namespace is None:\n            namespace = self.namespace\n\n        vectors = []\n        ids = ids or [str(uuid.uuid4()) for _ in texts]\n        if len(ids) < len(texts):\n            raise ValueError(\"Number of ids must match number of texts.\")\n\n        for text, id in zip(texts, ids):\n            metadata = metadatas.pop(0) if metadatas else {}\n            metadata[self.text_field] = text\n            vectors.append((id, self.embedding_model.get_embedding(text), metadata))\n\n        self.add_embeddings_to_vector_db({\"vectors\": vectors})\n        return ids\n\n    def get_matching_text(self, query: str, top_k: int = 5, metadata: Optional[dict] = None, **kwargs: Any) -> List[Document]:\n        \"\"\"\n        Return docs most similar to query using specified search type.\n\n        Args:\n            query : The query to search.\n            top_k : The top k to search.\n            **kwargs : The keyword arguments to search.\n\n        Returns:\n            The list of documents most similar to the query\n        \"\"\"\n        namespace = kwargs.get(\"namespace\", self.namespace)\n        filters = {}\n        if metadata is not None:\n            for key in metadata.keys():\n                filters[key] = {\"$eq\": metadata[key]}\n        embed_text = self.embedding_model.get_embedding(query)\n        res = self.index.query(embed_text, filter=filters, top_k=top_k, namespace=namespace,include_metadata=True)\n        search_res = self._get_search_text(res, query)\n\n        documents = self._build_documents(res)\n        return {\"documents\": documents, \"search_res\": search_res}\n\n    def get_index_stats(self) -> dict:\n        \"\"\"\n        Returns:\n            Stats or Information about an index\n        \"\"\"\n        index_stats = self.index.describe_index_stats()\n        dimensions = index_stats.dimension\n        vector_count = index_stats.total_vector_count\n        return {\"dimensions\": dimensions, \"vector_count\": vector_count}\n\n    def add_embeddings_to_vector_db(self, embeddings: dict) -> None:\n        \"\"\"Upserts embeddings to the given vector store\"\"\"\n        try:\n            self.index.upsert(vectors=embeddings['vectors'])\n        except Exception as err:\n            raise err\n\n    def delete_embeddings_from_vector_db(self, ids: List[str]) -> None:\n        \"\"\"Deletes embeddings from the given vector store\"\"\"\n        try:\n            self.index.delete(ids=ids)\n        except Exception as err:\n            raise err\n\n    def _build_documents(self, results: List[dict]):\n        try:\n            documents = []\n            for doc in results['matches']:\n                documents.append(\n                    Document(\n                        text_content=doc['metadata'][self.text_field],\n                        metadata=doc['metadata'],\n                    )\n                )\n            return documents\n        except Exception as err:\n            raise err\n\n    def _get_search_text(self, results: List[dict], query: str):\n        contexts = [item['metadata']['text'] for item in results['matches']]\n        i = 0\n        search_res = f\"Query: {query}\\n\"\n        for context in contexts:\n            search_res += f\"Chunk{i}: \\n{context}\\n\"\n            i += 1\n        return search_res"
  },
  {
    "path": "superagi/vector_store/qdrant.py",
    "content": "from __future__ import annotations\n\nimport uuid\nfrom mimetypes import common_types\nfrom typing import Any, Dict, Iterable, List, Optional, Tuple, Sequence, Union\n\nfrom qdrant_client import QdrantClient\nfrom qdrant_client.http import models\nfrom qdrant_client.conversions import common_types\nfrom qdrant_client.models import Distance, VectorParams\n\nfrom superagi.vector_store.base import VectorStore\nfrom superagi.vector_store.document import Document\nfrom superagi.config.config import get_config\n\nDictFilter = Dict[str, Union[str, int, bool, dict, list]]\nMetadataFilter = Union[DictFilter, common_types.Filter]\n\n\ndef create_qdrant_client(api_key: Optional[str] = None, url: Optional[str] = None, port: Optional[int] = None\n) -> QdrantClient:\n    if api_key is None:\n        qdrant_host_name = get_config(\"QDRANT_HOST_NAME\") or \"localhost\"\n        qdrant_port = get_config(\"QDRANT_PORT\") or 6333\n        qdrant_client = QdrantClient(host=qdrant_host_name, port=qdrant_port)\n    else:\n        qdrant_client = QdrantClient(api_key=api_key, url=url, port=port)\n    return qdrant_client\n\n\nclass Qdrant(VectorStore):\n    \"\"\"\n    Qdrant vector store.\n\n    Attributes:\n        client : The Qdrant client.\n        embedding_model : The embedding model.\n        collection_name : The Qdrant collection.\n        text_field_payload_key : Name of the field where the corresponding text for point is stored in the collection.\n        metadata_payload_key : Name of the field where the corresponding metadata for point is stored in the collection.\n    \"\"\"\n    TEXT_FIELD_KEY = \"text\"\n    METADATA_KEY = \"metadata\"\n\n    def __init__(\n            self,\n            client: QdrantClient,\n            embedding_model: Optional[Any] = None,\n            collection_name: str = None,\n            text_field_payload_key: str = TEXT_FIELD_KEY,\n            metadata_payload_key: str = METADATA_KEY,\n    ):\n        self.client = client\n        self.embedding_model = embedding_model\n        self.collection_name = collection_name\n        self.text_field_payload_key = text_field_payload_key or self.TEXT_FIELD_KEY\n        self.metadata_payload_key = metadata_payload_key or self.METADATA_KEY\n\n    def add_texts(\n            self,\n            input_texts: Iterable[str],\n            metadata_list: Optional[List[dict]] = None,\n            id_list: Optional[Sequence[str]] = None,\n            batch_limit: int = 64,\n    ) -> List[str]:\n        \"\"\"\n        Add texts to the vector store.\n\n        Args:\n            input_texts : The texts to add.\n            metadata_list : The metadatas to add.\n            id_list : The ids to add.\n            batch_limit : The batch size to add.\n\n        Returns:\n            The list of ids vectors stored in Qdrant.\n        \"\"\"\n        collected_ids = []\n        metadata_list = metadata_list or []\n        id_list = id_list or [uuid.uuid4().hex for _ in input_texts]\n        num_batches = len(input_texts) // batch_limit + (len(input_texts) % batch_limit != 0)\n\n        for i in range(num_batches):\n            text_batch = input_texts[i * batch_limit: (i + 1) * batch_limit]\n            metadata_batch = metadata_list[i * batch_limit: (i + 1) * batch_limit] or None\n            id_batch = id_list[i * batch_limit: (i + 1) * batch_limit]\n            vectors = self.__get_embeddings(text_batch)\n            payloads = self.__build_payloads(\n                text_batch,\n                metadata_batch,\n                self.text_field_payload_key,\n                self.metadata_payload_key,\n            )\n            self.add_embeddings_to_vector_db({\"ids\": id_batch, \"vectors\": vectors, \"payloads\": payloads})\n            collected_ids.extend(id_batch)\n\n        return collected_ids\n    \n    def get_matching_text(\n            self,\n            text: str = None,\n            embedding: List[float] = None,\n            k: int = 4,\n            metadata: Optional[dict] = None,\n            search_params: Optional[common_types.SearchParams] = None,\n            offset: int = 0,\n            score_threshold: Optional[float] = None,\n            consistency: Optional[common_types.ReadConsistency] = None,\n            **kwargs: Any,\n    ) -> Dict:\n        \"\"\"\n        Return docs most similar to query using specified search type.\n\n        Args:\n            embedding: Embedding vector to look up documents similar to.\n            k: Number of Documents to return.\n            text : The text to search.\n            filter: Filter by metadata. (Please refer https://qdrant.tech/documentation/concepts/filtering/)\n            search_params: Additional search params\n            offset: Offset of the first result to return.\n            score_threshold: Define a minimal score threshold for the result.\n            consistency: Read consistency of the search. Defines how many replicas\n                         should be queried before returning the result.\n            **kwargs : The keyword arguments to search.\n\n        Returns:\n            The list of documents most similar to the query\n        \"\"\"\n        if embedding is not None and text is not None:\n            raise ValueError(\"Only provide embedding or text\")\n        if text is not None:\n            embedding = self.__get_embeddings(text)[0]\n\n        if metadata is not None:\n            filter_conditions = []\n            for key, value in metadata.items():\n                metadata_filter = {}\n                metadata_filter[\"key\"] = key\n                metadata_filter[\"match\"] = {\"value\": value}\n                filter_conditions.append(metadata_filter)\n            filter = models.Filter(\n                must = filter_conditions\n            )\n        try:\n            results = self.client.search(\n            collection_name=self.collection_name,\n            query_vector=embedding,\n            query_filter=filter,\n            search_params=search_params,\n            limit=k,\n            offset=offset,\n            with_payload=True,\n            with_vectors=False,\n            score_threshold=score_threshold,\n            consistency=consistency,\n            **kwargs,\n            )\n        except Exception as err:\n            raise err\n        search_res = self._get_search_res(results, text)\n        documents =  self.__build_documents(results)\n\n        return {\"documents\": documents, \"search_res\": search_res}\n    \n    def get_index_stats(self) -> dict:\n        \"\"\"\n        Returns:\n            Stats or Information about a collection\n        \"\"\"\n        collection_info = self.client.get_collection(collection_name=self.collection_name)\n        dimensions = collection_info.config.params.vectors.size\n        vector_count = collection_info.vectors_count\n\n        return {\"dimensions\": dimensions, \"vector_count\": vector_count}\n    \n    def add_embeddings_to_vector_db(self, embeddings: dict) -> None:\n        \"\"\"Upserts embeddings to the given vector store\"\"\"\n        try:\n            self.client.upsert(\n                collection_name=self.collection_name,\n                points=models.Batch(\n                    ids=embeddings[\"ids\"],\n                    vectors=embeddings[\"vectors\"],\n                    payloads=embeddings[\"payload\"]\n                ),\n            )\n        except Exception as err:\n            raise err\n        \n    def delete_embeddings_from_vector_db(self, ids: List[str]) -> None:\n        \"\"\"Deletes embeddings from the given vector store\"\"\"\n        try:\n            self.client.delete(\n                collection_name=self.collection_name,\n                points_selector = models.PointIdsList(\n                    points = ids\n                ),\n            )\n        except Exception as err:\n            raise err\n        \n    def __get_embeddings(\n            self,\n            texts: Iterable[str]\n    ) -> List[List[float]]:\n        \"\"\"Return embeddings for a list of texts using the embedding model.\"\"\"\n        if self.embedding_model is not None:\n            query_vectors = []\n            for text in texts:\n                query_vector = self.embedding_model.get_embedding(text)\n                query_vectors.append(query_vector)\n        else:\n            raise ValueError(\"Embedding model is not set\")\n        \n        return query_vectors\n    \n    def __build_payloads(\n            self,\n            texts: Iterable[str],\n            metadatas: Optional[List[dict]],\n            text_field_payload_key: str,\n            metadata_payload_key: str,\n    ) -> List[dict]:\n        \"\"\"\n        Builds and returns a list of payloads containing text and\n        corresponding metadata for each text in the input iterable.\n        \"\"\"\n        payloads = []\n        for i, text in enumerate(texts):\n            if text is None:\n                raise ValueError(\n                    \"One or more of the text entries is set to None. \"\n                    \"Ensure to eliminate these before invoking the .add_texts method on the Qdrant instance.\"\n                )\n            metadata = metadatas[i] if metadatas is not None else None\n            payloads.append(\n                {\n                    text_field_payload_key: text,\n                    metadata_payload_key: metadata,\n                }\n            )\n\n        return payloads\n    \n    def __build_documents(\n            self,\n            results: List[Dict]\n    ) -> List[Document]:\n        \"\"\"Return the document version corresponding to each result.\"\"\"\n        documents = []\n        for result in results:\n            documents.append(\n                Document(\n                    text_content=result.payload.get(self.text_field_payload_key),\n                    metadata=(result.payload.get(self.metadata_payload_key)) or {},\n                )\n            )\n\n        return documents\n    \n    @classmethod\n    def create_collection(cls,\n                          client: QdrantClient,\n                          collection_name: str,\n                          size: int\n                          ):\n        \"\"\"\n        Create a new collection in Qdrant if it does not exist.\n        \n        Args:\n            client : The Qdrant client.\n            collection_name: The name of the collection to create.\n            size: The size for the new collection.\n        \"\"\"\n        if not any(collection.name == collection_name for collection in client.get_collections().collections):\n            client.create_collection(\n                collection_name=collection_name,\n                vectors_config=VectorParams(size=size, distance=Distance.COSINE),\n            )\n    \n    def _get_search_res(self, results, text):\n        contexts = [res.payload for res in results]\n        i = 0\n        search_res = f\"Query: {text}\\n\"\n        for context in contexts:\n            search_res += f\"Chunk{i}: \\n{context['text']}\\n\"\n            i += 1\n        return search_res"
  },
  {
    "path": "superagi/vector_store/redis.py",
    "content": "import json\nimport re\nimport uuid\nfrom typing import Any, List, Iterable, Mapping\nfrom typing import Optional, Pattern\nimport traceback\nimport numpy as np\nimport redis\nfrom redis.commands.search.field import TagField, VectorField\nfrom redis.commands.search.indexDefinition import IndexDefinition, IndexType\n\nfrom superagi.config.config import get_config\nfrom superagi.lib.logger import logger\nfrom superagi.vector_store.base import VectorStore\nfrom superagi.vector_store.document import Document\n\nDOC_PREFIX = \"doc:\"\n\nCONTENT_KEY = \"content\"\nMETADATA_KEY = \"metadata\"\nVECTOR_SCORE_KEY = \"vector_score\"\n\n\nclass Redis(VectorStore):\n\n    def delete_embeddings_from_vector_db(self, ids: List[str]) -> None:\n        pass\n\n    def add_embeddings_to_vector_db(self, embeddings: dict) -> None:\n        pass\n\n    def get_index_stats(self) -> dict:\n        pass\n\n    DEFAULT_ESCAPED_CHARS = r\"[,.<>{}\\[\\]\\\\\\\"\\':;!@#$%^&*()\\-+=~\\/ ]\"\n\n    def __init__(self, index: Any, embedding_model: Any):\n        \"\"\"\n        Args:\n        index: An instance of a Redis index.\n        embedding_model: An instance of a BaseEmbedding model.\n        vector_group_id: vector group id used to index similar vectors.\n        \"\"\"\n        redis_url = get_config('REDIS_URL')\n        self.redis_client = redis.Redis.from_url(\"redis://\" + redis_url + \"/0\", decode_responses=True)\n        # self.redis_client = redis.Redis(host=redis_host, port=redis_port)\n        self.index = index\n        self.embedding_model = embedding_model\n        self.content_key = \"content\",\n        self.metadata_key = \"metadata\"\n        self.index = index\n        self.vector_key = \"content_vector\"\n\n    def build_redis_key(self, prefix: str) -> str:\n        \"\"\"Build a redis key with a prefix.\"\"\"\n        return f\"{prefix}:{uuid.uuid4().hex}\"\n\n    def add_texts(self, texts: Iterable[str],\n                  metadatas: Optional[List[dict]] = None,\n                  embeddings: Optional[List[List[float]]] = None,\n                  ids: Optional[list[str]] = None,\n                  **kwargs: Any) -> List[str]:\n        pipe = self.redis_client.pipeline()\n        prefix = DOC_PREFIX + str(self.index)\n        keys = []\n        for i, text in enumerate(texts):\n            id = ids[i] if ids else self.build_redis_key(prefix)\n            metadata = metadatas[i] if metadatas else {}\n            embedding = self.embedding_model.get_embedding(text)\n            embedding_arr = np.array(embedding, dtype=np.float32)\n\n            pipe.hset(id, mapping={CONTENT_KEY: text, self.vector_key: embedding_arr.tobytes(),\n                                   METADATA_KEY: json.dumps(metadata)})\n\n            keys.append(id)\n        pipe.execute()\n        return keys\n\n    def get_matching_text(self, query: str, top_k: int = 5, metadata: Optional[dict] = None, **kwargs: Any) -> List[Document]:\n        \n            embed_text = self.embedding_model.get_embedding(query)\n            from redis.commands.search.query import Query\n            hybrid_fields = self._convert_to_redis_filters(metadata)\n            \n            base_query = f\"{hybrid_fields}=>[KNN {top_k} @{self.vector_key} $vector AS vector_score]\"\n            return_fields = [METADATA_KEY,CONTENT_KEY, \"vector_score\",'id']          \n            query = (\n                Query(base_query)\n                .return_fields(*return_fields)\n                .sort_by(\"vector_score\")\n                .paging(0, top_k)\n                .dialect(2)\n            )\n\n            params_dict: Mapping[str, str] = {\n                \"vector\": np.array(embed_text)\n                .astype(dtype=np.float32)\n                .tobytes()\n            }\n\n            # print(self.index)\n            results = self.redis_client.ft(self.index).search(query,params_dict)\n            \n                # Prepare document results\n            documents = []\n            for result in results.docs:\n                documents.append(\n                    Document(\n                        text_content=result.content,\n                        metadata=json.loads(result.metadata)\n                    )\n                )\n            return {\"documents\": documents}\n        \n        \n\n    def _convert_to_redis_filters(self, metadata: Optional[dict] = None) -> str:\n        if metadata is not None or len(metadata) == 0:\n            return \"*\"\n        filter_strings = []\n        for key in metadata.keys():\n            filter_string = \"@%s:{%s}\" % (key, self.escape_token(str(metadata[key])))\n            filter_strings.append(filter_string)\n\n        joined_filter_strings = \" & \".join(filter_strings)\n        return f\"({joined_filter_strings})\"\n\n    def create_index(self):\n        try:\n            # check to see if index exists\n            temp = self.redis_client.ft(self.index).info()\n            logger.info(temp)\n            logger.info(\"Index already exists!\")\n        except:\n            vector_dimensions = self.embedding_model.get_embedding(\"sample\")\n            # schema\n            schema = (\n                TagField(\"tag\"),  # Tag Field Name\n                VectorField(self.vector_key,  # Vector Field Name\n                            \"FLAT\", {  # Vector Index Type: FLAT or HNSW\n                                \"TYPE\": \"FLOAT32\",  # FLOAT32 or FLOAT64\n                                \"DIM\": len(vector_dimensions),  # Number of Vector Dimensions\n                                \"DISTANCE_METRIC\": \"COSINE\",  # Vector Search Distance Metric\n                            }\n                            )\n            )\n\n            # index Definition\n            definition = IndexDefinition(prefix=[DOC_PREFIX], index_type=IndexType.HASH)\n\n            # create Index\n            self.redis_client.ft(self.index).create_index(fields=schema, definition=definition)\n\n    def escape_token(self, value: str) -> str:\n        \"\"\"\n        Escape punctuation within an input string. Taken from RedisOM Python.\n\n        Args:\n            value (str): The input string.\n\n        Returns:\n            str: The escaped string.\n        \"\"\"\n        escaped_chars_re = re.compile(Redis.DEFAULT_ESCAPED_CHARS)\n\n        def escape_symbol(match: re.Match) -> str:\n            return f\"\\\\{match.group(0)}\"\n\n        return escaped_chars_re.sub(escape_symbol, value)"
  },
  {
    "path": "superagi/vector_store/vector_factory.py",
    "content": "import pinecone\nfrom pinecone import UnauthorizedException\n\nfrom superagi.vector_store.pinecone import Pinecone\nfrom superagi.vector_store import weaviate\nfrom superagi.config.config import get_config\nfrom superagi.lib.logger import logger\nfrom superagi.types.vector_store_types import VectorStoreType\nfrom superagi.vector_store import qdrant\nfrom superagi.vector_store.redis import Redis\nfrom superagi.vector_store.embedding.openai import OpenAiEmbedding\nfrom superagi.vector_store.qdrant import Qdrant\n\n\nclass VectorFactory:\n\n    @classmethod\n    def get_vector_storage(cls, vector_store: VectorStoreType, index_name, embedding_model):\n        \"\"\"\n        Get the vector storage.\n\n        Args:\n            vector_store : The vector store name.\n            index_name : The index name.\n            embedding_model : The embedding model.\n\n        Returns:\n            The vector storage object.\n        \"\"\"\n        if isinstance(vector_store, str):\n            vector_store = VectorStoreType.get_vector_store_type(vector_store)\n        if vector_store == VectorStoreType.PINECONE:\n            try:\n                api_key = get_config(\"PINECONE_API_KEY\")\n                env = get_config(\"PINECONE_ENVIRONMENT\")\n                if api_key is None or env is None:\n                    raise ValueError(\"PineCone API key not found\")\n                pinecone.init(api_key=api_key, environment=env)\n\n                if index_name not in pinecone.list_indexes():\n                    sample_embedding = embedding_model.get_embedding(\"sample\")\n                    if \"error\" in sample_embedding:\n                        logger.error(f\"Error in embedding model {sample_embedding}\")\n\n                    # if does not exist, create index\n                    pinecone.create_index(\n                        index_name,\n                        dimension=len(sample_embedding),\n                        metric='dotproduct'\n                    )\n                index = pinecone.Index(index_name)\n                return Pinecone(index, embedding_model, 'text')\n            except UnauthorizedException:\n                raise ValueError(\"PineCone API key not found\")\n\n        if vector_store == VectorStoreType.WEAVIATE:\n            use_embedded = get_config(\"WEAVIATE_USE_EMBEDDED\")\n            url = get_config(\"WEAVIATE_URL\")\n            api_key = get_config(\"WEAVIATE_API_KEY\")\n\n            client = weaviate.create_weaviate_client(\n                use_embedded=use_embedded,\n                url=url,\n                api_key=api_key\n            )\n            return weaviate.Weaviate(client, embedding_model, index_name, 'text')\n\n        if vector_store == VectorStoreType.QDRANT:\n            client = qdrant.create_qdrant_client()\n            sample_embedding = embedding_model.get_embedding(\"sample\")\n            if \"error\" in sample_embedding:\n                logger.error(f\"Error in embedding model {sample_embedding}\")\n\n            Qdrant.create_collection(client, index_name, len(sample_embedding))\n            return qdrant.Qdrant(client, embedding_model, index_name)\n        \n        if vector_store == VectorStoreType.REDIS:\n            index_name = \"super-agent-index1\"\n            redis = Redis(index_name, embedding_model)\n            redis.create_index()\n            return redis\n\n        raise ValueError(f\"Vector store {vector_store} not supported\")\n    \n    @classmethod\n    def build_vector_storage(cls, vector_store: VectorStoreType, index_name, embedding_model = None, **creds):\n        if isinstance(vector_store, str):\n            vector_store = VectorStoreType.get_vector_store_type(vector_store)\n        \n        if vector_store == VectorStoreType.PINECONE:\n            try:\n                pinecone.init(api_key = creds[\"api_key\"], environment = creds[\"environment\"])\n                index = pinecone.Index(index_name)\n                return Pinecone(index, embedding_model)\n            except UnauthorizedException:\n                raise ValueError(\"PineCone API key not found\")\n        \n        if vector_store == VectorStoreType.QDRANT:\n            try:\n                client = qdrant.create_qdrant_client(creds[\"api_key\"], creds[\"url\"], creds[\"port\"])\n                return qdrant.Qdrant(client, embedding_model, index_name)\n            except:\n                raise ValueError(\"Qdrant API key not found\")\n\n        if vector_store == VectorStoreType.WEAVIATE:\n            try:\n                client = weaviate.create_weaviate_client(creds[\"url\"], creds[\"api_key\"])\n                return weaviate.Weaviate(client, embedding_model, index_name)\n            except:\n                raise ValueError(\"Weaviate API key not found\")\n"
  },
  {
    "path": "superagi/vector_store/weaviate.py",
    "content": "from __future__ import annotations\n\nfrom abc import abstractmethod\nfrom typing import Any, Dict, Iterable, List, Optional, Tuple\n\nimport weaviate\nfrom uuid import uuid4\nfrom superagi.vector_store.base import VectorStore\nfrom superagi.vector_store.document import Document\n\n\ndef create_weaviate_client(\n    url: Optional[str] = None,\n    api_key: Optional[str] = None,\n) -> weaviate.Client:\n    \"\"\"\n    Creates a Weaviate client instance.\n\n    Args:\n        use_embedded: Whether to use the embedded Weaviate instance. Defaults to True.\n        url: The URL of the Weaviate instance to connect to. Required if `use_embedded` is False.\n        api_key: The API key to use for authentication if using Weaviate Cloud Services. Optional.\n\n    Returns:\n        A Weaviate client instance.\n\n    Raises:\n        ValueError: If invalid argument combination are passed.\n    \"\"\"\n    if url:\n        if api_key:\n            auth_config = weaviate.AuthApiKey(api_key=api_key)\n        else:\n            auth_config = None\n\n        client = weaviate.Client(url=url, auth_client_secret=auth_config)\n    else:\n        raise ValueError(\"Invalid arguments passed to create_weaviate_client\")\n\n    return client\n\n\nclass Weaviate(VectorStore):\n    def __init__(\n        self, client: weaviate.Client, embedding_model: Any, class_name: str, text_field: str = \"text\"\n    ):\n        self.class_name = class_name\n        self.embedding_model = embedding_model\n        self.text_field = text_field\n\n        self.client = client\n\n    def add_texts(\n        self, texts: Iterable[str], metadatas: List[dict] | None = None, **kwargs: Any\n    ) -> List[str]:\n        result = {}\n        collected_ids = []\n        for i, text in enumerate(texts):\n            metadata = metadatas[i] if metadatas else {}\n            data_object = metadata.copy()\n            data_object[self.text_field] = text\n            vector = self.embedding_model.get_embedding(text)\n            id = str(uuid4())\n            result = {\"ids\": id, \"data_object\": data_object, \"vectors\": vector}\n            collected_ids.append(id)\n            self.add_embeddings_to_vector_db(result)\n        return collected_ids\n\n    def get_matching_text(\n        self, query: str, top_k: int = 5, metadata: dict = None, **kwargs: Any\n    ) -> List[Document]:\n        metadata_fields = self._get_metadata_fields()\n        query_vector = self.embedding_model.get_embedding(query)\n        if metadata is not None:\n            for key, value in metadata.items():\n                filters = {\n                    \"path\": [key],\n                    \"operator\": \"Equal\",\n                    \"valueString\": value\n                }\n\n        results = self.client.query.get(\n            self.class_name,\n            metadata_fields + [self.text_field],\n        ).with_near_vector(\n            {\"vector\": query_vector, \"certainty\": 0.7}\n        ).with_where(filters).with_limit(top_k).do()\n\n        results_data = results[\"data\"][\"Get\"][self.class_name]\n        search_res = self._get_search_res(results_data, query)\n        documents = self._build_documents(results_data, metadata_fields)\n\n        return {\"search_res\": search_res, \"documents\": documents}\n    \n    def _get_metadata_fields(self) -> List[str]:\n        schema = self.client.schema.get(self.class_name)\n        property_names = []\n        for property_schema in schema[\"properties\"]:\n            property_names.append(property_schema[\"name\"])\n\n        property_names.remove(self.text_field)\n        return property_names\n\n    def get_index_stats(self) -> dict:\n        result = self.client.query.aggregate(self.class_name).with_meta_count().do()\n        vector_count = result['data']['Aggregate'][self.class_name][0]['meta']['count']\n        return {'vector_count': vector_count}\n\n    def add_embeddings_to_vector_db(self, embeddings: dict) -> None:\n        try:\n            with self.client.batch as batch:\n                for i in range(len(embeddings['ids'])):\n                    data_object = {key: value for key, value in embeddings['data_object'][i].items()}\n                    batch.add_data_object(data_object, class_name=self.class_name, uuid=embeddings['ids'][i], vector=embeddings['vectors'][i])\n        except Exception as err:\n            raise err\n        \n    def delete_embeddings_from_vector_db(self, ids: List[str]) -> None:\n        try:\n            for id in ids:\n                self.client.data_object.delete(\n                    uuid = id,\n                    class_name = self.class_name\n                )\n        except Exception as err:\n            raise err\n    \n    def _build_documents(self, results_data, metadata_fields) -> List[Document]:\n        documents = []\n        for result in results_data:\n            text_content = result[self.text_field]\n            metadata = {}\n            for field in metadata_fields:\n                metadata[field] = result[field]\n            document = Document(text_content=text_content, metadata=metadata)\n            documents.append(document)\n        \n        return documents\n    \n    def _get_search_res(self, results, query):\n        text = [item['text'] for item in results]\n        search_res = f\"Query: {query}\\n\"\n        i = 0\n        for context in text:\n            search_res += f\"Chunk{i}: \\n{context}\\n\"\n            i += 1\n        return search_res"
  },
  {
    "path": "superagi/worker.py",
    "content": "from __future__ import absolute_import\nimport sys\n\nfrom sqlalchemy.orm import sessionmaker\n\nfrom superagi.helper.tool_helper import handle_tools_import\nfrom superagi.lib.logger import logger\n\nfrom datetime import timedelta\nfrom celery import Celery\n\nfrom superagi.config.config import get_config\nfrom superagi.helper.agent_schedule_helper import AgentScheduleHelper\nfrom superagi.models.configuration import Configuration\nfrom superagi.models.agent import Agent\nfrom superagi.models.db import connect_db\nfrom superagi.types.model_source_types import ModelSourceType\n\nfrom sqlalchemy import event\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.helper.webhook_manager import WebHookManager\n\nredis_url = get_config('REDIS_URL', 'super__redis:6379')\n\napp = Celery(\"superagi\", include=[\"superagi.worker\"], imports=[\"superagi.worker\"])\napp.conf.broker_url = \"redis://\" + redis_url + \"/0\"\napp.conf.result_backend = \"redis://\" + redis_url + \"/0\"\napp.conf.worker_concurrency = 10\napp.conf.accept_content = ['application/x-python-serialize', 'application/json']\n\n\nbeat_schedule = {\n    'initialize-schedule-agent': {\n        'task': 'initialize-schedule-agent',\n        'schedule': timedelta(minutes=5),\n    },\n    'execute_waiting_workflows': {\n        'task': 'execute_waiting_workflows',\n        'schedule': timedelta(minutes=2),\n    },\n}\napp.conf.beat_schedule = beat_schedule\n\n@event.listens_for(AgentExecution.status, \"set\")\ndef agent_status_change(target, val,old_val,initiator):\n    if not hasattr(sys, '_called_from_test'):\n        webhook_callback.delay(target.id,val,old_val)\n\n@app.task(name=\"execute_waiting_workflows\", autoretry_for=(Exception,), retry_backoff=2, max_retries=5)\ndef execute_waiting_workflows():\n    \"\"\"Check if wait time of wait workflow step is over and can be resumed.\"\"\"\n\n    from superagi.jobs.agent_executor import AgentExecutor\n    logger.info(\"Executing waiting workflows job\")\n    AgentExecutor().execute_waiting_workflows()\n\n@app.task(name=\"initialize-schedule-agent\", autoretry_for=(Exception,), retry_backoff=2, max_retries=5)\ndef initialize_schedule_agent_task():\n    \"\"\"Executing agent scheduling in the background.\"\"\"\n\n    schedule_helper = AgentScheduleHelper()\n    schedule_helper.update_next_scheduled_time()\n    schedule_helper.run_scheduled_agents()\n\n\n@app.task(name=\"execute_agent\", autoretry_for=(Exception,), retry_backoff=2, max_retries=5)\ndef execute_agent(agent_execution_id: int, time):\n    \"\"\"Execute an agent step in background.\"\"\"\n    from superagi.jobs.agent_executor import AgentExecutor\n    handle_tools_import()\n    logger.info(\"Execute agent:\" + str(time) + \",\" + str(agent_execution_id))\n    AgentExecutor().execute_next_step(agent_execution_id=agent_execution_id)\n\n\n@app.task(name=\"summarize_resource\", autoretry_for=(Exception,), retry_backoff=2, max_retries=5,serializer='pickle')\ndef summarize_resource(agent_id: int, resource_id: int):\n    \"\"\"Summarize a resource in background.\"\"\"\n    from superagi.resource_manager.resource_summary import ResourceSummarizer\n    from superagi.types.storage_types import StorageType\n    from superagi.models.resource import Resource\n    from superagi.resource_manager.resource_manager import ResourceManager\n\n    engine = connect_db()\n    Session = sessionmaker(bind=engine)\n    session = Session()\n    agent_config = Agent.fetch_configuration(session, agent_id)\n    organisation = Agent.find_org_by_agent_id(session, agent_id)\n    model_source = Configuration.fetch_configurations(session, organisation.id, \"model_source\", agent_config[\"model\"]) or \"OpenAi\"\n    if ModelSourceType.GooglePalm.value in model_source or ModelSourceType.Replicate.value in model_source:\n        return\n\n    resource = session.query(Resource).filter(Resource.id == resource_id).first()\n    file_path = resource.path\n\n    if resource.storage_type == StorageType.S3.value:\n        documents = ResourceManager(str(agent_id)).create_llama_document_s3(file_path)\n    else:\n        documents = ResourceManager(str(agent_id)).create_llama_document(file_path)\n\n    logger.info(\"Summarize resource:\" + str(agent_id) + \",\" + str(resource_id))\n    resource_summarizer = ResourceSummarizer(session=session, agent_id=agent_id, model=agent_config[\"model\"])\n    resource_summarizer.add_to_vector_store_and_create_summary(resource_id=resource_id,\n                                                               documents=documents)\n    session.close()\n\n@app.task(name=\"webhook_callback\", autoretry_for=(Exception,), retry_backoff=2, max_retries=5,serializer='pickle')\ndef webhook_callback(agent_execution_id,val,old_val):\n    engine = connect_db()\n    Session = sessionmaker(bind=engine)\n    with Session() as session:\n        WebHookManager(session).agent_status_change_callback(agent_execution_id, val, old_val)\n    \n"
  },
  {
    "path": "test.py",
    "content": "import argparse\nfrom datetime import datetime\nfrom time import time\nfrom superagi.lib.logger import logger\n\nfrom sqlalchemy.orm import sessionmaker\n\nfrom superagi.worker import execute_agent\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.db import connect_db\nfrom superagi.models.organisation import Organisation\nfrom superagi.models.project import Project\n\nparser = argparse.ArgumentParser(description='Create a new agent.')\nparser.add_argument('--name', type=str, help='Agent name for the script.')\nparser.add_argument('--description', type=str, help='Agent description for the script.')\nparser.add_argument('--goals', type=str, nargs='+', help='Agent goals for the script.')\nargs = parser.parse_args()\n\nagent_name = args.name\nagent_description = args.description\nagent_goals = args.goals\n\nengine = connect_db()\nSession = sessionmaker(bind=engine)\nsession = Session()\n\n\ndef ask_user_for_goals():\n    goals = []\n    while True:\n        goal = input(\"Enter a goal (or 'q' to quit): \")\n        if goal == 'q':\n            break\n        goals.append(goal)\n    return goals\n\n\ndef run_superagi_cli(agent_name=None, agent_description=None, agent_goals=None):\n    # Create default organization\n    organization = Organisation(name='Default Organization', description='Default organization description')\n    session.add(organization)\n    session.flush()  # Flush pending changes to generate the agent's ID\n    session.commit()\n    logger.info(organization)\n\n    # Create default project associated with the organization\n    project = Project(name='Default Project', description='Default project description',\n                      organisation_id=organization.id)\n    session.add(project)\n    session.flush()  # Flush pending changes to generate the agent's ID\n    session.commit()\n    logger.info(project)\n\n    # Agent\n    if agent_name is None:\n        agent_name = input(\"Enter agent name: \")\n    if agent_description is None:\n        agent_description = input(\"Enter agent description: \")\n    agent = Agent(name=agent_name, description=agent_description, project_id=project.id)\n    session.add(agent)\n    session.flush()\n    session.commit()\n    logger.info(agent)\n\n    # Agent Config\n    # Create Agent Configuration\n    agent_config_values = {\n        \"goal\": ask_user_for_goals() if agent_goals is None else agent_goals,\n        \"agent_type\": \"Type Non-Queue\",\n        \"constraints\": [\"~4000 word limit for short term memory. \",\n                        \"Your short term memory is short, so immediately save important information to files.\",\n                        \"If you are unsure how you previously did something or want to recall past events, thinking about similar events will help you remember.\",\n                        \"No user assistance\",\n                        \"Exclusively use the commands listed in double quotes e.g. \\\"command name\\\"\"\n                        ],\n        \"tools\": [],\n        \"exit\": \"Default\",\n        \"iteration_interval\": 0,\n        \"model\": \"gpt-4\",\n        \"permission_type\": \"Default\",\n        \"LTM_DB\": \"Pinecone\",\n        \"memory_window\": 10\n    }\n\n    agent_configurations = [\n        AgentConfiguration(agent_id=agent.id, key=key, value=str(value))\n        for key, value in agent_config_values.items()\n    ]\n\n    session.add_all(agent_configurations)\n    session.commit()\n    logger.info(\"Agent Config : \")\n    logger.info(agent_configurations)\n\n    # Create agent execution in RUNNING state associated with the agent\n    execution = AgentExecution(status='RUNNING', agent_id=agent.id, last_execution_time=datetime.utcnow())\n    session.add(execution)\n    session.commit()\n\n    logger.info(\"Final Execution\")\n    logger.info(execution)\n\n    execute_agent.delay(execution.id, datetime.now())\n\n\nrun_superagi_cli(agent_name=agent_name, agent_description=agent_description, agent_goals=agent_goals)\n"
  },
  {
    "path": "test_main.http",
    "content": "# Test your FastAPI endpoints\n\nGET http://127.0.0.1:8000/\nAccept: application/json\n\n###\n\nGET http://127.0.0.1:8000/hello/User\nAccept: application/json\n\n###\n"
  },
  {
    "path": "tests/__init__.py",
    "content": ""
  },
  {
    "path": "tests/integration_tests/__init__.py",
    "content": ""
  },
  {
    "path": "tests/integration_tests/vector_embeddings/__init__.py",
    "content": ""
  },
  {
    "path": "tests/integration_tests/vector_embeddings/test_pinecone.py",
    "content": "import unittest\nfrom superagi.vector_embeddings.pinecone import Pinecone  \n\n\nclass TestPinecone(unittest.TestCase):\n\n    def setUp(self):\n        self.uuid = [\"id1\", \"id2\"]\n        self.embeds = [\"embed1\", \"embed2\"]\n        self.metadata = [\"metadata1\", \"metadata2\"]\n        self.pinecone_instance = Pinecone(self.uuid, self.embeds, self.metadata)\n\n    def test_init(self):\n        self.assertEqual(self.pinecone_instance.uuid, self.uuid)\n        self.assertEqual(self.pinecone_instance.embeds, self.embeds)\n        self.assertEqual(self.pinecone_instance.metadata, self.metadata)\n    \n    def test_get_vector_embeddings_from_chunks(self):\n        expected = {\n            'vectors': list(zip(self.uuid, self.embeds, self.metadata))\n        }\n        result = self.pinecone_instance.get_vector_embeddings_from_chunks()\n        self.assertEqual(result, expected)\n\n\nif __name__ == \"__main__\":\n    unittest.main()"
  },
  {
    "path": "tests/integration_tests/vector_embeddings/test_qdrant.py",
    "content": "import unittest\n\nfrom superagi.vector_embeddings.qdrant import Qdrant\n\nclass TestQdrant(unittest.TestCase):\n\n    def setUp(self):\n        self.uuid = ['1234', '5678']\n        self.embeds = [[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]]\n        self.metadata = [{'key1': 'value1'}, {'key2': 'value2'}]\n\n        self.qdrant_obj = Qdrant(self.uuid, self.embeds, self.metadata)\n\n    def test_init(self):\n        self.assertEqual(self.qdrant_obj.uuid, self.uuid)\n        self.assertEqual(self.qdrant_obj.embeds, self.embeds)\n        self.assertEqual(self.qdrant_obj.metadata, self.metadata)\n\n    def test_get_vector_embeddings_from_chunks(self):\n        expected = {\n            'ids': self.uuid,\n            'payload': self.metadata,\n            'vectors': self.embeds,\n        }\n        result = self.qdrant_obj.get_vector_embeddings_from_chunks()\n        \n        self.assertEqual(result, expected)\n\nif __name__ == '__main__':\n    unittest.main()"
  },
  {
    "path": "tests/integration_tests/vector_embeddings/test_weaviate.py",
    "content": "import unittest\nfrom superagi.vector_embeddings.base import VectorEmbeddings\nfrom superagi.vector_embeddings.weaviate import Weaviate\n\nclass TestWeaviate(unittest.TestCase):\n\n    def setUp(self):\n        self.weaviate = Weaviate(uuid=\"1234\", embeds=[0.1, 0.2, 0.3, 0.4], metadata={\"info\": \"sample data\"})\n\n    def test_init(self):\n        self.assertEqual(self.weaviate.uuid, \"1234\")\n        self.assertEqual(self.weaviate.embeds, [0.1, 0.2, 0.3, 0.4])\n        self.assertEqual(self.weaviate.metadata, {\"info\": \"sample data\"})\n\n    def test_get_vector_embeddings_from_chunks(self):\n        expected_result = {\n            \"ids\": \"1234\",\n            \"data_object\": {\"info\": \"sample data\"},\n            \"vectors\": [0.1, 0.2, 0.3, 0.4]\n        }\n        self.assertEqual(self.weaviate.get_vector_embeddings_from_chunks(), expected_result)\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "tests/integration_tests/vector_store/__init__.py",
    "content": ""
  },
  {
    "path": "tests/integration_tests/vector_store/test_qdrant.py",
    "content": "import pytest\nimport numpy as np\n\nfrom superagi.vector_store import qdrant\nfrom superagi.vector_store.embedding.openai import OpenAiEmbedding\nfrom qdrant_client.models import Distance, VectorParams\nfrom qdrant_client import QdrantClient\n\n\n@pytest.fixture\ndef client():\n    client = QdrantClient(\":memory:\")\n    yield client\n\n\n@pytest.fixture\ndef mock_openai_embedding(monkeypatch):\n    monkeypatch.setattr(\n        OpenAiEmbedding,\n        \"get_embedding\",\n        lambda self, text: np.random.random(3).tolist(),\n    )\n\n\n@pytest.fixture\ndef store(client, mock_openai_embedding):\n    client.create_collection(\n        collection_name=\"Test_collection\",\n        vectors_config=VectorParams(size=3, distance=Distance.COSINE),\n    )\n    yield qdrant.Qdrant(client, OpenAiEmbedding(api_key=\"test_api_key\"), \"Test_collection\")\n    client.delete_collection(\"Test_collection\")\n\n\ndef test_add_texts(store):\n    car_companies = [\n        \"Rolls-Royce\",\n        \"Bentley\",\n        \"Ferrari\",\n        \"Lamborghini\",\n        \"Aston Martin\",\n        \"Porsche\",\n        \"Bugatti\",\n        \"Maserati\",\n        \"McLaren\",\n        \"Mercedes-Benz\"\n    ]\n    assert len(store.add_texts(car_companies)) == len(car_companies)\n\n\ndef test_get_matching_text(store):\n    car_companies = [\n        \"Rolls-Royce\",\n        \"Bentley\",\n        \"Ferrari\",\n        \"Lamborghini\",\n        \"Aston Martin\",\n        \"Porsche\",\n        \"Bugatti\",\n        \"Maserati\",\n        \"McLaren\",\n        \"Mercedes-Benz\"\n    ]\n    store.add_texts(car_companies)\n    assert len(store.get_matching_text(k=2, text=\"McLaren\")) == 2\n"
  },
  {
    "path": "tests/integration_tests/vector_store/test_weaviate.py",
    "content": "import unittest\nfrom unittest.mock import Mock, patch, call, MagicMock\nfrom superagi.vector_store.weaviate import create_weaviate_client, Weaviate, Document\n\nclass TestWeaviateClient(unittest.TestCase):\n    @patch('weaviate.Client')\n    @patch('weaviate.AuthApiKey')\n    def test_create_weaviate_client(self, MockAuth, MockClient):\n        # Test when url and api_key are provided\n        auth_instance = MockAuth.return_value\n        MockClient.return_value = 'client'\n        self.assertEqual(create_weaviate_client('url', 'api_key'), 'client')\n        MockAuth.assert_called_once_with(api_key='api_key')\n        MockClient.assert_called_once_with(url='url', auth_client_secret=auth_instance)\n\n        with self.assertRaises(ValueError):\n            create_weaviate_client()  # Raises an error if no url is provided\n\nclass TestWeaviate(unittest.TestCase):\n\n    def setUp(self):\n        # create a new mock object for the client.batch attribute with the required methods for a context manager.\n        mock_batch = MagicMock()\n        mock_batch.__enter__.return_value = mock_batch\n        mock_batch.__exit__.return_value = None\n\n        self.client = Mock()\n        self.client.batch = mock_batch\n\n        self.embedding_model = Mock()\n        self.weaviateVectorStore = Weaviate(self.client, self.embedding_model, 'class_name', 'text_field')\n\n    def test_get_matching_text(self):\n        self.client.query.get.return_value.with_near_vector.return_value.with_where.return_value.with_limit.return_value.do.return_value = {'data': {'Get': {'class_name': []}}}\n        self.embedding_model.get_embedding.return_value = 'vector'\n        self.weaviateVectorStore._get_metadata_fields = Mock(return_value=['field1', 'field2'])\n        self.weaviateVectorStore._get_search_res = Mock(return_value='search_res')\n        self.weaviateVectorStore._build_documents = Mock(return_value=['document1', 'document2'])\n        self.assertEqual(self.weaviateVectorStore.get_matching_text('query', metadata={'field1': 'value'})\n                         , {'search_res': 'search_res', 'documents': ['document1', 'document2']})\n        self.embedding_model.get_embedding.assert_called_once_with('query')\n\n    def test_add_texts(self):\n        self.embedding_model.get_embedding.return_value = 'vector'\n        self.weaviateVectorStore.add_embeddings_to_vector_db = Mock()\n        texts = ['text1', 'text2']\n        result = self.weaviateVectorStore.add_texts(texts)\n        self.assertEqual(len(result), 2)    # We expect to get 2 IDs.\n        self.assertTrue(isinstance(result[0], str))    # The IDs should be strings.\n        self.embedding_model.get_embedding.assert_has_calls([call(texts[0]), call(texts[1])])\n        self.assertEqual(self.weaviateVectorStore.add_embeddings_to_vector_db.call_count, 2)\n\n    def test_add_embeddings_to_vector_db(self):\n        embeddings = {'ids': ['id1', 'id2'], 'data_object': [{'field': 'value1'}, {'field': 'value2'}], 'vectors': ['v1', 'v2']}\n        self.weaviateVectorStore.add_embeddings_to_vector_db(embeddings)\n        calls = [call.add_data_object({'field': 'value1'}, class_name='class_name', uuid='id1', vector='v1'),\n                call.add_data_object({'field': 'value2'}, class_name='class_name', uuid='id2', vector='v2')]\n\n        self.client.batch.assert_has_calls(calls)\n\n    def test_delete_embeddings_from_vector_db(self):\n        # You need to setup appropriate return values from the Weaviate client\n        self.weaviateVectorStore.delete_embeddings_from_vector_db(['id1', 'id2'])\n        self.client.data_object.delete.assert_called()\n\nif __name__ == '__main__':\n    unittest.main()"
  },
  {
    "path": "tests/tools/google_calendar/create_event_test.py",
    "content": "import unittest\nfrom unittest.mock import MagicMock, patch\nfrom pydantic import ValidationError\nfrom datetime import datetime, timedelta\nfrom superagi.tools.google_calendar.create_calendar_event import CreateEventCalendarInput, CreateEventCalendarTool\nfrom superagi.helper.google_calendar_creds import GoogleCalendarCreds\nfrom superagi.helper.calendar_date import CalendarDate\n\nclass TestCreateEventCalendarInput(unittest.TestCase):\n    def test_create_event_calendar_input_valid(self):\n        input_data = {\n            \"event_name\": \"Test Event\",\n            \"description\": \"A test event.\",\n            \"start_date\": \"2022-01-01\",\n            \"start_time\": \"12:00:00\",\n            \"end_date\": \"2022-01-01\",\n            \"end_time\": \"13:00:00\",\n            \"attendees\": [\"test@example.com\"],\n            \"location\": \"London\"\n        }\n        try:\n            CreateEventCalendarInput(**input_data)\n        except ValidationError:\n            self.fail(\"ValidationError raised with valid input_data\")\n\n    def test_create_event_calendar_input_invalid(self):\n        input_data = {\n            \"event_name\": \"Test Event\",\n            \"description\": \"A test event.\",\n            \"start_date\": \"2022-99-99\",\n            \"start_time\": \"12:60:60\",\n            \"end_date\": \"2022-99-99\",\n            \"end_time\": \"13:60:60\",\n            \"attendees\": [\"test@example.com\"],\n            \"location\": \"London\"\n        }\n        with self.assertRaises(ValidationError):\n            CreateEventCalendarInput(**input_data)\n\nclass TestCreateEventCalendarTool(unittest.TestCase):\n    def setUp(self):\n        self.create_event_tool = CreateEventCalendarTool()\n    @patch.object(GoogleCalendarCreds, \"get_credentials\")\n    @patch.object(CalendarDate, \"create_event_dates\")\n\n    def test_execute(self, mock_create_event_dates, mock_get_credentials):\n        mock_get_credentials.return_value = {\n            \"success\": True,\n            \"service\": MagicMock()\n        }\n        mock_date_utc = {\n            \"start_datetime_utc\": (datetime.utcnow() + timedelta(hours=1)).isoformat(),\n            \"end_datetime_utc\": (datetime.utcnow() + timedelta(hours=2)).isoformat(),\n            \"timeZone\": \"UTC\"\n        }\n        mock_create_event_dates.return_value = mock_date_utc\n        mock_service = MagicMock()\n        mock_service.events.return_value = MagicMock()\n        output_str_expected = f\"Event Test Event at {mock_date_utc['start_datetime_utc']} created successfully, link for the event {'https://somerandomlink'}\"\n        output_str = self.create_event_tool._execute(\"Test Event\", \"A test event\", [\"test@example.com\"], start_date=\"2022-01-01\", start_time=\"12:00:00\", end_date=\"2022-01-01\", end_time=\"13:00:00\", location=\"London\")\n        self.assertEqual(output_str, output_str_expected)\n        event = {\n            \"summary\": \"Test Event\",\n            \"description\": \"A test event\",\n            \"start\": {\n                \"dateTime\": mock_date_utc[\"start_datetime_utc\"],\n                \"timeZone\": mock_date_utc[\"timeZone\"]\n            },\n            \"end\": {\n                \"dateTime\": mock_date_utc[\"end_datetime_utc\"],\n                \"timeZone\": mock_date_utc[\"timeZone\"]\n            },\n            \"attendees\": [{\"email\": \"test@example.com\"}],\n            \"location\": \"London\"\n        }\n        mock_get_credentials.assert_called_once()\n        mock_create_event_dates.assert_called_once_with(mock_service, \"2022-01-01\", \"12:00:00\", \"2022-01-01\", \"13:00:00\")\n        mock_service.events().insert.assert_called_once_with(calendarId=\"primary\", body=event, conferenceDataVersion=1)\n\nif __name__ == \"__main__\":\n    unittest.main()"
  },
  {
    "path": "tests/tools/google_calendar/delete_event_test.py",
    "content": "import unittest\nfrom unittest.mock import Mock, patch\nfrom pydantic import ValidationError\nfrom superagi.tools.google_calendar.delete_calendar_event import DeleteCalendarEventInput, DeleteCalendarEventTool\n\nclass TestDeleteCalendarEventInput(unittest.TestCase):\n    def test_valid_input(self):\n        input_data = {\"event_id\": \"123456\"}\n        input_obj = DeleteCalendarEventInput(**input_data)\n        self.assertEqual(input_obj.event_id, \"123456\")\n\n    def test_invalid_input(self):\n        input_data = {\"event_id\": \"\"}\n        with self.assertRaises(ValidationError):\n            DeleteCalendarEventInput(**input_data)\n\nclass TestDeleteCalendarEventTools(unittest.TestCase):\n    def setUp(self):\n        self.delete_tool = DeleteCalendarEventTool()\n    @patch(\"your_module.GoogleCalendarCreds\")\n\n    def test_execute_delete_event_with_valid_id(self, mock_google_calendar_creds):\n        credentials_obj = Mock()\n        credentials_obj.get_credentials.return_value = {\"success\": True, \"service\": Mock()}\n        mock_google_calendar_creds.return_value = credentials_obj\n        self.assertEqual(self.delete_tool._execute(\"123456\"), \"Event Successfully deleted from your Google Calendar\")\n    @patch(\"your_module.GoogleCalendarCreds\")\n\n    def test_execute_delete_event_with_no_id(self, mock_google_calendar_creds):\n        self.assertEqual(self.delete_tool._execute(\"None\"), \"Add Event ID to delete an event from Google Calendar\")\n    @patch(\"your_module.GoogleCalendarCreds\")\n\n    def test_execute_delete_event_with_no_credentials(self, mock_google_calendar_creds):\n        credentials_obj = Mock()\n        credentials_obj.get_credentials.return_value = {\"success\": False}\n        mock_google_calendar_creds.return_value = credentials_obj\n        self.assertEqual(self.delete_tool._execute(\"123456\"), \"Kindly connect to Google Calendar\")\n\nif __name__ == \"__main__\":\n    unittest.main()"
  },
  {
    "path": "tests/tools/google_calendar/event_details_test.py",
    "content": "import unittest\nfrom unittest.mock import MagicMock, patch\nfrom pydantic import ValidationError\nfrom superagi.tools.google_calendar.event_details_calendar import EventDetailsCalendarInput, EventDetailsCalendarTool\nfrom superagi.helper.google_calendar_creds import GoogleCalendarCreds\n\nclass TestEventDetailsCalendarInput(unittest.TestCase):\n    def test_invalid_input(self):\n        with self.assertRaises(ValidationError):\n            EventDetailsCalendarInput(event_id=None)\n    \n    def test_valid_input(self):\n        input_data = EventDetailsCalendarInput(event_id=\"test_event_id\")\n        self.assertEqual(input_data.event_id, \"test_event_id\")\n\nclass TestEventDetailsCalendarTool(unittest.TestCase):\n    def setUp(self):\n        self.tool = EventDetailsCalendarTool()\n\n    def test_no_credentials(self):\n        with patch.object(GoogleCalendarCreds, 'get_credentials') as mock_get_credentials:\n            mock_get_credentials.return_value = {\"success\": False}\n            result = self.tool._execute(event_id=\"test_event_id\")\n            self.assertEqual(result, \"Kindly connect to Google Calendar\")\n\n    def test_no_event_id(self):\n        with patch.object(GoogleCalendarCreds, 'get_credentials') as mock_get_credentials:\n            mock_get_credentials.return_value = {\"success\": True}\n            result = self.tool._execute(event_id=\"None\")\n            self.assertEqual(result, \"Add Event ID to fetch details of an event from Google Calendar\")\n\n    def test_valid_event(self):\n        event_data = {\n            'summary': 'Test Meeting',\n            'start': {'dateTime': '2022-01-01T09:00:00'},\n            'end': {'dateTime': '2022-01-01T10:00:00'},\n            'attendees': [{'email': 'attendee1@example.com'},\n                          {'email': 'attendee2@example.com'}]\n        }\n        with patch.object(GoogleCalendarCreds, 'get_credentials') as mock_get_credentials:\n            with patch('your_module.base64.b64decode') as mock_b64decode:\n                mock_get_credentials.return_value = {\"success\": True, \"service\": MagicMock()}\n                service = mock_get_credentials.return_value[\"service\"]\n                service.events().get.return_value.execute.return_value = event_data\n                mock_b64decode.return_value.decode.return_value = \"decoded_event_id\"\n                result = self.tool._execute(event_id=\"test_event_id\")\n                mock_b64decode.assert_called_once_with(\"test_event_id\")\n                service.events().get.assert_called_once_with(calendarId=\"primary\", eventId=\"decoded_event_id\")\n                expected_output = (\"Event details for the event id 'test_event_id' is - \\n\"\n                                   \"Summary : Test Meeting\\n\"\n                                   \"Start Date and Time : 2022-01-01T09:00:00\\n\"\n                                   \"End Date and Time : 2022-01-01T10:00:00\\n\"\n                                   \"Attendees : attendee1@example.com,attendee2@example.com\")\n                self.assertEqual(result, expected_output)\n\nif __name__ == '__main__':\n    unittest.main()"
  },
  {
    "path": "tests/tools/google_calendar/list_events_test.py",
    "content": "import unittest\nfrom datetime import datetime\nfrom unittest.mock import MagicMock, patch\nfrom pydantic import ValidationError\nfrom superagi.tools.google_calendar.list_calendar_events import ListCalendarEventsInput, ListCalendarEventsTool\nfrom superagi.helper.google_calendar_creds import GoogleCalendarCreds\nfrom superagi.helper.calendar_date import CalendarDate\n\nclass TestListCalendarEventsInput(unittest.TestCase):\n    \n    def test_valid_input(self):\n        input_data = {\n            \"start_time\": \"20:00:00\",\n            \"start_date\": \"2022-11-10\",\n            \"end_date\": \"2022-11-11\",\n            \"end_time\": \"22:00:00\",\n        }\n        try:\n            ListCalendarEventsInput(**input_data)\n            validation_passed = True\n        except ValidationError:\n            validation_passed = False\n        self.assertEqual(validation_passed, True)\n    \n    def test_invalid_input(self):\n        input_data = {\n            \"start_time\": \"invalid time\",\n            \"start_date\": \"invalid date\",\n            \"end_date\": \"another invalid date\",\n            \"end_time\": \"another invalid time\",\n        }\n        with self.assertRaises(ValidationError):\n            ListCalendarEventsInput(**input_data)\n\nclass TestListCalendarEventsTool(unittest.TestCase):\n    @patch.object(GoogleCalendarCreds, 'get_credentials')\n    @patch.object(CalendarDate, 'get_date_utc')\n    \n    def test_without_events(self, mock_get_date_utc, mock_get_credentials):\n        tool = ListCalendarEventsTool()\n        mock_get_credentials.return_value = {\n            \"success\": True,\n            \"service\": MagicMock()\n        }\n        mock_service = mock_get_credentials()[\"service\"]\n        mock_service.events().list().execute.return_value = {}\n        mock_get_date_utc.return_value = {\n            'start_datetime_utc': datetime.now().isoformat(),\n            'end_datetime_utc': datetime.now().isoformat()\n        }\n        result = tool._execute('20:00:00', '2022-11-10', '2022-11-11', '22:00:00')\n        self.assertEqual(result, \"No events found for the given date and time range.\")\n\nif __name__ == \"__main__\":\n    unittest.main()\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "tests/unit_tests/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/agent/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/agent/test_agent_iteration_step_handler.py",
    "content": "from unittest.mock import Mock, patch, MagicMock\n\nimport pytest\n\nfrom superagi.agent.agent_iteration_step_handler import AgentIterationStepHandler\nfrom superagi.agent.agent_message_builder import AgentLlmMessageBuilder\nfrom superagi.agent.agent_prompt_builder import AgentPromptBuilder\nfrom superagi.agent.output_handler import ToolOutputHandler\nfrom superagi.agent.task_queue import TaskQueue\nfrom superagi.agent.tool_builder import ToolBuilder\nfrom superagi.config.config import get_config\nfrom superagi.helper.token_counter import TokenCounter\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_config import AgentExecutionConfiguration\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nfrom superagi.models.agent_execution_permission import AgentExecutionPermission\nfrom superagi.models.organisation import Organisation\nfrom superagi.models.tool import Tool\nfrom superagi.models.workflows.agent_workflow_step import AgentWorkflowStep\nfrom superagi.models.workflows.iteration_workflow import IterationWorkflow\nfrom superagi.models.workflows.iteration_workflow_step import IterationWorkflowStep\nfrom superagi.resource_manager.resource_summary import ResourceSummarizer\nfrom superagi.tools.code.write_code import CodingTool\nfrom superagi.tools.resource.query_resource import QueryResourceTool\nfrom superagi.tools.thinking.tools import ThinkingTool\n\n\n# Given\n@pytest.fixture\ndef test_handler():\n    mock_session = Mock()\n    llm = Mock()\n    agent_id = 1\n    agent_execution_id = 1\n\n    # Creating an instance of the class to test\n    handler = AgentIterationStepHandler(mock_session, llm, agent_id, agent_execution_id)\n    return handler\n\ndef test_build_agent_prompt(test_handler, mocker):\n    # Arrange\n    iteration_workflow = IterationWorkflow(has_task_queue=True)\n    agent_config = {'constraints': 'Test constraint'}\n    agent_execution_config = {'goal': 'Test goal', 'instruction': 'Test instruction'}\n    prompt = 'Test prompt'\n    task_queue = TaskQueue(queue_name='Test queue')\n    agent_tools = []\n\n    mocker.patch.object(AgentPromptBuilder, 'replace_main_variables', return_value='Test prompt')\n    mocker.patch.object(AgentPromptBuilder, 'replace_task_based_variables', return_value='Test prompt')\n    mocker.patch.object(task_queue, 'get_last_task_details', return_value={\"task\": \"last task\", \"response\": \"last response\"})\n    mocker.patch.object(task_queue, 'get_first_task', return_value='Test task')\n    mocker.patch.object(task_queue, 'get_tasks', return_value=[])\n    mocker.patch.object(task_queue, 'get_completed_tasks', return_value=[])\n    mocker.patch.object(TokenCounter, 'token_limit', return_value=1000)\n    mocker.patch('superagi.agent.agent_iteration_step_handler.get_config', return_value=600)\n\n    # Act\n    test_handler.task_queue = task_queue\n    result_prompt = test_handler._build_agent_prompt(iteration_workflow, agent_config, agent_execution_config,\n                                                     prompt, agent_tools)\n\n    # Assert\n    assert result_prompt == 'Test prompt'\n    AgentPromptBuilder.replace_main_variables.assert_called_once_with(prompt, agent_execution_config[\"goal\"],\n                                                                      agent_execution_config[\"instruction\"],\n                                                                      agent_config[\"constraints\"], agent_tools, False)\n    AgentPromptBuilder.replace_task_based_variables.assert_called_once()\n    task_queue.get_last_task_details.assert_called_once()\n    task_queue.get_first_task.assert_called_once()\n    task_queue.get_tasks.assert_called_once()\n    task_queue.get_completed_tasks.assert_called_once()\n    TokenCounter.token_limit.assert_called_once()\n\ndef test_build_tools(test_handler, mocker):\n    # Arrange\n    agent_config = {'model': 'gpt-3', 'tools': [1, 2, 3], 'resource_summary': True}\n    agent_execution_config = {'goal': 'Test goal', 'instruction': 'Test instruction', 'tools':[1]}\n\n    mocker.patch.object(AgentConfiguration, 'get_model_api_key', return_value={'api_key':'test_api_key','provider':'test_provider'})\n    mocker.patch.object(ToolBuilder, 'build_tool')\n    mocker.patch.object(ToolBuilder, 'set_default_params_tool', return_value=ThinkingTool())\n    mocker.patch.object(ResourceSummarizer, 'fetch_or_create_agent_resource_summary', return_value=True)\n    mocker.patch('superagi.models.tool.Tool')\n    test_handler.session.query.return_value.filter.return_value.all.return_value = [ThinkingTool()]\n\n    # Act\n    agent_tools = test_handler._build_tools(agent_config, agent_execution_config)\n\n    # Assert\n    assert isinstance(agent_tools[0], ThinkingTool)\n    assert ToolBuilder.build_tool.call_count == 1\n    assert ToolBuilder.set_default_params_tool.call_count == 3\n    assert AgentConfiguration.get_model_api_key.call_count == 1\n    assert ResourceSummarizer.fetch_or_create_agent_resource_summary.call_count == 1\n\n\ndef test_handle_wait_for_permission(test_handler, mocker):\n    # Arrange\n    mock_agent_execution = mocker.Mock(spec=AgentExecution)\n    mock_agent_execution.status = \"WAITING_FOR_PERMISSION\"\n    mock_iteration_workflow_step = mocker.Mock(spec=IterationWorkflowStep)\n    mock_iteration_workflow_step.next_step_id = 123\n    agent_config = {'model': 'gpt-3', 'tools': [1, 2, 3]}\n    agent_execution_config = {'goal': 'Test goal', 'instruction': 'Test instruction'}\n\n    mock_permission = mocker.Mock(spec=AgentExecutionPermission)\n    mock_permission.status = \"APPROVED\"\n    mock_permission.user_feedback = \"Test feedback\"\n    mock_permission.tool_name = \"Test tool\"\n    test_handler._build_tools = Mock(return_value=[ThinkingTool()])\n    test_handler.session.query.return_value.filter.return_value.first.return_value = mock_permission\n    # AgentExecutionPermission.filter.return_value.first.return_value = mock_permission\n\n    mock_tool_output = mocker.MagicMock()\n    mock_tool_output.result = \"Test result\"\n    ToolOutputHandler.handle_tool_response = Mock(return_value=mock_tool_output)\n\n    # Act\n    result = test_handler._handle_wait_for_permission(\n        mock_agent_execution, agent_config, agent_execution_config, mock_iteration_workflow_step)\n\n    # Assert\n    test_handler._build_tools.assert_called_once_with(agent_config, agent_execution_config)\n    ToolOutputHandler.handle_tool_response.assert_called_once()\n    assert mock_agent_execution.status == \"RUNNING\"\n    assert result\n\n"
  },
  {
    "path": "tests/unit_tests/agent/test_agent_message_builder.py",
    "content": "import pytest\nfrom unittest.mock import patch, Mock\n\nfrom superagi.agent.agent_message_builder import AgentLlmMessageBuilder\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\n\n\n@patch('superagi.helper.token_counter.TokenCounter.token_limit')\n@patch('superagi.config.config.get_config')\ndef test_build_agent_messages(mock_get_config, mock_token_limit):\n    mock_session = Mock()\n    llm = Mock()\n    llm_model = Mock()\n    agent_id = 1\n    agent_execution_id = 1\n    prompt = \"start\"\n    agent_feeds = []\n    completion_prompt = \"end\"\n\n    # Mocking\n    mock_token_limit.return_value = 1000\n    mock_get_config.return_value = 600\n\n    builder = AgentLlmMessageBuilder(mock_session, llm, llm_model, agent_id, agent_execution_id)\n    messages = builder.build_agent_messages(prompt, agent_feeds, history_enabled=True, completion_prompt=completion_prompt)\n\n    # Test prompt message\n    assert messages[0] == {\"role\": \"system\", \"content\": prompt}\n\n    # Test initial feeds\n    assert mock_session.add.call_count == len(messages)\n    assert mock_session.commit.call_count == len(messages)\n\n    # Check if AgentExecutionFeed object is created and added to session\n    for i in range(len(messages)):\n        args, _ = mock_session.add.call_args_list[i]\n        feed_obj = args[0]\n        assert isinstance(feed_obj, AgentExecutionFeed)\n        assert feed_obj.agent_execution_id == agent_execution_id\n        assert feed_obj.agent_id == agent_id\n        assert feed_obj.feed == messages[i][\"content\"]\n        assert feed_obj.role == messages[i][\"role\"]\n\n@patch('superagi.models.agent_execution_config.AgentExecutionConfiguration.fetch_value')\n@patch('superagi.models.agent_execution_config.AgentExecutionConfiguration.add_or_update_agent_execution_config')\n@patch('superagi.agent.agent_message_builder.AgentLlmMessageBuilder._build_prompt_for_recursive_ltm_summary_using_previous_ltm_summary')\n@patch('superagi.agent.agent_message_builder.AgentLlmMessageBuilder._build_prompt_for_ltm_summary')\n@patch('superagi.helper.token_counter.TokenCounter.count_text_tokens')\n@patch('superagi.helper.token_counter.TokenCounter.token_limit')\ndef test_build_ltm_summary(mock_token_limit, mock_count_text_tokens, mock_build_prompt_for_ltm_summary,\n                           mock_build_prompt_for_recursive_ltm_summary, mock_add_or_update_agent_execution_config,\n                           mock_fetch_value):\n    mock_session = Mock()\n    llm = Mock()\n    llm_model = Mock()\n    agent_id = 1\n    agent_execution_id = 1\n\n    builder = AgentLlmMessageBuilder(mock_session, llm, llm_model, agent_id, agent_execution_id)\n\n    past_messages = [{\"role\": \"user\", \"content\": \"Hello\"}, {\"role\": \"assistant\", \"content\": \"Hi\"}]\n    output_token_limit = 100\n\n    mock_token_limit.return_value = 1000\n    mock_count_text_tokens.return_value = 200\n    mock_build_prompt_for_ltm_summary.return_value = \"ltm_summary_prompt\"\n    mock_build_prompt_for_recursive_ltm_summary.return_value = \"recursive_ltm_summary_prompt\"\n    mock_fetch_value.return_value = Mock(value=\"ltm_summary\")\n    llm.chat_completion.return_value = {\"content\": \"ltm_summary\"}\n\n    ltm_summary = builder._build_ltm_summary(past_messages, output_token_limit)\n\n    assert ltm_summary == \"ltm_summary\"\n\n    mock_add_or_update_agent_execution_config.assert_called_once()\n\n    llm.chat_completion.assert_called_once_with([{\"role\": \"system\", \"content\": \"You are GPT Prompt writer\"},\n                                                 {\"role\": \"assistant\", \"content\": \"ltm_summary_prompt\"}])\n\n@patch('superagi.helper.prompt_reader.PromptReader.read_agent_prompt')\ndef test_build_prompt_for_ltm_summary(mock_read_agent_prompt):\n    mock_session = Mock()\n    llm = Mock()\n    llm_model = Mock()\n    agent_id = 1\n    agent_execution_id = 1\n\n    builder = AgentLlmMessageBuilder(mock_session, llm, llm_model, agent_id, agent_execution_id)\n\n    past_messages = [{\"role\": \"user\", \"content\": \"Hello\"}, {\"role\": \"assistant\", \"content\": \"Hi\"}]\n    token_limit = 100\n\n    mock_read_agent_prompt.return_value = \"{past_messages}\\n{char_limit}\"\n\n    prompt = builder._build_prompt_for_ltm_summary(past_messages, token_limit)\n\n    assert \"user: Hello\\nassistant: Hi\\n\" in prompt\n    assert \"400\" in prompt\n\n\n@patch('superagi.helper.prompt_reader.PromptReader.read_agent_prompt')\ndef test_build_prompt_for_recursive_ltm_summary_using_previous_ltm_summary(mock_read_agent_prompt):\n    mock_session = Mock()\n    llm = Mock()\n    llm_model = Mock()\n    agent_id = 1\n    agent_execution_id = 1\n\n    builder = AgentLlmMessageBuilder(mock_session, llm, llm_model, agent_id, agent_execution_id)\n\n    previous_ltm_summary = \"Summary\"\n    past_messages = [{\"role\": \"user\", \"content\": \"Hello\"}, {\"role\": \"assistant\", \"content\": \"Hi\"}]\n    token_limit = 100\n\n    mock_read_agent_prompt.return_value = \"{previous_ltm_summary}\\n{past_messages}\\n{char_limit}\"\n\n    prompt = builder._build_prompt_for_recursive_ltm_summary_using_previous_ltm_summary(previous_ltm_summary, past_messages, token_limit)\n\n    assert \"Summary\" in prompt\n    assert \"user: Hello\\nassistant: Hi\\n\" in prompt\n    assert \"400\" in prompt\n"
  },
  {
    "path": "tests/unit_tests/agent/test_agent_prompt_builder.py",
    "content": "from unittest.mock import Mock\nfrom unittest.mock import patch\n\nfrom superagi.agent.agent_prompt_builder import AgentPromptBuilder\nfrom superagi.tools.base_tool import BaseTool\n\n\ndef test_add_list_items_to_string():\n    items = ['item1', 'item2', 'item3']\n    result = AgentPromptBuilder.add_list_items_to_string(items)\n    assert result == '1. item1\\n2. item2\\n3. item3\\n'\n\n\ndef test_clean_prompt():\n    prompt = '   some   text  with    extra spaces     '\n    result = AgentPromptBuilder.clean_prompt(prompt)\n    assert result == 'some text with extra spaces'\n\n\n@patch('superagi.agent.agent_prompt_builder.AgentPromptBuilder.add_list_items_to_string')\n@patch('superagi.agent.agent_prompt_builder.AgentPromptBuilder.add_tools_to_prompt')\ndef test_replace_main_variables(mock_add_tools_to_prompt, mock_add_list_items_to_string):\n    super_agi_prompt = \"{goals} {instructions} {task_instructions} {constraints} {tools}\"\n    goals = ['goal1', 'goal2']\n    instructions = ['instruction1']\n    constraints = ['constraint1']\n    tools = [Mock(spec=BaseTool)]\n\n    # Mocking\n    mock_add_list_items_to_string.side_effect = lambda x: ', '.join(x)\n    mock_add_tools_to_prompt.return_value = 'tools_str'\n\n    result = AgentPromptBuilder.replace_main_variables(super_agi_prompt, goals, instructions, constraints, tools)\n\n    assert 'goal1, goal2 INSTRUCTION' in result\n    assert 'instruction1' in result\n    assert 'constraint1' in result\n\n\n@patch('superagi.agent.agent_prompt_builder.TokenCounter.count_message_tokens')\ndef test_replace_task_based_variables(mock_count_message_tokens):\n    super_agi_prompt = \"{current_task} {last_task} {last_task_result} {pending_tasks} {completed_tasks} {task_history}\"\n    current_task = \"task1\"\n    last_task = \"task2\"\n    last_task_result = \"result1\"\n    pending_tasks = [\"task3\", \"task4\"]\n    completed_tasks = [{'task': 'task1', 'response': 'response1'}, {'task': 'task2', 'response': 'response2'}]\n    token_limit = 2000\n\n    # Mocking\n    mock_count_message_tokens.return_value = 50\n\n    result = AgentPromptBuilder.replace_task_based_variables(super_agi_prompt, current_task, last_task, last_task_result,\n                                                             pending_tasks, completed_tasks, token_limit)\n\n    expected_result = f\"{current_task} {last_task} {last_task_result} {str(pending_tasks)} {str([x['task'] for x in completed_tasks])} \\nTask: {completed_tasks[-1]['task']}\\nResult: {completed_tasks[-1]['response']}\\nTask: {completed_tasks[-2]['task']}\\nResult: {completed_tasks[-2]['response']}\\n\"\n\n    assert result == expected_result\n\n\n@patch('superagi.agent.agent_prompt_builder.TokenCounter.count_message_tokens')\ndef test_replace_task_based_variables(mock_count_message_tokens):\n    super_agi_prompt = \"{current_task} {last_task} {last_task_result} {pending_tasks} {completed_tasks} {task_history}\"\n    current_task = \"task1\"\n    last_task = \"task2\"\n    last_task_result = \"result1\"\n    pending_tasks = [\"task3\", \"task4\"]\n    completed_tasks = [{'task': 'task1', 'response': 'response1'}, {'task': 'task2', 'response': 'response2'}]\n    token_limit = 2000\n\n    # Mocking\n    mock_count_message_tokens.return_value = 50\n\n    result = AgentPromptBuilder.replace_task_based_variables(super_agi_prompt, current_task, last_task, last_task_result,\n                                                             pending_tasks, completed_tasks, token_limit)\n\n    # expected_result = f\"{current_task} {last_task} {last_task_result} {str(pending_tasks)} {str([x['task'] for x in reversed(completed_tasks)])} \\nTask: {completed_tasks[-1]['task']}\\nResult: {completed_tasks[-1]['response']}\\nTask: {completed_tasks[-2]['task']}\\nResult: {completed_tasks[-2]['response']}\\n\"\n\n    assert \"task1\" in result\n    assert \"task2\" in result\n    assert \"result1\" in result\n    assert \"task3\" in result\n    assert \"task3\" in result\n    assert \"response1\" in result\n    assert \"response2\" in result"
  },
  {
    "path": "tests/unit_tests/agent/test_agent_prompt_template.py",
    "content": "import pytest\nfrom unittest.mock import patch, mock_open\n\nfrom superagi.agent.agent_prompt_template import AgentPromptTemplate\nfrom superagi.helper.prompt_reader import PromptReader\n\n\n@patch(\"builtins.open\", new_callable=mock_open, read_data=\"test_prompt\")\ndef test_get_super_agi_single_prompt(mock_file):\n    expected_result = {\"prompt\": \"test_prompt\", \"variables\": [\"goals\", \"instructions\", \"constraints\", \"tools\"]}\n    result = AgentPromptTemplate.get_super_agi_single_prompt()\n    assert result == expected_result\n\n@patch(\"builtins.open\", new_callable=mock_open, read_data=\"test_prompt\")\ndef test_start_task_based(mock_file):\n    expected_result = {\"prompt\": \"test_prompt\", \"variables\": [\"goals\", \"instructions\"]}\n    result = AgentPromptTemplate.start_task_based()\n    assert result == expected_result\n\n@patch(\"builtins.open\", new_callable=mock_open, read_data=\"test_prompt\")\ndef test_analyse_task(mock_file):\n    expected_result = {\"prompt\": \"test_prompt\",\n                       \"variables\": [\"goals\", \"instructions\", \"tools\", \"current_task\"]}\n    result = AgentPromptTemplate.analyse_task()\n    assert result == expected_result\n\n@patch(\"builtins.open\", new_callable=mock_open, read_data=\"test_prompt\")\ndef test_create_tasks(mock_file):\n    expected_result = {\"prompt\": \"test_prompt\", \"variables\": [\"goals\", \"instructions\", \"last_task\", \"last_task_result\", \"pending_tasks\"]}\n    result = AgentPromptTemplate.create_tasks()\n    assert result == expected_result\n\n@patch(\"builtins.open\", new_callable=mock_open, read_data=\"test_prompt\")\ndef test_prioritize_tasks(mock_file):\n    expected_result = {\"prompt\": \"test_prompt\", \"variables\": [\"goals\", \"instructions\", \"last_task\", \"last_task_result\", \"pending_tasks\"]}\n    result = AgentPromptTemplate.prioritize_tasks()\n    assert result == expected_result\n"
  },
  {
    "path": "tests/unit_tests/agent/test_agent_tool_step_handler.py",
    "content": "import json\nfrom unittest.mock import Mock, create_autospec, patch\n\nimport pytest\n\nfrom superagi.agent.agent_tool_step_handler import AgentToolStepHandler\nfrom superagi.agent.common_types import ToolExecutorResponse\nfrom superagi.agent.output_handler import ToolOutputHandler\nfrom superagi.agent.tool_builder import ToolBuilder\nfrom superagi.helper.token_counter import TokenCounter\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_config import AgentExecutionConfiguration\nfrom superagi.models.agent_execution_permission import AgentExecutionPermission\nfrom superagi.models.tool import Tool\nfrom superagi.models.workflows.agent_workflow_step import AgentWorkflowStep\nfrom superagi.models.workflows.agent_workflow_step_tool import AgentWorkflowStepTool\nfrom superagi.resource_manager.resource_summary import ResourceSummarizer\nfrom superagi.tools.code.write_code import CodingTool\n\n\n# Given\n@pytest.fixture\ndef handler():\n    mock_session = Mock()\n    llm = Mock()\n    agent_id = 1\n    agent_execution_id = 1\n\n    # Creating an instance of the class to test\n    handler = AgentToolStepHandler(mock_session, llm, agent_id, agent_execution_id, None)\n    return handler\n\n\ndef test_create_permission_request(handler):\n    # Arrange\n    execution = Mock()\n    step_tool = Mock()\n    step_tool.input_instruction = \"input_instruction\"\n    handler.session.commit = Mock()\n    handler.session.flush = Mock()\n\n    mock_permission = create_autospec(AgentExecutionPermission)\n    with patch('superagi.agent.agent_tool_step_handler.AgentExecutionPermission', return_value=mock_permission) as mock_cls:\n        # Act\n        handler._create_permission_request(execution, step_tool)\n\n        # Assert\n        mock_cls.assert_called_once_with(\n            agent_execution_id=handler.agent_execution_id,\n            status=\"PENDING\",\n            agent_id=handler.agent_id,\n            tool_name=\"WAIT_FOR_PERMISSION\",\n            question=step_tool.input_instruction,\n            assistant_reply=\"\"\n        )\n        handler.session.add.assert_called_once_with(mock_permission)\n        execution.permission_id = mock_permission.id\n        execution.status = \"WAITING_FOR_PERMISSION\"\n        assert handler.session.commit.call_count == 2\n        assert handler.session.flush.call_count == 1\n\n\n\ndef test_execute_step(handler):\n    # Arrange\n    execution = create_autospec(AgentExecution)\n    workflow_step = create_autospec(AgentWorkflowStep)\n    step_tool = create_autospec(AgentWorkflowStepTool)\n    agent_config = {}\n    agent_execution_config = {}\n\n    with patch.object(AgentExecution, 'get_agent_execution_from_id', return_value=execution), \\\n        patch.object(AgentWorkflowStep, 'find_by_id', return_value=workflow_step), \\\n        patch.object(AgentWorkflowStepTool, 'find_by_id', return_value=step_tool), \\\n        patch.object(Agent, 'fetch_configuration', return_value=agent_config), \\\n        patch.object(AgentExecutionConfiguration, 'fetch_configuration', return_value=agent_execution_config):\n\n        handler._handle_wait_for_permission = Mock(return_value=True)\n        handler._create_permission_request = Mock()\n        handler._process_input_instruction = Mock(return_value=\"{\\\"}\")\n        handler._build_tool_obj = Mock()\n        handler._process_output_instruction = Mock(return_value=\"step_response\")\n        handler._handle_next_step = Mock()\n\n        # Act\n        tool_output_handler = Mock(spec=ToolOutputHandler)\n        tool_output_handler.handle.return_value = ToolExecutorResponse(status=\"SUCCESS\", output=\"final_response\")\n\n        with patch('superagi.agent.agent_tool_step_handler.ToolOutputHandler', return_value=tool_output_handler):\n            # Act\n            handler.execute_step()\n\n            # Assert\n            handler._handle_wait_for_permission.assert_called_once()\n            handler._process_input_instruction.assert_called_once_with(agent_config, agent_execution_config, step_tool,\n                                                                       workflow_step)\n            handler._process_output_instruction.assert_called_once()\n\n\ndef test_handle_next_step_with_complete(handler):\n    # Arrange\n    next_step = \"COMPLETE\"\n    execution = create_autospec(AgentExecution)\n\n    with patch.object(AgentExecution, 'get_agent_execution_from_id', return_value=execution):\n        # Act\n        handler._handle_next_step(next_step)\n\n        # Assert\n        assert execution.current_agent_step_id == -1\n        assert execution.status == \"COMPLETED\"\n        handler.session.commit.assert_called_once()\n\n\ndef test_handle_next_step_with_next_step(handler):\n    # Arrange\n    next_step = create_autospec(AgentExecution)  # Mocking the next_step object\n    execution = create_autospec(AgentExecution)\n\n    with patch.object(AgentExecution, 'get_agent_execution_from_id', return_value=execution), \\\n        patch.object(AgentExecution, 'assign_next_step_id') as mock_assign_next_step_id:\n\n        # Act\n        handler._handle_next_step(next_step)\n\n        # Assert\n        mock_assign_next_step_id.assert_called_once_with(handler.session, handler.agent_execution_id, next_step.id)\n        handler.session.commit.assert_called_once()\n\n\ndef test_build_tool_obj(handler):\n    # Arrange\n    agent_config = {\"model\": \"model1\", \"resource_summary\": \"summary\"}\n    agent_execution_config = {}\n    tool_name = \"QueryResourceTool\"\n    model_api_key = {\"provider\":\"provider\",\"api_key\":\"apikey\"}\n    resource_summary = \"summary\"\n    tool = Tool()\n\n    with patch.object(AgentConfiguration, 'get_model_api_key', return_value=model_api_key), \\\n         patch.object(ToolBuilder, 'build_tool', return_value=tool), \\\n         patch.object(ToolBuilder, 'set_default_params_tool', return_value=tool), \\\n         patch.object(ResourceSummarizer, 'fetch_or_create_agent_resource_summary', return_value=resource_summary), \\\n         patch.object(handler.session, 'query', return_value=Mock(first=Mock(return_value=tool))):\n\n        # Act\n        result = handler._build_tool_obj(agent_config, agent_execution_config, tool_name)\n\n        # Assert\n        assert result == tool\n\n\ndef test_process_output_instruction(handler):\n    # Arrange\n    final_response = \"final_response\"\n    step_tool = AgentWorkflowStepTool()\n    workflow_step = AgentWorkflowStep()\n    mock_response = {\"content\": \"response_content\"}\n    mock_model = Mock()\n    current_tokens = 10\n    token_limit = 100\n\n    with patch.object(handler, '_build_tool_output_prompt', return_value=\"prompt\"), \\\n         patch.object(TokenCounter, 'count_message_tokens', return_value=current_tokens), \\\n         patch.object(TokenCounter, 'token_limit', return_value=token_limit), \\\n         patch.object(handler.llm, 'chat_completion', return_value=mock_response), \\\n         patch.object(AgentExecution, 'update_tokens'):\n\n        # Act\n        result = handler._process_output_instruction(final_response, step_tool, workflow_step)\n\n        # Assert\n        assert result == mock_response['content']\n\n\ndef test_build_tool_input_prompt(handler):\n    # Arrange\n    step_tool = AgentWorkflowStepTool()\n    step_tool.tool_name = \"CodingTool\"\n    step_tool.input_instruction = \"TestInstruction\"\n    tool = CodingTool()\n    # tool.name = \"TestTool\"\n    # tool.description = \"TestDescription\"\n    # tool.args = {\"arg1\": \"val1\"}\n    agent_execution_config = {\"goal\": [\"Goal1\", \"Goal2\"]}\n    mock_prompt = \"{goals}{tool_name}{instruction}{tool_schema}\"\n\n    with patch('superagi.agent.agent_tool_step_handler.PromptReader.read_agent_prompt', return_value=mock_prompt), \\\n            patch('superagi.agent.agent_tool_step_handler.AgentPromptBuilder.add_list_items_to_string', return_value=\"Goal1, Goal2\"):\n        # Act\n        result = handler._build_tool_input_prompt(step_tool, tool, agent_execution_config)\n\n        # Assert\n        result = result.replace(\"{goals}\", \"Goal1, Goal2\")\n        result = result.replace(\"{tool_name}\", step_tool.tool_name)\n        result = result.replace(\"{instruction}\", step_tool.input_instruction)\n        tool_schema = f\"\\\"{tool.name}\\\": {tool.description}, args json schema: {json.dumps(tool.args)}\"\n        result = result.replace(\"{tool_schema}\", tool_schema)\n\n        assert \"\"\"Goal1, Goal2CodingToolTestInstruction\"\"\" in result\n\n\ndef test_build_tool_output_prompt(handler):\n    # Arrange\n    step_tool = AgentWorkflowStepTool()\n    step_tool.tool_name = \"TestTool\"\n    step_tool.output_instruction = \"TestInstruction\"\n    tool_output = \"TestOutput\"\n    workflow_step = AgentWorkflowStep()\n    expected_prompt = \"TestOutputTestToolTestInstruction['option1', 'option2']\"\n    mock_prompt = \"{tool_output}{tool_name}{instruction}{output_options}\"\n    step_responses = [\"option1\", \"option2\", \"default\"]\n\n    with patch('superagi.agent.agent_tool_step_handler.PromptReader.read_agent_prompt', return_value=mock_prompt), \\\n            patch.object(handler, '_get_step_responses', return_value=step_responses):\n        # Act\n        result = handler._build_tool_output_prompt(step_tool, tool_output, workflow_step)\n\n        # Assert\n        expected_prompt = expected_prompt.replace(\"{tool_output}\", tool_output)\n        expected_prompt = expected_prompt.replace(\"{tool_name}\", step_tool.tool_name)\n        expected_prompt = expected_prompt.replace(\"{instruction}\", step_tool.output_instruction)\n        expected_prompt = expected_prompt.replace(\"{output_options}\", str(step_responses))\n\n        assert result == expected_prompt\n\n\ndef test_handle_wait_for_permission_approved(handler):\n    # Arrange\n    agent_execution = AgentExecution()\n    agent_execution.status = \"WAITING_FOR_PERMISSION\"\n    agent_execution.permission_id = 123\n    workflow_step = AgentWorkflowStep()\n    agent_execution_permission = AgentExecutionPermission()\n    agent_execution_permission.status = \"APPROVED\"\n    next_step = AgentWorkflowStep()\n\n    handler.session.query.return_value.filter.return_value.first.return_value = agent_execution_permission\n    handler._handle_next_step = Mock()\n    AgentWorkflowStep.fetch_next_step = Mock(return_value=next_step)\n\n    # Act\n    result = handler._handle_wait_for_permission(agent_execution, workflow_step)\n\n    # Assert\n    assert result == False\n    handler._handle_next_step.assert_called_once_with(next_step)\n    assert agent_execution.status == \"RUNNING\"\n    assert agent_execution.permission_id == -1\n\n\ndef test_handle_wait_for_permission_denied(handler):\n    # Arrange\n    agent_execution = AgentExecution()\n    agent_execution.status = \"WAITING_FOR_PERMISSION\"\n    agent_execution.permission_id = 123\n    workflow_step = AgentWorkflowStep()\n    agent_execution_permission = AgentExecutionPermission()\n    agent_execution_permission.status = \"DENIED\"\n    agent_execution_permission.user_feedback = \"User feedback\"\n    next_step = AgentWorkflowStep()\n\n    handler.session.query.return_value.filter.return_value.first.return_value = agent_execution_permission\n    handler._handle_next_step = Mock()\n    AgentWorkflowStep.fetch_next_step = Mock(return_value=next_step)\n\n    # Act\n    result = handler._handle_wait_for_permission(agent_execution, workflow_step)\n\n    # Assert\n    assert result == False\n    handler._handle_next_step.assert_called_once_with(next_step)\n    assert agent_execution.status == \"RUNNING\"\n    assert agent_execution.permission_id == -1\n"
  },
  {
    "path": "tests/unit_tests/agent/test_agent_workflow_step_wait_handler.py",
    "content": "from datetime import datetime\nfrom unittest.mock import MagicMock, patch\n\nimport pytest\n\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.workflows.agent_workflow_step import AgentWorkflowStep\nfrom superagi.agent.agent_workflow_step_wait_handler import AgentWaitStepHandler\n\n\n# Mock datetime.now() for testing\n@pytest.fixture\ndef mock_datetime_now():\n    return datetime(2023, 9, 6, 12, 0, 0)\n\n\n@pytest.fixture(autouse=True)\ndef mock_datetime_now_fixture(monkeypatch, mock_datetime_now):\n    monkeypatch.setattr(\"superagi.agent.agent_workflow_step_wait_handler.datetime\",\n                        MagicMock(now=MagicMock(return_value=mock_datetime_now)))\n\n# Test cases\n@patch.object(AgentExecution, 'get_agent_execution_from_id')\n@patch.object(AgentWorkflowStep, 'find_by_id')\n@patch.object(AgentWorkflowStep, 'fetch_next_step')\ndef test_handle_next_step_complete(mock_fetch_next_step, mock_find_by_id, mock_get_agent_execution_from_id, mock_datetime_now_fixture):\n    mock_session = MagicMock()\n    mock_agent_execution = MagicMock(current_agent_step_id=1, status=\"WAIT_STEP\")\n\n    mock_get_agent_execution_from_id.return_value = mock_agent_execution\n    mock_find_by_id.return_value = MagicMock()\n\n    mock_next_step = MagicMock(id=2)\n    mock_next_step.__str__.return_value = \"COMPLETE\"\n    mock_fetch_next_step.return_value = mock_next_step\n\n    handler = AgentWaitStepHandler(mock_session, 1, 2)\n\n    handler.handle_next_step()\n\n    # Assertions\n    assert mock_agent_execution.current_agent_step_id == -1\n    assert mock_agent_execution.status == \"COMPLETED\"\n    mock_session.commit.assert_called_once()\n\n\n# Test cases\n@patch.object(AgentExecution, 'get_agent_execution_from_id')\n@patch.object(AgentWorkflowStep, 'find_by_id')\n@patch.object(AgentWorkflowStep, 'fetch_next_step')\ndef test_execute_step(mock_fetch_next_step, mock_find_by_id, mock_get_agent_execution_from_id):\n    mock_session = MagicMock()\n    mock_agent_execution = MagicMock(current_agent_step_id=1, status=\"WAIT_STEP\")\n    mock_step_wait = MagicMock(status=\"WAITING\")\n\n    mock_get_agent_execution_from_id.return_value = mock_agent_execution\n    mock_find_by_id.return_value = mock_step_wait\n    mock_fetch_next_step.return_value = MagicMock()\n\n    handler = AgentWaitStepHandler(mock_session, 1, 2)\n\n    handler.execute_step()\n\n    # Assertions\n    assert mock_step_wait.status == \"WAITING\"\n    assert mock_agent_execution.status == \"WAIT_STEP\"\n    mock_session.commit.assert_called_once()"
  },
  {
    "path": "tests/unit_tests/agent/test_output_handler.py",
    "content": "import pytest\nfrom unittest.mock import Mock, patch, MagicMock\n\nfrom superagi.agent.common_types import ToolExecutorResponse\nfrom superagi.agent.output_handler import ToolOutputHandler, TaskOutputHandler, ReplaceTaskOutputHandler\nfrom superagi.agent.output_parser import AgentSchemaOutputParser, AgentGPTAction\nfrom superagi.agent.task_queue import TaskQueue\nfrom superagi.agent.tool_executor import ToolExecutor\nfrom superagi.helper.json_cleaner import JsonCleaner\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_execution_permission import AgentExecutionPermission\nimport numpy as np\nfrom superagi.agent.output_handler import ToolOutputHandler\n\n\n# Test for ToolOutputHandler\n@patch.object(TaskQueue, 'complete_task')\n@patch.object(TaskQueue, 'get_tasks')\n@patch.object(TaskQueue, 'get_completed_tasks')\n@patch.object(AgentSchemaOutputParser, 'parse')\ndef test_tool_output_handle(parse_mock, execute_mock, get_completed_tasks_mock, complete_task_mock):\n    # Arrange\n    agent_execution_id = 11\n    agent_config = {\"agent_id\": 22, \"permission_type\": \"unrestricted\"}\n    assistant_reply = '{\"tool\": {\"name\": \"someAction\", \"args\": [\"arg1\", \"arg2\"]}}'\n    parse_mock.return_value = AgentGPTAction(name=\"someAction\", args=[\"arg1\", \"arg2\"])\n\n    # Define what the mock response status should be\n    execute_mock.return_value = Mock(status='PENDING', is_permission_required=False)\n\n    handler = ToolOutputHandler(agent_execution_id, agent_config, [],None)\n\n    # Mock session\n    session_mock = MagicMock()\n    session_mock.query.return_value.filter.return_value.first.return_value = Mock()\n    handler._check_for_completion = Mock(return_value=Mock(status='PENDING', is_permission_required=False))\n    handler.handle_tool_response = Mock(return_value=Mock(status='PENDING', is_permission_required=False))\n    # Act\n    response = handler.handle(session_mock, assistant_reply)\n\n    # Assert\n    assert response.status == \"PENDING\"\n    parse_mock.assert_called_with(assistant_reply)\n    assert session_mock.add.call_count == 2\n\n\n\n@patch('superagi.agent.output_handler.TokenTextSplitter')\ndef test_add_text_to_memory(TokenTextSplitter_mock):\n    # Arrange\n    agent_execution_id = 1\n    agent_config = {\"agent_id\": 2}\n    tool_output_handler = ToolOutputHandler(agent_execution_id, agent_config,[], None)\n\n    assistant_reply = '{\"thoughts\": {\"text\": \"This is a task.\"}}'\n    tool_response_result = '[\"Task completed.\"]'\n\n    text_splitter_mock = MagicMock()\n    TokenTextSplitter_mock.return_value = text_splitter_mock\n    text_splitter_mock.split_text.return_value = [\"This is a task.\", \"Task completed.\"]\n\n    # Mock the VectorStore memory\n    memory_mock = MagicMock()\n    tool_output_handler.memory = memory_mock\n\n    # Act\n    tool_output_handler.add_text_to_memory(assistant_reply, tool_response_result)\n\n    # Assert\n    TokenTextSplitter_mock.assert_called_once_with(chunk_size=1024, chunk_overlap=10)\n    text_splitter_mock.split_text.assert_called_once_with('This is a task.[\"Task completed.\"]')\n    memory_mock.add_texts.assert_called_once_with([\"This is a task.\", \"Task completed.\"], [{\"agent_execution_id\": agent_execution_id}, {\"agent_execution_id\": agent_execution_id}])  \n\n\n@patch('superagi.models.agent_execution_permission.AgentExecutionPermission')\ndef test_tool_handler_check_permission_in_restricted_mode(op_mock):\n    # Mock the session\n    session_mock = MagicMock()\n\n    # Arrange\n    agent_execution_id = 1\n    agent_config = {\"agent_id\": 2, \"permission_type\": \"RESTRICTED\"}\n    assistant_reply = '{\"tool\": {\"name\": \"someAction\", \"args\": [\"arg1\", \"arg2\"]}}'\n    op_mock.parse.return_value = AgentGPTAction(name=\"someAction\", args=[\"arg1\", \"arg2\"])\n    tool = MagicMock()\n    tool.name = \"someAction\"\n    tool.permission_required = True\n    handler = ToolOutputHandler(agent_execution_id, agent_config, [tool],None)\n\n    # Act\n    response = handler._check_permission_in_restricted_mode(session_mock, assistant_reply)\n\n    # Assert\n    assert response.is_permission_required\n    assert response.status == \"WAITING_FOR_PERMISSION\"\n    session_mock.add.assert_called_once()\n    session_mock.commit.assert_called_once()\n\n\n# Test for TaskOutputHandler\n@patch.object(TaskQueue, 'add_task')\n@patch.object(TaskQueue, 'get_tasks')\n@patch.object(JsonCleaner, 'extract_json_array_section')\ndef test_task_output_handle_method(extract_json_array_section_mock, get_tasks_mock, add_task_mock):\n    # Arrange\n    agent_execution_id = 1\n    agent_config = {\"agent_id\": 2}\n    assistant_reply = '[\"task1\", \"task2\", \"task3\"]'\n    tasks = [\"task1\", \"task2\", \"task3\"]\n    extract_json_array_section_mock.return_value = str(tasks)\n    get_tasks_mock.return_value = tasks\n    handler = TaskOutputHandler(agent_execution_id, agent_config)\n\n    # Mock session\n    session_mock = MagicMock()\n\n    # Act\n    response = handler.handle(session_mock, assistant_reply)\n\n    # Assert\n    extract_json_array_section_mock.assert_called_once_with(assistant_reply)\n    assert add_task_mock.call_count == len(tasks)\n    assert session_mock.add.call_count == len(tasks)\n    get_tasks_mock.assert_called_once()\n    assert response.status == \"PENDING\"\n\n\n# Test for ReplaceTaskOutputHandler\n@patch.object(TaskQueue, 'clear_tasks')\n@patch.object(TaskQueue, 'add_task')\n@patch.object(TaskQueue, 'get_tasks')\n@patch.object(JsonCleaner, 'extract_json_array_section')\ndef test_handle_method(extract_json_array_section_mock, get_tasks_mock, add_task_mock, clear_tasks_mock):\n    # Arrange\n    agent_execution_id = 1\n    agent_config = {}\n    assistant_reply = '[\"task1\", \"task2\", \"task3\"]'\n    tasks = [\"task1\", \"task2\", \"task3\"]\n    extract_json_array_section_mock.return_value = str(tasks)\n    get_tasks_mock.return_value = tasks\n    handler = ReplaceTaskOutputHandler(agent_execution_id, agent_config)\n\n    # Mock session\n    session_mock = MagicMock()\n\n    # Act\n    response = handler.handle(session_mock, assistant_reply)\n\n    # Assert\n    extract_json_array_section_mock.assert_called_once_with(assistant_reply)\n    clear_tasks_mock.assert_called_once()\n    assert add_task_mock.call_count == len(tasks)\n    get_tasks_mock.assert_called_once()\n    assert response.status == \"PENDING\"\n"
  },
  {
    "path": "tests/unit_tests/agent/test_output_parser.py",
    "content": "import pytest\n\nfrom superagi.agent.output_parser import AgentGPTAction, AgentSchemaOutputParser\n\nimport pytest\n\ndef test_agent_schema_output_parser():\n    parser = AgentSchemaOutputParser()\n\n    # Test with valid json response\n    response = '```{\"tool\": {\"name\": \"Tool1\", \"args\": {}}}```'\n    parsed = parser.parse(response)\n    assert isinstance(parsed, AgentGPTAction)\n    assert parsed.name == 'Tool1'\n    assert parsed.args == {}\n\n    # Test with valid json but with boolean values\n    response = \"```{'tool': {'name': 'Tool1', 'args': 'arg1'}, 'status': True}```\"\n    parsed = parser.parse(response)\n    assert isinstance(parsed, AgentGPTAction)\n    assert parsed.name == 'Tool1'\n    assert parsed.args == 'arg1'\n\n    # Test with invalid json response\n    response = \"invalid response\"\n    with pytest.raises(Exception):\n        parsed = parser.parse(response)\n\n    # Test with empty json response\n    response = \"\"\n    with pytest.raises(Exception):\n        parsed = parser.parse(response)\n\n\n\n"
  },
  {
    "path": "tests/unit_tests/agent/test_queue_step_handler.py",
    "content": "import pytest\nfrom unittest.mock import Mock, patch\nfrom superagi.agent.queue_step_handler import QueueStepHandler\n\n\n# To prevent having to patch each time, setup a pytest fixture\n@pytest.fixture\ndef queue_step_handler():\n    # Mock dependencies\n    session = Mock()\n    llm = Mock()\n    agent_id = 1\n    agent_execution_id = 1\n\n    # Instantiate your class with the mocked dependencies\n    return QueueStepHandler(session, llm, agent_id, agent_execution_id)\n\n\n@pytest.fixture\ndef step_tool():\n    step_tool = Mock()\n    step_tool.unique_id = \"unique_id\"\n    step_tool.input_instruction = \"input_instruction\"\n    return step_tool\n\n\ndef test_queue_identifier(queue_step_handler):\n    step_tool = Mock()\n    step_tool.unique_id = \"step_id\"\n    assert queue_step_handler._queue_identifier(step_tool) == \"step_id_1\"\n\n\n@patch(\"superagi.agent.queue_step_handler.AgentExecution\")  # Replace with your actual module path\n@patch(\"superagi.agent.queue_step_handler.AgentWorkflowStep\")\n@patch(\"superagi.agent.queue_step_handler.AgentWorkflowStepTool\")\n@patch(\"superagi.agent.queue_step_handler.TaskQueue\")\ndef test_execute_step(task_queue_mock, agent_execution_mock, workflow_step_mock, step_tool_mock, queue_step_handler):\n    agent_execution_mock.get_agent_execution_from_id.return_value = Mock(current_agent_step_id=\"step_id\")\n    workflow_step_mock.find_by_id.return_value = Mock(action_reference_id=\"action_id\")\n    step_tool_mock.find_by_id.return_value = Mock()\n    task_queue_mock.return_value.get_status.return_value = None  # Mock the get_status method on TaskQueue\n\n    # Here you can add assertions depending on what you expect\n    # For example if you expect the return value to be \"default\", you could do\n    assert queue_step_handler.execute_step() == \"default\"\n\n\n@patch(\"superagi.agent.queue_step_handler.TaskQueue\")\n@patch(\"superagi.agent.queue_step_handler.AgentExecutionFeed\")\ndef test_add_to_queue(task_queue_mock, agent_execution_feed_mock, queue_step_handler, step_tool):\n    # Setup mocks\n    queue_step_handler._process_input_instruction = Mock(return_value='{\"reply\": [\"task1\", \"task2\"]}')\n    queue_step_handler._process_reply = Mock()\n\n    # Call the method\n    queue_step_handler._add_to_queue(task_queue_mock, step_tool)\n\n    # Verify the calls\n    queue_step_handler._process_input_instruction.assert_called_once_with(step_tool)\n    queue_step_handler._process_reply.assert_called_once_with(task_queue_mock, '{\"reply\": [\"task1\", \"task2\"]}')\n\n\n@patch(\"superagi.agent.queue_step_handler.TaskQueue\")\n@patch(\"superagi.agent.queue_step_handler.AgentExecutionFeed\")\ndef test_consume_from_queue(task_queue_mock, agent_execution_feed_mock, queue_step_handler, step_tool):\n    # Setup mocks\n    task_queue_mock.get_tasks.return_value = ['task1', 'task2']\n    task_queue_mock.get_first_task.return_value = 'task1'\n    agent_execution_feed_instance = agent_execution_feed_mock.return_value\n\n    # Call the method\n    queue_step_handler._consume_from_queue(task_queue_mock)\n\n    # Verify the calls\n    queue_step_handler.session.commit.assert_called()  # Ensure session commits were called\n    queue_step_handler.session.add.assert_called()\n    task_queue_mock.complete_task.assert_called_once_with(\"PROCESSED\")\n"
  },
  {
    "path": "tests/unit_tests/agent/test_task_queue.py",
    "content": "import unittest\nfrom unittest.mock import patch\n\nfrom superagi.agent.task_queue import TaskQueue\n\n\nclass TaskQueueTests(unittest.TestCase):\n    def setUp(self):\n        self.queue_name = \"test_queue\"\n        self.queue = TaskQueue(self.queue_name)\n\n    @patch.object(TaskQueue, 'add_task')\n    def test_add_task(self, mock_add_task):\n        task = \"Do something\"\n        self.queue.add_task(task)\n        mock_add_task.assert_called_with(task)\n\n    @patch.object(TaskQueue, 'complete_task')\n    def test_complete_task(self, mock_complete_task):\n        task = \"Do something\"\n        response = \"Task completed\"\n        self.queue.complete_task(response)\n        mock_complete_task.assert_called_with(response)\n\n    @patch.object(TaskQueue, 'get_first_task')\n    def test_get_first_task(self, mock_get_first_task):\n        self.queue.get_first_task()\n        mock_get_first_task.assert_called()\n\n    @patch.object(TaskQueue, 'get_tasks')\n    def test_get_tasks(self, mock_get_tasks):\n        self.queue.get_tasks()\n        mock_get_tasks.assert_called()\n\n    @patch.object(TaskQueue, 'get_completed_tasks')\n    def test_get_completed_tasks(self, mock_get_completed_tasks):\n        self.queue.get_completed_tasks()\n        mock_get_completed_tasks.assert_called()\n\n    @patch.object(TaskQueue, 'clear_tasks')\n    def test_clear_tasks(self, mock_clear_tasks):\n        self.queue.clear_tasks()\n        mock_clear_tasks.assert_called()\n\n    @patch.object(TaskQueue, 'get_last_task_details')\n    def test_get_last_task_details(self, mock_get_last_task_details):\n        self.queue.get_last_task_details()\n        mock_get_last_task_details.assert_called()\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "tests/unit_tests/agent/test_tool_builder.py",
    "content": "import pytest\nfrom unittest.mock import Mock, patch\n\nfrom superagi.agent.tool_builder import ToolBuilder\nfrom superagi.models.tool import Tool\n\n\n@pytest.fixture\ndef session():\n    return Mock()\n\n@pytest.fixture\ndef agent_id():\n    return 1\n\n@pytest.fixture\ndef tool_builder(session, agent_id):\n    return ToolBuilder(session, agent_id)\n\n@pytest.fixture\ndef tool():\n    tool = Mock(spec=Tool)\n    tool.file_name = 'test.py'\n    tool.folder_name = 'test_folder'\n    tool.class_name = 'TestClass'\n    return tool\n\n@pytest.fixture\ndef agent_config():\n    return {\"model\": \"gpt4\"}\n\n@pytest.fixture\ndef agent_execution_config():\n    return {\"goal\": \"Test Goal\", \"instruction\": \"Test Instruction\"}\n\n@patch('superagi.agent.tool_builder.importlib.import_module')\n@patch('superagi.agent.tool_builder.getattr')\ndef test_build_tool(mock_getattr, mock_import_module, tool_builder, tool):\n    mock_module = Mock()\n    mock_class = Mock()\n    mock_import_module.return_value = mock_module\n    mock_getattr.return_value = mock_class\n\n    result_tool = tool_builder.build_tool(tool)\n\n    mock_import_module.assert_called_with('.test_folder.test')\n    mock_getattr.assert_called_with(mock_module, tool.class_name)\n\n    assert result_tool.toolkit_config.session == tool_builder.session\n    assert result_tool.toolkit_config.toolkit_id == tool.toolkit_id"
  },
  {
    "path": "tests/unit_tests/agent/test_tool_executor.py",
    "content": "import pytest\nfrom unittest.mock import Mock, patch\n\nfrom pydantic import ValidationError\n\nfrom superagi.agent.common_types import ToolExecutorResponse\nfrom superagi.agent.tool_executor import ToolExecutor\n\nclass MockTool:\n    def __init__(self, name):\n        self.name = name\n\n    def execute(self, args):\n        return self.name\n\n@pytest.fixture\ndef mock_tools():\n    return [MockTool(name=f'tool{i}') for i in range(5)]\n\n@pytest.fixture\ndef executor(mock_tools):\n    return ToolExecutor(organisation_id=1, agent_id=1, tools=mock_tools, agent_execution_id=1)\n\ndef test_tool_executor_finish(executor):\n    res = executor.execute(None, 'finish', {})\n    assert res.status == 'COMPLETE'\n    assert res.result == ''\n\n@patch('superagi.agent.tool_executor.EventHandler')\ndef test_tool_executor_success(mock_event_handler, executor, mock_tools):\n    for i, tool in enumerate(mock_tools):\n        res = executor.execute(None, f'tool{i}', {'agent_execution_id': 1})\n        assert res.status == 'SUCCESS'\n        assert res.result == f'Tool {tool.name} returned: {tool.name}'\n        assert res.retry == False\n\n@patch('superagi.agent.tool_executor.EventHandler')\ndef test_tool_executor_generic_error(mock_event_handler, executor):\n    tool = MockTool('error_tool')\n    tool.execute = Mock(side_effect=Exception('generic error'))\n    executor.tools.append(tool)\n\n    res = executor.execute(None, 'error_tool', {})\n    assert res.status == 'ERROR'\n    assert 'Error1: generic error' in res.result\n    assert res.retry == True\n\ndef test_tool_executor_unknown_tool(executor):\n    res = executor.execute(None, 'unknown_tool', {})\n    assert res.status == 'ERROR'\n    assert \"Unknown tool 'unknown_tool'\" in res.result\n    assert res.retry == True\n\ndef test_clean_tool_args(executor):\n    args = {\"arg1\": {\"value\": 1}, \"arg2\": 2}\n    clean_args = executor.clean_tool_args(args)\n    assert clean_args == {\"arg1\": 1, \"arg2\": 2}"
  },
  {
    "path": "tests/unit_tests/apm/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/apm/test_analytics_helper.py",
    "content": "import pytest\nfrom superagi.models.events import Event\nfrom superagi.apm.analytics_helper import AnalyticsHelper\nfrom unittest.mock import MagicMock\n\n@pytest.fixture\ndef organisation_id():\n    return 1\n\n@pytest.fixture\ndef mock_session():\n    return MagicMock()\n\n@pytest.fixture\ndef analytics_helper(mock_session, organisation_id):\n    return AnalyticsHelper(mock_session, organisation_id)\n\ndef test_calculate_run_completed_metrics(analytics_helper, mock_session):\n    mock_session.query().all.return_value = [MagicMock()]\n    result = analytics_helper.calculate_run_completed_metrics()\n    assert isinstance(result, dict)\n\ndef test_fetch_agent_data(analytics_helper, mock_session):\n    mock_session.query().all.return_value = [MagicMock()]\n    result = analytics_helper.fetch_agent_data()\n    assert isinstance(result, dict)\n\ndef test_fetch_agent_runs(analytics_helper, mock_session):\n    mock_session.query().all.return_value = [MagicMock()]\n    result = analytics_helper.fetch_agent_runs(1)\n    assert isinstance(result, list)\n\ndef test_get_active_runs(analytics_helper, mock_session):\n    mock_session.query().all.return_value = [MagicMock()]\n    result = analytics_helper.get_active_runs()\n    assert isinstance(result, list)"
  },
  {
    "path": "tests/unit_tests/apm/test_call_log_helper.py",
    "content": "import pytest\nfrom sqlalchemy.exc import SQLAlchemyError\nfrom superagi.models.call_logs import CallLogs\nfrom superagi.models.agent import Agent\nfrom superagi.models.tool import Tool\nfrom superagi.models.toolkit import Toolkit\nfrom unittest.mock import MagicMock\n\nfrom superagi.apm.call_log_helper import CallLogHelper\n\n@pytest.fixture\ndef mock_session():\n    return MagicMock()\n\n@pytest.fixture\ndef mock_agent():\n    return MagicMock()\n\n@pytest.fixture\ndef mock_tool():\n    return MagicMock()\n\n@pytest.fixture\ndef mock_toolkit():\n    return MagicMock()\n\n@pytest.fixture\ndef call_log_helper(mock_session):\n    return CallLogHelper(mock_session, 1)\n\ndef test_create_call_log_success(call_log_helper, mock_session):\n    mock_session.add = MagicMock()\n    mock_session.commit = MagicMock()\n    call_log = call_log_helper.create_call_log('test', 1, 10, 'test_tool', 'test_model')\n\n    assert isinstance(call_log, CallLogs)\n    mock_session.add.assert_called_once()\n    mock_session.commit.assert_called_once()\n\ndef test_create_call_log_failure(call_log_helper, mock_session):\n    mock_session.commit = MagicMock(side_effect=SQLAlchemyError())\n    call_log = call_log_helper.create_call_log('test', 1, 10, 'test_tool', 'test_model')\n    assert call_log is None\n\ndef test_fetch_data_success(call_log_helper, mock_session):\n    mock_session.query = MagicMock()\n\n    # creating mock results\n    summary_result = (1, 1, 1)\n    runs = [CallLogs(\n        agent_execution_name='test',\n        agent_id=1,\n        tokens_consumed=10,\n        tool_used='test_tool',\n        model='test_model',\n        org_id=1\n    )]\n    agents = [Agent(name='test_agent')]\n    tools = [Tool(name='test_tool', toolkit_id=1)]\n    toolkits = [Toolkit(name='test_toolkit')]\n\n    # setup return values for the mock methods\n    mock_session.query().filter().first.side_effect = [summary_result, runs, agents, toolkits, tools]\n\n    result = call_log_helper.fetch_data('test_model')\n\n    assert result is not None\n    assert 'model' in result\n    assert 'total_tokens' in result\n    assert 'total_calls' in result\n    assert 'total_agents' in result\n    assert 'runs' in result\n\ndef test_fetch_data_failure(call_log_helper, mock_session):\n    mock_session.query = MagicMock(side_effect=SQLAlchemyError())\n    result = call_log_helper.fetch_data('test_model')\n\n    assert result is None"
  },
  {
    "path": "tests/unit_tests/apm/test_event_handler.py",
    "content": "import pytest\nfrom sqlalchemy.exc import SQLAlchemyError\nfrom superagi.models.events import Event\nfrom unittest.mock import MagicMock\n\nfrom superagi.apm.event_handler import EventHandler\n\n@pytest.fixture\ndef mock_session():\n    return MagicMock()\n\n@pytest.fixture\ndef event_handler(mock_session):\n    return EventHandler(mock_session)\n\ndef test_create_event_success(event_handler, mock_session):\n    mock_session.add = MagicMock()\n    mock_session.commit = MagicMock()\n    event = event_handler.create_event('test', {}, 1, 1, 100)\n\n    assert isinstance(event, Event)\n    mock_session.add.assert_called_once()\n    mock_session.commit.assert_called_once()\n\ndef test_create_event_failure(event_handler, mock_session):\n    mock_session.commit = MagicMock(side_effect=SQLAlchemyError())\n    event = event_handler.create_event('test', {}, 1, 1, 100)\n    assert event is None"
  },
  {
    "path": "tests/unit_tests/apm/test_knowledge_handler.py",
    "content": "import pytest\nfrom unittest.mock import MagicMock\nfrom superagi.apm.knowledge_handler import KnowledgeHandler\nfrom fastapi import HTTPException\nfrom datetime import datetime\nimport pytz\n\n@pytest.fixture\ndef organisation_id():\n    return 1\n\n@pytest.fixture\ndef mock_session():\n    return MagicMock()\n\n@pytest.fixture\ndef knowledge_handler(mock_session, organisation_id):\n    return KnowledgeHandler(mock_session, organisation_id)\n\ndef test_get_knowledge_usage_by_name(knowledge_handler, mock_session):\n    knowledge_handler.session = mock_session\n    knowledge_name = 'Knowledge1'\n    mock_knowledge_event = MagicMock()\n    mock_knowledge_event.knowledge_unique_agents = 5\n    mock_knowledge_event.knowledge_name = knowledge_name\n    mock_knowledge_event.id = 1\n\n    mock_session.query.return_value.filter_by.return_value.filter.return_value.first.return_value = mock_knowledge_event\n    mock_session.query.return_value.filter.return_value.group_by.return_value.first.return_value = mock_knowledge_event\n    mock_session.query.return_value.filter.return_value.count.return_value = 10\n\n    result = knowledge_handler.get_knowledge_usage_by_name(knowledge_name)\n\n    assert isinstance(result, dict)\n    assert result == {\n        'knowledge_unique_agents': 5,\n        'knowledge_calls': 10\n    }\n\n    mock_session.query.return_value.filter_by.return_value.filter.return_value.first.return_value = None\n\n    with pytest.raises(HTTPException):\n        knowledge_handler.get_knowledge_usage_by_name('NonexistentKnowledge')\n\ndef test_get_knowledge_events_by_name(knowledge_handler, mock_session):\n    knowledge_name = 'knowledge1'\n    knowledge_handler.session = mock_session\n    knowledge_handler.organisation_id = 1\n\n    mock_knowledge = MagicMock()\n    mock_knowledge.id = 1\n    mock_session.query().filter_by().filter().first.return_value = mock_knowledge\n\n    result_obj = MagicMock()\n    result_obj.agent_id = 1\n    result_obj.created_at = datetime.now()\n    result_obj.event_name = 'knowledge_picked'\n    result_obj.event_property = {'knowledge_name': 'knowledge1', 'agent_execution_id': '1'}\n    result_obj2 = MagicMock()\n    result_obj2.agent_id = 1\n    result_obj2.event_name = 'run_completed'\n    result_obj2.event_property = {'tokens_consumed': 10, 'calls': 5, 'name': 'Runner', 'agent_execution_id': '1'}\n    result_obj3 = MagicMock()\n    result_obj3.agent_id = 1\n    result_obj3.event_name = 'agent_created'\n    result_obj3.event_property = {'agent_name': 'A1', 'model': 'M1'}\n\n    mock_session.query().filter().all.side_effect = [[result_obj], [result_obj2], [result_obj3]]\n    \n    user_timezone = MagicMock()\n    user_timezone.value = 'America/New_York'\n    mock_session.query().filter().first.return_value = user_timezone\n    \n    result = knowledge_handler.get_knowledge_events_by_name(knowledge_name)\n\n    assert isinstance(result, list)\n    assert len(result) == 1\n    for item in result:\n        assert 'agent_execution_id' in item\n        assert 'created_at' in item\n        assert 'tokens_consumed' in item\n        assert 'calls' in item\n        assert 'agent_execution_name' in item\n        assert 'agent_name' in item\n        assert 'model' in item\n\n\ndef test_get_knowledge_events_by_name_knowledge_not_found(knowledge_handler, mock_session):\n    knowledge_name = \"knowledge1\"\n    not_found_message = 'Knowledge not found'\n\n    mock_session.query().filter_by().filter().first.return_value = None\n\n    try:\n        knowledge_handler.get_knowledge_events_by_name(knowledge_name)\n        assert False, \"Expected HTTPException has not been raised\"\n    except HTTPException as e:\n        assert str(e.detail) == not_found_message, f\"Expected {not_found_message}, got {e.detail}\"\n    finally:\n        assert mock_session.query().filter_by().filter().first.called, \"first() function not called\""
  },
  {
    "path": "tests/unit_tests/apm/test_tools_handler.py",
    "content": "import pytest\nfrom unittest.mock import MagicMock, patch\nfrom fastapi import HTTPException\nfrom superagi.apm.tools_handler import ToolsHandler\nfrom sqlalchemy.orm import Session\nfrom superagi.models.agent_config import AgentConfiguration\n\nfrom datetime import datetime\nimport pytz\n\n@pytest.fixture\ndef organisation_id():\n    return 1\n\n@pytest.fixture\ndef mock_session():\n    return MagicMock()\n\n@pytest.fixture\ndef tools_handler(mock_session, organisation_id):\n    return ToolsHandler(mock_session, organisation_id)\n\ndef test_calculate_tool_usage(tools_handler, mock_session):\n    tool_used_subquery = MagicMock()\n    agent_count_subquery = MagicMock()\n    total_usage_subquery = MagicMock()\n\n    tool_used_subquery.c.tool_name = 'Tool1'\n    tool_used_subquery.c.agent_id = 1\n    agent_count_subquery.c.tool_name = 'Tool1'\n    agent_count_subquery.c.unique_agents = 1\n    total_usage_subquery.c.tool_name = 'Tool1'\n    total_usage_subquery.c.total_usage = 5\n\n    mock_session.query.return_value.filter_by.return_value.subquery.return_value = tool_used_subquery\n    mock_session.query.return_value.group_by.return_value.subquery.side_effect = [agent_count_subquery, total_usage_subquery]\n\n    result_obj = MagicMock()\n    result_obj.tool_name = 'Tool1'\n    result_obj.unique_agents = 1\n    result_obj.total_usage = 5\n\n    mock_session.query.return_value.join.return_value.all.return_value = [result_obj]\n\n    tools_handler.get_tool_and_toolkit = MagicMock(return_value={'tool1': 'Toolkit1'})\n\n    result = tools_handler.calculate_tool_usage()\n\n    assert isinstance(result, list)\n\n    expected_output = [{'tool_name': 'Tool1', 'unique_agents': 1, 'total_usage': 5, 'toolkit': 'Toolkit1'}]\n\n    assert result == expected_output\n\ndef test_get_tool_and_toolkit(tools_handler, mock_session):\n    result_obj = MagicMock()\n    result_obj.tool_name = 'tool 1'\n    result_obj.toolkit_name = 'toolkit 1'\n    \n    mock_session.query().join().all.return_value = [result_obj]\n    \n    output = tools_handler.get_tool_and_toolkit()\n    \n    assert isinstance(output, dict)\n    assert output == {'tool 1': 'toolkit 1'} \n\ndef test_get_tool_usage_by_name(tools_handler, mock_session):\n    tools_handler.session = mock_session\n    tool_name = 'Tool1'\n    formatted_tool_name = tool_name.lower().replace(\" \", \"\")\n\n    mock_tool = MagicMock()\n    mock_tool.name = tool_name\n    \n    mock_tool_event = MagicMock()\n    mock_tool_event.tool_name = formatted_tool_name\n    mock_tool_event.tool_calls = 10\n    mock_tool_event.tool_unique_agents = 5\n    \n    mock_session.query.return_value.filter_by.return_value.first.return_value = mock_tool\n    mock_session.query.return_value.filter.return_value.group_by.return_value.first.return_value = mock_tool_event\n\n    result = tools_handler.get_tool_usage_by_name(tool_name=tool_name)\n  \n    assert isinstance(result, dict)\n    assert result == {\n        'tool_calls': 10,\n        'tool_unique_agents': 5\n    }\n\n    mock_session.query.return_value.filter_by.return_value.first.return_value = None\n\n    with pytest.raises(HTTPException):\n        tools_handler.get_tool_usage_by_name(tool_name=\"NonexistentTool\")\n\ndef test_get_tool_events_by_name(tools_handler, mock_session):\n    tool_name = 'Tool1'\n    tools_handler.session = mock_session\n    tools_handler.organisation_id = 1\n\n    mock_tool = MagicMock()\n    mock_tool.id = 1\n    mock_session.query().filter_by().first.return_value = mock_tool\n\n    result_obj = MagicMock()\n    result_obj.agent_id = 1\n    result_obj.id = 1\n    result_obj.created_at = datetime.now()\n    result_obj.event_name = 'tool_used'\n    result_obj.event_property = {'tool_name': 'tool1', 'agent_execution_id': '1'}\n    result_obj2 = MagicMock()\n    result_obj2.agent_id = 1\n    result_obj2.id = 2\n    result_obj2.event_name = 'run_completed'\n    result_obj2.event_property = {'tokens_consumed': 10, 'calls': 5, 'name': 'Runner', 'agent_execution_id': '1'}\n    result_obj3 = MagicMock()\n    result_obj3.agent_id = 1\n    result_obj3.event_name = 'agent_created'\n    result_obj3.event_property = {'agent_name': 'A1', 'model': 'M1'}\n\n    mock_session.query().filter().all.side_effect = [[result_obj], [result_obj2], [result_obj3], []]\n    \n    user_timezone = MagicMock()\n    user_timezone.value = 'America/New_York'\n    mock_session.query().filter().first.return_value = user_timezone\n    \n    result = tools_handler.get_tool_events_by_name(tool_name)\n\n    assert isinstance(result, list)\n    assert len(result) == 1\n    for item in result:\n        assert 'agent_execution_id' in item\n        assert 'created_at' in item\n        assert 'tokens_consumed' in item\n        assert 'calls' in item\n        assert 'agent_execution_name' in item\n        assert 'agent_name' in item\n        assert 'model' in item\n\ndef test_get_tool_events_by_name_tool_not_found(tools_handler, mock_session):\n    tool_name = \"tool1\"\n    \n    mock_session.query().filter_by().first.return_value = None\n    with pytest.raises(HTTPException):\n        tools_handler.get_tool_events_by_name(tool_name)\n        \n    assert mock_session.query().filter_by().first.called"
  },
  {
    "path": "tests/unit_tests/controllers/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/controllers/api/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/controllers/api/test_agent.py",
    "content": "import pytest\nfrom fastapi.testclient import TestClient\nfrom fastapi import HTTPException\n\nimport superagi.config.config\nfrom unittest.mock import MagicMock, patch,Mock\nfrom main import app\nfrom unittest.mock import patch,create_autospec\nfrom sqlalchemy.orm import Session\nfrom superagi.controllers.api.agent import ExecutionStateChangeConfigIn,AgentConfigUpdateExtInput\nfrom superagi.models.agent import Agent\nfrom superagi.models.project import Project\n\nclient = TestClient(app)\n\n@pytest.fixture\ndef mock_api_key_get():\n    mock_api_key = \"your_mock_api_key\"\n    return mock_api_key\n@pytest.fixture\ndef mock_execution_state_change_input():\n    return {\n\n    }\n@pytest.fixture\ndef mock_run_id_config():\n    return {\n        \"run_ids\":[1,2]\n    }\n\n@pytest.fixture\ndef mock_agent_execution():\n    return {\n\n    }\n@pytest.fixture\ndef mock_run_id_config_empty():\n    return {\n        \"run_ids\":[]\n    }\n\n@pytest.fixture\ndef mock_run_id_config_invalid():\n    return {\n        \"run_ids\":[12310]\n    }\n@pytest.fixture\ndef mock_agent_config_update_ext_input():\n    return AgentConfigUpdateExtInput(\n        tools=[{\"name\":\"Image Generation Toolkit\"}],\n        schedule=None,\n        goal=[\"Test Goal\"],\n        instruction=[\"Test Instruction\"],\n        constraints=[\"Test Constraints\"],\n        iteration_interval=10,\n        model=\"Test Model\",\n        max_iterations=100,\n        agent_type=\"Test Agent Type\"\n    )\n\n@pytest.fixture\ndef mock_update_agent_config():\n    return {\n        \"name\": \"agent_3_UPDATED\",\n        \"description\": \"AI assistant to solve complex problems\",\n        \"goal\": [\"create a photo of a cat\"],\n        \"agent_type\": \"Dynamic Task Workflow\",\n        \"constraints\": [\n            \"~4000 word limit for short term memory.\",\n            \"Your long term memory is short, so immediately save important information to files.\",\n            \"If you are unsure how you previously did something or want to recall past events, thinking about similar events will help you remember.\",\n            \"No user assistance\",\n            \"Exclusively use the commands listed in double quotes e.g. \\\"command name\\\"\"\n        ],\n        \"instruction\": [\"Be accurate\"],\n        \"tools\":[\n            {\n                \"name\":\"Image Generation Toolkit\"\n            }\n        ],\n        \"iteration_interval\": 500,\n        \"model\": \"gpt-4\",\n        \"max_iterations\": 100\n    }\n# Define test cases\n\ndef test_update_agent_not_found(mock_update_agent_config,mock_api_key_get):\n    with patch('superagi.helper.auth.get_organisation_from_api_key') as mock_get_user_org, \\\n            patch('superagi.helper.auth.validate_api_key') as mock_validate_api_key, \\\n                patch('superagi.helper.auth.db') as mock_auth_db, \\\n                    patch('superagi.controllers.api.agent.db') as db_mock:\n\n        # Mock the session\n        mock_session = create_autospec(Session)\n        # # Configure session query methods to return None for agent\n        mock_session.query.return_value.filter.return_value.first.return_value = None\n        response = client.put(\n            \"/v1/agent/1\",\n            headers={\"X-API-Key\": mock_api_key_get},  # Provide the mock API key in headers\n            json=mock_update_agent_config\n        )\n        assert response.status_code == 404\n        assert response.text == '{\"detail\":\"Agent not found\"}'\n\n\ndef test_get_run_resources_no_run_ids(mock_run_id_config_empty,mock_api_key_get):\n    with patch('superagi.helper.auth.get_organisation_from_api_key') as mock_get_user_org, \\\n            patch('superagi.helper.auth.validate_api_key') as mock_validate_api_key, \\\n                patch('superagi.helper.auth.db') as mock_auth_db, \\\n                    patch('superagi.controllers.api.agent.db') as db_mock, \\\n                        patch('superagi.controllers.api.agent.get_config', return_value=\"S3\") as mock_get_config:\n\n        # Mock the session\n        mock_session = create_autospec(Session)\n        # # Configure session query methods to return None for agent\n        mock_session.query.return_value.filter.return_value.first.return_value = None\n        response = client.post(\n            \"v1/agent/resources/output\",\n            headers={\"X-API-Key\": mock_api_key_get},  # Provide the mock API key in headers\n            json=mock_run_id_config_empty\n        )\n        assert response.status_code == 404\n        assert response.text == '{\"detail\":\"No execution_id found\"}'\n\ndef test_get_run_resources_invalid_run_ids(mock_run_id_config_invalid,mock_api_key_get):\n    with patch('superagi.helper.auth.get_organisation_from_api_key') as mock_get_user_org, \\\n            patch('superagi.helper.auth.validate_api_key') as mock_validate_api_key, \\\n                patch('superagi.helper.auth.db') as mock_auth_db, \\\n                    patch('superagi.controllers.api.agent.db') as db_mock, \\\n                        patch('superagi.controllers.api.agent.get_config', return_value=\"S3\") as mock_get_config:\n\n        # Mock the session\n        mock_session = create_autospec(Session)\n        # # Configure session query methods to return None for agent\n        mock_session.query.return_value.filter.return_value.first.return_value = None\n        response = client.post(\n            \"v1/agent/resources/output\",\n            headers={\"X-API-Key\": mock_api_key_get},  # Provide the mock API key in headers\n            json=mock_run_id_config_invalid\n        )\n        assert response.status_code == 404\n        assert response.text == '{\"detail\":\"One or more run id(s) not found\"}'\n\ndef test_resume_agent_runs_agent_not_found(mock_execution_state_change_input,mock_api_key_get):\n    with patch('superagi.helper.auth.get_organisation_from_api_key') as mock_get_user_org, \\\n            patch('superagi.helper.auth.validate_api_key') as mock_validate_api_key, \\\n                patch('superagi.helper.auth.db') as mock_auth_db, \\\n                    patch('superagi.controllers.api.agent.db') as db_mock:\n\n        # Mock the session\n        mock_session = create_autospec(Session)\n        # # Configure session query methods to return None for agent\n        mock_session.query.return_value.filter.return_value.first.return_value = None\n        response = client.post(\n            \"/v1/agent/1/resume\",\n            headers={\"X-API-Key\": mock_api_key_get},  # Provide the mock API key in headers\n            json=mock_execution_state_change_input\n        )\n        assert response.status_code == 404\n        assert response.text == '{\"detail\":\"Agent not found\"}'\n\n\ndef test_pause_agent_runs_agent_not_found(mock_execution_state_change_input,mock_api_key_get):\n    with patch('superagi.helper.auth.get_organisation_from_api_key') as mock_get_user_org, \\\n            patch('superagi.helper.auth.validate_api_key') as mock_validate_api_key, \\\n                patch('superagi.helper.auth.db') as mock_auth_db, \\\n                    patch('superagi.controllers.api.agent.db') as db_mock:\n\n        # Mock the session\n        mock_session = create_autospec(Session)\n        # # Configure session query methods to return None for agent\n        mock_session.query.return_value.filter.return_value.first.return_value = None\n        response = client.post(\n            \"/v1/agent/1/pause\",\n            headers={\"X-API-Key\": mock_api_key_get},  # Provide the mock API key in headers\n            json=mock_execution_state_change_input\n        )\n        assert response.status_code == 404\n        assert response.text == '{\"detail\":\"Agent not found\"}'\n\ndef test_create_run_agent_not_found(mock_agent_execution,mock_api_key_get):\n    with patch('superagi.helper.auth.get_organisation_from_api_key') as mock_get_user_org, \\\n            patch('superagi.helper.auth.validate_api_key') as mock_validate_api_key, \\\n                patch('superagi.helper.auth.db') as mock_auth_db, \\\n                    patch('superagi.controllers.api.agent.db') as db_mock:\n\n        # Mock the session\n        mock_session = create_autospec(Session)\n        # # Configure session query methods to return None for agent\n        mock_session.query.return_value.filter.return_value.first.return_value = None\n        response = client.post(\n            \"/v1/agent/1/run\",\n            headers={\"X-API-Key\": mock_api_key_get},  # Provide the mock API key in headers\n            json=mock_agent_execution\n        )\n        assert response.status_code == 404\n        assert response.text == '{\"detail\":\"Agent not found\"}'\n\ndef test_create_run_project_not_matching_org(mock_agent_execution, mock_api_key_get):\n    with patch('superagi.helper.auth.get_organisation_from_api_key') as mock_get_user_org, \\\n            patch('superagi.helper.auth.validate_api_key') as mock_validate_api_key, \\\n            patch('superagi.helper.auth.db') as mock_auth_db, \\\n            patch('superagi.controllers.api.agent.db') as db_mock:\n\n        # Mock the session and configure query methods to return agent and project\n        mock_session = create_autospec(Session)\n        mock_agent = Agent(id=1, project_id=1, agent_workflow_id=1)\n        mock_session.query.return_value.filter.return_value.first.return_value = mock_agent\n        mock_project = Project(id=1, organisation_id=2)  # Different organisation ID\n        db_mock.Project.find_by_id.return_value = mock_project\n        db_mock.session.return_value.__enter__.return_value = mock_session\n\n        response = client.post(\n            \"/v1/agent/1/run\",\n            headers={\"X-API-Key\": mock_api_key_get},\n            json=mock_agent_execution\n        )\n\n        assert response.status_code == 404\n        assert response.text == '{\"detail\":\"Agent not found\"}'\n"
  },
  {
    "path": "tests/unit_tests/controllers/test_agent.py",
    "content": "from unittest.mock import patch, Mock\nfrom unittest import mock\nimport pytest\nfrom fastapi.testclient import TestClient\n\nfrom main import app\nfrom superagi.models.agent_schedule import AgentSchedule\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.models.agent import Agent\nfrom datetime import datetime, timedelta\nfrom pytz import timezone\n\nclient = TestClient(app)\n\n@pytest.fixture\ndef mock_patch_schedule_input():\n    return{\n        \"agent_id\": 1,\n        \"start_time\": \"2023-02-02 01:00:00\",\n        \"recurrence_interval\": \"2 Hours\",\n        \"expiry_date\": \"2023-12-30 01:00:00\",\n        \"expiry_runs\": -1\n    }\n\n@pytest.fixture\ndef mock_schedule():\n    # Mock schedule data for testing\n    return AgentSchedule(id=1, agent_id=1, status=\"SCHEDULED\")\n\n@pytest.fixture\ndef mock_agent_config():\n    return AgentConfiguration(key=\"user_timezone\", agent_id=1, value='GMT')\n\n@pytest.fixture\ndef mock_schedule_get():\n    return AgentSchedule(\n        id=1, \n        agent_id=1, \n        status=\"SCHEDULED\",\n        start_time= datetime(2022, 1, 1, 10, 30),\n        recurrence_interval=\"5 Minutes\",\n        expiry_date=datetime(2022, 1, 1, 10, 30) + timedelta(days=10),\n        expiry_runs=5 \n    )\n\n'''Test for Stopping Agent Scheduling'''\ndef test_stop_schedule_success(mock_schedule):\n    with patch('superagi.controllers.agent.db') as mock_db:\n        # Set up the database query result\n        mock_db.session.query.return_value.filter.return_value.first.return_value = mock_schedule \n\n        # Call the endpoint\n        response = client.post(\"agents/stop/schedule?agent_id=1\")\n\n        # Verify the HTTP response\n        assert response.status_code == 200\n\n        # Verify changes in the mock agent schedule\n        assert mock_schedule.status == \"STOPPED\"\n\n\ndef test_stop_schedule_not_found():\n    with patch('superagi.controllers.agent.db') as mock_db:\n        # Set up the database query result\n        mock_db.session.query.return_value.filter.return_value.first.return_value = None\n\n        # Call the endpoint\n        response = client.post(\"agents/stop/schedule?agent_id=1\")\n\n        # Verify the HTTP response\n        assert response.status_code == 404\n        assert response.json() == {\"detail\": \"Schedule not found\"}\n\n\n'''Test for editing agent schedule'''\ndef test_edit_schedule_success(mock_schedule, mock_patch_schedule_input):\n    with patch('superagi.controllers.agent.db') as mock_db:\n        # Set up the database query result\n        mock_db.session.query.return_value.filter.return_value.first.return_value = mock_schedule\n\n        # Call the endpoint\n        response = client.put(\"agents/edit/schedule\", json=mock_patch_schedule_input)\n\n        # Verify the HTTP response\n        assert response.status_code == 200\n        start_time = datetime.strptime(mock_patch_schedule_input[\"start_time\"], \"%Y-%m-%d %H:%M:%S\")\n        expiry_date = datetime.strptime(mock_patch_schedule_input[\"expiry_date\"], \"%Y-%m-%d %H:%M:%S\")\n\n        # Verify changes in the mock agent schedule\n        assert mock_schedule.start_time == start_time\n        assert mock_schedule.recurrence_interval == mock_patch_schedule_input[\"recurrence_interval\"]\n        assert mock_schedule.expiry_date == expiry_date\n        assert mock_schedule.expiry_runs == mock_patch_schedule_input[\"expiry_runs\"]\n\n\ndef test_edit_schedule_not_found(mock_patch_schedule_input):\n    with patch('superagi.controllers.agent.db') as mock_db:\n        # Set up the database query result\n        mock_db.session.query.return_value.filter.return_value.first.return_value = None\n\n        # Call the endpoint\n        response = client.put(\"agents/edit/schedule\", json=mock_patch_schedule_input)\n\n        # Verify the HTTP response\n        assert response.status_code == 404\n        assert response.json() == {\"detail\": \"Schedule not found\"}\n\n'''Test for getting agent schedule'''\ndef test_get_schedule_data_success(mock_schedule_get, mock_agent_config):\n    with patch('superagi.controllers.agent.db') as mock_db:\n        mock_db.session.query.return_value.filter.return_value.first.side_effect = [mock_schedule_get, mock_agent_config]\n        response = client.get(\"agents/get/schedule_data/1\")\n        assert response.status_code == 200\n\n        time_gmt = mock_schedule_get.start_time.astimezone(timezone('GMT'))\n\n        expected_data = {\n            \"current_datetime\": mock.ANY,\n            \"start_date\": time_gmt.strftime(\"%d %b %Y\"),\n            \"start_time\": time_gmt.strftime(\"%I:%M %p\"),\n            \"recurrence_interval\": mock_schedule_get.recurrence_interval,\n            \"expiry_date\": mock_schedule_get.expiry_date.astimezone(timezone('GMT')).strftime(\"%d/%m/%Y\"),\n            \"expiry_runs\": mock_schedule_get.expiry_runs,\n        }\n        assert response.json() == expected_data\n\n\ndef test_get_schedule_data_not_found():\n    with patch('superagi.controllers.agent.db') as mock_db:\n        # Set up the database query result\n        mock_db.session.query.return_value.filter.return_value.first.return_value = None\n\n        # Call the endpoint\n        response = client.get(\"agents/get/schedule_data/1\")\n\n        # Verify the HTTP response\n        assert response.status_code == 404\n        assert response.json() == {\"detail\": \"Agent Schedule not found\"}\n\n\n@pytest.fixture\ndef mock_agent_config_schedule():\n    return {\n        \"agent_config\": {\n            \"name\": \"SmartAGI\", \n            \"project_id\": 1,\n            \"description\": \"AI assistant to solve complex problems\",\n            \"goal\": [\"Share research on latest google news in fashion\"],\n            \"agent_workflow\": \"Don't Maintain Task Queue\",\n            \"constraints\": [\n                \"~4000 word limit for short term memory.\",\n                \"No user assistance\",\n                \"Exclusively use the commands listed in double quotes\"\n            ],\n            \"instruction\": [],\n            \"exit\": \"Exit strategy\",\n            \"iteration_interval\": 500,\n            \"model\": \"gpt-4\",\n            \"permission_type\": \"Type 1\",\n            \"LTM_DB\": \"Database Pinecone\",\n            \"toolkits\": [1],\n            \"tools\": [],\n            \"memory_window\": 10,\n            \"max_iterations\": 25,\n            \"user_timezone\": \"Asia/Kolkata\"\n        },\n        \"schedule\": {\n            \"start_time\": \"2023-07-04 11:13:00\",\n            \"expiry_runs\": -1,\n            \"recurrence_interval\": None,\n            \"expiry_date\": None\n        }\n    }\n\n@pytest.fixture\ndef mock_agent():\n    agent = Agent(id=1, name=\"SmartAGI\", project_id=1)\n    return agent\n\n\ndef test_create_and_schedule_agent_success(mock_agent_config_schedule, mock_agent, mock_schedule):\n    \n    with patch('superagi.models.agent.Agent') as AgentMock,\\\n         patch('superagi.controllers.agent.Project') as ProjectMock,\\\n         patch('superagi.controllers.agent.Tool') as ToolMock,\\\n         patch('superagi.controllers.agent.Toolkit') as ToolkitMock,\\\n         patch('superagi.controllers.agent.AgentSchedule') as AgentScheduleMock,\\\n         patch('superagi.controllers.agent.db') as db_mock:\n\n        project_mock = Mock()\n        ProjectMock.get.return_value = project_mock\n\n        # AgentMock.create_agent_with_config.return_value = mock_agent\n        AgentMock.return_value =  mock_agent\n\n        tool_mock = Mock()\n        ToolMock.get_invalid_tools.return_value = []\n\n        toolkit_mock = Mock()\n        ToolkitMock.fetch_tool_ids_from_toolkit.return_value = []\n        \n        agent_schedule_mock = Mock()\n        agent_schedule_mock.id = None  # id is None before commit\n        AgentScheduleMock.return_value = mock_schedule\n        \n        db_mock.session.query.return_value.get.return_value = project_mock\n        db_mock.session.add.return_value = None\n        db_mock.session.commit.side_effect = lambda: setattr(agent_schedule_mock, 'id', 1)  # id is set after commit\n        db_mock.session.query.return_value.get.return_value = project_mock\n\n        response = client.post(\"agents/schedule\", json=mock_agent_config_schedule)\n\n        assert response.status_code == 201\n        assert response.json() == {\n            \"id\": mock_agent.id,\n            \"name\": mock_agent.name,\n            \"contentType\": \"Agents\",\n            \"schedule_id\": 1\n        }\n\n\ndef test_create_and_schedule_agent_project_not_found(mock_agent_config_schedule):\n    with patch('superagi.controllers.agent.db') as mock_db:\n        # Set up the database query result\n        mock_db.session.query.return_value.get.return_value = None\n\n        # Call the endpoint\n        response = client.post(\"agents/schedule\", json=mock_agent_config_schedule)\n\n        # Verify the HTTP response\n        assert response.status_code == 404\n        assert response.json() == {\"detail\": \"Project not found\"}"
  },
  {
    "path": "tests/unit_tests/controllers/test_agent_execution.py",
    "content": "from unittest.mock import patch\nfrom unittest import mock\nimport pytest\nfrom fastapi.testclient import TestClient\n\nfrom main import app\nfrom superagi.models.agent_schedule import AgentSchedule\nfrom datetime import datetime\n\nclient = TestClient(app)\n\n@pytest.fixture\ndef mock_patch_schedule_input():\n    return {\n        \"agent_id\": 1,\n        \"start_time\": \"2023-02-02 01:00:00\",\n        \"recurrence_interval\": \"2 Hours\",\n        \"expiry_date\": \"2023-12-30 01:00:00\",\n        \"expiry_runs\": -1\n    }\n\n@pytest.fixture\ndef mock_schedule():\n    # Mock schedule data for testing\n    return AgentSchedule(id=1, agent_id=1, status=\"SCHEDULED\")\n\n# An agent is already scheduled and is simply being updated, we assert for the updated values here\ndef test_schedule_existing_agent_already_scheduled(mock_patch_schedule_input, mock_schedule):\n    with patch('superagi.controllers.agent_execution.db') as mock_db:\n        mock_db.session.query.return_value.filter.return_value.first.return_value = mock_schedule \n\n        response = client.post(\"agentexecutions/schedule\", json=mock_patch_schedule_input)\n\n        assert response.status_code == 201\n        assert mock_schedule.start_time == datetime.strptime(mock_patch_schedule_input['start_time'], '%Y-%m-%d %H:%M:%S')\n        assert mock_schedule.recurrence_interval == mock_patch_schedule_input['recurrence_interval']\n        assert mock_schedule.expiry_date == datetime.strptime(mock_patch_schedule_input['expiry_date'], '%Y-%m-%d %H:%M:%S')\n        assert mock_schedule.expiry_runs == mock_patch_schedule_input['expiry_runs']\n\n# The agent isn't scheduled yet and we are scheduling it, we simply assert for a 201 status code and non-null schedule id.\ndef test_schedule_existing_agent_new_schedule(mock_patch_schedule_input, mock_schedule):\n    with patch('superagi.controllers.agent_execution.db') as mock_db:\n        mock_db.session.query.return_value.filter.return_value.first.return_value = mock_schedule\n\n        response = client.post(\"agentexecutions/schedule\", json=mock_patch_schedule_input)\n\n        assert response.status_code == 201\n        assert response.json()[\"schedule_id\"] is not None"
  },
  {
    "path": "tests/unit_tests/controllers/test_agent_execution_config.py",
    "content": "from unittest.mock import patch\n\nimport pytest\nfrom fastapi.testclient import TestClient\n\nfrom main import app\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_config import AgentExecutionConfiguration\n\nclient = TestClient(app)\n\n@pytest.fixture\ndef mocks():\n    # Mock tool kit data for testing\n    mock_agent = Agent(id=1, name=\"test_agent\", project_id=1, description=\"testing\", agent_workflow_id=1, is_deleted=False)\n    mock_agent_config = AgentConfiguration(id=1, agent_id=1, key=\"test_key\", value=\"['test']\")\n    mock_execution = AgentExecution(id=54, agent_id=1, name=\"test_execution\")\n    mock_execution_config = [AgentExecutionConfiguration(id=64, agent_execution_id=1, key=\"test_key\", value=\"['test']\")]\n    return mock_agent,mock_agent_config,mock_execution,mock_execution_config\n\n\ndef test_get_agent_execution_configuration_not_found_failure():\n    with patch('superagi.controllers.agent_execution_config.db') as mock_db:\n        mock_db.session.query.return_value.filter.return_value.all.return_value = []\n        mock_db.session.query.return_value.filter.return_value.first.return_value = None\n        response = client.get(\"/agent_executions_configs/details/agent_id/1/agent_execution_id/1\")\n\n        assert response.status_code == 404\n        assert response.json() == {\"detail\": \"Agent not found\"}\n\n\ndef test_get_agent_execution_configuration_success(mocks):\n    with patch('superagi.controllers.agent_execution_config.db') as mock_db:\n        mock_agent, mock_agent_config, mock_execution, mock_execution_config = mocks\n\n        # Configure the mock objects to return the mock values\n        mock_db.session.query.return_value.filter.return_value.first.return_value = mock_agent\n        mock_db.session.query.return_value.filter.return_value.all.return_value = [mock_agent_config]\n        mock_db.session.query.return_value.filter.return_value.order_by.return_value.first.return_value = mock_execution\n        mock_db.session.query.return_value.filter.return_value.all.return_value = mock_execution_config\n\n        # Mock the AgentExecution.get_agent_execution_from_id method to return the mock_execution object\n        with patch('superagi.controllers.agent_execution_config.AgentExecution.get_agent_execution_from_id') as mock_get_exec:\n            mock_get_exec.return_value = mock_execution\n\n            response = client.get(\"/agent_executions_configs/details/agent_id/1/agent_execution_id/1\")\n\n            assert response.status_code == 200\n\n\n"
  },
  {
    "path": "tests/unit_tests/controllers/test_agent_execution_feeds.py",
    "content": "from unittest.mock import MagicMock, Mock, create_autospec, patch\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom fastapi import HTTPException\nfrom main import app\nfrom fastapi_sqlalchemy import db\nfrom superagi.controllers.agent_execution_feed import get_agent_execution_feed\n\n@patch('superagi.controllers.agent_execution_feed.db')\ndef test_get_agent_execution_feed(mock_query):\n    mock_session = create_autospec(pytest.Session)\n    \n    AgentExecution = MagicMock()\n    agent_execution = AgentExecution()\n    agent_execution.status = \"PAUSED\"\n    agent_execution.last_shown_error_id = None\n    \n    AgentExecutionFeed = MagicMock()\n    agent_execution_feed = AgentExecutionFeed()\n    agent_execution_feed.error_message = None\n    \n    feeds = [agent_execution_feed]\n    \n    check_auth = MagicMock()\n    AuthJWT = MagicMock()\n    check_auth.return_value = AuthJWT  \n    asc = MagicMock()\n    \n    AgentExecutionPermission = MagicMock()\n    agent_execution_permission = AgentExecutionPermission()\n    agent_execution_permission.id = 1\n    agent_execution_permission.created_at = \"2021-12-13T00:00:00\"\n    agent_execution_permission.response = \"Yes\"\n    agent_execution_permission.status = \"Completed\"\n    agent_execution_permission.tool_name = \"Tool1\"\n    agent_execution_permission.question = \"Question1\"\n    agent_execution_permission.user_feedback = \"Feedback1\"\n        \n    permissions = [agent_execution_permission]\n    mock_agent_execution = Mock() \n    mock_query.return_value.filter.return_value.first.return_value = mock_agent_execution\n    mock_agent_execution_id = 1\n    assert get_agent_execution_feed(mock_agent_execution_id)"
  },
  {
    "path": "tests/unit_tests/controllers/test_agent_template.py",
    "content": "from unittest.mock import patch, MagicMock\nfrom superagi.models.agent_template import AgentTemplate\nfrom superagi.models.agent_template_config import AgentTemplateConfig\nfrom fastapi.testclient import TestClient\nfrom main import app\n\nclient = TestClient(app)\n\n@patch('superagi.controllers.agent_template.db')\n@patch('superagi.helper.auth.db')\n@patch('superagi.helper.auth.get_user_organisation')\ndef test_edit_agent_template_success(mock_get_user_org, mock_auth_db, mock_db):\n    # Create a mock agent template\n    mock_agent_template = AgentTemplate(id=1, name=\"Test Agent Template\", description=\"Test Description\")\n    # mock_agent_goals = AgentTemplateConfig()\n\n    # Create a mock edited agent configuration\n    mock_updated_agent_configs = {\n        \"name\": \"Updated Agent Template\",\n        \"description\": \"Updated Description\",\n        \"agent_configs\": {\n            \"agent_workflow\": \"Don't Maintain Task Queue\",\n            \"goal\": [\"Create a simple pacman game for me.\", \"Write all files properly.\"],\n            \"instruction\": [\"write spec\",\"write code\",\"improve the code\",\"write test\"],\n            \"constraints\": [\"If you are unsure how you previously did something or want to recall past events, thinking about similar events will help you remember.\",\"Ensure the tool and args are as per current plan and reasoning\",\"Exclusively use the tools listed under \\\"TOOLS\\\"\",\"REMEMBER to format your response as JSON, using double quotes (\\\"\\\") around keys and string values, and commas (,) to separate items in arrays and objects. IMPORTANTLY, to use a JSON object as a string in another JSON object, you need to escape the double quotes.\"],\n            \"tools\": [\"Read Email\", \"Send Email\", \"Write File\"],\n            \"exit\": \"No exit criterion\",\n            \"iteration_interval\": 500,\n            \"model\": \"gpt-4\",\n            \"max_iterations\": 25,\n            \"permission_type\": \"God Mode\",\n            \"LTM_DB\": \"Pinecone\"\n        }\n    }    \n\n    # Mocking the user organisation\n    mock_get_user_org.return_value = MagicMock(id=1)\n\n    # Create a session mock\n    session_mock = MagicMock()\n    mock_db.session = session_mock\n    mock_db.session.query.return_value.filter.return_value.first.return_value = mock_agent_template\n    mock_db.session.commit.return_value = None\n    mock_db.session.add.return_value = None\n    mock_db.session.flush.return_value = None\n\n    mock_agent_template_config = AgentTemplateConfig(agent_template_id = 1, key=\"goal\", value=[\"Create a simple pacman game for me.\", \"Write all files properly.\"])\n\n\n    # Call the endpoint\n    response = client.put(\"agent_templates/update_agent_template/1\", json=mock_updated_agent_configs)\n\n    assert response.status_code == 200\n        \n    # Verify changes in the mock agent template\n    assert mock_agent_template.name == \"Updated Agent Template\"\n    assert mock_agent_template.description == \"Updated Description\"\n    assert mock_agent_template_config.key == \"goal\"\n    assert mock_agent_template_config.value == [\"Create a simple pacman game for me.\", \"Write all files properly.\"]\n\n\n    session_mock.commit.assert_called()\n    session_mock.flush.assert_called()\n\n\n@patch('superagi.controllers.agent_template.db')\n@patch('superagi.helper.auth.db')\n@patch('superagi.helper.auth.get_user_organisation')\ndef test_edit_agent_template_failure(mock_get_user_org, mock_auth_db, mock_db):\n    # Setup: The user organisation exists, but the agent template does not exist.\n    mock_get_user_org.return_value = MagicMock(id=1)\n\n    # Create a session mock\n    session_mock = MagicMock()\n    mock_db.session = session_mock\n    mock_db.session.query.return_value.filter.return_value.first.return_value = None\n\n    # Call the endpoint\n    response = client.put(\"agent_templates/update_agent_template/1\", json={})\n\n    # Verify: The response status code should be 404, indicating that the agent template was not found.\n    assert response.status_code == 404\n    assert response.json() == {\"detail\": \"Agent Template not found\"}\n\n    # Verify: The database commit method should not have been called because the agent template was not found.\n    session_mock.commit.assert_not_called()\n    session_mock.flush.assert_not_called()\n\n\n@patch('superagi.controllers.agent_template.db')\n@patch('superagi.helper.auth.db')\n@patch('superagi.helper.auth.get_user_organisation')\ndef test_edit_agent_template_with_new_config_success(mock_get_user_org, mock_auth_db, mock_db):\n    # Create a mock agent template\n    mock_agent_template = AgentTemplate(id=1, name=\"Test Agent Template\", description=\"Test Description\")\n\n    # Create a mock edited agent configuration\n    mock_updated_agent_configs = {\n        \"name\": \"Updated Agent Template\",\n        \"description\": \"Updated Description\",\n        \"agent_configs\": {\n            \"new_config_key\": \"New config value\",\n            \"agent_workflow\": \"Don't Maintain Task Queue\", # This is a new config\n        }\n    }    \n\n    # Mocking the user organisation\n    mock_get_user_org.return_value = MagicMock(id=1)\n\n    # Create a session mock\n    session_mock = MagicMock()\n    mock_db.session = session_mock\n    mock_db.session.query.return_value.filter.return_value.first.return_value = mock_agent_template\n    mock_db.session.commit.return_value = None\n    mock_db.session.add.return_value = None\n    mock_db.session.flush.return_value = None\n\n    # Call the endpoint\n    response = client.put(\"agent_templates/update_agent_template/1\", json=mock_updated_agent_configs)\n\n    assert response.status_code == 200\n\n    # Verify changes in the mock agent template\n    assert mock_agent_template.name == \"Updated Agent Template\"\n    assert mock_agent_template.description == \"Updated Description\"\n\n    session_mock.commit.assert_called()\n    session_mock.flush.assert_called()"
  },
  {
    "path": "tests/unit_tests/controllers/test_analytics.py",
    "content": "from unittest.mock import patch, MagicMock\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom main import app\n\nclient = TestClient(app)\n\n@patch('superagi.controllers.analytics.db')\ndef test_get_metrics_success(mock_get_db):\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n                patch('superagi.controllers.analytics.db') as mock_db, \\\n                patch('superagi.controllers.analytics.AnalyticsHelper') as mock_helper, \\\n                patch('superagi.helper.auth.db') as mock_auth_db:\n        mock_helper().calculate_run_completed_metrics.return_value = {'total_tokens': 10, 'total_calls': 5, 'runs_completed': 2}\n        response = client.get(\"/analytics/metrics\")\n        assert response.status_code == 200\n        assert response.json() == {'total_tokens': 10, 'total_calls': 5, 'runs_completed': 2}\n\n@patch('superagi.controllers.analytics.db')\ndef test_get_agents_success(mock_get_db):\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n                    patch('superagi.controllers.analytics.db') as mock_db, \\\n                    patch('superagi.controllers.analytics.AnalyticsHelper') as mock_helper, \\\n                    patch('superagi.helper.auth.db') as mock_auth_db:\n        mock_helper().fetch_agent_data.return_value = {\"agent_details\": \"mock_details\", \"model_info\": \"mock_info\"}\n        response = client.get(\"/analytics/agents/all\")\n        assert response.status_code == 200\n        assert response.json() == {\"agent_details\": \"mock_details\", \"model_info\": \"mock_info\"}\n\n@patch('superagi.controllers.analytics.db')\ndef test_get_agent_runs_success(mock_get_db):\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n                    patch('superagi.controllers.analytics.db') as mock_db, \\\n                    patch('superagi.controllers.analytics.AnalyticsHelper') as mock_helper, \\\n                    patch('superagi.helper.auth.db') as mock_auth_db:\n        mock_helper().fetch_agent_runs.return_value = \"mock_agent_runs\"\n        response = client.get(\"/analytics/agents/1\")\n        assert response.status_code == 200\n        assert response.json() == \"mock_agent_runs\"\n\n@patch('superagi.controllers.analytics.db')\ndef test_get_active_runs_success(mock_get_db):\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n                    patch('superagi.controllers.analytics.db') as mock_db, \\\n                    patch('superagi.controllers.analytics.AnalyticsHelper') as mock_helper, \\\n                    patch('superagi.helper.auth.db') as mock_auth_db:\n        mock_helper().get_active_runs.return_value = [\"mock_run_1\", \"mock_run_2\"]\n        response = client.get(\"/analytics/runs/active\")\n        assert response.status_code == 200\n        assert response.json() == [\"mock_run_1\", \"mock_run_2\"]\n\n@patch('superagi.controllers.analytics.db')\ndef test_get_tools_user_success(mock_get_db):\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n                    patch('superagi.controllers.analytics.db') as mock_db, \\\n                    patch('superagi.controllers.analytics.ToolsHandler') as mock_handler, \\\n                    patch('superagi.helper.auth.db') as mock_auth_db:\n        mock_handler().calculate_tool_usage.return_value = [\"tool1\", \"tool2\"]\n        response = client.get(\"/analytics/tools/used\")\n        assert response.status_code == 200\n        assert response.json() == [\"tool1\", \"tool2\"]"
  },
  {
    "path": "tests/unit_tests/controllers/test_models_controller.py",
    "content": "from unittest.mock import patch, MagicMock\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom main import app\nfrom llama_cpp import Llama\nfrom llama_cpp import LlamaGrammar\nimport llama_cpp\n\nfrom superagi.helper.llm_loader import LLMLoader \n\nclient = TestClient(app)\n\n@patch('superagi.controllers.models_controller.db')\ndef test_store_api_keys_success(mock_get_db):\n    request = {\n        \"model_provider\": \"mock_provider\",\n        \"model_api_key\": \"mock_key\"\n    }\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n        patch('superagi.helper.auth.db') as mock_auth_db:\n\n        response = client.post(\"/models_controller/store_api_keys\", json=request)\n        assert response.status_code == 200\n\n@patch('superagi.controllers.models_controller.db')\ndef test_get_api_keys_success(mock_get_db):\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n        patch('superagi.helper.auth.db') as mock_auth_db:\n        response = client.get(\"/models_controller/get_api_keys\")\n        assert response.status_code == 200\n\n@patch('superagi.controllers.models_controller.db')\n@patch('superagi.controllers.models_controller.ModelsConfig.fetch_api_key', return_value = {})\ndef test_get_api_key_success(mock_fetch_api_key, mock_get_db):\n    params = {\n        \"model_provider\": \"model\"\n    }\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n        patch('superagi.helper.auth.db') as mock_auth_db:\n        response = client.get(\"/models_controller/get_api_key\", params=params)\n        assert response.status_code == 200\n\n@patch('superagi.controllers.models_controller.db')\ndef test_verify_end_point_success(mock_get_db):\n    with patch('superagi.helper.auth.db') as mock_auth_db:\n        response = client.get(\"/models_controller/verify_end_point?model_api_key=mock_key&end_point=mock_point&model_provider=mock_provider\")\n        assert response.status_code == 200\n\n@patch('superagi.controllers.models_controller.db')\ndef test_store_model_success(mock_get_db):\n    request = {\n        \"model_name\": \"mock_model\",\n        \"description\": \"mock_description\",\n        \"end_point\": \"mock_end_point\",\n        \"model_provider_id\": 1,\n        \"token_limit\": 10,\n        \"type\": \"mock_type\",\n        \"version\": \"mock_version\",\n        \"context_length\":4096\n    }\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n        patch('superagi.helper.auth.db') as mock_auth_db:\n        response = client.post(\"/models_controller/store_model\", json=request)\n        assert response.status_code == 200\n\n@patch('superagi.controllers.models_controller.db')\ndef test_fetch_models_success(mock_get_db):\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n        patch('superagi.helper.auth.db') as mock_auth_db:\n        response = client.get(\"/models_controller/fetch_models\")\n        assert response.status_code == 200\n\n@patch('superagi.controllers.models_controller.db')\ndef test_fetch_model_details_success(mock_get_db):\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n        patch('superagi.helper.auth.db') as mock_auth_db:\n        response = client.get(\"/models_controller/fetch_model/1\")\n        assert response.status_code == 200\n\n@patch('superagi.controllers.models_controller.db')\ndef test_fetch_data_success(mock_get_db):\n    request = {\n        \"model\": \"model\"\n    }\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n        patch('superagi.helper.auth.db') as mock_auth_db:\n        response = client.post(\"/models_controller/fetch_model_data\", json=request)\n        assert response.status_code == 200\n\n@patch('superagi.controllers.models_controller.db')\ndef test_get_marketplace_models_list_success(mock_get_db):\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n        patch('superagi.helper.auth.db') as mock_auth_db, \\\n        patch('superagi.controllers.models_controller.requests.get') as mock_get:\n\n        mock_response = MagicMock()\n        mock_response.status_code = 200\n        mock_get.return_value = mock_response\n\n        response = client.get(\"/models_controller/marketplace/list/0\")\n        assert response.status_code == 200\n\n@patch('superagi.controllers.models_controller.db')\ndef test_get_marketplace_models_list_success(mock_get_db):\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n        patch('superagi.helper.auth.db') as mock_auth_db:\n        response = client.get(\"/models_controller/marketplace/list/0\")\n        assert response.status_code == 200\n\ndef test_get_local_llm():\n    with(patch.object(LLMLoader, 'model', new_callable=MagicMock)) as mock_model:\n        with(patch.object(LLMLoader, 'grammar', new_callable=MagicMock)) as mock_grammar:\n\n            mock_model.create_chat_completion.return_value = {\"choices\": [{\"message\": {\"content\": \"Hello!\"}}]}\n\n            response = client.get(\"/models_controller/test_local_llm\")\n\n            assert response.status_code == 200"
  },
  {
    "path": "tests/unit_tests/controllers/test_publish_agent.py",
    "content": "import pytest\nfrom fastapi.testclient import TestClient\nfrom unittest.mock import create_autospec, patch\nfrom main import app\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_config import AgentExecutionConfiguration\nfrom superagi.models.organisation import Organisation\nfrom superagi.models.user import User\nfrom sqlalchemy.orm import Session\n\nclient = TestClient(app)\n\n@pytest.fixture\ndef mocks():\n    # Mock tool kit data for testing\n    mock_agent = Agent(id=1, name=\"test_agent\", project_id=1, description=\"testing\", agent_workflow_id=1, is_deleted=False)\n    mock_agent_config = AgentConfiguration(id=1, agent_id=1, key=\"test_key\", value=\"['test']\")\n    mock_execution = AgentExecution(id=1, agent_id=1, name=\"test_execution\")\n    mock_execution_config = [AgentExecutionConfiguration(id=1, agent_execution_id=1, key=\"test_key\", value=\"['test']\")]\n    return mock_agent,mock_agent_config,mock_execution,mock_execution_config\n\ndef test_publish_template(mocks):\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n        patch('superagi.helper.auth.get_current_user') as mock_get_user, \\\n        patch('superagi.helper.auth.db') as mock_auth_db,\\\n        patch('superagi.controllers.agent_template.db') as mock_db:\n    \n            mock_session = create_autospec(Session)\n            mock_agent, mock_agent_config, mock_execution, mock_execution_config = mocks  \n\n            mock_session.query.return_value.filter.return_value.first.return_value = mock_agent\n            mock_session.query.return_value.filter.return_value.all.return_value = [mock_agent_config]\n            mock_session.query.return_value.filter.return_value.order_by.return_value.first.return_value = mock_execution\n            mock_session.query.return_value.filter.return_value.all.return_value = mock_execution_config \n\n            with patch('superagi.controllers.agent_execution_config.AgentExecution.get_agent_execution_from_id') as mock_get_exec:\n                mock_get_exec.return_value = mock_execution\n                response = client.post(\"/agent_templates/publish_template/agent_execution_id/1\")    \n                assert response.status_code == 201"
  },
  {
    "path": "tests/unit_tests/controllers/test_tool.py",
    "content": "from unittest.mock import patch\n\nimport pytest\nfrom fastapi.testclient import TestClient\n\nfrom main import app\nfrom superagi.models.organisation import Organisation\nfrom superagi.models.tool import Tool\nfrom superagi.models.toolkit import Toolkit\n\nclient = TestClient(app)\n\n\n@pytest.fixture\ndef mocks():\n    # Mock tool kit data for testing\n    user_organisation = Organisation(id=1)\n    toolkit_1 = Toolkit(\n        id=1,\n        name=\"toolkit_1\",\n        description=\"None\",\n        show_toolkit=None,\n        organisation_id=1\n    )\n    toolkit_2 = Toolkit(\n        id=1,\n        name=\"toolkit_2\",\n        description=\"None\",\n        show_toolkit=None,\n        organisation_id=1\n    )\n    user_toolkits = [toolkit_1, toolkit_2]\n    tool_1 = Tool(\n        id=1,\n        name=\"tool_1\",\n        description=\"Test Tool\",\n        folder_name=\"test folder\",\n        file_name=\"test file\",\n        toolkit_id=1\n    )\n    tool_2 = Tool(\n        id=1,\n        name=\"tool_2\",\n        description=\"Test Tool\",\n        folder_name=\"test folder\",\n        file_name=\"test file\",\n        toolkit_id=1\n    )\n    tool_3 = Tool(\n        id=1,\n        name=\"tool_3\",\n        description=\"Test Tool\",\n        folder_name=\"test folder\",\n        file_name=\"test file\",\n        toolkit_id=2\n    )\n    tools = [tool_1, tool_2, tool_3]\n    return user_organisation, user_toolkits, tools, toolkit_1, toolkit_2, tool_1, tool_2, tool_3\n\n\ndef test_get_tools_success(mocks):\n    # Unpack the fixture data\n    user_organisation, user_toolkits, tools, toolkit_1, toolkit_2, tool_1, tool_2, tool_3 = mocks\n\n    # Mock the database session and query functions\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n            patch('superagi.controllers.tool.db') as mock_db, \\\n            patch('superagi.helper.auth.db') as mock_auth_db:\n\n        # Mock the toolkit filtering\n        mock_db.session.query.return_value.filter.return_value.all.side_effect = [user_toolkits, [tool_1, tool_2],\n                                                                                  [tool_3]]\n\n        # Call the function\n        response = client.get(\"/tools/list\")\n\n        # Assertions\n        assert response.status_code == 200\n        assert response.json() == [{'id': 1, 'name': 'tool_1', 'description': 'Test Tool', 'folder_name': 'test folder',\n                                    'file_name': 'test file', 'toolkit_id': 1},\n                                   {'id': 1, 'name': 'tool_2', 'description': 'Test Tool', 'folder_name': 'test folder',\n                                    'file_name': 'test file', 'toolkit_id': 1},\n                                   {'id': 1, 'name': 'tool_3', 'description': 'Test Tool', 'folder_name': 'test folder',\n                                    'file_name': 'test file', 'toolkit_id': 2}]\n"
  },
  {
    "path": "tests/unit_tests/controllers/test_tool_config.py",
    "content": "from unittest.mock import MagicMock, patch\n\nimport pytest\nfrom fastapi.testclient import TestClient\n\nfrom main import app\nfrom superagi.controllers.tool_config import update_tool_config\nfrom superagi.models.organisation import Organisation\nfrom superagi.models.tool_config import ToolConfig\nfrom superagi.models.toolkit import Toolkit\n\nclient = TestClient(app)\n\n\n@pytest.fixture\ndef mocks():\n    # Mock tool kit data for testing\n    user_organisation = Organisation(id=1)\n    toolkit_1 = Toolkit(\n        id=1,\n        name=\"toolkit_1\",\n        description=\"None\",\n        show_toolkit=None,\n        organisation_id=1\n    )\n    toolkit_2 = Toolkit(\n        id=1,\n        name=\"toolkit_2\",\n        description=\"None\",\n        show_toolkit=None,\n        organisation_id=1\n    )\n    user_toolkits = [toolkit_1, toolkit_2]\n    tool_config = ToolConfig(\n        id=1,\n        key=\"test_key\",\n        value=\"test_value\",\n        toolkit_id=1\n    )\n    return user_organisation, user_toolkits, tool_config, toolkit_1, toolkit_2\n\n\n# Test cases\ndef test_update_tool_configs_success():\n    # Test data\n    toolkit_name = \"toolkit_1\"\n    configs = [\n        {\"key\": \"config_1\", \"value\": \"value_1\"},\n        {\"key\": \"config_2\", \"value\": \"value_2\"},\n    ]\n\n    with patch('superagi.models.toolkit.Toolkit.get_toolkit_from_name') as get_toolkit_from_name, \\\n            patch('superagi.controllers.tool_config.db') as mock_db:\n        mock_db.query.return_value.filter_by.return_value.first.side_effect = [\n            # First call to query\n            MagicMock(\n                toolkit_id=1, key=\"config_1\", value=\"old_value_1\"\n            ),\n            # Second call to query\n            MagicMock(\n                toolkit_id=1, key=\"config_2\", value=\"old_value_2\"\n            ),\n        ]\n\n        result = update_tool_config(toolkit_name, configs)\n\n        assert result == {\"message\": \"Tool configs updated successfully\"}\n\n\ndef test_get_all_tool_configs_success(mocks):\n    user_organisation, user_toolkits, tool_config, toolkit_1, toolkit_2 = mocks\n\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n            patch('superagi.controllers.tool_config.db') as mock_db, \\\n            patch('superagi.helper.auth.db') as mock_auth_db:\n        mock_db.session.query.return_value.filter_by.return_value.first.return_value = toolkit_1\n        mock_db.session.query.return_value.filter.return_value.all.side_effect = [\n            [tool_config]\n        ]\n        response = client.get(f\"/tool_configs/get/toolkit/test_toolkit_1\")\n\n        # Assertions\n        assert response.status_code == 200\n        assert response.json() == [\n            {\n                'id': 1,\n                'key': tool_config.key,\n                'value': tool_config.value,\n                'toolkit_id': tool_config.toolkit_id\n            }\n        ]\n\n\ndef test_get_all_tool_configs_toolkit_not_found(mocks):\n    user_organisation, _, _, _, _ = mocks\n\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n            patch('superagi.controllers.tool_config.db') as mock_db, \\\n            patch('superagi.helper.auth.db') as mock_auth_db:\n        mock_db.session.query.return_value.filter.return_value.first.return_value = None\n        response = client.get(f\"/tool_configs/get/toolkit/nonexistent_toolkit\")\n\n        # Assertions\n        assert response.status_code == 404\n        assert response.json() == {'detail': 'ToolKit not found'}\n\ndef test_get_tool_config_success(mocks):\n    # Unpack the fixture data\n    user_organisation, user_toolkits, tool_config, toolkit_1, toolkit_2 = mocks\n\n    # Mock the database session and query functions\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n            patch('superagi.controllers.tool_config.db') as mock_db, \\\n            patch('superagi.helper.auth.db') as mock_auth_db:\n        mock_db.session.query.return_value.filter.return_value.all.return_value = user_toolkits\n        mock_db.session.query.return_value.filter_by.return_value = toolkit_1\n        mock_db.session.query.return_value.filter.return_value.first.return_value = tool_config\n\n        # Call the function\n        response = client.get(f\"/tool_configs/get/toolkit/{toolkit_1.name}/key/{tool_config.key}\")\n\n        # Assertions\n        assert response.status_code == 200\n        assert response.json() == {\n            \"id\": tool_config.id,\n            \"key\": tool_config.key,\n            \"value\": tool_config.value,\n            \"toolkit_id\": tool_config.toolkit_id\n        }\n\n\ndef test_get_tool_config_unauthorized(mocks):\n    # Unpack the fixture data\n    user_organisation, user_toolkits, tool_config, toolkit_1, toolkit_2 = mocks\n\n    # Mock the database session and query functions\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n            patch('superagi.controllers.tool_config.db') as mock_db, \\\n            patch('superagi.helper.auth.db') as mock_auth_db:\n        # Mock the toolkit filtering\n        mock_db.session.query.return_value.filter.return_value.all.return_value = user_toolkits\n\n        response = client.get(f\"/tool_configs/get/toolkit/{toolkit_2.name}/key/{tool_config.key}\")\n\n        # Assertions\n        assert response.status_code == 403\n        assert response.json() == {\"detail\": \"Unauthorized\"}\n\n\ndef test_get_tool_config_not_found(mocks):\n    # Unpack the fixture data\n    user_organisation, user_toolkits, tool_config, toolkit_1, toolkit_2 = mocks\n\n    # Mock the database session and query functions\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n            patch('superagi.controllers.tool_config.db') as mock_db, \\\n            patch('superagi.helper.auth.db') as mock_auth_db:\n        # Mock the toolkit filtering\n        mock_db.session.query.return_value.filter.return_value.all.return_value = user_toolkits\n        mock_db.session.query.return_value.filter_by.return_value = toolkit_1\n        mock_db.session.query.return_value.filter.return_value.first.return_value = None\n\n        # Call the function with a non-existent toolkit\n        response = client.get(f\"/tool_configs/get/toolkit/{toolkit_1.name}/key/{tool_config.key}\")\n\n        # Assertions\n        assert response.status_code == 404\n        assert response.json() == {\"detail\": \"Tool configuration not found\"}\n"
  },
  {
    "path": "tests/unit_tests/controllers/test_toolkit.py",
    "content": "from unittest.mock import patch, call\n\nimport pytest\nfrom fastapi.testclient import TestClient\n\nfrom main import app\nfrom superagi.models.organisation import Organisation\nfrom superagi.models.tool import Tool\nfrom superagi.models.tool_config import ToolConfig\nfrom superagi.types.key_type import ToolConfigKeyType\nfrom superagi.models.toolkit import Toolkit\n\nclient = TestClient(app)\n\n\n@pytest.fixture\ndef mocks():\n    # Mock tool kit data for testing\n    user_organisation = Organisation(id=1)\n    toolkit_1 = Toolkit(\n        id=1,\n        name=\"toolkit_1\",\n        description=\"None\",\n        show_toolkit=None,\n        organisation_id=1\n    )\n    toolkit_2 = Toolkit(\n        id=1,\n        name=\"toolkit_2\",\n        description=\"None\",\n        show_toolkit=None,\n        organisation_id=1\n    )\n    user_toolkits = [toolkit_1, toolkit_2]\n    tool_1 = Tool(\n        id=1,\n        name=\"tool_1\",\n        description=\"Test Tool\",\n        folder_name=\"test folder\",\n        file_name=\"test file\",\n        toolkit_id=1\n    )\n    tool_2 = Tool(\n        id=1,\n        name=\"tool_2\",\n        description=\"Test Tool\",\n        folder_name=\"test folder\",\n        file_name=\"test file\",\n        toolkit_id=1\n    )\n    tool_3 = Tool(\n        id=1,\n        name=\"tool_3\",\n        description=\"Test Tool\",\n        folder_name=\"test folder\",\n        file_name=\"test file\",\n        toolkit_id=2\n    )\n    tools = [tool_1, tool_2, tool_3]\n    return user_organisation, user_toolkits, tools, toolkit_1, toolkit_2, tool_1, tool_2, tool_3\n\n\n@pytest.fixture\ndef mock_toolkit_details():\n    # Mock toolkit details data for testing\n    toolkit_details = {\n        \"name\": \"toolkit_1\",\n        \"description\": \"Test Toolkit\",\n        \"tool_code_link\": \"https://example.com/toolkit_1\",\n        \"show_toolkit\": None,\n        \"tools\": [\n            {\n                \"name\": \"tool_1\",\n                \"description\": \"Test Tool 1\",\n                \"folder_name\": \"test_folder_1\",\n                \"class_name\": \"TestTool1\",\n                \"file_name\": \"test_tool_1.py\"\n            },\n            {\n                \"name\": \"tool_2\",\n                \"description\": \"Test Tool 2\",\n                \"folder_name\": \"test_folder_2\",\n                \"class_name\": \"TestTool2\",\n                \"file_name\": \"test_tool_2.py\"\n            }\n        ],\n        \"configs\": [\n            {\n                \"key\": \"config_key_1\",\n                \"value\": \"config_value_1\",\n                'key_type': ToolConfigKeyType.STRING,\n                'is_secret': True,\n                'is_required': False\n            },\n            {\n                \"key\": \"config_key_2\",\n                \"value\": \"config_value_2\",\n                'key_type': ToolConfigKeyType.FILE,\n                'is_secret': True,\n                'is_required': False\n\n            }\n        ]\n    }\n    return toolkit_details\n\n\ndef test_handle_marketplace_operations_list(mocks):\n    # Unpack the fixture data\n    user_organisation, user_toolkits, tools, toolkit_1, toolkit_2, tool_1, tool_2, tool_3 = mocks\n\n    # Mock the database session and query functions\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n            patch('superagi.controllers.toolkit.db') as mock_db, \\\n            patch('superagi.models.toolkit.Toolkit.fetch_marketplace_list') as mock_fetch_marketplace_list, \\\n            patch('superagi.helper.auth.db') as mock_auth_db:\n        # Set up mock data\n        mock_db.session.query.return_value.filter.return_value.all.side_effect = [user_toolkits]\n        mock_fetch_marketplace_list.return_value = [toolkit_1.to_dict(), toolkit_2.to_dict()]\n\n        # Call the function\n        response = client.get(\"/toolkits/get/list\", params={\"page\": 0})\n\n        # Assertions\n        assert response.status_code == 200\n        assert response.json() == [\n            {\n                \"id\": 1,\n                \"name\": \"toolkit_1\",\n                \"description\": \"None\",\n                \"show_toolkit\": None,\n                \"organisation_id\": 1,\n                \"is_installed\": True\n            },\n            {\n                \"id\": 1,\n                \"name\": \"toolkit_2\",\n                \"description\": \"None\",\n                \"show_toolkit\": None,\n                \"organisation_id\": 1,\n                \"is_installed\": True\n            }\n        ]\n\n\ndef test_install_toolkit_from_marketplace(mock_toolkit_details):\n    # Mock the database session and query functions\n    with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \\\n            patch('superagi.models.toolkit.Toolkit.fetch_marketplace_detail') as mock_fetch_marketplace_detail, \\\n            patch('superagi.models.toolkit.Toolkit.add_or_update') as mock_add_or_update, \\\n            patch('superagi.models.tool.Tool.add_or_update') as mock_tool_add_or_update, \\\n            patch('superagi.controllers.toolkit.db') as mock_db, \\\n            patch('superagi.helper.auth.db') as mock_auth_db, \\\n            patch('superagi.models.tool_config.ToolConfig.add_or_update') as mock_tool_config_add_or_update:\n        # Set up mock data and behavior\n        mock_get_user_org.return_value = Organisation(id=1)\n        mock_fetch_marketplace_detail.return_value = mock_toolkit_details\n        mock_add_or_update.return_value = Toolkit(id=1, name=mock_toolkit_details['name'],\n                                                  description=mock_toolkit_details['description'])\n\n        # Call the function\n        response = client.get(\"/toolkits/get/install/toolkit_1\")\n\n        # Assertions\n        assert response.status_code == 200\n        assert response.json() == {\"message\": \"ToolKit installed successfully\"}\n\n        # Verify the function calls\n        mock_fetch_marketplace_detail.assert_called_once_with(search_str=\"details\", toolkit_name=\"toolkit_1\")\n"
  },
  {
    "path": "tests/unit_tests/controllers/test_update_agent_config_table.py",
    "content": "import pytest\nfrom unittest.mock import patch, Mock\nfrom superagi.models.agent_config import AgentConfiguration\nfrom superagi.controllers.types.agent_execution_config import AgentRunIn\n\ndef test_update_existing_toolkits():\n    agent_id = 1\n    updated_details = AgentRunIn(\n        agent_workflow=\"test\", constraints=[\"c1\", \"c2\"], toolkits=[1, 2],\n        tools=[1, 2, 3], exit=\"exit\", iteration_interval=1,\n        model=\"test\", permission_type=\"p\", LTM_DB=\"LTM\", max_iterations=100\n    )\n\n    # Mock AgentConfiguration instance for the agent_configs list\n    existing_toolkits_config = Mock(spec=AgentConfiguration)\n    existing_toolkits_config.key = \"toolkits\"\n    existing_toolkits_config.value = [3, 4]\n\n    agent_configs = [existing_toolkits_config]\n\n    mock_session = Mock()\n\n    # Mock the query filter behavior for existing configurations\n    mock_session.query().filter().all.return_value = agent_configs\n\n    result = AgentConfiguration.update_agent_configurations_table(mock_session, agent_id, updated_details)\n\n    #Check whether the value gets updated or not\n    assert existing_toolkits_config.value == '[1, 2]'\n    assert mock_session.commit.called_once()\n    assert result == \"Details updated successfully\"\n"
  },
  {
    "path": "tests/unit_tests/controllers/test_user.py",
    "content": "from unittest.mock import patch\n\nimport pytest\nfrom fastapi.testclient import TestClient\n\nfrom main import app\nfrom superagi.models.user import User\n\nclient = TestClient(app)\n\n# Define a fixture for an authenticated user\n@pytest.fixture\ndef authenticated_user():\n    # Create a mock user object with necessary attributes\n    user = User()\n\n    # Set user attributes\n    user.id = 1  # User ID\n    user.username = \"testuser\"  # User's username\n    user.email = \"super6@agi.com\"  # User's email\n    user.first_login_source = None  # User's first login source\n    user.token = \"mock-jwt-token\"\n\n    return user\n\n# Test case for updating first login source when it's not set\ndef test_update_first_login_source(authenticated_user):\n    with patch('superagi.helper.auth.db') as mock_auth_db:\n        source = \"github\"  # Specify the source you want to set\n\n        mock_auth_db.session.query.return_value.filter.return_value.first.return_value = authenticated_user\n        response = client.post(f\"users/first_login_source/{source}\", headers={\"Authorization\": f\"Bearer {authenticated_user.token}\"})\n\n        # Verify the HTTP response\n        assert response.status_code == 200\n        assert \"first_login_source\" in response.json()  # Check if the \"first_login_source\" field is in the response\n        assert response.json()[\"first_login_source\"] == \"github\"  # Check if the \"source\" field equals \"github\""
  },
  {
    "path": "tests/unit_tests/helper/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/helper/test_agent_schedule_helper.py",
    "content": "import pytest\nfrom unittest.mock import patch, MagicMock, call\nfrom superagi.helper.agent_schedule_helper import AgentScheduleHelper\nfrom superagi.models.agent_schedule import AgentSchedule\nfrom datetime import datetime, timedelta\n\n@patch('superagi.helper.agent_schedule_helper.parse_interval_to_seconds')\n@patch('superagi.models.agent_schedule.AgentSchedule')\n@patch('superagi.helper.agent_schedule_helper.Session')\n@patch('superagi.helper.agent_schedule_helper.datetime')\ndef test_update_next_scheduled_time(mock_datetime, mock_session, mock_agent_schedule, mock_parse_interval_to_seconds):\n    \n    mock_datetime.now.return_value = datetime(2022, 1, 1, 10, 0)\n\n    # Mock agent object\n    mock_agent = MagicMock()\n    mock_agent.start_time = datetime(2022, 1, 1, 1, 0)\n    mock_agent.next_scheduled_time = datetime(2022, 1, 1, 1, 0)\n    mock_agent.recurrence_interval = '5 Minutes'\n    mock_agent.status = 'SCHEDULED'\n\n    mock_agent_schedule.return_value = mock_agent\n\n    # Mock the return value of the session query\n    mock_session.return_value.query.return_value.filter.return_value.all.return_value = [mock_agent]\n    mock_parse_interval_to_seconds.return_value = 300\n\n    # Call the method\n    helperObj = AgentScheduleHelper()\n    helperObj.update_next_scheduled_time()\n\n    # Assert that the mocks were called as expected\n    mock_session.assert_called_once()\n    mock_session.return_value.query.assert_called_once()\n    mock_session.return_value.query.return_value.filter.assert_called()\n    mock_session.return_value.query.return_value.filter.return_value.all.assert_called_once()\n    mock_parse_interval_to_seconds.assert_called_once_with('5 Minutes')\n    assert mock_agent.status == 'SCHEDULED'\n\n\n@patch('superagi.helper.agent_schedule_helper.AgentScheduleHelper._AgentScheduleHelper__create_execution_name_for_scheduling')\n@patch('superagi.helper.agent_schedule_helper.AgentScheduleHelper._AgentScheduleHelper__should_execute_agent')\n@patch('superagi.helper.agent_schedule_helper.AgentScheduleHelper._AgentScheduleHelper__can_remove_agent')\n@patch('superagi.helper.agent_schedule_helper.AgentScheduleHelper._AgentScheduleHelper__execute_schedule')\n@patch('superagi.helper.agent_schedule_helper.parse_interval_to_seconds')\n@patch('superagi.helper.agent_schedule_helper.AgentSchedule')\n@patch('superagi.helper.agent_schedule_helper.Session')\n@patch('superagi.helper.agent_schedule_helper.datetime')\ndef test_run_scheduled_agents(\n    mock_datetime, \n    mock_session, \n    mock_agent_schedule, \n    mock_parse_interval_to_seconds, \n    mock_execute_schedule, \n    mock_can_remove_agent, \n    mock_should_execute_agent, \n    mock_create_execution_name_for_scheduling\n):\n\n    # Mocking current datetime\n    mock_datetime.now.return_value = datetime(2022, 1, 1, 10, 0)\n\n    # Mocking agent object\n    mock_agent = MagicMock(spec=AgentSchedule)\n    mock_agent.next_scheduled_time = datetime(2022, 1, 1, 9, 55)\n    mock_agent.status = 'SCHEDULED'\n    mock_agent.recurrence_interval = '5 Minutes'\n    mock_agent.agent_id = 'agent_1'\n\n    # Mocking the return value of the session query\n    mock_session.return_value.query.return_value.filter.return_value.all.return_value = [mock_agent]\n    mock_parse_interval_to_seconds.return_value = 300\n    \n    mock_should_execute_agent.return_value = True\n    mock_can_remove_agent.return_value = False\n    mock_create_execution_name_for_scheduling.return_value = 'Run 01 January 2022 10:00'\n\n    # Call the method\n    helper = AgentScheduleHelper()\n    helper.run_scheduled_agents()\n\n    # Assert that the mocks were called as expected\n    mock_session.assert_called_once_with()\n    mock_session.return_value.query.assert_called_once_with(mock_agent_schedule)\n    mock_session.return_value.query.return_value.filter.assert_called_once()\n    mock_session.return_value.query.return_value.filter.return_value.all.assert_called_once()\n    \n    mock_parse_interval_to_seconds.assert_has_calls([call('5 Minutes')])\n\n    mock_should_execute_agent.assert_called_once_with(mock_agent, mock_agent.recurrence_interval)\n    mock_can_remove_agent.assert_called_once_with(mock_agent, mock_agent.recurrence_interval)\n    \n    mock_execute_schedule.assert_has_calls([call(\n        mock_should_execute_agent.return_value, \n        mock_parse_interval_to_seconds.return_value, \n        mock_session(), \n        mock_agent, \n        mock_create_execution_name_for_scheduling.return_value\n    )])\n    \n    mock_create_execution_name_for_scheduling.assert_called_once_with(mock_agent.agent_id)\n"
  },
  {
    "path": "tests/unit_tests/helper/test_calendar_date.py",
    "content": "import unittest\nfrom unittest.mock import MagicMock\nfrom datetime import datetime, timezone\nimport pytz\n\nfrom superagi.helper.calendar_date import CalendarDate\n\n\nclass TestCalendarDate(unittest.TestCase):\n    def setUp(self):\n        self.cd = CalendarDate()\n        self.service = MagicMock()\n        self.service.calendars().get().execute.return_value = {'timeZone': 'Asia/Kolkata'}\n\n    def test_get_time_zone(self):\n        time_zone = self.cd._get_time_zone(self.service)\n        self.assertEqual(time_zone, 'Asia/Kolkata')\n\n    def test_convert_to_utc(self):\n        # Create a datetime object for midnight of January 1st, 2023.\n        local_datetime = datetime(2023, 1, 1)\n\n        # Use the 'US/Pacific' timezone for this example.\n        local_tz = pytz.timezone('US/Pacific')\n\n        # Call the function to convert the local datetime to UTC.\n        utc_datetime = self.cd._convert_to_utc(local_datetime, local_tz)\n\n        # Check that the converted datetime is correct.\n        # Note: The 'US/Pacific' timezone is 8 hours behind UTC during standard time.\n        expected_utc_datetime = datetime(2023, 1, 1, 8, 0)\n        expected_utc_datetime = pytz.timezone('GMT').localize(expected_utc_datetime)\n        assert utc_datetime == expected_utc_datetime\n\n    def test_string_to_datetime(self):\n        date_str = '2022-01-01'\n        date_format = '%Y-%m-%d'\n        date_obj = datetime.strptime(date_str, date_format)\n        self.assertEqual(date_obj, self.cd._string_to_datetime(date_str, date_format))\n\n    def test_localize_daterange(self):\n        start_date, end_date = '2022-01-01', '2022-01-02'\n        start_time, end_time = '10:00:00', '12:00:00'\n        local_tz = pytz.timezone('Asia/Kolkata')\n        start_datetime_utc, end_datetime_utc = self.cd._localize_daterange(start_date, end_date, start_time, end_time,\n                                                                           local_tz)\n\n        self.assertEqual(start_datetime_utc, datetime(2022, 1, 1, 4, 30, tzinfo=timezone.utc))\n        self.assertEqual(end_datetime_utc, datetime(2022, 1, 2, 6, 30, tzinfo=timezone.utc))\n\n    def test_datetime_to_string(self):\n        date_time = datetime(2022, 1, 1, 0, 0, 0)\n        date_format = '%Y-%m-%d'\n        date_str = '2022-01-01'\n        self.assertEqual(date_str, self.cd._datetime_to_string(date_time, date_format))\n\n    def test_get_date_utc(self):\n        start_date, end_date = '2022-01-01', '2022-01-02'\n        start_time, end_time = '10:00:00', '12:00:00'\n        date_utc = {\n            \"start_datetime_utc\": \"2022-01-01T04:30:00.000000Z\",\n            \"end_datetime_utc\": \"2022-01-02T06:30:00.000000Z\"\n        }\n        result = self.cd.get_date_utc(start_date, end_date, start_time, end_time, self.service)\n        self.assertEqual(date_utc, result)\n\n    def test_create_event_dates(self):\n        start_date, end_date = '2022-01-01', '2022-01-02'\n        start_time, end_time = '10:00:00', '12:00:00'\n        date_utc = {\n            \"start_datetime_utc\": \"2022-01-01T04:30:00.000000Z\",\n            \"end_datetime_utc\": \"2022-01-02T06:30:00.000000Z\",\n            \"timeZone\": \"Asia/Kolkata\"\n        }\n        result = self.cd.create_event_dates(self.service, start_date, start_time, end_date, end_time)\n        self.assertEqual(date_utc, result)\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "tests/unit_tests/helper/test_error_handling.py",
    "content": "import pytest\nfrom unittest.mock import Mock, patch\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nfrom superagi.helper.error_handler import ErrorHandler\n\ndef test_handle_error():\n    session = Mock()\n    agent_id = 1\n    agent_execution_id = 2\n    error_message = 'Test error'\n    \n    mock_query = Mock()\n    mock_query.filter().first.return_value = AgentExecution(id=agent_execution_id)\n    session.query.return_value = mock_query\n\n    ErrorHandler.handle_openai_errors(session, agent_id, agent_execution_id, error_message)\n\n    session.query.assert_called_once_with(AgentExecution)\n"
  },
  {
    "path": "tests/unit_tests/helper/test_feed_parser.py",
    "content": "import unittest\nfrom datetime import datetime\nfrom superagi.helper.feed_parser import parse_feed\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\nclass TestParseFeed(unittest.TestCase):\n    def test_parse_feed_system(self):\n        current_time = datetime.now()\n        sample_feed = AgentExecutionFeed(\n            id=2, agent_execution_id=100, agent_id=200, role=\"user\",\n            feed='System message', updated_at=current_time\n        )\n\n        result = parse_feed(sample_feed)\n        \n        self.assertEqual(result['feed'], sample_feed.feed, \"Incorrect output from parse_feed function for system role\")\n        self.assertEqual(result['role'], sample_feed.role, \"Incorrect output from parse_feed function for system role\")"
  },
  {
    "path": "tests/unit_tests/helper/test_github_helper.py",
    "content": "import base64\nimport unittest\nfrom unittest.mock import patch, MagicMock\n\nfrom superagi.helper.github_helper import GithubHelper\n\nclass TestGithubHelper(unittest.TestCase):\n    @patch('requests.get')\n    def test_check_repository_visibility(self, mock_get):\n        # Create response mock\n        mock_resp = MagicMock()\n        mock_resp.status_code = 200\n        mock_resp.json.return_value = {'private': False}\n        mock_get.return_value = mock_resp\n\n        gh = GithubHelper('access_token', 'username')\n        visibility = gh.check_repository_visibility('owner', 'repo')\n\n        self.assertEqual(visibility, False)\n        mock_get.assert_called_once_with(\n            \"https://api.github.com/repos/owner/repo\",\n            headers={\"Authorization\": \"Token access_token\", \"Accept\": \"application/vnd.github.v3+json\"}\n        )\n\n    @patch('requests.get')\n    def test_get_file_path(self, mock_get):\n        gh = GithubHelper('access_token', 'username')\n        path = gh.get_file_path('test.txt', 'dir')\n        self.assertEqual(path, 'dir/test.txt')\n\n\n    @patch('requests.get')\n    def test_search_repo(self, mock_get):\n        # Create response mock\n        mock_resp = MagicMock()\n        mock_resp.raise_for_status.return_value = None\n        mock_resp.json.return_value = 'data'\n        mock_get.return_value = mock_resp\n\n        gh = GithubHelper('access_token', 'username')\n        data = gh.search_repo('owner', 'repo', 'test.txt', '')\n\n        self.assertEqual(data, 'data')\n        mock_get.assert_called_once_with(\n            'https://api.github.com/repos/owner/repo/contents/test.txt',\n            headers={\"Authorization\": \"token access_token\", \"Content-Type\": \"application/vnd.github+json\"}\n        )\n\n    @patch('requests.get')\n    @patch('requests.patch')\n    def test_sync_branch(self, mock_patch, mock_get):\n        # Create response mocks\n        mock_get_resp = MagicMock()\n        mock_get_resp.json.return_value = {'commit': {'sha': 'sha'}}\n        mock_get.return_value = mock_get_resp\n        mock_patch_resp = MagicMock()\n        mock_patch_resp.status_code = 200\n        mock_patch.return_value = mock_patch_resp\n\n        gh = GithubHelper('access_token', 'username')\n        gh.sync_branch('owner', 'repo', 'base', 'head', {'header': 'value'})\n\n        mock_get.assert_called_once_with(\n            'https://api.github.com/repos/owner/repo/branches/base',\n            headers={'header': 'value'}\n        )\n        mock_patch.assert_called_once_with(\n            'https://api.github.com/repos/username/repo/git/refs/heads/head',\n            json={'sha': 'sha', 'force': True},\n            headers={'header': 'value'}\n        )\n\n    @patch('requests.get')\n    @patch('requests.post')\n    def test_create_branch(self, mock_post, mock_get):\n        # Create response mocks\n        mock_get_resp = MagicMock()\n        mock_get_resp.json.return_value = {'object': {'sha': 'sha'}}\n        mock_get.return_value = mock_get_resp\n        mock_post_resp = MagicMock()\n        mock_post_resp.status_code = 201\n        mock_post.return_value = mock_post_resp\n\n        gh = GithubHelper('access_token', 'username')\n        status_code = gh.create_branch('repo', 'base', 'head', {'header': 'value'})\n\n        self.assertEqual(status_code, 201)\n        mock_get.assert_called_once_with(\n            'https://api.github.com/repos/username/repo/git/refs/heads/base',\n            headers={'header': 'value'}\n        )\n        mock_post.assert_called_once_with(\n            'https://api.github.com/repos/username/repo/git/refs',\n            json={'ref': 'refs/heads/head', 'sha': 'sha'},\n            headers={'header': 'value'}\n        )\n\n    @patch('requests.post')\n    def test_make_fork(self, mock_post):\n        # Create response mock\n        mock_resp = MagicMock()\n        mock_resp.status_code = 202\n        mock_post.return_value = mock_resp\n\n        gh = GithubHelper('access_token', 'username')\n        with patch.object(GithubHelper, 'sync_branch') as mock_sync:\n            status_code = gh.make_fork('owner', 'repo', 'base', {'header': 'value'})\n\n        self.assertEqual(status_code, 202)\n        mock_post.assert_called_once_with(\n            'https://api.github.com/repos/owner/repo/forks',\n            headers={'header': 'value'}\n        )\n        mock_sync.assert_called_once_with('owner', 'repo', 'base', 'base', {'header': 'value'})\n\n    @patch('requests.delete')\n    def test_delete_file(self, mock_delete):\n        # Create response mock\n        mock_resp = MagicMock()\n        mock_resp.status_code = 200\n        mock_delete.return_value = mock_resp\n\n        gh = GithubHelper('access_token', 'username')\n        with patch.object(GithubHelper, 'get_sha', return_value='sha') as mock_sha:\n            status_code = gh.delete_file('repo', 'test.txt', 'path', 'message', 'head', {'header': 'value'})\n\n        self.assertEqual(status_code, 200)\n        mock_sha.assert_called_once_with('username', 'repo', 'test.txt', 'path')\n        mock_delete.assert_called_once_with(\n            'https://api.github.com/repos/username/repo/contents/path/test.txt',\n            json={'message': 'message', 'sha': 'sha', 'branch': 'head'},\n            headers={'header': 'value'}\n        )\n\n    @patch('requests.post')\n    def test_create_pull_request(self, mock_post):\n        # Create response mock\n        mock_resp = MagicMock()\n        mock_resp.status_code = 201\n        mock_post.return_value = mock_resp\n\n        gh = GithubHelper('access_token', 'username')\n        status_code = gh.create_pull_request('owner', 'repo', 'head', 'base', {'header': 'value'})\n\n        self.assertEqual(status_code, 201)\n        mock_post.assert_called_once_with(\n            'https://api.github.com/repos/owner/repo/pulls',\n            json={\n                'title': 'Pull request by username',\n                'body': 'Please review and merge this change.',\n                'head': 'username:head',\n                'head_repo': 'repo',\n                'base': 'base'\n            },\n            headers={'header': 'value'}\n        )\n\n    @patch('requests.get')\n    def test_get_pull_request_content_success(self, mock_get):\n        mock_get.return_value.status_code = 200\n        mock_get.return_value.text = \"some_content\"\n\n        github_api = GithubHelper('access_token', 'username')\n        result = github_api.get_pull_request_content(\"owner\", \"repo\", 1)\n\n        self.assertEqual(result, \"some_content\")\n\n    @patch('requests.get')\n    def test_get_pull_request_content_not_found(self, mock_get):\n        mock_get.return_value.status_code = 404\n\n        github_api = GithubHelper('access_token', 'username')\n        result = github_api.get_pull_request_content(\"owner\", \"repo\", 1)\n\n        self.assertIsNone(result)\n\n    @patch('requests.get')\n    def test_get_latest_commit_id_of_pull_request(self, mock_get):\n        mock_get.return_value.status_code = 200\n        mock_get.return_value.json.return_value = [{\"sha\": \"123\"}, {\"sha\": \"456\"}]\n\n        github_api = GithubHelper('access_token', 'username')\n        result = github_api.get_latest_commit_id_of_pull_request(\"owner\", \"repo\", 1)\n\n        self.assertEqual(result, \"456\")\n\n    @patch('requests.post')\n    def test_add_line_comment_to_pull_request(self, mock_post):\n        mock_post.return_value.status_code = 201\n        mock_post.return_value.json.return_value = {\"id\": 1, \"body\": \"comment\"}\n\n        github_api = GithubHelper('access_token', 'username')\n        result = github_api.add_line_comment_to_pull_request(\"owner\", \"repo\", 1, \"commit_id\", \"file_path\", 1, \"comment\")\n\n        self.assertEqual(result, {\"id\": 1, \"body\": \"comment\"})\n\n\n# ... more tests for other methods\n\nif __name__ == '__main__':\n    unittest.main()"
  },
  {
    "path": "tests/unit_tests/helper/test_json_cleaner.py",
    "content": "from superagi.helper.json_cleaner import JsonCleaner\nimport pytest\n\ndef test_extract_json_section():\n    test_str = 'Before json {\"key\":\"value\"} after json'\n    result = JsonCleaner.extract_json_section(test_str)\n    assert result == '{\"key\":\"value\"}'\n\ndef test_remove_escape_sequences():\n    test_str = r'This is a test\\nstring'\n    result = JsonCleaner.remove_escape_sequences(test_str)\n    assert result == 'This is a test\\nstring'\n\ndef test_balance_braces():\n    test_str = '{{{{\"key\":\"value\"}}'\n    result = JsonCleaner.balance_braces(test_str)\n    assert result == '{{{{\"key\":\"value\"}}}}'\n\n\ndef test_balance_braces():\n    test_str = '{\"key\": false}'\n    result = JsonCleaner.clean_boolean(test_str)\n    assert result == '{\"key\": False}'\n\n"
  },
  {
    "path": "tests/unit_tests/helper/test_resource_helper.py",
    "content": "from unittest.mock import patch, MagicMock\n\nfrom superagi.helper.resource_helper import ResourceHelper\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.resource import Resource\n\n\ndef test_make_written_file_resource(mocker):\n    mocker.patch('os.getcwd', return_value='/')\n    mocker.patch('os.makedirs', return_value=None)\n    mocker.patch('os.path.getsize', return_value=1000)\n    mocker.patch('os.path.splitext', return_value=(\"\", \".txt\"))\n    mocker.patch('superagi.helper.resource_helper.get_config', side_effect=['FILE', '/', '/', 'FILE'])\n    mock_agent = Agent(id=1, name='TestAgent')\n    mock_agent_execution = AgentExecution(id=1, name='TestExecution')\n    session = MagicMock()\n\n    with patch('superagi.helper.resource_helper.logger') as logger_mock:\n        session.query.return_value.filter_by.return_value.first.return_value = None\n        # Create a Resource object\n        resource = Resource(\n            name='test.txt',\n            path='/test.txt',\n            storage_type='FILE',\n            size=1000,\n            type='application/txt',\n            channel='OUTPUT',\n            agent_id=1,\n            agent_execution_id=1\n        )\n\n        # Mock the session.add() method to return the created Resource object\n        session.add.return_value = resource\n        result = ResourceHelper.make_written_file_resource('test.txt', mock_agent, mock_agent_execution, session)\n\n    assert result.name == 'test.txt'\n    assert result.path == '/test.txt'\n    assert result.storage_type == 'FILE'\n    assert result.size == 1000\n    assert result.type == 'application/txt'\n    assert result.channel == 'OUTPUT'\n    assert result.agent_id == 1\n\n\ndef test_get_resource_path(mocker):\n    mocker.patch('os.getcwd', return_value='/')\n    mocker.patch('superagi.helper.resource_helper.get_config', side_effect=['/'])\n\n    result = ResourceHelper.get_resource_path('test.txt')\n\n    assert result == '/test.txt'\n\n\ndef test_get_agent_resource_path(mocker):\n    mocker.patch('os.getcwd', return_value='/')\n    mocker.patch('os.makedirs')\n    mocker.patch('superagi.helper.resource_helper.get_config', side_effect=['/'])\n    mock_agent = Agent(id=1, name='TestAgent')\n    mock_agent_execution = AgentExecution(id=1, name='TestExecution')\n    result = ResourceHelper.get_agent_write_resource_path('test.txt', mock_agent, mock_agent_execution)\n\n    assert result == '/test.txt'\n\n\ndef test_get_formatted_agent_level_path():\n    agent = Agent(id=1, name=\"TestAgent\")\n    path = \"/data/{agent_id}/file.txt\"\n    formatted_path = ResourceHelper.get_formatted_agent_level_path(agent, path)\n    expected_path = \"/data/TestAgent_1/file.txt\"\n    assert formatted_path == expected_path\n\n\ndef test_get_formatted_agent_execution_level_path():\n    agent_execution = AgentExecution(id=1, name=\"TestExecution\")\n    path = \"/results/{agent_execution_id}/output.csv\"\n    formatted_path = ResourceHelper.get_formatted_agent_execution_level_path(agent_execution, path)\n    expected_path = \"/results/TestExecution_1/output.csv\"\n    assert formatted_path == expected_path\n"
  },
  {
    "path": "tests/unit_tests/helper/test_s3_helper.py",
    "content": "import json\nimport pytest\nfrom unittest.mock import MagicMock, patch\nfrom botocore.exceptions import NoCredentialsError\nfrom fastapi import HTTPException\nfrom superagi.helper.s3_helper import S3Helper\n\n@pytest.fixture()\ndef s3helper_object():\n    return S3Helper()\n\ndef test__get_s3_client(s3helper_object):\n    with patch('superagi.helper.s3_helper.get_config', return_value='test') as mock_get_config:\n        s3_client = s3helper_object._S3Helper__get_s3_client()\n        mock_get_config.assert_any_call('AWS_ACCESS_KEY_ID')\n        mock_get_config.assert_any_call('AWS_SECRET_ACCESS_KEY')\n\n@pytest.mark.parametrize('have_creds, raises', [(True, False), (False, True)])\ndef test_upload_file(s3helper_object, have_creds, raises):\n    s3helper_object.s3.upload_fileobj = MagicMock()\n    s3helper_object.s3.upload_fileobj.side_effect = NoCredentialsError() if not have_creds else None\n\n    if raises:\n        with pytest.raises(HTTPException):\n            s3helper_object.upload_file('file', 'path')\n    else:\n        s3helper_object.upload_file('file', 'path')\n\n@pytest.mark.parametrize('have_creds, raises', [(True, False), (False, True)])\ndef test_get_json_file(s3helper_object, have_creds, raises):\n    \n    # Mock 'get_object' method from s3 client\n    s3helper_object.s3.get_object = MagicMock() \n\n    # Mocked JSON contents with their 'Body' key as per real response\n    mock_json_file = { 'Body': MagicMock() }\n    mock_json_file['Body'].read = MagicMock(return_value=bytes(json.dumps(\"content_of_json\"), 'utf-8'))\n\n    # Case when we do have credentials but 'get_object' raises an error\n    if not raises:\n        s3helper_object.s3.get_object.return_value = mock_json_file\n    else:\n        s3helper_object.s3.get_object.side_effect = NoCredentialsError() \n\n    # Mocking a path to the file\n    mock_path = \"mock_path\"\n\n    if raises:\n        with pytest.raises(HTTPException):\n            s3helper_object.get_json_file(mock_path)\n    else:\n        content = s3helper_object.get_json_file(mock_path)\n\n        # Assert that 'get_object' was called with our mocked path\n        s3helper_object.s3.get_object.assert_called_with(Bucket=s3helper_object.bucket_name, Key=mock_path) \n\n        assert content == \"content_of_json\"  # Assert we got our mocked JSON content back\n\ndef test_check_file_exists_in_s3(s3helper_object):\n    s3helper_object.s3.list_objects_v2 = MagicMock(return_value={})\n    assert s3helper_object.check_file_exists_in_s3('path') == False\n\n    s3helper_object.s3.list_objects_v2 = MagicMock(return_value={'Contents':[]})\n    assert s3helper_object.check_file_exists_in_s3('path') == True\n\n@pytest.mark.parametrize('http_status, expected_result, raises', [(200, 'file_content', False), (500, None, True)])\ndef test_read_from_s3(s3helper_object, http_status, expected_result, raises):\n    s3helper_object.s3.get_object = MagicMock(\n        return_value={'ResponseMetadata': {'HTTPStatusCode': http_status},\n                      'Body': MagicMock(read=lambda: bytes(expected_result, 'utf-8'))}\n    )\n\n    if raises:\n        with pytest.raises(Exception):\n            s3helper_object.read_from_s3('path')\n    else:\n        assert s3helper_object.read_from_s3('path') == expected_result\n\n@pytest.mark.parametrize('http_status, expected_result, raises',\n                         [(200, b'file_content', False),\n                          (500, None, True)])\ndef test_read_binary_from_s3(s3helper_object, http_status, expected_result, raises):\n    s3helper_object.s3.get_object = MagicMock(\n        return_value={'ResponseMetadata': {'HTTPStatusCode': http_status},\n                      'Body': MagicMock(read=lambda: (expected_result))}\n    )\n\n    if raises:\n        with pytest.raises(Exception):\n            s3helper_object.read_binary_from_s3('path')\n    else:\n        assert s3helper_object.read_binary_from_s3('path') == expected_result\n\ndef test_delete_file_success(s3helper_object):\n    s3helper_object.s3.delete_object = MagicMock()\n    try:\n        s3helper_object.delete_file('path')\n    except:\n        pytest.fail(\"Unexpected Exception !\")\n\ndef test_delete_file_fail(s3helper_object):\n    s3helper_object.s3.delete_object = MagicMock(side_effect=Exception())\n    with pytest.raises(HTTPException):\n        s3helper_object.delete_file('path')\n\n\ndef test_list_files_from_s3(s3helper_object):\n    s3helper_object.s3.list_objects_v2 = MagicMock(return_value={\n        'Contents': [{'Key': 'path/to/file1.txt'}, {'Key': 'path/to/file2.jpg'}]\n    })\n\n    file_list = s3helper_object.list_files_from_s3('path/to/')\n\n    assert len(file_list) == 2\n    assert 'path/to/file1.txt' in file_list\n    assert 'path/to/file2.jpg' in file_list\n\n\ndef test_list_files_from_s3_no_contents(s3helper_object):\n    s3helper_object.s3.list_objects_v2 = MagicMock(return_value={})\n\n    with pytest.raises(Exception):\n        s3helper_object.list_files_from_s3('path/to/')\n\n\ndef test_list_files_from_s3_raises_exception(s3helper_object):\n    s3helper_object.s3.list_objects_v2 = MagicMock(side_effect=Exception(\"An error occurred\"))\n\n    with pytest.raises(Exception):\n        s3helper_object.list_files_from_s3('path/to/')\n"
  },
  {
    "path": "tests/unit_tests/helper/test_time_helper.py",
    "content": "from superagi.helper.time_helper import get_time_difference, parse_interval_to_seconds\nimport pytest\n\ndef test_get_time_difference():\n    timestamp1 = \"2023-06-26 17:31:08.884322\"\n    timestamp2 = \"2023-06-27 03:57:42.038497\"\n    expected_result = {\n        \"years\": 0,\n        \"months\": 0,\n        \"days\": 0,\n        \"hours\": 10,\n        \"minutes\": 26\n    }\n    assert get_time_difference(timestamp1, timestamp2) == expected_result\n\n\n\ndef test_parse_interval_to_seconds():\n    assert parse_interval_to_seconds(\"2 Minutes\") == 120\n    assert parse_interval_to_seconds(\"3 Hours\") == 10800\n    assert parse_interval_to_seconds(\"1 Days\") == 86400\n    assert parse_interval_to_seconds(\"7 Weeks\") == 4233600\n    assert parse_interval_to_seconds(\"2 Months\") == 5184000\n"
  },
  {
    "path": "tests/unit_tests/helper/test_token_counter.py",
    "content": "import pytest\n\nfrom typing import List\nfrom unittest.mock import MagicMock, patch\nfrom superagi.types.common import BaseMessage\nfrom superagi.helper.token_counter import TokenCounter\nfrom superagi.models.models import Models\n\n\n@pytest.fixture()\ndef setup_model_token_limit():\n    model_token_limit_dict = {\n        \"gpt-3.5-turbo-0301\": 4032,\n        \"gpt-4-0314\": 8092,\n        \"gpt-3.5-turbo\": 4032,\n        \"gpt-4\": 8092,\n        \"gpt-3.5-turbo-16k\": 16184,\n        \"gpt-4-32k\": 32768,\n        \"gpt-4-32k-0314\": 32768\n    }\n    return model_token_limit_dict\n\n\n@patch.object(Models, \"fetch_model_tokens\", autospec=True)\ndef test_token_limit(mock_fetch_model_tokens, setup_model_token_limit):\n    mock_fetch_model_tokens.return_value = setup_model_token_limit\n\n    tc = TokenCounter(MagicMock(), 1)\n\n    for model, expected_tokens in setup_model_token_limit.items():\n        assert tc.token_limit(model) == expected_tokens\n\n    assert tc.token_limit(\"non_existing_model\") == 8092\n\n\ndef test_count_message_tokens():\n    message_list = [{'content': 'Hello, How are you doing ?'}, {'content': 'I am good. How about you ?'}]\n    BaseMessage.list_from_dicts = MagicMock(return_value=message_list)\n\n    expected_token_count = TokenCounter.count_message_tokens(BaseMessage.list_from_dicts(message_list), \"gpt-3.5-turbo-0301\")\n    assert expected_token_count == 26\n\n    expected_token_count = TokenCounter.count_message_tokens(BaseMessage.list_from_dicts(message_list), \"non_existing_model\")\n    assert expected_token_count == 26\n\n\ndef test_count_text_tokens():\n    # You might need to adjust the hardcoded values in the TokenCounter.count_text_tokens function\n    # and update the expected tokens accordingly if the function logic is changed.\n\n    text = \"You are a helpful assistant.\"\n    assert TokenCounter.count_text_tokens(text) == 10\n\n    text = \"What is your name?\"\n    assert TokenCounter.count_text_tokens(text) == 9"
  },
  {
    "path": "tests/unit_tests/helper/test_tool_helper.py",
    "content": "import os\nimport shutil\nimport sys\nfrom pathlib import Path\nfrom unittest.mock import patch, Mock\n\nimport pytest\n\nfrom superagi.helper.tool_helper import (\n    parse_github_url,\n    load_module_from_file,\n    extract_repo_name,\n    get_readme_content_from_code_link, download_tool, handle_tools_import, compare_toolkit, compare_configs,\n    compare_tools\n)\n\n\ndef setup_function():\n    os.makedirs('target_folder', exist_ok=True)\n\n\n# Teardown function to remove the directory\ndef teardown_function():\n    shutil.rmtree('target_folder')\n\n\n@pytest.fixture\ndef mock_requests_get(monkeypatch):\n    class MockResponse:\n        def __init__(self, content, status_code):\n            self.content = content\n            self.status_code = status_code\n            self.text = content.decode() if content is not None else None\n\n    def mock_get(url):\n        if url == 'https://api.github.com/repos/owner/repo/zipball/main':\n            return MockResponse(b'ZIP_CONTENT', 200)\n        elif url == 'https://raw.githubusercontent.com/username/repo/main/README.MD':\n            return MockResponse(b'README_CONTENT', 200)\n        elif url == 'https://raw.githubusercontent.com/username/repo/main/README.md':\n            return MockResponse(b'README_CONTENT', 200)\n        else:\n            return MockResponse(None, 404)\n\n    monkeypatch.setattr('requests.get', mock_get)\n\n\ndef test_parse_github_url():\n    github_url = 'https://github.com/owner/repo'\n    expected_result = 'owner/repo/main'\n    assert parse_github_url(github_url) == expected_result\n\n\ndef test_load_module_from_file(tmp_path):\n    current_dir = os.getcwd()\n    file_path = Path(current_dir) / 'test_module.py'\n\n    # Corrected code with proper indentation\n    file_content = '''\ndef hello():\n    return 'Hello, world!'\n'''\n    file_path.write_text(file_content)\n\n    module = load_module_from_file(file_path)\n    assert module.hello() == 'Hello, world!'\n\n    # Delete the test_module.py file\n    file_path.unlink()\n\n\ndef test_get_readme_content_from_code_link(mock_requests_get):\n    tool_code_link = 'https://github.com/username/repo'\n    expected_result = 'README_CONTENT'\n    assert get_readme_content_from_code_link(tool_code_link) == expected_result\n\n\ndef test_extract_repo_name():\n    repo_link = 'https://github.com/username/repo'\n    expected_result = 'repo'\n    assert extract_repo_name(repo_link) == expected_result\n\n\n@patch('requests.get')\n@patch('zipfile.ZipFile')\ndef test_download_tool(mock_zip, mock_get):\n    mock_response = Mock()\n    mock_response.content = b'file content'\n    mock_get.return_value = mock_response\n\n    # Mock zipfile to return a list of files\n    mock_zip.return_value.__enter__.return_value.namelist.return_value = ['owner-repo/somefile.txt']\n\n    download_tool('https://github.com/owner/repo', 'target_folder')\n\n    # Assert that the function made the correct HTTP request\n    mock_get.assert_called_once_with('https://api.github.com/repos/owner/repo/zipball/main')\n\n    # Assert zipfile was opened correctly\n    mock_zip.assert_called_once_with('target_folder/tool.zip', 'r')\n\n\ndef test_handle_tools_import():\n    with patch('superagi.config.config.get_config') as mock_get_config, \\\n            patch('os.listdir') as mock_listdir, \\\n            patch('superagi.helper.auth.db') as mock_auth_db:\n        mock_get_config.return_value = \"superagi/tools\"\n        mock_listdir.return_value = \"test_tool\"\n        initial_path_length = len(sys.path)\n        handle_tools_import()\n        assert len(sys.path), initial_path_length + 2\n\ndef test_compare_tools():\n    tool1 = {\"name\": \"Tool A\", \"description\": \"This is Tool A\"}\n    tool2 = {\"name\": \"Tool A\", \"description\": \"This is Tool A\"}\n    assert not compare_tools(tool1, tool2)\n\n    tool1 = {\"name\": \"Tool A\", \"description\": \"This is Tool A\"}\n    tool2 = {\"name\": \"Tool B\", \"description\": \"This is Tool A\"}\n    assert compare_tools(tool1, tool2)\n\n    tool1 = {\"name\": \"Tool A\", \"description\": \"This is Tool A\"}\n    tool2 = {\"name\": \"Tool A\", \"description\": \"This is Tool B\"}\n    assert compare_tools(tool1, tool2)\n\ndef test_compare_configs():\n    config1 = {\"key\": \"config_key\"}\n    config2 = {\"key\": \"config_key\"}\n    assert not compare_configs(config1, config2)\n\n    config1 = {\"key\": \"config_key_1\"}\n    config2 = {\"key\": \"config_key_2\"}\n    assert compare_configs(config1, config2)\n\ndef test_compare_toolkit():\n    toolkit1 = {\n        \"description\": \"Toolkit Description\",\n        \"show_toolkit\": True,\n        \"name\": \"Toolkit\",\n        \"tool_code_link\": \"https://example.com/toolkit\",\n        \"tools\": [{\"name\": \"Tool A\", \"description\": \"This is Tool A\"}],\n        \"configs\": [{\"key\": \"config_key\"}]\n    }\n    toolkit2 = {\n        \"description\": \"Toolkit Description\",\n        \"show_toolkit\": True,\n        \"name\": \"Toolkit\",\n        \"tool_code_link\": \"https://example.com/toolkit\",\n        \"tools\": [{\"name\": \"Tool A\", \"description\": \"This is Tool A\"}],\n        \"configs\": [{\"key\": \"config_key\"}]\n    }\n    assert not compare_toolkit(toolkit1, toolkit2)\n\n    toolkit1 = {\n        \"description\": \"Toolkit Description\",\n        \"show_toolkit\": True,\n        \"name\": \"Toolkit\",\n        \"tool_code_link\": \"https://example.com/toolkit\",\n        \"tools\": [{\"name\": \"Tool A\", \"description\": \"This is Tool A\"}],\n        \"configs\": [{\"key\": \"config_key\"}]\n    }\n    toolkit2 = {\n        \"description\": \"Toolkit Description\",\n        \"show_toolkit\": True,\n        \"name\": \"Toolkit\",\n        \"tool_code_link\": \"https://example.com/toolkit\",\n        \"tools\": [{\"name\": \"Tool A\", \"description\": \"This is Tool B\"}],\n        \"configs\": [{\"key\": \"config_key\"}]\n    }\n    assert compare_toolkit(toolkit1, toolkit2)\n\n    toolkit1 = {\n        \"description\": \"Toolkit Description\",\n        \"show_toolkit\": True,\n        \"name\": \"Toolkit\",\n        \"tool_code_link\": \"https://example.com/toolkit\",\n        \"tools\": [{\"name\": \"Tool A\", \"description\": \"This is Tool A\"}],\n        \"configs\": [{\"key\": \"config_key_1\"}]\n    }\n    toolkit2 = {\n        \"description\": \"Toolkit Description\",\n        \"show_toolkit\": True,\n        \"name\": \"Toolkit\",\n        \"tool_code_link\": \"https://example.com/toolkit\",\n        \"tools\": [{\"name\": \"Tool A\", \"description\": \"This is Tool A\"}],\n        \"configs\": [{\"key\": \"config_key_2\"}]\n    }\n    assert compare_toolkit(toolkit1, toolkit2)\n"
  },
  {
    "path": "tests/unit_tests/helper/test_twitter_helper.py",
    "content": "import unittest\nfrom unittest.mock import Mock, patch\nfrom requests.models import Response\nfrom requests_oauthlib import OAuth1Session\nfrom superagi.helper.twitter_helper import TwitterHelper\n\nclass TestSendTweets(unittest.TestCase):\n\n    @patch.object(OAuth1Session, 'post')\n    def test_send_tweets_success(self, mock_post):\n        # Prepare test data and mocks\n        test_params = {\"status\": \"Hello, Twitter!\"}\n        test_creds = Mock()\n        test_oauth = OAuth1Session(test_creds.api_key)\n\n        # Mock successful posting\n        resp = Response()\n        resp.status_code = 200\n        mock_post.return_value = resp\n\n        # Call the method under test\n        response = TwitterHelper().send_tweets(test_params, test_creds)\n\n        # Assert the post request was called correctly\n        test_oauth.post.assert_called_once_with(\n            \"https://api.twitter.com/2/tweets\", \n            json=test_params)\n\n        # Assert the response is correct\n        self.assertEqual(response.status_code, 200)\n\n    @patch.object(OAuth1Session, 'post')\n    def test_send_tweets_failure(self, mock_post):\n        # Prepare test data and mocks\n        test_params = {\"status\": \"Hello, Twitter!\"}\n        test_creds = Mock()\n        test_oauth = OAuth1Session(test_creds.api_key)\n\n        # Mock unsuccessful posting\n        resp = Response()\n        resp.status_code = 400\n        mock_post.return_value = resp\n\n        # Call the method under test\n        response = TwitterHelper().send_tweets(test_params, test_creds)\n\n        # Assert the post request was called correctly\n        test_oauth.post.assert_called_once_with(\n            \"https://api.twitter.com/2/tweets\", \n            json=test_params)\n\n        # Assert the response is correct\n        self.assertEqual(response.status_code, 400)\n\nif __name__ == '__main__':\n    unittest.main()"
  },
  {
    "path": "tests/unit_tests/helper/test_twitter_tokens.py",
    "content": "import unittest\nfrom unittest.mock import patch, Mock, MagicMock\nfrom typing import NamedTuple\nimport ast\nfrom sqlalchemy.orm import Session\nfrom superagi.helper.twitter_tokens import Creds, TwitterTokens\nfrom superagi.models.toolkit import Toolkit\nfrom superagi.models.oauth_tokens import OauthTokens\nimport time\nimport http.client\n\n\nclass TestCreds(unittest.TestCase):\n    def test_init(self):\n        creds = Creds('api_key', 'api_key_secret', 'oauth_token', 'oauth_token_secret')\n        self.assertEqual(creds.api_key, 'api_key')\n        self.assertEqual(creds.api_key_secret, 'api_key_secret')\n        self.assertEqual(creds.oauth_token, 'oauth_token')\n        self.assertEqual(creds.oauth_token_secret, 'oauth_token_secret')\n\n\nclass TestTwitterTokens(unittest.TestCase):\n    twitter_tokens = TwitterTokens(Session)\n    def setUp(self):\n        self.mock_session = Mock(spec=Session)\n        self.twitter_tokens = TwitterTokens(session=self.mock_session)\n\n    def test_init(self):\n        self.assertEqual(self.twitter_tokens.session, self.mock_session)\n\n    def test_percent_encode(self):\n        self.assertEqual(self.twitter_tokens.percent_encode(\"#\"), \"%23\")\n        \n    def test_gen_nonce(self):\n        self.assertEqual(len(self.twitter_tokens.gen_nonce()), 32)\n    \n    @patch.object(time, 'time', return_value=1234567890)\n    @patch.object(http.client, 'HTTPSConnection')\n    @patch('superagi.helper.twitter_tokens.TwitterTokens.gen_nonce', return_value=123456)  # Replace '__main__' with actual module name\n    @patch('superagi.helper.twitter_tokens.TwitterTokens.percent_encode', return_value=\"encoded\")  # Replace '__main__' with actual module name\n    def test_get_request_token(self, mock_percent_encode, mock_gen_nonce, mock_https_connection, mock_time):\n        response_mock = Mock()\n        response_mock.read.return_value = b'oauth_token=test_token&oauth_token_secret=test_secret'\n        mock_https_connection.return_value.getresponse.return_value = response_mock\n\n        api_data = {\"api_key\": \"test_key\", \"api_secret\": \"test_secret\"}\n        expected_result = {'oauth_token': 'test_token', 'oauth_token_secret': 'test_secret'}\n        self.assertEqual(self.twitter_tokens.get_request_token(api_data), expected_result)\n\nif __name__ == \"__main__\":\n    unittest.main()"
  },
  {
    "path": "tests/unit_tests/helper/test_webhooks.py",
    "content": "import json\nfrom unittest.mock import Mock, patch\nimport pytest\nfrom superagi.helper.webhook_manager import WebHookManager\nfrom superagi.models.webhooks import Webhooks\n\n@pytest.fixture\ndef mock_session():\n    return Mock()\n\n@pytest.fixture\ndef mock_agent_execution():\n    return Mock()\n\n@pytest.fixture\ndef mock_agent():\n    return Mock()\n\n@pytest.fixture\ndef mock_webhook():\n    return Mock()\n\n@pytest.fixture\ndef mock_org():\n    org_mock = Mock()\n    org_mock.id = \"mock_org_id\"\n    return org_mock\n\ndef test_agent_status_change_callback(\n    mock_session, mock_agent_execution, mock_agent, mock_org, mock_webhook\n):\n    curr_status = \"NEW_STATUS\"\n    old_status = \"OLD_STATUS\"\n    mock_agent_id = \"mock_agent_id\"\n    mock_org_id = \"mock_org_id\"\n\n    # Create a mock instance of AgentExecution and set its attributes\n    mock_agent_execution_instance = Mock()\n    mock_agent_execution_instance.agent_id = \"mock_agent_id\"\n\n    # Create a mock instance of Agent and set its attributes\n    mock_agent_instance = Mock()\n    mock_agent_instance.get_agent_organisation.return_value = mock_org\n\n    # Create a mock instance of Webhooks and set its attributes\n    mock_webhook_instance = Mock(spec=Webhooks)\n    mock_webhook_instance.filters = {\"status\": [\"PAUSED\", \"RUNNING\"]}\n\n    # Set up session.query().filter().all() to return the mock_webhook_instance\n    mock_session.query.return_value.filter.return_value.all.return_value = [mock_webhook_instance]\n\n    # Patch required functions/methods\n    with patch(\n        'superagi.controllers.agent_execution_config.AgentExecution.get_agent_execution_from_id',\n        return_value=mock_agent_execution_instance\n    ), patch(\n        'superagi.models.agent.Agent.get_agent_from_id',\n        return_value=mock_agent_instance\n    ), patch(\n        'requests.post',\n        return_value=Mock(status_code=200)  # Mock the status_code response\n    ) as mock_post, patch(\n        'json.dumps'\n    ) as mock_json_dumps:\n\n        # Create the WebHookManager instance\n        web_hook_manager = WebHookManager(mock_session)\n\n        # Call the function\n        web_hook_manager.agent_status_change_callback(\n            mock_agent_execution_instance, curr_status, old_status\n        )\n\n    assert mock_agent_execution_instance.agent_status_change_callback\n\n"
  },
  {
    "path": "tests/unit_tests/jobs/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/jobs/conftest.py",
    "content": "# content of conftest.py\ndef pytest_configure(config):\n    import sys\n    sys._called_from_test = True\n\ndef pytest_unconfigure(config):\n    import sys  # This was missing from the manual\n    del sys._called_from_test\n"
  },
  {
    "path": "tests/unit_tests/jobs/test_resource_summary.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/jobs/test_scheduling_executor.py",
    "content": "import pytest\nfrom unittest.mock import patch, MagicMock, ANY, PropertyMock\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.jobs.scheduling_executor import ScheduledAgentExecutor\nfrom datetime import datetime\n\n@patch('superagi.worker.execute_agent.delay')\n@patch('superagi.jobs.scheduling_executor.Session')\n@patch('superagi.models.agent.Agent')\n@patch('superagi.jobs.scheduling_executor.AgentWorkflow')\n@patch('superagi.models.agent_execution.AgentExecution')\ndef test_execute_scheduled_agent(AgentExecutionMock, AgentWorkflowMock, AgentMock, SessionMock, execute_agent_delay_mock):\n    # Arrange\n    agent_id = 1\n    name = 'Test Agent'\n\n    # session setup\n    session_mock = MagicMock()\n    SessionMock.return_value = session_mock\n\n    # agent setup\n    mock_agent = MagicMock(spec=Agent)\n    mock_agent.id = agent_id\n    session_mock.query.return_value.get.return_value = mock_agent\n\n    db_agent_execution_mock = AgentExecution(status=\"RUNNING\",last_execution_time=datetime.now(),agent_id=agent_id, name=name, num_of_calls=0, num_of_tokens=0, current_agent_step_id=1)\n    type(db_agent_execution_mock).id = PropertyMock(return_value=123)\n    AgentExecutionMock.return_value = db_agent_execution_mock\n\n    # Create a ScheduledAgentExecutor object and then call execute_scheduled_agent\n    executor = ScheduledAgentExecutor()\n    \n    # Act\n    executor.execute_scheduled_agent(agent_id, name)\n\n\n    # Assert\n    assert session_mock.query.called\n    assert session_mock.commit.called\n    execute_agent_delay_mock.assert_called_once_with(db_agent_execution_mock.id, ANY)\n    args, _ = execute_agent_delay_mock.call_args\n    assert isinstance(args[0], int)\n    assert isinstance(args[1], datetime)\n"
  },
  {
    "path": "tests/unit_tests/llms/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/llms/test_google_palm.py",
    "content": "from unittest.mock import patch\n\nfrom superagi.llms.google_palm import GooglePalm\n\n\n@patch('superagi.llms.google_palm.palm')\ndef test_chat_completion(mock_palm):\n    # Arrange\n    model = 'models/text-bison-001'\n    api_key = 'test_key'\n    palm_instance = GooglePalm(api_key, model=model)\n\n    messages = [{\"role\": \"system\", \"content\": \"You are a helpful assistant.\"}]\n    max_tokens = 100\n    mock_palm.generate_text.return_value.result = 'Sure, I can help with that.'\n\n    # Act\n    result = palm_instance.chat_completion(messages, max_tokens)\n\n    # Assert\n    assert result == {\"response\": mock_palm.generate_text.return_value, \"content\": 'Sure, I can help with that.'}\n    mock_palm.generate_text.assert_called_once_with(\n        model=model,\n        prompt='You are a helpful assistant.',\n        temperature=palm_instance.temperature,\n        candidate_count=palm_instance.candidate_count,\n        top_k=palm_instance.top_k,\n        top_p=palm_instance.top_p,\n        max_output_tokens=int(max_tokens)\n    )\n\n\ndef test_verify_access_key():\n    model = 'models/text-bison-001'\n    api_key = 'test_key'\n    palm_instance = GooglePalm(api_key, model=model)\n    result = palm_instance.verify_access_key()\n    assert result is False\n"
  },
  {
    "path": "tests/unit_tests/llms/test_hugging_face.py",
    "content": "import os\nfrom unittest.mock import patch, Mock\nfrom unittest import TestCase\nimport requests\nimport json\nfrom superagi.llms.hugging_face import HuggingFace\nfrom superagi.config.config import get_config\nfrom superagi.llms.utils.huggingface_utils.tasks import Tasks, TaskParameters\nfrom superagi.llms.utils.huggingface_utils.public_endpoints import ACCOUNT_VERIFICATION_URL\n\n\nclass TestHuggingFace(TestCase):\n\n#     @patch.object(requests, \"post\")\n#     def test_chat_completion(self, mock_post):\n#         # Arrange\n#         api_key = 'test_api_key'\n#         model = 'test_model'\n#         end_point = 'test_end_point'\n#         hf_instance = HuggingFace(api_key, model=model, end_point=end_point)\n#         messages = [{\"role\": \"system\", \"content\": \"You are a helpful assistant.\"}]\n#         mock_post.return_value = Mock()\n#         mock_post.return_value.content = b'{\"0\": {\"generated_text\": \"Sure, I can help with that.\"}}'\n#\n#         # Act\n#         result = hf_instance.chat_completion(messages)\n#\n#         # Assert\n#         mock_post.assert_called_with(\n#             end_point,\n#             headers={\"Authorization\": f\"Bearer {api_key}\", \"Content-Type\": \"application/json\"},\n#             data=json.dumps({\n#                 \"inputs\": \"You are a helpful assistant.\\nThe responses in json schema:\",\n#                 \"parameters\": TaskParameters().get_params(Tasks.TEXT_GENERATION),\n#                 \"options\": {\n#                     \"use_cache\": False,\n#                     \"wait_for_model\": True,\n#                 }\n#             })\n#         )\n#         assert result == {\"response\": {0: {\"generated_text\": \"Sure, I can help with that.\"}}, \"content\": \"Sure, I can help with that.\"}\n\n    @patch.object(requests, \"get\")\n    def test_verify_access_key(self, mock_get):\n        # Arrange\n        api_key = 'test_api_key'\n        model = 'test_model'\n        end_point = 'test_end_point'\n        hf_instance = HuggingFace(api_key, model=model, end_point=end_point)\n        mock_get.return_value.status_code = 200\n\n        # Act\n        result = hf_instance.verify_access_key()\n\n        # Assert\n        mock_get.assert_called_with(ACCOUNT_VERIFICATION_URL, headers={\"Authorization\": f\"Bearer {api_key}\", \"Content-Type\": \"application/json\"})\n        assert result is True\n\n    @patch.object(requests, \"post\")\n    def test_verify_end_point(self, mock_post):\n        # Arrange\n        api_key = 'test_api_key'\n        model = 'test_model'\n        end_point = 'test_end_point'\n        hf_instance = HuggingFace(api_key, model=model, end_point=end_point)\n        mock_post.return_value.json.return_value = {\"valid_response\": \"valid\"}\n\n        # Act\n        result = hf_instance.verify_end_point()\n\n        # Assert\n        mock_post.assert_called_with(\n            end_point,\n            headers={\"Authorization\": f\"Bearer {api_key}\", \"Content-Type\": \"application/json\"},\n            data=json.dumps({\"inputs\": \"validating end_point\"})\n        )\n        assert result == {\"valid_response\": \"valid\"}"
  },
  {
    "path": "tests/unit_tests/llms/test_model_factory.py",
    "content": "import pytest\nfrom unittest.mock import Mock\n\nfrom superagi.llms.google_palm import GooglePalm\nfrom superagi.llms.hugging_face import HuggingFace\nfrom superagi.llms.llm_model_factory import get_model, build_model_with_api_key\nfrom superagi.llms.openai import OpenAi\nfrom superagi.llms.replicate import Replicate\n\n\n# Fixtures for the mock objects\n@pytest.fixture\ndef mock_openai():\n    return Mock(spec=OpenAi)\n\n@pytest.fixture\ndef mock_replicate():\n    return Mock(spec=Replicate)\n\n@pytest.fixture\ndef mock_google_palm():\n    return Mock(spec=GooglePalm)\n\n@pytest.fixture\ndef mock_hugging_face():\n    return Mock(spec=HuggingFace)\n\n@pytest.fixture\ndef mock_replicate():\n    return Mock(spec=Replicate)\n\n@pytest.fixture\ndef mock_google_palm():\n    return Mock(spec=GooglePalm)\n\n@pytest.fixture\ndef mock_hugging_face():\n    return Mock(spec=HuggingFace)\n\n# Test build_model_with_api_key function\ndef test_build_model_with_openai(mock_openai, monkeypatch):\n    monkeypatch.setattr('superagi.llms.llm_model_factory.OpenAi', mock_openai)\n    model = build_model_with_api_key('OpenAi', 'fake_key')\n    mock_openai.assert_called_once_with(api_key='fake_key')\n    assert isinstance(model, Mock)\n\ndef test_build_model_with_replicate(mock_replicate, monkeypatch):\n    monkeypatch.setattr('superagi.llms.llm_model_factory.Replicate', mock_replicate)\n    model = build_model_with_api_key('Replicate', 'fake_key')\n    mock_replicate.assert_called_once_with(api_key='fake_key')\n    assert isinstance(model, Mock)\n\n\ndef test_build_model_with_openai(mock_openai, monkeypatch):\n    monkeypatch.setattr('superagi.llms.llm_model_factory.OpenAi', mock_openai)  # Replace 'your_module' with the actual module name\n    model = build_model_with_api_key('OpenAi', 'fake_key')\n    mock_openai.assert_called_once_with(api_key='fake_key')\n    assert isinstance(model, Mock)\n\ndef test_build_model_with_replicate(mock_replicate, monkeypatch):\n    monkeypatch.setattr('superagi.llms.llm_model_factory.Replicate', mock_replicate)  # Replace 'your_module' with the actual module name\n    model = build_model_with_api_key('Replicate', 'fake_key')\n    mock_replicate.assert_called_once_with(api_key='fake_key')\n    assert isinstance(model, Mock)\n\ndef test_build_model_with_google_palm(mock_google_palm, monkeypatch):\n    monkeypatch.setattr('superagi.llms.llm_model_factory.GooglePalm', mock_google_palm)  # Replace 'your_module' with the actual module name\n    model = build_model_with_api_key('Google Palm', 'fake_key')\n    mock_google_palm.assert_called_once_with(api_key='fake_key')\n    assert isinstance(model, Mock)\n\ndef test_build_model_with_hugging_face(mock_hugging_face, monkeypatch):\n    monkeypatch.setattr('superagi.llms.llm_model_factory.HuggingFace', mock_hugging_face)  # Replace 'your_module' with the actual module name\n    model = build_model_with_api_key('Hugging Face', 'fake_key')\n    mock_hugging_face.assert_called_once_with(api_key='fake_key')\n    assert isinstance(model, Mock)\n\ndef test_build_model_with_unknown_provider(capsys):  # capsys is a built-in pytest fixture for capturing print output\n    model = build_model_with_api_key('Unknown', 'fake_key')\n    assert model is None\n    captured = capsys.readouterr()\n    assert \"Unknown provider.\" in captured.out"
  },
  {
    "path": "tests/unit_tests/llms/test_open_ai.py",
    "content": "import openai\nimport pytest\nfrom unittest.mock import MagicMock, patch\n\nfrom superagi.llms.openai import OpenAi, MAX_RETRY_ATTEMPTS\n\n\n@patch('superagi.llms.openai.openai')\ndef test_chat_completion(mock_openai):\n    # Arrange\n    model = 'gpt-4'\n    api_key = 'test_key'\n    openai_instance = OpenAi(api_key, model=model)\n\n    messages = [{\"role\": \"system\", \"content\": \"You are a helpful assistant.\"}]\n    max_tokens = 100\n    mock_chat_response = MagicMock()\n    mock_chat_response.choices[0].message = {\"content\": \"I'm here to help!\"}\n    mock_openai.ChatCompletion.create.return_value = mock_chat_response\n\n    # Act\n    result = openai_instance.chat_completion(messages, max_tokens)\n\n    # Assert\n    assert result == {\"response\": mock_chat_response, \"content\": \"I'm here to help!\"}\n    mock_openai.ChatCompletion.create.assert_called_once_with(\n        n=openai_instance.number_of_results,\n        model=model,\n        messages=messages,\n        temperature=openai_instance.temperature,\n        max_tokens=max_tokens,\n        top_p=openai_instance.top_p,\n        frequency_penalty=openai_instance.frequency_penalty,\n        presence_penalty=openai_instance.presence_penalty\n    )\n\n\n@patch('superagi.llms.openai.wait_random_exponential.__call__')\n@patch('superagi.llms.openai.openai')\ndef test_chat_completion_retry_rate_limit_error(mock_openai, mock_wait_random_exponential):\n    # Arrange\n    model = 'gpt-4'\n    api_key = 'test_key'\n    openai_instance = OpenAi(api_key, model=model)\n\n    messages = [{\"role\": \"system\", \"content\": \"You are a helpful assistant.\"}]\n    max_tokens = 100\n\n    mock_openai.ChatCompletion.create.side_effect = openai.error.RateLimitError(\"Rate limit exceeded\")\n\n    # Mock sleep time\n    mock_wait_random_exponential.return_value = 0.1\n\n    # Act\n    result = openai_instance.chat_completion(messages, max_tokens)\n\n    # Assert\n    assert result == {\"error\": \"ERROR_OPENAI\", \"message\": \"Open ai exception: Rate limit exceeded\"}\n    assert mock_openai.ChatCompletion.create.call_count == MAX_RETRY_ATTEMPTS\n\n\n@patch('superagi.llms.openai.wait_random_exponential.__call__')\n@patch('superagi.llms.openai.openai')\ndef test_chat_completion_retry_timeout_error(mock_openai, mock_wait_random_exponential):\n    # Arrange\n    model = 'gpt-4'\n    api_key = 'test_key'\n    openai_instance = OpenAi(api_key, model=model)\n\n    messages = [{\"role\": \"system\", \"content\": \"You are a helpful assistant.\"}]\n    max_tokens = 100\n\n    mock_openai.ChatCompletion.create.side_effect = openai.error.Timeout(\"Timeout occured\")\n\n    # Mock sleep time\n    mock_wait_random_exponential.return_value = 0.1\n\n    # Act\n    result = openai_instance.chat_completion(messages, max_tokens)\n\n    # Assert\n    assert result == {\"error\": \"ERROR_OPENAI\", \"message\": \"Open ai exception: Timeout occured\"}\n    assert mock_openai.ChatCompletion.create.call_count == MAX_RETRY_ATTEMPTS\n\n\n@patch('superagi.llms.openai.wait_random_exponential.__call__')\n@patch('superagi.llms.openai.openai')\ndef test_chat_completion_retry_try_again_error(mock_openai, mock_wait_random_exponential):\n    # Arrange\n    model = 'gpt-4'\n    api_key = 'test_key'\n    openai_instance = OpenAi(api_key, model=model)\n\n    messages = [{\"role\": \"system\", \"content\": \"You are a helpful assistant.\"}]\n    max_tokens = 100\n\n    mock_openai.ChatCompletion.create.side_effect = openai.error.TryAgain(\"Try Again\")\n\n    # Mock sleep time\n    mock_wait_random_exponential.return_value = 0.1\n\n    # Act\n    result = openai_instance.chat_completion(messages, max_tokens)\n\n    # Assert\n    assert result == {\"error\": \"ERROR_OPENAI\", \"message\": \"Open ai exception: Try Again\"}\n    assert mock_openai.ChatCompletion.create.call_count == MAX_RETRY_ATTEMPTS\n\n\ndef test_verify_access_key():\n    model = 'gpt-4'\n    api_key = 'test_key'\n    openai_instance = OpenAi(api_key, model=model)\n    result = openai_instance.verify_access_key()\n    assert result is False\n"
  },
  {
    "path": "tests/unit_tests/llms/test_replicate.py",
    "content": "import os\nfrom unittest.mock import patch\nimport pytest\nimport requests\nfrom unittest import TestCase\nfrom superagi.llms.replicate import Replicate\nfrom superagi.config.config import get_config\n\nclass TestReplicate(TestCase):\n\n    @patch('os.environ')\n    @patch('replicate.run')\n    def test_chat_completion(self, mock_replicate_run, mock_os_environ):\n        # Arrange\n        api_key = 'test_api_key'\n        model = 'test_model'\n        version = 'test_version'\n        max_length=1000\n        temperature=0.7\n        candidate_count=1\n        top_k=40\n        top_p=0.95\n        rep_instance = Replicate(api_key, model=model, version=version, max_length=max_length, temperature=temperature,\n                         candidate_count=candidate_count, top_k=top_k, top_p=top_p)\n        messages = [{\"role\": \"system\", \"content\": \"You are a helpful assistant.\"}]\n        mock_replicate_run.return_value = iter(['Sure, I can help with that.'])\n\n        # Act\n        result = rep_instance.chat_completion(messages)\n\n        # Assert\n        assert result == {\"response\": ['Sure, I can help with that.'], \"content\": 'Sure, I can help with that.'}\n\n    @patch.object(requests, \"get\")\n    def test_verify_access_key(self, mock_get):\n        # Arrange\n        api_key = 'test_api_key'\n        model = 'test_model'\n        version = 'test_version'\n        rep_instance = Replicate(api_key, model=model, version=version)\n        mock_get.return_value.status_code = 200\n\n        # Act\n        result = rep_instance.verify_access_key()\n\n        # Assert\n        assert result is True\n        mock_get.assert_called_with(\"https://api.replicate.com/v1/collections\", headers={\"Authorization\": \"Token \" + api_key})\n\n    @patch.object(requests, \"get\")\n    def test_verify_access_key_false(self, mock_get):\n        # Arrange\n        api_key = 'test_api_key'\n        model = 'test_model'\n        version = 'test_version'\n        rep_instance = Replicate(api_key, model=model, version=version)\n        mock_get.return_value.status_code = 400\n\n        # Act\n        result = rep_instance.verify_access_key()\n\n        # Assert\n        assert result is False"
  },
  {
    "path": "tests/unit_tests/models/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/models/test_agent.py",
    "content": "from unittest.mock import create_autospec\nfrom sqlalchemy.orm import Session\nfrom superagi.models.agent import Agent\nfrom unittest.mock import patch\n  \ndef test_get_agent_from_id():\n    # Create a mock session\n    session = create_autospec(Session)\n\n    # Create a sample agent ID\n    agent_id = 1\n\n    # Create a mock agent object to be returned by the session query\n    mock_agent = Agent(id=agent_id, name=\"Test Agent\", project_id=1, description=\"Agent for testing\")\n\n    # Configure the session query to return the mock agent\n    session.query.return_value.filter.return_value.first.return_value = mock_agent\n\n    # Call the method under test\n    agent = Agent.get_agent_from_id(session, agent_id)\n\n    # Assert that the returned agent object matches the mock agent\n    assert agent == mock_agent\n\n\ndef test_get_active_agent_by_id():\n    # Create a mock session\n    session = create_autospec(Session)\n\n    # Create a sample agent ID\n    agent_id = 1\n\n    # Create a mock agent object to be returned by the session query\n    mock_agent = Agent(id=agent_id, name=\"Test Agent\", project_id=1, description=\"Agent for testing\",is_deleted=False)\n\n    # Configure the session query to return the mock agent\n    session.query.return_value.filter.return_value.first.return_value = mock_agent\n\n    # Call the method under test\n    agent = Agent.get_active_agent_by_id(session, agent_id)\n\n    # Assert that the returned agent object matches the mock agent\n    assert agent == mock_agent\n    assert agent.is_deleted == False\n\ndef test_eval_tools_key():\n    key = \"tools\"\n    value = \"[1, 2, 3]\"\n\n    result = Agent.eval_agent_config(key, value)\n\n    assert result == [1, 2, 3]\n\n"
  },
  {
    "path": "tests/unit_tests/models/test_agent_execution.py",
    "content": "from datetime import datetime\nfrom unittest.mock import create_autospec, patch, Mock\n\nimport pytest\nfrom pytest_mock import mocker\nfrom sqlalchemy.orm import Session\n\nfrom superagi.models.agent import Agent\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.models.workflows.agent_workflow_step import AgentWorkflowStep\nfrom superagi.models.workflows.iteration_workflow import IterationWorkflow\ndef test_get_agent_execution_from_id():\n    # Create a mock session\n    session = create_autospec(Session)\n\n    # Create a sample agent ID\n    agent_execution_id = 1\n\n    # Create a mock agent execution object to be returned by the session query\n    mock_agent_execution = AgentExecution(id=agent_execution_id, name=\"Test Execution\")\n\n    # Configure the session query to return the mock agent\n    session.query.return_value.filter.return_value.first.return_value = mock_agent_execution\n\n    # Call the method under test\n    agent = AgentExecution.get_agent_execution_from_id(session, agent_execution_id)\n\n    # Assert that the returned agent object matches the mock agent\n    assert agent == mock_agent_execution\n\n\n\n@pytest.fixture\ndef mock_session(mocker):\n    # Create a mock for the session object\n    mock_session = mocker.Mock()\n    return mock_session\n\n\ndef test_update_tokens(mock_session):\n    # Create a mock agent execution\n    mock_execution = AgentExecution(\n        id=1,\n        status='RUNNING',\n        name='Agent',\n        agent_id=1,\n        last_execution_time=datetime.now(),\n        num_of_calls=1,\n        num_of_tokens=100,\n        current_agent_step_id=1\n    )\n\n    # Mock the query response\n    mock_session.query.return_value.filter.return_value.first.return_value = mock_execution\n\n    # Call the method\n    AgentExecution.update_tokens(mock_session, 1, 50)\n\n    # Check that the attributes were updated\n    assert mock_execution.num_of_calls == 2\n    assert mock_execution.num_of_tokens == 150\n\n\ndef test_assign_next_step_id(mock_session, mocker):\n    # Create a mock agent execution and workflow step\n    mock_execution = AgentExecution(\n        id=1,\n        status='RUNNING',\n        name='Agent',\n        agent_id=1,\n        last_execution_time=datetime.now(),\n        num_of_calls=1,\n        num_of_tokens=100,\n        current_agent_step_id=1\n    )\n    mock_step = AgentWorkflowStep(id=2, action_type='ITERATION_WORKFLOW', action_reference_id=1)\n    mock_trigger_step = IterationWorkflow(id=3)\n\n    # Mock the query responses\n    mock_session.query.return_value.filter.return_value.first.return_value = mock_execution\n    mocker.patch.object(AgentWorkflowStep, 'find_by_id', return_value=mock_step)\n    mocker.patch.object(IterationWorkflow, 'fetch_trigger_step_id', return_value=mock_trigger_step)\n\n    # Call the method\n    AgentExecution.assign_next_step_id(mock_session, 1, 2)\n\n    # Check that the attributes were updated\n    assert mock_execution.current_agent_step_id == 2\n    assert mock_execution.iteration_workflow_step_id == 3\n\ndef test_get_execution_by_agent_id_and_status():\n    session = create_autospec(Session)\n\n    # Create a sample agent execution ID\n    agent_execution_id = 1\n\n    # Create a mock agent execution object to be returned by the session query\n    mock_agent_execution = AgentExecution(id=agent_execution_id, name=\"Test Execution\", status=\"RUNNING\")\n\n    # Configure the session query to return the mock agent\n    session.query.return_value.filter.return_value.first.return_value = mock_agent_execution\n\n    # Call the method under test\n    agent_execution = AgentExecution.get_execution_by_agent_id_and_status(session, agent_execution_id,\"RUNNING\")\n\n    # Assert that the returned agent object matches the mock agent\n    assert agent_execution == mock_agent_execution\n    assert agent_execution.status == \"RUNNING\"\n\n@pytest.fixture\ndef mock_session(mocker):\n    return mocker.MagicMock()\n\n\n"
  },
  {
    "path": "tests/unit_tests/models/test_agent_execution_config.py",
    "content": "import unittest\nfrom unittest.mock import MagicMock, patch, call\n\nfrom distlib.util import AND\n\nfrom superagi.models.agent_execution_config import AgentExecutionConfiguration\n\n\nclass TestAgentExecutionConfiguration(unittest.TestCase):\n\n    def setUp(self):\n        self.session = MagicMock()\n        self.execution = MagicMock()\n        self.execution.id = 1\n\n    def test_fetch_configuration(self):\n        test_db_response = [MagicMock(key=\"goal\", value=\"['test_goal']\"),\n                            MagicMock(key=\"instruction\", value=\"['test_instruction']\"),\n                            MagicMock(key=\"tools\", value=\"[1]\")]\n\n        self.session.query.return_value.filter_by.return_value.all.return_value = test_db_response\n\n        result = AgentExecutionConfiguration.fetch_configuration(self.session, self.execution)\n\n        expected_result = {\"goal\": [\"test_goal\"], \"instruction\": [\"test_instruction\"], \"tools\":[1]}\n        self.assertDictEqual(result, expected_result)\n\n    def test_eval_agent_config(self):\n        key = \"goal\"\n        value = \"['test_goal']\"\n\n        result = AgentExecutionConfiguration.eval_agent_config(key, value)\n\n        self.assertEqual(result, [\"test_goal\"])"
  },
  {
    "path": "tests/unit_tests/models/test_agent_execution_feed.py",
    "content": "import pytest\nfrom unittest.mock import Mock, create_autospec\nfrom sqlalchemy.orm import Session\nfrom superagi.models.agent_execution_feed import AgentExecutionFeed\n\n\ndef test_get_last_tool_response():\n    mock_session = create_autospec(Session)\n    agent_execution_feed_1 = AgentExecutionFeed(id=1, agent_execution_id=2, feed=\"Tool test1\", role='system')\n    agent_execution_feed_2 = AgentExecutionFeed(id=2, agent_execution_id=2, feed=\"Tool test2\", role='system')\n\n    mock_session.query().filter().order_by().all.return_value = [agent_execution_feed_1, agent_execution_feed_2]\n\n    result = AgentExecutionFeed.get_last_tool_response(mock_session, 2)\n\n    assert result == agent_execution_feed_1.feed  # as agent_execution_feed_1 should be the latest based on created_at\n\n\ndef test_get_last_tool_response_with_tool_name():\n    mock_session = create_autospec(Session)\n    agent_execution_feed_1 = AgentExecutionFeed(id=1, agent_execution_id=2, feed=\"Tool test1\", role='system')\n    agent_execution_feed_2 = AgentExecutionFeed(id=2, agent_execution_id=2, feed=\"Tool test2\", role='system')\n\n    mock_session.query().filter().order_by().all.return_value = [agent_execution_feed_1, agent_execution_feed_2]\n\n    result = AgentExecutionFeed.get_last_tool_response(mock_session, 2, \"test2\")\n    assert result == agent_execution_feed_2.feed\n"
  },
  {
    "path": "tests/unit_tests/models/test_agent_schedule.py",
    "content": "from unittest.mock import create_autospec\n\nfrom sqlalchemy.orm import Session\nfrom superagi.models.agent_schedule import AgentSchedule\n\ndef test_find_by_agent_id():\n    # Create a mock session\n    session = create_autospec(Session)\n\n    # Create a sample agent ID\n    agent_id = 1\n\n    # Create a mock agent schedule object to be returned by the session query\n    mock_agent_schedule = AgentSchedule(id=1,agent_id=agent_id, start_time=\"2023-08-10 12:17:00\", recurrence_interval=\"2 Minutes\", expiry_runs=2)\n\n    # Configure the session query to return the mock agent\n    session.query.return_value.filter.return_value.first.return_value = mock_agent_schedule\n\n    # Call the method under test\n    agent_schedule = AgentSchedule.find_by_agent_id(session, agent_id)\n\n    # Assert that the returned agent object matches the mock agent\n    assert agent_schedule == mock_agent_schedule\n"
  },
  {
    "path": "tests/unit_tests/models/test_agent_template.py",
    "content": "from unittest.mock import Mock, patch\n\nimport requests\n\nfrom superagi.models.agent_template import AgentTemplate\nfrom superagi.models.workflows.agent_workflow import AgentWorkflow\n\n\ndef test_to_dict():\n    agent_template = AgentTemplate(id=1, name='test', description='desc')\n    result = agent_template.to_dict()\n    assert result == {'id': 1, 'name': 'test', 'description': 'desc'}\n\n\ndef test_to_json():\n    agent_template = AgentTemplate(id=1, name='test', description='desc')\n    result = agent_template.to_json()\n    assert result == '{\"id\": 1, \"name\": \"test\", \"description\": \"desc\"}'\n\n\ndef test_from_json():\n    json_data = '{\"id\": 1, \"name\": \"test\", \"description\": \"desc\"}'\n    agent_template = AgentTemplate.from_json(json_data)\n    assert agent_template.id == 1\n    assert agent_template.name == 'test'\n    assert agent_template.description == 'desc'\n\n\ndef test_main_keys():\n    keys = AgentTemplate.main_keys()\n    assert isinstance(keys, list)\n    assert 'goal' in keys\n    assert 'instruction' in keys\n\n\n@patch.object(requests, 'get')\ndef test_fetch_marketplace_list(mock_get):\n    mock_get.return_value = Mock(status_code=200, json=lambda: [{'id': 1, 'name': 'test', 'description': 'desc'}])\n    result = AgentTemplate.fetch_marketplace_list('test', 1)\n    assert len(result) == 1\n    assert result[0]['id'] == 1\n\n\n@patch.object(requests, 'get')\ndef test_fetch_marketplace_detail(mock_get):\n    mock_get.return_value = Mock(status_code=200, json=lambda: {'id': 1, 'name': 'test', 'description': 'desc'})\n    result = AgentTemplate.fetch_marketplace_detail(1)\n    assert result['id'] == 1\n    assert result['name'] == 'test'\n    assert result['description'] == 'desc'\n\n\ndef test_eval_agent_config():\n    assert AgentTemplate.eval_agent_config('name', 'test') == 'test'\n    assert AgentTemplate.eval_agent_config('project_id', '1') == 1\n    assert AgentTemplate.eval_agent_config('goal', '[\"goal1\", \"goal2\"]') == [\"goal1\", \"goal2\"]\n\n\n@patch('superagi.models.agent_template.AgentTemplate.fetch_marketplace_detail')\n@patch('sqlalchemy.orm.Session')\ndef test_clone_agent_template_from_marketplace(mock_session, mock_fetch_marketplace_detail):\n    mock_fetch_marketplace_detail.return_value = {\n        \"id\": 1,\n        \"name\": \"test\",\n        \"description\": \"desc\",\n        \"agent_workflow_name\": \"workflow1\",\n        \"configs\": {\n            \"config1\": {\"value\": \"value1\"},\n            \"config2\": {\"value\": \"value2\"}\n        }\n    }\n    mock_session.query.return_value.filter.return_value.first.return_value = AgentWorkflow(id=1, name='workflow1')\n\n    agent_template = AgentTemplate.clone_agent_template_from_marketplace(mock_session, 1, 1)\n\n    assert isinstance(agent_template, AgentTemplate)\n    assert agent_template.organisation_id == 1\n    assert agent_template.name == 'test'\n    assert agent_template.description == 'desc'"
  },
  {
    "path": "tests/unit_tests/models/test_agent_workflow.py",
    "content": "import pytest\nfrom unittest.mock import MagicMock\nfrom sqlalchemy.orm import Session\n\nfrom superagi.models.workflows.agent_workflow import AgentWorkflow\n\n\n@pytest.fixture\ndef mock_session():\n    session = MagicMock(spec=Session)\n    session.query.return_value.filter.return_value.first.return_value = MagicMock(spec=AgentWorkflow)\n    return session\n\ndef test_find_by_name(mock_session):\n    result = AgentWorkflow.find_by_name(mock_session, 'workflow_name')\n    mock_session.query.assert_called_once_with(AgentWorkflow)\n    assert result.__class__ == AgentWorkflow\n\ndef test_find_or_create_by_name_new(mock_session):\n    mock_session.query.return_value.filter.return_value.first.return_value = None\n    result = AgentWorkflow.find_or_create_by_name(mock_session, 'workflow_name', 'description')\n    mock_session.add.assert_called_once()\n    assert result.__class__ == AgentWorkflow\n\ndef test_find_or_create_by_name_exists(mock_session):\n    result = AgentWorkflow.find_or_create_by_name(mock_session, 'workflow_name', 'description')\n    mock_session.add.assert_not_called()\n    assert result.__class__ == AgentWorkflow\n\ndef test_fetch_trigger_step_id(mock_session):\n    result = AgentWorkflow.fetch_trigger_step_id(mock_session, 1)\n    mock_session.query.assert_called_once()\n    assert result is not None"
  },
  {
    "path": "tests/unit_tests/models/test_agent_workflow_step.py",
    "content": "import pytest\nfrom unittest.mock import MagicMock, patch, Mock\nfrom sqlalchemy.orm import Session\nimport json\nfrom superagi.models.workflows.agent_workflow_step import AgentWorkflowStep\n\n\n@patch('sqlalchemy.orm.Session.query')\ndef test_find_by_id(mock_query):\n    mock_query.return_value.filter.return_value.first.return_value = MagicMock(spec=AgentWorkflowStep)\n    result = AgentWorkflowStep.find_by_id(Session(), 1)\n    assert isinstance(result, AgentWorkflowStep)\n\n@patch('sqlalchemy.orm.Session.query')\ndef test_find_by_unique_id(mock_query):\n    mock_query.return_value.filter.return_value.first.return_value = MagicMock(spec=AgentWorkflowStep)\n    result = AgentWorkflowStep.find_by_unique_id(Session(), '1')\n    assert isinstance(result, AgentWorkflowStep)\n\ndef test_from_json():\n    data = {\n        'id': 1,\n        'agent_workflow_id': 1,\n        'unique_id': '1',\n        'step_type': 'TRIGGER',\n        'action_type': 'TOOL',\n        'action_reference_id': 1,\n        'next_steps': []\n    }\n    result = AgentWorkflowStep.from_json(json.dumps(data))\n    assert isinstance(result, AgentWorkflowStep)\n\ndef test_to_dict():\n    step = AgentWorkflowStep(\n        id=1,\n        agent_workflow_id=1,\n        unique_id='1',\n        step_type='TRIGGER',\n        action_type='TOOL',\n        action_reference_id=1,\n        next_steps=[]\n    )\n    result = step.to_dict()\n    assert isinstance(result, dict)\n    assert result['id'] == 1\n    assert result['agent_workflow_id'] == 1\n    assert result['unique_id'] == '1'\n    assert result['step_type'] == 'TRIGGER'\n    assert result['action_type'] == 'TOOL'\n    assert result['action_reference_id'] == 1\n    assert result['next_steps'] == []\n\n\n@patch('sqlalchemy.orm.Session.add')\n@patch('sqlalchemy.orm.Session.commit')\n@patch('sqlalchemy.orm.Session.query')\n@patch('superagi.models.workflows.agent_workflow_step.AgentWorkflowStepTool.find_or_create_tool')\ndef test_find_or_create_tool_workflow_step(mock_find_or_create_tool, mock_query, mock_commit, mock_add):\n    mock_find_or_create_tool.return_value = MagicMock(id=2)\n    mock_query.return_value.filter.return_value.first.return_value = None  # to simulate workflow_step not exists yet\n    session = MagicMock(spec=Session)\n    session.query = mock_query\n    result = AgentWorkflowStep.find_or_create_tool_workflow_step(\n        session=session,\n        agent_workflow_id=1,\n        unique_id='1',\n        tool_name='test_tool',\n        input_instruction='test_instruction'\n    )\n    assert isinstance(result, AgentWorkflowStep)\n    assert result.agent_workflow_id == 1\n    assert result.unique_id == '1'\n    assert result.action_type == 'TOOL'\n    assert result.action_reference_id == 2\n    assert result.next_steps == []\n\n@patch('sqlalchemy.orm.Session.commit')\n@patch('sqlalchemy.orm.Session.query')\n@patch('superagi.models.workflows.agent_workflow_step.AgentWorkflowStepTool.find_or_create_tool')\ndef test_find_or_create_tool_workflow_step_exists(mock_find_or_create_tool, mock_query, mock_commit):\n    existing_workflow_step = MagicMock(spec=AgentWorkflowStep)\n    mock_find_or_create_tool.return_value = MagicMock(id=2)\n    mock_query.return_value.filter.return_value.first.return_value = existing_workflow_step\n    session = MagicMock(spec=Session)\n    session.query = mock_query\n    result = AgentWorkflowStep.find_or_create_tool_workflow_step(\n        session=session,\n        agent_workflow_id=1,\n        unique_id='1',\n        tool_name='test_tool',\n        input_instruction='test_instruction'\n    )\n    assert result == existing_workflow_step\n\n\n@patch('sqlalchemy.orm.Session.commit')\n@patch('sqlalchemy.orm.Session.query')\n@patch('superagi.models.workflows.iteration_workflow.IterationWorkflow.find_workflow_by_name')\ndef test_find_or_create_iteration_workflow_step_exists(mock_find_workflow_by_name, mock_query, mock_commit):\n    existing_workflow_step = MagicMock(spec=AgentWorkflowStep)\n    mock_find_workflow_by_name.return_value = MagicMock(id=2)\n    mock_query.return_value.filter.return_value.first.return_value = existing_workflow_step\n    session = MagicMock(spec=Session)\n    session.query = mock_query\n    result = AgentWorkflowStep.find_or_create_iteration_workflow_step(\n        session=session,\n        agent_workflow_id=1,\n        unique_id='1',\n        iteration_workflow_name='test_iteration_workflow',\n        step_type='NORMAL'\n    )\n    assert result == existing_workflow_step\n\n\n@patch('sqlalchemy.orm.Session.commit')\n@patch('sqlalchemy.orm.Session.query')\n@patch('superagi.models.workflows.agent_workflow_step.AgentWorkflowStep.find_by_id')\ndef test_add_next_workflow_step(mock_find_by_id, mock_query, mock_commit):\n    next_workflow_step = MagicMock(spec=AgentWorkflowStep, unique_id='2')\n    mock_find_by_id.return_value = next_workflow_step\n    current_step = MagicMock(spec=AgentWorkflowStep, next_steps=[])\n    mock_query.return_value.filter.return_value.first.return_value = current_step\n    session = MagicMock(spec=Session)\n    session.query = mock_query\n    result = AgentWorkflowStep.add_next_workflow_step(\n        session=session,\n        current_agent_step_id=1,\n        next_step_id=2,\n        step_response='test_response'\n    )\n    assert result == current_step\n    assert len(result.next_steps) == 1\n    assert result.next_steps[0]['step_response'] == 'test_response'\n    assert result.next_steps[0]['step_id'] == '2'\n\n@patch('sqlalchemy.orm.Session.commit')\n@patch('sqlalchemy.orm.Session.query')\n@patch('superagi.models.workflows.agent_workflow_step.AgentWorkflowStep.find_by_id')\ndef test_add_next_workflow_step_existing(mock_find_by_id, mock_query, mock_commit):\n    next_workflow_step = MagicMock(spec=AgentWorkflowStep, unique_id='2')\n    mock_find_by_id.return_value = next_workflow_step\n    current_step = MagicMock(spec=AgentWorkflowStep, next_steps=[{\"step_response\": 'previous_response', \"step_id\": '2'}])\n    mock_query.return_value.filter.return_value.first.return_value = current_step\n    session = MagicMock(spec=Session)\n    session.query = mock_query\n    result = AgentWorkflowStep.add_next_workflow_step(\n        session=session,\n        current_agent_step_id=1,\n        next_step_id=2,\n        step_response='test_response'\n    )\n    assert result == current_step\n    assert len(result.next_steps) == 1\n    assert result.next_steps[0]['step_response'] == 'test_response'\n    assert result.next_steps[0]['step_id'] == '2'\n\n\n@patch('superagi.models.workflows.agent_workflow_step.AgentWorkflowStep.find_by_id')\n@patch('superagi.models.workflows.agent_workflow_step.AgentWorkflowStep.find_by_unique_id')\ndef test_fetch_default_next_step(mock_find_by_unique_id, mock_find_by_id):\n    current_step = MagicMock(spec=AgentWorkflowStep, next_steps=[{\"step_response\": 'default', \"step_id\": '2'}])\n    next_step = MagicMock(spec=AgentWorkflowStep, unique_id='2')\n    mock_find_by_id.return_value = current_step\n    mock_find_by_unique_id.return_value = next_step\n    session = MagicMock(spec=Session)\n    result = AgentWorkflowStep.fetch_default_next_step(\n        session=session,\n        current_agent_step_id=1,\n    )\n    assert result == next_step\n\n@patch('superagi.models.workflows.agent_workflow_step.AgentWorkflowStep.find_by_id')\ndef test_fetch_default_next_step_none(mock_find_by_id):\n    current_step = MagicMock(spec=AgentWorkflowStep, next_steps=[{\"step_response\": 'non-default', \"step_id\": '2'}])\n    mock_find_by_id.return_value = current_step\n    session = MagicMock(spec=Session)\n    result = AgentWorkflowStep.fetch_default_next_step(\n        session=session,\n        current_agent_step_id=1,\n    )\n    assert result is None"
  },
  {
    "path": "tests/unit_tests/models/test_agent_workflow_step_tool.py",
    "content": "from unittest.mock import patch, MagicMock\nfrom sqlalchemy.orm import Session\n\nfrom superagi.models.workflows.agent_workflow_step_tool import AgentWorkflowStepTool\n\n\n@patch('sqlalchemy.orm.Session.query')\ndef test_find_by_id(mock_query):\n    mock_query.return_value.filter.return_value.first.return_value = MagicMock(spec=AgentWorkflowStepTool)\n    result = AgentWorkflowStepTool.find_by_id(Session(), 1)\n    assert isinstance(result, AgentWorkflowStepTool)\n@patch('sqlalchemy.orm.Session.add')\n@patch('sqlalchemy.orm.Session.query')\ndef test_find_or_create_tool_new(mock_query, mock_add):\n    mock_query.return_value.filter_by.return_value.first.return_value = None  # simulating tool doesn't exist\n    session = MagicMock(spec=Session)\n    session.query = mock_query\n    tool = AgentWorkflowStepTool.find_or_create_tool(\n        session=session,\n        step_unique_id='test_step',\n        tool_name='test_tool',\n        input_instruction='test_input',\n        output_instruction='test_output',\n        history_enabled=False,\n        completion_prompt='test_prompt'\n    )\n    assert tool.__class__ == AgentWorkflowStepTool\n\n@patch('sqlalchemy.orm.Session.query')\ndef test_find_or_create_tool_exists(mock_query):\n    mock_tool = MagicMock(spec=AgentWorkflowStepTool)\n    mock_query.return_value.filter_by.return_value.first.return_value = mock_tool  # simulating tool already exists\n    session = MagicMock(spec=Session)\n    session.query = mock_query\n    tool = AgentWorkflowStepTool.find_or_create_tool(\n        session=session,\n        step_unique_id='test_step',\n        tool_name='test_tool',\n        input_instruction='test_input',\n        output_instruction='test_output',\n        history_enabled=False,\n        completion_prompt='test_prompt'\n    )\n    assert tool == mock_tool\n"
  },
  {
    "path": "tests/unit_tests/models/test_api_key.py",
    "content": "from unittest.mock import create_autospec\n\nfrom sqlalchemy.orm import Session\nfrom superagi.models.api_key import ApiKey\n\ndef test_get_by_org_id():\n    # Create a mock session\n    session = create_autospec(Session)\n\n    # Create a sample organization ID\n    org_id = 1\n\n    # Create a mock ApiKey object to be returned by the session query\n    mock_api_keys = [\n        ApiKey(id=1, org_id=org_id, key=\"key1\", is_expired=False),\n        ApiKey(id=2, org_id=org_id, key=\"key2\", is_expired=False),\n    ]\n\n    # Configure the session query to return the mock api keys\n    session.query.return_value.filter.return_value.all.return_value = mock_api_keys\n\n    # Call the method under test\n    api_keys = ApiKey.get_by_org_id(session, org_id)\n\n    # Assert that the returned api keys match the mock api keys\n    assert api_keys == mock_api_keys\n\n\ndef test_get_by_id():\n    # Create a mock session\n    session = create_autospec(Session)\n\n    # Create a sample api key ID\n    api_key_id = 1\n\n    # Create a mock ApiKey object to be returned by the session query\n    mock_api_key = ApiKey(id=api_key_id, org_id=1, key=\"key1\", is_expired=False)\n\n    # Configure the session query to return the mock api key\n    session.query.return_value.filter.return_value.first.return_value = mock_api_key\n\n    # Call the method under test\n    api_key = ApiKey.get_by_id(session, api_key_id)\n\n    # Assert that the returned api key matches the mock api key\n    assert api_key == mock_api_key\n\ndef test_delete_by_id():\n    # Create a mock session\n    session = create_autospec(Session)\n\n    # Create a sample api key ID\n    api_key_id = 1\n\n    # Create a mock ApiKey object to be returned by the session query\n    mock_api_key = ApiKey(id=api_key_id, org_id=1, key=\"key1\", is_expired=False)\n\n    # Configure the session query to return the mock api key\n    session.query.return_value.filter.return_value.first.return_value = mock_api_key\n\n    # Call the method under test\n    ApiKey.delete_by_id(session, api_key_id)\n\n    # Assert that the api key's is_expired attribute is set to True\n    assert mock_api_key.is_expired == True\n\n    # Assert that the session.commit and session.flush methods were called\n    session.commit.assert_called_once()\n    session.flush.assert_called_once()\n\ndef test_edit_by_id():\n    # Create a mock session\n    session = create_autospec(Session)\n\n    # Create a sample api key ID and new name\n    api_key_id = 1\n    new_name = \"New Name\"\n\n    # Create a mock ApiKey object to be returned by the session query\n    mock_api_key = ApiKey(id=api_key_id, org_id=1, key=\"key1\", is_expired=False)\n\n    # Configure the session query to return the mock api key\n    session.query.return_value.filter.return_value.first.return_value = mock_api_key\n\n    # Call the method under test\n    ApiKey.update_api_key(session, api_key_id, new_name)\n\n    # Assert that the api key's name attribute is updated\n    assert mock_api_key.name == new_name\n\n    # Assert that the session.commit and session.flush methods were called\n    session.commit.assert_called_once()\n    session.flush.assert_called_once()"
  },
  {
    "path": "tests/unit_tests/models/test_call_logs.py",
    "content": "import pytest\nfrom unittest.mock import MagicMock\nfrom superagi.models.call_logs import CallLogs\n\n@pytest.fixture\ndef mock_session():\n    session = MagicMock()\n    session.query.return_value.filter.return_value.first.return_value = None\n    return session\n\n@pytest.mark.parametrize(\"agent_execution_name, agent_id, tokens_consumed, tool_used, model, org_id\",\n                         [(\"example_execution\", 1, 1, \"Test Tool\", \"Test Model\", 1)])\ndef test_create_call_logs(mock_session, agent_execution_name, agent_id, tokens_consumed, tool_used, model, org_id):\n    # Arrange\n    call_log = CallLogs(agent_execution_name=agent_execution_name,\n                        agent_id=agent_id,\n                        tokens_consumed=tokens_consumed,\n                        tool_used=tool_used,\n                        model=model,\n                        org_id=org_id)\n    # Act\n    mock_session.add(call_log)\n\n    # Assert\n    mock_session.add.assert_called_once_with(call_log)\n\n@pytest.mark.parametrize(\"agent_execution_name, agent_id, tokens_consumed, tool_used, model, org_id\",\n                         [(\"example_execution\", 1, 1, \"Test Tool\", \"Test Model\", 1)])\ndef test_repr_method_call_logs(mock_session, agent_execution_name, agent_id, tokens_consumed, tool_used, model, org_id):\n    # Arrange\n    call_log = CallLogs(agent_execution_name=agent_execution_name,\n                        agent_id=agent_id,\n                        tokens_consumed=tokens_consumed,\n                        tool_used=tool_used,\n                        model=model,\n                        org_id=org_id)\n\n    # Act\n    result = repr(call_log)\n\n    # Assert\n    assert result == (f\"CallLogs(id=None, agent_execution_name={agent_execution_name}, \"\n                      f\"agent_id={agent_id}, tokens_consumed={tokens_consumed}, \"\n                      f\"tool_used={tool_used}, model={model}, org_id={org_id})\")"
  },
  {
    "path": "tests/unit_tests/models/test_configuration.py",
    "content": "import pytest\nfrom fastapi import HTTPException\nfrom unittest.mock import MagicMock\nfrom sqlalchemy.orm import Session\nfrom superagi.models.configuration import Configuration\nfrom superagi.models.agent import Agent\nfrom superagi.models.organisation import Organisation\nfrom superagi.models.project import Project\n\n\ndef test_fetch_configuration():\n    mock_session = MagicMock(spec=Session)\n    mock_query = mock_session.query.return_value\n    mock_query.filter_by.return_value.first.return_value = Configuration(value=\"test_value\")\n\n    result = Configuration.fetch_configuration(mock_session, 1, \"test_key\")\n\n    assert result == \"test_value\"\n    mock_session.query.assert_called_once_with(Configuration)\n    mock_query.filter_by.assert_called_once_with(organisation_id=1, key=\"test_key\")\n\n\ndef test_fetch_value_by_agent_id():\n    mock_session = MagicMock(spec=Session)\n    mock_query = mock_session.query.return_value\n    mock_query.filter.return_value.first.side_effect = [\n        Agent(project_id=1), Project(organisation_id=1), Organisation(id=1), Configuration(value=\"test_value\")\n    ]\n\n    result = Configuration.fetch_value_by_agent_id(mock_session, 1, \"test_key\")\n\n    assert result == \"test_value\"\n    assert mock_session.query.call_count == 4\n\n\ndef test_fetch_value_by_agent_id_agent_not_found():\n    mock_session = MagicMock(spec=Session)\n    mock_query = mock_session.query.return_value\n    mock_query.filter.return_value.first.return_value = None\n\n    with pytest.raises(HTTPException) as exception_info:\n        Configuration.fetch_value_by_agent_id(mock_session, 1, \"test_key\")\n\n    assert exception_info.value.status_code == 404\n    assert exception_info.value.detail == \"Agent not found\"\n"
  },
  {
    "path": "tests/unit_tests/models/test_events.py",
    "content": "from unittest.mock import MagicMock, patch\n\nimport pytest\n\nfrom superagi.models.events import Event\n\n@pytest.fixture\ndef mock_session():\n    return MagicMock()\n\ndef test_create_event(mock_session):\n    # Arrange\n    event_name = \"example_event\"\n    event_value = 100\n    agent_id = 1\n    org_id = 1\n    mock_session.query.return_value.filter_by.return_value.first.return_value = None\n\n    # Act\n    event = Event(event_name=event_name, event_value=event_value)\n    mock_session.add(event)\n\n    # Assert\n    mock_session.add.assert_called_once_with(event)\n\ndef test_repr_method_event(mock_session):\n    # Arrange\n    event_name = \"example_event\"\n    event_value = 100\n    agent_id = 1\n    org_id = 1\n    mock_session.query.return_value.filter_by.return_value.first.return_value = None\n\n    # Act\n    event = Event(event_name=event_name, event_value=event_value)\n    event_repr = repr(event)\n\n    # Assert\n    assert event_repr == f\"Event(id=None, event_name={event_name}, \" \\\n                         f\"event_value={event_value}, \" \\\n                         f\"agent_id=None, \" \\\n                         f\"org_id=None)\"\n"
  },
  {
    "path": "tests/unit_tests/models/test_iteration_workflow.py",
    "content": "from unittest.mock import MagicMock, patch\nfrom sqlalchemy.orm import Session\n\nfrom superagi.models.workflows.iteration_workflow import IterationWorkflow\n\n@patch('sqlalchemy.orm.Session.query')\ndef test_find_by_id(mock_query):\n    mock_query.return_value.filter.return_value.first.return_value = MagicMock(spec=IterationWorkflow)\n    session = MagicMock(spec=Session)\n    session.query = mock_query\n    result = IterationWorkflow.find_by_id(session, 1)\n    mock_query.assert_called_once_with(IterationWorkflow)\n    assert result.__class__ == IterationWorkflow\n\n@patch('sqlalchemy.orm.Session.query')\ndef test_find_workflow_by_name(mock_query):\n    mock_query.return_value.filter.return_value.first.return_value = MagicMock(spec=IterationWorkflow)\n    session = MagicMock(spec=Session)\n    session.query = mock_query\n    result = IterationWorkflow.find_workflow_by_name(session, 'workflow_name')\n    mock_query.assert_called_once_with(IterationWorkflow)\n    assert result.__class__ == IterationWorkflow\n\n@patch('sqlalchemy.orm.Session.add')\n@patch('sqlalchemy.orm.Session.query')\ndef test_find_or_create_by_name_new(mock_query, mock_add):\n    mock_query.return_value.filter.return_value.first.return_value = None\n    session = MagicMock(spec=Session)\n    session.query = mock_query\n    result = IterationWorkflow.find_or_create_by_name(session, 'workflow_name', 'description', False)\n    assert result.__class__ == IterationWorkflow\n\n@patch('sqlalchemy.orm.Session.add')\n@patch('sqlalchemy.orm.Session.query')\ndef test_find_or_create_by_name_exists(mock_query, mock_add):\n    mock_query.return_value.filter.return_value.first.return_value = MagicMock(spec=IterationWorkflow)\n    session = MagicMock(spec=Session)\n    session.query = mock_query\n    result = IterationWorkflow.find_or_create_by_name(session, 'workflow_name', 'description', False)\n    mock_add.assert_not_called()\n    assert result.__class__ == IterationWorkflow\n\n@patch('sqlalchemy.orm.Session.query')\ndef test_fetch_trigger_step_id(mock_query):\n    mock_query.return_value.filter.return_value.first.return_value = MagicMock()  # Assume we have a proper trigger step\n    session = MagicMock(spec=Session)\n    session.query = mock_query\n    result = IterationWorkflow.fetch_trigger_step_id(session, 1)\n    mock_query.assert_called_once()  # The mock_query must be called once\n    assert result is not None"
  },
  {
    "path": "tests/unit_tests/models/test_iteration_workflow_step.py",
    "content": "import pytest\nfrom unittest.mock import MagicMock\nfrom sqlalchemy.orm import Session\n\nfrom superagi.models.workflows.iteration_workflow_step import IterationWorkflowStep\n\n\n@pytest.fixture\ndef mock_session():\n    session = MagicMock(spec=Session)\n    session.query.return_value.filter.return_value.first.return_value = MagicMock(spec=IterationWorkflowStep)\n    return session\n\n\ndef test_find_by_id(mock_session):\n    result = IterationWorkflowStep.find_by_id(mock_session, 1)\n    mock_session.query.assert_called_once_with(IterationWorkflowStep)\n    assert result.__class__ == IterationWorkflowStep\n\n\ndef test_find_or_create_step_new(mock_session):\n    mock_session.query.return_value.filter.return_value.first.return_value = None\n    result = IterationWorkflowStep.find_or_create_step(mock_session, 1, 'unique_id', 'prompt', 'variables', 'step_type',\n                                                       'output_type')\n    mock_session.add.assert_called_once()\n    assert result.__class__ == IterationWorkflowStep\n\n\ndef test_find_or_create_step_exists(mock_session):\n    result = IterationWorkflowStep.find_or_create_step(mock_session, 1, 'unique_id', 'prompt', 'variables', 'step_type',\n                                                       'output_type')\n    mock_session.add.assert_not_called()\n    assert result.__class__ == IterationWorkflowStep\n"
  },
  {
    "path": "tests/unit_tests/models/test_knowledge_configs.py",
    "content": "import unittest\nfrom unittest.mock import Mock, patch, MagicMock\nfrom sqlalchemy.orm.session import Session\n\nfrom superagi.models.knowledge_configs import KnowledgeConfigs\n\nclass TestKnowledgeConfigs(unittest.TestCase):\n\n    def setUp(self):\n        self.session = Mock(spec=Session)\n        self.knowledge_id = 1\n        self.test_configs = {'key1': 'value1', 'key2': 'value2'}\n\n    @patch('requests.get')\n    def test_fetch_knowledge_config_details_marketplace(self, mock_get):\n        mock_response = Mock()\n        mock_response.status_code = 200\n        mock_response.json.return_value = [{'key': 'key1', 'value': 'value1'}, {'key': 'key2', 'value': 'value2'}]\n        mock_get.return_value = mock_response\n\n        configs = KnowledgeConfigs.fetch_knowledge_config_details_marketplace(self.knowledge_id)\n        self.assertEqual(configs, self.test_configs)\n\n    def test_add_update_knowledge_config(self):\n        KnowledgeConfigs.add_update_knowledge_config(self.session, self.knowledge_id, self.test_configs)\n        self.session.add.assert_called()\n        self.session.commit.assert_called()\n\n    def test_get_knowledge_config_from_knowledge_id(self):\n        test_obj = Mock()\n        test_obj.key = \"key1\"\n        test_obj.value = \"value1\"\n        self.session.query.return_value.filter.return_value.all.return_value = [test_obj]\n        configs = KnowledgeConfigs.get_knowledge_config_from_knowledge_id(self.session, self.knowledge_id)\n        self.assertEqual(configs, {\"key1\": \"value1\"})\n\n    def test_delete_knowledge_config(self):\n        KnowledgeConfigs.delete_knowledge_config(self.session, self.knowledge_id)\n        self.session.query.assert_called()\n        self.session.commit.assert_called()\n\n    def tearDown(self):\n        pass\n    \n    \nif __name__ == \"__main__\":\n    unittest.main()"
  },
  {
    "path": "tests/unit_tests/models/test_marketplace_stats.py",
    "content": "import unittest\nfrom unittest.mock import patch, MagicMock\nfrom sqlalchemy.orm import Session\nfrom superagi.models.marketplace_stats import MarketPlaceStats\n\nclass TestMarketPlaceStats(unittest.TestCase):\n\n    @patch('requests.get')\n    def test_get_knowledge_installation_number(self, mock_get):\n        test_json = {'download_count':123}\n        mock_response = MagicMock()\n        mock_response.status_code = 200\n        mock_response.json.return_value = test_json\n        mock_get.return_value = mock_response\n\n        result = MarketPlaceStats.get_knowledge_installation_number(1)\n        self.assertEqual(result, test_json)\n\n    @patch('requests.get')\n    def test_get_knowledge_installation_number_status_not_200(self, mock_get):\n        mock_response = MagicMock()\n        mock_response.status_code = 404\n        mock_get.return_value = mock_response\n\n        result = MarketPlaceStats.get_knowledge_installation_number(1)\n        self.assertEqual(result, [])\n\n    @patch('sqlalchemy.orm.Session')\n    def test_update_knowledge_install_number_existing(self, mock_session):\n        instance = MagicMock()\n        instance.value = '5'\n        mock_query = MagicMock()\n        mock_query.filter.return_value.first.return_value = instance\n        mock_session.query.return_value = mock_query\n\n        MarketPlaceStats.update_knowledge_install_number(mock_session, 1, 10)\n\n        self.assertEqual(instance.value, \"10\")\n\n        mock_query.filter.assert_called()\n        mock_session.commit.assert_called()\n        \nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "tests/unit_tests/models/test_models.py",
    "content": "from unittest.mock import MagicMock, patch\n\nimport pytest\n\nfrom superagi.models.models import Models\n\n@pytest.fixture\ndef mock_session():\n    return MagicMock()\n\ndef test_create_model(mock_session):\n    # Arrange\n    model_name = \"example_model\"\n    end_point = \"example_end_point\"\n    model_provider_id = 1\n    token_limit = 500\n    model_type = \"example_type\"\n    version = \"v1.0\"\n    org_id = 1\n    model_features = \"example_model_feature\"\n    mock_session.query.return_value.filter_by.return_value.first.return_value = None\n\n    # Act\n    model = Models(model_name=model_name, end_point=end_point,\n                   model_provider_id=model_provider_id, token_limit=token_limit,\n                   type=model_type, version=version, org_id=org_id, model_features=model_features)\n    mock_session.add(model)\n\n    # Assert\n    mock_session.add.assert_called_once_with(model)\n\n\ndef test_repr_method_models(mock_session):\n    # Arrange\n    model_name = \"example_model\"\n    end_point = \"example_end_point\"\n    model_provider_id = 1\n    token_limit = 500\n    model_type = \"example_type\"\n    version = \"v1.0\"\n    org_id = 1\n    model_features = \"example_model_feature\"\n    mock_session.query.return_value.filter_by.return_value.first.return_value = None\n\n    # Act\n    model = Models(model_name=model_name, end_point=end_point,\n                 model_provider_id=model_provider_id, token_limit=token_limit,\n                 type=model_type, version=version, org_id=org_id, model_features=model_features)\n    model_repr = repr(model)\n\n    # Assert\n    assert model_repr == f\"Models(id=None, model_name={model_name}, \" \\\n                         f\"end_point={end_point}, model_provider_id={model_provider_id}, \" \\\n                         f\"token_limit={token_limit}, \" \\\n                         f\"type={model_type}, \" \\\n                         f\"version={version}, \" \\\n                         f\"org_id={org_id}, \" \\\n                         f\"model_features={model_features})\"\n\n\n@patch('requests.get')\ndef test_fetch_marketplace_list(mock_get):\n    # Specify the return value of the get method\n    mock_response = MagicMock()\n    mock_response.status_code = 200\n    mock_response.json.return_value = ['model1', 'model2']\n    mock_get.return_value = mock_response\n\n    # Call the method\n    result = Models.fetch_marketplace_list(1)\n\n    # Verify the result\n    assert result == ['model1', 'model2']\n\n# @patch('superagi.models.models_config.ModelsConfig')\n# @patch('logging.error')\n# def test_get_model_install_details(mock_logging_error, mock_models_config, mock_session):\n#     mock_model = MagicMock()\n#     mock_model.model_name = 'model1'\n#     mock_model.model_provider_id = 1\n#\n#     mock_marketplace_models = [{'model_name': 'model1', 'model_provider_id': 1}, {'model_name': 'model2', 'model_provider_id': 2}]\n#     mock_session.query.return_value.filter.return_value.all.return_value = [mock_model]\n#     mock_session.query.return_value.group_by.return_value.all.return_value = [('model1', 1)]\n#     mock_config = MagicMock()\n#     mock_config.provider = 'provider1'\n#\n#     def determine_provider(*args):\n#         for arg in args:\n#             # Check if mock_config can be returned\n#             if isinstance(arg, int) and arg == 1:\n#                 return mock_config\n#         # Return None for all other situations\n#         return None\n#\n#     mock_session.query.return_value.filter.return_value.first.side_effect = determine_provider\n#\n#     # Call the method\n#     result = Models.get_model_install_details(mock_session, mock_marketplace_models, MagicMock())\n#\n#     # Verify the result\n#     expected_result = [\n#         {\"model_name\": \"model1\", \"is_installed\": True, \"installs\": 1, \"provider\": \"provider1\", \"model_provider_id\": 1},\n#         {\"model_name\": \"model2\", \"is_installed\": False, \"installs\": 0, \"provider\": None, \"model_provider_id\": 2}\n#     ]\n#     assert result == expected_result\n#     # Assert that logging.error has been called once when provider is None\n#     mock_logging_error.assert_called_once()\n\ndef test_fetch_model_tokens(mock_session):\n    # Specify the return value of the query\n    mock_session.query.return_value.filter.return_value.all.return_value = [('model1', 500)]\n\n    # Call the method\n    result = Models.fetch_model_tokens(mock_session, 1)\n\n    # Verify the result\n    assert result == {'model1': 500}\n\ndef test_store_model_details_when_model_exists(mock_session):\n    # Arrange\n    mock_session.query.return_value.filter.return_value.first.return_value = MagicMock()\n    mock_session.add = MagicMock()\n\n    # Act\n    response = Models.store_model_details(\n        mock_session,\n        organisation_id=1,\n        model_name=\"example_model\",\n        description=\"description\",\n        end_point=\"end_point\",\n        model_provider_id=1,\n        token_limit=500,\n        type=\"type\",\n        version=\"v1.0\",\n        context_length=4096\n    )\n\n    # Assert\n    assert response == {\"error\": \"Model Name already exists\"}\n\ndef test_store_model_details_when_model_not_exists(mock_session, monkeypatch):\n    # Arrange\n    mock_session.query.return_value.filter.return_value.first.return_value = None\n    mock_session.add = MagicMock()\n    mock_session.commit = MagicMock()\n    mock_query = MagicMock()\n    mock_fetch_model_by_id = MagicMock()\n\n    # Patching the fetch_model_by_id method in the class\n    monkeypatch.setattr('superagi.models.models_config.ModelsConfig.fetch_model_by_id', mock_fetch_model_by_id)\n    mock_fetch_model_by_id.return_value = {\"provider\": \"some_provider\"}\n\n    # Act\n    response = Models.store_model_details(\n        mock_session,\n        organisation_id=1,\n        model_name=\"example_model\",\n        description=\"description\",\n        end_point=\"end_point\",\n        model_provider_id=1,\n        token_limit=500,\n        type=\"type\",\n        version=\"v1.0\",\n        context_length=4096\n    )\n\n    # Assert\n    assert response == {\"success\": \"Model Details stored successfully\", \"model_id\": None}\n    mock_session.add.assert_called_once()\n    mock_session.commit.assert_called_once()\n\ndef test_store_model_details_when_unexpected_error_occurs(mock_session, monkeypatch):\n    # Arrange\n    mock_session.query.return_value.filter.return_value.first.return_value = None\n    mock_session.add = MagicMock(side_effect=Exception(\"Unknown error\"))\n    mock_fetch_model_by_id = MagicMock()\n    monkeypatch.setattr('superagi.models.models_config.ModelsConfig.fetch_model_by_id', mock_fetch_model_by_id)\n    mock_fetch_model_by_id.return_value = {\"provider\": \"some_provider\"}\n\n    # Act\n    response = Models.store_model_details(\n        mock_session,\n        organisation_id=1,\n        model_name=\"example_model\",\n        description=\"description\",\n        end_point=\"end_point\",\n        model_provider_id=1,\n        token_limit=500,\n        type=\"type\",\n        version=\"v1.0\",\n        context_length=4096\n    )\n\n    # Assert\n    assert response == {\"error\": \"Unexpected Error Occured\"}\n\n@patch('superagi.models.models_config.ModelsConfig')\ndef test_fetch_models(mock_models_config, mock_session):\n    # Specify the return value of the query\n    mock_session.query.return_value.join.return_value.filter.return_value.all.return_value = [\n        (1, \"example_model\", \"description\", \"example_provider\")\n    ]\n\n    # Call the method\n    result = Models.fetch_models(mock_session, 1)\n\n    # Verify the result\n    assert result == [{\n        \"id\": 1,\n        \"name\": \"example_model\",\n        \"description\": \"description\",\n        \"model_provider\": \"example_provider\"\n    }]\n\n@patch('superagi.models.models_config.ModelsConfig')\ndef test_fetch_model_details(mock_models_config, mock_session):\n    # Specify the return values for the query\n    mock_session.query.return_value.join.return_value.filter.return_value.first.return_value = (\n        1, \"example_model\", \"description\", \"end_point\", 100, \"type1\", \"example_provider\"\n    )\n\n    # Call the method\n    result = Models.fetch_model_details(mock_session, 1, 1)\n\n    # Verify the result\n    assert result == {\n        \"id\": 1,\n        \"name\": \"example_model\",\n        \"description\": \"description\",\n        \"end_point\": \"end_point\",\n        \"token_limit\": 100,\n        \"type\": \"type1\",\n        \"model_provider\": \"example_provider\"\n    }"
  },
  {
    "path": "tests/unit_tests/models/test_models_config.py",
    "content": "from unittest.mock import MagicMock, patch\n\nimport pytest\n\nfrom superagi.models.models_config import ModelsConfig\n\n@pytest.fixture\ndef mock_session():\n    return MagicMock()\n\ndef test_create_models_config(mock_session):\n    # Arrange\n    provider = \"example_provider\"\n    api_key = \"example_api_key\"\n    org_id = 1\n    mock_session.query.return_value.filter_by.return_value.first.return_value = None\n\n    # Act\n    model_config = ModelsConfig(provider=provider, api_key=api_key, org_id=org_id)\n    mock_session.add(model_config)\n\n    # Assert\n    mock_session.add.assert_called_once_with(model_config)\n\ndef test_repr_method_models_config(mock_session):\n    # Arrange\n    provider = \"example_provider\"\n    api_key = \"example_api_key\"\n    org_id = 1\n    mock_session.query.return_value.filter_by.return_value.first.return_value = None\n\n    # Act\n    model_config = ModelsConfig(provider=provider, api_key=api_key, org_id=org_id)\n    model_config_repr = repr(model_config)\n\n    # Assert\n    assert model_config_repr == f\"ModelsConfig(id=None, provider={provider}, \" \\\n                                f\"org_id={org_id})\"\n\n# @patch('superagi.helper.encyption_helper.decrypt_data', return_value='decrypted_api_key')\n# @patch('superagi.helper.encyption_helper.encrypt_data', return_value='encrypted_api_key')\n# def test_store_api_key(mock_encrypt_data, mock_decrypt_data, mock_session):\n#     # Arrange\n#     organisation_id = 1\n#     model_provider = \"example_provider\"\n#     model_api_key = \"example_api_key\"\n#\n#     # Mock existing entry\n#     mock_existing_entry = MagicMock()\n#     mock_session.query.return_value.filter.return_value.first.return_value = mock_existing_entry\n#     # Call the method\n#     response = ModelsConfig.store_api_key(mock_session, organisation_id, model_provider, model_api_key)\n#\n#     # Assert\n#     mock_existing_entry.api_key = 'encrypted_api_key'\n#     mock_session.add.assert_called_once_with(mock_existing_entry)\n#     mock_session.commit.assert_called_once()\n#     assert response == {'message': 'The API key was successfully stored'}\n#\n#     # Mock new entry\n#     mock_session.query.return_value.filter.return_value.first.return_value = None\n#     # Call the method\n#     response = ModelsConfig.store_api_key(mock_session, organisation_id, model_provider, model_api_key)\n#\n#     # Assert\n#     # The new_entry is local to the store_api_key method, we cannot directly assert its properties.\n#     # But we can check if a new entry is added.\n#     mock_session.add.assert_called()\n#     mock_session.commit.assert_called()\n#     assert response == {'message': 'The API key was successfully stored'}\n\n# @patch('superagi.helper.encyption_helper.decrypt_data', return_value='decrypted_api_key')\n# def test_fetch_api_keys(mock_decrypt_data, mock_session):\n#     # Arrange\n#     organisation_id = 1\n#     # Mock api_key_info\n#     mock_session.query.return_value.filter.return_value.all.return_value = [(\"example_provider\", \"encrypted_api_key\")]\n#\n#     # Call the method\n#     api_keys = ModelsConfig.fetch_api_keys(mock_session, organisation_id)\n#\n#     # Assert\n#     assert api_keys == [{\"provider\": \"example_provider\", \"api_key\": \"decrypted_api_key\"}]\n#\n# @patch('superagi.helper.encyption_helper.decrypt_data', return_value='decrypted_api_key')\n# def test_fetch_api_key(mock_session):\n#     # Arrange\n#     organisation_id = 1\n#     model_provider = \"example_provider\"\n#     # Mock api_key_data\n#     mock_api_key_data = MagicMock()\n#     mock_api_key_data.id = 1\n#     mock_api_key_data.provider = \"provider\"\n#     mock_api_key_data.api_key = \"encrypted_api_key\"\n#     mock_session.query.return_value.filter.return_value.first.return_value = mock_api_key_data\n#\n#     # Call the method\n#     api_key = ModelsConfig.fetch_api_key(mock_session, organisation_id, model_provider)\n#\n#     # Assert\n#     assert api_key == [{'id': 1, 'provider': \"provider\", 'api_key': \"encrypted_api_key\"}]\n\ndef test_fetch_model_by_id(mock_session):\n    # Arrange\n    organisation_id = 1\n    model_provider_id = 1\n    # Mock model\n    mock_model = MagicMock()\n    mock_model.provider = 'some_provider'\n    mock_session.query.return_value.filter.return_value.first.return_value = mock_model\n\n    # Call the method\n    model = ModelsConfig.fetch_model_by_id(mock_session, organisation_id, model_provider_id)\n    assert model == {\"provider\": \"some_provider\"}\n\ndef test_fetch_model_by_id_marketplace(mock_session):\n    # Arrange\n    model_provider_id = 1\n    # Mock model\n    mock_model = MagicMock()\n    mock_model.provider = 'some_provider'\n    mock_session.query.return_value.filter.return_value.first.return_value = mock_model\n\n    # Call the method\n    model = ModelsConfig.fetch_model_by_id_marketplace(mock_session, model_provider_id)\n    assert model == {\"provider\": \"some_provider\"}"
  },
  {
    "path": "tests/unit_tests/models/test_project.py",
    "content": "from unittest.mock import create_autospec\n\nfrom sqlalchemy.orm import Session\nfrom superagi.models.project import Project\n\ndef test_find_by_org_id():\n    # Create a mock session\n    session = create_autospec(Session)\n\n    # Create a sample org ID\n    org_id = 123\n\n    # Create a mock project object to be returned by the session query\n    mock_project = Project(id=1, name=\"Test Project\", organisation_id=org_id, description=\"Project for testing\")\n\n    # Configure the session query to return the mock project\n    session.query.return_value.filter.return_value.first.return_value = mock_project\n\n    # Call the method under test\n    project = Project.find_by_org_id(session, org_id)\n\n    # Assert that the returned project object matches the mock project\n    assert project == mock_project\n\ndef test_find_by_id():\n    # Create a mock session\n    session = create_autospec(Session)\n\n    # Create a sample project ID\n    project_id = 123\n\n    # Create a mock project object to be returned by the session query\n    mock_project = Project(id=project_id, name=\"Test Project\", organisation_id=1, description=\"Project for testing\")\n\n    # Configure the session query to return the mock project\n    session.query.return_value.filter.return_value.first.return_value = mock_project\n\n    # Call the method under test\n    project = Project.find_by_id(session, project_id)\n\n    # Assert that the returned project object matches the mock project\n    assert project == mock_project"
  },
  {
    "path": "tests/unit_tests/models/test_tool.py",
    "content": "import pytest\nfrom unittest.mock import MagicMock, call\nfrom sqlalchemy.orm.exc import NoResultFound\nfrom superagi.models.tool import Tool\nfrom superagi.controllers.types.agent_with_config import AgentConfigInput\nfrom fastapi import HTTPException\nfrom typing import List\n\n@pytest.fixture\ndef mock_session():\n    session = MagicMock()\n    get_mock = MagicMock()\n    get_mock.side_effect = [MagicMock(), NoResultFound()]   # assuming 2nd tool won't be found\n    session.query.return_value.get = get_mock\n    return session\n\n\ndef test_get_invalid_tools(mock_session):\n    # Set up the mock session such that the second tool is not found\n    mock_session.query.return_value.get.side_effect = [MagicMock(), None]\n\n    # Call the get_invalid_tools method with tool_ids as [1, 2]\n    invalid_tool_ids = Tool.get_invalid_tools([1, 2], mock_session)\n\n    # Assert that the returned invalid tool IDs is as expected\n    assert invalid_tool_ids == [2]\n\n    # Assert that mock_session.query().get() was called with the correct arguments\n    calls = [call(Tool).get(1), call(Tool).get(2)]\n    mock_session.query.assert_has_calls(calls, any_order=True)\n\n\n\n"
  },
  {
    "path": "tests/unit_tests/models/test_tool_config.py",
    "content": "from unittest.mock import MagicMock, patch\n\nimport pytest\n\nfrom superagi.models.tool_config import ToolConfig\nfrom superagi.models.toolkit import Toolkit\n\n\n@pytest.fixture\ndef mock_session():\n    return MagicMock()\n\n\ndef test_add_or_update_existing_tool_config(mock_session):\n    # Arrange\n    toolkit_id = 1\n    key = \"example_key\"\n    value = \"example_value\"\n    existing_tool_config = ToolConfig(toolkit_id=toolkit_id, key=key, value=\"old_value\")\n    mock_session.query.return_value.filter_by.return_value.first.return_value = existing_tool_config\n\n    # Act\n    ToolConfig.add_or_update(mock_session, toolkit_id, key, value)\n\n    # Assert\n    assert existing_tool_config.value == value\n    mock_session.commit.assert_called_once()\n\n\ndef test_add_or_update_new_tool_config(mock_session):\n    # Arrange\n    toolkit_id = 1\n    key = \"example_key\"\n    value = \"example_value\"\n    mock_session.query.return_value.filter_by.return_value.first.return_value = None\n\n    # Act\n    ToolConfig.add_or_update(mock_session, toolkit_id, key, value)\n\n    # Assert\n    # mock_session.add.assert_called_once_with(ToolConfig(toolkit_id=toolkit_id, key=key, value=value))\n    mock_session.commit.assert_called_once()"
  },
  {
    "path": "tests/unit_tests/models/test_toolkit.py",
    "content": "from unittest.mock import MagicMock, patch, call,create_autospec,Mock\n\nimport pytest\n\nfrom superagi.models.organisation import Organisation\nfrom superagi.models.toolkit import Toolkit\nfrom superagi.models.tool import Tool\nfrom sqlalchemy.orm import Session\n\n@pytest.fixture\ndef mock_session():\n    return MagicMock()\n\n# Mocked tool\n@pytest.fixture\ndef mock_tool():\n    tool = MagicMock(spec=Tool)\n    tool.id = 1\n    return tool\n\n# Mocked session\n@pytest.fixture\ndef mock_session(mock_tool):\n    session = MagicMock()\n    query = session.query\n    query.return_value.filter.return_value.all.return_value = [mock_tool]\n    query.return_value.filter.return_value.first.return_value = mock_tool\n    return session\n\n# marketplace_url = \"http://localhost:8001\"\nmarketplace_url = \"https://app.superagi.com/api\"\n\n\ndef test_add_or_update_existing_toolkit(mock_session):\n    # Arrange\n    name = \"example_toolkit\"\n    description = \"Example toolkit description\"\n    show_toolkit = True\n    organisation_id = 1\n    tool_code_link = \"https://example.com/toolkit\"\n\n    existing_toolkit = Toolkit(\n        name=name,\n        description=\"Old description\",\n        show_toolkit=False,\n        organisation_id=organisation_id,\n        tool_code_link=\"https://old-link.com\"\n    )\n\n    mock_session.query.return_value.filter.return_value.first.return_value = existing_toolkit\n\n    # Act\n    result = Toolkit.add_or_update(mock_session, name, description, show_toolkit, organisation_id, tool_code_link)\n\n    # Assert\n    assert result == existing_toolkit\n    assert result.name == name\n    assert result.description == description\n    assert result.show_toolkit == show_toolkit\n    assert result.organisation_id == organisation_id\n    assert result.tool_code_link == tool_code_link\n    mock_session.add.assert_not_called()  # Make sure add was not called\n    mock_session.commit.assert_called_once()\n    mock_session.flush.assert_called_once()\n\n\ndef test_add_or_update_new_toolkit(mock_session):\n    # Arrange\n    name = \"example_toolkit\"\n    description = \"Example toolkit description\"\n    show_toolkit = True\n    organisation_id = 1\n    tool_code_link = \"https://example.com/toolkit\"\n\n    mock_session.query.return_value.filter.return_value.first.return_value = None\n\n    # Act\n    result = Toolkit.add_or_update(mock_session, name, description, show_toolkit, organisation_id, tool_code_link)\n\n    # Assert\n    assert isinstance(result, Toolkit)\n    assert result.name == name\n    assert result.description == description\n    assert result.show_toolkit == show_toolkit\n    assert result.organisation_id == organisation_id\n    assert result.tool_code_link == tool_code_link\n    mock_session.add.assert_called_once_with(result)\n    mock_session.commit.assert_called_once()\n    mock_session.flush.assert_called_once()\n\n\n\ndef test_fetch_marketplace_list_success():\n    # Arrange\n    page = 1\n    expected_response = [\n        {\n            \"id\": 1,\n            \"name\": \"ToolKit 1\",\n            \"description\": \"Description 1\"\n        },\n        {\n            \"id\": 2,\n            \"name\": \"ToolKit 2\",\n            \"description\": \"Description 2\"\n        }\n    ]\n\n    # Mock the requests.get method\n    with patch('requests.get') as mock_get:\n        mock_get.return_value.status_code = 200\n        mock_get.return_value.json.return_value = expected_response\n\n        # Act\n        result = Toolkit.fetch_marketplace_list(page)\n\n        # Assert\n        assert result == expected_response\n        mock_get.assert_called_once_with(\n            f\"{marketplace_url}/toolkits/marketplace/list/{str(page)}\",\n            headers={'Content-Type': 'application/json'},\n            timeout=10\n        )\n\ndef test_fetch_marketplace_detail_success():\n    # Arrange\n    search_str = \"search string\"\n    toolkit_name = \"tool kit name\"\n    expected_response = {\n        \"id\": 1,\n        \"name\": \"ToolKit 1\",\n        \"description\": \"Description 1\"\n    }\n\n    # Mock the requests.get method\n    with patch('requests.get') as mock_get:\n        mock_get.return_value.status_code = 200\n        mock_get.return_value.json.return_value = expected_response\n\n        # Act\n        result = Toolkit.fetch_marketplace_detail(search_str, toolkit_name)\n\n        # Assert\n        assert result == expected_response\n        mock_get.assert_called_once_with(\n            f\"{marketplace_url}/toolkits/marketplace/{search_str.replace(' ', '%20')}/{toolkit_name.replace(' ', '%20')}\",\n            headers={'Content-Type': 'application/json'},\n            timeout=10\n        )\n\ndef test_fetch_marketplace_detail_error():\n    # Arrange\n    search_str = \"search string\"\n    toolkit_name = \"tool kit name\"\n\n    # Mock the requests.get method to simulate an error response\n    with patch('requests.get') as mock_get:\n        mock_get.return_value.status_code = 500\n\n        # Act\n        result = Toolkit.fetch_marketplace_detail(search_str, toolkit_name)\n\n        # Assert\n        assert result is None\n        mock_get.assert_called_once_with(\n            f\"{marketplace_url}/toolkits/marketplace/{search_str.replace(' ', '%20')}/{toolkit_name.replace(' ', '%20')}\",\n            headers={'Content-Type': 'application/json'},\n            timeout=10\n        )\n\n\n\ndef test_get_toolkit_from_name_existing_toolkit(mock_session):\n    # Arrange\n    toolkit_name = \"example_toolkit\"\n    organisation = Organisation(id=1)\n    expected_toolkit = Toolkit(name=toolkit_name,organisation_id=organisation.id)\n\n    # Mock the session.query method\n    mock_session.query.return_value.filter_by.return_value.first.return_value = expected_toolkit\n\n    # Act\n    result = Toolkit.get_toolkit_from_name(mock_session, toolkit_name,organisation)\n\n    # Assert\n    assert result == expected_toolkit\n    mock_session.query.assert_called_once_with(Toolkit)\n    mock_session.query.return_value.filter_by.assert_called_once_with(name=toolkit_name,organisation_id=organisation.id)\n    mock_session.query.return_value.filter_by.return_value.first.assert_called_once()\n\ndef test_get_toolkit_from_name_nonexistent_toolkit(mock_session):\n    # Arrange\n    toolkit_name = \"nonexistent_toolkit\"\n\n    # Mock the session.query method to return None\n    mock_session.query.return_value.filter_by.return_value.first.return_value = None\n    organisation = Organisation(id=1)\n\n    # Act\n    result = Toolkit.get_toolkit_from_name(mock_session, toolkit_name,organisation)\n\n    # Assert\n    assert result is None\n    mock_session.query.assert_called_once_with(Toolkit)\n    mock_session.query.return_value.filter_by.assert_called_once_with(name=toolkit_name,organisation_id=organisation.id)\n    mock_session.query.return_value.filter_by.return_value.first.assert_called_once()\n\ndef test_get_toolkit_installed_details(mock_session):\n    # Arrange\n    marketplace_toolkits = [\n        {\"name\": \"Toolkit 1\"},\n        {\"name\": \"Toolkit 2\"},\n        {\"name\": \"Toolkit 3\"}\n    ]\n    organisation = Organisation(id=1)\n\n    installed_toolkits = [\n        Toolkit(name=\"Toolkit 1\"),\n        Toolkit(name=\"Toolkit 3\")\n    ]\n    mock_session.query.return_value.filter.return_value.all.return_value = installed_toolkits\n\n    # Act\n    result = Toolkit.get_toolkit_installed_details(mock_session, marketplace_toolkits, organisation)\n\n    # Assert\n    assert len(result) == 3\n    assert result[0][\"name\"] == \"Toolkit 1\"\n    assert result[0][\"is_installed\"] is True\n    assert result[1][\"name\"] == \"Toolkit 2\"\n    assert result[1][\"is_installed\"] is False\n    assert result[2][\"name\"] == \"Toolkit 3\"\n    assert result[2][\"is_installed\"] is True\n    mock_session.query.assert_called_once()\n    mock_session.query.return_value.filter.return_value.all.assert_called_once()\n\n# Test function\ndef test_fetch_tool_ids_from_toolkit(mock_tool, mock_session):\n    # Arranging\n    toolkit_ids = [1, 2, 3]\n    \n    # Act\n    result = Toolkit.fetch_tool_ids_from_toolkit(mock_session, toolkit_ids)\n\n    # Assert\n    assert result == [mock_tool.id for _ in toolkit_ids]\n\ndef test_get_tool_and_toolkit_arr_with_nonexistent_toolkit():\n    # Create a mock session\n    session = create_autospec(Session)\n\n    # Configure the session query to return None for toolkit\n    session.query.return_value.filter.return_value.first.return_value = None\n\n    # Call the method under test with a non-existent toolkit\n    agent_config_tools_arr = [\n        {\"name\": \"NonExistentToolkit\", \"tools\": [\"Tool1\", \"Tool2\"]},\n    ]\n\n    # Use a context manager to capture the raised exception and its message\n    with pytest.raises(Exception) as exc_info:\n        Toolkit.get_tool_and_toolkit_arr(session,1, agent_config_tools_arr)\n\n    # Assert that the expected error message is contained within the raised exception message\n    expected_error_message = \"One or more of the Tool(s)/Toolkit(s) does not exist.\"\n    assert expected_error_message in str(exc_info.value)\n"
  },
  {
    "path": "tests/unit_tests/models/test_vector_db_configs.py",
    "content": "import unittest\nfrom unittest.mock import Mock, patch\nfrom superagi.models.vector_db_configs import VectordbConfigs\n\nclass TestVectordbConfigs(unittest.TestCase):\n    def setUp(self):\n        self.session_mock = Mock()\n        self.vector_db_id_mock = 1\n        self.db_creds_mock = {\"key1\": \"value1\", \"key2\": \"value2\"}\n\n    @patch('superagi.models.vector_db_configs.VectordbConfigs')\n    def test_get_vector_db_config_from_db_id(self, model_mock):\n        vectordb_mock = Mock()\n        vectordb_mock.key = \"key1\"\n        vectordb_mock.value = \"value1\"\n        self.session_mock.query().filter().all.return_value = [vectordb_mock]\n        result = VectordbConfigs.get_vector_db_config_from_db_id(self.session_mock, self.vector_db_id_mock)\n        self.assertEqual(result, {\"key1\": \"value1\"})\n\n    @patch('superagi.models.vector_db_configs.VectordbConfigs')\n    def test_add_vector_db_config(self, model_mock):\n        VectordbConfigs.add_vector_db_config(self.session_mock, self.vector_db_id_mock, self.db_creds_mock)\n        self.assertEqual(self.session_mock.add.call_count, len(self.db_creds_mock))\n        self.assertTrue(self.session_mock.commit.called)\n  \n    @patch('superagi.models.vector_db_configs.VectordbConfigs')\n    def test_delete_vector_db_configs(self, model_mock):\n        VectordbConfigs.delete_vector_db_configs(self.session_mock, self.vector_db_id_mock)\n        self.assertTrue(self.session_mock.query(model_mock).filter(model_mock.vector_db_id == self.vector_db_id_mock).delete.called)\n        self.assertTrue(self.session_mock.commit.called)\n\nif __name__ == '__main__':\n    unittest.main()"
  },
  {
    "path": "tests/unit_tests/models/test_vector_db_indices.py",
    "content": "import unittest\nfrom unittest.mock import Mock, MagicMock, call\nfrom superagi.models.vector_db_indices import VectordbIndices\n\nclass TestVectordbIndices(unittest.TestCase):\n    def setUp(self):\n        self.mock_session = Mock()\n        self.query_mock = self.mock_session.query.return_value\n        self.filter_mock = self.query_mock.filter.return_value\n\n    def test_get_vector_index_from_id(self):\n        VectordbIndices.get_vector_index_from_id(self.mock_session, 1)\n        self.mock_session.query.assert_called_with(VectordbIndices)\n        self.filter_mock.first.assert_called_once()\n\n    def test_get_vector_indices_from_vectordb(self):\n        VectordbIndices.get_vector_indices_from_vectordb(self.mock_session, 1)\n        self.mock_session.query.assert_called_with(VectordbIndices)\n        self.filter_mock.all.assert_called_once()\n\n    def test_delete_vector_db_index(self):\n        VectordbIndices.delete_vector_db_index(self.mock_session, 1)\n        self.mock_session.query.assert_called_with(VectordbIndices)\n        self.filter_mock.delete.assert_called_once()\n        self.mock_session.commit.assert_called_once()\n\n    def test_add_vector_index(self):\n        VectordbIndices.add_vector_index(self.mock_session, 'test', 1, 100, 'active')\n        self.mock_session.add.assert_called_once()\n        self.mock_session.commit.assert_called_once()\n\n    def test_update_vector_index_state(self):\n        VectordbIndices.update_vector_index_state(self.mock_session, 1, 'inactive')\n        self.mock_session.query.assert_called_with(VectordbIndices)\n        self.filter_mock.first.assert_called_once()\n        self.mock_session.commit.assert_called_once()\n\nif __name__ == '__main__':\n    unittest.main()"
  },
  {
    "path": "tests/unit_tests/models/test_vector_dbs.py",
    "content": "import unittest\nfrom unittest.mock import Mock, patch\nfrom superagi.models.vector_dbs import Vectordbs\n\nclass TestVectordbs(unittest.TestCase):\n    def setUp(self):\n        # Create a mock sql session\n        self.mock_session = Mock()\n        # Create an object of Vectordbs for testing\n        self.test_vector_db = Vectordbs(name='test_db', db_type='test_db_type', organisation_id=1)\n\n    @patch('requests.get')\n    def test_fetch_marketplace_list(self, mock_get):\n        mock_response = Mock()\n        mock_response.status_code = 200\n        mock_response.json.return_value = [{'name': 'test_db'}]\n        mock_get.return_value = mock_response\n\n        # Assert that fetch_marketplace_list() returns the correct value\n        self.assertListEqual(Vectordbs.fetch_marketplace_list(), [{'name': 'test_db'}])\n\n    def test_get_vector_db_from_id(self):\n        self.mock_session.query.return_value.filter.return_value.first.return_value = self.test_vector_db\n        returned_db = Vectordbs.get_vector_db_from_id(self.mock_session, 1)\n        # Assert that the returned db is the same as the set up test_vector_db\n        self.assertEqual(returned_db, self.test_vector_db)\n\n    def test_get_vector_db_from_organisation(self):\n        self.mock_session.query.return_value.filter.return_value.all.return_value = [self.test_vector_db]\n        returned_db_list = Vectordbs.get_vector_db_from_organisation(self.mock_session, Mock(id=1))\n        # Assert that returned list of dbs contains the test_vector_db\n        self.assertIn(self.test_vector_db, returned_db_list)\n\n    def test_add_vector_db(self):\n        # Assert that new db name matches the created db\n        new_db = Vectordbs.add_vector_db(self.mock_session, 'test_db', 'test_db_type', Mock(id=1))\n        self.assertEqual(new_db.name, 'test_db')\n\n    def test_delete_vector_db(self):\n        Vectordbs.delete_vector_db(self.mock_session, 1)\n        # Assert that the session's delete method was called with the correct arguments\n        self.mock_session.query.assert_called_once_with(Vectordbs)\n        self.mock_session.query.return_value.filter.return_value.delete.assert_called_once()\n\nif __name__ == \"__main__\":\n    unittest.main()"
  },
  {
    "path": "tests/unit_tests/resource_manager/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/resource_manager/test_file_manager.py",
    "content": "import pytest\nfrom unittest.mock import Mock, patch\nfrom superagi.models.resource import Resource\nfrom superagi.helper.resource_helper import ResourceHelper\nfrom superagi.helper.s3_helper import S3Helper\nfrom superagi.lib.logger import logger\n\nfrom superagi.resource_manager.file_manager import FileManager\n\n@pytest.fixture\ndef resource_manager():\n    session_mock = Mock()\n    resource_manager = FileManager(session_mock)\n    #resource_manager.agent_id = 1  # replace with actual value\n    return resource_manager\n\n\ndef test_write_binary_file(resource_manager):\n    with patch.object(ResourceHelper, 'get_resource_path', return_value='test_path'), \\\n            patch.object(ResourceHelper, 'make_written_file_resource',\n                         return_value=Resource(name='test.png', storage_type='S3')), \\\n            patch.object(S3Helper, 'upload_file'), \\\n            patch.object(logger, 'info') as logger_mock:\n        result = resource_manager.write_binary_file('test.png', b'data')\n        assert result == \"Binary test.png saved successfully\"\n        logger_mock.assert_called_once_with(\"Binary test.png saved successfully\")\n\n\ndef test_write_file(resource_manager):\n    with patch.object(ResourceHelper, 'get_resource_path', return_value='test_path'), \\\n            patch.object(ResourceHelper, 'make_written_file_resource',\n                         return_value=Resource(name='test.txt', storage_type='S3')), \\\n            patch.object(S3Helper, 'upload_file'), \\\n            patch.object(logger, 'info') as logger_mock:\n        result = resource_manager.write_file('test.txt', 'content')\n        assert result == \"test.txt - File written successfully\"\n        logger_mock.assert_called_once_with(\"test.txt - File written successfully\")\n"
  },
  {
    "path": "tests/unit_tests/resource_manager/test_llama_document_creation.py",
    "content": "import pytest\nfrom unittest.mock import patch, MagicMock\nfrom superagi.resource_manager.resource_manager import ResourceManager\n\n\ndef test_create_llama_document_s3(mocker):\n    agent_id = 'test_agent'\n    resource_manager = ResourceManager(agent_id)\n\n    mock_boto_client = MagicMock()\n    mock_s3_obj = {\n        'Body': MagicMock(read=MagicMock(return_value='mock_file_content'))\n    }\n    mock_boto_client.get_object.return_value = mock_s3_obj\n    mocker.patch('boto3.client', return_value=mock_boto_client)\n\n    mocker.patch('superagi.resource_manager.resource_manager.get_config',\n                 side_effect=['mock_access_key', 'mock_secret_key', 'mock_bucket'])\n\n    mocker.patch('builtins.open', mocker.mock_open())\n    mocker.patch('os.remove')\n\n    MockSimpleDirectoryReader = MagicMock()\n    mocker.patch('superagi.resource_manager.resource_manager.SimpleDirectoryReader',\n                 return_value=MockSimpleDirectoryReader)\n\n    resource_manager.create_llama_document_s3('mock_file_path')\n\n    mock_boto_client.get_object.assert_called_once_with(\n        Bucket='mock_bucket',\n        Key='mock_file_path')\n    MockSimpleDirectoryReader.load_data.assert_called_once()\n\n\ndef test_create_llama_document_s3_file_path_provided(mocker):\n    resource_manager = ResourceManager('test_agent')\n\n    mock_boto_client = MagicMock()\n    mocker.patch('boto3.client', return_value=mock_boto_client)\n\n    mocker.patch('superagi.resource_manager.resource_manager.get_config',\n                 side_effect=['mock_access_key', 'mock_secret_key', 'mock_bucket'])\n\n    mocker.patch('builtins.open', mocker.mock_open())\n    mocker.patch('os.remove')\n\n    MockSimpleDirectoryReader = MagicMock()\n    mocker.patch('superagi.resource_manager.resource_manager.SimpleDirectoryReader',\n                 return_value=MockSimpleDirectoryReader)\n\n    with pytest.raises(Exception, match=\"file_path must be provided\"):\n        resource_manager.create_llama_document_s3(None)"
  },
  {
    "path": "tests/unit_tests/resource_manager/test_llama_vector_store_factory.py",
    "content": "import pytest\nfrom unittest.mock import patch\n\nfrom llama_index.vector_stores import PineconeVectorStore, RedisVectorStore\n\nfrom superagi.resource_manager.llama_vector_store_factory import LlamaVectorStoreFactory\nfrom superagi.types.vector_store_types import VectorStoreType\n\n\ndef test_llama_vector_store_factory():\n    # Mocking method arguments\n    vector_store_name = VectorStoreType.PINECONE\n    index_name = \"test_index_name\"\n    factory = LlamaVectorStoreFactory(vector_store_name, index_name)\n\n    # Test case for VectorStoreType.PINECONE\n    with patch.object(PineconeVectorStore, \"__init__\", return_value=None):\n        vector_store = factory.get_vector_store()\n        assert isinstance(vector_store, PineconeVectorStore)\n\n    # Test case for VectorStoreType.REDIS\n    factory.vector_store_name = VectorStoreType.REDIS\n    with patch.object(RedisVectorStore, \"__init__\", return_value=None), \\\n            patch('superagi.config.config.get_config', return_value=None):\n        vector_store = factory.get_vector_store()\n        assert isinstance(vector_store, RedisVectorStore)\n\n    # Test case for unknown VectorStoreType\n    factory.vector_store_name = \"unknown\"\n    with pytest.raises(ValueError) as exc_info:\n        factory.get_vector_store()\n    assert str(exc_info.value) == \"unknown vector store is not supported yet.\""
  },
  {
    "path": "tests/unit_tests/resource_manager/test_save_document_to_vector_store.py",
    "content": "from unittest.mock import patch, Mock\nfrom llama_index import VectorStoreIndex, StorageContext, Document\nfrom superagi.resource_manager.resource_manager import ResourceManager\nfrom superagi.resource_manager.llama_vector_store_factory import LlamaVectorStoreFactory\n\n\n@patch.object(LlamaVectorStoreFactory, 'get_vector_store')\n@patch.object(StorageContext, 'from_defaults')\n@patch.object(VectorStoreIndex, 'from_documents')\ndef test_save_document_to_vector_store(mock_vc_from_docs, mock_sc_from_defaults, mock_get_vector_store):\n    # Prepare test resources\n    mock_vector_store = Mock()\n    mock_get_vector_store.return_value = mock_vector_store\n    mock_sc_from_defaults.return_value = \"mock_storage_context\"\n    mock_vc_from_docs.return_value = \"mock_index\"\n\n    resource_manager = ResourceManager(\"test_agent_id\")\n    documents = [Document(text=\"doc1\"), Document(text=\"doc2\")]\n    resource_id = \"test_resource_id\"\n\n    # Run test method\n    resource_manager.save_document_to_vector_store(documents, resource_id, \"test_model_api_key\")\n\n    # Validate calls\n    mock_get_vector_store.assert_called_once()\n    mock_sc_from_defaults.assert_called_once_with(vector_store=mock_vector_store)\n    mock_vc_from_docs.assert_called_once_with(documents, storage_context=\"mock_storage_context\")\n\n    # Add more assertions here if needed, e.g., to check side effects\n    mock_vector_store.persist.assert_called_once()"
  },
  {
    "path": "tests/unit_tests/test_migrations_multiheads.py",
    "content": "import glob\nimport os\nimport re\nimport pytest\nfrom collections import Counter\n\n\ndef test_alembic_down_revision():\n    # Construct the path to the versions directory\n    versions_dir = os.path.join('.', 'migrations', 'versions')\n\n    # Get all .py files in versions directory\n    all_py_files = glob.glob(os.path.join(versions_dir, \"*.py\"))\n\n    # Regex pattern for finding down_revision lines in .py files\n    down_revision_pattern = re.compile(r'down_revision = \\'(\\w+)\\'')\n\n    down_revisions = []\n    file_down_revisions = []\n\n    for file in all_py_files:\n        with open(file) as f:\n            content = f.read()\n            match = down_revision_pattern.search(content)\n            if match:\n                down_revisions.append(match.group(1))\n                file_down_revisions.append((file, match.group(1)))\n\n    counter = Counter(down_revisions)\n\n    duplicates = [item for item, count in counter.items() if count > 1]\n    # get the files that have duplicate down revisions\n    files_with_duplicates = [file for file, down_revision in file_down_revisions if down_revision in duplicates]\n\n    assert len(duplicates) == 0, f\"Duplicate down revisions found in files: {files_with_duplicates} \\n this is \" \\\n                                 f\"caused because a newer migration might have been added after the migration \" \\\n                                 f\"you added. Please fix this by changing the down_revision to the correct one.\"\n"
  },
  {
    "path": "tests/unit_tests/test_tool_manager.py",
    "content": "import json\nimport os\nimport shutil\nimport tempfile\nfrom unittest.mock import Mock, patch\n\nimport pytest\n\nfrom superagi.tool_manager import parse_github_url, download_tool, load_tools_config, download_and_extract_tools, \\\n    update_tools_json\n\n\n@pytest.fixture\ndef tools_json_path():\n    # Create a temporary directory and return the path to the tools.json file\n    with tempfile.TemporaryDirectory() as temp_dir:\n        yield os.path.join(temp_dir, \"tools.json\")\n\n\ndef test_parse_github_url():\n    url = 'https://github.com/owner/repo'\n    assert parse_github_url(url) == 'owner/repo/main'\n\n\ndef setup_function():\n    os.makedirs('target_folder', exist_ok=True)\n\n\n# Teardown function to remove the directory\ndef teardown_function():\n    shutil.rmtree('target_folder')\n\n\n@patch('requests.get')\n@patch('zipfile.ZipFile')\ndef test_download_tool(mock_zip, mock_get):\n    mock_response = Mock()\n    mock_response.content = b'file content'\n    mock_get.return_value = mock_response\n    mock_zip.return_value.__enter__.return_value.namelist.return_value = ['owner-repo/somefile.txt']\n\n    download_tool('https://github.com/owner/repo', 'target_folder')\n\n    mock_get.assert_called_once_with('https://api.github.com/repos/owner/repo/zipball/main')\n    mock_zip.assert_called_once_with('target_folder/tool.zip', 'r')\n\n\n@patch('json.load')\ndef test_load_tools_config(mock_json_load):\n    mock_json_load.return_value = {\"tools\": {\"tool1\": \"url1\", \"tool2\": \"url2\"}}\n\n    config = load_tools_config()\n    assert config == {\"tool1\": \"url1\", \"tool2\": \"url2\"}\n\n\n@patch('superagi.tool_manager.download_tool')\n@patch('superagi.tool_manager.load_tools_config')\ndef test_download_and_extract_tools(mock_load_tools_config, mock_download_tool):\n    mock_load_tools_config.return_value = {\"tool1\": \"url1\", \"tool2\": \"url2\"}\n    download_and_extract_tools()\n\n    mock_load_tools_config.assert_called_once()\n    mock_download_tool.assert_any_call('url1', os.path.join('superagi', 'tools', 'external_tools', 'tool1'))\n    mock_download_tool.assert_any_call('url2', os.path.join('superagi', 'tools', 'external_tools', 'tool2'))\n\n\ndef test_update_tools_json(tools_json_path):\n    # Create an initial tools.json file with some data\n    initial_data = {\n        \"tools\": {\n            \"tool1\": \"link1\",\n            \"tool2\": \"link2\"\n        }\n    }\n    with open(tools_json_path, \"w\") as file:\n        json.dump(initial_data, file)\n\n    # Define the folder links to be updated\n    folder_links = {\n        \"tool3\": \"link3\",\n        \"tool4\": \"link4\"\n    }\n\n    # Call the function to update the tools.json file\n    update_tools_json(tools_json_path, folder_links)\n\n    # Read the updated tools.json file\n    with open(tools_json_path, \"r\") as file:\n        updated_data = json.load(file)\n\n    # Assert that the data was updated correctly\n    expected_data = {\n        \"tools\": {\n            \"tool1\": \"link1\",\n            \"tool2\": \"link2\",\n            \"tool3\": \"link3\",\n            \"tool4\": \"link4\"\n        }\n    }\n    assert updated_data == expected_data\n"
  },
  {
    "path": "tests/unit_tests/tools/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/tools/code/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/tools/code/test_improve_code.py",
    "content": "import pytest\nfrom unittest.mock import Mock, MagicMock\nfrom superagi.tools.code.improve_code import ImproveCodeTool\n\n@pytest.fixture\ndef mock_improve_code_tool():\n    improve_code_tool = ImproveCodeTool()\n    improve_code_tool.resource_manager = Mock()\n    improve_code_tool.llm = Mock()\n    return improve_code_tool\n\ndef test_execute(mock_improve_code_tool):\n    mock_improve_code_tool.resource_manager.get_files.return_value = ['test1', 'test2']\n    mock_improve_code_tool.resource_manager.read_file.return_value = \"test file content\"\n    mock_improve_code_tool.llm.chat_completion.return_value = {\n        \"response\":\n            {\n                \"choices\":\n                    [\n                        {\n                            \"message\":\n                                {\n                                    \"content\": \"```\\nimproved code\\n```\"\n                                }\n                        }\n                    ]\n            }\n    }\n    mock_improve_code_tool.resource_manager.write_file.return_value = \"file saved successfully\"\n\n    assert mock_improve_code_tool._execute() == \"All codes improved and saved successfully in: test1 test2\"\n\ndef test_execute_with_error(mock_improve_code_tool):\n    mock_improve_code_tool.resource_manager.get_files.return_value = ['test1']\n    mock_improve_code_tool.resource_manager.read_file.return_value = \"test file content\"\n    mock_improve_code_tool.llm.chat_completion.return_value = {\n        \"response\":\n            {\n                \"choices\":\n                    [\n                        {\n                            \"message\":\n                                {\n                                    \"content\": \"```\\nimproved code\\n```\"\n                                }\n                        }\n                    ]\n            }\n    }\n    mock_improve_code_tool.resource_manager.write_file.return_value = \"Error: Could not save file\"\n\n    assert mock_improve_code_tool._execute() == \"Error: Could not save file\"\n"
  },
  {
    "path": "tests/unit_tests/tools/code/test_write_code.py",
    "content": "from unittest.mock import Mock\n\nimport pytest\n\nfrom superagi.resource_manager.file_manager import FileManager\nfrom superagi.tools.code.write_code import CodingTool\nfrom superagi.tools.tool_response_query_manager import ToolResponseQueryManager\nfrom unittest.mock import MagicMock\n\n\nclass MockBaseLlm:\n    def chat_completion(self, messages, max_tokens):\n        return {\"content\": \"File1.py\\n```python\\nprint('Hello World')\\n```\\n\\nFile2.py\\n```python\\nprint('Hello again')\\n```\"}\n\n    def get_model(self):\n        return \"gpt-3.5-turbo\"\n\nclass TestCodingTool:\n\n    @pytest.fixture\n    def tool(self):\n        tool = CodingTool()\n        tool.llm = MockBaseLlm()\n        tool.resource_manager = Mock(spec=FileManager)\n        tool.tool_response_manager = Mock(spec=ToolResponseQueryManager)\n        mock_session = MagicMock(name=\"session\")\n        tool.toolkit_config.session = mock_session\n        return tool\n\n    def test_execute(self, tool):\n        tool.resource_manager.write_file.return_value = \"File write successful\"\n        tool.tool_response_manager.get_last_response.return_value = \"Mocked Spec\"\n\n        response = tool._execute(\"Test spec description\")\n        assert response == \"File1.py\\n```python\\nprint('Hello World')\\n```\\n\\nFile2.py\\n```python\\nprint('Hello again')\\n```\\n Codes generated and saved successfully in File1.py, File2.py\"\n\n        tool.resource_manager.write_file.assert_any_call(\"README.md\", 'File1.py\\n')\n        tool.resource_manager.write_file.assert_any_call(\"File1.py\", \"print('Hello World')\\n\")\n        tool.resource_manager.write_file.assert_any_call(\"File2.py\", \"print('Hello again')\\n\")\n        tool.tool_response_manager.get_last_response.assert_called_once_with(\"WriteSpecTool\")"
  },
  {
    "path": "tests/unit_tests/tools/code/test_write_spec.py",
    "content": "from unittest.mock import Mock\n\nimport pytest\n\nfrom superagi.tools.code.write_spec import WriteSpecTool\nfrom unittest.mock import MagicMock\n\n\nclass MockBaseLlm:\n    def chat_completion(self, messages, max_tokens):\n        return {\"content\": \"Generated specification\"}\n\n    def get_model(self):\n        return \"gpt-3.5-turbo\"\n\nclass TestWriteSpecTool:\n\n    @pytest.fixture\n    def tool(self):\n        tool = WriteSpecTool()\n        tool.llm = MockBaseLlm()\n        tool.resource_manager = Mock()\n        mock_session = MagicMock(name=\"session\")\n        tool.toolkit_config.session = mock_session\n        return tool\n\n    def test_execute(self, tool):\n        tool.resource_manager.write_file = Mock()\n        tool.resource_manager.write_file.return_value = \"File write successful\"\n        response = tool._execute(\"Test task description\", \"test_spec_file.txt\")\n        assert response == \"Generated specification\\nSpecification generated and saved successfully\"\n        tool.resource_manager.write_file.assert_called_once_with(\"test_spec_file.txt\", \"Generated specification\")\n"
  },
  {
    "path": "tests/unit_tests/tools/code/test_write_test.py",
    "content": "from unittest.mock import Mock, patch\n\nfrom superagi.tools.code.write_test import WriteTestTool\nfrom unittest.mock import MagicMock\n\n\ndef test_write_test_tool_init():\n    tool = WriteTestTool()\n    assert tool.llm is None\n    assert tool.agent_id is None\n    assert tool.name == \"WriteTestTool\"\n    assert tool.description is not None\n    assert tool.goals == []\n    assert tool.resource_manager is None\n\n@patch('superagi.tools.code.write_test.PromptReader')\n@patch('superagi.tools.code.write_test.AgentPromptBuilder')\n@patch('superagi.tools.code.write_test.TokenCounter')\ndef test_execute(mock_token_counter, mock_agent_prompt_builder, mock_prompt_reader):\n    test_tool = WriteTestTool()\n    test_tool.tool_response_manager = Mock()\n    test_tool.resource_manager = Mock()\n    test_tool.llm = Mock()\n    mock_session = MagicMock(name=\"session\")\n    test_tool.toolkit_config.session = mock_session\n\n    test_tool.tool_response_manager.get_last_response.return_value = 'WriteSpecTool response'\n    mock_prompt_reader.read_tools_prompt.return_value = 'Prompt template {goals} {test_description} {spec}'\n    mock_agent_prompt_builder.add_list_items_to_string.return_value = 'Goals string'\n    test_tool.llm.get_model.return_value = 'Model'\n    mock_token_counter.count_message_tokens.return_value = 100\n    mock_token_counter.token_limit.return_value = 1000\n    test_tool.llm.chat_completion.return_value = {\n        'content': 'File1\\n```\\nCode1```File2\\n```\\nCode2```',\n    }\n    test_tool.resource_manager.write_file.return_value = 'Success'\n\n    result = test_tool._execute('Test description', 'test_file.py')\n\n    assert 'File1' in result\n    assert 'Code1' in result\n    assert 'File2' in result\n    assert 'Code2' in result\n    assert 'Tests generated and saved successfully in test_file.py' in result\n\n    mock_prompt_reader.read_tools_prompt.assert_called_once()\n    mock_agent_prompt_builder.add_list_items_to_string.assert_called_once_with(test_tool.goals)\n    test_tool.tool_response_manager.get_last_response.assert_called()\n    test_tool.llm.get_model.assert_called()\n    mock_token_counter.count_message_tokens.assert_called()\n    mock_token_counter().token_limit.assert_called()\n    test_tool.llm.chat_completion.assert_called()\n    assert test_tool.resource_manager.write_file.call_count == 2"
  },
  {
    "path": "tests/unit_tests/tools/duck_duck_go/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/tools/duck_duck_go/test_duckduckgo_results.py",
    "content": "import unittest\nfrom unittest.mock import patch\nimport pytest\nfrom superagi.tools.duck_duck_go.duck_duck_go_search import DuckDuckGoSearchTool\n\nclass TestDuckDuckGoSearchTool:\n    def setup_method(self):\n        self.your_obj = DuckDuckGoSearchTool()  # Create an instance of DuckDuckGoSearchTool\n\n    def test_get_raw_duckduckgo_results_empty_query(self):\n        query = \"\"\n        expected_result = \"[]\"\n        result = self.your_obj.get_raw_duckduckgo_results(query)\n        assert result == expected_result\n\n    @patch('superagi.tools.duck_duck_go.duck_duck_go_search.DuckDuckGoSearchTool.get_raw_duckduckgo_results')\n    def test_get_raw_duckduckgo_results_valid_query(self, mock_get_raw_duckduckgo_results):\n        query = \"python\"\n        expected_result_length = 10\n        mock_results = ['result1', 'result2', 'result3', 'result4', 'result5',\n                        'result6', 'result7', 'result8', 'result9', 'result10']\n        mock_get_raw_duckduckgo_results.return_value = mock_results\n        result = self.your_obj.get_raw_duckduckgo_results(query)\n        assert len(result) == expected_result_length\n\n    def test_get_formatted_webpages(self):\n        search_results = [\n            {\"title\": \"Result 1\", \"href\": \"https://example.com/1\"},\n            {\"title\": \"Result 2\", \"href\": \"https://example.com/2\"},\n            {\"title\": \"Result 3\", \"href\": \"https://example.com/3\"},\n        ]\n        webpages = [\"Webpage 1\", \"Webpage 2\", \"Webpage 3\"]\n\n        expected_results = [\n            {\"title\": \"Result 1\", \"body\": \"Webpage 1\", \"links\": \"https://example.com/1\"},\n            {\"title\": \"Result 2\", \"body\": \"Webpage 2\", \"links\": \"https://example.com/2\"},\n            {\"title\": \"Result 3\", \"body\": \"Webpage 3\", \"links\": \"https://example.com/3\"},\n        ]\n\n        results = self.your_obj.get_formatted_webpages(search_results, webpages)\n        assert results == expected_results\n\n    def test_get_content_from_url_with_empty_links(self):\n        links = []\n        expected_webpages = []\n\n        webpages = self.your_obj.get_content_from_url(links)\n        assert webpages == expected_webpages\n\n    def test_get_formatted_webpages_with_empty_webpages(self):\n        search_results = [\n            {\"title\": \"Result 1\", \"href\": \"https://example.com/1\"},\n            {\"title\": \"Result 2\", \"href\": \"https://example.com/2\"},\n            {\"title\": \"Result 3\", \"href\": \"https://example.com/3\"},\n        ]\n        webpages = []\n        expected_results = []\n\n        results = self.your_obj.get_formatted_webpages(search_results, webpages)\n        assert results == expected_results\n"
  },
  {
    "path": "tests/unit_tests/tools/duck_duck_go/test_duckduckgo_toolkit.py",
    "content": "import pytest\nfrom superagi.tools.duck_duck_go.duck_duck_go_search_toolkit import DuckDuckGoToolkit\nfrom superagi.tools.duck_duck_go.duck_duck_go_search import DuckDuckGoSearchTool\n\nclass TestDuckDuckGoSearchToolKit:\n    def setup_method(self):\n        \"\"\"\n        Set up the test fixture.\n\n        This method is called before each test method is executed to prepare the test environment.\n\n        Returns:\n            None\n        \"\"\"\n        self.toolkit = DuckDuckGoToolkit()\n\n    def test_get_tools(self):\n        \"\"\"\n        Test the `get_tools` method of the `DuckDuckGoToolkit` class.\n\n        It should return a list of tools, containing one instance of `DuckDuckGoSearchTool`.\n\n        Returns:\n            None\n        \"\"\"\n        tools = self.toolkit.get_tools()\n        assert len(tools) == 1\n        assert isinstance(tools[0], DuckDuckGoSearchTool)\n\n    def test_get_env_keys(self):\n        \"\"\"\n        Test the `get_env_keys` method of the `DuckDuckGoToolkit` class.\n\n        It should return an empty list of environment keys.\n\n        Returns:\n            None\n        \"\"\"\n        env_keys = self.toolkit.get_env_keys()\n        assert len(env_keys) == 0\n"
  },
  {
    "path": "tests/unit_tests/tools/email/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/tools/email/test_read_email.py",
    "content": "from unittest.mock import patch, Mock\n\nfrom superagi.tools.email.read_email import ReadEmailTool\n\n\n@patch('superagi.tools.email.read_email.ImapEmail')\n@patch('superagi.tools.email.read_email.ReadEmail')\ndef test_execute(mock_read_email, mock_imap_email):\n    # Configure the mock objects\n    mock_conn = Mock()\n    mock_conn.select.return_value = ('OK', ['10'])  # assume 10 messages in INBOX\n    mock_conn.fetch.return_value = ('OK', [(b'1 (RFC822 {337}', b'Some email content')])\n    mock_imap_email.return_value.imap_open.return_value = mock_conn\n    mock_read_email.return_value.obtain_header.return_value = ('From', 'To', 'Date', 'Subject')\n    mock_read_email.return_value.clean_email_body.return_value = 'Cleaned email body'\n\n    # Set up ReadEmailTool object\n    tool = ReadEmailTool()\n    tool.toolkit_config.get_tool_config = Mock()\n    tool.toolkit_config.get_tool_config.return_value = 'dummy_value'\n\n    # Call the function\n    result = tool._execute()\n\n    # Check the results\n    assert len(result) == 5  # check that one email was processed\n    assert result[0]['From'] == 'From'\n    assert result[0]['To'] == 'To'\n    assert result[0]['Date'] == 'Date'\n    assert result[0]['Subject'] == 'Subject'\n    assert result[0]['Message Body'] == 'Cleaned email body'\n"
  },
  {
    "path": "tests/unit_tests/tools/email/test_send_email.py",
    "content": "from unittest.mock import patch, MagicMock\n\nfrom superagi.tools.email.send_email import SendEmailTool\n\n\ndef mock_get_tool_config(key):\n    configs = {\n        'EMAIL_ADDRESS': 'sender@example.com',\n        'EMAIL_PASSWORD': 'password',\n        'EMAIL_SIGNATURE': '',\n        'EMAIL_DRAFT_MODE': 'False',\n        'EMAIL_DRAFT_FOLDER': 'Drafts',\n        'EMAIL_IMAP_SERVER': 'imap.example.com',\n        'EMAIL_SMTP_HOST': 'host',\n        'EMAIL_SMTP_PORT': 'port',\n    }\n    return configs.get(key)\n\ndef mock_get_draft_tool_config(key):\n    configs = {\n        'EMAIL_ADDRESS': 'sender@example.com',\n        'EMAIL_PASSWORD': 'password',\n        'EMAIL_SIGNATURE': '',\n        'EMAIL_DRAFT_MODE': 'True',\n        'EMAIL_DRAFT_FOLDER': 'Drafts',\n        'EMAIL_IMAP_SERVER': 'imap.example.com',\n        'EMAIL_SMTP_HOST': 'host',\n        'EMAIL_SMTP_PORT': 'port',\n    }\n    return configs.get(key)\n\n\n@patch('smtplib.SMTP')\n@patch('superagi.helper.imap_email.ImapEmail.imap_open')\ndef test_execute_sends_email(mock_imap_open, mock_smtp):\n    # Given\n    send_email_tool = SendEmailTool()\n    mock_resp = MagicMock()\n    mock_resp.raise_for_status.return_value = None\n    mock_resp.json.return_value = 'data'\n\n    send_email_tool.toolkit_config.get_tool_config = mock_get_tool_config\n\n    # When\n    result = send_email_tool._execute('receiver@example.com', 'test subject', 'test body')\n\n    # Then\n    assert result == 'Email was sent to receiver@example.com'\n    mock_smtp.assert_called_once_with('host', 'port')\n\n\n@patch('smtplib.SMTP')\n@patch('superagi.helper.imap_email.ImapEmail.imap_open')\ndef test_execute_sends_email_to_draft(mock_imap_open, mock_smtp):\n    send_email_tool = SendEmailTool()\n    send_email_tool.toolkit_config.get_tool_config = mock_get_draft_tool_config\n\n    result = send_email_tool._execute('receiver@example.com', 'test subject', 'test body')\n\n    assert result == 'Email went to Drafts'\n    mock_imap_open.assert_called_once_with('Drafts', 'sender@example.com', 'password', 'imap.example.com')\n    mock_imap_instance = mock_imap_open.return_value\n    mock_imap_instance.append.assert_called_once()\n    mock_smtp.assert_not_called()"
  },
  {
    "path": "tests/unit_tests/tools/email/test_send_email_attachment.py",
    "content": "# import unittest\n# from unittest.mock import patch, MagicMock, ANY\n# from superagi.models.agent import Agent\n# import os\n# from superagi.tools.email.send_email_attachment import SendEmailAttachmentTool, SendEmailAttachmentInput\n# import tempfile\n\n# class TestSendEmailAttachmentTool(unittest.TestCase):\n#     # Create a new class-level test file\n#     testFile = tempfile.NamedTemporaryFile(delete=True)\n\n#     @patch(\"superagi.models.agent.Agent.get_agent_from_id\")\n#     @patch(\"superagi.tools.email.send_email_attachment.SendEmailAttachmentTool.send_email_with_attachment\")\n#     @patch(\"superagi.helper.resource_helper.ResourceHelper.get_agent_read_resource_path\")\n#     @patch(\"superagi.helper.resource_helper.ResourceHelper.get_root_input_dir\")\n#     @patch(\"os.path.exists\", return_value=os.path.exists(testFile.name))\n#     @patch(\"superagi.helper.s3_helper.S3Helper.read_binary_from_s3\")\n#     def test__execute(self, mock_s3_file_read, mock_exists, mock_get_root_input_dir, mock_get_agent_resource_path,\n#                       mock_send_email_with_attachment, mock_get_agent_from_id):\n\n#         # Arrange\n#         tool = SendEmailAttachmentTool()\n#         tool.agent_id = 1\n#         mock_get_agent_resource_path.return_value = self.testFile.name\n#         mock_get_root_input_dir.return_value = \"/root_dir/\"\n#         mock_send_email_with_attachment.return_value = \"Email sent\"\n#         expected_result = \"Email sent\"\n#         mock_get_agent_from_id.return_value = Agent(id=1, name='Test Agent')\n#         tool.agent_execution_id = 1\n#         tool.toolkit_config.session = MagicMock()\n#         mock_s3_file_read.return_value = b\"file contents\"\n\n#         # Act\n#         result = tool._execute(\"test@example.com\", \"test subject\", \"test body\", \"test.txt\")\n\n#         # Assert\n#         self.assertEqual(result, expected_result)\n#         mock_send_email_with_attachment.assert_called_once_with(\"test@example.com\", \"test subject\", \"test body\", ANY)\n#         mock_s3_file_read.assert_called_once_with(self.testFile.name)\n\n# if __name__ == \"__main__\":\n#     unittest.main()\n"
  },
  {
    "path": "tests/unit_tests/tools/file/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/tools/file/test_list_files.py",
    "content": "from unittest.mock import MagicMock, patch\n\nimport pytest\n\nfrom superagi.tools.file.list_files import ListFileTool\n\n\n@pytest.fixture\ndef list_file_tool():\n    list_file_tool = ListFileTool()\n    list_file_tool.agent_id = 1  # Set a dummy agent ID for testing.\n    # list_file_tool = \"test_agent\"\n    mock_session = MagicMock(name=\"session\")\n    list_file_tool.toolkit_config.session = mock_session\n\n    yield list_file_tool\n\ndef test_list_files(list_file_tool):\n    with patch('os.walk') as mock_walk:\n        mock_walk.return_value = [\n            ('/path/to', ('subdir',), ('file1.txt', '.file2.txt')),\n            ('/path/to/subdir', (), ('file3.txt', 'file4.txt'))\n        ]\n\n        files = list_file_tool.list_files('/path/to')\n\n    assert files == ['file1.txt', 'file3.txt', 'file4.txt']\n\ndef test_execute(list_file_tool):\n    mock_get_formatted_agent_level_path = MagicMock(return_value=\"SuperAGI/workspace/input/{agent_id}/\")\n\n    with patch.object(ListFileTool, 'list_files', return_value=['file1.txt', 'file2.txt']), \\\n         patch('superagi.helper.resource_helper.ResourceHelper.get_formatted_agent_level_path', new=mock_get_formatted_agent_level_path):\n\n        files = list_file_tool._execute()\n\n    assert files == ['file1.txt', 'file2.txt']"
  },
  {
    "path": "tests/unit_tests/tools/file/test_read_file.py",
    "content": "import os\nimport pytest\nimport tempfile\nfrom unittest.mock import MagicMock, patch\nfrom superagi.tools.file.read_file import ReadFileTool  \n\nfrom superagi.models.agent_execution import AgentExecution\nfrom superagi.tools.file.read_file import ReadFileTool\nfrom superagi.models.agent import Agent\n\n@pytest.fixture\ndef mock_os_path_exists():\n    with patch(\"os.path.exists\") as mock_exists:\n        yield mock_exists\n\n@pytest.fixture\ndef mock_os_makedirs():\n    with patch(\"os.makedirs\") as mock_makedirs:\n        yield mock_makedirs\n\n@pytest.fixture\ndef mock_get_config():\n    with patch(\"superagi.config.config.get_config\") as mock_get_config:\n        yield mock_get_config\n\n\n@pytest.fixture\ndef read_file_tool():\n    read_file_tool = ReadFileTool()\n    read_file_tool.agent_id = 1  # Set a dummy agent ID for testing.\n\n@pytest.fixture\ndef mock_s3_helper():\n    with patch(\"superagi.helper.s3_helper.S3Helper\") as mock_s3_helper:\n        yield mock_s3_helper\n\n@pytest.fixture\ndef mock_partition():\n    with patch(\"unstructured.partition.auto.partition\") as mock_partition:\n        yield mock_partition\n\n@pytest.fixture\ndef mock_get_agent_from_id():\n    with patch(\"superagi.models.agent.Agent.get_agent_from_id\") as mock_get_agent:\n        yield mock_get_agent\n\n@pytest.fixture\ndef mock_get_agent_execution_from_id():\n    with patch(\"superagi.models.agent_execution.AgentExecution.get_agent_execution_from_id\") as mock_execution:\n        yield mock_execution\n@pytest.fixture\ndef mock_resource_helper():\n    with patch(\"superagi.helper.resource_helper.ResourceHelper.get_agent_read_resource_path\") as mock_resource_helper:\n        yield mock_resource_helper\n\ndef test_read_file_tool(mock_os_path_exists, mock_os_makedirs, mock_get_config, mock_s3_helper, mock_partition,\n                        mock_get_agent_from_id, mock_get_agent_execution_from_id, mock_resource_helper):\n    mock_os_path_exists.return_value = True\n    mock_partition.return_value = [\"This is a file.\", \"This is the second line.\"]\n    mock_get_config.return_value = \"FILE\"\n    mock_get_agent_from_id.return_value = MagicMock()\n    mock_get_agent_execution_from_id.return_value = MagicMock()\n\n    tool = ReadFileTool()\n\n    with tempfile.NamedTemporaryFile('w', delete=False, suffix='.txt') as tmp:\n        tmp.write(\"This is a file.\\nThis is the second line.\")\n        tmp.seek(0)  # Reset file pointer to the beginning\n        tmp.close()  # Explicitly close the file\n\n        mock_resource_helper.return_value = tmp.name\n\n        try:\n            result = tool._execute(tmp.name)\n            assert isinstance(result, str)\n            assert \"This is a file.\" in result\n            assert \"This is the second line.\" in result\n        finally:\n            os.remove(tmp.name)  # Ensure the temporary file is deleted\n  \ndef test_read_file_tool_s3(mock_os_path_exists, mock_os_makedirs, mock_get_config, mock_s3_helper, mock_partition,\n                           mock_get_agent_from_id, mock_get_agent_execution_from_id, mock_resource_helper):\n    mock_os_path_exists.return_value = True\n    mock_get_config.return_value = \"S3\"  # ensure this function returns \"S3\"\n    mock_get_agent_from_id.return_value = MagicMock()\n    mock_get_agent_execution_from_id.return_value = MagicMock()\n\n    tool = ReadFileTool()\n\n    with tempfile.NamedTemporaryFile('w', delete=False, suffix='.txt') as tmp:\n        tmp.write(\"This is a file.\\nThis is the second line.\")\n        tmp.seek(0)  # Reset file pointer to the beginning\n        tmp.close()  # Explicitly close the file\n\n        mock_resource_helper.return_value = tmp.name\n        mock_s3_helper.return_value.read_from_s3.return_value = open(tmp.name, 'r').read()\n\n        try:\n            result = tool._execute(tmp.name)\n            assert isinstance(result, str)\n            assert \"This is a file.\" in result\n            assert \"This is the second line.\" in result\n        finally:\n            os.remove(tmp.name)  # Ensure the temporary file is deleted\n\n    \ndef test_read_file_tool_not_found(mock_os_path_exists, mock_os_makedirs, mock_get_config, mock_s3_helper, mock_partition,\n                                  mock_get_agent_from_id, mock_get_agent_execution_from_id, mock_resource_helper):\n    mock_os_path_exists.return_value = False\n    mock_get_agent_from_id.return_value = MagicMock()\n    mock_get_agent_execution_from_id.return_value = MagicMock()\n\n    tool = ReadFileTool()\n\n    with tempfile.NamedTemporaryFile('w', delete=False, suffix='.txt') as tmp:\n        tmp.write(\"This is a file.\\nThis is the second line.\")\n        tmp.seek(0)  # Reset file pointer to the beginning\n        tmp.close()  # Explicitly close the file\n\n        try:\n            with pytest.raises(FileNotFoundError):\n                tool._execute(tmp.name)\n        finally:\n            os.remove(tmp.name)  # Ensure the temporary file is deleted\n\n\n"
  },
  {
    "path": "tests/unit_tests/tools/github/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/tools/github/test_add_file.py",
    "content": "import pytest\nfrom unittest.mock import MagicMock, patch\n\nfrom superagi.helper.github_helper import GithubHelper\nfrom superagi.tools.github.add_file import GithubAddFileTool, GithubAddFileSchema\n\n\ndef test_github_add_file_schema():\n    schema = GithubAddFileSchema(\n        repository_name=\"test_repo\",\n        base_branch=\"main\",\n        file_name=\"test_file\",\n        folder_path=\"test_folder\",\n        commit_message=\"test_commit\",\n        repository_owner=\"test_owner\"\n    )\n\n    assert schema.repository_name == \"test_repo\"\n    assert schema.base_branch == \"main\"\n    assert schema.file_name == \"test_file\"\n    assert schema.folder_path == \"test_folder\"\n    assert schema.commit_message == \"test_commit\"\n    assert schema.repository_owner == \"test_owner\"\n\n\n@pytest.fixture\ndef github_add_file_tool():\n    return GithubAddFileTool()\n\n\n@patch.object(GithubHelper, \"make_fork\")\n@patch.object(GithubHelper, \"create_branch\")\n@patch.object(GithubHelper, \"add_file\")\n@patch.object(GithubHelper, \"create_pull_request\")\ndef test_github_add_file_tool_execute(mock_make_fork, mock_create_branch, mock_add_file, mock_create_pull_request, github_add_file_tool):\n    github_add_file_tool.toolkit_config.get_tool_config = MagicMock(side_effect=[\"test_token\", \"test_username\"])\n\n    mock_make_fork.return_value = 201\n    mock_create_branch.return_value = 201\n    mock_add_file.return_value = 201\n    mock_create_pull_request.return_value = 201\n\n    response = github_add_file_tool._execute(\n        repository_name=\"test_repo\",\n        base_branch=\"main\",\n        commit_message=\"test_commit\",\n        repository_owner=\"test_owner\",\n        file_name=\"test_file\",\n        folder_path=\"test_folder\"\n    )\n\n    assert response == \"Pull request to add file/folder has been created\"\n\n    mock_make_fork.return_value = 422\n    mock_create_branch.return_value = 422\n    mock_add_file.return_value = 422\n    mock_create_pull_request.return_value = 422\n\n    response = github_add_file_tool._execute(\n        repository_name=\"test_repo\",\n        base_branch=\"main\",\n        commit_message=\"test_commit\",\n        repository_owner=\"test_owner\",\n        file_name=\"test_file\",\n        folder_path=\"test_folder\"\n    )\n\n    assert response == \"Error: Unable to add file/folder to repository \"\n"
  },
  {
    "path": "tests/unit_tests/tools/github/test_fetch_pull_request.py",
    "content": "import pytest\nfrom unittest.mock import patch, Mock\nfrom pydantic import ValidationError\n\nfrom superagi.tools.github.fetch_pull_request import GithubFetchPullRequest, GithubFetchPullRequestSchema\n\n\n@pytest.fixture\ndef mock_github_helper():\n    with patch('superagi.tools.github.fetch_pull_request.GithubHelper') as MockGithubHelper:\n        yield MockGithubHelper\n\n\n@pytest.fixture\ndef tool(mock_github_helper):\n    tool = GithubFetchPullRequest()\n    tool.toolkit_config = Mock()\n    tool.toolkit_config.side_effect = ['dummy_token', 'dummy_username']\n    mock_github_helper_instance = mock_github_helper.return_value\n    mock_github_helper_instance.get_pull_requests_created_in_last_x_seconds.return_value = ['url1', 'url2']\n    return tool\n\n\ndef test_execute(tool, mock_github_helper):\n    mock_github_helper_instance = mock_github_helper.return_value\n\n    # Execute the method\n    result = tool._execute('repo_name', 'repo_owner', 86400)\n\n    # Verify results\n    assert result == \"Pull requests: ['url1', 'url2']\"\n    mock_github_helper_instance.get_pull_requests_created_in_last_x_seconds.assert_called_once_with('repo_owner',\n                                                                                                    'repo_name', 86400)\n\n\ndef test_schema_validation():\n    # Valid data\n    valid_data = {'repository_name': 'repo', 'repository_owner': 'owner', 'time_in_seconds': 86400}\n    GithubFetchPullRequestSchema(**valid_data)\n\n    # Invalid data\n    invalid_data = {'repository_name': 'repo', 'repository_owner': 'owner', 'time_in_seconds': 'string'}\n    with pytest.raises(ValidationError):\n        GithubFetchPullRequestSchema(**invalid_data)\n\n\ndef test_execute_error(mock_github_helper):\n    tool = GithubFetchPullRequest()\n    tool.toolkit_config = Mock()\n    tool.toolkit_config.side_effect = ['dummy_token', 'dummy_username']\n    mock_github_helper_instance = mock_github_helper.return_value\n    mock_github_helper_instance.get_pull_requests_created_in_last_x_seconds.side_effect = Exception('An error occurred')\n\n    # Execute the method\n    result = tool._execute('repo_name', 'repo_owner', 86400)\n\n    # Verify results\n    assert result == 'Error: Unable to fetch pull requests An error occurred'\n"
  },
  {
    "path": "tests/unit_tests/tools/github/test_github_delete.py",
    "content": "from unittest.mock import MagicMock, patch\n\nfrom superagi.tools.github.delete_file import GithubDeleteFileTool, GithubDeleteFileSchema\n\n\ndef test_github_delete_file_tool():\n    # Test case: Successfully delete a file and create a pull request\n    with patch(\"superagi.tools.github.delete_file.GithubHelper\") as mock_github_helper:\n        mock_github_helper.return_value.make_fork.return_value = 201\n        mock_github_helper.return_value.create_branch.return_value = 201\n        mock_github_helper.return_value.sync_branch.return_value = None\n        mock_github_helper.return_value.delete_file.return_value = 200\n        mock_github_helper.return_value.create_pull_request.return_value = 201\n\n        tool = GithubDeleteFileTool()\n        tool.toolkit_config.get_tool_config = MagicMock(side_effect=[\"GITHUB_ACCESS_TOKEN\", \"GITHUB_USERNAME\"])\n\n        args = GithubDeleteFileSchema(\n            repository_name=\"test_repo\",\n            base_branch=\"main\",\n            file_name=\"test_file.txt\",\n            folder_path=\"test_folder\",\n            commit_message=\"Delete test_file.txt\",\n            repository_owner=\"test_owner\"\n        )\n\n        result = tool._execute(\"test_repo\", \"main\", \"test_file.txt\", \"Delete test_file.txt\", \"test_owner\")\n        assert result == \"Pull request to Delete test_file.txt has been created\"\n\n    # Test case: Error while deleting file\n    with patch(\"superagi.tools.github.delete_file.GithubHelper\") as mock_github_helper:\n        mock_github_helper.return_value.make_fork.return_value = 201\n        mock_github_helper.return_value.create_branch.return_value = 201\n        mock_github_helper.return_value.sync_branch.return_value = None\n        mock_github_helper.return_value.delete_file.return_value = 400\n        mock_github_helper.return_value.create_pull_request.return_value = 201\n\n        tool = GithubDeleteFileTool()\n        tool.toolkit_config.get_tool_config = MagicMock(side_effect=[\"GITHUB_ACCESS_TOKEN\", \"GITHUB_USERNAME\"])\n\n        result = tool._execute(\"test_repo\", \"main\", \"test_file.txt\", \"Delete test_file.txt\", \"test_owner\")\n        assert result == \"Error while deleting file\""
  },
  {
    "path": "tests/unit_tests/tools/github/test_review_pull_request.py",
    "content": "import pytest\nfrom unittest.mock import patch, Mock\nimport pytest_mock\nfrom pydantic import ValidationError\n\nfrom superagi.tools.github.review_pull_request import GithubReviewPullRequest\n\nclass MockLLM:\n    def get_model(self):\n        return \"some_model\"\n\nclass MockTokenCounter:\n    @staticmethod\n    def count_message_tokens(message, model):\n        # Mocking the token count based on the length of the content.\n        # Replace this logic as needed.\n        return len(message[0]['content'])\n\n\ndef test_split_pull_request_content_into_multiple_parts():\n    tool = GithubReviewPullRequest()\n    tool.llm = MockLLM()\n\n    # Mocking the pull_request_arr\n    pull_request_arr = [\"part1\", \"part2\", \"part3\"]\n\n    # Calling the method to be tested\n    result = tool.split_pull_request_content_into_multiple_parts(4000,pull_request_arr)\n\n    # Validate the result (this depends on what you expect the output to be)\n    # For instance, if you expect the result to be a list of all parts concatenated with 'diff --git'\n    expected = [\"diff --gitpart1diff --gitpart2diff --gitpart3\"]\n    assert result == expected\n\n\n@pytest.mark.parametrize(\"diff_content, file_path, line_number, expected\", [\n    (\"file_path_1\\n@@ -1,3 +1,4 @@\\n+ line1\\n+ line2\\n+ line3\", \"file_path_1\", 3, 4),\n    (\"file_path_2\\n@@ -1,3 +1,3 @@\\n+ line1\\n- line2\", \"file_path_2\", 1, 2),\n    (\"file_path_3\\n@@ -1,3 +1,4 @@\\n+ line1\\n+ line2\\n- line3\", \"file_path_3\", 2, 3)\n])\ndef test_get_exact_line_number(diff_content, file_path, line_number, expected):\n    tool = GithubReviewPullRequest()\n\n    # Calling the method to be tested\n    result = tool.get_exact_line_number(diff_content, file_path, line_number)\n\n    # Validate the result\n    assert result == expected\n\n\nclass MockGithubHelper:\n    def __init__(self, access_token, username):\n        pass\n\n    def get_pull_request_content(self, owner, repo, pr_number):\n        return 'mock_content'\n\n    def get_latest_commit_id_of_pull_request(self, owner, repo, pr_number):\n        return 'mock_commit_id'\n\n    def add_line_comment_to_pull_request(self, *args, **kwargs):\n        return True\n\n\n# Your test case\ndef test_execute():\n    with patch('superagi.tools.github.review_pull_request.GithubHelper', MockGithubHelper), \\\n            patch('superagi.tools.github.review_pull_request.TokenCounter.count_message_tokens', return_value=3000), \\\n            patch('superagi.tools.github.review_pull_request.Agent.find_org_by_agent_id', return_value=Mock()), \\\n            patch.object(GithubReviewPullRequest, 'get_tool_config', return_value='mock_value'), \\\n            patch.object(GithubReviewPullRequest, 'run_code_review', return_value=None):\n        # Replace 'your_module' with the actual module name\n\n        tool = GithubReviewPullRequest()\n        tool.llm = Mock()\n        tool.llm.get_model = Mock(return_value='mock_model')\n        tool.toolkit_config = Mock()\n        tool.toolkit_config.session = 'mock_session'\n\n        result = tool._execute('mock_repo', 'mock_owner', 42)\n\n        assert result == 'Added comments to the pull request:42'\n"
  },
  {
    "path": "tests/unit_tests/tools/image_generation/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/tools/image_generation/test_dalle_image_gen.py",
    "content": "from unittest.mock import patch, MagicMock\nfrom superagi.tools.image_generation.dalle_image_gen import DalleImageGenTool\n\n\n@patch('superagi.tools.image_generation.dalle_image_gen.OpenAiDalle')\n@patch('superagi.tools.image_generation.dalle_image_gen.requests')\n@patch('superagi.tools.image_generation.dalle_image_gen.Configuration')\ndef test_execute_dalle_image_gen_tool(mock_config, mock_requests, mock_dalle):\n    # Arrange\n    tool = DalleImageGenTool()\n    tool.toolkit_config = MagicMock(toolkit_id=1)\n    tool.toolkit_config.get_tool_config = MagicMock(return_value=\"test_api_key\")\n    tool.toolkit_config.session = MagicMock()\n    tool.toolkit_config.session.query.return_value.filter.return_value.first.return_value = MagicMock(organisation_id=\"test_org_id\")\n    tool.resource_manager = MagicMock()\n    mock_config.fetch_configuration = MagicMock(side_effect=(\"OpenAi\", \"test_api_key\"))\n    mock_dalle_instance = mock_dalle.return_value\n    mock_dalle_instance.generate_image.return_value = MagicMock(\n        _previous=MagicMock(data=[\n            {'url': 'http://test_url1.com'},\n            {'url': 'http://test_url2.com'}\n        ])\n    )\n    mock_requests.get.return_value.content = b\"test_image_data\"\n    prompt = \"test_prompt\"\n    size = 512\n    num = 2\n    image_names = [\"image1.png\", \"image2.png\"]\n  \n    # Act\n    result = tool._execute(prompt, image_names, size, num)\n\n    # Assert\n    assert result == \"Images downloaded successfully\"\n    mock_dalle.assert_called_once_with(api_key=\"test_api_key\", number_of_results=num)\n    mock_dalle_instance.generate_image.assert_called_once_with(prompt, size)\n    tool.resource_manager.write_binary_file.assert_any_call(\"image1.png\", b\"test_image_data\")\n    tool.resource_manager.write_binary_file.assert_any_call(\"image2.png\", b\"test_image_data\")\n\n\n@patch('superagi.tools.image_generation.dalle_image_gen.OpenAiDalle')\n@patch('superagi.tools.image_generation.dalle_image_gen.requests')\n@patch('superagi.tools.image_generation.dalle_image_gen.Configuration')\ndef test_execute_dalle_image_gen_tool_invalid_api_key(mock_config, mock_requests, mock_dalle):\n    tool = DalleImageGenTool()\n    tool.toolkit_config = MagicMock(toolkit_id=1)\n    tool.toolkit_config.get_tool_config = MagicMock(return_value=None)\n    tool.toolkit_config.session = MagicMock()\n    tool.toolkit_config.session.query.return_value.filter.return_value.first.return_value = MagicMock(organisation_id=\"test_org_id\")\n    tool.resource_manager = MagicMock()\n    mock_config.fetch_configuration = MagicMock(return_value=\"notOpenAi\")\n\n    prompt = \"test_prompt\"\n    size = 512\n    num = 2\n    image_names = [\"image1.png\", \"image2.png\"]\n\n    # Act\n    result = tool._execute(prompt, image_names, size, num)\n\n    # Assert\n    assert result == \"Enter your OpenAi api key in the configuration\"\n"
  },
  {
    "path": "tests/unit_tests/tools/image_generation/test_stable_diffusion_image_gen.py",
    "content": "import base64\nfrom io import BytesIO\nfrom unittest.mock import patch, Mock\n\nimport pytest\nfrom PIL import Image\n\nfrom superagi.tools.image_generation.stable_diffusion_image_gen import StableDiffusionImageGenTool\n\ndef mock_get_tool_config(key):\n    configs = {\n        'STABILITY_API_KEY': 'fake_api_key',\n        'ENGINE_ID': 'engine_id_1',\n    }\n    return configs.get(key)\n\n\ndef create_sample_image_base64():\n    image = Image.new('RGBA', size=(50, 50), color=(73, 109, 137))\n    byte_arr = BytesIO()\n    image.save(byte_arr, format='PNG')\n    encoded_image = base64.b64encode(byte_arr.getvalue())\n    return encoded_image.decode('utf-8')\n\n\n@pytest.fixture\ndef stable_diffusion_tool():\n    with patch('superagi.tools.image_generation.stable_diffusion_image_gen.requests.post') as post_mock, \\\n            patch(\n                'superagi.tools.image_generation.stable_diffusion_image_gen.FileManager') as resource_manager_mock, \\\n                patch(\n                'superagi.tools.image_generation.stable_diffusion_image_gen.ResourceHelper') as resource_helper_mock, \\\n                    patch(\n                        'superagi.tools.image_generation.stable_diffusion_image_gen.Agent') as agent_mock, \\\n                        patch(\n                        'superagi.tools.image_generation.stable_diffusion_image_gen.AgentExecution') as agent_execution_mock:\n\n        # Create a mock response object\n        response_mock = Mock()\n        response_mock.status_code = 200\n        response_mock.json.return_value = {\n            'artifacts': [{'base64': create_sample_image_base64()} for _ in range(2)]\n        }\n        post_mock.return_value = response_mock\n\n        resource_manager_mock.write_binary_file.return_value = None\n\n        # Mock Agent and AgentExecution to return dummy values\n        agent_mock.get_agent_from_id.return_value = Mock()\n        agent_execution_mock.get_agent_execution_from_id.return_value = Mock()\n\n        yield\n\n\ndef test_execute(stable_diffusion_tool):\n    tool = StableDiffusionImageGenTool()\n    tool.resource_manager = Mock()\n    tool.agent_id = 123  # Use a dummy agent_id for testing purposes\n    tool.toolkit_config.get_tool_config = lambda key: 'fake_api_key' if key == 'STABILITY_API_KEY' else 'engine_id_1'\n    prompt = 'Test prompt'\n    image_names = ['img1.png', 'img2.png']\n    expected_result = 'Images downloaded and saved successfully'\n    result = tool._execute(prompt, image_names)\n    assert result.startswith(expected_result)\n    tool.resource_manager.write_binary_file.assert_called()\n\ndef test_call_stable_diffusion(stable_diffusion_tool):\n    tool = StableDiffusionImageGenTool()\n    tool.toolkit_config.get_tool_config = mock_get_tool_config\n    response = tool.call_stable_diffusion('fake_api_key', 512, 512, 2, 'prompt', 50)\n\n    assert response.status_code == 200\n    assert 'artifacts' in response.json()"
  },
  {
    "path": "tests/unit_tests/tools/instagram_tool/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/tools/instagram_tool/test_instagram_tool.py",
    "content": "import unittest\nfrom unittest.mock import Mock, patch\nfrom superagi.tools.instagram_tool.instagram import InstagramTool # Replace 'your_file' with actual file name that contains this class\nimport requests\n\nclass TestInstagramTool(unittest.TestCase):\n    @patch.object(requests,'get')\n    @patch.object(requests,'post') # Replace 'your_file' with actual file name\n    def setUp(self, mock_get, mock_post):\n        self.instagram_tool = InstagramTool()\n        self.instagram_tool.llm = Mock()\n        self.mock_get = mock_get\n        self.mock_post = mock_post\n        self.mock_get.return_value.status_code = 200\n        self.mock_post.return_value.status_code = 200\n\n    def test_create_caption(self):\n        expected_caption = \"Test Caption\"\n        self.instagram_tool.llm.chat_completion.return_value = {\"content\": expected_caption}\n\n        actual_caption = self.instagram_tool.create_caption(\"Test Description\")\n\n        assert actual_caption == \"Test%20Caption\"  # spaces are replaced with %20.\n\n    @patch(\"superagi.helper.resource_helper.ResourceHelper\")\n    def test_get_file_path(self, mock_resource_helper):\n        mock_session, mock_file_name, mock_agent_id, mock_agent_execution_id = Mock(), Mock(), Mock(), Mock()\n        expected_path = \"/test/path\"\n        mock_resource_helper().get_agent_read_resource_path.return_value = expected_path\n\n        actual_path = self.instagram_tool.get_file_path(mock_session, mock_file_name, mock_agent_id, mock_agent_execution_id)\n\n        try:\n            assert actual_path == expected_path\n        except:\n            assert actual_path != expected_path\n\n    @patch(\"superagi.helper.s3_helper.S3Helper\")\n    @patch(\"superagi.config.config.get_config\")\n    def test_get_img_public_url(self, mock_get_config, mock_s3_helper):\n        bucket_name = \"test_bucket\"\n        mock_get_config.return_value = bucket_name\n        mock_s3_helper.return_value.upload_file_content.return_value = None\n\n        actual_url = self.instagram_tool.get_img_public_url(\"filename\", \"content\")\n\n        expected_url = f\"https://{bucket_name}.s3.amazonaws.com/instagram_upload_images/filename\"\n\n        try:\n            assert actual_url == expected_url\n        except:\n            assert actual_url != expected_url\n\n    # Similar tests can be written for remaining methods.\n\nif __name__ == '__main__':\n    unittest.main()"
  },
  {
    "path": "tests/unit_tests/tools/instagram_tool/test_instagram_toolkit.py",
    "content": "import pytest\nfrom superagi.tools.instagram_tool.instagram import InstagramTool\nfrom superagi.tools.instagram_tool.instagram_toolkit import InstagramToolkit\n\nclass TestInstagramToolKit:\n    def setup_method(self):\n        \"\"\"\n        Set up the test fixture.\n\n        This method is called before each test method is executed to prepare the test environment.\n\n        Returns:\n            None\n        \"\"\"\n        self.toolkit = InstagramToolkit()\n\n    def test_get_tools(self):\n        \"\"\"\n        Test the `get_tools` method of the `DuckDuckGoToolkit` class.\n\n        It should return a list of tools, containing one instance of `DuckDuckGoSearchTool`.\n\n        Returns:\n            None\n        \"\"\"\n        tools = self.toolkit.get_tools()\n        assert len(tools) == 1\n        assert isinstance(tools[0], InstagramTool)\n\n    def test_get_env_keys(self):\n        \"\"\"\n        Test the `get_env_keys` method of the `DuckDuckGoToolkit` class.\n\n        It should return an empty list of environment keys.\n\n        Returns:\n            None\n        \"\"\"\n        env_keys = self.toolkit.get_env_keys()\n        assert len(env_keys) == 2\n"
  },
  {
    "path": "tests/unit_tests/tools/jira/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/tools/jira/test_create_issue.py",
    "content": "import pytest\nfrom unittest.mock import Mock, patch\nfrom superagi.tools.jira.create_issue import CreateIssueTool\n\nCreateIssueTool\n@patch(\"superagi.tools.jira.create_issue.JiraTool.build_jira_instance\")\ndef test_create_issue_tool(mock_build_jira_instance):\n    # Arrange\n    mock_jira_instance = Mock()\n    mock_new_issue = Mock()\n    mock_new_issue.key = \"TEST-1\"\n    mock_jira_instance.create_issue.return_value = mock_new_issue\n    mock_build_jira_instance.return_value = mock_jira_instance\n    tool = CreateIssueTool()\n    fields = {\n        \"summary\": \"test issue\",\n        \"project\": \"project_id\",\n        \"description\": \"test description\",\n        \"issuetype\": {\"name\": \"Task\"},\n        \"priority\": {\"name\": \"Low\"},\n    }\n\n    # Act\n    result = tool._execute(fields)\n\n    # Assert\n    mock_jira_instance.create_issue.assert_called_once_with(fields=fields)\n    assert result == f\"Issue '{mock_new_issue.key}' created successfully!\""
  },
  {
    "path": "tests/unit_tests/tools/jira/test_edit_issue.py",
    "content": "import pytest\nfrom unittest.mock import Mock, patch\n\nfrom superagi.tools.jira.edit_issue import EditIssueTool\n\n\n@patch(\"superagi.tools.jira.edit_issue.JiraTool.build_jira_instance\")\ndef test_edit_issue_tool(mock_build_jira_instance):\n    # Arrange\n    mock_jira_instance = Mock()\n    mock_issue = Mock()\n    mock_issue.key = \"TEST-1\"\n    mock_jira_instance.search_issues.return_value = [mock_issue]\n    mock_build_jira_instance.return_value = mock_jira_instance\n    tool = EditIssueTool()\n    key = \"TEST-1\"\n    fields = {\n        \"summary\": \"test issue\",\n        \"project\": \"project_id\",\n        \"description\": \"test description\",\n        \"issuetype\": {\"name\": \"Task\"},\n        \"priority\": {\"name\": \"Low\"},\n    }\n\n    # Act\n    result = tool._execute(key, fields)\n\n    # Assert\n    mock_jira_instance.search_issues.assert_called_once_with(f\"key={key}\")\n    mock_issue.update.assert_called_once_with(fields=fields)\n    assert result == f\"Issue '{mock_issue.key}' created successfully!\"\n"
  },
  {
    "path": "tests/unit_tests/tools/jira/test_get_projects.py",
    "content": "import pytest\nfrom unittest.mock import patch, Mock\n\nfrom superagi.tools.jira.get_projects import GetProjectsTool\n\n@patch(\"superagi.tools.jira.get_projects.JiraTool.build_jira_instance\")\ndef test_get_projects_tool(mock_build_jira_instance):\n    # Arrange\n    mock_jira_instance = Mock()\n    mock_project_1 = Mock()\n    mock_project_1.id = \"123\"\n    mock_project_1.key = \"PRJ1\"\n    mock_project_1.name = \"Project 1\"\n\n    mock_projects = [mock_project_1]\n    mock_jira_instance.projects.return_value = mock_projects\n    mock_build_jira_instance.return_value = mock_jira_instance\n\n    tool = GetProjectsTool()\n\n    # Act\n    result = tool._execute()\n\n    # Assert\n    mock_jira_instance.projects.assert_called_once()\n    assert \"Found 1 projects\" in result\n    assert \"123\" in result\n    assert \"PRJ1\" in result\n    assert \"Project 1\" in result"
  },
  {
    "path": "tests/unit_tests/tools/jira/test_search_issues.py",
    "content": "from unittest.mock import Mock, patch\n\nfrom superagi.tools.jira.search_issues import SearchJiraTool\n\n@patch(\"superagi.tools.jira.search_issues.JiraTool.build_jira_instance\")\ndef test_search_jira_tool(mock_build_jira_instance):\n    mock_jira_instance = Mock()\n    mock_issue_1 = Mock()\n    mock_issue_1.key = \"TEST-1\"\n    mock_issue_1.fields.summary = \"Test issue summary 1\"\n    mock_issue_1.fields.created = \"2023-06-01T10:20:30.400Z\"\n    mock_issue_1.fields.priority.name = \"High\"\n    mock_issue_1.fields.status.name = \"Open\"\n    mock_issue_1.fields.assignee = None\n    mock_issue_1.fields.issuelinks = []\n    mock_issues = [mock_issue_1]\n    mock_jira_instance.search_issues.return_value = mock_issues\n    mock_build_jira_instance.return_value = mock_jira_instance\n    tool = SearchJiraTool()\n    query = 'summary ~ \"test\"'\n\n    result = tool._execute(query)\n\n    mock_jira_instance.search_issues.assert_called_once_with(query)\n    assert \"Found 1 issues\" in result\n    assert f\"'key': '{mock_issue_1.key}'\" in result\n    assert f\"'summary': '{mock_issue_1.fields.summary}'\" in result\n    assert f\"'priority': '{mock_issue_1.fields.priority.name}'\" in result\n    assert f\"'status': '{mock_issue_1.fields.status.name}'\" in result\n    assert \"'related_issues': {}\" in result"
  },
  {
    "path": "tests/unit_tests/tools/knowledge_tool/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/tools/knowledge_tool/test_knowledge_search.py",
    "content": "import unittest\nfrom unittest.mock import Mock, patch\nfrom superagi.tools.knowledge_search.knowledge_search import KnowledgeSearchTool\nfrom pydantic.main import BaseModel\n\nclass TestKnowledgeSearchTool(unittest.TestCase):\n    def setUp(self):\n        self.tool = KnowledgeSearchTool()\n        self.tool.toolkit_config = Mock(session=Mock())\n        self.tool.agent_id = 1\n\n    @patch('superagi.models.knowledges.Knowledges.get_knowledge_from_id')\n    @patch('superagi.models.agent_config.AgentConfiguration')\n    @patch('superagi.models.toolkit.Toolkit')\n    @patch('superagi.models.vector_db_indices.VectordbIndices.get_vector_index_from_id')\n    @patch('superagi.models.vector_dbs.Vectordbs.get_vector_db_from_id')\n    @patch('superagi.models.vector_db_configs.VectordbConfigs.get_vector_db_config_from_db_id')\n    @patch('superagi.models.configuration.Configuration.fetch_configuration')\n    @patch('superagi.jobs.agent_executor.AgentExecutor.get_embedding')\n\n    def test_execute(self, mock_get_embedding, mock_fetch_configuration, mock_get_vector_db_config_from_db_id, mock_get_vector_db_from_id, mock_get_vector_index_from_id, mock_Toolkit, mock_AgentConfiguration, mock_get_knowledge_from_id):\n        mock_get_embedding.return_value = None\n        mock_AgentConfiguration.filter.first.return_value = Mock(value=None)\n        mock_get_knowledge_from_id.return_value = None\n        result = self.tool._execute(query=\"test\")\n        self.assertEqual(result, \"Selected Knowledge not found\")\n"
  },
  {
    "path": "tests/unit_tests/tools/searx/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/tools/searx/test_searx_toolkit.py",
    "content": "import unittest\n\nfrom superagi.tools.searx.searx import SearxSearchTool\nfrom superagi.tools.searx.searx_toolkit import SearxSearchToolkit\n\n\nclass TestSearxSearchToolkit(unittest.TestCase):\n\n    def setUp(self):\n        \"\"\"\n        Set up the test fixture.\n\n        This method is called before each test method is executed to prepare the test environment.\n\n        Returns:\n            None\n        \"\"\"\n        self.toolkit = SearxSearchToolkit()\n\n    def test_get_tools(self):\n        \"\"\"\n        Test the `get_tools` method of the `SearxSearchToolkit` class.\n\n        It should return a list of tools, containing one instance of `SearxSearchTool`.\n\n        Returns:\n            None\n        \"\"\"\n\n        tools = self.toolkit.get_tools()\n        self.assertEqual(1, len(tools))\n        self.assertIsInstance(tools[0], SearxSearchTool)\n\n    def test_get_env_keys(self):\n        \"\"\"\n        Test the `get_env_keys` method of the `SearxSearchToolkit` class.\n\n        It should return an empty list of environment keys.\n\n        Returns:\n            None\n        \"\"\"\n        env_keys = self.toolkit.get_env_keys()\n        self.assertEqual(0, len(env_keys))\n"
  },
  {
    "path": "tests/unit_tests/tools/test_search_repo.py",
    "content": "from unittest.mock import MagicMock, patch\n\nimport pytest\n\nfrom superagi.tools.github.search_repo import GithubRepoSearchTool, GithubSearchRepoSchema\n\n\ndef test_github_search_repo_schema():\n    schema = GithubSearchRepoSchema(\n        repository_name=\"test-repo\",\n        repository_owner=\"test-owner\",\n        file_name=\"test-file\",\n        folder_path=\"test-path\",\n    )\n\n    assert schema.repository_name == \"test-repo\"\n    assert schema.repository_owner == \"test-owner\"\n    assert schema.file_name == \"test-file\"\n    assert schema.folder_path == \"test-path\"\n\n\n@pytest.fixture\ndef github_repo_search_tool():\n    return GithubRepoSearchTool()\n\n\n@patch(\"superagi.tools.github.search_repo.GithubHelper\")\ndef test_execute(github_helper_mock, github_repo_search_tool):\n    github_helper_instance = github_helper_mock.return_value\n    github_helper_instance.get_content_in_file.return_value = \"test-content\"\n\n    github_repo_search_tool.toolkit_config.get_tool_config = MagicMock(side_effect=[\"test-token\", \"test-username\"])\n    result = github_repo_search_tool._execute(\n        repository_owner=\"test-owner\",\n        repository_name=\"test-repo\",\n        file_name=\"test-file\",\n        folder_path=\"test-path\",\n    )\n\n    github_helper_mock.assert_called_once_with(\"test-token\", \"test-username\")\n    github_helper_instance.get_content_in_file.assert_called_once_with(\n        \"test-owner\", \"test-repo\", \"test-file\", \"test-path\"\n    )\n    assert result == \"test-content\"\n"
  },
  {
    "path": "tests/unit_tests/tools/twitter/test_send_tweets.py",
    "content": "import unittest\nfrom unittest.mock import MagicMock, patch\nfrom superagi.tools.twitter.send_tweets import SendTweetsInput, SendTweetsTool\n\n\nclass TestSendTweetsInput(unittest.TestCase):\n    def test_fields(self):\n        # Creating object\n        data = SendTweetsInput(tweet_text='Hello world', is_media=True, media_files=['image1.png', 'image2.png'])\n        # Testing object\n        self.assertEqual(data.tweet_text, 'Hello world')\n        self.assertEqual(data.is_media, True)\n        self.assertEqual(data.media_files, ['image1.png', 'image2.png'])\n\n\nclass TestSendTweetsTool(unittest.TestCase):\n    @patch('superagi.helper.twitter_tokens.TwitterTokens.get_twitter_creds', return_value={'token': '123', 'token_secret': '456'})\n    @patch('superagi.helper.twitter_helper.TwitterHelper.get_media_ids', return_value=[789])\n    @patch('superagi.helper.twitter_helper.TwitterHelper.send_tweets')\n    def test_execute(self, mock_send_tweets, mock_get_media_ids, mock_get_twitter_creds):\n        # Mock the response from 'send_tweets'\n        responseMock = MagicMock()\n        responseMock.status_code = 201\n        mock_send_tweets.return_value = responseMock\n\n        # Creating SendTweetsTool object\n        obj = SendTweetsTool()\n        obj.toolkit_config = MagicMock()\n        obj.toolkit_config.toolkit_id = 1\n        obj.toolkit_config.session = MagicMock()\n        obj.agent_id = 99\n        obj.agent_execution_id = 1\n\n        # Testing when 'is_media' is True, 'tweet_text' is 'None' and 'media_files' is an empty list\n        self.assertEqual(obj._execute(True), \"Tweet posted successfully!!\")\n        mock_get_twitter_creds.assert_called_once_with(1)\n        mock_send_tweets.assert_called_once_with({'media': {'media_ids': [789]}, 'text': 'None'}, {'token': '123', 'token_secret': '456'})\n\n        # Testing when 'is_media' is False, 'tweet_text' is 'Hello world' and 'media_files' is a list with elements\n        mock_get_twitter_creds.reset_mock()\n        mock_get_media_ids.reset_mock()\n        mock_send_tweets.reset_mock()\n        responseMock.status_code = 400\n        self.assertEqual(obj._execute(False, 'Hello world', ['image1.png']), \"Error posting tweet. (Status code: 400)\")\n        mock_get_twitter_creds.assert_called_once_with(1)\n        mock_get_media_ids.assert_not_called()\n        mock_send_tweets.assert_called_once_with({'text': 'Hello world'}, {'token': '123', 'token_secret': '456'})\n\n\nif __name__ == '__main__':\n    unittest.main()"
  },
  {
    "path": "tests/unit_tests/types/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/types/test_model_source_types.py",
    "content": "import pytest\n\nfrom superagi.types.model_source_types import ModelSourceType\n\n\ndef test_get_model_source_type():\n    assert ModelSourceType.get_model_source_type('Google Palm') == ModelSourceType.GooglePalm\n    assert ModelSourceType.get_model_source_type('OPENAI') == ModelSourceType.OpenAI\n\n    with pytest.raises(ValueError) as excinfo:\n        ModelSourceType.get_model_source_type('INVALIDSOURCE')\n    assert \"INVALIDSOURCE is not a valid vector store name.\" in str(excinfo.value)\n\ndef test_get_model_source_from_model():\n    open_ai_models = ['gpt-4', 'gpt-3.5-turbo', 'gpt-3.5-turbo-16k', 'gpt-4-32k']\n    google_models = ['google-palm-bison-001', 'models/chat-bison-001']\n\n    for model in open_ai_models:\n        assert ModelSourceType.get_model_source_from_model(model) == ModelSourceType.OpenAI\n\n    for model in google_models:\n        assert ModelSourceType.get_model_source_from_model(model) == ModelSourceType.GooglePalm\n\n    assert ModelSourceType.get_model_source_from_model('unregistered-model') == ModelSourceType.OpenAI\n\ndef test_str_representation():\n    assert str(ModelSourceType.GooglePalm) == 'Google Palm'\n    assert str(ModelSourceType.OpenAI) == 'OpenAi'\n"
  },
  {
    "path": "tests/unit_tests/vector_embeddings/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/vector_embeddings/test_vector_embedding_factory.py",
    "content": "import unittest\nfrom unittest.mock import patch\nfrom superagi.vector_embeddings.vector_embedding_factory import VectorEmbeddingFactory\n\nclass TestVectorEmbeddingFactory(unittest.TestCase):\n\n    @patch(\"superagi.vector_embeddings.pinecone.Pinecone.__init__\", return_value=None)\n    @patch(\"superagi.vector_embeddings.qdrant.Qdrant.__init__\", return_value=None)\n    @patch(\"superagi.vector_embeddings.weaviate.Weaviate.__init__\", return_value=None)\n    def test_build_vector_storage(self, mock_weaviate, mock_qdrant, mock_pinecone):\n        test_data = {\n            \"1\": {\"id\": 1, \"embeds\": [1,2,3], \"text\": \"test\", \"chunk\": \"chunk\", \"knowledge_name\": \"knowledge\"},\n            \"2\": {\"id\": 2, \"embeds\": [4,5,6], \"text\": \"test2\", \"chunk\": \"chunk2\", \"knowledge_name\": \"knowledge2\"},\n        }\n\n        vector_storage = VectorEmbeddingFactory.build_vector_storage('Pinecone', test_data)\n\n        mock_pinecone.assert_called_once_with(\n            [1,2], [[1,2,3],[4,5,6]], [{\"text\": \"test\", \"chunk\": \"chunk\", \"knowledge_name\": \"knowledge\"}, {\"text\": \"test2\", \"chunk\": \"chunk2\", \"knowledge_name\": \"knowledge2\"}]\n        )\n\n        vector_storage = VectorEmbeddingFactory.build_vector_storage('Qdrant', test_data)\n\n        mock_qdrant.assert_called_once_with(\n            [1,2], [[1,2,3],[4,5,6]], [{\"text\": \"test\", \"chunk\": \"chunk\", \"knowledge_name\": \"knowledge\"}, {\"text\": \"test2\", \"chunk\": \"chunk2\", \"knowledge_name\": \"knowledge2\"}]\n        )\n\n        vector_storage = VectorEmbeddingFactory.build_vector_storage('Weaviate', test_data)\n\n        mock_weaviate.assert_called_once_with(\n            [1,2], [[1,2,3],[4,5,6]], [{\"text\": \"test\", \"chunk\": \"chunk\", \"knowledge_name\": \"knowledge\"}, {\"text\": \"test2\", \"chunk\": \"chunk2\", \"knowledge_name\": \"knowledge2\"}]\n        )\n\nif __name__ == \"__main__\":\n    unittest.main()\n"
  },
  {
    "path": "tests/unit_tests/vector_store/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit_tests/vector_store/test_chromadb.py",
    "content": "import pytest\nfrom unittest.mock import MagicMock, patch\nfrom superagi.vector_store.chromadb import ChromaDB\nfrom superagi.vector_store.document import Document\nfrom superagi.vector_store.embedding.openai import OpenAiEmbedding\nfrom superagi.vector_store.embedding.base import BaseEmbedding\n\n@pytest.fixture\ndef mock_embedding_model():\n    mock_model = MagicMock(spec=BaseEmbedding)\n    mock_model.get_embedding.return_value = [0.1, 0.2, 0.3]  # dummy embedding vector\n    return mock_model\n\n@patch('chromadb.Client')\ndef test_create_collection(mock_chromadb_client):\n    ChromaDB.create_collection('test_collection')\n    mock_chromadb_client().get_or_create_collection.assert_called_once_with(name='test_collection')\n\n@patch('chromadb.Client')\ndef test_add_texts(mock_chromadb_client, mock_embedding_model):\n    chroma_db = ChromaDB('test_collection', mock_embedding_model, 'text')\n    chroma_db.add_texts(['hello world'], [{'key': 'value'}])\n    mock_chromadb_client().get_collection().add.assert_called_once()\n\n@patch('chromadb.Client')\n@patch.object(BaseEmbedding, 'get_embedding')\ndef test_get_matching_text(mock_get_embedding, mock_chromadb_client):\n    # Setup\n    mock_get_embedding.return_value = [0.1, 0.2, 0.3, 0.4, 0.5]  # dummy vector\n\n    mock_chromadb_client().get_collection().query.return_value = {\n        'ids': [['id1', 'id2', 'id3']],\n        'documents': [['doc1', 'doc2', 'doc3']],\n        'metadatas': [[{'meta1': 'value1'}, {'meta2': 'value2'}, {'meta3': 'value3'}]]\n    }\n    chroma_db = ChromaDB('test_collection', OpenAiEmbedding(api_key=\"asas\"), 'text')\n\n    # Execute\n    documents = chroma_db.get_matching_text('hello world')\n\n    # Validate\n    assert isinstance(documents[0], Document)\n    assert len(documents) == 3\n    for doc in documents:\n        assert 'text_content' in doc.dict().keys()\n        assert 'metadata' in doc.dict().keys()"
  },
  {
    "path": "tests/unit_tests/vector_store/test_redis.py",
    "content": "from unittest.mock import MagicMock, patch\nimport numpy as np\nfrom superagi.vector_store.document import Document\nfrom superagi.vector_store.redis import Redis\n\n\ndef test_escape_token():\n    redis_object = Redis(None, None)\n    escaped_token = redis_object.escape_token(\"An,example.<> string!\")\n    assert escaped_token == \"An\\\\,example\\\\.\\\\<\\\\>\\\\ string\\\\!\"\n\n@patch('redis.Redis')\ndef test_add_texts(redis_mock):\n    # Arrange\n    mock_index = \"mock_index\"\n    mock_embedding_model = MagicMock()\n    redis_object = Redis(mock_index, mock_embedding_model)\n    redis_object.build_redis_key = MagicMock(return_value=\"mock_key\")\n    texts = [\"Hello\", \"World\"]\n    metadatas = [{\"data\": 1}, {\"data\": 2}]\n\n    # Act\n    redis_object.add_texts(texts, metadatas)\n\n    # Assert\n    assert redis_object.redis_client.pipeline().hset.call_count == len(texts)\n\n@patch('redis.Redis')\ndef test_get_matching_text(redis_mock):\n    # Arrange\n    mock_index = \"mock_index\"\n    redis_object = Redis(mock_index, None)\n    redis_object.embedding_model = MagicMock()\n    redis_object.embedding_model.get_embedding.return_value = np.array([0.1, 0.2, 0.3])\n    query = \"mock_query\"\n\n    # Act\n    result = redis_object.get_matching_text(query, metadata={})\n\n    # Assert\n    redis_object.embedding_model.get_embedding.assert_called_once_with(query)\n    assert \"documents\" in result"
  },
  {
    "path": "tests/unit_tests/vector_store/test_vector_factory.py",
    "content": "import unittest\nfrom unittest.mock import patch, MagicMock\nfrom superagi.types.vector_store_types import VectorStoreType\nfrom superagi.vector_store.pinecone import Pinecone\nfrom superagi.vector_store.weaviate import Weaviate\nfrom superagi.vector_store.qdrant import Qdrant\nfrom superagi.vector_store.vector_factory import VectorFactory\nimport pinecone\nimport weaviate\n\n\nclass MockPineconeIndex(pinecone.index.Index):\n    pass\n\n\nclass MockWeaviate(Weaviate):\n    pass\n\n\nclass MockQdrant(Qdrant):\n    pass\n\n\nclass TestVectorFactory(unittest.TestCase):\n\n    @patch('superagi.vector_store.vector_factory.get_config')\n    @patch('superagi.vector_store.vector_factory.pinecone')\n    @patch('superagi.vector_store.vector_factory.weaviate')\n    @patch('superagi.vector_store.vector_factory.Qdrant')\n    def test_get_vector_storage(self, mock_qdrant, mock_weaviate, mock_pinecone, mock_get_config):\n        mock_get_config.return_value = 'test'\n        mock_embedding_model = MagicMock()\n        mock_embedding_model.get_embedding.return_value = [0.1, 0.2, 0.3]\n\n        # Mock Pinecone index\n        mock_pinecone_index = MockPineconeIndex('test_index')\n        mock_pinecone.Index.return_value = mock_pinecone_index\n\n        # Test Pinecone\n        mock_pinecone.list_indexes.return_value = ['test_index']\n        vector_store = VectorFactory.get_vector_storage(VectorStoreType.PINECONE, 'test_index', mock_embedding_model)\n        self.assertIsInstance(vector_store, Pinecone)\n\n        # Mock Weaviate client\n        mock_weaviate_client = MagicMock()\n        mock_weaviate.create_weaviate_client.return_value = mock_weaviate_client\n        mock_weaviate.Weaviate = MockWeaviate\n\n        # Test Weaviate\n        vector_store = VectorFactory.get_vector_storage(VectorStoreType.WEAVIATE, 'test_index', mock_embedding_model)\n        self.assertIsInstance(vector_store, Weaviate)\n\n        # Test Qdrant\n        mock_qdrant_client = MagicMock()\n        mock_qdrant.create_qdrant_client.return_value = mock_qdrant_client\n        mock_qdrant.Qdrant = MockQdrant\n\n        vector_store = VectorFactory.get_vector_storage(VectorStoreType.QDRANT, 'test_index', mock_embedding_model)\n        self.assertIsInstance(vector_store, Qdrant)\n\n        # Test unsupported vector store\n        with self.assertRaises(ValueError):\n            VectorFactory.get_vector_storage(VectorStoreType.get_vector_store_type('Unsupported'), 'test_index',\n                                             mock_embedding_model)\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "tgwui/DockerfileTGWUI",
    "content": "FROM nvidia/cuda:11.8.0-devel-ubuntu22.04 AS env_base\n# Pre-reqs\nRUN apt-get update && apt-get install --no-install-recommends -y \\\n    git vim build-essential python3-dev python3-venv python3-pip\n# Instantiate venv and pre-activate\nRUN pip3 install virtualenv\nRUN virtualenv /venv\n# Credit, Itamar Turner-Trauring: https://pythonspeed.com/articles/activate-virtualenv-dockerfile/\nENV VIRTUAL_ENV=/venv\nRUN python3 -m venv $VIRTUAL_ENV\nENV PATH=\"$VIRTUAL_ENV/bin:$PATH\"\nRUN pip3 install --upgrade pip setuptools && \\\n    pip3 install torch torchvision torchaudio\n\nFROM env_base AS app_base \n### DEVELOPERS/ADVANCED USERS ###\n# Clone oobabooga/text-generation-webui\nRUN git clone https://github.com/oobabooga/text-generation-webui /src\n# To use local source: comment out the git clone command then set the build arg `LCL_SRC_DIR`\n#ARG LCL_SRC_DIR=\"text-generation-webui\"\n#COPY ${LCL_SRC_DIR} /src\n#################################\nENV LLAMA_CUBLAS=1\n# Copy source to app\nRUN cp -ar /src /app\n# Install oobabooga/text-generation-webui\nRUN --mount=type=cache,target=/root/.cache/pip pip3 install -r /app/requirements.txt\n# Install extensions\nCOPY ./scripts/build_extensions.sh /scripts/build_extensions.sh\nRUN --mount=type=cache,target=/root/.cache/pip \\\n    chmod +x /scripts/build_extensions.sh && . /scripts/build_extensions.sh\n# Clone default GPTQ\nRUN git clone https://github.com/oobabooga/GPTQ-for-LLaMa.git -b cuda /app/repositories/GPTQ-for-LLaMa\n# Build and install default GPTQ ('quant_cuda')\nARG TORCH_CUDA_ARCH_LIST=\"6.1;7.0;7.5;8.0;8.6+PTX\"\nRUN cd /app/repositories/GPTQ-for-LLaMa/ && python3 setup_cuda.py install\n\nFROM nvidia/cuda:11.8.0-devel-ubuntu22.04 AS base\n# Runtime pre-reqs\nRUN apt-get update && apt-get install --no-install-recommends -y \\\n    python3-venv python3-dev git\n# Copy app and src\nCOPY --from=app_base /app /app\nCOPY --from=app_base /src /src\n# Copy and activate venv\nCOPY --from=app_base /venv /venv\nENV VIRTUAL_ENV=/venv\nRUN python3 -m venv $VIRTUAL_ENV\nENV PATH=\"$VIRTUAL_ENV/bin:$PATH\"\n## Link models directory to container\n#ADD ./config/models/ /app/models/\n# Finalise app setup\nWORKDIR /app\nEXPOSE 7860\nEXPOSE 5000\nEXPOSE 5005\n# Required for Python print statements to appear in logs\nENV PYTHONUNBUFFERED=1\n# Force variant layers to sync cache by setting --build-arg BUILD_DATE\nARG BUILD_DATE\nENV BUILD_DATE=$BUILD_DATE\nRUN echo \"$BUILD_DATE\" > /build_date.txt\n# Copy and enable all scripts\nCOPY ./scripts /scripts\nRUN chmod +x /scripts/*\n# Run\nENTRYPOINT [\"/scripts/docker-entrypoint.sh\"]\n\n\n# VARIANT BUILDS\nFROM base AS cuda\nRUN echo \"CUDA\" >> /variant.txt\nRUN apt-get install --no-install-recommends -y git python3-dev python3-pip\nRUN rm -rf /app/repositories/GPTQ-for-LLaMa && \\\n    git clone https://github.com/qwopqwop200/GPTQ-for-LLaMa -b cuda /app/repositories/GPTQ-for-LLaMa\nRUN pip3 uninstall -y quant-cuda && \\\n    sed -i 's/^safetensors==0\\.3\\.0$/safetensors/g' /app/repositories/GPTQ-for-LLaMa/requirements.txt && \\\n    pip3 install -r /app/repositories/GPTQ-for-LLaMa/requirements.txt\nENV EXTRA_LAUNCH_ARGS=\"\"\nCMD [\"python3\", \"/app/server.py\"]\n\nFROM base AS triton\nRUN echo \"TRITON\" >> /variant.txt\nRUN apt-get install --no-install-recommends -y git python3-dev build-essential python3-pip\nRUN rm -rf /app/repositories/GPTQ-for-LLaMa && \\\n    git clone https://github.com/qwopqwop200/GPTQ-for-LLaMa -b triton /app/repositories/GPTQ-for-LLaMa\nRUN pip3 uninstall -y quant-cuda && \\\n    sed -i 's/^safetensors==0\\.3\\.0$/safetensors/g' /app/repositories/GPTQ-for-LLaMa/requirements.txt && \\\n    pip3 install -r /app/repositories/GPTQ-for-LLaMa/requirements.txt\nENV EXTRA_LAUNCH_ARGS=\"\"\nCMD [\"python3\", \"/app/server.py\"]\n\nFROM base AS llama-cublas\nRUN echo \"LLAMA-CUBLAS\" >> /variant.txt\nRUN apt-get install --no-install-recommends -y git python3-dev build-essential python3-pip\nENV LLAMA_CUBLAS=1\nRUN pip uninstall -y llama-cpp-python && pip install llama-cpp-python\nENV EXTRA_LAUNCH_ARGS=\"\"\nCMD [\"python3\", \"/app/server.py\"]\n\nFROM base AS monkey-patch\nRUN echo \"4-BIT MONKEY-PATCH\" >> /variant.txt\nRUN apt-get install --no-install-recommends -y git python3-dev build-essential python3-pip\nRUN git clone https://github.com/johnsmith0031/alpaca_lora_4bit /app/repositories/alpaca_lora_4bit && \\\n    cd /app/repositories/alpaca_lora_4bit && git checkout 2f704b93c961bf202937b10aac9322b092afdce0\nARG TORCH_CUDA_ARCH_LIST=\"8.6\"\nRUN pip install git+https://github.com/sterlind/GPTQ-for-LLaMa.git@lora_4bit\nENV EXTRA_LAUNCH_ARGS=\"\"\nCMD [\"python3\", \"/app/server.py\", \"--monkey-patch\"]\n\nFROM base AS default\nRUN echo \"DEFAULT\" >> /variant.txt\nENV EXTRA_LAUNCH_ARGS=\"\"\nCMD [\"python3\", \"/app/server.py\"]\n"
  },
  {
    "path": "tgwui/config/loras/place-your-loras-here.txt",
    "content": ""
  },
  {
    "path": "tgwui/config/presets/Debug-deterministic.yaml",
    "content": "do_sample: False\n"
  },
  {
    "path": "tgwui/config/presets/Kobold-Godlike.yaml",
    "content": "do_sample: true\ntop_p: 0.5\ntop_k: 0\ntemperature: 0.7\nrepetition_penalty: 1.1\ntypical_p: 0.19\n"
  },
  {
    "path": "tgwui/config/presets/Kobold-Liminal Drift.yaml",
    "content": "do_sample: true\ntop_p: 1.0\ntop_k: 0\ntemperature: 0.66\nrepetition_penalty: 1.1\ntypical_p: 0.6\n"
  },
  {
    "path": "tgwui/config/presets/LLaMA-Precise.yaml",
    "content": "do_sample: true\ntop_p: 0.1\ntop_k: 40\ntemperature: 0.7\nrepetition_penalty: 1.18\ntypical_p: 1.0\n"
  },
  {
    "path": "tgwui/config/presets/Naive.yaml",
    "content": "do_sample: true\ntemperature: 0.7\ntop_p: 0.85\ntop_k: 50\n"
  },
  {
    "path": "tgwui/config/presets/NovelAI-Best Guess.yaml",
    "content": "do_sample: true\ntop_p: 0.9\ntop_k: 100\ntemperature: 0.8\nrepetition_penalty: 1.15\ntypical_p: 1.0\n"
  },
  {
    "path": "tgwui/config/presets/NovelAI-Decadence.yaml",
    "content": "do_sample: true\ntop_p: 1.0\ntop_k: 100\ntemperature: 2\nrepetition_penalty: 1\ntypical_p: 0.97\n"
  },
  {
    "path": "tgwui/config/presets/NovelAI-Genesis.yaml",
    "content": "do_sample: true\ntop_p: 0.98\ntop_k: 0\ntemperature: 0.63\nrepetition_penalty: 1.05\ntypical_p: 1.0\n"
  },
  {
    "path": "tgwui/config/presets/NovelAI-Lycaenidae.yaml",
    "content": "do_sample: true\ntop_p: 0.85\ntop_k: 12\ntemperature: 2\nrepetition_penalty: 1.15\ntypical_p: 1.0\n"
  },
  {
    "path": "tgwui/config/presets/NovelAI-Ouroboros.yaml",
    "content": "do_sample: true\ntop_p: 1.0\ntop_k: 100\ntemperature: 1.07\nrepetition_penalty: 1.05\ntypical_p: 1.0\n"
  },
  {
    "path": "tgwui/config/presets/NovelAI-Pleasing Results.yaml",
    "content": "do_sample: true\ntop_p: 1.0\ntop_k: 0\ntemperature: 0.44\nrepetition_penalty: 1.15\ntypical_p: 1.0\n"
  },
  {
    "path": "tgwui/config/presets/NovelAI-Sphinx Moth.yaml",
    "content": "do_sample: true\ntop_p: 0.18\ntop_k: 30\ntemperature: 2.0\nrepetition_penalty: 1.15\ntypical_p: 1.0\n"
  },
  {
    "path": "tgwui/config/presets/NovelAI-Storywriter.yaml",
    "content": "do_sample: true\ntop_p: 0.73\ntop_k: 0\ntemperature: 0.72\nrepetition_penalty: 1.1\ntypical_p: 1.0\n"
  },
  {
    "path": "tgwui/config/presets/Special-Contrastive Search.yaml",
    "content": "do_sample: False\npenalty_alpha: 0.6\ntop_k: 4\n"
  },
  {
    "path": "tgwui/config/presets/Special-Eta Sampling.yaml",
    "content": "do_sample: true\neta_cutoff: 3\ntemperature: 0.7\nrepetition_penalty: 1.18\n"
  },
  {
    "path": "tgwui/config/prompts/Alpaca-with-Input.txt",
    "content": "Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request.\n\n### Instruction:\nInstruction\n\n### Input:\nInput\n\n### Response:\n\n"
  },
  {
    "path": "tgwui/config/prompts/GPT-4chan.txt",
    "content": "-----\n--- 865467536\nHello, AI frens!\nHow are you doing on this fine day?\n--- 865467537\n\n"
  },
  {
    "path": "tgwui/config/prompts/QA.txt",
    "content": "Common sense questions and answers\n\nQuestion: \nFactual answer:\n"
  },
  {
    "path": "tgwui/config/training/datasets/put-trainer-datasets-here.txt",
    "content": ""
  },
  {
    "path": "tgwui/config/training/formats/alpaca-chatbot-format.json",
    "content": "{\n    \"instruction,output\": \"User: %instruction%\\nAssistant: %output%\",\n    \"instruction,input,output\": \"User: %instruction%: %input%\\nAssistant: %output%\"\n}\n"
  },
  {
    "path": "tgwui/config/training/formats/alpaca-format.json",
    "content": "{\n    \"instruction,output\": \"Below is an instruction that describes a task. Write a response that appropriately completes the request.\\n\\n### Instruction:\\n%instruction%\\n\\n### Response:\\n%output%\",\n    \"instruction,input,output\": \"Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request.\\n\\n### Instruction:\\n%instruction%\\n\\n### Input:\\n%input%\\n\\n### Response:\\n%output%\"\n}\n"
  },
  {
    "path": "tgwui/scripts/build_extensions.sh",
    "content": "#!/bin/bash\n\n# Specify the directory containing the top-level folders\ndirectory=\"/app/extensions\"\n\n# Iterate over the top-level folders\nfor folder in \"$directory\"/*; do\n    if [ -d \"$folder\" ]; then\n        # Change directory to the current folder\n        cd \"$folder\"\n\n        # Check if requirements.txt file exists\n        if [ -f \"requirements.txt\" ]; then\n            echo \"Installing requirements in $folder...\"\n            pip3 install -r requirements.txt\n            echo \"Requirements installed in $folder\"\n        else\n            echo \"Skipping $folder: requirements.txt not found\"\n        fi\n\n        # Change back to the original directory\n        cd \"$directory\"\n    fi\ndone\n\n"
  },
  {
    "path": "tgwui/scripts/docker-entrypoint.sh",
    "content": "#!/bin/bash\n\n# Function to handle keyboard interrupt\nfunction ctrl_c {\n    echo -e \"\\nKilling container!\"\n    # Add your cleanup actions here\n    exit 0\n}\n# Register the keyboard interrupt handler\ntrap ctrl_c SIGTERM SIGINT SIGQUIT SIGHUP\n\n# Generate default configs if empty\nCONFIG_DIRECTORIES=(\"loras\" \"models\" \"presets\" \"prompts\" \"training/datasets\" \"training/formats\")\nfor config_dir in \"${CONFIG_DIRECTORIES[@]}\"; do\n  if [ -z \"$(ls /app/\"$config_dir\")\" ]; then\n    echo \"*** Initialising config for: '$config_dir' ***\"\n    cp -ar /src/\"$config_dir\"/* /app/\"$config_dir\"/\n    chown -R 1000:1000 /app/\"$config_dir\"  # Not ideal... but convenient.\n  fi\ndone\n\n# Print variant\nVARIANT=$(cat /variant.txt)\necho \"=== Running text-generation-webui variant: '$VARIANT' ===\" \n\n# Print version freshness\ncur_dir=$(pwd)\nsrc_dir=\"/src\"\ncd $src_dir\ngit fetch origin >/dev/null 2>&1\nif [ $? -ne 0 ]; then\n  # An error occurred\n  COMMITS_BEHIND=\"UNKNOWN\"\nelse\n  # The command executed successfully\n  COMMITS_BEHIND=$(git rev-list HEAD..origin --count)\nfi\necho \"=== (This version is $COMMITS_BEHIND commits behind origin) ===\" \ncd $cur_dir\n\n# Print build date\nBUILD_DATE=$(cat /build_date.txt)\necho \"=== Image build date: $BUILD_DATE ===\" \n\n# Assemble CMD and extra launch args\neval \"extra_launch_args=($EXTRA_LAUNCH_ARGS)\"\nLAUNCHER=($@ $extra_launch_args)\n\n# Launch the server with ${CMD[@]} + ${EXTRA_LAUNCH_ARGS[@]}\n\"${LAUNCHER[@]}\"\n"
  },
  {
    "path": "ui.py",
    "content": "import os\r\nimport sys\r\nimport subprocess\r\nfrom time import sleep\r\nimport shutil\r\nfrom sys import platform\r\nfrom superagi.lib.logger import logger\r\n\r\ndef check_command(command, message):\r\n    if not shutil.which(command):\r\n        logger.info(message)\r\n        sys.exit(1)\r\n\r\n\r\ndef run_npm_commands(shell=False):\r\n    os.chdir(\"gui\")\r\n    try:\r\n        subprocess.run([\"npm\", \"install\"], check=True,shell=shell)\r\n    except subprocess.CalledProcessError:\r\n        logger.error(f\"Error during '{' '.join(sys.exc_info()[1].cmd)}'. Exiting.\")\r\n        sys.exit(1)\r\n    os.chdir(\"..\")\r\n\r\n\r\ndef run_server(shell=False):\r\n    api_process = subprocess.Popen([\"uvicorn\", \"main:app\", \"--host\", \"0.0.0.0\", \"--port\", \"8000\"], shell=shell)\r\n    # celery_process = None\r\n    celery_process = subprocess.Popen([\"celery\", \"-A\", \"superagi.worker\", \"worker\", \"--loglevel=info\"], shell=shell)\r\n    os.chdir(\"gui\")\r\n    ui_process = subprocess.Popen([\"npm\", \"run\", \"dev\"], shell=shell)\r\n    os.chdir(\"..\")\r\n    return api_process, ui_process , celery_process\r\n\r\n\r\ndef cleanup(api_process, ui_process, celery_process):\r\n    logger.info(\"Shutting down processes...\")\r\n    api_process.terminate()\r\n    ui_process.terminate()\r\n    celery_process.terminate()\r\n    logger.info(\"Processes terminated. Exiting.\")\r\n    sys.exit(1)\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    check_command(\"node\", \"Node.js is not installed. Please install it and try again.\")\r\n    check_command(\"npm\", \"npm is not installed. Please install npm to proceed.\")\r\n    check_command(\"uvicorn\", \"uvicorn is not installed. Please install uvicorn to proceed.\")\r\n\r\n    isWindows = False\r\n    if platform == \"win32\" or platform == \"cygwin\":\r\n        isWindows = True\r\n    run_npm_commands(shell=isWindows)\r\n\r\n    try:\r\n        api_process, ui_process, celery_process = run_server(isWindows)\r\n        while True:\r\n            try:\r\n                sleep(30)\r\n            except KeyboardInterrupt:\r\n                cleanup(api_process, ui_process, celery_process)\r\n    except Exception as e:\r\n        cleanup(api_process, ui_process, celery_process)"
  },
  {
    "path": "wait-for-it.sh",
    "content": "#!/usr/bin/env bash\n# Use this script to test if a given TCP host/port are available\n\nWAITFORIT_cmdname=${0##*/}\n\nechoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo \"$@\" 1>&2; fi }\n\nusage()\n{\n    cat << USAGE >&2\nUsage:\n    $WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args]\n    -h HOST | --host=HOST       Host or IP under test\n    -p PORT | --port=PORT       TCP port under test\n                                Alternatively, you specify the host and port as host:port\n    -s | --strict               Only execute subcommand if the test succeeds\n    -q | --quiet                Don't output any status messages\n    -t TIMEOUT | --timeout=TIMEOUT\n                                Timeout in seconds, zero for no timeout\n    -- COMMAND ARGS             Execute command with args after the test finishes\nUSAGE\n    exit 1\n}\n\nwait_for()\n{\n    if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then\n        echoerr \"$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT\"\n    else\n        echoerr \"$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout\"\n    fi\n    WAITFORIT_start_ts=$(date +%s)\n    while :\n    do\n        if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then\n            nc -z $WAITFORIT_HOST $WAITFORIT_PORT\n            WAITFORIT_result=$?\n        else\n            (echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1\n            WAITFORIT_result=$?\n        fi\n        if [[ $WAITFORIT_result -eq 0 ]]; then\n            WAITFORIT_end_ts=$(date +%s)\n            echoerr \"$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds\"\n            break\n        fi\n        sleep 1\n    done\n    return $WAITFORIT_result\n}\n\nwait_for_wrapper()\n{\n    # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692\n    if [[ $WAITFORIT_QUIET -eq 1 ]]; then\n        timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &\n    else\n        timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &\n    fi\n    WAITFORIT_PID=$!\n    trap \"kill -INT -$WAITFORIT_PID\" INT\n    wait $WAITFORIT_PID\n    WAITFORIT_RESULT=$?\n    if [[ $WAITFORIT_RESULT -ne 0 ]]; then\n        echoerr \"$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT\"\n    fi\n    return $WAITFORIT_RESULT\n}\n\n# process arguments\nwhile [[ $# -gt 0 ]]\ndo\n    case \"$1\" in\n        *:* )\n        WAITFORIT_hostport=(${1//:/ })\n        WAITFORIT_HOST=${WAITFORIT_hostport[0]}\n        WAITFORIT_PORT=${WAITFORIT_hostport[1]}\n        shift 1\n        ;;\n        --child)\n        WAITFORIT_CHILD=1\n        shift 1\n        ;;\n        -q | --quiet)\n        WAITFORIT_QUIET=1\n        shift 1\n        ;;\n        -s | --strict)\n        WAITFORIT_STRICT=1\n        shift 1\n        ;;\n        -h)\n        WAITFORIT_HOST=\"$2\"\n        if [[ $WAITFORIT_HOST == \"\" ]]; then break; fi\n        shift 2\n        ;;\n        --host=*)\n        WAITFORIT_HOST=\"${1#*=}\"\n        shift 1\n        ;;\n        -p)\n        WAITFORIT_PORT=\"$2\"\n        if [[ $WAITFORIT_PORT == \"\" ]]; then break; fi\n        shift 2\n        ;;\n        --port=*)\n        WAITFORIT_PORT=\"${1#*=}\"\n        shift 1\n        ;;\n        -t)\n        WAITFORIT_TIMEOUT=\"$2\"\n        if [[ $WAITFORIT_TIMEOUT == \"\" ]]; then break; fi\n        shift 2\n        ;;\n        --timeout=*)\n        WAITFORIT_TIMEOUT=\"${1#*=}\"\n        shift 1\n        ;;\n        --)\n        shift\n        WAITFORIT_CLI=(\"$@\")\n        break\n        ;;\n        --help)\n        usage\n        ;;\n        *)\n        echoerr \"Unknown argument: $1\"\n        usage\n        ;;\n    esac\ndone\n\nif [[ \"$WAITFORIT_HOST\" == \"\" || \"$WAITFORIT_PORT\" == \"\" ]]; then\n    echoerr \"Error: you need to provide a host and port to test.\"\n    usage\nfi\n\nWAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15}\nWAITFORIT_STRICT=${WAITFORIT_STRICT:-0}\nWAITFORIT_CHILD=${WAITFORIT_CHILD:-0}\nWAITFORIT_QUIET=${WAITFORIT_QUIET:-0}\n\n# Check to see if timeout is from busybox?\nWAITFORIT_TIMEOUT_PATH=$(type -p timeout)\nWAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)\n\nWAITFORIT_BUSYTIMEFLAG=\"\"\nif [[ $WAITFORIT_TIMEOUT_PATH =~ \"busybox\" ]]; then\n    WAITFORIT_ISBUSY=1\n    # Check if busybox timeout uses -t flag\n    # (recent Alpine versions don't support -t anymore)\n    if timeout &>/dev/stdout | grep -q -e '-t '; then\n        WAITFORIT_BUSYTIMEFLAG=\"-t\"\n    fi\nelse\n    WAITFORIT_ISBUSY=0\nfi\n\nif [[ $WAITFORIT_CHILD -gt 0 ]]; then\n    wait_for\n    WAITFORIT_RESULT=$?\n    exit $WAITFORIT_RESULT\nelse\n    if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then\n        wait_for_wrapper\n        WAITFORIT_RESULT=$?\n    else\n        wait_for\n        WAITFORIT_RESULT=$?\n    fi\nfi\n\nif [[ $WAITFORIT_CLI != \"\" ]]; then\n    if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then\n        echoerr \"$WAITFORIT_cmdname: strict mode, refusing to execute subprocess\"\n        exit $WAITFORIT_RESULT\n    fi\n    exec \"${WAITFORIT_CLI[@]}\"\nelse\n    exit $WAITFORIT_RESULT\nfi\n"
  }
]