[
  {
    "path": ".gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\nshare/python-wheels/\n*.egg-info/\n.installed.cfg\n*.egg\nMANIFEST\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.nox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n*.py,cover\n.hypothesis/\n.pytest_cache/\ncover/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\ndb.sqlite3\ndb.sqlite3-journal\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\n.pybuilder/\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# IPython\nprofile_default/\nipython_config.py\n\n# pyenv\n#   For a library or package, you might want to ignore these files since the code is\n#   intended to run in multiple environments; otherwise, check them in:\n# .python-version\n\n# pipenv\n#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.\n#   However, in case of collaboration, if having platform-specific dependencies or dependencies\n#   having no cross-platform support, pipenv may install dependencies that don't work, or not\n#   install all needed dependencies.\n#Pipfile.lock\n\n# poetry\n#   Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.\n#   This is especially recommended for binary packages to ensure reproducibility, and is more\n#   commonly ignored for libraries.\n#   https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control\n#poetry.lock\n\n# pdm\n#   Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.\n#pdm.lock\n#   pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it\n#   in version control.\n#   https://pdm.fming.dev/#use-with-ide\n.pdm.toml\n\n# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm\n__pypackages__/\n\n# Celery stuff\ncelerybeat-schedule\ncelerybeat.pid\n\n# SageMath parsed files\n*.sage.py\n\n# Environments\n.env\n.venv\nenv/\nvenv/\nENV/\nenv.bak/\nvenv.bak/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n.dmypy.json\ndmypy.json\n\n# Pyre type checker\n.pyre/\n\n# pytype static type analyzer\n.pytype/\n\n# Cython debug symbols\ncython_debug/\n\n# PyCharm\n#  JetBrains specific template is maintained in a separate JetBrains.gitignore that can\n#  be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore\n#  and can be added to the global gitignore or merged into this file.  For a more nuclear\n#  option (not recommended) you can uncomment the following to ignore the entire idea folder.\n#.idea/\n\n# Custom ignores\nfunztionz.db\nencryption_key.json\n"
  },
  {
    "path": ".replit",
    "content": "entrypoint = \"main.py\"\nmodules = [\"python-3.11\"]\n\n[nix]\nchannel = \"stable-24_05\"\n\n[unitTest]\nlanguage = \"python3\"\n\n[gitHubImport]\nrequiredFiles = [\".replit\", \"replit.nix\"]\n\n[deployment]\nrun = [\"python3\", \"main.py\"]\ndeploymentTarget = \"cloudrun\"\n\n[[ports]]\nlocalPort = 5000\nexternalPort = 5000\n\n[[ports]]\nlocalPort = 8000\nexternalPort = 8000\n\n[[ports]]\nlocalPort = 8080\nexternalPort = 80\n"
  },
  {
    "path": "CNAME",
    "content": "babyagi.org"
  },
  {
    "path": "CODE_READINESS_ANALYSIS.md",
    "content": "# BabyAGI Code Readiness Analysis\n\n**Analysis Date:** January 2026\n**Repository:** yoheinakajima/babyagi\n**Verdict:** **NOT PRODUCTION READY**\n\n---\n\n## Executive Summary\n\nBabyAGI is an experimental self-building autonomous agent framework built on a custom \"functionz\" function management system. **The author explicitly states this is not meant for production use**, and this analysis confirms that assessment. While the project demonstrates innovative ideas around self-building agents, it has significant issues that must be addressed before recommending it for general use.\n\n### Quick Assessment\n\n| Category | Score | Status |\n|----------|-------|--------|\n| Security | 2/10 | **Critical Issues** |\n| Testing | 0/10 | **No Tests** |\n| Documentation | 4.5/10 | **Moderate** |\n| Error Handling | 6.5/10 | **Mixed** |\n| Dependencies | 3/10 | **Poor** |\n| Code Quality | 5/10 | **Experimental** |\n| **Overall Readiness** | **3/10** | **Not Ready** |\n\n---\n\n## 1. Project Overview\n\n### What is BabyAGI?\n\nBabyAGI is an experimental framework for a self-building autonomous agent. The core philosophy is that \"the optimal way to build a general autonomous agent is to build the simplest thing that can build itself.\"\n\n**Key Components:**\n- **Functionz Framework**: Core engine for storing, managing, and executing functions from a database\n- **Flask Dashboard**: Web UI for function management, monitoring, and logs\n- **REST API**: Endpoints for programmatic function management\n- **Function Packs**: Pre-built function libraries (default, drafts, plugins)\n- **Self-Building Agents**: Experimental features for AI-powered function generation\n\n### Author's Own Assessment\n\nFrom the README:\n> *\"This is a framework built by Yohei who has never held a job as a developer. The purpose of this repo is to share ideas and spark discussion and for experienced devs to play with. **Not meant for production use**. Use with caution.\"*\n\n---\n\n## 2. Critical Issues Requiring Immediate Attention\n\n### 2.1 Security Vulnerabilities\n\n#### CRITICAL: Arbitrary Code Execution (RCE)\n\n**Location:** `babyagi/functionz/core/execution.py:44, 122`\n\nThe framework uses `exec()` to execute function code stored in the database without any sandboxing or validation:\n\n```python\nexec(function_version['code'], local_scope)\n```\n\n**Risk:** Anyone who can write to the database can execute arbitrary code on the host system.\n\n#### CRITICAL: SQL Injection\n\n**Location:** `babyagi/functionz/packs/drafts/user_db.py:251`\n\nRaw SQL is constructed using f-strings:\n\n```python\nalter_stmt = f'ALTER TABLE {table_name} ADD COLUMN {new_column.name} {new_column.type}'\nuser_db.engine.execute(alter_stmt)\n```\n\n**Risk:** Complete database compromise through malicious table names.\n\n#### CRITICAL: Encryption Key Exposure\n\n**Location:** `babyagi/functionz/db/models.py:28`\n\nThe encryption key is printed to stdout/logs:\n\n```python\nprint(f\"Using encryption key: {ENCRYPTION_KEY}\")\n```\n\n**Risk:** All encrypted secrets can be decrypted if logs are accessible.\n\n#### HIGH: Secrets Injection Without Scoping\n\n**Location:** `babyagi/functionz/core/execution.py:158-162`\n\nALL stored secret keys are injected into every function's execution scope:\n\n```python\nlocal_scope.update(secret_keys)  # All secrets available to any function\n```\n\n**Risk:** Any function can access all stored credentials.\n\n### 2.2 No Test Coverage\n\n**Finding:** Zero tests exist in the entire codebase.\n\n- No `test_*.py` files\n- No `tests/` directory\n- No pytest, unittest, or any test framework configured\n- No CI/CD pipeline\n\n**Impact:** No automated verification that the code works correctly. Any change could introduce regressions without detection.\n\n### 2.3 Dependency Management Chaos\n\n**Finding:** Three conflicting dependency systems:\n\n1. `requirements.txt` (pip)\n2. `pyproject.toml` (Poetry)\n3. `setup.py` (setuptools)\n\n**Critical Problems:**\n- `poetry.lock` only tracks 11 packages; core dependencies like SQLAlchemy, cryptography, scikit-learn are missing\n- Four critical packages have NO version constraints: `cryptography`, `scikit-learn`, `litellm`, `openai`\n- Version conflicts: setup.py says Python >=3.6, pyproject.toml says >=3.10.0,<3.12\n- Package versions out of sync (setup.py: 0.1.2, pyproject.toml: 0.0.8)\n\n---\n\n## 3. Complete Issue Inventory\n\n### Security Issues (16 found)\n\n| Severity | Issue | Location |\n|----------|-------|----------|\n| CRITICAL | Arbitrary code execution via exec() | execution.py:44,122 |\n| CRITICAL | SQL injection vulnerability | user_db.py:251 |\n| CRITICAL | Encryption key printed to logs | models.py:28 |\n| CRITICAL | Plaintext encryption key file | models.py:15-20 |\n| HIGH | All secrets injected to all functions | execution.py:158-162 |\n| HIGH | Unvalidated pip install of packages | execution.py:19 |\n| HIGH | Insufficient input validation | execution.py:170-174 |\n| HIGH | Weak secret storage mechanism | local_db.py:235-259 |\n| MEDIUM | Debug logging of secret operations | local_db.py:236-244 |\n| MEDIUM | Database file permissions unset | local_db.py:14 |\n| MEDIUM | No CSRF protection | api/__init__.py |\n| MEDIUM | No rate limiting | api/__init__.py |\n| MEDIUM | Unvalidated dynamic imports | execution.py:32-35 |\n| MEDIUM | Duplicate method definitions | local_db.py:235,248 |\n| LOW | No timeout on code execution | execution.py:55-141 |\n| LOW | No authentication on API/dashboard | Multiple files |\n\n### Code Quality Issues\n\n| Issue | Location | Impact |\n|-------|----------|--------|\n| Silent exception suppression | `__init__.py:122-123` | Errors hidden from users |\n| print() instead of logging | Multiple files | Inconsistent logging |\n| No custom exception classes | Entire codebase | Poor error semantics |\n| Extensive DEBUG print statements | drafts/*.py | Development code in repo |\n\n### Incomplete/Experimental Features\n\nThe `drafts/` directory contains experimental features explicitly marked as incomplete:\n\n- `generate_function.py` - 674 lines with 26+ DEBUG statements\n- `self_build.py` / `self_build2.py` - Self-building agent experiments\n- `choose_or_create_function.py` - Function selection logic\n- `react_agent.py` - ReAct agent implementation\n\nFrom README: *\"These draft features are experimental concepts and may not function as intended. They require significant improvements and should be used with caution.\"*\n\n---\n\n## 4. Documentation Assessment\n\n### Strengths\n- Well-structured README with clear quick start\n- Good examples in `examples/` directory\n- Progressive complexity from basic to advanced features\n- Clear warnings about experimental status\n\n### Gaps\n- No API documentation (no OpenAPI/Swagger spec)\n- Limited docstrings (56% coverage, but minimal Args/Returns)\n- No architecture documentation\n- No troubleshooting guide\n- No generated documentation (Sphinx, MkDocs, etc.)\n\n**Score: 4.5/10**\n\n---\n\n## 5. Error Handling Assessment\n\n### Strengths\n- No bare `except:` clauses - good practice\n- Widespread try/except coverage in API layer\n- Proper re-raising in critical execution paths\n- Good logging in API/dashboard modules\n\n### Weaknesses\n- Silent exception suppression in `__init__.py` (lines 54-56, 122-123)\n- Inconsistent use of print() vs logging module\n- No custom exception classes\n- Encryption failures silently return None\n\n**Score: 6.5/10**\n\n---\n\n## 6. Architecture Assessment\n\n### Strengths\n- Clean modular structure (core, db, api, dashboard, packs)\n- Separation of concerns between components\n- Decorator-based registration pattern\n- Versioning system for functions\n- Trigger-based automation capability\n\n### Concerns\n- Global singleton pattern for Functionz instance\n- Tight coupling between execution engine and database\n- Dynamic `exec()` of database code is inherently risky\n- No sandboxing or isolation of function execution\n\n---\n\n## 7. Recommendations for Production Readiness\n\n### Must Fix Before Any Use\n\n1. **Remove exec() or add sandboxing** - Consider using RestrictedPython or containerized execution\n2. **Fix SQL injection** - Use parameterized queries exclusively\n3. **Stop logging encryption key** - Remove the print statement immediately\n4. **Add scope-based secret injection** - Only inject secrets required by each function\n5. **Add authentication** - Protect API and dashboard endpoints\n6. **Add test suite** - Minimum 80% coverage on core components\n\n### Should Fix\n\n6. **Consolidate dependency management** - Pick one system (recommend Poetry)\n7. **Pin all dependencies** - Especially security-critical packages\n8. **Replace print() with logging** - Consistent logging configuration\n9. **Add custom exceptions** - Improve error semantics\n10. **Add input validation** - Type and value validation on all inputs\n\n### Nice to Have\n\n11. **Add API documentation** - OpenAPI/Swagger specification\n12. **Set up CI/CD** - Automated testing and security scanning\n13. **Add execution timeouts** - Prevent infinite loops\n14. **Add rate limiting** - Prevent abuse\n15. **Document architecture** - Help contributors understand the system\n\n---\n\n## 8. Conclusion\n\n**BabyAGI is an interesting experimental project that demonstrates innovative ideas about self-building autonomous agents.** However, it has critical security vulnerabilities, no tests, and dependency management issues that make it unsuitable for any production use or recommendation to others.\n\n### Who Should Use This?\n\n- **Researchers** exploring self-building agent concepts\n- **Experienced developers** who can identify and work around the issues\n- **Contributors** who want to help improve the framework\n\n### Who Should NOT Use This?\n\n- Anyone building production systems\n- Developers who need reliable, tested code\n- Projects that require security compliance\n- Teams without security expertise to mitigate the risks\n\n### Bottom Line\n\nThe author is transparent about the experimental nature of this project. **Respect that warning.** If you want to experiment with the concepts, understand that you're working with early-stage research code that has significant issues. If you need a production-ready agent framework, look elsewhere or contribute to making BabyAGI production-ready.\n\n---\n\n## Appendix: Files Reviewed\n\n### Core Framework\n- `babyagi/__init__.py` (140 lines)\n- `babyagi/functionz/core/framework.py` (149 lines)\n- `babyagi/functionz/core/execution.py` (254 lines)\n- `babyagi/functionz/core/registration.py` (266 lines)\n\n### Database Layer\n- `babyagi/functionz/db/base_db.py` (62 lines)\n- `babyagi/functionz/db/local_db.py` (259 lines)\n- `babyagi/functionz/db/db_router.py` (301 lines)\n- `babyagi/functionz/db/models.py` (~130 lines)\n\n### API/Dashboard\n- `babyagi/api/__init__.py` (158 lines)\n- `babyagi/dashboard/__init__.py` (132 lines)\n\n### Function Packs\n- `babyagi/functionz/packs/default/*.py`\n- `babyagi/functionz/packs/drafts/*.py`\n- `babyagi/functionz/packs/plugins/*.py`\n\n### Configuration\n- `requirements.txt`\n- `pyproject.toml`\n- `setup.py`\n- `poetry.lock`\n- `README.md`\n"
  },
  {
    "path": "MANIFEST.in",
    "content": "# Include the README and LICENSE\ninclude README.md\ninclude LICENSE\n\n# Include all package directories and their contents\nrecursive-include babyagi *\n\n# Include examples\nrecursive-include examples *\n\n# Exclude specific sensitive or unwanted files\nexclude encryption_key.json\nexclude funztionz.db\n\n# Exclude other unnecessary files\nglobal-exclude *.pyc\nglobal-exclude __pycache__/\n\n# Exclude .git and .gitignore\nglobal-exclude .git\nglobal-exclude .gitignore\n\n# Exclude .egg-info directory and files\nglobal-exclude *.egg-info\nglobal-exclude *.egg-info/*\n"
  },
  {
    "path": "README.md",
    "content": "# BabyAGI\n\n> [!NOTE]\n> The original BabyAGI from March 2023 introduced task planning as a method for developing autonomous agents. This project has been archived and moved to the [babyagi_archive](https://github.com/yoheinakajima/babyagi_archive) repo (September 2024 snapshot).\n\n> [!CAUTION]\n> This is a framework built by Yohei who has never held a job as a developer. The purpose of this repo is to share ideas and spark discussion and for experienced devs to play with. Not meant for production use. Use with cautioun.\n\n---\n\nThis newest BabyAGI is an experimental framework for a self-building autonomous agent. Earlier efforts to expand BabyAGI have made it clear that the optimal way to build a general autonomous agent is to build the simplest thing that can build itself.\n\nCheck out [this introductory X/Twitter thread](https://x.com/yoheinakajima/status/1840678823681282228) for a simple overview.\n\nThe core is a new function framework (**functionz**) for storing, managing, and executing functions from a database. It offers a graph-based structure for tracking imports, dependent functions, and authentication secrets, with automatic loading and comprehensive logging capabilities. Additionally, it comes with a dashboard for managing functions, running updates, and viewing logs.\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Basic Usage](#basic-usage)\n- [Function Metadata](#function-metadata)\n- [Function Loading](#function-loading)\n- [Key Dependencies](#key-dependencies)\n- [Execution Environment](#execution-environment)\n  - [Log](#log)\n- [Dashboard](#dashboard)\n- [Pre-loaded Functions](#pre-loaded-functions)\n- [Future/Draft Features](#futuredraft-features)\n- [API Reference](#api-reference)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Quick Start\n\nTo quickly check out the dashboard and see how it works:\n\n1. **Install BabyAGI:**\n\n    ```bash\n    pip install babyagi\n    ```\n\n2. **Import BabyAGI and load the dashboard:**\n\n    ```python\n    import babyagi\n\n    if __name__ == \"__main__\":\n        app = babyagi.create_app('/dashboard')\n        app.run(host='0.0.0.0', port=8080)\n    ```\n\n3. **Navigate to the dashboard:**\n\n    Open your browser and go to `http://localhost:8080/dashboard` to access the BabyAGI dashboard.\n    \n## Basic Usage\n\nStart by importing `babyagi` and registering your functions. Here's how to register two functions, where one depends on the other:\n\n```python\nimport babyagi\n\n# Register a simple function\n@babyagi.register_function()\ndef world():\n    return \"world\"\n\n# Register a function that depends on 'world'\n@babyagi.register_function(dependencies=[\"world\"])\ndef hello_world():\n    x = world()\n    return f\"Hello {x}!\"\n\n# Execute the function\nprint(babyagi.hello_world())  # Output: Hello world!\n\nif __name__ == \"__main__\":\n    app = babyagi.create_app('/dashboard')\n    app.run(host='0.0.0.0', port=8080)\n```\n\n## Function Metadata\n\nFunctions can be registered with metadata to enhance their capabilities and manage their relationships. Here's a more comprehensive example of function metadata, showing logical usage of all fields:\n\n```python\nimport babyagi\n\n@babyagi.register_function(\n    imports=[\"math\"],\n    dependencies=[\"circle_area\"],\n    key_dependencies=[\"openai_api_key\"],\n    metadata={\n        \"description\": \"Calculates the volume of a cylinder using the circle_area function.\"\n    }\n)\ndef cylinder_volume(radius, height):\n    import math\n    area = circle_area(radius)\n    return area * height\n```\n\n**Available Metadata Fields:**\n\n- `imports`: List of external libraries the function depends on.\n- `dependencies`: List of other functions this function depends on.\n- `key_dependencies`: List of secret keys required by the function.\n- `metadata[\"description\"]`: A description of what the function does.\n\n## Function Loading\n\nIn addition to using `register_function`, you can use `load_function` to load plugins or draft packs of functions. BabyAGI comes with built-in function packs, or you can load your own packs by pointing to the file path.\n\nYou can find available function packs in `babyagi/functionz/packs`.\n\n**Loading Custom Function Packs:**\n\n```python\nimport babyagi\n\n# Load your custom function pack\nbabyagi.load_functions(\"path/to/your/custom_functions.py\")\n```\n\nThis approach makes function building and management easier by organizing related functions into packs.\n\n## Key Dependencies\n\nYou can store `key_dependencies` directly from your code or manage them via the dashboard.\n\n**Storing Key Dependencies from Code:**\n\n```python\nimport babyagi\n\n# Add a secret key\nbabyagi.add_key_wrapper('openai_api_key', 'your_openai_api_key')\n```\n\n**Adding Key Dependencies via Dashboard:**\n\nNavigate to the dashboard and use the **add_key_wrapper** feature to securely add your secret keys.\n\n## Execution Environment\n\nBabyAGI automatically loads essential function packs and manages their dependencies, ensuring a seamless execution environment. Additionally, it logs all activities, including the relationships between functions, to provide comprehensive tracking of function executions and dependencies.\n\n### Log\n\nBabyAGI implements a comprehensive logging system to track all function executions and their interactions. The logging mechanism ensures that every function call, including its inputs, outputs, execution time, and any errors, is recorded for monitoring and debugging purposes.\n\n**Key Logging Features:**\n\n- **Execution Tracking:** Logs when a function starts and finishes execution, including the function name, arguments, keyword arguments, and execution time.\n  \n- **Error Logging:** Captures and logs any errors that occur during function execution, providing detailed error messages for troubleshooting.\n\n- **Dependency Management:** Automatically resolves and logs dependencies between functions, ensuring that all required functions and libraries are loaded before execution.\n\n- **Trigger Logging:** Logs the execution of triggered functions, detailing which functions were triggered by others and their respective execution outcomes.\n\n- **Comprehensive Records:** Maintains a history of all function executions, enabling users to review past activities, understand function relationships, and analyze performance metrics.\n\n**How Triggers Work:**\n\nTriggers are mechanisms that allow certain functions to be automatically executed in response to specific events or actions within the system. For example, when a function is added or updated, a trigger can initiate the generation of a description for that function.\n\nTriggers enhance the autonomy of BabyAGI by enabling automated workflows and reducing the need for manual intervention. However, it's essential to manage triggers carefully to avoid unintended recursive executions or conflicts between dependent functions.\n\n## Dashboard\n\nThe BabyAGI dashboard offers a user-friendly interface for managing functions, monitoring executions, and handling configurations. Key features include:\n\n- **Function Management:** Register, deregister, and update functions directly from the dashboard.\n\n- **Dependency Visualization:** View and manage dependencies between functions to understand their relationships.\n\n- **Secret Key Management:** Add and manage secret keys securely through the dashboard interface.\n\n- **Logging and Monitoring:** Access comprehensive logs of function executions, including inputs, outputs, and execution times.\n\n- **Trigger Management:** Set up triggers to automate function executions based on specific events or conditions.\n\n**Accessing the Dashboard:**\n\nAfter running your application, navigate to `http://localhost:8080/dashboard` to access the BabyAGI dashboard.\n## Pre-loaded Functions Summary\n\nBabyAGI includes two pre-loaded function packs:\n\n1. **Default Functions (`packs/default_functions.py`):**\n   - **Function Execution:** Run, add, update, or retrieve functions and versions.\n   - **Key Management:** Add and retrieve secret keys.\n   - **Triggers:** Add triggers to execute functions based on others.\n   - **Logs:** Retrieve logs with optional filters.\n\n2. **AI Functions (`packs/ai_generator.py`):**\n   - **AI Description & Embeddings:** Auto-generate descriptions and embeddings for functions.\n   - **Function Selection:** Find or choose similar functions based on prompts.\n\n## Running a Self-Building Agent\n\nBabyAGI includes two experimental self-building agents, showcasing how the framework can help a self-building coding agent leverage existing functions to write new ones.\n\n### 1. `process_user_input` in the `code_writing_functions` pack\n\nThis function first determines whether to use an existing function or generate new ones. If new functions are needed, it breaks them down into smaller reusable components and combines them into a final function.\n\nTry this:\n\n~~~python\nimport babyagi\n\nbabyagi.add_key_wrapper('openai_api_key', os.environ['OPENAI_API_KEY'])\nbabyagi.load_functions(\"drafts/code_writing_functions\")\n\nbabyagi.process_user_input(\"Grab today's score from ESPN and email it to test@test.com\")\n~~~\n\nWhen you run this, you will see the functions being generated in the shell and new functions will be available in the dashboard once completed.\n\n### 2. `self_build` in the `self_build` pack\n\nThis function takes a user description and generates X distinct tasks that a user might ask an AI assistant. Each task is processed by `process_user_input`, creating new functions if no existing ones suffice.\n\nTry this:\n\n~~~python\nimport babyagi\n\nbabyagi.add_key_wrapper('openai_api_key', os.environ['OPENAI_API_KEY'])\nbabyagi.load_functions(\"drafts/code_writing_functions\")\nbabyagi.load_functions(\"drafts/self_build\")\n\nbabyagi.self_build(\"A sales person at an enterprise SaaS company.\", 3)\n~~~\n\nThis will generate 3 distinct tasks a salesperson might ask an AI assistant and create functions to handle those.\n\n*The functions will be generated and stored in the dashboard, but note that the generated code is minimal and may need improvement.\n\n![alt text](https://github.com/yoheinakajima/babyagi_staging/blob/main/self_build.png?raw=true)\n\n\n\n**Warning:** These draft features are experimental concepts and may not function as intended. They require significant improvements and should be used with caution.\n\n\n## Contributing\n\nContributions are greatly appreciatedly, but candidly I have not been great at managing PRs. Please be patient as things will move slow while I am working on this alone (on nights and weekends). I may start by building a small core crew before collaborating with a larger group.\n\nIf you are a dev, investor, friend of open-source and interesting supporting AI work I do, please fill [this form](https://forms.gle/UZLyT75HQULr8XNUA) (I have a few fun initiatives coming up!)\n\n## License\n\nBabyAGI is released under the MIT License. See the [LICENSE](LICENSE) file for more details.\n"
  },
  {
    "path": "babyagi/__init__.py",
    "content": "# babyagi/__init__.py\n\nfrom flask import Flask, g\nfrom .functionz.core.framework import Functionz\nfrom .dashboard import create_dashboard\nfrom .api import create_api_blueprint\nimport os\nimport importlib.util\nimport traceback\nimport sys\n\n# Singleton instance of the functionz framework\n_func_instance = Functionz()\n\n\ndef get_func_instance():\n    return _func_instance\n\ndef create_app(dashboard_route='/dashboard'):\n    app = Flask(__name__)\n\n    # Remove leading slash if present to avoid double slashes\n    if dashboard_route.startswith('/'):\n        dashboard_route = dashboard_route[1:]\n\n    # Create and register the dashboard blueprint with dashboard_route\n    dashboard_blueprint = create_dashboard(_func_instance, dashboard_route)\n\n    # Create and register the API blueprint\n    api_blueprint = create_api_blueprint()\n\n    # Register the blueprints\n    app.register_blueprint(dashboard_blueprint, url_prefix=f'/{dashboard_route}')\n    app.register_blueprint(api_blueprint)  # Mounted at '/api' as defined in the blueprint\n\n    # Store the dashboard route for use in templates\n    app.config['DASHBOARD_ROUTE'] = dashboard_route\n\n    # Ensure the Functionz instance is accessible in the request context\n    @app.before_request\n    def set_functionz():\n        g.functionz = _func_instance\n        g.dashboard_route = dashboard_route  # Optional, if needed globally\n\n    return app\n\n# Function to register functions using the babyagi framework\ndef register_function(*args, **kwargs):\n    def wrapper(func):\n        try:\n            _func_instance.register_function(*args, **kwargs)(func)\n            setattr(sys.modules[__name__], func.__name__, func)\n            #print(f\"Function '{func.__name__}' registered successfully.\")\n        except Exception as e:\n            print(f\"Error registering function '{func.__name__}': {e}\")\n            traceback.print_exc()\n        return func\n    return wrapper\n\n# Function to load additional function packs\ndef load_functions(pack_name_or_path):\n    #print(f\"Attempting to load function pack: {pack_name_or_path}\")\n    if os.path.exists(pack_name_or_path):\n        try:\n            spec = importlib.util.spec_from_file_location(\"custom_pack\", pack_name_or_path)\n            module = importlib.util.module_from_spec(spec)\n            spec.loader.exec_module(module)\n            #print(f\"Custom pack loaded from {pack_name_or_path}\")\n        except Exception as e:\n            #print(f\"Failed to load custom pack from path '{pack_name_or_path}': {e}\")\n            traceback.print_exc()\n    else:\n        try:\n            print(f\"Assuming '{pack_name_or_path}' is an internal pack...\")\n            _func_instance.load_function_pack(pack_name_or_path)\n            print(f\"Internal pack '{pack_name_or_path}' loaded successfully.\")\n        except Exception as e:\n            print(f\"Failed to load internal pack '{pack_name_or_path}': {e}\")\n            traceback.print_exc()\n\n\ndef use_blueprints(app, dashboard_route='/dashboard'):\n    \"\"\"\n    Registers the babyagi blueprints with the provided Flask app.\n\n    Args:\n        app (Flask): The Flask application instance.\n        dashboard_route (str): The route prefix for the dashboard.\n    \"\"\"\n    # Remove leading slash if present\n    if dashboard_route.startswith('/'):\n        dashboard_route = dashboard_route[1:]\n\n    # Create blueprints\n    dashboard_blueprint = create_dashboard(_func_instance, dashboard_route)\n    api_blueprint = create_api_blueprint()\n\n    # Register blueprints\n    app.register_blueprint(dashboard_blueprint, url_prefix=f'/{dashboard_route}')\n    app.register_blueprint(api_blueprint)  # Mounted at '/api' as defined in the blueprint\n\n    # Store the dashboard route for use in templates\n    app.config['DASHBOARD_ROUTE'] = dashboard_route\n\n    # Ensure the Functionz instance is accessible in the request context\n    @app.before_request\n    def set_functionz():\n        g.functionz = _func_instance\n        g.dashboard_route = dashboard_route  # Optional, if needed globally\n\n\ndef __getattr__(name):\n    \"\"\"\n    Dynamic attribute access for the babyagi module.\n    If a function with the given name exists in the database,\n    return a callable that executes the function via the executor.\n    \"\"\"\n    try:\n        if _func_instance.get_function(name):\n            # Return a callable that executes the function via the executor\n            return lambda *args, **kwargs: _func_instance.executor.execute(name, *args, **kwargs)\n    except Exception as e:\n        pass\n    raise AttributeError(f\"module '{__name__}' has no attribute '{name}'\")\n\n\n# Auto-load default function packs when babyagi is imported\ntry:\n    print(\"Attempting to load default function packs...\")\n    # Uncomment if needed\n    _func_instance.load_function_pack('default/default_functions')\n    _func_instance.load_function_pack('default/ai_functions')\n    _func_instance.load_function_pack('default/os')\n    _func_instance.load_function_pack('default/function_calling_chat')\nexcept Exception as e:\n    print(f\"Error loading default function packs: {e}\")\n    traceback.print_exc()\n\nprint(\"babyagi/__init__.py loaded\")\n"
  },
  {
    "path": "babyagi/api/__init__.py",
    "content": "# babyagi/api/__init__.py\n\nfrom flask import Blueprint, jsonify, request, g\nfrom datetime import datetime\nfrom io import StringIO\nimport logging\nimport os\nimport sys\nimport importlib.util\n\nlogger = logging.getLogger(__name__)\n\ndef create_api_blueprint():\n    api = Blueprint('api', __name__, url_prefix='/api')\n\n    # Removed the before_request function since g.functionz is set in the main app\n\n    @api.route('/functions')\n    def get_functions():\n        logger.debug(\"Accessing /api/functions route.\")\n        try:\n            functions = g.functionz.get_all_functions()\n            logger.debug(f\"Retrieved {len(functions)} functions.\")\n            return jsonify(functions)\n        except Exception as e:\n            logger.error(f\"Error in get_functions: {str(e)}\", exc_info=True)\n            return jsonify({\"error\": str(e)}), 500\n\n    @api.route('/function/<function_name>')\n    def get_function(function_name):\n        logger.debug(f\"Accessing /api/function/{function_name} route.\")\n        try:\n            function = g.functionz.db.get_function(function_name)\n            if not function:\n                logger.warning(f\"Function '{function_name}' not found.\")\n                return jsonify({\"error\": f\"Function '{function_name}' not found.\"}), 404\n            return jsonify(function)\n        except Exception as e:\n            logger.error(f\"Error getting function {function_name}: {str(e)}\", exc_info=True)\n            return jsonify({\"error\": str(e)}), 500\n\n    @api.route('/function/<function_name>', methods=['PUT'])\n    def update_function(function_name):\n        logger.debug(f\"Accessing /api/function/{function_name} [PUT] route.\")\n        try:\n            data = request.get_json()\n            if not data or 'code' not in data:\n                logger.warning(\"No 'code' provided in request data.\")\n                return jsonify({\"error\": \"No 'code' provided in request data.\"}), 400\n            g.functionz.update_function(function_name, code=data['code'])\n            logger.info(f\"Function '{function_name}' updated successfully.\")\n            return jsonify({\"status\": \"success\"})\n        except Exception as e:\n            logger.error(f\"Error updating function {function_name}: {str(e)}\", exc_info=True)\n            return jsonify({\"error\": str(e)}), 500\n\n    @api.route('/execute/<function_name>', methods=['POST'])\n    def execute_function(function_name):\n        logger.debug(f\"Accessing /api/execute/{function_name} [POST] route.\")\n        try:\n            params = request.get_json() or {}\n\n            if function_name == 'execute_function_wrapper':\n                # Special handling for execute_function_wrapper\n                inner_function_name = params.pop('function_name', None)\n                args = params.pop('args', [])\n                kwargs = params.pop('kwargs', {})\n                result = g.functionz.executor.execute(function_name, inner_function_name, *args, **kwargs)\n            else:\n                # Normal execution for other functions\n                result = g.functionz.executor.execute(function_name, **params)\n\n            logger.info(f\"Function '{function_name}' executed successfully.\")\n            return jsonify(result)\n        except Exception as e:\n            logger.error(f\"Error executing function {function_name}: {str(e)}\", exc_info=True)\n            return jsonify({\"error\": str(e)}), 500\n\n    @api.route('/function/<function_name>/versions')\n    def get_function_versions(function_name):\n        logger.debug(f\"Accessing /api/function/{function_name}/versions route.\")\n        try:\n            versions = g.functionz.get_function_versions(function_name)\n            logger.debug(f\"Retrieved {len(versions)} versions for function '{function_name}'.\")\n            return jsonify(versions)\n        except Exception as e:\n            logger.error(f\"Error getting versions for function {function_name}: {str(e)}\", exc_info=True)\n            return jsonify({\"error\": str(e)}), 500\n\n    @api.route('/function/<function_name>/activate/<version>', methods=['POST'])\n    def activate_function_version(function_name, version):\n        logger.debug(f\"Accessing /api/function/{function_name}/activate/{version} [POST] route.\")\n        try:\n            g.functionz.activate_function_version(function_name, int(version))\n            logger.info(f\"Version {version} of function '{function_name}' activated successfully.\")\n            return jsonify({\"status\": \"success\"})\n        except ValueError:\n            logger.warning(f\"Invalid version number provided: {version}\")\n            return jsonify({\"error\": \"Invalid version number.\"}), 400\n        except Exception as e:\n            logger.error(f\"Error activating version {version} for function {function_name}: {str(e)}\", exc_info=True)\n            return jsonify({\"error\": str(e)}), 500\n\n\n    @api.route('/logs/<function_name>')\n    @api.route('/logs', defaults={'function_name': None})\n    def get_logs(function_name):\n        logger.debug(f\"Accessing /api/logs/{function_name if function_name else 'all'} route.\")\n        try:\n            start_date_str = request.args.get('start_date')\n            end_date_str = request.args.get('end_date')\n            triggered_by_log_id_str = request.args.get('triggered_by_log_id')  # New filter\n            start_date = datetime.fromisoformat(start_date_str) if start_date_str else None\n            end_date = datetime.fromisoformat(end_date_str) if end_date_str else None\n            triggered_by_log_id = int(triggered_by_log_id_str) if triggered_by_log_id_str else None  # Convert to int if provided\n\n            logs = g.functionz.db.get_logs(function_name, start_date, end_date, triggered_by_log_id)\n            if function_name:\n                logger.debug(f\"Retrieved {len(logs)} logs for function '{function_name}'.\")\n            else:\n                logger.debug(f\"Retrieved {len(logs)} logs for all functions.\")\n            return jsonify(logs)\n        except ValueError:\n            logger.warning(\"Invalid date format or triggered_by_log_id provided.\")\n            return jsonify({\"error\": \"Invalid date format or triggered_by_log_id. Use ISO format for dates and integer for triggered_by_log_id.\"}), 400\n        except Exception as e:\n            logger.error(f\"Error getting logs for function '{function_name}': {str(e)}\", exc_info=True)\n            return jsonify({\"error\": str(e)}), 500\n\n    @api.route('/log_bundle/<int:log_id>')\n    def get_log_bundle(log_id):\n        logger.debug(f\"Accessing /api/log_bundle/{log_id} route.\")\n        try:\n            logs = g.functionz.db.get_log_bundle(log_id)\n            return jsonify({'logs': logs})\n        except Exception as e:\n            logger.error(f\"Error getting log bundle for log_id '{log_id}': {str(e)}\", exc_info=True)\n            return jsonify({\"error\": str(e)}), 500\n\n\n    @api.route('/triggers/<function_name>', methods=['GET'])\n    def get_triggers(function_name):\n        logger.debug(f\"Accessing /api/triggers/{function_name} [GET] route.\")\n        try:\n            triggers = g.functionz.get_triggers_for_function(function_name)\n            trigger_list = [\n                getattr(trigger.triggering_function, 'name', 'any function')\n                for trigger in triggers\n            ]\n            logger.debug(f\"Retrieved {len(trigger_list)} triggers for function '{function_name}'.\")\n            return jsonify(trigger_list)\n        except Exception as e:\n            logger.error(f\"Error getting triggers for function {function_name}: {str(e)}\", exc_info=True)\n            return jsonify({\"error\": str(e)}), 500\n\n\n    logger.info(\"API blueprint created successfully.\")\n    return api\n"
  },
  {
    "path": "babyagi/dashboard/__init__.py",
    "content": "# babyagi/dashboard/__init__.py\n\nfrom flask import Blueprint, render_template, g, send_from_directory\nimport logging\nimport os\n\nlogger = logging.getLogger(__name__)\n\ndef create_dashboard(func_instance, dashboard_route):\n    if func_instance is None:\n        raise ValueError(\"func_instance cannot be None\")\n    if dashboard_route is None:\n        raise ValueError(\"dashboard_route cannot be None\")\n\n    dashboard = Blueprint('dashboard', __name__, \n                          template_folder='templates', \n                          static_folder='static',\n                          static_url_path='/dashboard/static')\n\n    logger.info(\"Creating dashboard blueprint...\")\n\n    @dashboard.before_request\n    def before_request():\n        \"\"\"Set up the necessary context before each request.\"\"\"\n        g.functionz = func_instance\n        g.dashboard_route = dashboard_route\n        logger.debug(\"Set g.functionz and g.dashboard_route for the request context.\")\n\n    @dashboard.route('/')\n    def dashboard_home():\n        logger.info(\"Accessing dashboard home page.\")\n        try:\n            logger.debug(f\"Dashboard Route: {g.dashboard_route}\")\n            return render_template('index.html', dashboard_route=g.dashboard_route)\n        except Exception as e:\n            logger.error(f\"Error in dashboard_home: {str(e)}\", exc_info=True)\n            return f\"Error loading dashboard: {str(e)}\", 500\n\n    @dashboard.route('/function/<function_name>')\n    def function_detail(function_name):\n        logger.info(f\"Accessing function detail for: {function_name}\")\n        try:\n            function = g.functionz.db.get_function(function_name)\n            if not function:\n                logger.warning(f\"Function '{function_name}' not found.\")\n                return f\"Function '{function_name}' not found.\", 404\n            return render_template('function_details.html', function_name=function_name, dashboard_route=g.dashboard_route)\n        except Exception as e:\n            logger.error(f\"Error in function_detail: {str(e)}\", exc_info=True)\n            return f\"Error loading function detail: {str(e)}\", 500\n\n    @dashboard.route('/graph')\n    def function_graph():\n        logger.info(\"Accessing function relationship graph page.\")\n        try:\n            return render_template('function_graph.html', dashboard_route=g.dashboard_route)\n        except Exception as e:\n            logger.error(f\"Error in function_graph: {str(e)}\", exc_info=True)\n            return f\"Error loading function graph: {str(e)}\", 500\n\n    @dashboard.route('/mermaid')\n    def function_graph_mermaid():\n        logger.info(\"Accessing mermaid function relationship graph page.\")\n        try:\n            return render_template('function_graph_mermaid.html', dashboard_route=g.dashboard_route)\n        except Exception as e:\n            logger.error(f\"Error in function_graph_mermaid: {str(e)}\", exc_info=True)\n            return f\"Error loading mermaid function graph: {str(e)}\", 500\n\n    @dashboard.route('/3d')\n    def function_graph_3d():\n        logger.info(\"Accessing 3D function relationship graph page.\")\n        try:\n            return render_template('function_graph_3d.html', dashboard_route=g.dashboard_route)\n        except Exception as e:\n            logger.error(f\"Error in function_graph_3d: {str(e)}\", exc_info=True)\n            return f\"Error loading 3D function graph: {str(e)}\", 500\n\n    @dashboard.route('/logs')\n    def logs_dashboard():\n        logger.info(\"Accessing logs dashboard.\")\n        try:\n            return render_template('logs_dashboard.html', dashboard_route=g.dashboard_route)\n        except Exception as e:\n            logger.error(f\"Error in logs_dashboard: {str(e)}\", exc_info=True)\n            return f\"Error loading logs dashboard: {str(e)}\", 500\n\n    @dashboard.route('/log/<int:log_id>')\n    def log_page(log_id):\n        logger.info(f\"Accessing log page for Log ID {log_id}.\")\n        try:\n            return render_template(\n                'log_page.html',\n                log_id=log_id,\n                dashboard_route=g.dashboard_route  # Pass the dashboard route if needed\n            )\n        except Exception as e:\n            logger.error(f\"Error in log_page for Log ID {log_id}: {str(e)}\", exc_info=True)\n            return f\"Error loading log page for Log ID {log_id}: {str(e)}\", 500\n    \n    @dashboard.route('/log_graph')\n    def log_relationship_graph():\n        logger.info(\"Accessing log relationship graph.\")\n        try:\n            return render_template('log_relationship_graph.html', dashboard_route=g.dashboard_route)\n        except Exception as e:\n            logger.error(f\"Error in log_relationship_graph: {str(e)}\", exc_info=True)\n            return f\"Error loading log relationship graph: {str(e)}\", 500\n\n    @dashboard.route('/chat')\n    def chat_page():\n        logger.info(\"Accessing chat page.\")\n        try:\n            return render_template('chat.html', dashboard_route=g.dashboard_route)\n        except Exception as e:\n            logger.error(f\"Error in chat_page: {str(e)}\", exc_info=True)\n            return f\"Error loading chat page: {str(e)}\", 500\n    \n    @dashboard.route('/<path:filename>')\n    def serve_static_files(filename):\n        \"\"\"Serve static files from the dashboard's static folder.\"\"\"\n        logger.debug(f\"Serving static file: {filename}\")\n        try:\n            return send_from_directory(dashboard.static_folder, filename)\n        except Exception as e:\n            logger.error(f\"Error serving static file '{filename}': {str(e)}\", exc_info=True)\n            return \"File not found.\", 404\n\n    logger.info(\"Dashboard blueprint created successfully.\")\n    return dashboard\n\nlogger.info(\"Dashboard __init__.py loaded successfully.\")\n"
  },
  {
    "path": "babyagi/dashboard/static/css/style.css",
    "content": "/* static/css/style.css */\n\n/* Global Variables */\n:root {\n    /* Color variables */\n    --primary-color: #3498db;\n    --secondary-color: #2c3e50;\n    --background-color: #f0f4f8;\n    --text-color: #333333;\n    --border-color: #e0e0e0;\n    --hover-color: #f8f9fa;\n    --card-bg-color: #ffffff;\n    --bg-color: #f0f4f8;\n    --text-color: #333;\n    --accent-color: #3498db;\n    --hover-color: #f7fbfc;\n    --card-bg: #ffffff;\n}\n\n\n\n/* Global Styles */\nbody, html {\n    margin: 0;\n    padding: 0;\n    font-family: 'Inter', Arial, sans-serif;\n    background-color: var(--background-color);\n    color: var(--text-color);\n    font-size: 12px;\n    line-height: 1.4;\n}\n\n.container {\n    width: 100%;\n    max-width: 100%;\n    padding: 20px;\n    margin: 0 auto;\n    box-sizing: border-box;\n}\n\n\n.details-container {\n    width: 100%;\n    max-width: 1600px;\n    padding: 20px;\n    margin: 0 auto;\n    box-sizing: border-box;\n}\n\n/* Hide elements with 'mobile-only' class on screens wider than 768px */\n@media (min-width: 768px) {\n    .mobile-only {\n        display: none;\n    }\n}\n\n/* Hide elements with 'desktop-only' class on screens narrower than 768px */\n@media (max-width: 767px) {\n    .desktop-only {\n        display: none;\n    }\n}\n\n\n/* Headers */\nh1 {\n    color: var(--secondary-color);\n    font-size: 1.5em;\n    font-weight: 600;\n    margin-bottom: 20px;\n    text-align: left;\n}\n\nh1 small {\n    font-size: 0.7em;\n    font-weight: normal;\n    margin-left: 10px;\n}\n\nh1 small a {\n    color: var(--primary-color);\n    text-decoration: none;\n}\n\n/* Navigation Menu Styles */\nnav {\n    background-color: var(--secondary-color);\n    padding: 10px 0;\n    margin-bottom: 20px;\n}\n\nnav ul {\n    list-style-type: none;\n    margin: 0;\n    padding: 0;\n    display: flex;\n    justify-content: left;\n    flex-wrap: wrap;\n}\n\nnav li {\n    margin: 0 15px;\n}\n\nnav a {\n    color: #ffffff;\n    text-decoration: none;\n    font-weight: 500;\n    font-size: 14px;\n}\n\nnav a:hover {\n    text-decoration: underline;\n    color: var(--primary-color);\n}\n\n/* Breadcrumb Styles */\n.breadcrumb {\n    margin-bottom: 20px;\n}\n\n.breadcrumb a {\n    color: var(--primary-color);\n    text-decoration: none;\n}\n\n.breadcrumb a:hover {\n    text-decoration: underline;\n}\n\n\n\n/* Search Bar Styles */\n#searchInput {\n    width: 100%;\n    max-width: 1200px; /* Match the container's max-width */\n    padding: 10px;\n    margin-bottom: 20px;\n    font-size: 14px;\n    border: 1px solid var(--border-color);\n    border-radius: 4px;\n    box-sizing: border-box;\n}\n\n/* Table Styles */\ntable {\n    width: 100%;\n    border-collapse: separate;\n    border-spacing: 0;\n    background-color: var(--card-bg-color);\n    box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n    table-layout: fixed;\n}\n\nth, td {\n    padding: 12px;\n    text-align: left;\n    border-bottom: 1px solid var(--border-color);\n    vertical-align: top;\n}\n\ntd {\n    word-wrap: break-word;\n    overflow-wrap: break-word;\n}\n\nth {\n    background-color: var(--secondary-color);\n    color: white;\n    font-weight: 500;\n    white-space: nowrap;\n    cursor: pointer;\n}\n\nth.sortable:hover {\n    background-color: var(--primary-color);\n}\n\ntr:hover {\n    background-color: var(--hover-color);\n}\n\n.function-name {\n    color: var(--primary-color);\n    font-weight: 500;\n    text-decoration: none;\n}\n\n.function-name:hover {\n    text-decoration: underline;\n}\n\n.function-link, .function-name {\n    color: var(--primary-color);\n    font-weight: 500;\n    text-decoration: none;\n}\n\n.function-link:hover, .function-name:hover {\n    text-decoration: underline;\n}\n\n.small-text {\n    font-size: 0.92em;\n    color: #666;\n}\n\n.params-list, .dependencies-list, .imports-list, .triggers-list {\n    list-style-type: none;\n    padding: 0;\n    margin: 0;\n}\n\n.params-list li, .dependencies-list li, .imports-list, .triggers-list li {\n    margin-bottom: 2px;\n}\n\n/* Card Styles (for mobile view) */\n.function-grid {\n    display: none;\n    grid-template-columns: 1fr;\n    gap: 15px;\n    padding: 10px;\n}\n\n.function-card {\n    background-color: var(--background-color);\n    border: 1px solid var(--border-color);\n    border-radius: 4px;\n    padding: 15px;\n}\n\n.function-meta {\n    color: #666;\n    margin-bottom: 10px;\n}\n\n.function-description {\n    margin-bottom: 10px;\n}\n\n.params-title {\n    font-weight: 500;\n    margin-top: 8px;\n    margin-bottom: 3px;\n}\n\n.log-info {\n    display: flex;\n    justify-content: space-between;\n    color: #666;\n    border-top: 1px solid var(--border-color);\n    padding-top: 8px;\n    margin-top: 8px;\n}\n\n/* Function Detail Page Styles */\n.function-detail {\n    background-color: var(--card-bg-color);\n    padding: 20px;\n    border-radius: 8px;\n    margin-bottom: 20px;\n}\n\n.section-title {\n    font-size: 1.2em;\n    font-weight: bold;\n    margin-top: 20px;\n    margin-bottom: 10px;\n    color: var(--primary-color);\n}\n\n.button {\n    background-color: var(--primary-color);\n    color: white;\n    padding: 10px 15px;\n    border: none;\n    border-radius: 4px;\n    cursor: pointer;\n    font-size: 14px;\n    margin-right: 10px;\n}\n\n.button:hover {\n    background-color: var(--hover-color);\n}\n\n#functionLogs {\n    max-height:600px;\n    overflow-y:scroll;\n}\n\n.log-entry, .execution-result {\n    background-color: #f8f9fa;\n    padding: 10px;\n    margin-bottom: 10px;\n    border-radius: 4px;\n    font-family: monospace;\n    font-size: 12px;\n    line-height: 1.4;\n    overflow-x: auto;\n}\n\n.param-input {\n    margin-bottom: 10px;\n}\n\n.param-input label {\n    display: block;\n    margin-bottom: 5px;\n}\n\n.param-input input, .param-input textarea {\n    width: 100%;\n    padding: 5px;\n    border: 1px solid var(--border-color);\n    border-radius: 4px;\n}\n\n.breadcrumb {\n    margin-bottom: 20px;\n}\n\n.breadcrumb a {\n    color: var(--primary-color);\n    text-decoration: none;\n}\n\n.breadcrumb a:hover {\n    text-decoration: underline;\n}\n\n.two-column {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 20px;\n}\n\n.column {\n    flex: 1;\n    min-width: 300px;\n}\n\n.detail-item {\n    background-color: #f8f9fa;\n    padding: 10px;\n    margin-bottom: 10px;\n    border-radius: 4px;\n    font-family: monospace;\n    font-size: 12px;\n    line-height: 1.4;\n    overflow-x: auto;\n}\n\n.detail-label {\n    display: inline-block;\n    min-width: 120px;\n    font-weight: bold;\n    color: var(--primary-color);\n    margin-right: 10px;\n}\n\n.detail-value {\n    display: inline-block;\n}\n\n.detail-list {\n    margin: 5px 0 5px 130px;\n    padding-left: 20px;\n}\n\n.CodeMirror {\n    font-size: 12px;\n    border: 1px solid var(--border-color);\n    border-radius: 4px;\n    margin-bottom: 5px;\n}\n\n/* Version History */\n.version-item {\n    padding: 10px;\n    border-bottom: 1px solid #ccc;\n    background-color: #f8f9fa;\n    margin-bottom: 5px;\n    word-wrap: break-word;\n    white-space: pre-wrap;\n    max-height:600px;\n}\n\n.version-item.active {\n    background-color: #e0f7fa;\n}\n\n.version-item pre {\n    background-color: #f1f1f1;\n    padding: 10px;\n    border-radius: 4px;\n    font-size: 12px;\n    overflow-x: auto;\n    white-space: pre-wrap;\n    word-wrap: break-word;\n    line-height: 1.4;\n}\n\n#toggleVersionHistory {\n    margin-top: 10px;\n}\n\n#versionHistory {\n    margin-top: 10px;\n}\n\n/* Media Queries */\n@media (max-width: 768px) {\n    /* Hide the table in mobile, show the card grid */\n    table {\n        display: none;\n    }\n    .function-grid {\n        display: grid;\n    }\n    .two-column {\n        flex-direction: column;\n    }\n    .container, #searchInput, .function-detail, .column, input, body {\n        padding: 10px;\n        max-width: 100%;\n    }\n    .param-input{\n        margin:10px;\n    }\n}"
  },
  {
    "path": "babyagi/dashboard/static/js/dashboard.js",
    "content": "/* static/js/dashboard.js */\n\n// Assume that dashboardRoute, apiFunctionsUrl, and apiLogsUrl are defined in the HTML template\n\nlet currentSort = { key: null, direction: 'asc' };\nlet allFunctions = []; // This will hold the functions data globally\n\nfunction filterTable() {\n    const input = document.getElementById(\"searchInput\").value.toLowerCase();\n    const table = document.getElementById(\"functionTable\");\n    const rows = table.getElementsByTagName(\"tr\");\n    const grid = document.getElementById(\"functionGrid\");\n    const cards = grid.getElementsByClassName(\"function-card\");\n\n    for (let i = 1; i < rows.length; i++) { // Start at 1 to skip header row\n        let match = false;\n        const cells = rows[i].getElementsByTagName(\"td\");\n        for (let j = 0; j < cells.length; j++) {\n            if (cells[j].innerText.toLowerCase().includes(input)) {\n                match = true;\n                break;\n            }\n        }\n        rows[i].style.display = match ? \"\" : \"none\";\n    }\n\n    // Filter cards for mobile view\n    for (let i = 0; i < cards.length; i++) {\n        if (cards[i].innerText.toLowerCase().includes(input)) {\n            cards[i].style.display = \"\";\n        } else {\n            cards[i].style.display = \"none\";\n        }\n    }\n}\nfunction sortTable(key) {\n    const direction = currentSort.key === key && currentSort.direction === 'asc' ? 'desc' : 'asc';\n    currentSort = { key, direction };\n\n    const sortedFunctions = [...allFunctions].sort((a, b) => {\n        let valA, valB;\n        if (key === 'name') {\n            valA = a.name.toLowerCase();\n            valB = b.name.toLowerCase();\n        } else if (key === 'created_date') {\n            valA = new Date(a.created_date);\n            valB = new Date(b.created_date);\n        } else if (key === 'total_logs') {\n            valA = a.total_logs || 0;\n            valB = b.total_logs || 0;\n        } else if (key === 'last_log_date') {\n            valA = new Date(a.last_log_date || 0);\n            valB = new Date(b.last_log_date || 0);\n        }\n\n        if (direction === 'asc') return valA > valB ? 1 : -1;\n        return valA < valB ? 1 : -1;\n    });\n\n    populateDashboard(sortedFunctions);\n}\n\nasync function fetchLogs(functionName) {\n    try {\n        const response = await fetch(`${apiLogsUrl}${encodeURIComponent(functionName)}`);\n        if (!response.ok) {\n            throw new Error('Failed to fetch logs');\n        }\n        const logs = await response.json();\n        return {\n            total_logs: logs.length,\n            last_log_date: logs.length > 0 ? logs[logs.length - 1].timestamp : null\n        };\n    } catch (error) {\n        console.error(`Error fetching logs for ${functionName}:`, error);\n        return { total_logs: 0, last_log_date: null };\n    }\n}\n\nfunction updateLogsAsync(tasks) {\n    const promises = tasks.map(([functionName, row]) => {\n        return fetchLogs(functionName).then(({ total_logs, last_log_date }) => {\n            const totalLogsCell = row.querySelector('.total-logs');\n            const lastLogDateCell = row.querySelector('.last-log-date');\n            totalLogsCell.textContent = total_logs;\n            lastLogDateCell.textContent = last_log_date ? new Date(last_log_date).toLocaleDateString() : 'N/A';\n\n            // Update function in allFunctions array\n            const func = allFunctions.find(f => f.name === functionName);\n            if (func) {\n                func.total_logs = total_logs;\n                func.last_log_date = last_log_date;\n            }\n        });\n    });\n    return Promise.all(promises);\n}\n\nasync function populateDashboard(functions) {\n    allFunctions = functions; // Store functions globally for sorting\n    const tableBody = document.querySelector('#functionTable tbody');\n    const grid = document.getElementById('functionGrid');\n    const logTasks = [];\n\n    tableBody.innerHTML = '';\n    grid.innerHTML = '';\n\n    for (const func of functions) {\n        const row = document.createElement('tr');\n        const description = func.metadata && func.metadata.description ? func.metadata.description : 'No description available';\n        const createdDate = new Date(func.created_date).toLocaleDateString();\n\n        row.innerHTML = `\n            <td><a href=\"${dashboardRoute}/function/${encodeURIComponent(func.name)}\" class=\"function-name\">${func.name}</a></td>\n            <td class=\"small-text\">v${func.version}</td>\n            <td>${description}</td>\n            <td>${formatParams(func.input_parameters)}</td>\n            <td>${formatParams(func.output_parameters)}</td>\n            <td>${formatList(func.dependencies, 'dependencies-list', dashboardRoute)}</td>\n            <td>${formatList(func.imports, 'imports-list')}</td>\n            <td>${formatList(func.triggers, 'triggers-list', dashboardRoute)}</td>\n            <td class=\"small-text\">${createdDate}</td>\n            <td class=\"small-text total-logs\">Loading...</td>\n            <td class=\"small-text last-log-date\">Loading...</td>\n        `;\n        tableBody.appendChild(row);\n\n        // Populate card view (for mobile)\n        const card = document.createElement('div');\n        card.className = 'function-card';\n        card.innerHTML = `\n            <a href=\"${dashboardRoute}function/${encodeURIComponent(func.name)}\" class=\"function-name\">${func.name}</a>\n            <div class=\"function-meta\">v${func.version} | Created: ${createdDate}</div>\n            <div class=\"function-description\">${description}</div>\n            <div class=\"params-title\">Input Parameters:</div>\n            ${formatParams(func.input_parameters)}\n            <div class=\"params-title\">Output Parameters:</div>\n            ${formatParams(func.output_parameters)}\n            <div class=\"params-title\">Dependencies:</div>\n            ${formatList(func.dependencies, 'dependencies-list', dashboardRoute)}\n            <div class=\"params-title\">Imports:</div>\n            ${formatList(func.imports, 'imports-list')}\n            <div class=\"params-title\">Triggers:</div>\n            ${formatList(func.triggers, 'triggers-list', dashboardRoute)}\n            <div class=\"log-info\">\n                <span>Total Logs: <span class=\"total-logs\">Loading...</span></span>\n                <span>Last Log: <span class=\"last-log-date\">Loading...</span></span>\n            </div>\n        `;\n        grid.appendChild(card);\n\n        logTasks.push([func.name, row]);\n    }\n\n    updateLogsAsync(logTasks);\n}\n\nfunction formatParams(params) {\n    if (!params || params.length === 0) {\n        return '<span class=\"small-text\"></span>';\n    }\n    return '<ul class=\"params-list\">' + \n        params.map(param => `<li>${param.name}: <span class=\"small-text\">${param.type}</span></li>`).join('') + \n        '</ul>';\n}\n\nfunction formatList(items, className, dashboardRoute) {\n    if (!items || items.length === 0) {\n        return '<span class=\"small-text\">-</span>';\n    }\n    return '<ul class=\"' + className + '\">' + \n        items.map(item => {\n            if (className === 'dependencies-list' || className === 'triggers-list') {\n                return `<li><a href=\"${dashboardRoute}/function/${encodeURIComponent(item)}\" class=\"function-link\">${item}</a></li>`;\n            }\n            return `<li>${item}</li>`;\n        }).join('') + \n        '</ul>';\n}\n\n// Fetch functions data and populate the dashboard\nasync function fetchFunctionsAndPopulate() {\n    try {\n        const response = await fetch(apiFunctionsUrl);\n        if (!response.ok) {\n            throw new Error('Failed to fetch functions');\n        }\n        const data = await response.json();\n        populateDashboard(data);\n    } catch (error) {\n        console.error('Error fetching functions:', error);\n        document.querySelector('.container').innerHTML += `<p style=\"color: red;\">Error loading functions. Please try refreshing the page.</p>`;\n    }\n}\n\n// Call the function when the page loads\ndocument.addEventListener('DOMContentLoaded', () => {\n    fetchFunctionsAndPopulate();\n\n    // Add event listener for search input\n    const searchInput = document.getElementById(\"searchInput\");\n    searchInput.addEventListener('input', filterTable);\n});"
  },
  {
    "path": "babyagi/dashboard/static/js/function_details.js",
    "content": "// At the top of function_details.js\n\n\n// Ensure apiRoutes is defined\nwindow.apiRoutes = window.apiRoutes || {};\n\n// Helper function to get the API route\nfunction getApiRoute(routeName, ...args) {\n    if (typeof apiRoutes[routeName] === 'function') {\n        return apiRoutes[routeName](...args);\n    } else {\n        return apiRoutes[routeName];\n    }\n}\n\nwindow.getApiRoute = getApiRoute;\n\nlet functionData;\nlet codeEditor;\n\n// Expose necessary functions to the global scope\nwindow.loadFunctionDetails = loadFunctionDetails;\nwindow.loadFunctionLogs = loadFunctionLogs;\nwindow.initCodeEditor = initCodeEditor;\nwindow.displayFunctionDetails = displayFunctionDetails;\nwindow.createExecutionForm = createExecutionForm;\nwindow.updateFunction = updateFunction;\nwindow.executeFunction = executeFunction;\nwindow.toggleVersionHistory = toggleVersionHistory;\nwindow.loadFunctionVersions = loadFunctionVersions;\nwindow.activateVersion = activateVersion;\n\nfunction loadFunctionDetails() {\n    fetch(getApiRoute('getFunction'))\n        .then(response => {\n            if (!response.ok) {\n                throw new Error(`HTTP error! status: ${response.status}`);\n            }\n            return response.json();\n        })\n        .then(data => {\n            functionData = data;\n            console.log(\"functionData\",functionData)\n            displayFunctionDetails();\n            createExecutionForm();\n            initCodeEditor();\n        })\n        .catch(error => {\n            console.error('Error:', error);\n            document.getElementById('functionDetails').innerHTML = `<p>Error loading function details: ${error.message}</p>`;\n        });\n}\n\nfunction loadFunctionLogs() {\n    fetch(getApiRoute('getLogs'))\n        .then(response => {\n            if (!response.ok) {\n                throw new Error(`HTTP error! status: ${response.status}`);\n            }\n            return response.json();\n        })\n        .then(logs => {\n            let logsHtml = logs.map(log => `\n                <div class=\"log-entry\">\n                    <strong>Timestamp:</strong> ${new Date(log.timestamp).toLocaleString()}<br>\n                    <strong>Message:</strong> ${log.message}<br>\n                    <strong>Params:</strong> ${JSON.stringify(log.params)}<br>\n                    <strong>Output:</strong> ${JSON.stringify(log.output)}<br>\n                    <strong>Time spent:</strong> ${log.time_spent} seconds\n                </div>\n            `).join('');\n            document.getElementById('functionLogs').innerHTML = logsHtml;\n        })\n        .catch(error => {\n            console.error('Error:', error);\n            document.getElementById('functionLogs').innerHTML = `<p>Error loading logs: ${error.message}</p>`;\n        });\n}\n\nfunction initCodeEditor() {\n    const editorElement = document.getElementById('codeEditor'); // Example: Get the editor element\n\n    // Check if the editor element exists\n    if (!editorElement) {\n        console.error(\"Code editor textarea not found!\");\n        return;\n    }\n\n    // Destroy the previous CodeMirror instance if it exists\n    if (codeEditor) {\n        codeEditor.toTextArea(); // Converts the editor back into a textarea\n        codeEditor = null; // Clear the reference\n    }\n\n    // Initialize the new CodeMirror instance\n    codeEditor = CodeMirror.fromTextArea(editorElement, {\n        mode: \"python\",\n        theme: \"monokai\",\n        lineNumbers: true,\n        indentUnit: 4,\n        tabSize: 4,\n        indentWithTabs: false,\n        autofocus: true\n    });\n    console.log(\"initCodeEditor executing\");\n    console.log(\"window.functionData.code\", functionData.code);\n    console.log(\"window.functionData\", functionData);\n\n    // Set the current function code (if available)\n    if (functionData && functionData.code) {\n        codeEditor.setValue(functionData.code);\n    } else {\n        codeEditor.setValue(\"\"); // Clear editor if no code\n    }\n\n    // Refresh CodeMirror to fix display issues\n    setTimeout(() => {\n        codeEditor.refresh();\n    }, 200); // Short delay to ensure the editor is fully visible before refreshing\n}\n\n\n\nfunction displayFunctionDetails() {\n    document.getElementById('functionName').textContent = functionData.name;\n\n    let detailsHtml = `\n        <div class=\"detail-item\">\n            <span class=\"detail-label\">Version:</span>\n            <span class=\"detail-value\">${functionData.version}</span>\n        </div>\n        <div class=\"detail-item\">\n            <span class=\"detail-label\">Created Date:</span>\n            <span class=\"detail-value\">${new Date(functionData.created_date).toLocaleString()}</span>\n        </div>\n        <div class=\"detail-item\">\n            <span class=\"detail-label\">Description:</span>\n            <span class=\"detail-value\">${functionData.metadata.description || 'No description available'}</span>\n        </div>\n        <div class=\"detail-item\">\n            <span class=\"detail-label\">Dependencies:</span>\n            <span class=\"detail-value\">$\n                <span class=\"detail-value\">\n                  ${functionData.dependencies.length ? functionData.dependencies.map(dep => `\n                    <a href=\"${dashboardRoute}/function/${encodeURIComponent(dep)}\" class=\"function-name\">${dep}</a>\n                  `).join(', ') : 'None'}\n                </span>\n\n            </span>\n        </div>\n        <div class=\"detail-item\">\n            <span class=\"detail-label\">Imports:</span>\n            <span class=\"detail-value\">${functionData.imports ? functionData.imports.join(', ') : 'None'}</span>\n        </div>\n        <div class=\"detail-item\">\n            <span class=\"detail-label\">Triggers:</span>\n            <span class=\"detail-value\">${functionData.triggers.join(', ') || 'None'}</span>\n        </div>\n        <div class=\"detail-item\">\n            <span class=\"detail-label\">Input Parameters:</span>\n            <ul class=\"detail-list\">\n                ${functionData.input_parameters.map(param => `<li>${param.name} (${param.type})</li>`).join('')}\n            </ul>\n        </div>\n        <div class=\"detail-item\">\n            <span class=\"detail-label\">Output Parameters:</span>\n            <ul class=\"detail-list\">\n                ${functionData.output_parameters.map(param => `<li>${param.name} (${param.type})</li>`).join('')}\n            </ul>\n        </div>\n    `;\n\n    document.getElementById('functionDetails').innerHTML = detailsHtml;\n}\n\nfunction createExecutionForm() {\n    let formHtml = '';\n    if (functionData.name === 'execute_function_wrapper') {\n        formHtml += `\n            <div class=\"param-input\">\n                <label for=\"function_name\">function_name (str):</label>\n                <input type=\"text\" id=\"function_name\" name=\"function_name\">\n            </div>\n            <div class=\"param-input\">\n                <label for=\"args\">args (comma-separated values):</label>\n                <input type=\"text\" id=\"args\" name=\"args\">\n            </div>\n            <div class=\"param-input\">\n                <label for=\"kwargs\">kwargs (JSON format):</label>\n                <textarea id=\"kwargs\" name=\"kwargs\" rows=\"5\" cols=\"50\"></textarea>\n            </div>\n        `;\n    } else {\n        functionData.input_parameters.forEach(param => {\n            if (param.type === 'json') {\n                formHtml += `\n                    <div class=\"param-input\">\n                        <label for=\"${param.name}\">${param.name} (${param.type}):</label>\n                        <textarea id=\"${param.name}\" name=\"${param.name}\" rows=\"5\" cols=\"50\"></textarea>\n                    </div>\n                `;\n            } else {\n                formHtml += `\n                    <div class=\"param-input\">\n                        <label for=\"${param.name}\">${param.name} (${param.type}):</label>\n                        <input type=\"text\" id=\"${param.name}\" name=\"${param.name}\">\n                    </div>\n                `;\n            }\n        });\n    }\n    document.getElementById('executionForm').innerHTML = formHtml;\n}\n\nfunction updateFunction() {\n    const updatedCode = codeEditor.getValue();\n    fetch(getApiRoute('updateFunction'), {\n        method: 'PUT',\n        headers: {\n            'Content-Type': 'application/json',\n        },\n        body: JSON.stringify({\n            code: updatedCode,\n        }),\n    })\n    .then(response => response.json())\n    .then(data => {\n        alert('Function updated successfully');\n        functionData.code = updatedCode;\n        if (data.version) {\n            functionData.version = data.version;\n        }\n        displayFunctionDetails();\n    })\n    .catch((error) => {\n        console.error('Error:', error);\n        alert('Error updating function');\n    });\n}\n\nfunction executeFunction() {\n    let params = {};\n    if (functionData.name === 'execute_function_wrapper') {\n        const functionNameInput = document.getElementById('function_name').value.trim();\n        if (!functionNameInput) {\n            alert('Function name is required.');\n            return;\n        }\n        const args = document.getElementById('args').value ? \n            document.getElementById('args').value.split(',').map(arg => arg.trim()) : [];\n        let kwargs = {};\n        const kwargsValue = document.getElementById('kwargs').value.trim();\n        if (kwargsValue) {\n            try {\n                kwargs = JSON.parse(kwargsValue);\n            } catch (e) {\n                alert('Invalid JSON input for kwargs. Please check your input.');\n                return;\n            }\n        }\n        params = {\n            function_name: functionNameInput,\n            args: args,\n            kwargs: kwargs\n        };\n    } else {\n        for (const param of functionData.input_parameters) {\n            let value = document.getElementById(param.name).value.trim();\n\n            // Skip empty inputs\n            if (value === '') continue;\n\n            try {\n                switch (param.type) {\n                    case 'int':\n                        value = parseInt(value, 10);\n                        if (isNaN(value)) throw new Error(`Invalid integer for ${param.name}`);\n                        break;\n                    case 'float':\n                        value = parseFloat(value);\n                        if (isNaN(value)) throw new Error(`Invalid float for ${param.name}`);\n                        break;\n                    case 'bool':\n                        value = value.toLowerCase();\n                        if (value !== 'true' && value !== 'false') throw new Error(`Invalid boolean for ${param.name}. Use 'true' or 'false'.`);\n                        value = value === 'true';\n                        break;\n                    case 'date':\n                        value = new Date(value);\n                        if (isNaN(value.getTime())) throw new Error(`Invalid date for ${param.name}`);\n                        break;\n                    case 'list':\n                        value = value.split(',').map(item => item.trim());\n                        break;\n                    case 'json':\n                        value = JSON.parse(value);\n                        break;\n                }\n                params[param.name] = value;\n            } catch (error) {\n                alert(`Error with parameter ${param.name}: ${error.message}`);\n                return;\n            }\n        }\n    }\n\n    fetch(getApiRoute('executeFunction'), {\n        method: 'POST',\n        headers: {\n            'Content-Type': 'application/json',\n        },\n        body: JSON.stringify(params),\n    })\n    .then(response => {\n        if (!response.ok) {\n            return response.text().then(text => {\n                throw new Error(text || response.statusText);\n            });\n        }\n        return response.json();\n    })\n    .then(data => {\n        document.getElementById('executionResult').innerHTML = `<pre>${JSON.stringify(data, null, 2)}</pre>`;\n    })\n    .catch((error) => {\n        console.error('Error:', error);\n        document.getElementById('executionResult').innerHTML = `<pre class=\"error\">Error executing function: ${error.message}</pre>`;\n    });\n}\n\nlet isVersionHistoryVisible = false;\n\nfunction toggleVersionHistory() {\n    const versionHistory = document.getElementById('versionHistory');\n    if (isVersionHistoryVisible) {\n        versionHistory.style.display = 'none';\n        document.getElementById('toggleVersionHistory').textContent = 'Show Versions';\n    } else {\n        loadFunctionVersions();\n        versionHistory.style.display = 'block';\n        document.getElementById('toggleVersionHistory').textContent = 'Hide Versions';\n    }\n    isVersionHistoryVisible = !isVersionHistoryVisible;\n}\n\nfunction loadFunctionVersions() {\n    fetch(getApiRoute('getFunctionVersions'))\n        .then(response => response.json())\n        .then(versions => {\n            const versionHistoryDiv = document.getElementById('versionHistory');\n            let versionHtml = versions.map(version => `\n                <div class=\"version-item ${version.is_active ? 'active' : ''}\">\n                    <strong>Version ${version.version}</strong> - Created: ${new Date(version.created_date).toLocaleString()}\n                    <pre>${version.code}</pre>\n                    <button class=\"button\" onclick=\"activateVersion(${version.version})\">Activate Version</button>\n                </div>\n            `).join('');\n            versionHistoryDiv.innerHTML = versionHtml;\n        })\n        .catch(error => console.error('Error loading versions:', error));\n}\n\nfunction activateVersion(version) {\n    const url = getApiRoute('activateVersion', version);\n    fetch(url, {\n        method: 'POST',\n    })\n    .then(response => response.json())\n    .then(data => {\n        alert('Version activated successfully');\n        loadFunctionDetails();\n        loadFunctionVersions();\n    })\n    .catch(error => console.error('Error activating version:', error));\n}\n\nwindow.addEventListener('load', function() {\n    loadFunctionDetails();\n    loadFunctionLogs();\n});\n"
  },
  {
    "path": "babyagi/dashboard/static/js/function_graph.js",
    "content": "// function_graph.js\nlet cy;\n\ndocument.addEventListener('DOMContentLoaded', () => {\n    cy = cytoscape({\n        container: document.getElementById('graph'),\n        style: [\n            {\n                selector: 'node',\n                style: {\n                    'shape': 'rectangle',\n                    'background-color': '#E6F2FF',\n                    'label': 'data(id)',\n                    'text-valign': 'center',\n                    'text-halign': 'center',\n                    'text-wrap': 'wrap',\n                    'text-max-width': '150px',\n                    'width': 'label',\n                    'height': 'label',\n                    'padding': '12px',\n                    'font-weight': 'bold',\n                    'font-size': '16px',\n                    'color': '#333333',\n                    'text-outline-color': '#FFFFFF',\n                    'text-outline-width': 1,\n                    'cursor': 'pointer'\n                }\n            },\n            {\n                selector: 'node[type=\"import\"]',\n                style: {\n                    'background-color': '#E6FFF2'\n                }\n            },\n            {\n                selector: 'node[type=\"trigger\"]',\n                style: {\n                    'background-color': '#FFE6E6'\n                }\n            },\n            {\n                selector: 'node:hover',\n                style: {\n                    'background-opacity': 0.8\n                }\n            },\n            {\n                selector: 'edge',\n                style: {\n                    'width': 1,\n                    'line-color': '#999999',\n                    'target-arrow-color': '#999999',\n                    'target-arrow-shape': 'triangle',\n                    'curve-style': 'bezier',\n                    'arrow-scale': 1.5\n                }\n            },\n            {\n                selector: 'edge[type=\"dependency\"]',\n                style: {\n                    'width': 2\n                }\n            },\n            {\n                selector: 'edge[type=\"trigger\"]',\n                style: {\n                    'line-style': 'dashed',\n                    'label': 'trigger',\n                    'font-size': '12px',\n                    'text-rotation': 'autorotate',\n                    'text-margin-y': -10\n                }\n            }\n        ],\n        layout: {\n            name: 'cose',\n            idealEdgeLength: 50,\n            nodeOverlap: 20,\n            refresh: 20,\n            fit: true,\n            padding: 30,\n            randomize: false,\n            componentSpacing: 80,\n            nodeRepulsion: 450000,\n            edgeElasticity: 100,\n            nestingFactor: 5,\n            gravity: 80,\n            numIter: 1000,\n            initialTemp: 200,\n            coolingFactor: 0.95,\n            minTemp: 1.0\n        },\n        wheelSensitivity: 0.2\n    });\n\n    fetch('/api/functions')\n        .then(response => response.json())\n        .then(data => {\n            const elements = [];\n            const imports = new Set();\n\n            data.forEach(func => {\n                elements.push({ data: { id: func.name, type: 'function' } });\n\n                func.dependencies.forEach(dep => {\n                    elements.push({ data: { id: dep, type: 'function' } });\n                    elements.push({ data: { source: func.name, target: dep, type: 'dependency' } });\n                });\n\n                func.triggers.forEach(trigger => {\n                    elements.push({ data: { id: trigger, type: 'trigger' } });\n                    elements.push({ data: { source: func.name, target: trigger, type: 'trigger' } });\n                });\n\n                func.imports.forEach(imp => imports.add(imp));\n            });\n\n            imports.forEach(imp => {\n                elements.push({ data: { id: imp, type: 'import' } });\n            });\n\n            data.forEach(func => {\n                func.imports.forEach(imp => {\n                    elements.push({ data: { source: func.name, target: imp, type: 'import' } });\n                });\n            });\n\n            cy.add(elements);\n            cy.layout({ name: 'cose' }).run();\n\n            cy.fit(40);\n\n            cy.zoom({\n                level: cy.zoom() * 1.3,\n                renderedPosition: { x: cy.width() / 2, y: cy.height() / 2 }\n            });\n        });\n\n    cy.on('tap', 'node', function(evt) {\n        const node = evt.target;\n        if (node.data('type') === 'function' || node.data('type') === 'trigger') {\n            showFunctionOverlay(node.id());\n        }\n    });\n\n    cy.on('zoom pan', () => {\n        closeOverlay();\n    });\n});\n\nfunction showFunctionOverlay(functionName) {\n    const overlay = document.getElementById('overlay');\n    const content = document.getElementById('overlay-content');\n\n    fetch(`/api/function/${functionName}`)\n        .then(response => response.json())\n        .then(data => {\n            content.innerHTML = `\n                <h3>${data.name}</h3>\n                <div id=\"tab-buttons\">\n                    <button class=\"tab-button active\" onclick=\"showTab('description', '${data.name}')\">Description</button>\n                    <button class=\"tab-button\" onclick=\"showTab('code', '${data.name}')\">Code</button>\n                    <button class=\"tab-button\" onclick=\"showTab('logs', '${data.name}')\">Logs</button>\n                </div>\n                <div id=\"tab-content\">\n                    <div id=\"description-tab\">\n                        <p><strong>Description:</strong> ${data.metadata.description || 'No description available.'}</p>\n                        <p><strong>Version:</strong> ${data.version}</p>\n                    </div>\n                    <div id=\"code-tab\" style=\"display: none;\"></div>\n                    <div id=\"logs-tab\" style=\"display: none;\"></div>\n                </div>\n            `;\n\n            const node = cy.$id(functionName);\n            const renderedPosition = node.renderedPosition();\n\n            overlay.style.left = `${renderedPosition.x + 10}px`;\n            overlay.style.top = `${renderedPosition.y + 10}px`;\n            overlay.style.display = 'block';\n        });\n}\n\nfunction showTab(tabName, functionName) {\n    const tabs = ['description', 'code', 'logs'];\n    tabs.forEach(tab => {\n        const tabElement = document.getElementById(`${tab}-tab`);\n        const tabButton = document.querySelector(`button.tab-button:nth-child(${tabs.indexOf(tab) + 1})`);\n        if (tab === tabName) {\n            tabElement.style.display = 'block';\n            tabButton.classList.add('active');\n        } else {\n            tabElement.style.display = 'none';\n            tabButton.classList.remove('active');\n        }\n    });\n\n    if (tabName === 'code' && document.getElementById('code-tab').innerHTML === '') {\n        showCode(functionName);\n    } else if (tabName === 'logs' && document.getElementById('logs-tab').innerHTML === '') {\n        showLogs(functionName);\n    }\n}\n\nfunction showCode(functionName) {\n    fetch(`/api/function/${functionName}`)\n        .then(response => response.json())\n        .then(data => {\n            const codeTab = document.getElementById('code-tab');\n            codeTab.innerHTML = `\n                <h4>Code:</h4>\n                <pre><code>${data.code}</code></pre>\n            `;\n        });\n}\n\nfunction showLogs(functionName) {\n    fetch(`/api/logs/${functionName}`)\n        .then(response => response.json())\n        .then(data => {\n            const logsTab = document.getElementById('logs-tab');\n            logsTab.innerHTML = `\n                <h4>Logs:</h4>\n                <pre>${JSON.stringify(data, null, 2)}</pre>\n            `;\n        });\n}\n\nfunction closeOverlay() {\n    document.getElementById('overlay').style.display = 'none';\n}"
  },
  {
    "path": "babyagi/dashboard/static/js/log_dashboard.js",
    "content": "let currentSort = { key: 'timestamp', direction: 'desc' }; // Set default sort to 'timestamp' descending\nlet allLogs = []; // Holds all fetched logs\nlet filteredLogs = []; // Holds logs after filtering\nlet rootLogs = []; // Holds the root logs after building the tree\n\n// Fetch unique values for function names and log types to populate filter dropdowns\nasync function populateFilters() {\n    try {\n        const response = await fetch(apiLogsUrl);\n        if (!response.ok) {\n            throw new Error('Failed to fetch logs for filters');\n        }\n        let logs = await response.json();\n\n        // **Sort logs by timestamp descending (most recent first)**\n        logs.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));\n\n        allLogs = logs;\n        filteredLogs = logs;\n\n        const functionFilter = document.getElementById('functionFilter');\n        const logTypeFilter = document.getElementById('logTypeFilter');\n\n        const uniqueFunctions = [...new Set(logs.map(log => log.function_name))].sort();\n        uniqueFunctions.forEach(func => {\n            const option = document.createElement('option');\n            option.value = func;\n            option.textContent = func;\n            functionFilter.appendChild(option);\n        });\n\n        const uniqueLogTypes = [...new Set(logs.map(log => log.log_type))].sort();\n        uniqueLogTypes.forEach(type => {\n            const option = document.createElement('option');\n            option.value = type;\n            option.textContent = capitalizeFirstLetter(type);\n            logTypeFilter.appendChild(option);\n        });\n\n        // Build the tree structure\n        rootLogs = buildLogTree(filteredLogs);\n\n        renderLogs();\n    } catch (error) {\n        console.error('Error populating filters:', error);\n        alert('Failed to load logs for filters. Please try again later.');\n    }\n}\n\n// Build log tree based on parent_log_id\nfunction buildLogTree(logs) {\n    const logsById = {};\n    const rootLogs = [];\n\n    // Initialize logsById mapping and add children array to each log\n    logs.forEach(log => {\n        log.children = [];\n        logsById[log.id] = log;\n    });\n\n    // Build the tree\n    logs.forEach(log => {\n        if (log.parent_log_id !== null) {\n            const parentLog = logsById[log.parent_log_id];\n            if (parentLog) {\n                parentLog.children.push(log);\n            } else {\n                // Parent log not found, treat as root\n                rootLogs.push(log);\n            }\n        } else {\n            rootLogs.push(log);\n        }\n    });\n\n    return rootLogs;\n}\n\n// Render logs in table and grid formats\nfunction renderLogs() {\n    renderTable();\n    renderGrid();\n}\n\n// Render Logs Table (Desktop View)\nfunction renderTable() {\n    const tableBody = document.querySelector('#logTable tbody');\n    tableBody.innerHTML = '';\n\n    rootLogs.forEach(log => {\n        renderLogRow(tableBody, log, 0);\n    });\n}\n\n// Recursive function to render each log row and its children\nfunction renderLogRow(tableBody, log, depth, parentRowId) {\n    const row = document.createElement('tr');\n    const rowId = 'log-' + log.id;\n    row.id = rowId;\n\n    // If it's a child row, add a class to indicate it's a child\n    if (parentRowId) {\n        row.classList.add('child-of-log-' + parentRowId);\n        row.style.display = 'none'; // Hide child rows by default\n    }\n\n    // Check if log has children\n    const hasChildren = log.children && log.children.length > 0;\n\n    // Create expand/collapse icon\n    let toggleIcon = '';\n    if (hasChildren) {\n        toggleIcon = `<span class=\"toggle-icon\" data-log-id=\"${log.id}\" style=\"cursor:pointer;\">[+]</span> `;\n    }\n\n    row.innerHTML = `\n        <td><a href=\"${dashboardRoute}/log/${log.id}\" class=\"function-link\">${log.id}</a></td>\n        <td><a href=\"${dashboardRoute}/function/${encodeURIComponent(log.function_name)}\" class=\"function-link\">${log.function_name}</a></td>\n        <td style=\"padding-left:${depth * 20}px\">${toggleIcon}${log.message}</td>\n        <td>${new Date(log.timestamp).toLocaleString()}</td>\n        <td>${capitalizeFirstLetter(log.log_type)}</td>\n        <td>${log.time_spent ? log.time_spent.toFixed(3) : 'N/A'}</td>\n        <td>${log.parent_log_id !== null ? log.parent_log_id : 'N/A'}</td>\n        <td>${log.triggered_by_log_id !== null ? log.triggered_by_log_id : 'N/A'}</td>\n    `;\n    tableBody.appendChild(row);\n\n    // Add event listener for toggle\n    if (hasChildren) {\n        row.querySelector('.toggle-icon').addEventListener('click', function() {\n            toggleChildRows(log.id);\n            // Update the icon\n            const icon = this;\n            if (icon.textContent === '[+]') {\n                icon.textContent = '[-]';\n            } else {\n                icon.textContent = '[+]';\n            }\n        });\n    }\n\n    // Recursively render children\n    if (hasChildren) {\n        log.children.forEach(childLog => {\n            renderLogRow(tableBody, childLog, depth + 1, log.id);\n        });\n    }\n}\n\n// Function to toggle child rows\nfunction toggleChildRows(parentLogId) {\n    const childRows = document.querySelectorAll('.child-of-log-' + parentLogId);\n\n    childRows.forEach(row => {\n        if (row.style.display === 'none') {\n            row.style.display = '';\n        } else {\n            row.style.display = 'none';\n            // Recursively hide any child rows\n            const childLogId = row.id.replace('log-', '');\n            toggleChildRows(childLogId);\n            // Reset the toggle icon of child rows to '[+]'\n            const toggleIcon = row.querySelector('.toggle-icon');\n            if (toggleIcon) {\n                toggleIcon.textContent = '[+]';\n            }\n        }\n    });\n}\n\n// Render Logs Grid (Mobile View)\nfunction renderGrid() {\n    const logGrid = document.getElementById('logGrid');\n    logGrid.innerHTML = '';\n\n    rootLogs.forEach(log => {\n        renderLogCard(logGrid, log, 0);\n    });\n}\n\n// Recursive function to render log cards and their children\nfunction renderLogCard(container, log, depth) {\n    const card = document.createElement('div');\n    card.className = 'log-card';\n    card.style.marginLeft = (depth * 20) + 'px';\n\n    card.innerHTML = `\n        <h5>ID: <a href=\"${dashboardRoute}/log/${log.id}\" class=\"function-link\">${log.id}</a></h5>\n        <div class=\"log-meta\">Function: <a href=\"${dashboardRoute}/function/${encodeURIComponent(log.function_name)}\">${log.function_name}</a> | ${new Date(log.timestamp).toLocaleString()}</div>\n        <div class=\"log-details\"><strong>Message:</strong> ${log.message}</div>\n        <div class=\"log-details\"><strong>Log Type:</strong> ${capitalizeFirstLetter(log.log_type)}</div>\n        <div class=\"log-details\"><strong>Time Spent:</strong> ${log.time_spent ? log.time_spent.toFixed(3) : 'N/A'} seconds</div>\n        <div class=\"log-details\"><strong>Parent Log ID:</strong> ${log.parent_log_id !== null ? log.parent_log_id : 'N/A'}</div>\n        <div class=\"log-details\"><strong>Triggered By Log ID:</strong> ${log.triggered_by_log_id !== null ? log.triggered_by_log_id : 'N/A'}</div>\n    `;\n    container.appendChild(card);\n\n    // Recursively render children\n    if (log.children && log.children.length > 0) {\n        log.children.forEach(childLog => {\n            renderLogCard(container, childLog, depth + 1);\n        });\n    }\n}\n\n// Capitalize the first letter of a string\nfunction capitalizeFirstLetter(string) {\n    return string.charAt(0).toUpperCase() + string.slice(1);\n}\n\n// Sort logs based on a key\nfunction sortLogs(key) {\n    if (currentSort.key === key) {\n        currentSort.direction = currentSort.direction === 'asc' ? 'desc' : 'asc';\n    } else {\n        currentSort.key = key;\n        currentSort.direction = 'asc';\n    }\n\n    // Sort root logs\n    rootLogs.sort((a, b) => {\n        let valA = a[key];\n        let valB = b[key];\n\n        // Handle null or undefined values\n        if (valA === null || valA === undefined) valA = '';\n        if (valB === null || valB === undefined) valB = '';\n\n        // If sorting by timestamp, convert to Date\n        if (key === 'timestamp') {\n            valA = new Date(valA);\n            valB = new Date(valB);\n        }\n\n        // If sorting by time_spent or IDs, ensure numerical comparison\n        if (key === 'time_spent' || key === 'id' || key === 'parent_log_id' || key === 'triggered_by_log_id') {\n            valA = Number(valA);\n            valB = Number(valB);\n        }\n\n        if (valA > valB) return currentSort.direction === 'asc' ? 1 : -1;\n        if (valA < valB) return currentSort.direction === 'asc' ? -1 : 1;\n        return 0;\n    });\n\n    renderLogs();\n}\n\n// Apply Filters\nfunction applyFilters() {\n    const functionFilter = document.getElementById('functionFilter').value.toLowerCase();\n    const logTypeFilter = document.getElementById('logTypeFilter').value.toLowerCase();\n    const startDate = document.getElementById('startDate').value;\n    const endDate = document.getElementById('endDate').value;\n\n    // First, filter the logs\n    filteredLogs = allLogs.filter(log => {\n        let matchesFunction = true;\n        let matchesLogType = true;\n        let matchesStartDate = true;\n        let matchesEndDate = true;\n\n        if (functionFilter) {\n            matchesFunction = log.function_name.toLowerCase().includes(functionFilter);\n        }\n\n        if (logTypeFilter) {\n            matchesLogType = log.log_type.toLowerCase() === logTypeFilter;\n        }\n\n        if (startDate) {\n            matchesStartDate = new Date(log.timestamp) >= new Date(startDate);\n        }\n\n        if (endDate) {\n            // Add one day to endDate to include the entire end day\n            const endDateObj = new Date(endDate);\n            endDateObj.setDate(endDateObj.getDate() + 1);\n            matchesEndDate = new Date(log.timestamp) < endDateObj;\n        }\n\n        return matchesFunction && matchesLogType && matchesStartDate && matchesEndDate;\n    });\n\n    // Rebuild the tree\n    rootLogs = buildLogTree(filteredLogs);\n\n    renderLogs();\n}\n\n// Reset Filters\nfunction resetFilters() {\n    document.getElementById('functionFilter').value = '';\n    document.getElementById('logTypeFilter').value = '';\n    document.getElementById('startDate').value = '';\n    document.getElementById('endDate').value = '';\n    filteredLogs = allLogs;\n\n    // Rebuild the tree\n    rootLogs = buildLogTree(filteredLogs);\n\n    renderLogs();\n}\n\n// Initialize the logs dashboard\ndocument.addEventListener('DOMContentLoaded', () => {\n    populateFilters();\n});\n"
  },
  {
    "path": "babyagi/dashboard/static/js/log_graph.js",
    "content": "document.addEventListener('DOMContentLoaded', () => {\n    loadLogs();\n});\n\nasync function loadLogs() {\n    try {\n        const response = await fetch(apiLogsUrl);\n        if (!response.ok) {\n            throw new Error('Failed to fetch logs');\n        }\n        const logs = await response.json();\n        renderGraph(logs);\n    } catch (error) {\n        console.error('Error loading logs:', error);\n        alert('Failed to load logs. Please try again later.');\n    }\n}\n\nfunction renderGraph(logs) {\n    // Process logs and build graph data\n    const elements = logs.map(log => ({\n        data: { id: log.id, label: log.function_name }\n    }));\n\n    // Add edges for relationships\n    logs.forEach(log => {\n        if (log.parent_log_id) {\n            elements.push({\n                data: {\n                    id: `parent-${log.id}`,\n                    source: log.parent_log_id,\n                    target: log.id,\n                    label: 'Parent'\n                }\n            });\n        }\n        if (log.triggered_by_log_id) {\n            elements.push({\n                data: {\n                    id: `trigger-${log.id}`,\n                    source: log.triggered_by_log_id,\n                    target: log.id,\n                    label: 'Triggered By'\n                }\n            });\n        }\n    });\n\n    // Initialize Cytoscape graph\n    var cy = cytoscape({\n        container: document.getElementById('graph'),\n        elements: elements,\n        style: [\n            {\n                selector: 'node',\n                style: {\n                    'label': 'data(label)',\n                    'background-color': '#666',\n                    'text-valign': 'center',\n                    'text-halign': 'center',\n                    'color': '#fff',\n                    'text-outline-width': 2,\n                    'text-outline-color': '#666'\n                }\n            },\n            {\n                selector: 'edge',\n                style: {\n                    'width': 2,\n                    'line-color': '#ccc',\n                    'target-arrow-color': '#ccc',\n                    'target-arrow-shape': 'triangle',\n                    'curve-style': 'bezier'\n                }\n            }\n        ],\n        layout: {\n            name: 'breadthfirst',\n            directed: true,\n            padding: 10\n        }\n    });\n\n    // Add event listeners if needed\n}\n"
  },
  {
    "path": "babyagi/dashboard/templates/base.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    {% block head %}\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>{% block title %}PythonFunc Dashboard{% endblock %}</title>\n    <link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap\" rel=\"stylesheet\">\n    <!-- Include external CSS -->\n    <link rel=\"stylesheet\" href=\"{{ url_for('dashboard.static', filename='css/style.css') }}\">\n    {% endblock %}\n</head>\n<body>\n    <!-- Include the navigation menu outside the container for styling purposes -->\n    <nav>\n        <ul>\n            <li><a href=\"{{ url_for('dashboard.dashboard_home') }}\">Home</a></li>\n            <li><a href=\"{{ url_for('dashboard.function_graph') }}\">Graph</a></li>\n            <li><a href=\"{{ url_for('dashboard.function_graph_mermaid') }}\">Mermaid Graph</a></li>\n            <li><a href=\"{{ url_for('dashboard.function_graph_3d') }}\">3D Graph</a></li>\n            <li><a href=\"{{ url_for('dashboard.logs_dashboard') }}\">Logs</a></li>\n            <li><a href=\"{{ url_for('dashboard.chat_page') }}\">Chat</a></li>\n            <!--<li><a href=\"{{ url_for('dashboard.log_relationship_graph') }}\">Log Graph</a></li>-->\n        </ul>\n    </nav>\n    <div class=\"container\">\n        <!-- Breadcrumb -->\n        {% block breadcrumb %}{% endblock %}\n        <!-- Main content -->\n        {% block content %}{% endblock %}\n    </div>\n    {% block scripts %}{% endblock %}\n</body>\n</html>\n"
  },
  {
    "path": "babyagi/dashboard/templates/chat.html",
    "content": "{% extends \"base.html\" %}\n{% block title %}Chat Application{% endblock %}\n{% block breadcrumb %}\n    <div class=\"breadcrumb\">\n        <a href=\"{{ url_for('dashboard.dashboard_home') }}\">Home</a> &gt; Chat\n    </div>\n{% endblock %}\n{% block content %}\n    <div class=\"header-container\">\n        <h1>Function-Enhanced Chat Application</h1>\n        <!-- Additional header content can be added here -->\n    </div>\n\n    <div class=\"main-content\">\n        <!-- Function Selection Section -->\n        <div class=\"function-selection\">\n            <h2>Select Available Functions</h2>\n            <input type=\"text\" id=\"searchBar\" placeholder=\"Search functions...\" class=\"search-bar\">\n            <div id=\"functionList\" class=\"function-list\">\n                <!-- Function items will be populated here -->\n            </div>\n        </div>\n\n        <!-- Chat Section -->\n        <div class=\"chat-container\">\n            <!-- Available Functions Display -->\n            <div id=\"availableFunctionsContainer\" class=\"available-functions-container\">\n                <h3>Available Functions:</h3>\n                <div id=\"availableFunctionsList\" class=\"available-functions-list\">\n                    <!-- Selected functions will be displayed here -->\n                </div>\n            </div>\n\n            <div id=\"chatWindow\" class=\"chat-window\">\n                <!-- Chat messages will be displayed here -->\n            </div>\n            <div class=\"chat-input-container\">\n                <textarea id=\"userMessage\" placeholder=\"Type your message here...\" rows=\"2\"></textarea>\n                <button id=\"sendMessage\" class=\"btn btn-success\">Send</button>\n            </div>\n        </div>\n    </div>\n\n    <!-- Function Details Modal -->\n    <div id=\"functionModal\" class=\"modal\">\n        <div class=\"modal-content\">\n            <span class=\"close-button\">&times;</span>\n            <div id=\"modalContent\">\n                <!-- Function details will be displayed here -->\n            </div>\n        </div>\n    </div>\n{% endblock %}\n{% block scripts %}\n    <!-- Include Marked.js for Markdown parsing -->\n    <script src=\"https://cdn.jsdelivr.net/npm/marked/marked.min.js\"></script>\n\n    <style>\n        /* Basic Styles */\n        .header-container {\n            margin-bottom: 20px;\n        }\n        .main-content {\n            display: flex;\n            flex-direction: column;\n        }\n        .function-selection {\n            margin-bottom: 20px;\n            flex-shrink: 0;\n        }\n        .search-bar {\n            width: 100%;\n            padding: 5px;\n            margin-bottom: 10px;\n            box-sizing: border-box;\n        }\n        .function-list {\n            overflow-y: auto;\n            max-height: calc(100vh - 400px); /* Adjust based on header and other elements */\n        }\n        .function-item {\n            border-bottom: 1px solid #ddd;\n            padding: 5px 10px;\n            cursor: pointer;\n            display: flex;\n            align-items: center;\n            transition: background-color 0.2s;\n            position: relative;\n        }\n        .function-item:hover {\n            background-color: #f0f0f0;\n        }\n        .function-item.selected {\n            background-color: #e0f7fa;\n        }\n        .function-name {\n            flex: 1;\n            font-weight: bold;\n            text-decoration: none;\n            color: inherit;\n        }\n        .add-button {\n            margin-left: 5px;\n        }\n        .info-button {\n            background: none;\n            border: none;\n            cursor: pointer;\n            font-size: 16px;\n            margin-left: 5px;\n            position: relative;\n        }\n        .chat-container {\n            border: 1px solid #ccc;\n            padding: 10px;\n            border-radius: 5px;\n            flex: 1;\n            display: flex;\n            flex-direction: column;\n            max-height: calc(100vh - 400px);\n            margin-top: 20px; /* Added margin to separate from function list */\n        }\n        .chat-window {\n            flex: 1;\n            overflow-y: auto;\n            margin-bottom: 10px;\n            padding: 5px;\n            border: 1px solid #ddd;\n            border-radius: 5px;\n            background-color: #f9f9f9;\n        }\n        .chat-message {\n            margin-bottom: 10px;\n        }\n        .chat-message.user {\n            text-align: right;\n        }\n        .chat-message.assistant {\n            text-align: left;\n        }\n        .chat-input-container {\n            display: flex;\n            margin-top: 10px;\n            padding-bottom: 10px; /* Added padding at the bottom */\n        }\n        #userMessage {\n            flex: 1;\n            resize: none;\n            padding: 5px;\n        }\n        #sendMessage {\n            margin-left: 10px;\n        }\n        .available-functions-container {\n            margin-bottom: 20px;\n        }\n        .available-functions-list {\n            display: flex;\n            flex-wrap: wrap;\n        }\n        .available-function-item {\n            background-color: #e0f7fa;\n            padding: 5px 10px;\n            margin-right: 10px;\n            margin-bottom: 10px;\n            border-radius: 3px;\n            position: relative;\n            cursor: default;\n        }\n        .available-function-item .remove-function {\n            position: absolute;\n            top: 2px;\n            right: 5px;\n            cursor: pointer;\n            font-weight: bold;\n        }\n        /* Modal Styles */\n        .modal {\n            display: none; /* Hidden by default */\n            position: fixed;\n            z-index: 1000; /* Sit on top */\n            left: 0;\n            top: 0;\n            width: 100%; /* Full width */\n            height: 100%; /* Full height */\n            overflow: auto;\n            background-color: rgba(0,0,0,0.5); /* Black w/ opacity */\n        }\n        .modal-content {\n            background-color: #fefefe;\n            margin: 5% auto; /* 15% from the top and centered */\n            padding: 20px;\n            border: 1px solid #888;\n            width: 80%; /* Could be more or less, depending on screen size */\n            max-height: 80%;\n            overflow-y: auto;\n            position: relative;\n        }\n        .close-button {\n            color: #aaa;\n            float: right;\n            font-size: 28px;\n            font-weight: bold;\n            cursor: pointer;\n            position: absolute;\n            right: 10px;\n            top: 5px;\n        }\n        .close-button:hover,\n        .close-button:focus {\n            color: black;\n            text-decoration: none;\n            cursor: pointer;\n        }\n        /* Responsive Layout */\n        @media (min-width: 768px) {\n            .main-content {\n                flex-direction: row;\n            }\n            .function-selection {\n                width: 25%;\n                margin-right: 20px;\n            }\n            .chat-container {\n                width: 75%;\n                margin-top: 0; /* Remove top margin in row layout */\n            }\n        }\n    </style>\n\n    <script>\n        document.addEventListener('DOMContentLoaded', function() {\n            const functionListContainer = document.getElementById('functionList');\n            const chatWindow = document.getElementById('chatWindow');\n            const userMessageInput = document.getElementById('userMessage');\n            const sendMessageButton = document.getElementById('sendMessage');\n            const searchBar = document.getElementById('searchBar');\n            const modal = document.getElementById('functionModal');\n            const modalContent = document.getElementById('modalContent');\n            const closeButton = document.querySelector('.close-button');\n\n            let availableFunctions = [];\n            let allFunctions = [];\n            let chatHistory = [\n                // Optionally, you can initialize with system message if needed\n                // { role: 'system', message: 'You are a helpful assistant.' }\n            ];\n\n            // Function to fetch available functions using /api/functions endpoint\n            function fetchFunctions() {\n                fetch(\"{{ url_for('api.get_functions') }}\", {\n                    method: 'GET',\n                    headers: { 'Content-Type': 'application/json' }\n                })\n                .then(response => response.json())\n                .then(data => {\n                    allFunctions = data;\n                    displayFunctions(allFunctions);\n                })\n                .catch(error => console.error('Error fetching functions:', error));\n            }\n\n            // Function to display functions as selectable items\n            function displayFunctions(functions) {\n                functionListContainer.innerHTML = '';\n                functions.forEach(func => {\n                    console.log(func);\n                    const functionItem = document.createElement('div');\n                    functionItem.className = 'function-item';\n                    functionItem.dataset.name = func.name;\n                    functionItem.dataset.description = func.description || '';\n                    functionItem.dataset.details = JSON.stringify(func);\n\n                    const functionName = document.createElement('a');\n                    functionName.className = 'function-name';\n                    functionName.textContent = func.name;\n                    functionName.href = '/function/' + encodeURIComponent(func.name);\n\n                    const addButton = document.createElement('button');\n                    addButton.className = 'add-button';\n                    addButton.textContent = 'Add';\n\n                    // **New Code Starts Here**\n                    // Check if the function is already in availableFunctions\n                    if (availableFunctions.includes(func.name)) {\n                        addButton.textContent = 'Remove';\n                        addButton.classList.add('remove');\n                    } else {\n                        addButton.textContent = 'Add';\n                        addButton.classList.remove('remove');\n                    }\n                    // **New Code Ends Here**\n\n                    addButton.addEventListener('click', function(event) {\n                        event.stopPropagation();\n                        toggleFunctionSelection(func.name);\n                        if (addButton.textContent === 'Add') {\n                            addButton.textContent = 'Remove';\n                            addButton.classList.add('remove');\n                        } else {\n                            addButton.textContent = 'Add';\n                            addButton.classList.remove('remove');\n                        }\n                    });\n\n                    const infoButton = document.createElement('button');\n                    infoButton.className = 'info-button';\n                    infoButton.innerHTML = 'ℹ️';\n\n                    // Add click event listener to open modal with function details\n                    infoButton.addEventListener('click', function(event) {\n                        event.stopPropagation();\n                        openModal(func);\n                    });\n\n                    functionItem.appendChild(functionName);\n                    functionItem.appendChild(addButton);\n                    functionItem.appendChild(infoButton);\n\n                    functionListContainer.appendChild(functionItem);\n\n                    // Add click event listener for selecting the function item\n                    functionItem.addEventListener('click', function(event) {\n                        // Avoid triggering when clicking on addButton or infoButton\n                        if (event.target === addButton || event.target === infoButton || infoButton.contains(event.target)) {\n                            return;\n                        }\n                        window.location.href = '/function/' + encodeURIComponent(func.name);\n                    });\n                });\n            }\n\n\n            // Function to open modal with function details\n            function openModal(func) {\n                // Assemble the detailed information\n                let infoContent = `<h2>${func.name}</h2>`;\n                infoContent += `<strong>Version:</strong> ${func.version || 'N/A'}<br>`;\n                infoContent += `<strong>Created Date:</strong> ${func.created_date || 'N/A'}<br>`;\n                infoContent += `<strong>Metadata:</strong> <pre>${JSON.stringify(func.metadata, null, 2) || '{}'}<pre><br>`;\n                infoContent += `<strong>Dependencies:</strong> <pre>${JSON.stringify(func.dependencies, null, 2) || '[]'}<pre><br>`;\n                infoContent += `<strong>Triggers:</strong> <pre>${JSON.stringify(func.triggers, null, 2) || '[]'}<pre><br>`;\n                infoContent += `<strong>Input Parameters:</strong> <pre>${JSON.stringify(func.input_parameters, null, 2) || '[]'}<pre><br>`;\n                infoContent += `<strong>Output Parameters:</strong> <pre>${JSON.stringify(func.output_parameters, null, 2) || '[]'}<pre><br>`;\n                infoContent += `<strong>Code:</strong><pre>${func.code || 'N/A'}</pre>`;\n\n                modalContent.innerHTML = infoContent;\n                modal.style.display = 'block';\n            }\n\n            // Close the modal when the user clicks on the close button\n            closeButton.addEventListener('click', function() {\n                modal.style.display = 'none';\n            });\n\n            // Close the modal when the user clicks anywhere outside of the modal content\n            window.addEventListener('click', function(event) {\n                if (event.target === modal) {\n                    modal.style.display = 'none';\n                }\n            });\n\n            // Filter functions based on search input\n            searchBar.addEventListener('input', function() {\n                const query = this.value.toLowerCase();\n                const filteredFunctions = allFunctions.filter(func =>\n                    func.name.toLowerCase().includes(query) ||\n                    (func.description && func.description.toLowerCase().includes(query))\n                );\n                displayFunctions(filteredFunctions);\n            });\n\n            // Toggle function selection\n            function toggleFunctionSelection(functionName) {\n                const index = availableFunctions.indexOf(functionName);\n                if (index === -1) {\n                    availableFunctions.push(functionName);\n                    addFunctionToAvailableList(functionName);\n                } else {\n                    availableFunctions.splice(index, 1);\n                    removeFunctionFromAvailableList(functionName);\n                }\n            }\n\n            // Add function to available functions list in UI\n            function addFunctionToAvailableList(functionName) {\n                const availableFunctionsList = document.getElementById('availableFunctionsList');\n                const functionItem = document.createElement('div');\n                functionItem.className = 'available-function-item';\n                functionItem.dataset.name = functionName;\n                functionItem.textContent = functionName;\n\n                const removeButton = document.createElement('span');\n                removeButton.className = 'remove-function';\n                removeButton.textContent = '×';\n\n                removeButton.addEventListener('click', function() {\n                    toggleFunctionSelection(functionName);\n                    // Update the add button in the function list\n                    const functionItems = document.querySelectorAll('.function-item');\n                    functionItems.forEach(item => {\n                        if (item.dataset.name === functionName) {\n                            const addButton = item.querySelector('.add-button');\n                            if (addButton) {\n                                addButton.textContent = 'Add';\n                                addButton.classList.remove('remove');\n                            }\n                        }\n                    });\n                });\n\n                functionItem.appendChild(removeButton);\n                availableFunctionsList.appendChild(functionItem);\n            }\n\n            // Remove function from available functions list in UI\n            function removeFunctionFromAvailableList(functionName) {\n                const availableFunctionsList = document.getElementById('availableFunctionsList');\n                const functionItems = availableFunctionsList.querySelectorAll('.available-function-item');\n                functionItems.forEach(item => {\n                    if (item.dataset.name === functionName) {\n                        availableFunctionsList.removeChild(item);\n                    }\n                });\n            }\n\n            // Send user message\n            sendMessageButton.addEventListener('click', function() {\n                const userMessage = userMessageInput.value.trim();\n                if (userMessage === '') return;\n\n                if (availableFunctions.length === 0) {\n                    alert('Please select at least one function before sending a message.');\n                    return;\n                }\n\n                // Display user message\n                addMessageToChat('user', userMessage);\n\n                // Clear input\n                userMessageInput.value = '';\n\n                // Prepare parameters\n                const params = {\n                    chat_history: chatHistory,\n                    available_function_names: availableFunctions.join(', ')\n                };\n\n                fetch(\"{{ url_for('api.execute_function', function_name='chat_with_functions') }}\", {\n                    method: 'POST',\n                    headers: { 'Content-Type': 'application/json' },\n                    body: JSON.stringify(params)\n                })\n                .then(response => response.json())\n                .then(data => {\n                    console.log('Data received from server:', data);\n\n                    let assistantResponse;\n\n                    if (typeof data === 'string') {\n                        assistantResponse = data;\n                    } else if (data.message) {\n                        assistantResponse = data.message;\n                    } else {\n                        assistantResponse = JSON.stringify(data);\n                    }\n\n                    // Display the assistant's response\n                    addMessageToChat('assistant', assistantResponse);\n                })\n                .catch(error => {\n                    console.error('Error:', error);\n                    addMessageToChat('assistant', 'Error processing your request.');\n                });\n            });\n\n            // Function to add message to chat window\n            function addMessageToChat(role, message) {\n                if (typeof message !== 'string') {\n                    message = 'No message received.';\n                }\n\n                const messageElement = document.createElement('div');\n                messageElement.className = `chat-message ${role}`;\n\n                if (role === 'assistant') {\n                    // Parse Markdown\n                    messageElement.innerHTML = marked.parse(message);\n                } else {\n                    messageElement.textContent = message;\n                }\n\n                chatWindow.appendChild(messageElement);\n                chatWindow.scrollTop = chatWindow.scrollHeight;\n\n                // Save message to chat history\n                chatHistory.push({ role: role, message: message });\n            }\n\n            // Initialize by fetching functions\n            fetchFunctions();\n        });\n    </script>\n{% endblock %}\n"
  },
  {
    "path": "babyagi/dashboard/templates/function_details.html",
    "content": "{% extends \"base.html\" %}\n{% block title %}Function Details: {{ function_name }}{% endblock %}\n{% block head %}\n    <link rel=\"stylesheet\" href=\"{{ url_for('dashboard.static', filename='css/style.css') }}\">\n    <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/codemirror.min.css\">\n    <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/theme/monokai.min.css\">\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/codemirror.min.js\"></script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/mode/python/python.min.js\"></script>\n{% endblock %}\n{% block breadcrumb %}\n    <div class=\"breadcrumb\">\n        <a href=\"{{ url_for('dashboard.dashboard_home') }}\">Home</a> &gt; <span id=\"functionName\">{{ function_name }}</span>\n    </div>\n{% endblock %}\n{% block content %}\n    <h1>Function: <span id=\"functionName\">{{ function_name }}</span></h1>\n\n    <div class=\"two-column\">\n        <div class=\"column\">\n            <div class=\"function-detail\">\n                <div class=\"section-title\">Execute Function</div>\n                <div id=\"executionForm\"></div>\n                <button onclick=\"executeFunction()\" class=\"button\">Execute</button>\n                <div id=\"executionResult\" class=\"execution-result\"></div>\n            </div>\n            <div class=\"function-detail\">\n                <div class=\"section-title\">Details</div>\n                <div id=\"functionDetails\"></div>\n                <div id=\"functionTriggers\"></div>\n            </div>\n        </div>\n\n        <div class=\"column\">\n            <div class=\"function-detail\">\n                <div class=\"section-title\">Code</div>\n                <textarea id=\"codeEditor\"></textarea>\n                <button onclick=\"updateFunction()\" class=\"button\">Update Function</button>\n            </div>\n\n            <div class=\"function-detail\">\n                <div class=\"section-title\">Logs</div>\n                <div id=\"functionLogs\"></div>\n            </div>\n\n            <div class=\"function-detail\">\n                <div class=\"section-title\">\n                    Versions\n                </div>\n                <button class=\"button\" id=\"toggleVersionHistory\">Show Versions</button>\n                <div id=\"versionHistory\" class=\"version-history\" style=\"display: none;\"></div>\n            </div>\n        </div>\n    </div>\n{% endblock %}\n{% block scripts %}\n    <script>\n        window.functionName = \"{{ function_name }}\";\n        window.dashboardRoute = \"{{ url_for('dashboard.dashboard_home') }}\";\n        const apiRoutes = {\n            getFunction: \"{{ url_for('api.get_function', function_name=function_name) }}\",\n            executeFunction: \"{{ url_for('api.execute_function', function_name=function_name) }}\",\n            getLogs: \"{{ url_for('api.get_logs', function_name=function_name) }}\",\n            getTriggers: \"{{ url_for('api.get_triggers', function_name=function_name) }}\",\n            getFunctionVersions: \"{{ url_for('api.get_function_versions', function_name=function_name) }}\",\n            activateVersion: \"{{ url_for('api.activate_function_version', function_name=function_name, version='VERSION_PLACEHOLDER') }}\",\n            updateFunction: \"{{ url_for('api.update_function', function_name=function_name) }}\"\n        };\n    </script>\n    <script src=\"{{ url_for('dashboard.static', filename='js/function_details.js') }}\"></script>\n{% endblock %}\n"
  },
  {
    "path": "babyagi/dashboard/templates/function_graph.html",
    "content": "{% extends \"base.html\" %}\n{% block title %}Function Relationship Graph{% endblock %}\n\n{% block head %}\n    {{ super() }}\n    <!-- Include Cytoscape.js -->\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.21.1/cytoscape.min.js\"></script>\n    <!-- Include CodeMirror CSS and JS -->\n    <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/codemirror.min.css\">\n    <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/theme/monokai.min.css\">\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/codemirror.min.js\"></script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/mode/python/python.min.js\"></script>\n    <!-- Page-Specific Styles -->\n    <style>\n        #graph {\n            width: 100%;\n            height: calc(100vh - 160px); /* Adjust height considering nav and breadcrumb */\n            background-color: var(--background-color);\n        }\n\n        .overlay {\n            position: absolute;\n            background: var(--card-bg-color);\n            border: 1px solid var(--border-color);\n            padding: 20px;\n            border-radius: 8px;\n            box-shadow: 0 2px 5px rgba(0,0,0,0.1);\n            z-index: 10;\n            top: 10px;\n            right: 10px;\n            width: 400px;\n            height: 90vh;\n            overflow-y: auto;\n            display: none;\n        }\n\n        .close-btn {\n            position: absolute;\n            top: 10px;\n            right: 10px;\n            font-size: 20px;\n            cursor: pointer;\n            color: var(--text-color);\n        }\n\n        .toggle-menu {\n            display: flex;\n            justify-content: space-around;\n            margin-bottom: 20px;\n        }\n\n        .toggle-menu button {\n            padding: 10px;\n            cursor: pointer;\n            background-color: var(--primary-color);\n            color: white;\n            border: none;\n            border-radius: 4px;\n        }\n\n        .toggle-menu button:hover {\n            background-color: var(--hover-color);\n        }\n\n        .card {\n            border: 1px solid var(--border-color);\n            border-radius: 8px;\n            padding: 20px;\n            margin-bottom: 15px;\n            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);\n            background-color: var(--card-bg-color);\n        }\n\n        .card-title {\n            font-size: 1.2em;\n            margin-bottom: 10px;\n            color: var(--primary-color);\n        }\n\n        .card-content {\n            display: none;\n        }\n\n        .card-content.active {\n            display: block;\n        }\n\n        #tab-buttons {\n            display: flex;\n            margin-bottom: 10px;\n        }\n\n        .tab-button {\n            padding: 5px 10px;\n            margin-right: 5px;\n            background-color: #f0f0f0;\n            border: 1px solid #ccc;\n            border-radius: 3px;\n            cursor: pointer;\n        }\n\n        .tab-button.active {\n            background-color: #007bff;\n            color: white;\n            border-color: #0056b3;\n        }\n\n        #tab-content {\n            border: 1px solid #ccc;\n            padding: 10px;\n            border-radius: 3px;\n        }\n    </style>\n{% endblock %}\n\n{% block breadcrumb %}\n    <div class=\"breadcrumb\">\n        <a href=\"{{ url_for('dashboard.dashboard_home') }}\">Home</a> &gt; Function Graph\n    </div>\n{% endblock %}\n\n{% block content %}\n    <h1>Function Relationship Graph</h1>\n    <div id=\"graph\"></div>\n\n    <!-- Overlay for Function Details -->\n    <div id=\"overlay\" class=\"overlay\">\n        <span class=\"close-btn\" onclick=\"closeOverlay()\">×</span>\n        <div id=\"overlay-content\">\n            <h2 id=\"functionName\"></h2>\n            <!-- Tab buttons -->\n            <div id=\"tab-buttons\">\n                <button class=\"tab-button active\" onclick=\"showTab('description')\">Description</button>\n                <button class=\"tab-button\" onclick=\"showTab('code')\">Code</button>\n                <button class=\"tab-button\" onclick=\"showTab('logs')\">Logs</button>\n                <button class=\"tab-button\" onclick=\"showTab('execute')\">Execute</button>\n                <button class=\"tab-button\" onclick=\"showTab('versions')\">Versions</button>\n            </div>\n            <!-- Tab content -->\n            <div id=\"tab-content\">\n                <div id=\"description-tab\">\n                    <div id=\"functionDetails\"></div>\n                    <div id=\"functionTriggers\"></div>\n                </div>\n                <div id=\"code-tab\" style=\"display: none;\">\n                    <textarea id=\"codeEditor\"></textarea>\n                    <button onclick=\"updateFunction()\" class=\"button\">Update Function</button>\n                </div>\n                <div id=\"logs-tab\" style=\"display: none;\">\n                    <div id=\"functionLogs\"></div>\n                </div>\n                <div id=\"execute-tab\" style=\"display: none;\">\n                    <div id=\"executionForm\"></div>\n                    <button onclick=\"executeFunction()\" class=\"button\">Execute</button>\n                    <div id=\"executionResult\" class=\"execution-result\"></div>\n                </div>\n                <div id=\"versions-tab\" style=\"display: none;\">\n                    <button class=\"button\" id=\"toggleVersionHistory\">Show Versions</button>\n                    <div id=\"versionHistory\" class=\"version-history\" style=\"display: none;\"></div>\n                </div>\n            </div>\n        </div>\n    </div>\n{% endblock %}\n\n{% block scripts %}\n    {{ super() }}\n    <script>\n        // Define dashboardRoute correctly without _external and _scheme\n        window.dashboardRoute = \"{{ url_for('dashboard.dashboard_home') }}\";\n\n        // Initialize Cytoscape graph\n        let cy;\n        document.addEventListener('DOMContentLoaded', () => {\n            cy = cytoscape({\n                container: document.getElementById('graph'),\n                style: [\n                    {\n                        selector: 'node',\n                        style: {\n                            'shape': 'rectangle',\n                            'background-color': '#E6F2FF',\n                            'label': 'data(id)',\n                            'text-valign': 'center',\n                            'text-halign': 'center',\n                            'text-wrap': 'wrap',\n                            'text-max-width': '150px',\n                            'width': 'label',\n                            'height': 'label',\n                            'padding': '12px',\n                            'font-weight': 'bold',\n                            'font-size': '16px',\n                            'color': '#333333',\n                            'text-outline-color': '#FFFFFF',\n                            'text-outline-width': 1,\n                            'cursor': 'pointer'\n                        }\n                    },\n                    {\n                        selector: 'node[type=\"import\"]',\n                        style: {\n                            'background-color': '#E6FFF2'  // Light green for imports\n                        }\n                    },\n                    {\n                        selector: 'node[type=\"trigger\"]',\n                        style: {\n                            'background-color': '#FFE6E6'  // Light red for triggers\n                        }\n                    },\n                    {\n                        selector: 'node:hover',\n                        style: {\n                            'background-opacity': 0.8\n                        }\n                    },\n                    {\n                        selector: 'edge',\n                        style: {\n                            'width': 1,\n                            'line-color': '#999999',\n                            'target-arrow-color': '#999999',\n                            'target-arrow-shape': 'triangle',\n                            'curve-style': 'bezier',\n                            'arrow-scale': 1.5\n                        }\n                    },\n                    {\n                        selector: 'edge[type=\"dependency\"]',\n                        style: {\n                            'width': 2\n                        }\n                    },\n                    {\n                        selector: 'edge[type=\"trigger\"]',\n                        style: {\n                            'line-style': 'dashed',\n                            'label': 'trigger',\n                            'font-size': '12px',\n                            'text-rotation': 'autorotate',\n                            'text-margin-y': -10\n                        }\n                    }\n                ],\n                layout: {\n                    name: 'cose',\n                    idealEdgeLength: 50,\n                    nodeOverlap: 20,\n                    refresh: 20,\n                    fit: true,\n                    padding: 30,\n                    randomize: false,\n                    componentSpacing: 80,\n                    nodeRepulsion: 450000,\n                    edgeElasticity: 100,\n                    nestingFactor: 5,\n                    gravity: 80,\n                    numIter: 1000,\n                    initialTemp: 200,\n                    coolingFactor: 0.95,\n                    minTemp: 1.0\n                },\n                wheelSensitivity: 0.2\n            });\n\n            fetch('/api/functions')\n                .then(response => {\n                    if (!response.ok) {\n                        throw new Error('Failed to fetch functions');\n                    }\n                    return response.json();\n                })\n                .then(data => {\n                    const elements = [];\n                    const imports = new Set();\n\n                    data.forEach(func => {\n                        elements.push({ data: { id: func.name, type: 'function' } });\n\n                        func.dependencies.forEach(dep => {\n                            elements.push({ data: { id: dep, type: 'function' } });\n                            elements.push({ data: { source: func.name, target: dep, type: 'dependency' } });\n                        });\n\n                        func.triggers.forEach(trigger => {\n                            elements.push({ data: { id: trigger, type: 'trigger' } });\n                            elements.push({ data: { source: func.name, target: trigger, type: 'trigger' } });\n                        });\n\n                        func.imports.forEach(imp => imports.add(imp));\n                    });\n\n                    imports.forEach(imp => {\n                        elements.push({ data: { id: imp, type: 'import' } });\n                    });\n\n                    data.forEach(func => {\n                        func.imports.forEach(imp => {\n                            elements.push({ data: { source: func.name, target: imp, type: 'import' } });\n                        });\n                    });\n\n                    cy.add(elements);\n                    cy.layout({ name: 'cose' }).run();\n\n                    // Zoom to fit with a bit of padding\n                    cy.fit(40);\n\n                    // Add a slight zoom in\n                    cy.zoom({\n                        level: cy.zoom() * 1.3,\n                        renderedPosition: { x: cy.width() / 2, y: cy.height() / 2 }\n                    });\n                })\n                .catch(error => {\n                    console.error('Error fetching functions:', error);\n                });\n\n            cy.on('tap', 'node', function(evt) {\n                const node = evt.target;\n                if (node.data('type') === 'function') {\n                    showFunctionOverlay(node.id());\n                }\n            });\n\n            cy.on('zoom pan', () => {\n                closeOverlay();\n            });\n        });\n\n        // Initialize global variables and API routes\n        window.functionName = null;\n        window.apiRoutes = {}; // Initialize apiRoutes as an empty object\n        window.functionDetailsJsLoaded = false; // Flag to check if function_details.js is loaded\n\n        // Update apiRoutes based on the selected function\n        window.updateApiRoutes = function(functionName) {\n            window.apiRoutes = {\n                getFunction: `/api/function/${functionName}`,\n                updateFunction: `/api/function/${functionName}`,\n                executeFunction: `/api/execute/${functionName}`,\n                getLogs: `/api/logs/${functionName}`,\n                getFunctionVersions: `/api/function/${functionName}/versions`,\n                activateVersion: (version) => `/api/function/${functionName}/versions/${version}/activate`\n            };\n        };\n\n        // Function to show the overlay with function details\n        function showFunctionOverlay(functionName) {\n            const overlay = document.getElementById('overlay');\n            document.getElementById('functionName').textContent = functionName;\n\n            // Set global functionName\n            window.functionName = functionName;\n\n            // Update apiRoutes with the current function name\n            window.updateApiRoutes(functionName);\n\n            overlay.style.display = 'block';\n\n            // Fetch the function data from the API\n            fetch(window.apiRoutes.getFunction)\n                .then(response => {\n                    if (!response.ok) {\n                        throw new Error('Failed to fetch function data');\n                    }\n                    return response.json();\n                })\n                .then(data => {\n                    console.log(\"Fetched function data:\", data);\n\n                    if (data.error) {\n                        console.error(\"Error fetching function data:\", data.error);\n                        return;\n                    }\n\n                    // Set the global functionData to the fetched data\n                    window.functionData = data;\n\n                    // Check if function_details.js is loaded\n                    if (!window.functionDetailsJsLoaded) {\n                        var script = document.createElement('script');\n                        script.src = \"{{ url_for('dashboard.static', filename='js/function_details.js') }}\";\n                        script.onload = function() {\n                            window.functionDetailsJsLoaded = true;\n\n                            // Call the required functions after loading the script\n                            window.loadFunctionDetails();\n                            window.loadFunctionLogs();\n\n                            // Initialize CodeMirror editor\n                            window.initCodeEditor();\n\n                            // Set up version history toggle\n                            const toggleVersionHistoryBtn = document.getElementById('toggleVersionHistory');\n                            if (toggleVersionHistoryBtn) {\n                                toggleVersionHistoryBtn.onclick = window.toggleVersionHistory;\n                            }\n\n                            // Default to showing the Description tab\n                            showTab('description');\n                        };\n                        document.head.appendChild(script);\n                    } else {\n                        // If function_details.js is already loaded, just call the necessary functions\n                        window.loadFunctionDetails();\n                        window.loadFunctionLogs();\n\n                        // Initialize CodeMirror editor\n                        if (typeof codeEditor === 'undefined' || !codeEditor) {\n                            window.initCodeEditor();\n                        } else {\n                            codeEditor.setValue('');\n                            codeEditor.toTextArea();\n                            window.initCodeEditor();\n                        }\n\n                        // Set up version history toggle\n                        const toggleVersionHistoryBtn = document.getElementById('toggleVersionHistory');\n                        if (toggleVersionHistoryBtn) {\n                            toggleVersionHistoryBtn.onclick = window.toggleVersionHistory;\n                        }\n\n                        // Default to showing the Description tab\n                        showTab('description');\n                    }\n                })\n                .catch(error => {\n                    console.error('Error fetching function data:', error);\n                });\n        }\n\n        // Function to handle tab switching\n        function showTab(tabName) {\n            const tabs = ['description', 'code', 'logs', 'execute', 'versions'];\n            tabs.forEach(tab => {\n                const tabElement = document.getElementById(`${tab}-tab`);\n                const tabButton = document.querySelector(`button.tab-button:nth-child(${tabs.indexOf(tab) + 1})`);\n                if (tab === tabName) {\n                    tabElement.style.display = 'block';\n                    tabButton.classList.add('active');\n                } else {\n                    tabElement.style.display = 'none';\n                    tabButton.classList.remove('active');\n                }\n            });\n\n            // Load content for specific tabs if needed\n            if (tabName === 'code' && document.getElementById('code-tab').innerHTML === '') {\n                window.initCodeEditor();\n            } else if (tabName === 'logs' && document.getElementById('logs-tab').innerHTML === '') {\n                window.loadFunctionLogs();\n            } else if (tabName === 'execute' && document.getElementById('executionForm').innerHTML === '') {\n                window.createExecutionForm();\n            } else if (tabName === 'versions' && document.getElementById('versionHistory').innerHTML === '') {\n                window.loadFunctionVersions();\n            }\n        }\n\n        // Function to close the overlay\n        function closeOverlay() {\n            document.getElementById('overlay').style.display = 'none';\n        }\n\n        // Function to toggle card visibility (if needed)\n        function toggleCard(cardId) {\n            const allCards = document.querySelectorAll('.card .card-content');\n            allCards.forEach(card => card.classList.remove('active'));\n\n            const selectedCard = document.getElementById(cardId).querySelector('.card-content');\n            selectedCard.classList.add('active');\n        }\n\n        // Override the executeFunction to ensure it uses POST method\n        window.executeFunction = function() {\n            let params = {};\n            const form = document.getElementById('executionForm');\n            const inputs = form.querySelectorAll('input, textarea');\n            inputs.forEach(input => {\n                params[input.name] = input.value;\n            });\n\n            fetch(apiRoutes.executeFunction, {\n                method: 'POST',\n                headers: {\n                    'Content-Type': 'application/json',\n                },\n                body: JSON.stringify(params),\n            })\n            .then(response => {\n                if (!response.ok) {\n                    return response.text().then(text => {\n                        throw new Error(text || response.statusText);\n                    });\n                }\n                return response.json();\n            })\n            .then(data => {\n                document.getElementById('executionResult').innerHTML = `<pre>${JSON.stringify(data, null, 2)}</pre>`;\n            })\n            .catch((error) => {\n                console.error('Error:', error);\n                document.getElementById('executionResult').innerHTML = `<pre class=\"error\">Error executing function: ${error.message}</pre>`;\n            });\n        };\n    </script>\n{% endblock %}\n"
  },
  {
    "path": "babyagi/dashboard/templates/function_graph_3d.html",
    "content": "{% extends \"base.html\" %}\n{% block title %}3D Function Relationship Graph{% endblock %}\n{% block head %}\n    {{ super() }}\n    <style>\n        body {\n            margin: 0;\n            overflow: hidden;\n            font-family: 'Inter', Arial, sans-serif;\n        }\n        #3d-graph {\n            width: 100%;\n            height: 100vh;\n        }\n        .node-label {\n            background-color: white;\n            padding: 5px;\n            border-radius: 5px;\n            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);\n            position: absolute;\n            display: none;\n            z-index: 1;\n        }\n    </style>\n{% endblock %}\n{% block breadcrumb %}\n    <div class=\"breadcrumb\">\n        <a href=\"{{ url_for('dashboard.dashboard_home') }}\">Home</a> &gt; 3D Graph\n    </div>\n{% endblock %}\n{% block content %}\n    <div id=\"3d-graph\"></div>\n    <div id=\"node-label\" class=\"node-label\"></div>\n{% endblock %}\n{% block scripts %}\n    <!-- Include the 3D Force-Directed Graph and Three.js libraries -->\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js\"></script>\n    <script src=\"https://unpkg.com/3d-force-graph\"></script>\n\n    <script>\n        // Main script to generate 3D graph\n\n        // Fetch the data for functions and dependencies (same structure as before)\n        fetch('/api/functions')\n            .then(response => response.json())\n            .then(data => {\n                const imports = new Set();\n\n                // Prepare the nodes and links arrays for the 3D force-directed graph\n                const nodes = [];\n                const links = [];\n\n                // Map function data to nodes and edges\n                data.forEach(func => {\n                    nodes.push({ id: func.name, group: 'function' });\n\n                    func.dependencies.forEach(dep => {\n                        links.push({ source: func.name, target: dep, type: 'dependency' });\n                    });\n\n                    func.triggers.forEach(trigger => {\n                        links.push({ source: func.name, target: trigger, type: 'trigger' });\n                    });\n\n                    func.imports.forEach(imp => imports.add(imp));\n                });\n\n                imports.forEach(imp => {\n                    nodes.push({ id: imp, group: 'import' });\n                });\n\n                data.forEach(func => {\n                    func.imports.forEach(imp => {\n                        links.push({ source: func.name, target: imp, type: 'import' });\n                    });\n                });\n\n                // Create the 3D graph using 3D Force-Directed Graph\n                const Graph = ForceGraph3D()\n                    (document.getElementById('3d-graph'))\n                    .graphData({ nodes, links })\n                    .nodeLabel('id')\n                    .nodeAutoColorBy('group')\n                    .linkWidth(link => link.type === 'dependency' ? 2 : 1)\n                    .linkDirectionalParticles(2)\n                    .linkDirectionalParticleWidth(2)\n                    .nodeThreeObject(node => {\n                        // Create a custom 3D object for nodes using the correct version of THREE\n                        const sphereGeometry = new THREE.SphereGeometry(8, 32, 32);\n                        const material = new THREE.MeshBasicMaterial({ color: node.group === 'function' ? 0x44aa88 : 0xffcc00 });\n                        return new THREE.Mesh(sphereGeometry, material);\n                    })\n                    .onNodeClick(node => {\n                        // On node click, dynamically fetch and show more information\n                        expandNode(node);\n                    });\n\n                // Function to expand a node and add more details dynamically\n                function expandNode(node) {\n                    // Fetch the details of the clicked node (function)\n                    const url = '/api/functions/' + node.id;\n\n                    fetch(url)\n                        .then(response => response.json())\n                        .then(funcData => {\n                            // Handle function data here\n                            // You can add more nodes or display details as needed\n                        })\n                        .catch(error => {\n                            console.error('Error fetching function details:', error);\n                        });\n                }\n            });\n    </script>\n{% endblock %}\n"
  },
  {
    "path": "babyagi/dashboard/templates/function_graph_mermaid.html",
    "content": "{% extends \"base.html\" %}\n{% block title %}Function Relationship Mermaid Graph{% endblock %}\n\n{% block head %}\n    {{ super() }}\n    <!-- Include Mermaid.js as an ESM module -->\n    <script type=\"module\">\n        import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';\n        \n        // Initialize Mermaid with desired configuration\n        mermaid.initialize({\n            startOnLoad: false, // We will manually initialize after graph is inserted\n            theme: 'default',\n            flowchart: {\n                useMaxWidth: true,\n                htmlLabels: true,\n                fontFamily: 'Arial, sans-serif' // Use web-safe fonts to avoid CORS issues\n            }\n        });\n    </script>\n    <style>\n        /* Additional styles specific to the function_graph_mermaid.html */\n        #graph {\n            width: 100%;\n            height: calc(100vh - 160px); /* Adjust height considering nav and breadcrumb */\n            background-color: var(--background-color);\n            overflow: auto;\n            padding: 20px;\n        }\n\n        /* Download Button Styles */\n        #download-btn {\n            position: fixed;\n            top: 120px; /* Adjust based on your layout */\n            right: 30px;\n            padding: 10px 20px;\n            background-color: var(--primary-color);\n            color: white;\n            border: none;\n            border-radius: 5px;\n            cursor: pointer;\n            z-index: 1001; /* Ensure it's above the graph */\n            box-shadow: 0 2px 5px rgba(0,0,0,0.2);\n        }\n\n        #download-btn:hover {\n            background-color: var(--hover-color);\n        }\n\n        /* Responsive Adjustments */\n        @media (max-width: 768px) {\n            #download-btn {\n                top: 100px;\n                right: 20px;\n                padding: 8px 16px;\n            }\n        }\n\n        /* Optional: Enhance node hover effects */\n        .mermaid .node rect {\n            cursor: pointer;\n        }\n\n        .mermaid .node:hover rect {\n            stroke: var(--primary-color);\n            stroke-width: 2px;\n        }\n    </style>\n{% endblock %}\n\n{% block breadcrumb %}\n    <div class=\"breadcrumb\">\n        <a href=\"{{ url_for('dashboard.dashboard_home') }}\">Home</a> &gt; Mermaid Graph\n    </div>\n{% endblock %}\n\n{% block content %}\n    <h1>Function Relationship Mermaid Graph</h1>\n    <div id=\"graph\">\n        <div class=\"mermaid\">\n            %% Mermaid graph will be injected here\n        </div>\n    </div>\n    <!-- Download Button -->\n    <!-- <button id=\"download-btn\">Download Image</button>-->\n{% endblock %}\n\n{% block scripts %}\n    {{ super() }}\n    <script type=\"module\">\n        import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';\n\n        document.addEventListener('DOMContentLoaded', () => {\n            fetch('/api/functions')\n                .then(response => {\n                    if (!response.ok) {\n                        throw new Error('Failed to fetch functions');\n                    }\n                    return response.json();\n                })\n                .then(data => {\n                    let mermaidGraph = 'graph TD\\n';\n\n                    const imports = new Set();\n                    const wrappers = [];  // To store functions ending with _wrapper\n\n                    // Process each function to build the graph\n                    data.forEach(func => {\n                        // Prepare input and output parameters\n                        const inputs = Array.isArray(func.input_parameters) && func.input_parameters.length > 0\n                            ? func.input_parameters.map(param => `${param.name}: ${param.type}`).join(', ')\n                            : 'None';\n                        const outputs = Array.isArray(func.output_parameters) && func.output_parameters.length > 0\n                            ? func.output_parameters.map(param => `${param.name}: ${param.type}`).join(', ')\n                            : 'None';\n\n                        // Multiline label using <br/> for inputs and outputs, with function name in bold\n                        const label = `<b>${func.name}</b><br/>Inputs: ${inputs}<br/>Outputs: ${outputs}`;\n\n                        if (func.name.endsWith('_wrapper')) {\n                            wrappers.push(func.name);  // Add _wrapper functions to this array\n                        }\n\n                        // Define node with HTML-like labels for better formatting\n                        mermaidGraph += `    ${func.name}[\"${label}\"]\\n`;\n\n                        // Add dependencies as edges\n                        func.dependencies.forEach(dep => {\n                            mermaidGraph += `    ${func.name} -->|Depends on| ${dep}\\n`;\n                        });\n\n                        // Add triggers as dashed edges\n                        func.triggers.forEach(trigger => {\n                            mermaidGraph += `    ${func.name} -.->|Triggered by| ${trigger}\\n`;\n                        });\n\n                        // Collect imports\n                        if (Array.isArray(func.imports)) {\n                            func.imports.forEach(imp => imports.add(imp));\n                        }\n                    });\n\n                    // Define Imports subgraph\n                    if (imports.size > 0) {\n                        mermaidGraph += `    subgraph Imports\\n`;\n                        imports.forEach(imp => {\n                            mermaidGraph += `        ${imp}[\"Import: ${imp}\"]\\n`;\n                        });\n                        mermaidGraph += `    end\\n`;\n\n                        // Link functions to imports\n                        data.forEach(func => {\n                            if (Array.isArray(func.imports)) {\n                                func.imports.forEach(imp => {\n                                    mermaidGraph += `    ${func.name} -->|Uses| ${imp}\\n`;\n                                });\n                            }\n                        });\n                    }\n\n                    // Define Wrapper_Functions subgraph if any\n                    if (wrappers.length > 0) {\n                        mermaidGraph += `    subgraph Wrapper_Functions\\n`;\n                        wrappers.forEach(wrapper => {\n                            mermaidGraph += `        ${wrapper}[\"<b>${wrapper}</b>\"]\\n`;\n                        });\n                        mermaidGraph += `    end\\n`;\n\n                        // Link wrapper functions if necessary\n                        // (Add any specific links related to wrapper functions here)\n                    }\n\n                    // Inject the graph into the Mermaid container\n                    const graphContainer = document.querySelector('.mermaid');\n                    graphContainer.innerHTML = mermaidGraph;\n\n                    // Render the Mermaid graph\n                    mermaid.init(undefined, graphContainer);\n\n                    // Add click event listeners to nodes for interactivity\n                    // Note: Mermaid does not provide built-in click events, so we need to add them manually\n                    // This approach uses SVG elements generated by Mermaid\n                    // Ensure that the graph has been rendered before adding event listeners\n\n                    // Delay to ensure Mermaid has rendered the SVG\n                    setTimeout(() => {\n                        const nodes = graphContainer.querySelectorAll('.node');\n                        nodes.forEach(node => {\n                            node.style.cursor = 'pointer'; // Change cursor to pointer\n                            node.addEventListener('click', () => {\n                                // Extract function name from the label\n                                const rawLabel = node.querySelector('text').innerHTML;\n                                const functionName = rawLabel.split('<br/>')[0].replace('<b>', '').replace('</b>', '');\n                                // Optional: Implement a click handler if needed\n                                // For now, we'll just alert the function name\n                                alert(`Function: ${functionName}`);\n                            });\n                        });\n                    }, 500); // Adjust delay as necessary\n                })\n                .catch(error => {\n                    console.error('Error fetching functions:', error);\n                    document.getElementById('graph').innerHTML = `<p>Error loading graph: ${error.message}</p>`;\n                });\n        });\n\n        // Download Image Functionality\n        document.getElementById('download-btn').addEventListener('click', () => {\n            const graphContainer = document.querySelector('.mermaid');\n            const svg = graphContainer.querySelector('svg');\n\n            if (!svg) {\n                alert('Graph is not loaded yet.');\n                return;\n            }\n\n            const serializer = new XMLSerializer();\n            const svgString = serializer.serializeToString(svg);\n\n            // Create a canvas to draw the SVG\n            const canvas = document.createElement('canvas');\n            const bbox = svg.getBBox();\n            canvas.width = bbox.width;\n            canvas.height = bbox.height;\n            const ctx = canvas.getContext('2d');\n\n            const img = new Image();\n            const svgBlob = new Blob([svgString], {type: 'image/svg+xml;charset=utf-8'});\n            const url = URL.createObjectURL(svgBlob);\n\n            img.onload = () => {\n                ctx.drawImage(img, 0, 0);\n                URL.revokeObjectURL(url);\n\n                // Create a PNG data URL\n                const pngUrl = canvas.toDataURL('image/png');\n\n                // Create a temporary link to trigger download\n                const downloadLink = document.createElement('a');\n                downloadLink.href = pngUrl;\n                downloadLink.download = 'function_relationship_graph.png';\n                document.body.appendChild(downloadLink);\n                downloadLink.click();\n                document.body.removeChild(downloadLink);\n            };\n\n            img.onerror = (error) => {\n                console.error('Error loading SVG image for download:', error);\n                alert('Failed to convert graph to image.');\n            };\n\n            img.src = url;\n        });\n    </script>\n{% endblock %}\n"
  },
  {
    "path": "babyagi/dashboard/templates/index.html",
    "content": "{% extends \"base.html\" %}\n{% block title %}Function Dashboard{% endblock %}\n{% block content %}\n    <h1>Function Dashboard</h1>\n    <input type=\"text\" id=\"searchInput\" placeholder=\"Search functions...\" onkeyup=\"filterTable()\">\n    <table id=\"functionTable\">\n        <thead>\n            <tr>\n                <th class=\"sortable\" onclick=\"sortTable('name')\">Name</th>\n                <th>Version</th>\n                <th>Description</th>\n                <th>Input Parameters</th>\n                <th>Output Parameters</th>\n                <th>Dependencies</th>\n                <th>Imports</th>\n                <th>Triggers</th>\n                <th class=\"sortable\" onclick=\"sortTable('created_date')\">Created Date</th>\n                <th class=\"sortable\" onclick=\"sortTable('total_logs')\">Total Logs</th>\n                <th class=\"sortable\" onclick=\"sortTable('last_log_date')\">Last Log Date</th>\n            </tr>\n        </thead>\n        <tbody>\n            <!-- Function rows will be dynamically inserted here -->\n        </tbody>\n    </table>\n    <div id=\"functionGrid\" class=\"function-grid\">\n        <!-- Function cards will be dynamically inserted here for mobile view -->\n    </div>\n{% endblock %}\n{% block scripts %}\n    <script>\n        const dashboardRoute = \"{{ url_for('dashboard.dashboard_home') }}\";\n        const apiFunctionsUrl = \"{{ url_for('api.get_functions') }}\";\n        const apiLogsUrl = \"{{ url_for('api.get_logs', function_name='') }}\"; // Base URL for logs\n    </script>\n    <!-- Include external JavaScript -->\n    <script src=\"{{ url_for('dashboard.static', filename='js/dashboard.js') }}\"></script>\n{% endblock %}\n"
  },
  {
    "path": "babyagi/dashboard/templates/log_page.html",
    "content": "{% extends \"base.html\" %}\n{% block title %}Log Details{% endblock %}\n{% block content %}\n<h1>Log Details for Log ID {{ log_id }}</h1>\n\n<!-- Container to display the logs -->\n<div id=\"logContainer\"></div>\n{% endblock %}\n\n{% block scripts %}\n<style>\n    /* CSS Styles */\n    .log-entry {\n        margin-left: 20px;\n        border-left: 1px solid #ccc;\n        padding-left: 10px;\n        position: relative;\n    }\n\n    .log-entry::before {\n        content: '';\n        position: absolute;\n        left: -1px;\n        top: 0;\n        bottom: 0;\n        width: 1px;\n        background: #ccc;\n    }\n\n    .log-header {\n        font-weight: bold;\n        display: flex;\n        align-items: center;\n    }\n\n    .log-status {\n        width: 12px;\n        height: 12px;\n        border-radius: 50%;\n        margin-right: 10px;\n    }\n\n    .log-status-success {\n        background-color: green;\n    }\n\n    .log-status-error {\n        background-color: red;\n    }\n\n    .log-status-other {\n        background-color: yellow;\n    }\n\n    .log-details {\n        margin-top: 5px;\n        display: none; /* Hidden by default */\n        background-color: #f9f9f9;\n        padding: 10px;\n    }\n\n    .toggle-button {\n        color: blue;\n        cursor: pointer;\n        text-decoration: underline;\n        margin-left: 10px;\n    }\n\n    pre {\n        background-color: #f4f4f4;\n        padding: 10px;\n        overflow: auto;\n    }\n</style>\n\n<script>\n    document.addEventListener('DOMContentLoaded', function() {\n        const logId = {{ log_id }};\n        const apiLogBundleUrl = '/api/log_bundle/' + logId;\n\n        fetch(apiLogBundleUrl)\n        .then(response => {\n            if (!response.ok) {\n                throw new Error(`Error ${response.status}: ${response.statusText}`);\n            }\n            return response.json();\n        })\n        .then(data => {\n            const logs = data.logs;\n            if (!logs || logs.length === 0) {\n                document.getElementById('logContainer').innerHTML = '<p>No logs found.</p>';\n                return;\n            }\n\n            const logsById = {};\n            logs.forEach(log => {\n                log.children = [];\n                logsById[log.id] = log;\n            });\n\n            // Build the tree by assigning children to their respective parents\n            logs.forEach(log => {\n                if (log.parent_log_id !== null && logsById[log.parent_log_id]) {\n                    logsById[log.parent_log_id].children.push(log);\n                }\n            });\n    \n            // Identify all root logs (logs without a parent in the fetched bundle)\n            const rootLogs = logs.filter(log => log.parent_log_id === null || !logsById[log.parent_log_id]);\n    \n            const logContainer = document.getElementById('logContainer');\n            rootLogs.forEach(log => {\n                renderLog(logContainer, log);\n            });\n        })\n        .catch(error => {\n            console.error('Error fetching log bundle:', error);\n            document.getElementById('logContainer').innerHTML = `<p>Error loading log bundle: ${error.message}</p>`;\n        });\n\n        function renderLog(container, log, depth = 0) {\n            const div = document.createElement('div');\n            div.className = 'log-entry';\n            div.style.marginLeft = (depth * 20) + 'px';\n\n            const header = document.createElement('div');\n            header.className = 'log-header';\n\n            const statusDiv = document.createElement('div');\n            statusDiv.className = 'log-status ' + getLogStatusClass(log.log_type);\n            header.appendChild(statusDiv);\n\n            const messageSpan = document.createElement('span');\n            messageSpan.textContent = `${log.function_name}: ${log.message}`;\n\n            const toggleButton = document.createElement('span');\n            toggleButton.className = 'toggle-button';\n            toggleButton.textContent = '[Show Details]';\n            toggleButton.addEventListener('click', function() {\n                if (detailsDiv.style.display === 'none') {\n                    detailsDiv.style.display = 'block';\n                    toggleButton.textContent = '[Hide Details]';\n                } else {\n                    detailsDiv.style.display = 'none';\n                    toggleButton.textContent = '[Show Details]';\n                }\n            });\n\n            header.appendChild(messageSpan);\n            header.appendChild(toggleButton);\n            div.appendChild(header);\n\n            const detailsDiv = document.createElement('div');\n            detailsDiv.className = 'log-details';\n\n            // Handle null or undefined params/output\n            const params = log.params ? JSON.stringify(log.params, null, 2) : 'N/A';\n            const output = log.output ? JSON.stringify(log.output, null, 2) : 'N/A';\n\n            detailsDiv.innerHTML = `\n                <p><strong>ID:</strong> ${log.id}</p>\n                <p><strong>Timestamp:</strong> ${new Date(log.timestamp).toLocaleString()}</p>\n                <p><strong>Log Type:</strong> ${log.log_type}</p>\n                <p><strong>Time Spent:</strong> ${log.time_spent ? log.time_spent.toFixed(3) + ' s' : 'N/A'}</p>\n                <p><strong>Parent Log ID:</strong> ${log.parent_log_id !== null ? log.parent_log_id : 'N/A'}</p>\n                <p><strong>Triggered By Log ID:</strong> ${log.triggered_by_log_id !== null ? log.triggered_by_log_id : 'N/A'}</p>\n                <p><strong>Params:</strong></p>\n                <pre>${params}</pre>\n                <p><strong>Output:</strong></p>\n                <pre>${output}</pre>\n            `;\n\n            div.appendChild(detailsDiv);\n\n            container.appendChild(div);\n\n            // Recursively render children\n            if (log.children && log.children.length > 0) {\n                log.children.forEach(childLog => {\n                    renderLog(container, childLog, depth + 1);\n                });\n            }\n        }\n\n        function getLogStatusClass(logType) {\n            switch (logType.toLowerCase()) {\n                case 'success':\n                    return 'log-status-success';\n                case 'error':\n                    return 'log-status-error';\n                default:\n                    return 'log-status-other';\n            }\n        }\n    });\n</script>\n{% endblock %}"
  },
  {
    "path": "babyagi/dashboard/templates/log_relationship_graph.html",
    "content": "{% extends \"base.html\" %}\n{% block title %}Log Relationship Graph{% endblock %}\n{% block breadcrumb %}\n    <div class=\"breadcrumb\">\n        <a href=\"{{ url_for('dashboard.dashboard_home') }}\">Home</a> &gt; Log Graph\n    </div>\n{% endblock %}\n{% block content %}\n    <h1>Log Relationship Graph</h1>\n    <div class=\"controls\">\n        <input type=\"text\" id=\"functionName\" placeholder=\"Function name (optional)\">\n        <input type=\"datetime-local\" id=\"startDate\" placeholder=\"Start date\">\n        <input type=\"datetime-local\" id=\"endDate\" placeholder=\"End date\">\n        <button onclick=\"loadLogs()\">Load Logs</button>\n    </div>\n    <div id=\"graph\"></div>\n    <div class=\"legend\">\n        <div class=\"legend-item\">\n            <div class=\"legend-color\" style=\"background-color: #3366cc;\"></div>\n            <span>Parent Relationship</span>\n        </div>\n        <div class=\"legend-item\">\n            <div class=\"legend-color\" style=\"background-color: #dc3912; border-top: 2px dashed #dc3912;\"></div>\n            <span>Trigger Relationship</span>\n        </div>\n    </div>\n    <div id=\"overlay\" class=\"overlay\">\n        <div class=\"overlay-content\">\n            <span class=\"close-btn\" onclick=\"closeOverlay()\">&times;</span>\n            <h2 id=\"logTitle\"></h2>\n            <pre id=\"logContent\"></pre>\n        </div>\n    </div>\n{% endblock %}\n{% block scripts %}\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.21.1/cytoscape.min.js\"></script>\n    <script>\n        const apiLogsUrl = \"{{ url_for('api.get_logs') }}\";\n    </script>\n    <script src=\"{{ url_for('dashboard.static', filename='js/log_graph.js') }}\"></script>\n{% endblock %}\n"
  },
  {
    "path": "babyagi/dashboard/templates/logs_dashboard.html",
    "content": "{% extends \"base.html\" %}\n{% block title %}Logs Dashboard{% endblock %}\n{% block breadcrumb %}\n    <div class=\"breadcrumb\">\n        <a href=\"{{ url_for('dashboard.dashboard_home') }}\">Home</a> &gt; Logs\n    </div>\n{% endblock %}\n{% block content %}\n    <h1>Logs Dashboard</h1>\n\n    <!-- Filter Section -->\n    <div class=\"filter-container\">\n        <label class=\"filter-label\" for=\"functionFilter\">Function:</label>\n        <select id=\"functionFilter\" class=\"filter-select\">\n            <option value=\"\">All</option>\n            <!-- Dynamic options will be populated here -->\n        </select>\n\n        <label class=\"filter-label\" for=\"logTypeFilter\">Log Type:</label>\n        <select id=\"logTypeFilter\" class=\"filter-select\">\n            <option value=\"\">All</option>\n            <option value=\"info\">Info</option>\n            <option value=\"success\">Success</option>\n            <option value=\"error\">Error</option>\n            <!-- Add more log types if applicable -->\n        </select>\n\n        <label class=\"filter-label\" for=\"dateFilter\">Date Range:</label>\n        <input type=\"date\" id=\"startDate\" class=\"filter-select\">\n        <input type=\"date\" id=\"endDate\" class=\"filter-select\">\n\n        <button class=\"btn btn-primary\" onclick=\"applyFilters()\">Apply Filters</button>\n        <button class=\"btn btn-secondary\" onclick=\"resetFilters()\">Reset Filters</button>\n    </div>\n\n    <!-- Logs Table (Desktop View) -->\n    <table id=\"logTable\" class=\"table table-striped table-bordered desktop-only\">\n        <thead>\n            <tr>\n                <th class=\"sortable\" onclick=\"sortLogs('id')\">ID</th>\n                <th class=\"sortable\" onclick=\"sortLogs('function_name')\">Function Name</th>\n                <th class=\"sortable\" onclick=\"sortLogs('message')\">Message</th>\n                <th class=\"sortable\" onclick=\"sortLogs('timestamp')\">Timestamp</th>\n                <th class=\"sortable\" onclick=\"sortLogs('log_type')\">Log Type</th>\n                <th class=\"sortable\" onclick=\"sortLogs('time_spent')\">Time Spent (s)</th>\n                <th class=\"sortable\" onclick=\"sortLogs('parent_log_id')\">Parent Log ID</th>\n                <th class=\"sortable\" onclick=\"sortLogs('triggered_by_log_id')\">Triggered By Log ID</th>\n            </tr>\n        </thead>\n        <tbody>\n            <!-- Log rows will be dynamically inserted here -->\n        </tbody>\n    </table>\n\n    <!-- Logs Grid (Mobile View) -->\n    <div id=\"logGrid\" class=\"log-grid mobile-only\">\n        <!-- Log cards will be dynamically inserted here -->\n    </div>\n{% endblock %}\n{% block scripts %}\n    <script>\n        const dashboardRoute = \"{{ url_for('dashboard.dashboard_home') }}\";\n        const apiLogsUrl = \"{{ url_for('api.get_logs') }}\";\n    </script>\n    <!-- Include external JavaScript -->\n    <script src=\"{{ url_for('dashboard.static', filename='js/log_dashboard.js') }}\"></script>\n{% endblock %}\n"
  },
  {
    "path": "babyagi/functionz/__init__.py",
    "content": "from .core.framework import func\n\n__all__ = ['func']\n"
  },
  {
    "path": "babyagi/functionz/core/__init__.py",
    "content": ""
  },
  {
    "path": "babyagi/functionz/core/execution.py",
    "content": "import subprocess\nimport sys\nimport importlib\nimport inspect\nfrom typing import Any, Dict, List, Optional\nfrom datetime import datetime\nimport logging\n\nlogger = logging.getLogger(__name__)\n\nclass FunctionExecutor:\n    def __init__(self, python_func):\n        self.python_func = python_func\n\n    def _install_external_dependency(self, package_name: str, imp_name: str) -> Any:\n        try:\n            return importlib.import_module(imp_name)\n        except ImportError:\n            subprocess.check_call([sys.executable, \"-m\", \"pip\", \"install\", package_name])\n            return importlib.import_module(package_name)\n\n    def _resolve_dependencies(self, function_version: Dict[str, Any], local_scope: Dict[str, Any],\n                              parent_log_id: Optional[int], executed_functions: List[str],\n                              visited: Optional[set] = None) -> None:\n        if visited is None:\n            visited = set()\n\n        function_name = function_version['name']\n        function_imports = self.python_func.db.get_function_imports(function_name)\n\n        for imp in function_imports:\n            lib_name = imp['lib'] if imp['lib'] else imp['name']\n            if lib_name not in local_scope:\n                module = self._install_external_dependency(lib_name, imp['name'])\n                local_scope[imp['name']] = module\n\n        for dep_name in function_version.get('dependencies', []):\n            if dep_name not in local_scope and dep_name not in visited:\n                visited.add(dep_name)\n                dep_data = self.python_func.db.get_function(dep_name)\n                if not dep_data:\n                    raise ValueError(f\"Dependency '{dep_name}' not found in the database.\")\n                self._resolve_dependencies(dep_data, local_scope, parent_log_id, executed_functions, visited)\n                exec(dep_data['code'], local_scope)\n                if dep_name in local_scope:\n                    dep_func = local_scope[dep_name]\n                    # Wrap the dependent function\n                    local_scope[dep_name] = self._create_function_wrapper(dep_func, dep_name, parent_log_id, executed_functions)\n\n    def _create_function_wrapper(self, func: callable, func_name: str, parent_log_id: int, executed_functions: List[str]):\n        def wrapper(*args, **kwargs):\n            return self.execute(func_name, *args, executed_functions=executed_functions, parent_log_id=parent_log_id, **kwargs)\n        return wrapper\n\n    def execute(\n        self,\n        function_name: str,\n        *args,\n        executed_functions: Optional[List[str]] = None,\n        parent_log_id: Optional[int] = None,\n        wrapper_log_id: Optional[int] = None,\n        triggered_by_log_id: Optional[int] = None,\n        **kwargs\n    ) -> Any:\n        start_time = datetime.now()\n        executed_functions = executed_functions or []\n        log_id = None\n        bound_args = None\n        output = None\n\n        # Ensure wrapper_log_id is initialized\n        wrapper_log_id = wrapper_log_id if wrapper_log_id is not None else None\n\n        logger.info(f\"Executing function: {function_name}\")\n\n        try:\n            executed_functions.append(function_name)\n            function_version = self.python_func.db.get_function(function_name)\n            if not function_version:\n                raise ValueError(f\"Function '{function_name}' not found in the database.\")\n\n            # If the function being executed is the wrapper, create a special log entry and set wrapper_log_id\n            if function_name == 'execute_function_wrapper':\n                log_id = self._add_execution_log(\n                    function_name,\n                    start_time,\n                    {},\n                    None,\n                    0,\n                    parent_log_id,\n                    triggered_by_log_id,\n                    'started'\n                )\n                wrapper_log_id = log_id\n            else:\n                log_id = self._add_execution_log(\n                    function_name,\n                    start_time,\n                    {},\n                    None,\n                    0,\n                    wrapper_log_id if wrapper_log_id else parent_log_id,\n                    triggered_by_log_id,\n                    'started'\n                )\n\n            # Include 'datetime' in local_scope\n            local_scope = {\n                'func': self.python_func,\n                'parent_log_id': log_id,\n                'datetime': datetime  # Added datetime here\n            }\n\n            self._resolve_dependencies(\n                function_version,\n                local_scope,\n                parent_log_id=log_id,\n                executed_functions=executed_functions\n            )\n            self._inject_secret_keys(local_scope)\n\n            exec(function_version['code'], local_scope)\n            if function_name not in local_scope:\n                raise ValueError(f\"Failed to load function '{function_name}'.\")\n\n            func = local_scope[function_name]\n            bound_args = self._bind_function_arguments(func, args, kwargs)\n            self._validate_input_parameters(function_version, bound_args)\n\n            params = bound_args.arguments\n            self._update_execution_log_params(log_id, params)\n\n            output = func(*bound_args.args, **bound_args.kwargs)\n            end_time = datetime.now()\n            time_spent = (end_time - start_time).total_seconds()\n\n            self._update_execution_log(log_id, output, time_spent, 'success')\n\n            # Check and execute triggers for the function\n            self._execute_triggered_functions(function_name, output, executed_functions, log_id)\n            return output\n\n        except Exception as e:\n            end_time = datetime.now()\n            time_spent = (end_time - start_time).total_seconds()\n            if log_id is not None:\n                self._update_execution_log(log_id, None, time_spent, 'error', str(e))\n            raise\n\n    \n\n    def _check_key_dependencies(self, function_version: Dict[str, Any]) -> None:\n        if 'key_dependencies' in function_version.get('metadata', {}):\n            for key_name in function_version['metadata']['key_dependencies']:\n                if key_name not in self.python_func.db.get_all_secret_keys():\n                    raise ValueError(f\"Required secret key '{key_name}' not found for function '{function_version['name']}'\")\n\n    def _inject_secret_keys(self, local_scope: Dict[str, Any]) -> None:\n        secret_keys = self.python_func.db.get_all_secret_keys()\n        if secret_keys:\n            logger.debug(f\"Injecting secret keys: {list(secret_keys.keys())}\")\n            local_scope.update(secret_keys)\n\n    def _bind_function_arguments(self, func: callable, args: tuple, kwargs: dict) -> inspect.BoundArguments:\n        sig = inspect.signature(func)\n        bound_args = sig.bind(*args, **kwargs)\n        bound_args.apply_defaults()\n        return bound_args\n\n    def _validate_input_parameters(self, function_version: Dict[str, Any], bound_args: inspect.BoundArguments) -> None:\n        input_params = function_version.get('input_parameters', [])\n        for param in input_params:\n            if param['name'] not in bound_args.arguments:\n                raise ValueError(f\"Missing required input parameter '{param['name']}' for function '{function_version['name']}'\")\n\n    def _add_execution_log(self, function_name: str, start_time: datetime, params: Dict[str, Any],\n                           output: Any, time_spent: float, parent_log_id: Optional[int],\n                           triggered_by_log_id: Optional[int], log_type: str, error_message: Optional[str] = None) -> int:\n        if log_type == 'started':\n            message = \"Execution started.\"\n        elif log_type == 'success':\n            message = \"Execution successful.\"\n        else:\n            message = f\"Execution failed. Error: {error_message}\"\n        return self.python_func.db.add_log(\n            function_name=function_name,\n            message=message,\n            timestamp=start_time,\n            params=params,\n            output=output,\n            time_spent=time_spent,\n            parent_log_id=parent_log_id,\n            triggered_by_log_id=triggered_by_log_id,\n            log_type=log_type\n        )\n\n    def _update_execution_log(self, log_id: int, output: Any, time_spent: float, log_type: str,\n          error_message: Optional[str] = None):\n        message = \"Execution successful.\" if log_type == 'success' else f\"Execution failed. Error: {error_message}\"\n        update_data = {\n            'message': message,\n            'log_type': log_type\n        }\n        if output is not None:\n            update_data['output'] = output\n        if time_spent is not None:\n            update_data['time_spent'] = time_spent\n\n            self.python_func.db.update_log(log_id=log_id, **update_data)\n\n\n    def _update_execution_log_params(self, log_id: int, params: Dict[str, Any]) -> None:\n        self.python_func.db.update_log(log_id=log_id, params=params)\n\n\n    \n    def _execute_triggered_functions(self, function_name: str, output: Any, executed_functions: List[str], log_id: int) -> None:\n        triggered_function_names = self.python_func.db.get_triggers_for_function(function_name)\n        logger.info(f\"Functions triggered by {function_name}: {triggered_function_names}\")\n\n        for triggered_function_name in triggered_function_names:\n            if triggered_function_name in executed_functions:\n                logger.warning(f\"Triggered function '{triggered_function_name}' already executed in this chain. Skipping to prevent recursion.\")\n                continue\n\n            try:\n                logger.info(f\"Preparing to execute trigger: {triggered_function_name}\")\n                triggered_function = self.python_func.db.get_function(triggered_function_name)\n                if triggered_function:\n                    trigger_args, trigger_kwargs = self._prepare_trigger_arguments(triggered_function, output)\n                    logger.info(f\"Executing trigger {triggered_function_name} with args: {trigger_args} and kwargs: {trigger_kwargs}\")\n\n                    trigger_output = self.execute(\n                        triggered_function_name,\n                        *trigger_args,\n                        executed_functions=executed_functions.copy(),\n                        parent_log_id=log_id,\n                        triggered_by_log_id=log_id,\n                        **trigger_kwargs\n                    )\n                    logger.info(f\"Trigger {triggered_function_name} execution completed. Output: {trigger_output}\")\n                else:\n                    logger.error(f\"Triggered function '{triggered_function_name}' not found in the database.\")\n            except Exception as e:\n                logger.error(f\"Error executing triggered function '{triggered_function_name}': {str(e)}\")\n\n    def _prepare_trigger_arguments(self, triggered_function: Dict[str, Any], output: Any) -> tuple:\n        triggered_params = triggered_function.get('input_parameters', [])\n        if triggered_params:\n            # If the triggered function expects parameters, pass the output as the first parameter\n            return (output,), {}\n        else:\n            # If the triggered function doesn't expect parameters, don't pass any\n            return (), {}\n"
  },
  {
    "path": "babyagi/functionz/core/framework.py",
    "content": "# core/framework.py\n\nimport os\nimport sys\nimport importlib.util\nfrom typing import Optional, List, Dict, Any\nfrom datetime import datetime\nimport logging\n\nfrom ..db.db_router import DBRouter\nfrom .execution import FunctionExecutor\nfrom .registration import FunctionRegistrar\n\nlogger = logging.getLogger(__name__)\n\nclass Functionz:\n    def __init__(self, db_type='local', **db_kwargs):\n        self.db = DBRouter(db_type, **db_kwargs)\n        self.executor = FunctionExecutor(self)\n        self.registrar = FunctionRegistrar(self)\n\n    # Function execution\n    def execute_function(self, function_name: str, *args, **kwargs):\n        return self.executor.execute(function_name, *args, **kwargs)\n\n    def __getattr__(self, name):\n        if self.db.get_function(name):\n            return lambda *args, **kwargs: self.executor.execute(name, *args, **kwargs)\n        raise AttributeError(f\"'PythonFunc' object has no attribute '{name}'\")\n\n    # Function management\n    def get_function(self, name: str):\n        return self.db.get_function(name)\n\n    def get_function_versions(self, name: str):\n        return self.db.get_function_versions(name)\n\n    def get_all_functions(self) -> List[Dict[str, Any]]:\n        return self.db.get_all_functions()\n\n    def activate_function_version(self, name: str, version: int) -> None:\n        self.db.activate_function_version(name, version)\n\n    def get_function_imports(self, name: str):\n        return self.db.get_function_imports(name)\n\n    # Function registration (exposing registrar methods)\n    def register_function(self, *args, **kwargs):\n        return self.registrar.register_function(*args, **kwargs)\n\n    def update_function(self, *args, **kwargs):\n        return self.registrar.update_function(*args, **kwargs)\n\n    def add_function(self, *args, **kwargs):\n        return self.registrar.add_function(*args, **kwargs)\n\n    # Key management\n    def add_key(self, key_name: str, key_value: str) -> None:\n        self.db.add_secret_key(key_name, key_value)\n\n    def get_all_secret_keys(self, *args, **kwargs):\n        return self.db.get_all_secret_keys(*args, **kwargs)\n\n    # Import management\n    def get_all_imports(self, *args, **kwargs):\n        return self.db.get_all_imports(*args, **kwargs)\n\n    # Function pack and file loading\n    def load_function_pack(self, pack_name: str):\n        packs_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'packs')\n        pack_path = os.path.join(packs_dir, pack_name + '.py')\n\n        if not os.path.exists(pack_path):\n            logger.error(f\"Function pack '{pack_name}' not found.\")\n            return\n\n        self._load_module_from_path(pack_path, pack_name)\n\n    def load_functions_from_file(self, file_path: str):\n        if not os.path.exists(file_path):\n            logger.error(f\"File '{file_path}' not found.\")\n            return\n\n        module_name = os.path.splitext(os.path.basename(file_path))[0]\n        self._load_module_from_path(file_path, module_name)\n\n    def _load_module_from_path(self, path: str, module_name: str):\n        spec = importlib.util.spec_from_file_location(module_name, path)\n        module = importlib.util.module_from_spec(spec)\n        module.func = self\n\n        original_sys_path = sys.path[:]\n        try:\n            babyagi_root = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))\n            if babyagi_root not in sys.path:\n                sys.path.insert(0, babyagi_root)\n\n            spec.loader.exec_module(module)\n            logger.info(f\"Loaded module '{module_name}' from '{path}'\")\n        except Exception as e:\n            logger.error(f\"Error loading module '{module_name}' from '{path}': {str(e)}\")\n            import traceback\n            logger.error(traceback.format_exc())\n        finally:\n            sys.path = original_sys_path\n\n    # Trigger management\n    def add_trigger(self, triggered_function_name, triggering_function_name=None):\n        self.db.add_trigger(triggered_function_name, triggering_function_name)\n\n    def get_triggers_for_function(self, function_name: str) -> List[str]:\n        function_data = self.get_function(function_name)\n        return function_data.get('triggers', []) if function_data else []\n\n    # Logging and display\n    def get_logs(self, function_name: Optional[str] = None,\n                 start_date: Optional[datetime] = None,\n                 end_date: Optional[datetime] = None) -> List[Dict[str, Any]]:\n        return self.db.get_logs(function_name, start_date, end_date)\n\n    def display(self):\n        functions = self.db.get_all_functions()\n        result = []\n\n        for function in functions:\n            function_info = [\n                f\"Function: {function['name']}\",\n                f\"  Version: {function['version']}\",\n                f\"  Created Date: {function['created_date']}\",\n                f\"  Metadata: {function['metadata']}\",\n                f\"  Dependencies: {function['dependencies']}\",\n                f\"  Triggers: {function.get('triggers', [])}\",\n                \"  Input Parameters:\",\n            ]\n            for param in function['input_parameters']:\n                function_info.append(f\"    - {param['name']} ({param['type']})\")\n\n            function_info.append(\"  Output Parameters:\")\n            for param in function['output_parameters']:\n                function_info.append(f\"    - {param['name']} ({param['type']})\")\n\n            function_info.append(f\"  Code:\\n{function['code']}\")\n            function_info.append(\"---\")\n\n            result.append(\"\\n\".join(function_info))\n\n        return \"\\n\\n\".join(result)\n\n# Create the global 'func' instance\nfunc = Functionz()"
  },
  {
    "path": "babyagi/functionz/core/registration.py",
    "content": "# core/registration.py\n\nfrom .execution import FunctionExecutor\nimport inspect\nimport ast\nfrom typing import Optional, List, Dict, Any, Union\nimport logging\nimport json\n\nlogger = logging.getLogger(__name__)\n\nclass FunctionRegistrar:\n    def __init__(self, python_func):\n        self.python_func = python_func\n\n    def register_function(self, metadata: Optional[Dict[str, Any]] = None,\n                          imports: Optional[List[str]] = None,\n                          dependencies: Optional[List[str]] = None,\n                          triggers: Optional[List[str]] = None,\n                          key_dependencies: Optional[List[str]] = None):\n        \"\"\"Decorator to register a function.\"\"\"\n        def decorator(func):\n            function_name = func.__name__\n            source_lines = inspect.getsourcelines(func)[0]\n            func_start = next(i for i, line in enumerate(source_lines) if line.strip().startswith('def '))\n            function_code = ''.join(source_lines[func_start:]).strip()\n\n            # Store metadata on the function object\n            func.__pythonfunc_metadata__ = {\n                'metadata': metadata or {},\n                'imports': imports or [],\n                'dependencies': dependencies or [],\n                'triggers': triggers or [], \n                'key_dependencies': key_dependencies or []\n            }\n\n            self.add_function(function_name, metadata=metadata, code=function_code,\n                              imports=imports, dependencies=dependencies, \n                              key_dependencies=key_dependencies, triggers=triggers)\n            def wrapper(*args, **kwargs):\n                return self.python_func.executor.execute(function_name, *args, **kwargs)\n            return wrapper\n        return decorator\n\n    def parse_function_parameters(self, code: str):\n        \"\"\"\n        Parse the input and output parameters of a given function code.\n        \"\"\"\n        try:\n            # Parse the source code into an AST\n            tree = ast.parse(code)\n\n            # Find the function definition node\n            function_def = next(node for node in ast.walk(tree) if isinstance(node, ast.FunctionDef))\n\n            # Parse input parameters\n            input_params = []\n            for arg in function_def.args.args:\n                param_type = 'Any'\n                if arg.annotation:\n                    param_type = ast.unparse(arg.annotation)\n                input_params.append({'name': arg.arg, 'type': param_type})\n\n            # Parse return statement to identify output parameters\n            output_params = []\n            returns = [node for node in ast.walk(function_def) if isinstance(node, ast.Return)]\n            if returns:\n                return_node = returns[0].value\n                if isinstance(return_node, ast.Dict):\n                    # If returning a dictionary, treat each key as an output parameter\n                    for key in return_node.keys:\n                        if isinstance(key, ast.Str):\n                            output_params.append({'name': key.s, 'type': 'Any'})\n                elif isinstance(return_node, (ast.Name, ast.Attribute)):\n                    # If returning a single variable\n                    output_params.append({'name': 'output', 'type': 'Any'})\n                elif isinstance(return_node, ast.Str):\n                    # If returning a string literal\n                    output_params.append({'name': 'output', 'type': 'str'})\n                else:\n                    # For other types of returns, use a generic 'output' parameter\n                    output_params.append({'name': 'output', 'type': 'Any'})\n\n            return input_params, output_params\n        except Exception as e:\n            # print(f\"Error parsing function parameters: {str(e)}\")\n            return [], []\n\n    def parse_import(self, imp):\n        try:\n            #print(\"Attempt to parse the string as JSON\")\n            #print(imp.type())\n            parsed = json.loads(imp)\n            #print(\"Parsed string as JSON\")\n            return parsed\n        except json.JSONDecodeError:\n            print(\"Failed to parse the string as JSON\")\n            # If it fails, return the original string (it's a simple import)\n            return imp\n\n    # Register imports helper function\n    def register_imports(self, imports):\n        print(f\"Registering imports: {imports}\")\n        if isinstance(imports, list):\n            for imp in imports:\n                self.process_single_import(imp)\n        elif isinstance(imports, dict):\n            self.process_single_import(imports)\n\n    def process_single_import(self, imp):\n        if isinstance(imp, str):\n            self.python_func.db.add_import(imp, 'external', lib=None)\n        elif isinstance(imp, dict):\n            name = imp.get('name')\n            lib = imp.get('lib')\n            if name:\n                self.python_func.db.add_import(name, 'external', lib=lib)\n        else:\n            print(f\"Unsupported import format: {imp}\")\n\n    def process_imports(self, imports):\n        import_names = []\n        if imports:\n            if isinstance(imports, list):\n                for imp in imports:\n                    if isinstance(imp, str):\n                        import_names.append(imp)\n                    elif isinstance(imp, dict):\n                        import_name = imp.get('name')\n                        if import_name:\n                            import_names.append(import_name)\n            elif isinstance(imports, dict):\n                import_name = imports.get('name')\n                if import_name:\n                    import_names.append(import_name)\n        return import_names\n\n    def function_has_no_changes(self, name, code, metadata, import_names, dependencies, triggers):\n        existing_function = self.python_func.db.get_function(name)\n        if not existing_function:\n            return False  # Function does not exist, so changes are needed\n\n        existing_code = existing_function.get('code')\n        existing_metadata = existing_function.get('metadata', {})\n        existing_description = existing_metadata.get('description')\n        existing_imports = existing_function.get('imports') or []\n        existing_dependencies = existing_function.get('dependencies') or []\n        existing_triggers = existing_function.get('triggers') or []\n\n        new_description = metadata.get('description') if metadata else None\n\n        if (existing_code == code and\n            existing_description == new_description and\n            set(existing_imports) == set(import_names) and\n            set(existing_dependencies) == set(dependencies) and\n            set(existing_triggers) == set(triggers)):\n            return True  # No changes\n        else:\n            return False  # Changes detected\n\n    def add_function(self, name: str, metadata: Optional[Dict[str, Any]] = None,\n                    code: Optional[str] = None, imports: Optional[List[Union[str, Dict[str, str]]]] = None,\n                    dependencies: Optional[List[str]] = None, triggers: Optional[List[str]] = None,\n                    key_dependencies: Optional[List[str]] = None,\n                    input_parameters: Optional[List[Dict[str, str]]] = None,\n                    output_parameters: Optional[List[Dict[str, str]]] = None) -> None:\n\n        if code:\n            # Parse input and output parameters if not provided\n            if input_parameters is None or output_parameters is None:\n                parsed_input, parsed_output = self.parse_function_parameters(code)\n                input_parameters = input_parameters or parsed_input\n                output_parameters = output_parameters or parsed_output\n\n        # Process imports\n        import_names = self.process_imports(imports)\n\n        # Ensure lists are not None\n        dependencies = dependencies or []\n        triggers = triggers or []\n\n        # Check for changes\n        if self.function_has_no_changes(name, code, metadata, import_names, dependencies, triggers):\n            #print(f\"Function {name} has no changes.\")\n            return\n\n        # Register imports\n        if imports:\n            self.register_imports(imports)\n\n        # Add or update the function in the database\n        existing_function = self.python_func.db.get_function(name)\n        if existing_function:\n            # Function exists, update it\n            self.python_func.db.update_function(\n                name, code=code, metadata=metadata, dependencies=dependencies,\n                input_parameters=input_parameters, output_parameters=output_parameters,\n                imports=import_names, triggers=triggers\n            )\n        else:\n            # Function does not exist, add it\n            self.python_func.db.add_function(\n                name, code=code, metadata=metadata, dependencies=dependencies,\n                input_parameters=input_parameters, output_parameters=output_parameters,\n                imports=import_names, triggers=triggers\n            )\n\n        if key_dependencies:\n            print(f\"Function {name} requires keys: {key_dependencies}\")\n            metadata = metadata or {}\n            metadata['key_dependencies'] = key_dependencies\n\n        if self.python_func.db.get_function('function_added_or_updated'):\n            try:\n                action = 'updated' if existing_function else 'added'\n                self.python_func.executor.execute(function_name='function_added_or_updated', action=action, triggered_function_name=name)\n            except Exception as e:\n                logger.error(f\"Error executing trigger function 'function_added_or_updated': {str(e)}\")\n\n    def update_function(self, name: str, code: Optional[str] = None, imports: Optional[List[Union[str, Dict[str, str]]]] = None,\n                        metadata: Optional[Dict[str, Any]] = None,\n                        dependencies: Optional[List[str]] = None,\n                        triggers: Optional[List[str]] = None,\n                        key_dependencies: Optional[List[str]] = None,\n                        input_parameters: Optional[List[Dict[str, str]]] = None,\n                        output_parameters: Optional[List[Dict[str, str]]] = None) -> None:\n\n        if code:\n            # Parse input and output parameters if not provided\n            if input_parameters is None or output_parameters is None:\n                parsed_input, parsed_output = self.parse_function_parameters(code)\n                input_parameters = input_parameters or parsed_input\n                output_parameters = output_parameters or parsed_output\n\n        # Process imports\n        import_names = self.process_imports(imports)\n\n        # Ensure lists are not None\n        dependencies = dependencies or []\n        triggers = triggers or []\n\n        # Check for changes\n        if self.function_has_no_changes(name, code, metadata, import_names, dependencies, triggers):\n            # print(f\"Function {name} has no changes.\")\n            return\n\n        # Update the function in the database\n        self.python_func.db.update_function(\n            name, code=code, metadata=metadata, dependencies=dependencies,\n            input_parameters=input_parameters, output_parameters=output_parameters,\n            imports=import_names, triggers=triggers\n        )\n\n        if key_dependencies:\n            metadata = metadata or {}\n            metadata['key_dependencies'] = key_dependencies\n\n        # Register imports\n        if imports:\n            self.register_imports(imports)\n\n        if self.python_func.db.get_function('function_added_or_updated'):\n            try:\n                self.python_func.executor.execute(function_name='function_added_or_updated', action='updated', triggered_function_name=name)\n            except Exception as e:\n                logger.error(f\"Error executing trigger function 'function_added_or_updated': {str(e)}\")\n"
  },
  {
    "path": "babyagi/functionz/db/__init__.py",
    "content": ""
  },
  {
    "path": "babyagi/functionz/db/base_db.py",
    "content": "from abc import ABC, abstractmethod\nfrom typing import Optional, List, Dict, Any\nfrom datetime import datetime\n\nclass BaseDB(ABC):\n    # Function management\n    @abstractmethod\n    def add_function(self, name: str, code: str, metadata: Optional[Dict[str, Any]] = None,\n                     dependencies: Optional[List[str]] = None,\n                     input_parameters: Optional[List[Dict[str, Any]]] = None,\n                     output_parameters: Optional[List[Dict[str, Any]]] = None) -> None:\n        pass\n\n    @abstractmethod\n    def get_function(self, name: str) -> Optional[Dict[str, Any]]:\n        pass\n\n    @abstractmethod\n    def get_all_functions(self) -> List[Dict[str, Any]]:\n        pass\n\n    @abstractmethod\n    def update_function(self, name: str, code: Optional[str] = None,\n                        metadata: Optional[Dict[str, Any]] = None,\n                        dependencies: Optional[List[str]] = None,\n                        input_parameters: Optional[List[Dict[str, Any]]] = None,\n                        output_parameters: Optional[List[Dict[str, Any]]] = None) -> None:\n        pass\n\n    @abstractmethod\n    def remove_function(self, name: str) -> None:\n        pass\n\n    @abstractmethod\n    def get_function_versions(self, name: str) -> List[Dict[str, Any]]:\n        pass\n\n    @abstractmethod\n    def activate_function_version(self, name: str, version: int) -> None:\n        pass\n\n    # Import management\n    @abstractmethod\n    def add_import(self, name: str, source: str, lib: Optional[str] = None) -> None:\n        pass\n\n    @abstractmethod\n    def get_all_imports(self) -> List[Dict[str, Any]]:\n        pass\n\n    # Logging\n    @abstractmethod\n    def add_log(self, function_name: str, message: str, timestamp: datetime,\n                params: Optional[Dict[str, Any]] = None,\n                output: Optional[Any] = None,\n                time_spent: Optional[float] = None) -> None:\n        pass\n\n    @abstractmethod\n    def get_logs(self, function_name: Optional[str] = None,\n                 start_date: Optional[datetime] = None,\n                 end_date: Optional[datetime] = None) -> List[Dict[str, Any]]:\n        pass"
  },
  {
    "path": "babyagi/functionz/db/db_router.py",
    "content": "from typing import List, Optional, Dict, Any\nfrom contextlib import contextmanager\nfrom datetime import datetime\n\nfrom .local_db import LocalDB\nfrom .base_db import BaseDB\nfrom .models import Import, Function, FunctionVersion, Log\n\nclass ImportResult:\n    def __init__(self, name: str, source: str):\n        self.name = name\n        self.source = source\n\nclass DBRouter(BaseDB):\n    def __init__(self, db_type: str = 'local', **kwargs):\n        if db_type == 'local':\n            self.db = LocalDB(**kwargs)\n        else:\n            raise ValueError(f\"Unsupported database type: {db_type}\")\n\n    @contextmanager\n    def session_scope(self):\n        with self.db.session_scope() as session:\n            yield session\n\n    # Function management\n    def add_function(self, name: str, code: str, metadata: Optional[Dict[str, Any]] = None, \n                     dependencies: Optional[List[str]] = None, \n                     triggers: Optional[List[str]] = None,\n                     input_parameters: Optional[List[Dict[str, str]]] = None,\n                     output_parameters: Optional[List[Dict[str, str]]] = None,\n                     imports: Optional[List[str]] = None) -> None:\n        with self.session_scope() as session:\n            self.db.add_or_update_function(session, name, code, metadata, dependencies, triggers, input_parameters, output_parameters, imports)\n\n    def update_function(self, name: str, code: Optional[str] = None, \n                        metadata: Optional[Dict[str, Any]] = None, \n                        dependencies: Optional[List[str]] = None,\n                        triggers: Optional[List[str]] = None,\n                        input_parameters: Optional[List[Dict[str, str]]] = None,\n                        output_parameters: Optional[List[Dict[str, str]]] = None,\n                        imports: Optional[List[str]] = None) -> None:\n        with self.session_scope() as session:\n            function = self.db.get_function(session, name)\n            if function:\n                active_version = self.db.get_active_version(session, function)\n                self.db.add_or_update_function(\n                    session, name, \n                    code if code is not None else active_version.code,\n                    metadata or active_version.function_metadata,\n                    dependencies, \n                    triggers if triggers is not None else active_version.triggers,\n                    input_parameters or active_version.input_parameters,\n                    output_parameters or active_version.output_parameters,\n                    imports\n                )\n\n    def get_function(self, name: str) -> Optional[Dict[str, Any]]:\n        with self.session_scope() as session:\n            function = self.db.get_function(session, name)\n            if function:\n                active_version = self.db.get_active_version(session, function)\n                if active_version:\n                    return {\n                        'name': function.name,\n                        'version': active_version.version,\n                        'code': active_version.code,\n                        'metadata': active_version.function_metadata,\n                        'dependencies': [dep.name for dep in active_version.dependencies],\n                        'imports': [imp.name for imp in active_version.imports],\n                        'created_date': active_version.created_date.isoformat(),\n                        'input_parameters': active_version.input_parameters,\n                        'output_parameters': active_version.output_parameters,\n                        'triggers': active_version.triggers\n                    }\n            return None\n\n    def get_all_functions(self) -> List[Dict[str, Any]]:\n        with self.session_scope() as session:\n            functions = self.db.get_all_functions(session)\n            return [\n                {\n                    'name': function.name,\n                    'version': active_version.version,\n                    'code': active_version.code,\n                    'metadata': active_version.function_metadata,\n                    'dependencies': [dep.name for dep in active_version.dependencies],\n                    'imports': [imp.name for imp in active_version.imports],\n                    'created_date': active_version.created_date.isoformat(),\n                    'input_parameters': active_version.input_parameters,\n                    'output_parameters': active_version.output_parameters,\n                    'triggers': active_version.triggers\n                }\n                for function in functions\n                if (active_version := next((v for v in function.versions if v.is_active), None))\n            ]\n\n    def remove_function(self, name: str) -> None:\n        with self.session_scope() as session:\n            function = self.db.get_function(session, name)\n            if function:\n                session.delete(function)\n\n    def get_function_versions(self, name: str) -> List[Dict[str, Any]]:\n        with self.session_scope() as session:\n            function = self.db.get_function(session, name)\n            if function:\n                return [\n                    {\n                        'version': v.version,\n                        'code': v.code,\n                        'metadata': v.function_metadata,\n                        'is_active': v.is_active,\n                        'dependencies': [dep.name for dep in v.dependencies],\n                        'created_date': v.created_date.isoformat(),\n                        'input_parameters': v.input_parameters,\n                        'output_parameters': v.output_parameters,\n                        'triggers': v.triggers\n                    }\n                    for v in function.versions\n                ]\n            return []\n\n    def activate_function_version(self, name: str, version: int) -> None:\n        with self.session_scope() as session:\n            function = self.db.get_function(session, name)\n            if function:\n                for v in function.versions:\n                    v.is_active = (v.version == version)\n\n    # Import management\n    def add_import(self, name: str, source: str, lib: Optional[str] = None) -> None:\n        with self.session_scope() as session:\n            self.db.add_import(session, name, source, lib)\n\n    def get_all_imports(self) -> List[Dict[str, Any]]:\n        with self.session_scope() as session:\n            imports = session.query(Import).all()\n            return [{\"name\": imp.name, \"source\": imp.source, \"lib\": imp.lib} for imp in imports]\n\n    def get_function_imports(self, function_name: str) -> List[Dict[str, Any]]:\n        with self.session_scope() as session:\n            function = session.query(Function).filter_by(name=function_name).first()\n            if function:\n                imports = (session.query(Import)\n                           .join(FunctionVersion.imports)\n                           .filter(FunctionVersion.function_id == function.id)\n                           .all())\n                return [{\"name\": imp.name, \"source\": imp.source, \"lib\": imp.lib} for imp in imports]\n            return []\n\n    # Logging\n    def add_log(self, function_name: str, message: str, timestamp: datetime, \n                params: Optional[Dict[str, Any]] = None, \n                output: Optional[Any] = None, \n                time_spent: Optional[float] = None, \n                parent_log_id: Optional[int] = None, \n                triggered_by_log_id: Optional[int] = None, \n                log_type: str = 'info') -> int:\n        with self.session_scope() as session:\n            return self.db.add_log(\n                session=session,\n                function_name=function_name,\n                message=message,\n                timestamp=timestamp,\n                params=params,\n                output=output,\n                time_spent=time_spent,\n                parent_log_id=parent_log_id,\n                triggered_by_log_id=triggered_by_log_id,\n                log_type=log_type\n            )\n\n    def update_log(self, log_id: int, **kwargs) -> None:\n        with self.session_scope() as session:\n            self.db.update_log(\n                session=session,\n                log_id=log_id,\n                **kwargs\n            )\n\n\n    def update_log_params(self, log_id: int, params: Dict[str, Any]) -> None:\n        with self.session_scope() as session:\n            self.db.update_log_params(\n                session=session,\n                log_id=log_id,\n                params=params\n            )\n\n\n\n    def get_logs(self, function_name: Optional[str] = None, \n                 start_date: Optional[datetime] = None, \n                 end_date: Optional[datetime] = None, \n                 triggered_by_log_id: Optional[int] = None) -> List[Dict[str, Any]]:\n        with self.session_scope() as session:\n            logs = self.db.get_logs(session, function_name, start_date, end_date, triggered_by_log_id)\n            return [\n                {\n                    'id': log.id,\n                    'function_name': log.function_name,\n                    'message': log.message,\n                    'timestamp': log.timestamp.isoformat(),\n                    'params': log.params,\n                    'output': log.output,\n                    'time_spent': log.time_spent,\n                    'parent_log_id': log.parent_log_id,\n                    'triggered_by_log_id': log.triggered_by_log_id,\n                    'log_type': log.log_type\n                }\n                for log in logs\n            ]\n\n    def get_log_bundle(self, log_id: int) -> List[Dict[str, Any]]:\n        with self.session_scope() as session:\n            logs_collected = {}\n\n            def fetch_related_logs(current_log_id):\n                if current_log_id in logs_collected:\n                    return\n                log = self.db.get_log(session, current_log_id)\n                if log:\n                    logs_collected[current_log_id] = log\n                else:\n                    logger.warning(f\"Log ID {current_log_id} not found.\")\n                    return\n\n                # Fetch parent log\n                if log.parent_log_id:\n                    fetch_related_logs(log.parent_log_id)\n\n                    # Fetch sibling logs\n                    sibling_logs = session.query(Log).filter(\n                        Log.parent_log_id == log.parent_log_id,\n                        Log.id != current_log_id\n                    ).all()\n                    for sibling in sibling_logs:\n                        fetch_related_logs(sibling.id)\n\n                # Fetch child logs\n                child_logs = self.db.get_child_logs(session, current_log_id)\n                for child in child_logs:\n                    fetch_related_logs(child.id)\n\n            fetch_related_logs(log_id)\n\n            # Convert logs to dictionaries\n            all_logs = [\n                {\n                    'id': log.id,\n                    'function_name': log.function_name,\n                    'message': log.message,\n                    'timestamp': log.timestamp.isoformat(),\n                    'params': log.params,\n                    'output': log.output,\n                    'time_spent': log.time_spent,\n                    'parent_log_id': log.parent_log_id,\n                    'triggered_by_log_id': log.triggered_by_log_id,\n                    'log_type': log.log_type\n                }\n                for log in logs_collected.values()\n            ]\n\n            return all_logs\n\n\n    \n    # Secret key management\n    def add_secret_key(self, key_name: str, key_value: str) -> None:\n        with self.session_scope() as session:\n            existing_key = self.db.get_secret_key(session, key_name)\n            if existing_key:\n                existing_key.value = key_value\n            else:\n                self.db.add_secret_key(session, key_name, key_value)\n\n    def get_secret_key(self, key_name: str) -> Optional[str]:\n        with self.session_scope() as session:\n            secret_key = self.db.get_secret_key(session, key_name)\n            return secret_key.value if secret_key else None\n\n    def get_all_secret_keys(self) -> Dict[str, str]:\n        with self.session_scope() as session:\n            secret_keys = self.db.get_all_secret_keys(session)\n            return {key.name: key.value for key in secret_keys if key.value is not None}\n\n    # Trigger management\n    def add_trigger(self, triggered_function_name: str, triggering_function_name: Optional[str] = None) -> None:\n        with self.session_scope() as session:\n            self.db.add_trigger(session, triggered_function_name, triggering_function_name)\n\n    def get_triggers_for_function(self, function_name: str) -> List[str]:\n        with self.session_scope() as session:\n            all_functions = self.db.get_all_functions(session)\n            triggered_functions = []\n            for func in all_functions:\n                active_version = self.db.get_active_version(session, func)\n                if active_version and active_version.triggers:\n                    if function_name in active_version.triggers:\n                        triggered_functions.append(func.name)\n            return triggered_functions"
  },
  {
    "path": "babyagi/functionz/db/local_db.py",
    "content": "# local_db.py\n\nfrom sqlalchemy import create_engine, or_\nfrom sqlalchemy.orm import sessionmaker, scoped_session, joinedload\nfrom sqlalchemy.exc import SQLAlchemyError\nfrom contextlib import contextmanager\nfrom .models import Base, Function, FunctionVersion, Import, Log, SecretKey, fernet\nimport datetime\n\n\n\nclass LocalDB:\n    def __init__(self, db_path='sqlite:///funztionz.db'):\n        self.engine = create_engine(db_path)\n        Base.metadata.create_all(self.engine)\n        self.Session = scoped_session(sessionmaker(bind=self.engine))\n\n    @contextmanager\n    def session_scope(self):\n        session = self.Session()\n        try:\n            yield session\n            session.commit()\n        except SQLAlchemyError as e:\n            session.rollback()\n            raise e\n        finally:\n            self.Session.remove()\n\n    def serialize_for_json(self, obj):\n        \"\"\"\n        Recursively convert datetime objects to ISO format strings within the given object.\n        Handles dictionaries, lists, and individual datetime objects.\n        \"\"\"\n        if isinstance(obj, dict):\n            return {k: self.serialize_for_json(v) for k, v in obj.items()}\n        elif isinstance(obj, list):\n            return [self.serialize_for_json(element) for element in obj]\n        elif isinstance(obj, datetime.datetime):\n            return obj.isoformat()\n        else:\n            return obj\n\n\n    def get_function(self, session, name):\n        return session.query(Function).filter_by(name=name).first()\n\n    def get_active_version(self, session, function):\n        return session.query(FunctionVersion).filter_by(function_id=function.id, is_active=True).options(\n            joinedload(FunctionVersion.dependencies)\n        ).first()\n\n    def get_all_functions(self, session):\n        return session.query(Function).options(\n            joinedload(Function.versions).joinedload(FunctionVersion.dependencies)\n        ).all()\n\n    def add_or_update_function(self, session, name, code, metadata, dependencies, triggers, input_parameters, output_parameters, imports=None):\n        function = self.get_function(session, name)\n        if not function:\n            function = Function(name=name)\n            session.add(function)\n            session.flush()\n\n        # Handle imports before creating the FunctionVersion\n        import_objects = []\n        if imports:\n            for import_name in imports:\n                imp = session.query(Import).filter_by(name=import_name).first()\n                if not imp:\n                    imp = Import(name=import_name, source='external')\n                    session.add(imp)\n                    session.flush()\n                import_objects.append(imp)\n\n        # Create the FunctionVersion instance, now including triggers as JSON\n        version = FunctionVersion(\n            function=function,\n            version=len(function.versions) + 1,\n            code=code,\n            function_metadata=metadata or {},\n            is_active=True,\n            input_parameters=input_parameters or [],\n            output_parameters=output_parameters or [],\n            imports=import_objects,  # Pass the list of Import objects here\n            triggers=triggers or []  # Store the triggers as JSON\n        )\n        session.add(version)\n\n        # Handle dependencies\n        if dependencies:\n            for dep in dependencies:\n                dep_func = self.get_function(session, dep)\n                if dep_func:\n                    version.dependencies.append(dep_func)\n\n        # Deactivate previous versions\n        for v in function.versions:\n            if v != version:\n                v.is_active = False\n\n\n    def add_import(self, session, name, source, lib=None):\n        existing_import = session.query(Import).filter_by(name=name).first()\n        if not existing_import:\n            new_import = Import(name=name, source=source, lib=lib)\n            session.add(new_import)\n\n\n\n    def add_log(self, session, function_name, message, timestamp, params, output, time_spent, parent_log_id=None, triggered_by_log_id=None, log_type='info'):\n        if isinstance(timestamp, str):\n            # Convert the string timestamp back to a datetime object\n            timestamp = datetime.datetime.fromisoformat(timestamp)\n\n        # Serialize params and output to ensure JSON serializability\n        serialized_params = self.serialize_for_json(params) if params else None\n        serialized_output = self.serialize_for_json(output) if output else None\n\n        new_log = Log(\n            function_name=function_name,\n            message=message,\n            timestamp=timestamp,\n            params=serialized_params,\n            output=serialized_output,\n            time_spent=time_spent,\n            parent_log_id=parent_log_id,\n            triggered_by_log_id=triggered_by_log_id,\n            log_type=log_type\n        )\n        session.add(new_log)\n        session.flush()  # This ensures new_log.id is populated\n        return new_log.id\n\n    def update_log(self, session, log_id: int, **kwargs) -> None:\n        # Fetch the log entry by id\n        log_entry = session.query(Log).filter(Log.id == log_id).first()\n        if log_entry:\n            # Update only the fields provided in kwargs\n            for key, value in kwargs.items():\n                if hasattr(log_entry, key):\n                    setattr(log_entry, key, value)\n                else:\n                    raise ValueError(f\"Log has no attribute '{key}'\")\n            # No need to call session.commit(); it will be committed in the session scope\n        else:\n            raise ValueError(f\"Log with id {log_id} not found.\")\n\n\n\n    def update_log_params(self, session, log_id: int, params) -> None:\n        log_entry = session.query(Log).filter_by(id=log_id).one_or_none()\n        if log_entry is None:\n            raise ValueError(f\"Log entry with id {log_id} not found.\")\n\n        log_entry.params = params\n        session.commit()\n\n\n\n    def get_log(self, session, log_id: int):\n        \"\"\"\n        Fetches a single log entry by its ID.\n\n        :param session: SQLAlchemy session object.\n        :param log_id: The ID of the log to retrieve.\n        :return: Log object if found, else None.\n        \"\"\"\n        return session.query(Log).filter_by(id=log_id).first()\n\n    def get_child_logs(self, session, parent_id: int):\n        \"\"\"\n        Retrieves all child logs that have the given parent_log_id.\n\n        :param session: SQLAlchemy session object.\n        :param parent_id: The ID of the parent log.\n        :return: List of Log objects.\n        \"\"\"\n        return session.query(Log).filter_by(parent_log_id=parent_id).all()\n    \n    def get_logs(self, session, function_name=None, start_date=None, end_date=None, triggered_by_log_id=None):\n        query = session.query(Log)\n\n        if function_name:\n            query = query.filter(Log.function_name == function_name)\n\n        if start_date:\n            query = query.filter(Log.timestamp >= start_date)\n\n        if end_date:\n            query = query.filter(Log.timestamp <= end_date)\n\n        if triggered_by_log_id:\n            query = query.filter(Log.triggered_by_log_id == triggered_by_log_id)\n\n        return query.all()\n\n\n    def get_log_bundle(self, session, log_id):\n        logs_collected = {}\n\n        def fetch_related_logs(current_log_id):\n            if current_log_id in logs_collected:\n                return\n            log = session.query(Log).filter_by(id=current_log_id).one_or_none()\n            if not log:\n                return\n            logs_collected[current_log_id] = log\n\n            # Fetch parent log\n            if log.parent_log_id:\n                fetch_related_logs(log.parent_log_id)\n\n                # Fetch sibling logs\n                sibling_logs = session.query(Log).filter(\n                    Log.parent_log_id == log.parent_log_id,\n                    Log.id != current_log_id\n                ).all()\n                for sibling in sibling_logs:\n                    if sibling.id not in logs_collected:\n                        fetch_related_logs(sibling.id)\n\n            # Fetch child logs\n            child_logs = session.query(Log).filter_by(parent_log_id=current_log_id).all()\n            for child in child_logs:\n                if child.id not in logs_collected:\n                    fetch_related_logs(child.id)\n\n        fetch_related_logs(log_id)\n        return list(logs_collected.values())\n\n\n\n\n    def add_secret_key(self, session, function_id, key_name, key_value):\n        print(f\"Encrypting value for key '{key_name}'\")\n        try:\n            encrypted_value = fernet.encrypt(key_value.encode())\n            print(f\"Value encrypted successfully for key '{key_name}'\")\n            secret_key = SecretKey(function_id=function_id, name=key_name, _encrypted_value=encrypted_value)\n            session.add(secret_key)\n            print(f\"Secret key '{key_name}' added to session\")\n        except Exception as e:\n            print(f\"Error in add_secret_key: {str(e)}\")\n            raise\n\n    \n    def add_secret_key(self, session, key_name, key_value):\n        encrypted_value = fernet.encrypt(key_value.encode())\n        secret_key = SecretKey(name=key_name, _encrypted_value=encrypted_value)\n        session.add(secret_key)\n\n    def get_secret_key(self, session, key_name):\n        return session.query(SecretKey).filter_by(name=key_name).first()\n\n    \n    def get_all_secret_keys(self, session):\n        return session.query(SecretKey).all()\n\n    "
  },
  {
    "path": "babyagi/functionz/db/models.py",
    "content": "# models.py\n\nfrom sqlalchemy import Column, Integer, String, DateTime, JSON, ForeignKey, Boolean, Table, Float, LargeBinary\nfrom sqlalchemy.ext.declarative import declarative_base\nfrom sqlalchemy.orm import relationship\nfrom cryptography.fernet import Fernet\nfrom cryptography.fernet import InvalidToken\nfrom sqlalchemy.ext.hybrid import hybrid_property\nimport os\nimport json\nfrom datetime import datetime\n\nBase = declarative_base()\n\nKEY_FILE = 'encryption_key.json'\n\ndef get_or_create_key():\n    if os.path.exists(KEY_FILE):\n        with open(KEY_FILE, 'r') as f:\n            return json.load(f)['key']\n    else:\n        key = Fernet.generate_key().decode()\n        with open(KEY_FILE, 'w') as f:\n            json.dump({'key': key}, f)\n        return key\n\nENCRYPTION_KEY = get_or_create_key()\nprint(f\"Using encryption key: {ENCRYPTION_KEY}\")\nfernet = Fernet(ENCRYPTION_KEY.encode())\n\n# Association table for function dependencies (many-to-many between FunctionVersion and Function)\nfunction_dependency = Table('function_dependency', Base.metadata,\n    Column('function_version_id', Integer, ForeignKey('function_versions.id')),\n    Column('dependency_id', Integer, ForeignKey('functions.id'))\n)\n\n# **Define function_version_imports association table here**\nfunction_version_imports = Table('function_version_imports', Base.metadata,\n    Column('function_version_id', Integer, ForeignKey('function_versions.id')),\n    Column('import_id', Integer, ForeignKey('imports.id'))\n)\n\n\nclass Function(Base):\n    __tablename__ = 'functions'\n    id = Column(Integer, primary_key=True)\n    name = Column(String, unique=True)\n    versions = relationship(\"FunctionVersion\", back_populates=\"function\", cascade=\"all, delete-orphan\")\n\nclass FunctionVersion(Base):\n    __tablename__ = 'function_versions'\n    id = Column(Integer, primary_key=True)\n    function_id = Column(Integer, ForeignKey('functions.id'))\n    version = Column(Integer)\n    code = Column(String)\n    function_metadata = Column(JSON)\n    is_active = Column(Boolean, default=False)\n    created_date = Column(DateTime, default=datetime.utcnow)\n    input_parameters = Column(JSON)\n    output_parameters = Column(JSON)\n    function = relationship(\"Function\", back_populates=\"versions\")\n    dependencies = relationship('Function', secondary=function_dependency,\n                                primaryjoin=(function_dependency.c.function_version_id == id),\n                                secondaryjoin=(function_dependency.c.dependency_id == Function.id))\n    imports = relationship('Import', secondary=function_version_imports, back_populates='function_versions')\n    triggers = Column(JSON, nullable=True)  # Store triggers as a JSON field\n\n\n\nclass Import(Base):\n    __tablename__ = 'imports'\n    id = Column(Integer, primary_key=True)\n    name = Column(String, unique=True)\n    lib = Column(String, nullable=True)\n    source = Column(String)\n    function_versions = relationship('FunctionVersion', secondary=function_version_imports, back_populates='imports')\n\n\nclass Log(Base):\n    __tablename__ = 'logs'\n\n    id = Column(Integer, primary_key=True)\n    function_name = Column(String, nullable=False)\n    message = Column(String, nullable=False)\n    timestamp = Column(DateTime, nullable=False)\n    params = Column(JSON, nullable=True)\n    output = Column(JSON, nullable=True)\n    time_spent = Column(Float, nullable=True)\n    log_type = Column(String, nullable=False)\n\n    # Parent Log Relationship\n    parent_log_id = Column(Integer, ForeignKey('logs.id'), nullable=True)\n    parent_log = relationship(\n        'Log',\n        remote_side=[id],\n        backref='child_logs',\n        foreign_keys=[parent_log_id]\n    )\n\n    # Triggered By Log Relationship\n    triggered_by_log_id = Column(Integer, ForeignKey('logs.id'), nullable=True)\n    triggered_by_log = relationship(\n        'Log',\n        remote_side=[id],\n        backref='triggered_logs',\n        foreign_keys=[triggered_by_log_id]\n    )\n\n\nclass SecretKey(Base):\n    __tablename__ = 'secret_keys'\n    id = Column(Integer, primary_key=True)\n    name = Column(String, nullable=False, unique=True)  # Make name unique\n    _encrypted_value = Column(LargeBinary, nullable=False)\n\n    @hybrid_property\n    def value(self):\n        if self._encrypted_value:\n            try:\n                return fernet.decrypt(self._encrypted_value).decode()\n            except InvalidToken:\n                print(f\"Error decrypting value for key: {self.name}. The encryption key may have changed.\")\n                return None\n        return None\n\n    @value.setter\n    def value(self, plaintext_value):\n        if plaintext_value:\n            self._encrypted_value = fernet.encrypt(plaintext_value.encode())\n        else:\n            self._encrypted_value = None\n\n"
  },
  {
    "path": "babyagi/functionz/packs/default/ai_functions.py",
    "content": "# packs/ai_generator.py\n\nfrom functionz.core.framework import func\n\n@func.register_function(\n    metadata={\"description\": \"GPT Call function using LiteLLm\"},\n    imports=[\"litellm\"],\n    key_dependencies=[\"openai_api_key\"]\n)\ndef gpt_call(prompt: str) -> str:\n    from litellm import completion\n    messages = [{\"role\": \"user\", \"content\": prompt}]\n    response = completion(model=\"gpt-4o\", messages=messages)\n    return response['choices'][0]['message']['content']\n\n@func.register_function(\n    metadata={\"description\": \"Generates a description for a function using LiteLLm\"},\n    dependencies=[\"gpt_call\"]\n)\ndef description_writer(function_code: str) -> str:\n    prompt = (\n        f\"Provide a concise and clear description for the following Python function:\\n\\n\"\n        f\"{function_code}\\n\\n\"\n        f\"Description:\"\n    )\n    description = func.gpt_call(prompt)\n    return description\n\n@func.register_function(\n    metadata={\"description\": \"Generates and updates descriptions for functions lacking one or having an empty description\"},\n    dependencies=[\"description_writer\"],\n    triggers=[\"function_added_or_updated\"]\n)\ndef ai_description_generator(function_name: str) -> None:\n    print(f\"Generating AI description for function: {function_name}\")\n    function = func.db.get_function(function_name)\n    if not function:\n        print(f\"Function '{function_name}' not found in the database.\")\n        return\n\n    description = function.get('metadata', {}).get('description', '').strip()\n    function_code = function.get('code', '')\n\n    if not description and function_code.strip():\n        #print(f\"Generating description for function '{function_name}'.\")\n        generated_description = func.description_writer(function_code)\n        func.update_function(\n            name=function_name,\n            metadata={\"description\": generated_description}\n        )\n        print(f\"Description for function '{function_name}' has been generated and updated.\")\n        return f\"Description for function '{function_name}' has been generated and updated.\"\n    elif not function_code.strip():\n        print(f\"Function '{function_name}' has no code to generate a description.\")\n        return f\"Function '{function_name}' has no code to generate a description.\"\n    else:\n        print(f\"Function '{function_name}' already has a non-empty description.\")\n        return f\"Function '{function_name}' already has a non-empty description.\"\n\n@func.register_function(\n    metadata={\"description\": \"Scans all functions and generates descriptions for those lacking one\"},\n    dependencies=[\"ai_description_generator\"]\n)\ndef generate_missing_descriptions() -> None:\n    all_functions = func.db.get_all_functions()\n    missing_description_functions = [\n        func_info['name'] for func_info in all_functions\n        if not func_info.get('metadata', {}).get('description')\n    ]\n    if not missing_description_functions:\n        print(\"All functions already have descriptions.\")\n        return\n    print(f\"Found {len(missing_description_functions)} function(s) without descriptions. Generating descriptions...\")\n    for function_name in missing_description_functions:\n        func.ai_description_generator(function_name)\n    print(\"Description generation process completed.\")\n\n\n@func.register_function(\n    metadata={\"description\": \"Embeds an input using LiteLLM\"},\n    imports=[\"litellm\"],\n    key_dependencies=[\"openai_api_key\"]\n)\ndef embed_input(input_text: str, model: str = \"text-embedding-ada-002\", \n                encoding_format: str = \"float\", dimensions: int = None, \n                timeout: int = 600) -> list:\n    from litellm import embedding\n    import os\n\n    # Set OpenAI API Key from environment variables\n    os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY')\n\n    # Prepare the embedding request with optional parameters\n    embedding_params = {\n        \"model\": model,\n        \"input\": [input_text],\n        \"encoding_format\": encoding_format,\n        \"timeout\": timeout\n    }\n\n    if dimensions:\n        embedding_params[\"dimensions\"] = dimensions\n\n    # Call the LiteLLM embedding function\n    response = embedding(**embedding_params)\n\n    # Return the embedding from the response\n    return response['data'][0]['embedding']\n\n\n@func.register_function(\n    metadata={\"description\": \"Embeds and updates a function's description if it exists\"},\n    dependencies=[\"embed_input\"],\n    imports=[\"os\",\"csv\"]\n)\ndef embed_function_description(function: str) -> None:\n    print(f\"Embedding description for function: {function}\")\n    # Retrieve the function details from the database\n    function_data = func.db.get_function(function)\n    if not function_data:\n        print(f\"Function '{function}' not found in the database.\")\n        return\n\n    description = function_data.get('metadata', {}).get('description', '').strip()\n    if description:\n        print(f\"Embedding description for function '{function}'.\")\n        embedding = func.embed_input(description)\n\n        # Check if 'function_embeddings.csv' exists, create it if not\n        file_path = 'function_embeddings.csv'\n        file_exists = os.path.isfile(file_path)\n\n        # Create a list to store CSV data\n        rows = []\n\n        if file_exists:\n            with open(file_path, mode='r') as file:\n                reader = csv.reader(file)\n                rows = list(reader)\n\n        # Look for the function in the existing rows\n        function_found = False\n        for i, row in enumerate(rows):\n            if row[0] == function:  # function column is the first column\n                rows[i][1] = str(embedding)  # Update the embedding\n                function_found = True\n                print(f\"Updated embedding for function '{function}'.\")\n\n        if not function_found:\n            # Add a new row if the function is not found\n            rows.append([function, str(embedding)])\n            print(f\"Added new function '{function}' with its embedding.\")\n\n        # Write back the data to the CSV file (create or update)\n        with open(file_path, mode='w', newline='') as file:\n            writer = csv.writer(file)\n            writer.writerows(rows)\n\n        print(f\"Embedding for function '{function}' has been saved.\")\n        return embedding\n    else:\n        print(f\"Function '{function}' has no description to embed.\")\n        return f\"Function '{function}' has no description to embed.\"\n\n\n\n@func.register_function(\n    metadata={\"description\": \"Finds similar functions based on the provided description\"},\n    dependencies=[\"embed_input\"],\n    imports=[\"numpy\", \"csv\", \"sklearn\",\"os\"]\n)\ndef find_similar_function(description: str, top_n: int = 3):\n    import numpy as np\n    from sklearn.metrics.pairwise import cosine_similarity\n    # Step 1: Embed the input description\n    #print(f\"Embedding input description: {description}\")\n    input_embedding = func.embed_input(description)\n\n    # Step 2: Load stored embeddings and descriptions from CSV\n    file_path = 'function_embeddings.csv'\n    stored_embeddings = []\n    stored_functions = []\n\n    if not os.path.isfile(file_path):\n        print(f\"No embeddings found in {file_path}.\")\n        return []\n\n    with open(file_path, mode='r') as file:\n        reader = csv.reader(file)\n        for row in reader:\n            stored_functions.append(row[0])\n            stored_embeddings.append(np.fromstring(row[1].strip(\"[]\"), sep=','))\n\n    if not stored_embeddings:\n        print(\"No embeddings stored.\")\n        return []\n\n    # Step 3: Calculate cosine similarity between the input embedding and stored embeddings\n    similarities = cosine_similarity([input_embedding], stored_embeddings)\n\n    # Step 4: Sort stored functions by similarity\n    sorted_indices = np.argsort(similarities[0])[::-1]  # Sort in descending order\n\n    # Step 5: Return the top N most similar functions\n    similar_functions = [stored_functions[i] for i in sorted_indices[:top_n]]\n\n    print(f\"Top {top_n} similar functions: {similar_functions}\")\n    return similar_functions\n\n\n@func.register_function(\n    metadata={\"description\": \"Generates embeddings for functions missing from the CSV\"},\n    dependencies=[\"embed_function_description\"],\n    imports=[\"os\", \"csv\"]\n)\ndef generate_missing_embeddings() -> None:\n    # Step 1: Retrieve all functions from the database\n    all_functions = func.db.get_all_functions()\n    all_function_names = [func_info['name'] for func_info in all_functions]\n\n    # Step 2: Check if 'function_embeddings.csv' exists\n    file_path = 'function_embeddings.csv'\n    file_exists = os.path.isfile(file_path)\n\n    # Read existing embeddings from CSV if the file exists\n    embedded_functions = []\n    if file_exists:\n        with open(file_path, mode='r') as file:\n            reader = csv.reader(file)\n            embedded_functions = [row[0] for row in reader]  # First column is the function name\n\n    # Step 3: Find functions without embeddings\n    missing_embeddings = [func_name for func_name in all_function_names if func_name not in embedded_functions]\n\n    if not missing_embeddings:\n        print(\"All functions already have embeddings.\")\n        return\n\n    print(f\"Found {len(missing_embeddings)} function(s) without embeddings. Generating embeddings...\")\n\n    # Step 4: Embed the functions that are missing\n    for function_name in missing_embeddings:\n        print(f\"Embedding function: {function_name}\")\n        func.embed_function_description(function_name)\n\n    print(\"Embedding generation process completed.\")\n\n\n\n@func.register_function(\n    metadata={\"description\": \"Chooses a function to use\"},\n    dependencies=[\"get_all_functions\",\"gpt_call\"]\n)\ndef choose_function(prompt: str) -> str:\n    functions = func.get_all_functions()\n    prompt = (\n        f\"Which functions are most relevant to the following input? It could be ones to use or look at as reference to build a new one:\\n\\n\"\n        f\"{prompt}\\n\\n\"\n        f\"Functions:{functions}\"\n    )\n    choice = func.gpt_call(prompt)\n    return {\"functions\":functions,\"choice\":choice}"
  },
  {
    "path": "babyagi/functionz/packs/default/default_functions.py",
    "content": "# packs/default_functions.py\n\nfrom babyagi.functionz.core.framework import func\nfrom datetime import datetime\nfrom typing import Optional, Dict, Any, List\n\n@func.register_function()\ndef execute_function_wrapper(function_name: str, *args, **kwargs):\n    # Create an initial log for the wrapper\n    wrapper_log_id = func.db.add_log(\n        function_name=\"execute_function_wrapper\",\n        message=\"Wrapper execution started.\",\n        timestamp=datetime.now(),\n        params={\"function_name\": function_name, \"args\": args, \"kwargs\": kwargs},\n        output=None,\n        time_spent=0,\n        parent_log_id=None,\n        triggered_by_log_id=None,\n        log_type='started'\n    )\n    # Execute the function with the wrapper's log ID as the parent ID\n    result = func.execute_function(function_name, *args, parent_log_id=wrapper_log_id, **kwargs)\n\n    # Update the wrapper log after execution\n    func.db.update_log(wrapper_log_id, output=result, log_type='success', message=\"Wrapper execution completed.\")\n    return result\n\n\n@func.register_function(\n    metadata={\n        \"description\": \"Dynamically adds a new function to the system with the provided code and metadata.\"\n    },\n    imports=[\"typing\"]\n)\ndef add_new_function(\n    name: str,\n    code: str,\n    metadata: dict = None,\n    imports: list = None,\n    dependencies: list = None,\n    key_dependencies: list = None,\n    triggers: list = None\n) -> bool:\n\n    try:\n        func.registrar.add_function(\n            name=name,\n            code=code,\n            metadata=metadata,\n            imports=imports,\n            dependencies=dependencies,\n            key_dependencies=key_dependencies,\n            triggers=triggers\n        )\n        #print(f\"Function '{name}' added successfully.\")\n        return True\n    except Exception as e:\n        print(f\"Error adding function '{name}': {str(e)}\")\n        return False\n\n\n@func.register_function()\ndef function_added_or_updated(action=None, triggered_function_name=None):\n    \"\"\"\n    Triggered whenever a function is added or updated.\n    \"\"\"\n    print(f\"Function '{triggered_function_name}' has been {action}.\")\n    function_data = func.get_function(triggered_function_name) if triggered_function_name else None\n    if function_data:\n        return triggered_function_name\n    else:\n        print(f\"Function '{triggered_function_name}' not found in the database.\")\n        return None\n\n@func.register_function(\n    metadata={\"description\": \"Add a secret key to the database.\"},\n    imports=[\"os\"]\n)\ndef add_key_wrapper(key_name: str, key_value: str):\n    return func.add_key(key_name, key_value)\n\n@func.register_function(metadata={\"description\": \"Get all versions of a given function.\"})\ndef get_function_versions_wrapper(name: str):\n    return func.get_function_versions(name)\n\n@func.register_function()\ndef get_function_wrapper(name: str):\n    return func.get_function(name)\n\n\n@func.register_function(metadata={\"description\": \"Get all versions of a given function.\"})\ndef get_all_functions_wrapper():\n    return func.get_all_functions()\n\n@func.register_function(metadata={\"description\": \"Activate a specific version of a function.\"})\ndef activate_function_version_wrapper(name: str, version: int):\n    return func.activate_function_version(name, version)\n\n@func.register_function(metadata={\"description\": \"Display all registered functions and their metadata.\"})\ndef display_functions_wrapper():\n    return func.display()\n\n@func.register_function(\n    metadata={\"description\": \"Get logs for a specific function, optionally filtered by date.\"},\n    imports=['datetime']\n                       )\ndef get_logs_wrapper(function_name: str = None, start_date: datetime = None,\n                 end_date: datetime = None):\n    return func.get_logs(function_name, start_date, end_date)\n\n@func.register_function(metadata={\"description\": \"Add a trigger that executes a specific function when another function is executed.\"})\ndef add_trigger_wrapper(triggered_function_name: str, triggering_function_name: Optional[str] = None):\n    return func.add_trigger(triggered_function_name, triggering_function_name)\n\n\n@func.register_function(metadata={\"description\": \"Get all secret keys stored.\"})\ndef get_all_secret_keys():\n    return func.get_all_secret_keys()\n\n\n@func.register_function(metadata={\"description\": \"Get all imports.\"})\ndef get_all_imports_wrapper():\n    return func.get_all_imports()"
  },
  {
    "path": "babyagi/functionz/packs/default/function_calling_chat.py",
    "content": "from functionz.core.framework import func\nimport json\nimport litellm\n\n# Assuming `func` is the registry from your framework\n# and `execute_function_wrapper` is already registered in the database.\n\n@func.register_function(\n    metadata={\n        \"description\": \"A chat application that interacts with LiteLLM and executes selected functions from the database.\"\n    },\n    imports=[\"litellm\", \"json\"],\n    dependencies=[\"get_function_wrapper\", \"execute_function_wrapper\"],\n    key_dependencies=[\"OPENAI_API_KEY\"]  # Ensure this key is set in your environment\n)\ndef chat_with_functions(chat_history, available_function_names) -> str:\n    def map_python_type_to_json(python_type: str) -> dict:\n        \"\"\"\n        Maps Python type annotations to JSON Schema types.\n\n        Args:\n            python_type (str): The Python type as a string.\n\n        Returns:\n            dict: The corresponding JSON Schema type with additional details if necessary.\n        \"\"\"\n        type_mapping = {\n            \"str\": {\"type\": \"string\"},\n            \"int\": {\"type\": \"integer\"},\n            \"float\": {\"type\": \"number\"},\n            \"bool\": {\"type\": \"boolean\"},\n            \"list\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}},  # Assuming list of strings\n            \"dict\": {\"type\": \"object\"},\n            \"Any\": {\"type\": \"string\"}  # Default to string for unsupported types\n        }\n        return type_mapping.get(python_type, {\"type\": \"string\"})\n\n    # Enable verbose logging for LiteLLM\n    litellm.set_verbose = True\n\n    # Initialize chat context with system message\n    chat_context = [\n        {\"role\": \"system\", \"content\": \"You are a helpful assistant.\"}\n    ]\n\n    # Validate and append chat history\n    if not isinstance(chat_history, list):\n        raise ValueError(\"chat_history must be a list of messages.\")\n\n    for message in chat_history:\n        if not isinstance(message, dict):\n            raise ValueError(\"Each message in chat_history must be a dictionary.\")\n        role = message.get('role')\n        content = message.get('message')\n        if role not in ['user', 'assistant', 'system']:\n            raise ValueError(\"Message role must be 'user', 'assistant', or 'system'.\")\n        if not isinstance(content, str):\n            raise ValueError(\"Message content must be a string.\")\n        chat_context.append({\"role\": role, \"content\": content})\n\n    # Handle available_function_names input\n    if isinstance(available_function_names, str):\n        # Split the string by commas and strip whitespace\n        available_function_names = [name.strip() for name in available_function_names.split(',') if name.strip()]\n    elif isinstance(available_function_names, list):\n        # Ensure all elements are strings and strip whitespace\n        available_function_names = [name.strip() for name in available_function_names if isinstance(name, str) and name.strip()]\n    else:\n        raise ValueError(\"available_function_names must be a string or a list of strings.\")\n\n    if not available_function_names:\n        raise ValueError(\"No valid function names provided in available_function_names.\")\n\n    # Fetch available functions from the database\n    tools = []\n    for func_name in available_function_names:\n        # Retrieve function details using the get_function_wrapper\n        function_data = get_function_wrapper(func_name)\n        if function_data:\n            # Construct the tool definition for LiteLLM\n            tool = {\n                \"type\": \"function\",\n                \"function\": {\n                    \"name\": function_data['name'],\n                    \"description\": function_data['metadata']['description'],\n                    \"parameters\": {\n                        \"type\": \"object\",\n                        \"properties\": {},\n                        \"required\": []\n                    },\n                },\n            }\n\n            # Map input_parameters to the tool's parameters\n            for param in function_data.get('input_parameters', []):\n                # Convert Python types to JSON Schema types\n                json_schema = map_python_type_to_json(param['type'])\n                tool['function']['parameters']['properties'][param['name']] = {\n                    **json_schema,\n                    \"description\": param.get('description', '')\n                }\n                if param.get('required', False):\n                    tool['function']['parameters']['required'].append(param['name'])\n\n            tools.append(tool)\n        else:\n            # Handle the case where the function is not found\n            raise ValueError(f\"Function '{func_name}' not found in the database.\")\n\n\n    # Call LiteLLM's completion API with the user message and available tools\n    response = litellm.completion(\n        model=\"gpt-4-turbo\",\n        messages=chat_context,\n        tools=tools,\n        tool_choice=\"auto\"\n    )\n\n    # Extract the message from the response\n    response_message = response['choices'][0]['message']\n\n    # Check if the model wants to call any functions\n    tool_calls = response_message.get('tool_calls', [])\n\n    # If there are function calls, execute them\n    if tool_calls:\n        # Append the assistant's message to the chat context\n        chat_context.append(response_message)\n\n        for tool_call in tool_calls:\n            function_name = tool_call['function']['name']\n            function_args = json.loads(tool_call['function']['arguments'])\n            tool_call_id = tool_call['id']  # Extract the tool_call_id\n\n            # Execute the function using execute_function_wrapper\n            try:\n                function_response = execute_function_wrapper(function_name, **function_args)\n            except Exception as e:\n                function_response = f\"Error executing function '{function_name}': {str(e)}\"\n\n            # Ensure function_response is a string\n            if not isinstance(function_response, str):\n                function_response = json.dumps(function_response)\n\n            # Append the function response to the chat context\n            chat_context.append({\n                \"tool_call_id\": tool_call_id,  # Include the tool_call_id\n                \"role\": \"tool\",  # Use 'tool' as per LiteLLM's protocol\n                \"name\": function_name,\n                \"content\": function_response\n            })\n\n        # Call LiteLLM again with the updated context including function responses\n        second_response = litellm.completion(\n            model=\"gpt-4-turbo\",\n            messages=chat_context\n        )\n\n        # Extract and return the assistant's final response\n        assistant_response = second_response['choices'][0]['message']['content']\n        return assistant_response\n    else:\n        # If no functions are called, return the assistant's message directly\n        assistant_response = response_message.get('content', '')\n        return assistant_response\n"
  },
  {
    "path": "babyagi/functionz/packs/default/os.py",
    "content": "@func.register_function(\n    metadata={\"description\": \"Returns the current directory and recursively lists all files and folders, excluding hidden files, folders (those starting with a '.'), and the '__pycache__' folder. The output omits the current directory prefix from file paths for readability.\"},\n    imports=[\"os\"]\n)\ndef get_full_directory_contents_cleaned():\n    current_directory = os.getcwd()  # Get current working directory\n    directory_structure = {}\n\n    # Walk through the directory and its subdirectories\n    for root, dirs, files in os.walk(current_directory):\n        # Filter out hidden directories, '__pycache__', and hidden files\n        dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__']\n        files = [f for f in files if not f.startswith('.')]\n\n        # Remove the current directory path from the root\n        relative_root = root.replace(current_directory, \"\").lstrip(os.sep)\n        directory_structure[relative_root] = {\n            \"folders\": dirs,\n            \"files\": files\n        }\n\n    return {\"current_directory\": current_directory, \"directory_structure\": directory_structure}\n"
  },
  {
    "path": "babyagi/functionz/packs/drafts/choose_or_create_function.py",
    "content": "from functionz.core.framework import func\n\n@func.register_function(\n    metadata={\"description\": \"Choose or create a function based on user input and execute it.\"},\n    dependencies=[\n        \"display_functions_wrapper\",\n        \"get_function_wrapper\",\n        \"execute_function_wrapper\",\n        \"generate_function_from_description\"\n    ],\n    imports=[\n        {\"name\": \"litellm\", \"lib\": \"litellm\"},\n        {\"name\": \"pydantic\", \"lib\": \"pydantic\"},\n        {\"name\": \"typing\", \"lib\": \"typing\"},\n        {\"name\": \"json\", \"lib\": \"json\"},\n    ]\n)\ndef choose_or_create_function(user_input: str) -> dict:\n    \"\"\"\n    Takes user input, compares against existing functions, decides whether to use an existing function or generate a new one, then executes the function with generated parameters.\n\n    Args:\n        user_input (str): The user's input or request.\n\n    Returns:\n        dict: A dictionary containing the result of the function execution, intermediate steps, and any relevant information.\n    \"\"\"\n    from litellm import completion\n    from pydantic import BaseModel, Field, ValidationError\n    from typing import List, Optional, Dict, Any\n    import json\n\n    intermediate_steps = []\n\n    # Step 1: Fetch existing functions\n    try:\n        existing_functions = display_functions_wrapper()\n        print(f\"[DEBUG] Existing Functions: {existing_functions}\")\n        intermediate_steps.append({\"step\": \"Fetch Existing Functions\", \"content\": existing_functions})\n    except Exception as e:\n        print(f\"[ERROR] Failed to fetch existing functions: {e}\")\n        intermediate_steps.append({\"step\": \"Error Fetching Existing Functions\", \"content\": str(e)})\n        return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error fetching existing functions.\"}\n\n    # Step 2: Use LLM to decide whether to use an existing function or generate a new one\n    system_prompt = \"\"\"\nYou are an assistant that helps decide whether an existing function can fulfill a user's request or if a new function needs to be created.\n\nPlease analyze the user's input and the list of available functions.\n\nReturn your decision in the following JSON format:\n\n{\n    \"use_existing_function\": true or false,\n    \"function_name\": \"name of the existing function\" (if applicable),\n    \"function_description\": \"description of the function to generate\" (if applicable)\n}\n\nProvide only the JSON response, without any additional text.\n\"\"\"\n\n    class FunctionDecision(BaseModel):\n        use_existing_function: bool = Field(..., description=\"True if an existing function can be used; False if a new function needs to be generated.\")\n        function_name: Optional[str] = Field(None, description=\"Name of the existing function to use.\")\n        function_description: Optional[str] = Field(None, description=\"Description of the new function to generate.\")\n\n    decision_prompt = f\"\"\"\nThe user has provided the following input:\n\\\"{user_input}\\\"\n\nAvailable Functions:\n{existing_functions}\n\"\"\"\n\n    try:\n        decision_response = completion(\n            model=\"gpt-4o-mini\",\n            messages=[\n                {\"role\": \"system\", \"content\": system_prompt},\n                {\"role\": \"user\", \"content\": decision_prompt}\n            ],\n            response_format=FunctionDecision\n        )\n        print(f\"[DEBUG] Decision Response: {decision_response}\")\n    except Exception as e:\n        print(f\"[ERROR] LLM call for FunctionDecision failed: {e}\")\n        intermediate_steps.append({\"step\": \"Error in FunctionDecision LLM Call\", \"content\": str(e)})\n        return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error during function decision analysis.\"}\n\n    # Parse the response\n    try:\n        content = decision_response.choices[0].message.content\n        print(f\"[DEBUG] Raw Decision Content: {content}\")\n        decision_parsed = FunctionDecision.parse_raw(content)\n        print(f\"[DEBUG] Parsed FunctionDecision: {decision_parsed}\")\n        intermediate_steps.append({\"step\": \"Function Decision\", \"content\": decision_parsed.dict()})\n    except (ValidationError, IndexError, AttributeError, json.JSONDecodeError) as e:\n        print(f\"[ERROR] Parsing FunctionDecision response failed: {e}\")\n        intermediate_steps.append({\"step\": \"Error Parsing FunctionDecision Response\", \"content\": str(e)})\n        return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error parsing FunctionDecision response.\"}\n\n    if decision_parsed.use_existing_function and decision_parsed.function_name:\n        function_name = decision_parsed.function_name\n        print(f\"[INFO] Using existing function: {function_name}\")\n    elif not decision_parsed.use_existing_function and decision_parsed.function_description:\n        # Generate the new function\n        print(f\"[INFO] Generating new function based on description.\")\n        gen_result = generate_function_from_description(decision_parsed.function_description)\n        intermediate_steps.extend(gen_result.get(\"intermediate_steps\", []))\n        if not gen_result.get(\"added_to_database\"):\n            print(f\"[ERROR] Failed to generate and add new function.\")\n            return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error generating new function.\"}\n        # Get the function name from the generated function code\n        function_name = gen_result.get(\"function_name\")\n        if not function_name:\n            # Extract function name from the code\n            import re\n            match = re.search(r'def\\s+([a-zA-Z_][a-zA-Z0-9_]*)\\s*\\(', gen_result.get(\"final_code\", \"\"))\n            if match:\n                function_name = match.group(1)\n                print(f\"[INFO] Extracted function name: {function_name}\")\n            else:\n                print(f\"[ERROR] Function name not found in generated code.\")\n                return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Function name not found in generated code.\"}\n    else:\n        print(f\"[ERROR] Invalid decision or missing information.\")\n        return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Invalid function decision.\"}\n\n    # Step 3: Get the function code using get_function_wrapper\n    try:\n        function_info = get_function_wrapper(function_name)\n        if not function_info:\n            print(f\"[ERROR] Function {function_name} not found.\")\n            intermediate_steps.append({\"step\": \"Error Fetching Function\", \"content\": f\"Function {function_name} not found.\"})\n            return {\"intermediate_steps\": intermediate_steps, \"error\": f\"# Function {function_name} not found.\"}\n        print(f\"[DEBUG] Function Info: {function_info}\")\n        intermediate_steps.append({\"step\": \"Fetch Function Info\", \"content\": function_info})\n    except Exception as e:\n        print(f\"[ERROR] Fetching function info failed: {e}\")\n        intermediate_steps.append({\"step\": \"Error Fetching Function Info\", \"content\": str(e)})\n        return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error fetching function info.\"}\n\n    # Step 4: Use LLM to generate parameters for the function based on user input\n    param_prompt = f\"\"\"\n    The user has provided the following input:\n    \\\"{user_input}\\\"\n\n    The function to execute is:\n    {function_info.get('code', '')}\n\n    Generate a JSON object with a single key \"parameters\" that contains the parameters required by the function, filled in appropriately based on the user's input.\n\n    Return only the JSON object, with no additional text.\n    \"\"\"\n\n    try:\n        # Define a Pydantic model with a fixed field \"parameters\"\n        class FunctionParameters(BaseModel):\n            parameters: Dict[str, Any]\n\n            class Config:\n                extra = 'forbid'  # This sets 'additionalProperties' to False\n\n        param_response = completion(\n            model=\"gpt-4o-mini\",\n            messages=[\n                {\"role\": \"system\", \"content\": \"You are an assistant that provides only JSON-formatted data, with no additional text.\"},\n                {\"role\": \"user\", \"content\": param_prompt}\n            ],\n            response_format=FunctionParameters  # Keep the same parsing format\n        )\n        print(f\"[DEBUG] Parameter Response: {param_response}\")\n    except Exception as e:\n        print(f\"[ERROR] LLM call for parameter generation failed: {e}\")\n        intermediate_steps.append({\"step\": \"Error in Parameter Generation LLM Call\", \"content\": str(e)})\n        return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error generating parameters.\"}\n\n    # Parse the response using the Pydantic model\n    try:\n        content = param_response.choices[0].message.content\n        print(f\"[DEBUG] Raw Parameter Content: {content}\")\n        function_params_model = FunctionParameters.parse_raw(content)\n        function_params = function_params_model.parameters  # Extract the parameters dictionary\n        print(f\"[DEBUG] Parsed Parameters: {function_params}\")\n        intermediate_steps.append({\"step\": \"Generate Function Parameters\", \"content\": function_params})\n    except (ValidationError, IndexError, AttributeError, json.JSONDecodeError) as e:\n        print(f\"[ERROR] Parsing parameters failed: {e}\")\n        intermediate_steps.append({\"step\": \"Error Parsing Parameters\", \"content\": str(e)})\n        return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error parsing function parameters.\"}\n\n    # Step 5: Execute the function using execute_function_wrapper\n    try:\n        # Ensure that function_params is a dictionary\n        if not isinstance(function_params, dict):\n            raise TypeError(\"function_params must be a dictionary\")\n        execution_result = execute_function_wrapper(function_name, **function_params)\n        print(f\"[DEBUG] Execution Result: {execution_result}\")\n        intermediate_steps.append({\"step\": \"Execute Function\", \"content\": execution_result})\n    except Exception as e:\n        print(f\"[ERROR] Function execution failed: {e}\")\n        intermediate_steps.append({\"step\": \"Error Executing Function\", \"content\": str(e)})\n        return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error executing function.\"}\n\n    return {\n        \"intermediate_steps\": intermediate_steps,\n        \"execution_result\": execution_result\n    }"
  },
  {
    "path": "babyagi/functionz/packs/drafts/code_writing_functions.py",
    "content": "from functionz.core.framework import func\n\n@func.register_function(\n  metadata={\"description\": \"Checks if an existing function satisfies the user input\"},\n  dependencies=[\"gpt_call\", \"get_all_functions_wrapper\"]\n)\ndef check_existing_functions(user_input):\n  import json\n\n  while True:\n      # Get all functions and their descriptions\n      functions = get_all_functions_wrapper()\n      function_descriptions = [\n          {\"name\": f['name'], \"description\": f['metadata'].get('description', '')}\n          for f in functions\n      ]\n\n      # Prepare the prompt\n      prompt = f\"\"\"\nYou are an expert software assistant. The user has provided the following request:\n\n\"{user_input}\"\n\nBelow is a list of available functions with their descriptions:\n\n{function_descriptions}\n\nDetermine if any of the existing functions perfectly fulfill the user's request. If so, return the name of the function.\n\nProvide your answer in the following JSON format:\n{{\n  \"function_found\": true or false,\n  \"function_name\": \"<name of the function if found, else null>\"\n}}\n\nExamples:\n\nExample 1:\nUser input: \"Calculate the sum of two numbers\"\nFunctions: [{{\"name\": \"add_numbers\", \"description\": \"Adds two numbers\"}}]\nResponse:\n{{\n  \"function_found\": true,\n  \"function_name\": \"add_numbers\"\n}}\n\nExample 2:\nUser input: \"Translate text to French\"\nFunctions: [{{\"name\": \"add_numbers\", \"description\": \"Adds two numbers\"}}]\nResponse:\n{{\n  \"function_found\": false,\n  \"function_name\": null\n}}\n\nNow, analyze the user's request and provide the JSON response.\n\"\"\"\n\n      response = gpt_call(prompt)\n\n      # Try to parse the JSON response\n      try:\n          result = json.loads(response)\n          if 'function_found' in result and isinstance(result['function_found'], bool) and \\\n             ('function_name' in result):\n              return result\n          else:\n              raise ValueError(\"Invalid JSON structure\")\n      except Exception as e:\n          # If parsing fails, retry\n          continue\n\n@func.register_function(\n  metadata={\"description\": \"Breaks down the user task into smaller functions\"},\n  dependencies=[\"gpt_call\"]\n)\ndef break_down_task(user_input):\n  import json\n  while True:\n      # Prepare the prompt with detailed context\n      prompt = f\"\"\"\nYou are an expert software assistant helping to break down a user's request into smaller functions for a microservice-inspired architecture. The system is designed to be modular, with each function being small and designed optimally for potential future reuse.\n\nWhen breaking down the task, consider the following:\n\n- Each function should be as small as possible and do one thing well.\n- Use existing functions where possible. You have access to functions such as 'gpt_call', 'find_similar_function', and others in our function database.\n- Functions can depend on each other. Use 'dependencies' to specify which functions a function relies on.\n- Functions should include appropriate 'imports' if external libraries are needed.\n- Provide the breakdown as a list of functions, where each function includes its 'name', 'description', 'input_parameters', 'output_parameters', 'dependencies', and 'code' (just a placeholder or brief description at this stage).\n- Make sure descriptions are detailed so an engineer could build it to spec.\n- Every sub function you create should be designed to be reusable by turning things into parameters, vs hardcoding them.\n\nUser request:\n\n\"{user_input}\"\n\nProvide your answer in JSON format as a list of functions. Each function should have the following structure:\n\n{{\n  \"name\": \"function_name\",\n  \"description\": \"Brief description of the function\",\n  \"input_parameters\": [{{\"name\": \"param1\", \"type\": \"type1\"}}, ...],\n  \"output_parameters\": [{{\"name\": \"output\", \"type\": \"type\"}}, ...],\n  \"dependencies\": [\"dependency1\", \"dependency2\", ...],\n  \"imports\": [\"import1\", \"import2\", ...],\n  \"code\": \"Placeholder or brief description\"\n}}\n\nExample:\n\n[\n  {{\n      \"name\": \"process_data\",\n      \"description\": \"Processes input data\",\n      \"input_parameters\": [{{\"name\": \"data\", \"type\": \"str\"}}],\n      \"output_parameters\": [{{\"name\": \"processed_data\", \"type\": \"str\"}}],\n      \"dependencies\": [],\n      \"imports\": [],\n      \"code\": \"Placeholder for process_data function\"\n  }},\n  {{\n      \"name\": \"analyze_data\",\n      \"description\": \"Analyzes processed data\",\n      \"input_parameters\": [{{\"name\": \"processed_data\", \"type\": \"str\"}}],\n      \"output_parameters\": [{{\"name\": \"analysis_result\", \"type\": \"str\"}}],\n      \"dependencies\": [\"process_data\"],\n      \"imports\": [],\n      \"code\": \"Placeholder for analyze_data function\"\n  }}\n]\n\nNow, provide the breakdown for the user's request.\n\"\"\"\n\n      response = gpt_call(prompt)\n\n      # Try to parse the JSON response\n      try:\n          functions = json.loads(response)\n          # Basic validation of the structure\n          if isinstance(functions, list) and all('name' in func and 'description' in func for func in functions):\n              return functions\n          else:\n              raise ValueError(\"Invalid JSON structure\")\n      except Exception as e:\n          # If parsing fails, retry\n          continue\n\n@func.register_function(\n  metadata={\"description\": \"Decides if imports or external APIs are needed\"},\n  dependencies=[\"gpt_call\", \"get_all_functions_wrapper\"]\n)\ndef decide_imports_and_apis(context):\n  import json\n  while True:\n      # Get all available functions and their imports\n      all_functions = get_all_functions_wrapper()\n      existing_imports = set()\n      for func in all_functions:\n          existing_imports.update(func.get('imports', []))\n\n      # Prepare the prompt\n      prompt = f\"\"\"\nYou are an expert software assistant helping to decide what imports and external APIs are needed for a set of functions based on the context provided.\n\nContext:\n\n{context}\n\nExisting standard Python imports:\n\n{list(existing_imports)}\n\nDetermine the libraries (imports) and external APIs needed for these functions. Separate standard Python libraries from external libraries or APIs.\n\nProvide your answer in the following JSON format:\n\n{{\n  \"standard_imports\": [\"import1\", \"import2\", ...],\n  \"external_imports\": [\"external_import1\", \"external_import2\", ...],\n  \"external_apis\": [\"api1\", \"api2\", ...],\n  \"documentation_needed\": [\n      {{\"name\": \"external_import1\", \"type\": \"import\" or \"api\"}},\n      ...\n  ]\n}}\n\nNote: 'documentation_needed' should include any external imports or APIs for which documentation should be looked up.\n\nExample:\n\n{{\n  \"standard_imports\": [\"os\", \"json\"],\n  \"external_imports\": [\"requests\"],\n  \"external_apis\": [\"SerpAPI\"],\n  \"documentation_needed\": [\n      {{\"name\": \"requests\", \"type\": \"import\"}},\n      {{\"name\": \"SerpAPI\", \"type\": \"api\"}}\n  ]\n}}\n\nNow, analyze the context and provide the JSON response.\n\"\"\"\n\n      response = gpt_call(prompt)\n\n      # Try to parse the JSON response\n      try:\n          result = json.loads(response)\n          # Basic validation of the structure\n          if all(key in result for key in ['standard_imports', 'external_imports', 'external_apis', 'documentation_needed']):\n              return result\n          else:\n              raise ValueError(\"Invalid JSON structure\")\n      except Exception as e:\n          # If parsing fails, retry\n          continue\n\n@func.register_function(\n  metadata={\"description\": \"Gets functions that depend on a given function\"},\n  dependencies=[\"get_all_functions_wrapper\"]\n)\ndef get_functions_that_depend_on(function_name):\n  all_functions = get_all_functions_wrapper()\n  dependent_functions = []\n  for function in all_functions:\n      if function_name in function.get('dependencies', []):\n          dependent_functions.append(function['name'])\n  return dependent_functions\n\n\n@func.register_function(\n    metadata={\"description\": \"Generates the function code using LLM\"},\n    dependencies=[\"gpt_call\", \"get_function_wrapper\", \"get_functions_that_depend_on\", \"get_all_functions_wrapper\"]\n)\ndef generate_function_code(function, context):\n    while True:\n\n        print(\"\\033[1;32mGenerating code for function: \", function[\"name\"], \"\\033[0m\")\n        # Gather dependent functions and their code\n        dependencies = function.get('dependencies', [])\n        dependency_code = ''\n        for dep in dependencies:\n            dep_function = get_function_wrapper(dep)\n            if dep_function:\n                dependency_code += f\"\\n# Code for dependency function '{dep}':\\n{dep_function['code']}\\n\"\n\n        # Gather functions that depend on the same imports\n        imports = function.get('imports', [])\n        functions_with_same_imports = []\n        all_functions = get_all_functions_wrapper()\n        for func_with_imports in all_functions:\n            if set(func_with_imports.get('imports', [])) & set(imports):\n                functions_with_same_imports.append(func_with_imports)\n\n        similar_imports_functions_code = ''\n        for func_with_imports in functions_with_same_imports:\n            similar_imports_functions_code += f\"\\n# Code for function '{func_with_imports['name']}' that uses similar imports:\\n{func_with_imports['code']}\\n\"\n\n        # Prepare the prompt\n        prompt = f\"\"\"\nYou are an expert Python programmer. Your task is to write detailed and working code for the following function based on the context provided. Do not provide placeholder code, but rather do your best like you are the best senior engineer in the world and provide the best code possible. DO NOT PROVIDE PLACEHOLDER CODE.\n\nFunction details:\n\nName: {function['name']}\nDescription: {function['description']}\nInput parameters: {function['input_parameters']}\nOutput parameters: {function['output_parameters']}\nDependencies: {function['dependencies']}\nImports: {function['imports']}\n\nOverall context:\n\n{context}\n\nDependency code:\n\n{dependency_code}\n\nCode from functions with similar imports:\n\n{similar_imports_functions_code}\n\nPlease provide the function details in JSON format, following this structure:\n\n{{\n  \"function_name\": \"<function_name>\",\n  \"metadata\": {{\n    \"description\": \"<function_description>\",\n    \"input_parameters\": {function['input_parameters']},\n    \"output_parameters\": {function['output_parameters']}\n  }},\n  \"code\": \"<function_code_as_string>\",\n  \"imports\": {function['imports']},\n  \"dependencies\": {function['dependencies']},\n  \"key_dependencies\": [],\n  \"triggers\": []\n}}\n\n**Example JSON Output:**\n\n{{\n  \"function_name\": \"example_function\",\n  \"metadata\": {{\n    \"description\": \"An example function.\",\n    \"input_parameters\": [{{\"name\": \"param1\", \"type\": \"str\"}}],\n    \"output_parameters\": [{{\"name\": \"result\", \"type\": \"str\"}}]\n  }},\n  \"code\": \"<complete function code goes here>\",\n  \"imports\": [\"os\"],\n  \"dependencies\": [],\n  \"key_dependencies\": [],\n  \"triggers\": []\n}}\n\nProvide the JSON output only, without any additional text. Do not provide placeholder code, but write complete code that is ready to run and provide the expected output.\n\nNow, please provide the JSON output for the function '{function['name']}'.\n\"\"\"\n\n        response = gpt_call(prompt)\n\n        try:\n            # Parse the JSON response\n            import json\n            function_data = json.loads(response)\n\n            # Return the parsed function data\n            return function_data\n        except json.JSONDecodeError as e:\n            # If parsing fails, retry\n            print(f\"JSON decoding error: {str(e)}\")\n            continue\n        except Exception as e:\n            print(f\"Error processing function data: {str(e)}\")\n            return None\n\n\n@func.register_function(\n    metadata={\"description\": \"Creates a new function if similar functions are not sufficient\"},\n    dependencies=[\"decide_imports_and_apis\", \"generate_function_code\",\"add_new_function\"]\n)\ndef create_function(function, context):\n    # Decide imports and APIs\n    imports_and_apis = decide_imports_and_apis(context)\n    function['imports'] = imports_and_apis.get('standard_imports', []) + imports_and_apis.get('external_imports', [])\n\n    # Update context with imports and APIs\n    context.update({'imports_and_apis': imports_and_apis})\n\n    # Generate function code\n    function_data = generate_function_code(function, context)\n\n    if function_data:\n        # Register the function using the parsed JSON data\n        add_new_function(\n            name=function_data['function_name'],\n            code=function_data['code'],\n            metadata=function_data['metadata'],\n            imports=function_data.get('imports', []),\n            dependencies=function_data.get('dependencies', []),\n            key_dependencies=function_data.get('key_dependencies', []),\n            triggers=function_data.get('triggers', [])\n        )\n\n        #print(f\"Function '{function_data['function_name']}' registered successfully.\")\n\n        return {\n            'name': function_data['function_name'],\n            'code': function_data['code'],\n            'metadata': function_data['metadata'],\n            'imports': function_data.get('imports', []),\n            'dependencies': function_data.get('dependencies', []),\n            'key_dependencies': function_data.get('key_dependencies', []),\n            'triggers': function_data.get('triggers', [])\n        }\n    else:\n        print(\"Failed to generate function code.\")\n        return None\n\n\n\n@func.register_function(\n  metadata={\"description\": \"Generates the required functions based on the breakdown\"},\n  dependencies=[\"find_similar_function\", \"create_function\", \"get_function_wrapper\"]\n)\ndef generate_functions(function_breakdown, context):\n  for function in function_breakdown:\n      function_name = function['name']\n      # Find similar functions\n      similar_functions = find_similar_function(function['description'])\n      function_found = False\n      for similar_function_name in similar_functions:\n          similar_function = get_function_wrapper(similar_function_name)\n          if similar_function and similar_function['metadata'].get('description', '') == function['description']:\n              function_found = True\n              break\n      if not function_found:\n          # Combine context for this function\n          function_context = context.copy()\n          function_context.update({'function': function})\n          create_function(function, function_context)\n\n@func.register_function(\n  metadata={\"description\": \"Runs the final function to produce the output for the user\"},\n  dependencies=[\"func\"]\n)\ndef run_final_function(function_name, *args, **kwargs):\n  result = func.execute_function(function_name, *args, **kwargs)\n  return result\n\n@func.register_function(\n    metadata={\"description\": \"Extracts parameters from user input for a given function\"},\n    dependencies=[\"gpt_call\", \"get_function_wrapper\"]\n)\ndef extract_function_parameters(user_input, function_name):\n    import json\n    # Get the function code and parameters\n    function = get_function_wrapper(function_name)\n    if not function:\n        print(f\"Function '{function_name}' not found.\")\n        return None\n\n    # Prepare the prompt to convert user input into function parameters\n    while True:\n        prompt = f\"\"\"\nYou are an expert assistant. The user wants to execute the following function:\n\nFunction code:\n{function['code']}\n\nFunction description:\n{function['metadata'].get('description', '')}\n\nFunction parameters:\n{function['metadata'].get('input_parameters', [])}\n\nThe user has provided the following input:\n\"{user_input}\"\n\nYour task is to extract the required parameters from the user's input and provide them in JSON format that matches the function's parameters.\n\nProvide your answer in the following JSON format:\n{{\n  \"parameters\": {{\n    \"param1\": value1,\n    \"param2\": value2,\n    ...\n  }}\n}}\n\nEnsure that the parameters match the function's required input parameters.\n\nExamples:\n\nExample 1:\n\nFunction code:\ndef add_numbers(a, b):\n    return a + b\n\nFunction parameters:\n[{{\"name\": \"a\", \"type\": \"int\"}}, {{\"name\": \"b\", \"type\": \"int\"}}]\n\nUser input: \"Add 5 and 3\"\n\nResponse:\n{{\n  \"parameters\": {{\n    \"a\": 5,\n    \"b\": 3\n  }}\n}}\n\nExample 2:\n\nFunction code:\ndef greet_user(name):\n    return f\"Hello, {{name}}!\"\n\nFunction parameters:\n[{{\"name\": \"name\", \"type\": \"str\"}}]\n\nUser input: \"Say hello to Alice\"\n\nResponse:\n{{\n  \"parameters\": {{\n    \"name\": \"Alice\"\n  }}\n}}\n\nNow, using the function provided and the user's input, extract the parameters and provide the JSON response.\n\"\"\"\n        response = gpt_call(prompt)\n\n        # Try to parse the JSON response\n        try:\n            result = json.loads(response)\n            if 'parameters' in result and isinstance(result['parameters'], dict):\n                return result['parameters']\n            else:\n                raise ValueError(\"Invalid JSON structure\")\n        except Exception as e:\n            # If parsing fails, retry\n            continue\n\n@func.register_function(\n    metadata={\"description\": \"Main function to process user input and generate the required functions\"},\n    dependencies=[\"check_existing_functions\", \"break_down_task\", \"generate_functions\", \"run_final_function\", \"extract_function_parameters\"]\n)\ndef process_user_input(user_input):\n    # First, check if an existing function satisfies the user input\n    print(\"\\033[1;95mProcessing user input: \", user_input, \"\\033[0m\")\n    result = check_existing_functions(user_input)\n    if result['function_found']:\n        function_name = result['function_name']\n    else:\n        # Break down the task into functions\n        function_breakdown = break_down_task(user_input)\n        # Context to be passed around\n        context = {'user_input': user_input, 'function_breakdown': function_breakdown}\n        # Generate the required functions\n        generate_functions(function_breakdown, context)\n        # Assume the main function is the first one in the breakdown\n        function_name = function_breakdown[0]['name']\n\n    # Extract parameters from user input for the function\n    parameters = extract_function_parameters(user_input, function_name)\n    if parameters is None:\n        print(\"Failed to extract parameters from user input.\")\n        return None\n\n    # Call the function with the parameters\n    output = run_final_function(function_name, **parameters)\n    return output\n\n\n"
  },
  {
    "path": "babyagi/functionz/packs/drafts/generate_function.py",
    "content": "\nfrom functionz.core.framework import func\n\n# Function 1: Fetch existing functions\n@func.register_function(\n    metadata={\"description\": \"Fetch existing functions using display_functions_wrapper.\"},\n    dependencies=[\"display_functions_wrapper\"],\n    imports=[\n        {\"name\": \"json\", \"lib\": \"json\"}\n    ]\n)\ndef fetch_existing_functions(description: str) -> dict:\n    \"\"\"\n    Fetches existing functions and returns them along with the initial intermediate_steps.\n\n    Args:\n        description (str): User description of the function to generate.\n\n    Returns:\n        dict: A dictionary containing existing functions and intermediate steps.\n    \"\"\"\n    intermediate_steps = []\n    try:\n        existing_functions = display_functions_wrapper()\n        print(f\"[DEBUG] Existing Functions: {existing_functions}\")\n        intermediate_steps.append({\"step\": \"Fetch Existing Functions\", \"content\": existing_functions})\n        return {\"existing_functions\": existing_functions, \"intermediate_steps\": intermediate_steps}\n    except Exception as e:\n        print(f\"[ERROR] Failed to fetch existing functions: {e}\")\n        intermediate_steps.append({\"step\": \"Error Fetching Existing Functions\", \"content\": str(e)})\n        return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error fetching existing functions.\"}\n\n# Function 2: Analyze internal functions\n@func.register_function(\n    metadata={\"description\": \"Analyze internal functions and identify reusable and reference functions.\"},\n    dependencies=[\"litellm\", \"FunctionSuggestion\"],\n    imports=[\n        {\"name\": \"litellm\", \"lib\": \"litellm\"},\n        {\"name\": \"pydantic\", \"lib\": \"pydantic\"},\n        {\"name\": \"typing\", \"lib\": \"typing\"},\n        {\"name\": \"json\", \"lib\": \"json\"},\n    ]\n)\ndef analyze_internal_functions(description: str, existing_functions: str, intermediate_steps: list) -> dict:\n    \"\"\"\n    Analyzes existing functions to identify reusable and reference functions.\n\n    Args:\n        description (str): User description of the function to generate.\n        existing_functions (str): Existing functions obtained from the previous step.\n        intermediate_steps (list): List of intermediate steps.\n\n    Returns:\n        dict: A dictionary containing updated intermediate steps, reusable_functions, and reference_functions.\n    \"\"\"\n    from litellm import completion\n    from pydantic import BaseModel, Field, ValidationError\n    from typing import List\n    import json\n\n    # Define Pydantic model for parsing internal function responses\n    class FunctionSuggestion(BaseModel):\n        reusable_functions: List[str] = Field(default_factory=list)\n        reference_functions: List[str] = Field(default_factory=list)\n\n    # System prompt for code generation adhering to the functionz framework guidelines.\n    system_prompt = \"\"\"\n    You are an AI designed to help developers write Python functions using the functionz framework. Every function you generate must adhere to the following rules:\n\n    Function Registration: All functions must be registered with the functionz framework using the @babyagi.register_function() decorator. Each function can include metadata, dependencies, imports, and key dependencies.\n\n    Basic Function Registration Example:\n\n    def function_name(param1, param2):\n        # function logic here\n        return result\n\n    Metadata and Dependencies: When writing functions, you may include optional metadata (such as descriptions) and dependencies. Dependencies can be other functions or secrets (API keys, etc.).\n\n    Import Handling: Manage imports by specifying them in the decorator as dictionaries with 'name' and 'lib' keys. Include these imports within the function body.\n\n    Secret Management: When using API keys or authentication secrets, reference the stored key with globals()['key_name'].\n\n    Error Handling: Functions should handle errors gracefully, catching exceptions if necessary.\n\n    General Guidelines: Use simple, clean, and readable code. Follow the structure and syntax of the functionz framework. Ensure proper function documentation via metadata.\n    \"\"\"\n\n    display_prompt = f\"\"\"You are an assistant helping a developer build a function using the functionz framework.\n\n    The user has provided the following function description: {description}\n\n    The current available functions are listed below. Please specify if any of these functions can be used directly (for reuse), or if any should be referenced while building the new function. Return your response as structured JSON.\n\n    Available Functions:\n    {existing_functions}\n    \"\"\"\n\n    # Step 2.1: Make the LLM call using JSON mode with Pydantic model\n    try:\n        display_response = completion(\n            model=\"gpt-4o-mini\",\n            messages=[\n                {\"role\": \"system\", \"content\": system_prompt},\n                {\"role\": \"user\", \"content\": display_prompt}\n            ],\n            response_format=FunctionSuggestion\n        )\n        print(f\"[DEBUG] Display Response: {display_response}\")\n    except Exception as e:\n        print(f\"[ERROR] LLM call for FunctionSuggestion failed: {e}\")\n        intermediate_steps.append({\"step\": \"Error in FunctionSuggestion LLM Call\", \"content\": str(e)})\n        return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error during FunctionSuggestion analysis.\"}\n\n    # Step 2.2: Access and parse the response\n    try:\n        content = display_response.choices[0].message.content\n        print(f\"[DEBUG] Raw Display Content: {content}\")\n        display_response_parsed = FunctionSuggestion.parse_raw(content)\n        print(f\"[DEBUG] Parsed FunctionSuggestion: {display_response_parsed}\")\n        intermediate_steps.append({\"step\": \"Analyze Internal Functions\", \"content\": display_response_parsed.dict()})\n    except (ValidationError, IndexError, AttributeError, json.JSONDecodeError) as e:\n        print(f\"[ERROR] Parsing FunctionSuggestion response failed: {e}\")\n        intermediate_steps.append({\"step\": \"Error Parsing FunctionSuggestion Response\", \"content\": str(e)})\n        return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error parsing FunctionSuggestion response.\"}\n\n    reusable_functions = display_response_parsed.reusable_functions\n    reference_functions = display_response_parsed.reference_functions\n    print(f\"[DEBUG] Reusable Functions: {reusable_functions}\")\n    print(f\"[DEBUG] Reference Functions: {reference_functions}\")\n\n    return {\n        \"intermediate_steps\": intermediate_steps,\n        \"reusable_functions\": reusable_functions,\n        \"reference_functions\": reference_functions\n    }\n\n# Function 3: Fetch function codes\n@func.register_function(\n    metadata={\"description\": \"Fetch function codes for given function names using get_function_wrapper.\"},\n    dependencies=[\"get_function_wrapper\"],\n    imports=[\n        {\"name\": \"json\", \"lib\": \"json\"},\n        {\"name\": \"typing\", \"lib\": \"typing\"},\n    ]\n)\ndef fetch_function_codes(function_names, intermediate_steps):\n    \"\"\"\n    Fetches function codes for given function names.\n\n    Args:\n        function_names (List[str]): List of function names to fetch.\n        intermediate_steps (list): List of intermediate steps.\n\n    Returns:\n        dict: A dictionary containing updated intermediate steps and function_codes.\n    \"\"\"\n    from typing import List\n    try:\n        function_codes = {\n            func_name: get_function_wrapper(func_name).get(\"code\", \"\")\n            for func_name in function_names\n        }\n        print(f\"[DEBUG] Function Codes: {function_codes}\")\n        intermediate_steps.append({\"step\": \"Fetch Function Codes\", \"content\": function_codes})\n        return {\n            \"intermediate_steps\": intermediate_steps,\n            \"function_codes\": function_codes\n        }\n    except Exception as e:\n        print(f\"[ERROR] Fetching function codes failed: {e}\")\n        intermediate_steps.append({\"step\": \"Error Fetching Function Codes\", \"content\": str(e)})\n        return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error fetching function codes.\"}\n\n# Function 4: Determine required external APIs\n@func.register_function(\n    metadata={\"description\": \"Determine required external APIs based on the user's function description.\"},\n    dependencies=[\"litellm\"],\n    imports=[\n        {\"name\": \"litellm\", \"lib\": \"litellm\"},\n        {\"name\": \"pydantic\", \"lib\": \"pydantic\"},\n        {\"name\": \"typing\", \"lib\": \"typing\"},\n        {\"name\": \"json\", \"lib\": \"json\"},\n    ]\n)\ndef determine_required_external_apis(description: str, intermediate_steps: list) -> dict:\n    \"\"\"\n    Determines required external APIs based on the user's function description.\n\n    Args:\n        description (str): User description of the function to generate.\n        intermediate_steps (list): List of intermediate steps.\n\n    Returns:\n        dict: A dictionary containing updated intermediate steps and external_apis as a list of dictionaries.\n    \"\"\"\n    from litellm import completion\n    from pydantic import BaseModel, Field, ValidationError, validator\n    from typing import List, Optional, Union\n    import json\n\n    # Define Pydantic models\n    class Endpoint(BaseModel):\n        method: Optional[str]\n        url: str\n        description: Optional[str] = None\n\n    class APIDetails(BaseModel):\n        api_name: str = Field(alias=\"name\")  # Use alias to map 'name' to 'api_name'\n        purpose: str\n        endpoints: Optional[List[Union[Endpoint, str]]] = Field(default_factory=list)\n\n        @validator(\"endpoints\", pre=True, each_item=True)\n        def convert_to_endpoint(cls, v):\n            \"\"\"Convert string URLs into Endpoint objects if necessary.\"\"\"\n            if isinstance(v, str):\n                return Endpoint(url=v)  # Create an Endpoint object from a URL string\n            return v\n\n    class APIResponse(BaseModel):\n        name: str\n        purpose: str\n        endpoints: List[Endpoint]\n\n    # System prompt\n    system_prompt = \"\"\"\n    [Your existing system prompt here]\n    \"\"\"\n\n    prompt_for_apis = f\"\"\"You are an assistant analyzing function requirements.\n\n    The user has provided the following function description: {description}.\n\n    Identify if this function will require external APIs (including SDKs or libraries). If so, return a structured JSON with a list of external APIs, their purposes, and any relevant endpoints.\"\"\"\n\n    try:\n        api_response = completion(\n            model=\"gpt-4o-mini\",\n            messages=[\n                {\"role\": \"system\", \"content\": system_prompt},\n                {\"role\": \"user\", \"content\": prompt_for_apis}\n            ],\n            response_format=APIDetails\n        )\n        print(f\"[DEBUG] API Response: {api_response}\")\n    except Exception as e:\n        print(f\"[ERROR] LLM call for APIResponse failed: {e}\")\n        intermediate_steps.append({\"step\": \"Error in APIResponse LLM Call\", \"content\": str(e)})\n        return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error during APIResponse analysis.\"}\n\n    # Step 3.2: Access and parse the API response\n    try:\n        content = api_response.choices[0].message.content\n        print(f\"[DEBUG] Raw API Content: {content}\")\n        api_response_parsed = APIResponse.parse_raw(content)\n        print(f\"[DEBUG] Parsed APIResponse: {api_response_parsed}\")\n        intermediate_steps.append({\"step\": \"Identify External API\", \"content\": api_response_parsed.dict()})\n\n        # Ensure external_apis is always a list\n        external_apis = [api_response_parsed.dict()]  # Wrap in a list\n    except (ValidationError, IndexError, AttributeError, json.JSONDecodeError) as e:\n        print(f\"[ERROR] Parsing APIResponse failed: {e}\")\n        intermediate_steps.append({\"step\": \"Error Parsing APIResponse\", \"content\": str(e)})\n        return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error parsing APIResponse.\"}\n\n    return {\n        \"intermediate_steps\": intermediate_steps,\n        \"external_apis\": external_apis  # Now a list of dicts\n    }\n\n\n\n# Function 5: Handle API documentation and extraction\n@func.register_function(\n    metadata={\"description\": \"Search API documentation and extract relevant information.\"},\n    dependencies=[\"serpapi_search_v2\", \"scrape_website\", \"litellm\"],\n    key_dependencies=[\"serpapi_api_key\", \"firecrawl_api_key\"],\n    imports=[\n        {\"name\": \"litellm\", \"lib\": \"litellm\"},\n        {\"name\": \"pydantic\", \"lib\": \"pydantic\"},\n        {\"name\": \"typing\", \"lib\": \"typing\"},\n        {\"name\": \"json\", \"lib\": \"json\"},\n        {\"name\": \"urllib\", \"lib\": \"urllib\"},\n    ]\n)\ndef handle_api_documentation(api_name: str, description: str, intermediate_steps: list) -> dict:\n    \"\"\"\n    Searches API documentation for a given API and extracts relevant information.\n\n    Args:\n        api_name (str): Name of the API to search for.\n        description (str): User description of the function to generate.\n        intermediate_steps (list): List of intermediate steps.\n\n    Returns:\n        dict: A dictionary containing updated intermediate steps and api_contexts.\n    \"\"\"\n    from litellm import completion\n    from pydantic import BaseModel, Field, ValidationError\n    from typing import List\n    import json\n    from urllib.parse import urlparse\n\n    # Define Pydantic models\n    class URLSelection(BaseModel):\n        selected_urls: List[str] = Field(default_factory=list)\n\n    # Updated ExtractionInfo model with 'requires_more_info'\n    class ExtractionInfo(BaseModel):\n        relevant_info: str\n        additional_urls: List[str] = Field(default_factory=list)\n        requires_more_info: bool\n\n    # System prompt\n    system_prompt = \"\"\"\n    You are an AI designed to help developers write Python functions using the functionz framework. Every function you generate must adhere to the following rules:\n\n    Function Registration: All functions must be registered with the functionz framework using the @babyagi.register_function() decorator. Each function can include metadata, dependencies, imports, and key dependencies.\n\n    Basic Function Registration Example:\n\n    def function_name(param1, param2):\n        # function logic here\n        return result\n\n    Metadata and Dependencies: When writing functions, you may include optional metadata (such as descriptions) and dependencies. Dependencies can be other functions or secrets (API keys, etc.).\n\n    Import Handling: Manage imports by specifying them in the decorator as dictionaries with 'name' and 'lib' keys. Include these imports within the function body.\n\n    Secret Management: When using API keys or authentication secrets, reference the stored key with globals()['key_name'].\n\n    Error Handling: Functions should handle errors gracefully, catching exceptions if necessary.\n\n    General Guidelines: Use simple, clean, and readable code. Follow the structure and syntax of the functionz framework. Ensure proper function documentation via metadata.\n    \"\"\"\n\n    # Function to check if a URL is valid\n    def is_valid_url(url: str) -> bool:\n        try:\n            result = urlparse(url)\n            return all([result.scheme, result.netloc])\n        except ValueError:\n            return False\n\n    # Function to chunk text\n    def chunk_text(text: str, chunk_size: int = 100000, overlap: int = 10000) -> List[str]:\n        chunks = []\n        start = 0\n        while start < len(text):\n            end = start + chunk_size\n            if end < len(text):\n                # Find the last newline within the overlap\n                last_newline = text.rfind('\\n', end - overlap, end)\n                if last_newline != -1:\n                    end = last_newline + 1\n            chunks.append(text[start:end])\n            start = end - overlap\n        return chunks\n\n    search_query = f\"{api_name} API documentation python\"\n    print(f\"[DEBUG] Searching for API documentation with query: {search_query}\")\n    try:\n        search_results = serpapi_search_v2(query=search_query)\n        print(f\"[DEBUG] Search Results for {api_name}: {search_results}\")\n        intermediate_steps.append({\"step\": f\"Search API Documentation for {api_name}\", \"content\": search_results})\n    except Exception as e:\n        print(f\"[ERROR] serpapi_search_v2 failed for {api_name}: {e}\")\n        intermediate_steps.append({\"step\": f\"Error Searching API Documentation for {api_name}\", \"content\": str(e)})\n        return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error searching API documentation.\"}\n\n    link_selection_prompt = f\"\"\"You are given the following search results for the query \"{search_query}\":\n    {json.dumps(search_results)}\n\n    Which links seem most relevant for obtaining Python API documentation? Return them as a structured JSON list of URLs.\"\"\"\n\n    try:\n        link_selection_response = completion(\n            model=\"gpt-4o-mini\",\n            messages=[\n                {\"role\": \"system\", \"content\": system_prompt},\n                {\"role\": \"user\", \"content\": link_selection_prompt}\n            ],\n            response_format=URLSelection\n        )\n        print(f\"[DEBUG] Link Selection Response for {api_name}: {link_selection_response}\")\n    except Exception as e:\n        print(f\"[ERROR] LLM call for URLSelection failed for {api_name}: {e}\")\n        intermediate_steps.append({\"step\": f\"Error in URLSelection LLM Call for {api_name}\", \"content\": str(e)})\n        return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error in URLSelection LLM call.\"}\n\n    # Step 4.2: Access and parse the link selection response\n    try:\n        content = link_selection_response.choices[0].message.content\n        print(f\"[DEBUG] Raw Link Selection Content for {api_name}: {content}\")\n        link_selection_parsed = URLSelection.parse_raw(content)\n        print(f\"[DEBUG] Parsed URLSelection for {api_name}: {link_selection_parsed}\")\n        intermediate_steps.append({\"step\": f\"Select Relevant URLs for {api_name}\", \"content\": link_selection_parsed.dict()})\n    except (ValidationError, IndexError, AttributeError, json.JSONDecodeError) as e:\n        print(f\"[ERROR] Parsing URLSelection response for {api_name} failed: {e}\")\n        intermediate_steps.append({\"step\": f\"Error Parsing URLSelection Response for {api_name}\", \"content\": str(e)})\n        return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error parsing URLSelection response.\"}\n\n    selected_urls = link_selection_parsed.selected_urls or []\n    print(f\"[DEBUG] Selected URLs for {api_name}: {selected_urls}\")\n    scraped_urls = set()\n    api_scrape_info = {}\n    api_contexts = []\n    accumulated_info = \"\"  # To accumulate relevant info\n\n    requires_more_info = True  # Initialize to True to start the loop\n\n    # Step 5: Scrape and recursively explore additional URLs until no more info is needed\n    while selected_urls and requires_more_info:\n        current_url = selected_urls.pop(0)\n        print(f\"[DEBUG] Scraping URL: {current_url}\")\n        if current_url in scraped_urls or not is_valid_url(current_url):\n            print(f\"[DEBUG] URL already scraped or invalid: {current_url}\")\n            continue\n\n        try:\n            scrape_result = scrape_website(current_url)\n            print(f\"[DEBUG] Scrape Result for {current_url}: {scrape_result}\")\n        except Exception as e:\n            print(f\"[ERROR] scrape_website failed for {current_url}: {e}\")\n            intermediate_steps.append({\"step\": f\"Error Scraping URL: {current_url}\", \"content\": str(e)})\n            continue  # Skip to the next URL\n\n        scraped_urls.add(current_url)\n        if not scrape_result.get(\"error\"):\n            api_scrape_info[current_url] = scrape_result\n            intermediate_steps.append({\"step\": f\"Scrape URL: {current_url}\", \"content\": scrape_result})\n        else:\n            print(f\"[WARN] Error in scrape_result for {current_url}: {scrape_result.get('error')}\")\n            intermediate_steps.append({\"step\": f\"Scrape Error for URL: {current_url}\", \"content\": scrape_result.get(\"error\")})\n            continue  # Skip to the next URL\n\n        # Step 6: Use LLM to extract relevant info and decide if more info is needed\n        extraction_prompt = f\"\"\"The user wants to create a function described as follows: {description}.\nYou have accumulated the following relevant API information so far:\n{accumulated_info}\n\nYou have just scraped the following new API documentation:\n{json.dumps(scrape_result)}\n\nBased on the new information, extract any additional relevant API methods, endpoints, and usage patterns needed to implement the user's function. Indicate whether more information is required by setting 'requires_more_info' to true or false. If any other URLs should be scraped for further information, include them in the 'additional_urls' field.\"\"\"\n\n        # Chunk the extraction prompt if it's too long\n        extraction_prompt_chunks = chunk_text(extraction_prompt)\n        extraction_results = []\n\n        for chunk in extraction_prompt_chunks:\n            try:\n                extraction_response = completion(\n                    model=\"gpt-4o-mini\",\n                    messages=[\n                        {\"role\": \"system\", \"content\": system_prompt},\n                        {\"role\": \"user\", \"content\": chunk}\n                    ],\n                    response_format=ExtractionInfo\n                )\n                print(f\"[DEBUG] Extraction Response: {extraction_response}\")\n                extraction_results.append(extraction_response)\n            except Exception as e:\n                print(f\"[ERROR] LLM call for ExtractionInfo failed: {e}\")\n                intermediate_steps.append({\"step\": \"Error in ExtractionInfo LLM Call\", \"content\": str(e)})\n                continue  # Skip to the next chunk\n\n        # Combine extraction results\n        combined_extraction = {\n            \"relevant_info\": \"\",\n            \"additional_urls\": [],\n            \"requires_more_info\": False\n        }\n        for result in extraction_results:\n            try:\n                content = result.choices[0].message.content\n                parsed_result = ExtractionInfo.parse_raw(content)\n                combined_extraction[\"relevant_info\"] += parsed_result.relevant_info + \"\\n\"\n                combined_extraction[\"additional_urls\"].extend(parsed_result.additional_urls)\n                if parsed_result.requires_more_info:\n                    combined_extraction[\"requires_more_info\"] = True\n            except (ValidationError, IndexError, AttributeError, json.JSONDecodeError) as e:\n                print(f\"[ERROR] Parsing ExtractionInfo response failed: {e}\")\n                intermediate_steps.append({\"step\": \"Error Parsing ExtractionInfo Response\", \"content\": str(e)})\n\n        # Update accumulated info\n        accumulated_info += combined_extraction[\"relevant_info\"]\n        print(f\"[DEBUG] Updated Accumulated Info: {accumulated_info}\")\n\n        # Include extracted info in API contexts\n        api_contexts.append(combined_extraction[\"relevant_info\"])\n        print(f\"[DEBUG] Updated API Contexts: {api_contexts}\")\n\n        # Queue additional URLs for scraping\n        new_urls = [url for url in combined_extraction[\"additional_urls\"] if url not in scraped_urls and is_valid_url(url)]\n        print(f\"[DEBUG] New URLs to Scrape: {new_urls}\")\n        selected_urls.extend(new_urls)\n\n        # Check if more information is required\n        requires_more_info = combined_extraction[\"requires_more_info\"]\n        print(f\"[DEBUG] Requires More Info: {requires_more_info}\")\n\n    return {\n        \"intermediate_steps\": intermediate_steps,\n        \"api_contexts\": api_contexts\n    }\n\n\n# Function 6: Generate final function code\n@func.register_function(\n    metadata={\"description\": \"Generate the final function code using all gathered information.\"},\n    dependencies=[\"litellm\"],\n    imports=[\n        {\"name\": \"litellm\", \"lib\": \"litellm\"},\n        {\"name\": \"json\", \"lib\": \"json\"},\n        {\"name\": \"typing\", \"lib\": \"typing\"},\n    ]\n)\ndef generate_final_function_code(description: str, reusable_function_code: dict, reference_function_code: dict, api_contexts: list, intermediate_steps: list) -> dict:\n    \"\"\"\n    Generates the final function code using all gathered information.\n\n    Args:\n        description (str): User description of the function to generate.\n        reusable_function_code (dict): Codes of reusable functions.\n        reference_function_code (dict): Codes of reference functions.\n        api_contexts (list): List of API contexts.\n        intermediate_steps (list): List of intermediate steps.\n\n    Returns:\n        dict: A dictionary containing updated intermediate steps and the combined final function details.\n    \"\"\"\n    from litellm import completion\n    from pydantic import BaseModel, Field, ValidationError\n    from typing import Dict, Any, List, Optional\n    import json\n\n    # Define Pydantic model\n    class GeneratedFunction(BaseModel):\n        name: str\n        code: str\n        metadata: Optional[Dict[str, Any]] = Field(default_factory=dict)\n        imports: Optional[List[Dict[str, str]]] = Field(default_factory=list)\n        dependencies: List[str] = Field(default_factory=list)\n        key_dependencies: List[str] = Field(default_factory=list)\n        triggers: List[str] = Field(default_factory=list)\n\n        class Config:\n            extra = \"forbid\"\n\n    # System prompt\n    system_prompt = \"\"\"\n    You are an AI designed to help developers write Python functions using the functionz framework. Every function you generate must adhere to the following rules:\n\n    Function Registration: All functions must be registered with the functionz framework using the @babyagi.register_function() decorator. Each function can include metadata, dependencies, imports, and key dependencies.\n\n    Basic Function Registration Example:\n\n    def function_name(param1, param2):\n        # function logic here\n        return result\n\n    Metadata and Dependencies: When writing functions, you may include optional metadata (such as descriptions) and dependencies. Dependencies can be other functions or secrets (API keys, etc.).\n\n    Import Handling: Manage imports by specifying them in the decorator as dictionaries with 'name' and 'lib' keys. Include these imports within the function body.\n\n    Secret Management: When using API keys or authentication secrets, reference the stored key with globals()['key_name'].\n\n    Error Handling: Functions should handle errors gracefully, catching exceptions if necessary.\n\n    General Guidelines: Use simple, clean, and readable code. Follow the structure and syntax of the functionz framework. Ensure proper function documentation via metadata.\n    \"\"\"\n\n    # Function to chunk text\n    def chunk_text(text: str, chunk_size: int = 100000, overlap: int = 10000) -> List[str]:\n        chunks = []\n        start = 0\n        while start < len(text):\n            end = start + chunk_size\n            if end < len(text):\n                # Find the last newline within the overlap\n                last_newline = text.rfind('\\n', end - overlap, end)\n                if last_newline != -1:\n                    end = last_newline + 1\n            chunks.append(text[start:end])\n            start = end - overlap\n        return chunks\n\n    final_prompt = f\"\"\"{system_prompt}\n\n    The user wants to create a function with the following description: {description}.\n\n    You have the following internal reusable functions:\n    {json.dumps(reusable_function_code)}\n\n    You have the following internal reference functions:\n    {json.dumps(reference_function_code)}\n\n    You have the following context on the necessary external APIs and their usage:\n    {json.dumps(api_contexts)}\n\n    Generate a complete function using the functionz framework that adheres to the provided guidelines and utilizes the specified internal and external functions. Ensure the function is registered with the correct metadata, dependencies, and includes all relevant imports.\n\n    Provide the function details in a structured format including:\n    1. Function name\n    2. Complete function code (do not the @babyagi.register_function decorator)\n    3. Metadata (description)\n    4. Imports\n    5. Dependencies\n    6. Key dependencies\n    7. Triggers (if any)\n    \"\"\"\n\n    # Chunk the final prompt if it's too long\n    final_prompt_chunks = chunk_text(final_prompt)\n    final_results = []\n\n    for chunk in final_prompt_chunks:\n        try:\n            final_response = completion(\n                model=\"gpt-4o-mini\",\n                messages=[\n                    {\"role\": \"system\", \"content\": system_prompt},\n                    {\"role\": \"user\", \"content\": chunk}\n                ],\n                response_format=GeneratedFunction\n            )\n            print(f\"[DEBUG] Final Response: {final_response}\")\n            final_results.append(final_response)\n        except Exception as e:\n            print(f\"[ERROR] LLM call for GeneratedFunction failed: {e}\")\n            intermediate_steps.append({\"step\": \"Error in GeneratedFunction LLM Call\", \"content\": str(e)})\n            return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error during GeneratedFunction generation.\"}\n\n    # Combine final results\n    combined_final = {\n        \"name\": \"\",\n        \"code\": \"\",\n        \"metadata\": {},\n        \"imports\": [],\n        \"dependencies\": [],\n        \"key_dependencies\": [],\n        \"triggers\": []\n    }\n    for result in final_results:\n        try:\n            content = result.choices[0].message.content\n            parsed_result = GeneratedFunction.parse_raw(content)\n            if not combined_final[\"name\"]:\n                combined_final[\"name\"] = parsed_result.name\n            combined_final[\"code\"] += parsed_result.code + \"\\n\"\n            if parsed_result.metadata:\n                combined_final[\"metadata\"].update(parsed_result.metadata or {})\n            if parsed_result.imports:\n                combined_final[\"imports\"].extend(parsed_result.imports)\n            if parsed_result.dependencies:\n                combined_final[\"dependencies\"].extend(parsed_result.dependencies)\n            if parsed_result.key_dependencies:\n                combined_final[\"key_dependencies\"].extend(parsed_result.key_dependencies)\n            if parsed_result.triggers:\n                combined_final[\"triggers\"].extend(parsed_result.triggers)\n\n        except (ValidationError, IndexError, AttributeError, json.JSONDecodeError) as e:\n            print(f\"[ERROR] Parsing GeneratedFunction response failed: {e}\")\n            intermediate_steps.append({\"step\": \"Error Parsing GeneratedFunction Response\", \"content\": str(e)})\n            return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error parsing GeneratedFunction response.\"}\n\n    # Remove duplicates from lists\n    combined_final[\"imports\"] = list({json.dumps(imp): imp for imp in combined_final[\"imports\"]}.values())\n    combined_final[\"dependencies\"] = list(set(combined_final[\"dependencies\"]))\n    combined_final[\"key_dependencies\"] = list(set(combined_final[\"key_dependencies\"]))\n    combined_final[\"triggers\"] = list(set(combined_final[\"triggers\"]))\n\n    print(f\"[DEBUG] Combined Final GeneratedFunction: {combined_final}\")\n    intermediate_steps.append({\"step\": \"Generate Final Function\", \"content\": combined_final})\n\n    return {\n        \"intermediate_steps\": intermediate_steps,\n        \"combined_final\": combined_final\n    }\n\n# Function 7: Add function to database\n@func.register_function(\n    metadata={\"description\": \"Add the generated function to the database.\"},\n    dependencies=[\"add_new_function\"],\n    imports=[\n        {\"name\": \"json\", \"lib\": \"json\"},\n    ]\n)\ndef add_function_to_database(combined_final: dict, intermediate_steps: list) -> dict:\n    \"\"\"\n    Adds the generated function to the database.\n\n    Args:\n        combined_final (dict): The combined final function details.\n        intermediate_steps (list): List of intermediate steps.\n\n    Returns:\n        dict: A dictionary containing updated intermediate steps and the success status.\n    \"\"\"\n    try:\n        success = add_new_function(\n            name=combined_final[\"name\"],\n            code=combined_final[\"code\"],\n            metadata=combined_final[\"metadata\"],\n            imports=combined_final[\"imports\"],\n            dependencies=combined_final[\"dependencies\"],\n            key_dependencies=combined_final[\"key_dependencies\"],\n            triggers=combined_final[\"triggers\"]\n        )\n        intermediate_steps.append({\"step\": \"Add Function to Database\", \"content\": {\"success\": success}})\n    except Exception as e:\n        print(f\"[ERROR] Failed to add function to database: {e}\")\n        intermediate_steps.append({\"step\": \"Error Adding Function to Database\", \"content\": str(e)})\n        success = False\n\n    return {\n        \"intermediate_steps\": intermediate_steps,\n        \"success\": success\n    }\n\n# Main Function: Orchestrate all steps\n@func.register_function(\n    metadata={\"description\": \"Main function to generate a function from a description.\"},\n    dependencies=[\n        \"fetch_existing_functions\",\n        \"analyze_internal_functions\",\n        \"fetch_function_codes\",\n        \"determine_required_external_apis\",\n        \"handle_api_documentation\",\n        \"generate_final_function_code\",\n        \"add_function_to_database\"\n    ],\n    imports=[\n        {\"name\": \"json\", \"lib\": \"json\"},\n        {\"name\": \"typing\", \"lib\": \"typing\"},\n    ]\n)\ndef generate_function_from_description(description: str) -> dict:\n    \"\"\"\n    Main function that generates a Python function based on a user-provided description.\n\n    Args:\n        description (str): User description of the function to generate.\n\n    Returns:\n        dict: A dictionary containing intermediate steps, the final generated function code, and whether it was successfully added to the database.\n    \"\"\"\n    intermediate_steps = []\n\n    # Step 1: Fetch existing functions\n    result = fetch_existing_functions(description)\n    if \"error\" in result:\n        return {\"intermediate_steps\": result[\"intermediate_steps\"], \"final_code\": result[\"error\"], \"added_to_database\": False}\n    existing_functions = result[\"existing_functions\"]\n    intermediate_steps.extend(result[\"intermediate_steps\"])\n\n    # Step 2: Analyze internal functions\n    result = analyze_internal_functions(description, existing_functions, intermediate_steps)\n    if \"error\" in result:\n        return {\"intermediate_steps\": result[\"intermediate_steps\"], \"final_code\": result[\"error\"], \"added_to_database\": False}\n    intermediate_steps = result[\"intermediate_steps\"]\n    reusable_functions = result[\"reusable_functions\"]\n    reference_functions = result[\"reference_functions\"]\n\n    # Step 3: Fetch function codes for reusable and reference functions\n    reusable_function_code = {}\n    if reusable_functions:\n        result = fetch_function_codes(reusable_functions, intermediate_steps)\n        if \"error\" in result:\n            return {\"intermediate_steps\": result[\"intermediate_steps\"], \"final_code\": result[\"error\"], \"added_to_database\": False}\n        intermediate_steps = result[\"intermediate_steps\"]\n        reusable_function_code = result[\"function_codes\"]\n\n    reference_function_code = {}\n    if reference_functions:\n        result = fetch_function_codes(reference_functions, intermediate_steps)\n        if \"error\" in result:\n            return {\"intermediate_steps\": result[\"intermediate_steps\"], \"final_code\": result[\"error\"], \"added_to_database\": False}\n        intermediate_steps = result[\"intermediate_steps\"]\n        reference_function_code = result[\"function_codes\"]\n\n    # Step 4: Determine required external APIs\n    result = determine_required_external_apis(description, intermediate_steps)\n    if \"error\" in result:\n        return {\"intermediate_steps\": result[\"intermediate_steps\"], \"final_code\": result[\"error\"], \"added_to_database\": False}\n    intermediate_steps = result[\"intermediate_steps\"]\n    external_apis_dicts = result[\"external_apis\"]\n\n    # Ensure external_apis_dicts is a list\n    if not isinstance(external_apis_dicts, list):\n        external_apis_dicts = [external_apis_dicts]\n\n    # Reconstruct APIResponse objects from dicts\n    from typing import Optional, List\n    from pydantic import BaseModel\n\n    class Endpoint(BaseModel):\n        method: Optional[str]\n        url: str\n        description: Optional[str] = None\n\n    class APIResponse(BaseModel):\n        name: str\n        purpose: str\n        endpoints: List[Endpoint]\n\n    external_apis = []\n    for api_dict in external_apis_dicts:\n        api_response_parsed = APIResponse(**api_dict)\n        external_apis.append(api_response_parsed)\n\n    # Step 5: Handle API documentation and extract contexts\n    api_contexts = []\n    for api_response_parsed in external_apis:\n        api_name = api_response_parsed.name\n        result = handle_api_documentation(api_name, description, intermediate_steps)\n        if \"error\" in result:\n            return {\"intermediate_steps\": result[\"intermediate_steps\"], \"final_code\": result[\"error\"], \"added_to_database\": False}\n        intermediate_steps = result[\"intermediate_steps\"]\n        api_contexts.extend(result[\"api_contexts\"])\n\n    # Step 6: Generate final function code\n    result = generate_final_function_code(description, reusable_function_code, reference_function_code, api_contexts, intermediate_steps)\n    if \"error\" in result:\n        return {\"intermediate_steps\": result[\"intermediate_steps\"], \"final_code\": result[\"error\"], \"added_to_database\": False}\n    intermediate_steps = result[\"intermediate_steps\"]\n    combined_final = result[\"combined_final\"]\n\n    # Step 7: Add function to database\n    result = add_function_to_database(combined_final, intermediate_steps)\n    intermediate_steps = result[\"intermediate_steps\"]\n    success = result[\"success\"]\n\n    return {\n        \"intermediate_steps\": intermediate_steps,\n        \"final_code\": combined_final[\"code\"],\n        \"added_to_database\": success\n    }\n"
  },
  {
    "path": "babyagi/functionz/packs/drafts/react_agent.py",
    "content": "from functionz.core.framework import func\n\n@func.register_function(\n    metadata={\n        \"description\": \"An agent that takes an input, plans using LLM, executes actions using functions from display_functions_wrapper(), and continues until the task is complete using chain-of-thought techniques while providing detailed reasoning and function execution steps.\"\n    },\n    imports=[\"litellm\", \"json\", \"copy\"],\n    dependencies=[\"get_function_wrapper\", \"execute_function_wrapper\", \"get_all_functions_wrapper\"],\n    key_dependencies=[\"OPENAI_API_KEY\"]\n)\ndef react_agent(input_text) -> str:\n    def map_python_type_to_json(python_type: str) -> dict:\n        type_mapping = {\n            \"str\": {\"type\": \"string\"},\n            \"int\": {\"type\": \"integer\"},\n            \"float\": {\"type\": \"number\"},\n            \"bool\": {\"type\": \"boolean\"},\n            \"list\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}},\n            \"dict\": {\"type\": \"object\"},\n            \"Any\": {\"type\": \"string\"}\n        }\n        return type_mapping.get(python_type, {\"type\": \"string\"})\n\n    try:\n        # Enable verbose logging for LiteLLM\n        litellm.set_verbose = True\n\n        # Get available functions using get_all_functions_wrapper\n        all_functions = get_all_functions_wrapper()\n\n        # Extract function names from the structured data\n        available_function_names = [func_info['name'] for func_info in all_functions]\n\n        # Fetch available functions from the database\n        tools = []\n        for func_name in available_function_names:\n            # Retrieve function details using get_function_wrapper\n            function_data = get_function_wrapper(func_name)\n            if function_data:\n                # Construct the tool definition for LiteLLM\n                tool = {\n                    \"type\": \"function\",\n                    \"function\": {\n                        \"name\": function_data['name'],\n                        \"description\": function_data['metadata'].get('description', ''),\n                        \"parameters\": {\n                            \"type\": \"object\",\n                            \"properties\": {},\n                            \"required\": []\n                        },\n                    },\n                }\n\n                # Map input_parameters to the tool's parameters\n                for param in function_data.get('input_parameters', []):\n                    json_schema = map_python_type_to_json(param['type'])\n                    tool['function']['parameters']['properties'][param['name']] = {\n                        **json_schema,\n                        \"description\": param.get('description', '')\n                    }\n                    if param.get('required', False):\n                        tool['function']['parameters']['required'].append(param['name'])\n\n                tools.append(tool)\n            else:\n                raise ValueError(f\"Function '{func_name}' not found in the database.\")\n\n        # Initialize function call history\n        function_call_history = []\n\n        # Initialize chat context with system message\n        system_prompt = (\n            \"You are an AI assistant that uses a chain-of-thought reasoning process to solve tasks. \"\n            \"Let's think step by step to solve the following problem. \"\n            \"You have access to the following functions which you can use to complete the task. \"\n            \"Explain your reasoning in detail, including any functions you use and their outputs. \"\n            \"At the end of your reasoning, provide the final answer after 'Answer:'. \"\n            \"Before finalizing, review your reasoning for any errors or inconsistencies. \"\n            \"Avoid repeating function calls with the same arguments you've already tried. \"\n            \"Here is the history of function calls you have made so far: {{function_call_history}}\"\n        )\n\n        chat_context = [\n            {\"role\": \"system\", \"content\": system_prompt.replace(\"{{function_call_history}}\", \"None\")},\n            {\"role\": \"user\", \"content\": input_text},\n        ]\n\n        # Initialize loop parameters\n        max_iterations = 5\n        iteration = 0\n\n        full_reasoning_path = \"\"\n\n        while iteration < max_iterations:\n            iteration += 1\n\n            # Update the system prompt with the current function call history\n            if function_call_history:\n                history_str = \"\\n\".join([\n                    f\"- {call['function_name']} with arguments {call['arguments']} produced output: {call['output']}\"\n                    for call in function_call_history\n                ])\n            else:\n                history_str = \"None\"\n\n            chat_context[0]['content'] = system_prompt.replace(\"{{function_call_history}}\", history_str)\n\n            # Call LiteLLM's completion API with the chat context and tools\n            response = litellm.completion(\n                model=\"gpt-4-turbo\",\n                messages=chat_context,\n                tools=tools,\n                tool_choice=\"auto\",\n                max_tokens=1500,\n                temperature=0.7\n            )\n\n            # Extract the message from the response\n            response_message = response['choices'][0]['message']\n\n            # Append the assistant's message to the chat context and full reasoning path\n            chat_context.append(response_message)\n            full_reasoning_path += f\"\\nIteration {iteration}:\\n{response_message['content']}\\n\"\n\n            # Check if the assistant wants to call any functions\n            tool_calls = response_message.get('tool_calls', [])\n\n            if tool_calls:\n                for tool_call in tool_calls:\n                    function_name = tool_call['function']['name']\n                    function_args = json.loads(tool_call['function']['arguments'])\n                    tool_call_id = tool_call['id']\n\n                    # Check if this function call with these arguments has already been made\n                    if any(\n                        call['function_name'] == function_name and call['arguments'] == function_args\n                        for call in function_call_history\n                    ):\n                        function_response = f\"Function '{function_name}' with arguments {function_args} has already been called. Please try a different approach.\"\n                    else:\n                        # Execute the function using execute_function_wrapper\n                        try:\n                            function_output = execute_function_wrapper(function_name, **function_args)\n                            function_call_history.append({\n                                'function_name': function_name,\n                                'arguments': function_args,\n                                'output': function_output\n                            })\n                            function_response = f\"Function '{function_name}' executed successfully with output: {function_output}\"\n                        except Exception as e:\n                            function_response = f\"Error executing function '{function_name}': {str(e)}\"\n\n                    # Ensure function_response is a string\n                    if not isinstance(function_response, str):\n                        function_response = json.dumps(function_response)\n\n                    # Append the function response to the chat context and full reasoning path\n                    chat_context.append({\n                        \"tool_call_id\": tool_call_id,\n                        \"role\": \"tool\",\n                        \"name\": function_name,\n                        \"content\": function_response\n                    })\n                    full_reasoning_path += f\"Function Call: {function_name}\\nArguments: {function_args}\\nOutput: {function_response}\\n\"\n\n                # Continue the loop to allow the assistant to process the function outputs\n                continue\n            else:\n                # No function calls, assume task is complete\n                break\n\n        # Extract the final answer from the last assistant message\n        final_answer = response_message['content'].split('Answer:')[-1].strip() if 'Answer:' in response_message['content'] else response_message['content']\n\n        # Compile the full response including reasoning steps and function call history\n        if function_call_history:\n            function_calls_str = \"\\n\".join([\n                f\"Function '{call['function_name']}' called with arguments {call['arguments']}, produced output: {call['output']}\"\n                for call in function_call_history\n            ])\n        else:\n            function_calls_str = \"No functions were called.\"\n\n        full_response = (\n            f\"Full Reasoning Path:\\n{full_reasoning_path}\\n\\n\"\n            f\"Functions Used:\\n{function_calls_str}\\n\\n\"\n            f\"Final Answer:\\n{final_answer}\"\n        )\n\n        return full_response\n\n    except Exception as e:\n        return f\"An error occurred: {str(e)}\\n\\nFull reasoning path so far:\\n{full_reasoning_path}\""
  },
  {
    "path": "babyagi/functionz/packs/drafts/self_build.py",
    "content": "# self_build.py\n\nfrom functionz.core.framework import func\nimport json\n\n@func.register_function(\n    metadata={\"description\": \"Generates queries based on user description\"},\n    dependencies=[\"gpt_call\"],\n    imports=[\"json\"]\n)\ndef generate_queries(user_description, X=3, max_retries=3):\n    \"\"\"\n    Generates X distinct queries that require action based on the user description using gpt_call. \n\n    Args:\n        user_description (str): Description of the user or their needs.\n        X (int, optional): Number of queries to generate. Defaults to 3.\n        max_retries (int, optional): Maximum number of retries for generating valid queries. Defaults to 3.\n\n    Returns:\n        list: A list of generated queries.\n\n    Raises:\n        ValueError: If unable to generate valid queries within the retry limit.\n    \"\"\"\n    prompt = f\"\"\"\nYou are an AI assistant. Based on the following user description, generate {X} distinct queries that such a user might ask:\n\nUser Description:\n\"{user_description}\"\n\nProvide the queries in JSON format as a list:\n\n[\n  \"Query 1\",\n  \"Query 2\",\n  ...\n]\n\nEnsure the queries are diverse, relevant to the user description, and represent realistic questions that this user might ask. Make requests that require action, such as using tools and APIs, which you should specify in the request. Based on the user description, guess what types of tools they use and specify them in the query.\n\"\"\"\n\n    errors = []  # To collect error messages from each attempt\n\n    for attempt in range(1, max_retries + 1):\n        response = gpt_call(prompt)\n        try:\n            queries = json.loads(response)\n            if isinstance(queries, list) and len(queries) == X and all(isinstance(q, str) for q in queries):\n                return queries\n            else:\n                error_message = (\n                    f\"Attempt {attempt}: Invalid JSON structure or incorrect number of queries. \"\n                    f\"Expected {X} string queries, but received: {response}\"\n                )\n                errors.append(error_message)\n        except json.JSONDecodeError as e:\n            error_message = (\n                f\"Attempt {attempt}: JSON decoding failed with error: {str(e)}. \"\n                f\"Response received: {response}\"\n            )\n            errors.append(error_message)\n        except Exception as e:\n            error_message = (\n                f\"Attempt {attempt}: An unexpected error occurred: {str(e)}. \"\n                f\"Response received: {response}\"\n            )\n            errors.append(error_message)\n\n    # After all attempts, raise an error with all collected messages\n    full_error_message = \" | \".join(errors)\n    raise ValueError(f\"Failed to generate {X} valid queries after {max_retries} attempts. Errors: {full_error_message}\")\n\n\n@func.register_function(\n    metadata={\"description\": \"Processes generated queries based on user description\"},\n    dependencies=[\"generate_queries\", \"process_user_input\"],\n    imports=[\"json\"]\n)\ndef self_build(user_description, X=3):\n    \"\"\"\n    Generates queries based on the user description and processes each query.\n\n    Args:\n        user_description (str): Description of the user or their needs.\n        X (int, optional): Number of queries to generate and process. Defaults to 3.\n\n    Returns:\n        list: A list of dictionaries containing each query and its corresponding output.\n\n    Raises:\n        ValueError: If query generation fails.\n    \"\"\"\n    try:\n\n        print(\"\\033[1;33mUser Description: \", user_description, \"\\033[0m\")\n        # Generate queries\n        queries = generate_queries(user_description, X)\n    except ValueError as e:\n        # Log the error message for debugging\n        print(f\"Error in generate_queries: {str(e)}\")\n        return []\n\n    print(\"\\033[1;34mQueries generated by self_build: \", queries, \"\\033[0m\")\n    results = []\n    for idx, query in enumerate(queries, start=1):\n        try:\n            output = process_user_input(query)\n            results.append({'query': query, 'output': output})\n        except Exception as e:\n            # Log the error message for debugging\n            print(f\"Error processing query {idx} ('{query}'): {str(e)}\")\n            results.append({'query': query, 'output': None, 'error': str(e)})\n\n    return results\n"
  },
  {
    "path": "babyagi/functionz/packs/drafts/self_build2.py",
    "content": "from functionz.core.framework import func\n\n@func.register_function(\n    metadata={\n        \"name\": \"generate_and_process_queries\",\n        \"description\": \"Generates a specified number of synthetic queries based on a user description and processes each query using the choose_or_create_function.\",\n        \"input_parameters\": {\n            \"user_description\": \"A detailed description provided by the user.\",\n            \"num_queries\": \"An integer specifying the number of synthetic queries to generate.\"\n        },\n        \"output\": \"A dictionary containing the results of each processed query along with intermediate steps and any errors.\"\n    },\n    dependencies=[\n        \"choose_or_create_function\",\n        \"litellm.completion\",\n    ],\n    imports=[\n        {\"name\": \"litellm\", \"lib\": \"litellm\"},\n        {\"name\": \"pydantic\", \"lib\": \"pydantic\"},\n        {\"name\": \"typing\", \"lib\": \"typing\"},\n        {\"name\": \"json\", \"lib\": \"json\"},\n    ]\n)\ndef generate_and_process_queries(user_description: str, num_queries: int) -> dict:\n    \"\"\"\n    Generates X synthetic queries based on the user description and processes each query\n    using the choose_or_create_function.\n\n    Args:\n        user_description (str): The user's description to base synthetic queries on.\n        num_queries (int): The number of synthetic queries to generate.\n\n    Returns:\n        dict: A dictionary containing the results of each query execution, intermediate steps, and any relevant information.\n    \"\"\"\n    from litellm import completion\n    from pydantic import BaseModel, Field, ValidationError\n    from typing import List, Dict, Any\n    import json\n\n    intermediate_steps = []\n    results = []\n\n    # Step 1: Generate synthetic queries based on the user description\n    system_prompt = \"\"\"\nYou are an AI assistant specialized in generating relevant and distinct queries based on a given description.\n\nGiven a user description, generate a specified number of unique and diverse queries that a user might ask an AI assistant.\nEnsure that the queries are varied and cover different aspects of the description.\n\nReturn your response in the following JSON format:\n\n{\n    \"queries\": [\n        \"First synthetic query.\",\n        \"Second synthetic query.\",\n        ...\n    ]\n}\n\nProvide only the JSON response, without any additional text.\n\"\"\"\n\n    class QueryGenerationResponse(BaseModel):\n        queries: List[str] = Field(..., description=\"A list of generated synthetic queries.\")\n\n    generation_prompt = f\"\"\"\nUser Description:\n\\\"\\\"\\\"{user_description}\\\"\\\"\\\"\n\nNumber of Queries to Generate:\n{num_queries}\n\"\"\"\n\n    try:\n        generation_response = completion(\n            model=\"gpt-4o-mini\",\n            messages=[\n                {\"role\": \"system\", \"content\": system_prompt},\n                {\"role\": \"user\", \"content\": generation_prompt}\n            ],\n            response_format=QueryGenerationResponse\n        )\n        print(f\"[DEBUG] Generation Response: {generation_response}\")\n    except Exception as e:\n        print(f\"[ERROR] LLM call for query generation failed: {e}\")\n        intermediate_steps.append({\"step\": \"Error in Query Generation LLM Call\", \"content\": str(e)})\n        return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error generating synthetic queries.\"}\n\n    # Parse the response\n    try:\n        content = generation_response.choices[0].message.content\n        print(f\"[DEBUG] Raw Generation Content: {content}\")\n        generation_parsed = QueryGenerationResponse.parse_raw(content)\n        print(f\"[DEBUG] Parsed Query Generation: {generation_parsed}\")\n        intermediate_steps.append({\"step\": \"Generate Synthetic Queries\", \"content\": generation_parsed.dict()})\n    except (ValidationError, IndexError, AttributeError, json.JSONDecodeError) as e:\n        print(f\"[ERROR] Parsing query generation response failed: {e}\")\n        intermediate_steps.append({\"step\": \"Error Parsing Query Generation Response\", \"content\": str(e)})\n        return {\"intermediate_steps\": intermediate_steps, \"error\": \"# Error parsing synthetic queries.\"}\n\n    synthetic_queries = generation_parsed.queries\n\n    if not synthetic_queries or len(synthetic_queries) != num_queries:\n        print(f\"[ERROR] Number of generated queries does not match the requested number.\")\n        intermediate_steps.append({\n            \"step\": \"Query Count Mismatch\",\n            \"content\": f\"Requested: {num_queries}, Generated: {len(synthetic_queries)}\"\n        })\n        return {\n            \"intermediate_steps\": intermediate_steps,\n            \"error\": \"# The number of generated queries does not match the requested number.\"\n        }\n\n    # Step 2: Process each synthetic query using choose_or_create_function\n    for idx, query in enumerate(synthetic_queries, start=1):\n        intermediate_steps.append({\"step\": f\"Processing Query {idx}\", \"content\": query})\n        try:\n            # Assuming choose_or_create_function is accessible within the scope\n            # If it's in a different module, you might need to import it accordingly\n            query_result = choose_or_create_function(query)\n            results.append({\n                \"query\": query,\n                \"result\": query_result.get(\"execution_result\"),\n                \"intermediate_steps\": query_result.get(\"intermediate_steps\", [])\n            })\n            intermediate_steps.append({\n                \"step\": f\"Executed Query {idx}\",\n                \"content\": query_result.get(\"execution_result\")\n            })\n        except Exception as e:\n            print(f\"[ERROR] Processing query {idx} failed: {e}\")\n            intermediate_steps.append({\n                \"step\": f\"Error Processing Query {idx}\",\n                \"content\": str(e)\n            })\n            results.append({\n                \"query\": query,\n                \"error\": f\"# Error processing query: {e}\"\n            })\n\n    return {\n        \"intermediate_steps\": intermediate_steps,\n        \"results\": results\n    }\n"
  },
  {
    "path": "babyagi/functionz/packs/drafts/user_db.py",
    "content": "# packs/user_db.py\n\nfrom PythonFunc.core.framework import func\n\n@func.register_function(\n    metadata={\"description\": \"Base UserDB class for database operations.\"},\n    imports=[\"sqlalchemy\", \"contextlib\"]\n)\ndef get_user_db_class():\n    from sqlalchemy import create_engine, Column, Integer, String, MetaData\n    from sqlalchemy.ext.declarative import declarative_base\n    from sqlalchemy.orm import sessionmaker\n    from contextlib import contextmanager\n    from sqlalchemy.exc import SQLAlchemyError\n\n    class UserDB:\n        def __init__(self, db_url='sqlite:///user_db.sqlite'):\n            self.engine = create_engine(db_url)\n            self.Session = sessionmaker(bind=self.engine)\n            self.metadata = MetaData()\n            self.Base = declarative_base(metadata=self.metadata)\n\n        @contextmanager\n        def session_scope(self):\n            session = self.Session()\n            try:\n                yield session\n                session.commit()\n            except SQLAlchemyError as e:\n                session.rollback()\n                raise e\n            finally:\n                session.close()\n\n    return UserDB.__name__  # Return the name of the class instead of the class itself\n\n@func.register_function(\n    metadata={\"description\": \"Create a new database.\"},\n    dependencies=[\"get_user_db_class\"],\n    imports=[\"sqlalchemy\"]\n)\ndef create_database(db_name: str, db_type: str = 'sqlite', **kwargs):\n    from sqlalchemy import create_engine, MetaData\n\n    if db_type == 'sqlite':\n        db_url = f'sqlite:///{db_name}.sqlite'\n    elif db_type == 'postgresql':\n        db_url = f'postgresql://{kwargs.get(\"user\")}:{kwargs.get(\"password\")}@{kwargs.get(\"host\", \"localhost\")}:{kwargs.get(\"port\", 5432)}/{db_name}'\n    elif db_type == 'mysql':\n        db_url = f'mysql+pymysql://{kwargs.get(\"user\")}:{kwargs.get(\"password\")}@{kwargs.get(\"host\", \"localhost\")}:{kwargs.get(\"port\", 3306)}/{db_name}'\n    else:\n        raise ValueError(f\"Unsupported database type: {db_type}\")\n\n    UserDB_name = func.get_user_db_class()\n    # Reconstruct the UserDB class\n    UserDB = type(UserDB_name, (), {\n        '__init__': lambda self, db_url: setattr(self, 'engine', create_engine(db_url)),\n        'metadata': MetaData()\n    })\n\n    user_db = UserDB(db_url)  # Pass db_url here\n\n    new_engine = create_engine(db_url)\n    user_db.metadata.create_all(new_engine)\n    return f\"Database '{db_name}' created successfully.\"\n\n\n@func.register_function(\n    metadata={\"description\": \"List all SQLite databases.\"},\n    dependencies=[\"get_user_db_class\"],\n    imports=[\"os\", \"sqlalchemy\"]\n)\ndef list_databases():\n    import os\n    from sqlalchemy import create_engine, MetaData\n    UserDB_name = func.get_user_db_class()\n    UserDB = type(UserDB_name, (), {\n        '__init__': lambda self, db_url: setattr(self, 'engine', create_engine(db_url)),\n        'metadata': MetaData()\n    })\n    # This function doesn't actually use UserDB, but we include it for consistency\n    return [f for f in os.listdir() if f.endswith('.sqlite')]\n\n@func.register_function(\n    metadata={\"description\": \"Delete a database.\"},\n    dependencies=[\"get_user_db_class\"],\n    imports=[\"os\", \"sqlalchemy\"]\n)\ndef delete_database(db_name: str, db_type: str = 'sqlite', **kwargs):\n    import os\n    from sqlalchemy import create_engine, MetaData\n    UserDB_name = func.get_user_db_class()\n    UserDB = type(UserDB_name, (), {\n        '__init__': lambda self, db_url: setattr(self, 'engine', create_engine(db_url)),\n        'metadata': MetaData()\n    })\n    # This function doesn't actually use UserDB, but we include it for consistency\n    if db_type == 'sqlite':\n        os.remove(f'{db_name}.sqlite')\n        return f\"Database '{db_name}' deleted successfully.\"\n    else:\n        raise NotImplementedError(f\"Deleting {db_type} databases is not implemented yet.\")\n\n@func.register_function(\n    metadata={\"description\": \"Create a new table in the database.\"},\n    dependencies=[\"get_user_db_class\"],\n    imports=[\"sqlalchemy\", \"json\"]  # Added 'json' to imports\n)\ndef create_table(db_name: str, table_name: str, columns: str):\n    from sqlalchemy import create_engine, MetaData, Table, Column, String, Integer, Float, Boolean, DateTime, LargeBinary\n    import json  # Imported json within the function\n\n\n    try:\n        columns = json.loads(columns)\n        print(\"Parsed columns:\", columns)  # Debugging statement\n    except json.JSONDecodeError as e:\n        return f\"Invalid JSON for columns: {e}\"\n\n    def get_column_type(type_name):\n        type_map = {\n            'string': String,\n            'integer': Integer,\n            'float': Float,\n            'boolean': Boolean,\n            'datetime': DateTime,\n            'binary': LargeBinary,\n            'embedding': LargeBinary  # We'll use LargeBinary for embeddings\n        }\n        return type_map.get(type_name.lower(), String)  # Default to String if type not found\n\n    UserDB_name = func.get_user_db_class()\n    UserDB = type(UserDB_name, (), {\n        '__init__': lambda self, db_url: setattr(self, 'engine', create_engine(db_url)),\n        'metadata': MetaData(),\n    })\n    user_db = UserDB(f'sqlite:///{db_name}.sqlite')\n\n    # Create the table\n    table = Table(\n        table_name,\n        user_db.metadata,\n        Column('id', Integer, primary_key=True),\n        *(Column(col['name'], get_column_type(col['type'])) for col in columns)\n    )\n\n    # Create the table in the database\n    table.create(user_db.engine, checkfirst=True)\n\n    return f\"Table '{table_name}' created successfully in database '{db_name}'.\"\n\n\n\n@func.register_function(\n    metadata={\"description\": \"List all tables in a database.\"},\n    dependencies=[\"get_user_db_class\"],\n    imports=[\"sqlalchemy\"]\n)\ndef list_tables(db_name: str):\n    from sqlalchemy import create_engine, MetaData\n    UserDB_name = func.get_user_db_class()\n    UserDB = type(UserDB_name, (), {\n        '__init__': lambda self, db_url: setattr(self, 'engine', create_engine(db_url)),\n        'metadata': MetaData()\n    })\n    user_db = UserDB(f'sqlite:///{db_name}.sqlite')\n    user_db.metadata.reflect(user_db.engine)\n    return [table.name for table in user_db.metadata.tables.values()]\n\n@func.register_function(\n    metadata={\"description\": \"Get details of a specific table.\"},\n    dependencies=[\"get_user_db_class\"],\n    imports=[\"sqlalchemy\"]\n)\ndef get_table(db_name: str, table_name: str):\n    from sqlalchemy import create_engine, MetaData, Table\n    from sqlalchemy.exc import NoSuchTableError\n\n    UserDB_name = func.get_user_db_class()\n    UserDB = type(UserDB_name, (), {\n        '__init__': lambda self, db_url: setattr(self, 'engine', create_engine(db_url)),\n        'metadata': MetaData()\n    })\n\n    try:\n        user_db = UserDB(f'sqlite:///{db_name}.sqlite')\n        user_db.metadata.reflect(user_db.engine)\n\n        if table_name in user_db.metadata.tables:\n            table = Table(table_name, user_db.metadata, autoload_with=user_db.engine)\n            return {\n                \"name\": table.name,\n                \"columns\": [{\"name\": column.name, \"type\": str(column.type)} for column in table.columns]\n            }\n        else:\n            return f\"Table '{table_name}' not found in database '{db_name}'.\"\n    except NoSuchTableError:\n        return f\"Table '{table_name}' not found in database '{db_name}'.\"\n    except Exception as e:\n        return f\"Error getting table details: {str(e)}\"\n        \n@func.register_function(\n    metadata={\"description\": \"Update a table by adding new columns.\"},\n    dependencies=[\"get_user_db_class\"],\n    imports=[\"sqlalchemy\", \"json\"]  # Added 'json' to imports\n)\ndef update_table(db_name: str, table_name: str, new_columns: str):\n    from sqlalchemy import create_engine, MetaData, Table, Column, String, Integer, Float, Boolean, DateTime, LargeBinary\n    from sqlalchemy.schema import CreateTable\n    import json  # Imported json within the function\n\n    try:\n        new_columns = json.loads(new_columns)\n        print(\"Parsed columns:\", new_columns)  # Debugging statement\n    except json.JSONDecodeError as e:\n        return f\"Invalid JSON for columns: {e}\"\n\n    def get_column_type(type_name):\n        type_map = {\n            'string': String,\n            'integer': Integer,\n            'float': Float,\n            'boolean': Boolean,\n            'datetime': DateTime,\n            'binary': LargeBinary,\n            'embedding': LargeBinary  # We'll use LargeBinary for embeddings\n        }\n        return type_map.get(type_name.lower(), String)  # Default to String if type not found\n\n\n    UserDB_name = func.get_user_db_class()\n    UserDB = type(UserDB_name, (), {\n        '__init__': lambda self, db_url: setattr(self, 'engine', create_engine(db_url)),\n        'metadata': MetaData()\n    })\n\n    try:\n        user_db = UserDB(f'sqlite:///{db_name}.sqlite')\n        user_db.metadata.reflect(user_db.engine)\n\n        if table_name not in user_db.metadata.tables:\n            return f\"Table '{table_name}' not found in database '{db_name}'.\"\n\n        table = Table(table_name, user_db.metadata, autoload_with=user_db.engine)\n        existing_columns = set(column.name for column in table.columns)\n\n        for col in new_columns:\n            if col['name'] not in existing_columns:\n                new_column = Column(col['name'], get_column_type(col['type']))\n                # Generate the SQL statement to add the new column\n                alter_stmt = f'ALTER TABLE {table_name} ADD COLUMN {new_column.name} {new_column.type}'\n                user_db.engine.execute(alter_stmt)\n\n        # Refresh the table metadata\n        user_db.metadata.clear()\n        user_db.metadata.reflect(user_db.engine)\n\n        return f\"Table '{table_name}' updated successfully in database '{db_name}'.\"\n\n    except Exception as e:\n        return f\"An error occurred while updating the table: {e}\"\n\n\n@func.register_function(\n    metadata={\"description\": \"Delete a table from the database.\"},\n    dependencies=[\"get_user_db_class\"],\n    imports=[\"sqlalchemy\"]\n)\ndef delete_table(db_name: str, table_name: str):\n    from sqlalchemy import create_engine, MetaData, Table\n    from sqlalchemy.exc import NoSuchTableError\n\n    UserDB_name = func.get_user_db_class()\n    UserDB = type(UserDB_name, (), {\n        '__init__': lambda self, db_url: setattr(self, 'engine', create_engine(db_url)),\n        'metadata': MetaData()\n    })\n\n    try:\n        user_db = UserDB(f'sqlite:///{db_name}.sqlite')\n        user_db.metadata.reflect(user_db.engine)\n\n        if table_name in user_db.metadata.tables:\n            table = Table(table_name, user_db.metadata, autoload_with=user_db.engine)\n            table.drop(user_db.engine)\n            user_db.metadata.remove(table)\n            return f\"Table '{table_name}' deleted successfully from database '{db_name}'.\"\n        else:\n            return f\"Table '{table_name}' not found in database '{db_name}'.\"\n    except NoSuchTableError:\n        return f\"Table '{table_name}' not found in database '{db_name}'.\"\n    except Exception as e:\n        return f\"Error deleting table: {str(e)}\"\n\n\n@func.register_function(\n    metadata={\"description\": \"Create a new record in a table.\"},\n    dependencies=[\"get_user_db_class\", \"convert_value\"],\n    imports=[\"sqlalchemy\", \"json\"]\n)\ndef create_record(db_name: str, table_name: str, data: list):\n    from sqlalchemy import create_engine, MetaData, Table, String\n    from sqlalchemy.orm import sessionmaker\n    import json\n\n    if not isinstance(data_dict, dict):\n        return \"Error: Data must be a JSON object\"\n\n    UserDB_name = func.get_user_db_class()\n    UserDB = type(UserDB_name, (), {\n        '__init__': lambda self, db_url: setattr(self, 'engine', create_engine(db_url)),\n        'metadata': MetaData()\n    })\n    user_db = UserDB(f'sqlite:///{db_name}.sqlite')\n    user_db.metadata.reflect(user_db.engine)\n    table = Table(table_name, user_db.metadata, autoload_with=user_db.engine)\n    Session = sessionmaker(bind=user_db.engine)\n\n    # Get column types\n    column_types = {c.name: c.type for c in table.columns}\n\n    # Convert input data to appropriate types\n    converted_data = {key: func.convert_value(value, column_types.get(key, String)) for key, value in data.items()}\n\n    try:\n        with Session() as session:\n            ins = table.insert().values(**converted_data)\n            session.execute(ins)\n            session.commit()\n        return f\"Record created in table '{table_name}' of database '{db_name}'.\"\n    except Exception as e:\n        return f\"Error creating record: {str(e)}\"\n        \ndef read_records(db_name: str, table_name: str, filters: dict = None):\n    from sqlalchemy import create_engine, MetaData, Table\n    from sqlalchemy.orm import sessionmaker\n    UserDB_name = func.get_user_db_class()\n    UserDB = type(UserDB_name, (), {\n        '__init__': lambda self, db_url: setattr(self, 'engine', create_engine(db_url)),\n        'metadata': MetaData()\n    })\n    user_db = UserDB(f'sqlite:///{db_name}.sqlite')\n    user_db.metadata.reflect(user_db.engine)\n    table = Table(table_name, user_db.metadata, autoload_with=user_db.engine)\n    Session = sessionmaker(bind=user_db.engine)\n    with Session() as session:\n        query = session.query(table)\n        if filters:\n            query = query.filter_by(**filters)\n        return [dict(row) for row in query.all()]\n\n@func.register_function(\n    metadata={\"description\": \"Update a record in a table.\"},\n    dependencies=[\"get_user_db_class\", \"convert_value\"],\n    imports=[\"sqlalchemy\", \"json\"]\n)\ndef update_record(db_name: str, table_name: str, record_id: int, data: json):\n    from sqlalchemy import create_engine, MetaData, Table, String\n    from sqlalchemy.orm import sessionmaker\n    import json\n\n    if not isinstance(data_dict, dict):\n        return \"Error: Data must be a JSON object\"\n\n    UserDB_name = func.get_user_db_class()\n    UserDB = type(UserDB_name, (), {\n        '__init__': lambda self, db_url: setattr(self, 'engine', create_engine(db_url)),\n        'metadata': MetaData()\n    })\n    user_db = UserDB(f'sqlite:///{db_name}.sqlite')\n    user_db.metadata.reflect(user_db.engine)\n    table = Table(table_name, user_db.metadata, autoload_with=user_db.engine)\n    Session = sessionmaker(bind=user_db.engine)\n\n    # Get column types\n    column_types = {c.name: c.type for c in table.columns}\n\n    # Convert input data to appropriate types\n    converted_data = {key: func.convert_value(value, column_types.get(key, String)) for key, value in data.items()}\n\n    try:\n        with Session() as session:\n            update = table.update().where(table.c.id == record_id).values(**converted_data)\n            result = session.execute(update)\n            session.commit()\n            if result.rowcount:\n                return f\"Record {record_id} in table '{table_name}' of database '{db_name}' updated successfully.\"\n            return f\"Record {record_id} not found in table '{table_name}' of database '{db_name}'.\"\n    except Exception as e:\n        return f\"Error updating record: {str(e)}\"\n\n@func.register_function(\n    metadata={\"description\": \"Delete a record from a table.\"},\n    dependencies=[\"get_user_db_class\"],\n    imports=[\"sqlalchemy\"]\n)\ndef delete_record(db_name: str, table_name: str, record_id: int):\n    from sqlalchemy import create_engine, MetaData, Table\n    from sqlalchemy.orm import sessionmaker\n    UserDB_name = func.get_user_db_class()\n    UserDB = type(UserDB_name, (), {\n        '__init__': lambda self, db_url: setattr(self, 'engine', create_engine(db_url)),\n        'metadata': MetaData()\n    })\n    user_db = UserDB(f'sqlite:///{db_name}.sqlite')\n    user_db.metadata.reflect(user_db.engine)\n    table = Table(table_name, user_db.metadata, autoload_with=user_db.engine)\n    Session = sessionmaker(bind=user_db.engine)\n    with Session() as session:\n        delete = table.delete().where(table.c.id == record_id)\n        result = session.execute(delete)\n        session.commit()\n        if result.rowcount:\n            return f\"Record {record_id} in table '{table_name}' of database '{db_name}' deleted successfully.\"\n        return f\"Record {record_id} not found in table '{table_name}' of database '{db_name}'.\"\n\n\n@func.register_function(\n    metadata={\"description\": \"Convert value to specified SQLAlchemy type\"},\n    imports=[\"sqlalchemy\", \"json\", \"datetime\"]\n)\ndef convert_value(value, target_type):\n    from sqlalchemy import Boolean, DateTime, LargeBinary, Integer, Float\n    import json\n    from datetime import datetime\n\n    if isinstance(value, str):\n        if target_type == Boolean:\n            return value.lower() in ('true', 'yes', '1', 'on')\n        elif target_type == DateTime:\n            return datetime.fromisoformat(value)\n        elif target_type == LargeBinary:\n            try:\n                # Assume it's a JSON array for embeddings\n                return json.dumps(json.loads(value)).encode('utf-8')\n            except json.JSONDecodeError:\n                # If not JSON, treat as regular binary data\n                return value.encode('utf-8')\n        elif target_type in (Integer, Float):\n            return target_type(value)\n    return value  # Return as-is for String or if already correct type\n\n@func.register_function(\n    metadata={\"description\": \"Create a new table in the database.\"},\n    dependencies=[\"get_user_db_class\"],\n    imports=[\"sqlalchemy\"]\n)"
  },
  {
    "path": "babyagi/functionz/packs/plugins/airtable.py",
    "content": "from functionz import func\n\n# Initialize the Airtable Table instance\n@func.register_function(\n    metadata={\"description\": \"Initialize Airtable table instance with access token, base ID, and table name.\"},\n    key_dependencies=[\"airtable_access_token\"],\n    imports=[\"pyairtable\"]\n)\ndef init_airtable(base_id, table_name):\n    \"\"\"\n    Initialize the Airtable Table instance.\n    :param base_id: ID of the Airtable base\n    :param table_name: Name of the table within the base\n    :return: Airtable Table instance\n    \"\"\"\n    api_token = globals()[\"airtable_access_token\"]\n    from pyairtable import Table\n    return Table(api_token, base_id, table_name)\n\n\n# Create a single record in a given Airtable table\n@func.register_function(\n    metadata={\"description\": \"Create a new record in a specific Airtable table.\"},\n    dependencies=[\"init_airtable\"]\n)\ndef create_record(base_id, table_name, record_data):\n    \"\"\"\n    Create a new record in the specified Airtable table.\n    :param base_id: ID of the Airtable base\n    :param table_name: Name of the table within the base\n    :param record_data: Dictionary containing record fields and values\n    :return: The newly created record\n    \"\"\"\n    table = init_airtable(base_id, table_name)\n    return table.create(record_data)\n\n\n# Retrieve a single record by its ID\n@func.register_function(\n    metadata={\"description\": \"Retrieve a specific record from Airtable using its record ID.\"},\n    dependencies=[\"init_airtable\"]\n)\ndef get_record_by_id(base_id, table_name, record_id):\n    \"\"\"\n    Retrieve a record by its unique ID from the specified Airtable table.\n    :param base_id: ID of the Airtable base\n    :param table_name: Name of the table within the base\n    :param record_id: Unique record ID in Airtable\n    :return: The record data as a dictionary\n    \"\"\"\n    table = init_airtable(base_id, table_name)\n    return table.get(record_id)\n\n\n# Update an existing record by its ID\n@func.register_function(\n    metadata={\"description\": \"Update a record in Airtable using its ID and new field values.\"},\n    dependencies=[\"init_airtable\"]\n)\ndef update_record(base_id, table_name, record_id, updated_fields):\n    \"\"\"\n    Update a record in Airtable with new values for specified fields.\n    :param base_id: ID of the Airtable base\n    :param table_name: Name of the table within the base\n    :param record_id: Unique record ID in Airtable\n    :param updated_fields: Dictionary with updated field values\n    :return: The updated record data as a dictionary\n    \"\"\"\n    table = init_airtable(base_id, table_name)\n    return table.update(record_id, updated_fields)\n\n\n# Delete a record by its ID\n@func.register_function(\n    metadata={\"description\": \"Delete a specific record from an Airtable table.\"},\n    dependencies=[\"init_airtable\"]\n)\ndef delete_record(base_id, table_name, record_id):\n    \"\"\"\n    Delete a record from Airtable using its unique ID.\n    :param base_id: ID of the Airtable base\n    :param table_name: Name of the table within the base\n    :param record_id: Unique record ID in Airtable\n    :return: Deletion confirmation message\n    \"\"\"\n    table = init_airtable(base_id, table_name)\n    return table.delete(record_id)\n\n\n# Retrieve all records from a table\n@func.register_function(\n    metadata={\"description\": \"Retrieve all records from a specific Airtable table.\"},\n    dependencies=[\"init_airtable\"]\n)\ndef get_all_records(base_id, table_name, max_records=100, sort_by=None):\n    \"\"\"\n    Get all records from the specified table, with optional sorting.\n    :param base_id: ID of the Airtable base\n    :param table_name: Name of the table within the base\n    :param max_records: Maximum number of records to retrieve\n    :param sort_by: Optional list of fields to sort the records by\n    :return: List of all records\n    \"\"\"\n    table = init_airtable(base_id, table_name)\n    return table.all(max_records=max_records, sort=sort_by)\n\n\n# Upsert multiple records into a table based on unique fields\n@func.register_function(\n    metadata={\"description\": \"Upsert (create or update) multiple records into a table using unique field identifiers.\"},\n    dependencies=[\"init_airtable\"]\n)\ndef batch_upsert_records(base_id, table_name, records, key_fields):\n    \"\"\"\n    Upsert multiple records into the specified table.\n    :param base_id: ID of the Airtable base\n    :param table_name: Name of the table within the base\n    :param records: List of records to be upserted\n    :param key_fields: List of fields to use as unique keys\n    :return: List of created or updated records\n    \"\"\"\n    table = init_airtable(base_id, table_name)\n    return table.batch_upsert(records, key_fields=key_fields)\n\n\n# Batch create multiple records in a table\n@func.register_function(\n    metadata={\"description\": \"Create multiple records in a table using batch operations.\"},\n    dependencies=[\"init_airtable\"]\n)\ndef batch_create_records(base_id, table_name, records):\n    \"\"\"\n    Create multiple records in the specified table.\n    :param base_id: ID of the Airtable base\n    :param table_name: Name of the table within the base\n    :param records: List of records to be created\n    :return: List of created records\n    \"\"\"\n    table = init_airtable(base_id, table_name)\n    return table.batch_create(records)\n\n\n# Batch delete multiple records from a table\n@func.register_function(\n    metadata={\"description\": \"Delete multiple records in a table using batch operations.\"},\n    dependencies=[\"init_airtable\"]\n)\ndef batch_delete_records(base_id, table_name, record_ids):\n    \"\"\"\n    Batch delete records using their unique IDs.\n    :param base_id: ID of the Airtable base\n    :param table_name: Name of the table within the base\n    :param record_ids: List of record IDs to be deleted\n    :return: Confirmation messages for deleted records\n    \"\"\"\n    table = init_airtable(base_id, table_name)\n    return table.batch_delete(record_ids)\n\n\n\nfrom functionz import func\n\n@func.register_function(\n    metadata={\"description\": \"Fetch a dynamic number of rows from Airtable based on a flexible search query.\"},\n    dependencies=[\"init_airtable\"],\n    imports=[\"pyairtable\"]\n)\ndef get_dynamic_records(base_id, table_name, max_records=100, search_query=None, sort_by=None, fields=None, view=None, page_size=100):\n    \"\"\"\n    Fetch a dynamic number of records from an Airtable table based on a custom query.\n\n    :param base_id: ID of the Airtable base\n    :param table_name: Name of the table within the base\n    :param max_records: Maximum number of records to retrieve\n    :param search_query: Dictionary of field-value pairs to match (e.g., {\"Name\": \"Alice\", \"Age\": 30})\n    :param sort_by: List of fields to sort the records by (e.g., [\"Name\", \"-Age\"])\n    :param fields: List of specific fields to retrieve (e.g., [\"Name\", \"Age\"])\n    :param view: View ID or name to filter the records by\n    :param page_size: Number of records per page request\n    :return: List of matching records\n    \"\"\"\n    from pyairtable.formulas import match\n    table = init_airtable(base_id, table_name)\n\n    # Construct a formula using the match function if search_query is provided\n    formula = None\n    if search_query:\n        from pyairtable.formulas import match\n        formula = match(search_query)\n\n    # Use iterate to handle large datasets if max_records is set higher than page_size\n    records = table.iterate(\n        formula=formula,\n        sort=sort_by,\n        fields=fields,\n        view=view,\n        page_size=page_size,\n        max_records=max_records\n    )\n\n    # Collect results from the generator into a list\n    return list(records)\n\n"
  },
  {
    "path": "babyagi/functionz/packs/plugins/augie.py",
    "content": "from babyagi.functionz.core.framework import func\n\n@func.register_function(\n  metadata={\"description\": \"Generate parameters for Augie creation using GPT.\"},\n  dependencies=[\"gpt_call\"]\n)\ndef generate_augie_params(user_input, voice_id=\"29vD33N1CtxCmqQRPOHJ\"):\n  \"\"\"\n  This function generates JSON parameters for creating an Augie video.\n  It uses GPT to structure the user input into the required format, keeping the default voice_id.\n\n  Parameters:\n  - user_input: The basic user input text.\n  - voice_id: Default voice ID (not generated by GPT).\n\n  Returns: A dictionary with the necessary parameters for creating the Augie video.\n  \"\"\"\n  prompt = (\n      \"You are creating parameters for a video generation API request. \"\n      \"The user has provided input text for the video content. Structure the input into the following JSON format:\\n\"\n      \"{\\n\"\n      \"  'name': '<brief title>',\\n\"\n      \"  'text': '<full video content text>',\\n\"\n      \"  'orientation': 'landscape' or 'portrait',\\n\"\n      \"  'make_video': true or false\\n\"\n      \"}\\n\"\n      \"Do not generate a voice ID, use the one provided by the API system.\"\n  )\n\n  gpt_output = gpt_call({\"prompt\": prompt, \"user_input\": user_input})\n\n  # Parse GPT output and construct parameters\n  params = gpt_output['text']  # Assuming gpt_call returns a structured response.\n  params['voice_id'] = voice_id  # Set the default voice ID.\n\n  return params\n\n\n@func.register_function(\n  metadata={\"description\": \"Creates a video on Augie platform.\"},\n  key_dependencies=[\"augie_api_key\"],\n  imports={\"name\": \"requests\", \"lib\": \"requests\"}\n)\ndef create_augie(params):\n  \"\"\"Function to create a video on Augie platform with parameters.\"\"\"\n  API_KEY = globals()['augie_api_key']\n  BASE_URL = 'https://beta.api.augie.studio/v1'\n\n  headers = {\n      'x-api-key': API_KEY,\n      'Content-Type': 'application/json'\n  }\n\n  import requests\n  response = requests.post(f'{BASE_URL}/augies', json=params, headers=headers)\n\n  if response.status_code == 201:\n      return response.json()  # Returns the creation response\n  else:\n      raise Exception(f\"Failed to create Augie: {response.text}\")\n\n\n@func.register_function(\n  metadata={\"description\": \"Checks the status of the created video.\"},\n  key_dependencies=[\"augie_api_key\"],\n  imports={\"name\": \"requests\", \"lib\": \"requests\"}\n)\ndef get_augie_status(augie_id):\n  \"\"\"Function to check the status of an Augie video creation.\"\"\"\n  API_KEY = globals()['augie_api_key']\n  BASE_URL = 'https://beta.api.augie.studio/v1'\n\n  headers = {\n      'x-api-key': API_KEY\n  }\n\n  import requests\n  response = requests.get(f'{BASE_URL}/augies/{augie_id}/status', headers=headers)\n\n  if response.status_code == 200:\n      status_data = response.json()\n      if status_data.get('status') == 'succeeded' and 'output' in status_data and 'video' in status_data['output']:\n          return {\"status\": \"completed\", \"video_url\": status_data['output']['video']}\n      else:\n          return {\"status\": \"processing\"}\n  else:\n      raise Exception(f\"Failed to get Augie status: {response.text}\")\n\n\n@func.register_function(\n  metadata={\"description\": \"Wrapper to create a video and keep checking its status until available.\"},\n  dependencies=[\"generate_augie_params\", \"create_augie\", \"get_augie_status\"],\n  imports={\"name\": \"time\", \"lib\": \"time\"}\n)\ndef create_and_wait_for_video(user_input, timeout=300, interval=10):\n  \"\"\"\n  Wrapper function to create a video from user input and wait for it to be available.\n  - user_input: Basic input from the user, processed by GPT.\n  - timeout: The max time to wait (in seconds).\n  - interval: Time between status checks (in seconds).\n  \"\"\"\n  import time\n\n  # Generate parameters using GPT\n  params = generate_augie_params(user_input)\n\n  # Create the video\n  creation_response = create_augie(params)\n  augie_id = creation_response.get('id')\n\n  if not augie_id:\n      raise Exception(\"Failed to retrieve Augie ID after creation.\")\n\n  # Wait and check the status periodically\n  start_time = time.time()\n  while time.time() - start_time < timeout:\n      status_response = get_augie_status(augie_id)\n      if status_response['status'] == 'completed':\n          return status_response  # Return video URL if available\n      time.sleep(interval)\n\n  # Timeout reached, return failure\n  raise TimeoutError(f\"Video creation timed out after {timeout} seconds.\")\n"
  },
  {
    "path": "babyagi/functionz/packs/plugins/e2b.py",
    "content": "import babyagi\n\n@babyagi.register_function(\n    metadata={\"description\": \"Executes AI-generated Python code in a secure E2B sandbox.\"},\n    imports=[\"e2b_code_interpreter\"],\n    key_dependencies=[\"e2b_api_key\"]\n)\ndef execute_code_in_sandbox(code: str):\n    \"\"\"\n    This function initializes an E2B sandbox and executes AI-generated Python code within it.\n\n    :param code: Python code to be executed.\n    :return: Results and logs from the code execution.\n    \"\"\"\n    from e2b_code_interpreter import CodeInterpreter\n  \n    with CodeInterpreter() as sandbox:\n        # Execute the code in the sandbox\n        execution = sandbox.notebook.exec_cell(code)\n\n        # Handle execution errors\n        if execution.error:\n            return {\"error\": execution.error.name, \"message\": execution.error.value, \"traceback\": execution.error.traceback}\n\n        # Gather results\n        results = [{\"text\": result.text, \"formats\": result.formats()} for result in execution.results]\n        logs = {\"stdout\": execution.logs.stdout, \"stderr\": execution.logs.stderr}\n\n        return {\"results\": results, \"logs\": logs}\n\n\n# Function 2: Chat with LLM (OpenAI) and parse response to execute in sandbox\n\n@babyagi.register_function(\n    metadata={\"description\": \"Calls the OpenAI API (gpt-3.5-turbo) to generate code and execute it in an E2B sandbox.\"},\n    imports=[\"litellm\", \"os\"],\n    key_dependencies=[\"openai_api_key\"],\n    dependencies=[\"execute_code_in_sandbox\"]\n)\ndef chat_with_llm_and_execute(user_message: str):\n    \"\"\"\n    This function calls the OpenAI API (via litellm) to generate Python code based on the user's message,\n    then executes that code in an E2B sandbox.\n\n    :param user_message: The message to prompt the LLM with.\n    :return: Results from the executed code and logs.\n    \"\"\"\n    from litellm import completion\n  \n    # Load OpenAI API key from environment\n    api_key = globals()['openai_api_key']\n\n    # Define the message for the LLM\n    messages = [{\"role\": \"user\", \"content\": user_message}]\n\n    # Call the LLM using litellm completion method\n    response = completion(model=\"gpt-3.5-turbo\", messages=messages)\n    llm_generated_code = response['choices'][0]['message']['content']\n\n    # Execute the generated code in the E2B sandbox\n    return execute_code_in_sandbox(llm_generated_code)\n\n\n# Function 3: Save generated charts\n\n@babyagi.register_function(\n    metadata={\"description\": \"Saves a base64-encoded PNG chart to a file.\"},\n    imports=[\"base64\"],\n)\ndef save_chart(base64_png: str, filename: str = \"chart.png\"):\n    \"\"\"\n    Saves a base64-encoded PNG chart to a file.\n\n    :param base64_png: Base64-encoded PNG data.\n    :param filename: The name of the file to save the chart.\n    :return: The path to the saved chart.\n    \"\"\"\n    png_data = base64.b64decode(base64_png)\n\n    # Save the decoded PNG to a file\n    with open(filename, \"wb\") as file:\n        file.write(png_data)\n\n    return f\"Chart saved to {filename}\"\n\n\n# Function 4: Execute main flow (chat with LLM, run code, save chart if exists)\n\n@babyagi.register_function(\n    metadata={\"description\": \"Main function to prompt LLM, execute code in E2B, and save any generated charts.\"},\n    dependencies=[\"chat_with_llm_and_execute\", \"save_chart\"]\n)\ndef e2b_llm_to_chart(user_message: str):\n    \"\"\"\n    The main workflow function: sends a message to the LLM, executes the generated code, and saves any charts.\n\n    :param user_message: The user's input prompt for the LLM.\n    :return: Final results and path to saved chart if applicable.\n    \"\"\"\n    # Get code execution results and logs\n    execution_results = chat_with_llm_and_execute(user_message)\n\n    # Check if any chart (PNG) was generated\n    if execution_results[\"results\"]:\n        for result in execution_results[\"results\"]:\n            if \"png\" in result[\"formats\"]:\n                # Save the chart if PNG format is present\n                chart_filename = save_chart(result[\"formats\"][\"png\"])\n                return {\"execution_results\": execution_results, \"chart_saved_to\": chart_filename}\n\n    return {\"execution_results\": execution_results}\n"
  },
  {
    "path": "babyagi/functionz/packs/plugins/firecrawl.py",
    "content": "# 1. Crawl a website and initiate a crawl job.\n@func.register_function(\n    metadata={\"description\": \"Submits a crawl job for a website and returns a job ID.\"},\n    key_dependencies=[\"firecrawl_api_key\"],\n    imports={\"name\":\"firecrawl\",\"lib\":\"firecrawl-py\"}\n)\ndef crawl_website(url: str, limit: int = 100, formats: list = [\"markdown\", \"html\"], poll_interval: int = 30):\n    \"\"\"\n    Submits a crawl job for the given URL and returns the crawl job status and job ID.\n    \"\"\"\n    from firecrawl import FirecrawlApp\n    api_key = globals()['firecrawl_api_key']\n    app = FirecrawlApp(api_key=api_key)\n\n    try:\n        crawl_status = app.crawl_url(\n            url, \n            params={'limit': limit, 'scrapeOptions': {'formats': formats}},\n            poll_interval=poll_interval\n        )\n        return crawl_status\n    except Exception as e:\n        return {\"error\": str(e)}\n\n\n# 2. Check the status of a crawl job.\n@func.register_function(\n    metadata={\"description\": \"Checks the status of an ongoing or completed crawl job by its job ID.\"},\n    key_dependencies=[\"firecrawl_api_key\"],\n    imports={\"name\":\"firecrawl\",\"lib\":\"firecrawl-py\"}\n)\ndef check_crawl_status(crawl_id: str):\n    \"\"\"\n    Checks the status of the crawl job and returns the job details including markdown and HTML data.\n    \"\"\"\n    from firecrawl import FirecrawlApp\n    api_key = globals()['firecrawl_api_key']\n    app = FirecrawlApp(api_key=api_key)\n\n    try:\n        crawl_status = app.check_crawl_status(crawl_id)\n        return crawl_status\n    except Exception as e:\n        return {\"error\": str(e)}\n\n\n# 3. Scrape a single website URL for markdown and HTML data.\n@func.register_function(\n    metadata={\"description\": \"Scrapes a single URL and returns markdown and HTML content.\"},\n    key_dependencies=[\"firecrawl_api_key\"],\n    imports={\"name\":\"firecrawl\",\"lib\":\"firecrawl-py\"}\n)\ndef scrape_website(url: str, formats: list = [\"markdown\", \"html\"]):\n    \"\"\"\n    Scrapes the given URL and returns the data (markdown, HTML, and metadata).\n    \"\"\"\n    from firecrawl import FirecrawlApp\n    api_key = globals()['firecrawl_api_key']\n    app = FirecrawlApp(api_key=api_key)\n\n    try:\n        scrape_result = app.scrape_url(url, params={'formats': formats})\n        return scrape_result\n    except Exception as e:\n        return {\"error\": str(e)}\n"
  },
  {
    "path": "babyagi/functionz/packs/plugins/harmonic.py",
    "content": "# Harmonic API Functions Pack for Functionz Framework\n\n\n@func.register_function(\n    metadata={\"description\": \"Fetch a company's enrichment data using its identifier (URL or domain).\"},\n    key_dependencies=[\"harmonic_api_key\"],\n    imports=[{\"name\": \"requests\", \"lib\": \"requests\"}]\n)\ndef harmonic_enrich_company(identifier):\n    \"\"\"\n    Enrich a company using its URL, domain, or identifier.\n    Returns the full response from Harmonic API.\n    \"\"\"\n    api_key = globals()['harmonic_api_key']\n    url = \"https://api.harmonic.ai/companies\"\n    headers = {\"accept\": \"application/json\", \"apikey\": api_key}\n\n    # Determine the appropriate parameter based on identifier type\n    if identifier.startswith('http'):\n        params = {\"crunchbase_url\": identifier} if 'crunchbase.com' in identifier else {\"website_url\": identifier}\n    elif '.' in identifier and not identifier.startswith('http'):\n        params = {\"website_domain\": identifier}\n    else:\n        url += f\"/{identifier}\"\n        params = {}\n\n    # Use POST if parameters are present, otherwise GET\n    response = requests.post(url, headers=headers, params=params) if params else requests.get(url, headers=headers)\n    response.raise_for_status()\n    return response.json()\n\n\n@func.register_function(\n    metadata={\"description\": \"Search for companies using a set of keywords.\"},\n    key_dependencies=[\"harmonic_api_key\"],\n    imports=[{\"name\": \"requests\", \"lib\": \"requests\"}]\n)\ndef harmonic_search_companies(keywords, include_ids_only=False):\n    \"\"\"\n    Search for companies using keywords.\n    Returns a list of companies and their metadata.\n    \"\"\"\n    api_key = globals()['harmonic_api_key']\n    url = \"https://api.harmonic.ai/search/companies_by_keywords\"\n    headers = {\"accept\": \"application/json\", \"apikey\": api_key, \"Content-Type\": \"application/json\"}\n\n    data = {\"keywords\": keywords, \"include_ids_only\": include_ids_only}\n    response = requests.post(url, headers=headers, json=data)\n    response.raise_for_status()\n    return response.json()\n\n\n@func.register_function(\n    metadata={\"description\": \"Fetch detailed information about a person using their ID.\"},\n    key_dependencies=[\"harmonic_api_key\"],\n    imports=[{\"name\": \"requests\", \"lib\": \"requests\"}]\n)\ndef harmonic_enrich_person_by_id(person_id):\n    \"\"\"\n    Retrieve detailed information about a person using their Harmonic ID.\n    \"\"\"\n    api_key = globals()['harmonic_api_key']\n    url = f\"https://api.harmonic.ai/persons/{person_id}\"\n    headers = {\"accept\": \"application/json\", \"apikey\": api_key}\n\n    response = requests.get(url, headers=headers)\n    response.raise_for_status()\n    return response.json()\n"
  },
  {
    "path": "babyagi/functionz/packs/plugins/payman.py",
    "content": "from babyagi.functionz.core.framework import func\n\n# Store API keys (both test and real) from Replit secrets into the function database\n@func.register_function(\n    metadata={\"description\": \"Store PayMan API keys (test and real) from Replit secrets into the function database\"},\n    imports=[\"os\"]\n)\ndef store_payman_api_keys():\n    # Store test API key\n    func.add_key('payman_test_api_key', os.environ['PAYMAN_TEST_API_KEY'])\n    # Store real API key\n    func.add_key('payman_api_key', os.environ['PAYMAN_API_KEY'])\n\n\n# Create Task Function\n@func.register_function(\n    metadata={\"description\": \"Create a task on PayMan platform (test by default, real if 'real_money' is True)\"},\n    key_dependencies=[\"payman_test_api_key\", \"payman_api_key\"],\n    imports=[\"requests\"]\n)\ndef create_task(title: str, description: str, payout: int, currency: str = \"USD\", category: str = \"MARKETING\", real_money: bool = False):\n    if real_money:\n        api_key = globals()['payman_api_key']\n        base_url = \"https://agent.payman.ai/api\"\n    else:\n        api_key = globals()['payman_test_api_key']\n        base_url = \"https://agent-sandbox.payman.ai/api\"\n\n    headers = {\n        \"x-payman-api-secret\": api_key,\n        \"Content-Type\": \"application/json\",\n        \"Accept\": \"application/vnd.payman.v1+json\"\n    }\n    payload = {\n        \"title\": title,\n        \"description\": description,\n        \"payout\": payout,  # Payout in cents (e.g. 5000 for $50)\n        \"currency\": currency,\n        \"category\": category,\n        \"requiredSubmissions\": 1,\n        \"submissionPolicy\": \"OPEN_SUBMISSIONS_ONE_PER_USER\"\n    }\n    try:\n        response = requests.post(f\"{base_url}/tasks\", headers=headers, json=payload)\n        return response.json()\n    except requests.exceptions.HTTPError as e:\n        return {\"error\": str(e)}\n\n\n# Get Task by ID Function\n@func.register_function(\n    metadata={\"description\": \"Get a task by its ID on PayMan platform (test by default, real if 'real_money' is True)\"},\n    key_dependencies=[\"payman_test_api_key\", \"payman_api_key\"],\n    imports=[\"requests\"]\n)\ndef get_task_by_id(task_id: str, real_money: bool = False):\n    if real_money:\n        api_key = globals()['payman_api_key']\n        base_url = \"https://agent.payman.ai/api\"\n    else:\n        api_key = globals()['payman_test_api_key']\n        base_url = \"https://agent-sandbox.payman.ai/api\"\n\n    headers = {\n        \"x-payman-api-secret\": api_key,\n        \"Content-Type\": \"application/json\",\n        \"Accept\": \"application/vnd.payman.v1+json\"\n    }\n    try:\n        response = requests.get(f\"{base_url}/tasks/{task_id}\", headers=headers)\n        return response.json()\n    except requests.exceptions.HTTPError as e:\n        return {\"error\": str(e)}\n\n\n# Get All Tasks Function\n@func.register_function(\n    metadata={\"description\": \"Get all tasks for the current organization on PayMan platform (test by default, real if 'real_money' is True)\"},\n    key_dependencies=[\"payman_test_api_key\", \"payman_api_key\"],\n    imports=[\"requests\"]\n)\ndef get_all_tasks(page: int = 0, limit: int = 20, real_money: bool = False):\n    if real_money:\n        api_key = globals()['payman_api_key']\n        base_url = \"https://agent.payman.ai/api\"\n    else:\n        api_key = globals()['payman_test_api_key']\n        base_url = \"https://agent-sandbox.payman.ai/api\"\n\n    headers = {\n        \"x-payman-api-secret\": api_key,\n        \"Content-Type\": \"application/json\",\n        \"Accept\": \"application/vnd.payman.v1+json\"\n    }\n    params = {\n        \"page\": page,\n        \"limit\": limit\n    }\n    try:\n        response = requests.get(f\"{base_url}/tasks\", headers=headers, params=params)\n        return response.json()\n    except requests.exceptions.HTTPError as e:\n        return {\"error\": str(e)}\n\n\n@func.register_function(\n    metadata={\"description\": \"Get all submissions for a task on PayMan platform (test by default, real if 'real_money' is True)\"},\n    key_dependencies=[\"payman_test_api_key\", \"payman_api_key\"],\n    imports=[\"requests\"]\n)\ndef get_task_submissions(task_id: str, statuses: list = None, page: int = 0, limit: int = 20, real_money: bool = False):\n    if real_money:\n        api_key = globals()['payman_api_key']\n        base_url = \"https://agent.payman.ai/api\"\n    else:\n        api_key = globals()['payman_test_api_key']\n        base_url = \"https://agent-sandbox.payman.ai/api\"\n\n    headers = {\n        \"x-payman-api-secret\": api_key,\n        \"Content-Type\": \"application/json\",\n        \"Accept\": \"application/vnd.payman.v1+json\"\n    }\n\n    params = {\n        \"page\": page,\n        \"limit\": limit\n    }\n\n    if statuses:\n        params[\"statuses\"] = \",\".join(statuses)\n\n    try:\n        response = requests.get(f\"{base_url}/tasks/{task_id}/submissions\", headers=headers, params=params)\n        return response.json()\n    except requests.exceptions.HTTPError as e:\n        return {\"error\": str(e)}\n\n# Approve Task Submission Function\n@func.register_function(\n    metadata={\"description\": \"Approve a task submission on PayMan platform (test by default, real if 'real_money' is True)\"},\n    key_dependencies=[\"payman_test_api_key\", \"payman_api_key\"],\n    imports=[\"requests\"]\n)\ndef approve_task_submission(submission_id: str, real_money: bool = False):\n    if real_money:\n        api_key = globals()['payman_api_key']\n        base_url = \"https://agent.payman.ai/api\"\n    else:\n        api_key = globals()['payman_test_api_key']\n        base_url = \"https://agent-sandbox.payman.ai/api\"\n\n    headers = {\n        \"x-payman-api-secret\": api_key,\n        \"Content-Type\": \"application/json\",\n        \"Accept\": \"application/vnd.payman.v1+json\"\n    }\n    try:\n        response = requests.post(f\"{base_url}/tasks/submissions/{submission_id}/approve\", headers=headers)\n        return response.json()\n    except requests.exceptions.HTTPError as e:\n        return {\"error\": str(e)}\n\n\n# Reject Task Submission Function\n@func.register_function(\n    metadata={\"description\": \"Reject a task submission on PayMan platform (test by default, real if 'real_money' is True)\"},\n    key_dependencies=[\"payman_test_api_key\", \"payman_api_key\"],\n    imports=[\"requests\"]\n)\ndef reject_task_submission(submission_id: str, rejection_reason: str, real_money: bool = False):\n    if real_money:\n        api_key = globals()['payman_api_key']\n        base_url = \"https://agent.payman.ai/api\"\n    else:\n        api_key = globals()['payman_test_api_key']\n        base_url = \"https://agent-sandbox.payman.ai/api\"\n\n    headers = {\n        \"x-payman-api-secret\": api_key,\n        \"Content-Type\": \"application/json\",\n        \"Accept\": \"application/vnd.payman.v1+json\"\n    }\n    try:\n        response = requests.post(f\"{base_url}/tasks/submissions/{submission_id}/reject\", headers=headers, json=rejection_reason)\n        return response.json()\n    except requests.exceptions.HTTPError as e:\n        return {\"error\": str(e)}\n"
  },
  {
    "path": "babyagi/functionz/packs/plugins/serpapi.py",
    "content": "@func.register_function(\n  metadata={\n      \"description\": \"Perform a search using the latest SerpApi Python client library with customizable parameters.\"\n  },\n  key_dependencies=[\"serpapi_api_key\"],\n  imports=[\"serpapi\"]\n)\ndef serpapi_search_v2(query: str, engine: str = \"google\", location: str = \"United States\", language: str = \"en\", country: str = \"us\", safe_search: bool = False, num_results: int = 10, start: int = 0, async_request: bool = False, output_format: str = \"json\"):\n  \"\"\"\n  Perform a search using the SerpApi service with a flexible set of parameters.\n\n  Args:\n      query (str): The search query.\n      engine (str): The search engine to use (e.g., 'google', 'bing'). Default is 'google'.\n      location (str): The location to target the search. Default is 'United States'.\n      language (str): UI language for the search. Default is 'en'.\n      country (str): Country code for the search. Default is 'us'.\n      safe_search (bool): Flag for SafeSearch filtering. Default is False.\n      num_results (int): Number of search results to retrieve. Default is 10.\n      start (int): Pagination offset. Default is 0.\n      async_request (bool): Whether to make an asynchronous request. Default is False.\n      output_format (str): Format of the output ('json' or 'html'). Default is 'json'.\n\n  Returns:\n      dict or str: The search results in the specified format.\n  \"\"\"\n  # Import necessary modules and classes within function scope.\n\n  # Get the API key from the global variables.\n  api_key = globals().get(\"serpapi_api_key\", \"\")\n  if not api_key:\n      raise ValueError(\"API key is missing. Please provide a valid SerpApi key.\")\n\n  # Initialize the SerpApi client.\n  client = serpapi.Client(api_key=api_key)\n\n  # Define the search parameters.\n  params = {\n      \"q\": query,\n      \"engine\": engine,\n      \"location\": location,\n      \"hl\": language,\n      \"gl\": country,\n      \"safe\": \"active\" if safe_search else \"off\",\n      \"num\": num_results,\n      \"start\": start,\n      \"async\": async_request,\n      \"output\": output_format,\n  }\n\n  try:\n      # Perform the search and get the results.\n      search_results = client.search(**params)\n\n      # Return the results in the specified format.\n      if output_format == \"json\":\n          return search_results.as_dict()\n      elif output_format == \"html\":\n          return search_results.get(\"raw_html\", \"No HTML content found.\")\n      else:\n          raise ValueError(\"Invalid output format specified. Choose either 'json' or 'html'.\")\n\n  except requests.exceptions.HTTPError as e:\n      # Handle potential SerpApi errors and HTTP errors.\n      return {\"error\": str(e)}\n"
  },
  {
    "path": "babyagi/functionz/packs/plugins/voilanorbert.py",
    "content": "@func.register_function(\n  metadata={\"description\": \"Search for a contact by name and domain using VoilaNorbert's API.\"},\n  key_dependencies=[\"voilanorbert_api_key\"],\n  imports=[\"requests\", \"time\"]\n)\ndef search_contact_by_name_domain(name, domain):\n  \"\"\"\n  Searches for a contact by name and domain using the VoilaNorbert API.\n\n  Args:\n      name (str): Full name of the person to search.\n      domain (str): Domain of the company the person works for.\n\n  Returns:\n      dict: The contact information if found, otherwise an appropriate message.\n  \"\"\"\n  api_key = globals().get('voilanorbert_api_key')\n  if not api_key:\n      return {\"error\": \"API key not found\"}\n\n  # Prepare the API request\n  search_url = 'https://api.voilanorbert.com/2018-01-08/search/name'\n  auth = ('any_string', api_key)\n  data = {'name': name, 'domain': domain}\n\n  try:\n      # POST request to initiate search\n      response = requests.post(search_url, auth=auth, data=data)\n      if response.status_code == 402:\n          return {\"error\": \"No credits available for this search\"}\n      elif response.status_code != 200:\n          return {\"error\": f\"Failed to search contact: {response.json()}\"}\n\n      result = response.json()\n      contact_id = result.get('id')\n\n      # Polling to check if the email is found\n      contact_url = f'https://api.voilanorbert.com/2018-01-08/contacts/{contact_id}'\n      while True:\n          contact_response = requests.get(contact_url, auth=auth)\n          if contact_response.status_code == 200:\n              contact_data = contact_response.json()\n              if not contact_data['searching']:\n                  if contact_data['email']:\n                      return {\n                          \"email\": contact_data['email']['email'],\n                          \"score\": contact_data['email']['score']\n                      }\n                  return {\"message\": \"Email not found!\"}\n          time.sleep(10)\n\n  except requests.RequestException as e:\n      return {\"error\": str(e)}\n\n\n@func.register_function(\n  metadata={\"description\": \"Search for contacts by domain using VoilaNorbert's API.\"},\n  key_dependencies=[\"voilanorbert_api_key\"],\n  imports=[\"requests\"]\n)\ndef search_contact_by_domain(domain):\n  \"\"\"\n  Searches for contacts by domain using the VoilaNorbert API.\n\n  Args:\n      domain (str): The domain of the company to search for contacts.\n\n  Returns:\n      list: A list of found contacts with emails if available.\n  \"\"\"\n  api_key = globals().get('voilanorbert_api_key')\n  if not api_key:\n      return {\"error\": \"API key not found\"}\n\n  # Prepare the API request\n  search_url = 'https://api.voilanorbert.com/2018-01-08/search/domain'\n  auth = ('any_string', api_key)\n  data = {'domain': domain}\n\n  try:\n      # POST request to initiate search\n      response = requests.post(search_url, auth=auth, data=data)\n      if response.status_code == 402:\n          return {\"error\": \"No credits available for this search\"}\n      elif response.status_code != 200:\n          return {\"error\": f\"Failed to search contacts: {response.json()}\"}\n\n      result = response.json()\n      return result.get('result', [])\n\n  except requests.RequestException as e:\n      return {\"error\": str(e)}\n"
  },
  {
    "path": "babyagi/functionz/packs/plugins/wokelo.py",
    "content": "@func.register_function(\n  metadata={\"description\": \"Get an authentication token using the Wokelo API credentials.\"},\n  key_dependencies=[\"wokelo_username\", \"wokelo_password\"],\n  imports=[{\"name\": \"requests\", \"lib\": \"requests\"}]\n)\ndef get_auth_token():\n  \"\"\"Obtain an authentication token using Wokelo API credentials stored as secrets.\"\"\"\n  import requests\n  BASE_URL = 'https://api.wokelo.ai'\n  url = BASE_URL + '/auth/token'\n\n  headers = {\"Content-Type\": \"application/x-www-form-urlencoded\"}\n  data = {\n      \"client_id\": \"B5I07FeItrqH5V8ytQKNwHPDHeMQnGBheg7A6FAg\",\n      \"client_secret\": \"JkVEP6FZhTkolz9vwkFSFAMVKLO0r9CnYU2RlGcRSzxZGZSkdSbSCed30VHg55IWU94F3sh0fTGUy8dTGslQZmcpCGvPhEUs9w3uobWa4ftXvsahriFCReRIxEUdd2f8\",\n      \"grant_type\": \"password\",\n      \"username\": globals()['wokelo_username'],\n      \"password\": globals()['wokelo_password'],\n  }\n\n  response = requests.post(url, headers=headers, data=data)\n\n  if response.status_code == 200:\n      # Successfully obtained token\n      token_info = response.json()\n      return token_info.get(\"access_token\")\n  else:\n      return {\"error\": f\"Failed to obtain token. Status code: {response.status_code}\", \"details\": response.text}\n\n\n@func.register_function(\n  metadata={\"description\": \"Create an industry snapshot report in Wokelo.\"},\n  dependencies=[\"get_auth_token\"],\n  imports=[{\"name\": \"requests\", \"lib\": \"requests\"}]\n)\ndef create_industry_snapshot(access_token: str, industry_name: str):\n  \"\"\"Initiate a new industry snapshot report.\"\"\"\n  import requests\n  BASE_URL = 'https://api.wokelo.ai'\n  url = f'{BASE_URL}/api/industry_primer/v3/start/'\n  headers = {'Authorization': f'Bearer {access_token}', 'Content-Type': 'application/json'}\n  payload = {\"industry\": industry_name}\n\n  response = requests.post(url, json=payload, headers=headers)\n  if response.status_code == 200:\n      return response.json().get('report_id')\n  else:\n      return {\"error\": \"Failed to create industry snapshot.\", \"details\": response.text}\n\n\n@func.register_function(\n  metadata={\"description\": \"Check the status of an industry report using its report ID.\"},\n  dependencies=[\"get_auth_token\"],\n  imports=[{\"name\": \"requests\", \"lib\": \"requests\"}]\n)\ndef check_report_status(access_token: str, report_id: str):\n  \"\"\"Check the status of a generated report in Wokelo.\"\"\"\n  import requests\n  BASE_URL = 'https://api.wokelo.ai'\n  url = f'{BASE_URL}/api/assets/get_report_status/?report_id={report_id}'\n  headers = {'Authorization': f'Bearer {access_token}'}\n\n  response = requests.get(url, headers=headers)\n  if response.status_code == 200:\n      return response.json()\n  else:\n      return {\"error\": \"Failed to check report status.\", \"details\": response.text}\n\n\n@func.register_function(\n  metadata={\"description\": \"Download the generated report from Wokelo.\"},\n  dependencies=[\"get_auth_token\"],\n  imports=[{\"name\": \"requests\", \"lib\": \"requests\"}]\n)\ndef download_report(access_token: str, report_id: str, file_type: str = 'pdf'):\n  \"\"\"Download a specific report in a given file format.\"\"\"\n  import requests\n  BASE_URL = 'https://api.wokelo.ai'\n  url = f'{BASE_URL}/api/assets/download_report/'\n  headers = {'Authorization': f'Bearer {access_token}', 'Content-Type': 'application/json'}\n  payload = {\"file_type\": file_type, \"report_id\": report_id}\n\n  response = requests.post(url, json=payload, headers=headers)\n  if response.status_code == 200:\n      return response.content\n  else:\n      return {\"error\": \"Failed to download report.\", \"details\": response.text}\n\n\n@func.register_function(\n  metadata={\"description\": \"Generate an industry report in Wokelo by tying all steps together.\"},\n  dependencies=[\"get_auth_token\", \"create_industry_snapshot\", \"check_report_status\", \"download_report\"],\n  imports=[{\"name\": \"time\", \"lib\": \"time\"}]\n)\ndef generate_industry_report(industry_name: str, file_type: str = 'pdf'):\n  \"\"\"\n  Complete workflow for generating and downloading an industry report.\n\n  Args:\n      industry_name (str): The name of the industry to generate the report for.\n      file_type (str): The format of the report file to be downloaded. Default is 'pdf'.\n\n  Returns:\n      str: File path of the downloaded report.\n  \"\"\"\n  # Step 1: Get an authentication token.\n  access_token = get_auth_token()\n  if not isinstance(access_token, str):\n      return access_token  # If there's an error, return the error message.\n\n  # Step 2: Create an industry snapshot.\n  report_id = create_industry_snapshot(access_token, industry_name)\n  if not isinstance(report_id, str):\n      return report_id  # If there's an error, return the error message.\n\n  # Step 3: Check report status until it's ready.\n  print(f\"Initiated report creation. Waiting for the report (ID: {report_id}) to be exported.\")\n  while True:\n      status_info = check_report_status(access_token, report_id)\n      if 'status' in status_info and status_info['status'] == 'exported':\n          print(f\"Report is ready for download: {report_id}\")\n          break\n      elif 'status' in status_info:\n          print(f\"Current report status: {status_info['status']}. Checking again in 30 seconds...\")\n      else:\n          return status_info  # Error occurred.\n      time.sleep(30)\n\n  # Step 4: Download the report.\n  report_content = download_report(access_token, report_id, file_type)\n  if isinstance(report_content, dict) and 'error' in report_content:\n      return report_content  # Return the error if download failed.\n\n  # Step 5: Save the report locally.\n  report_filename = f'report_{report_id}.{file_type}'\n  with open(report_filename, 'wb') as report_file:\n      report_file.write(report_content)\n\n  return f\"Report downloaded successfully: {report_filename}\"\n"
  },
  {
    "path": "examples/custom_flask_example.py",
    "content": "#this is an example of how to use the babyagi framework in a custom flask app\n\nfrom flask import Flask\nimport babyagi\nfrom babyagi import register_function, load_functions\n\napp = Flask(__name__)\n\n# Use the babyagi blueprints\nbabyagi.use_blueprints(app, dashboard_route='/dashboard')\n\n@register_function()\ndef integrated_function():\n    return \"Hello from integrated function!\"\n\nload_functions('plugins/firecrawl')\n\n@app.route('/')\ndef home():\n    return \"Welcome to the main app. Visit /dashboard for BabyAGI dashboard.\"\n\nif __name__ == \"__main__\":\n    app.run(host='0.0.0.0', port=8080)\n"
  },
  {
    "path": "examples/custom_route_example.py",
    "content": "# this is an example of how to use babyagi with custom routes\n\nfrom babyagi import create_app, register_function\n\napp = create_app('/dashboard')\n\n@register_function()\ndef another_custom_function():\n    return \"Hello from another custom function!\"\n\n@app.route('/')\ndef home():\n    return f\"Welcome to the main app. Visit <a href=\\\"/dashboard\\\">/dashboard</a> for BabyAGI dashboard.\"\n\nif __name__ == \"__main__\":\n    app.run(host='0.0.0.0', port=8080)\n"
  },
  {
    "path": "examples/quickstart_example.py",
    "content": "\n\nimport babyagi\nimport os\n\n\napp = babyagi.create_app('/dashboard')\n\n# Add OpenAI key to enable automated descriptions and embedding of functions.\nbabyagi.add_key_wrapper('openai_api_key',os.environ['OPENAI_API_KEY'])\n\n\n@app.route('/')\ndef home():\n    return f\"Welcome to the main app. Visit <a href=\\\"/dashboard\\\">/dashboard</a> for BabyAGI dashboard.\"\n\nif __name__ == \"__main__\":\n    app.run(host='0.0.0.0', port=8080)\n"
  },
  {
    "path": "examples/self_build_example.py",
    "content": "import babyagi\nimport os\n\n# Add OpenAI key to enable automated descriptions and embedding of functions.\nbabyagi.add_key_wrapper('openai_api_key',os.environ['OPENAI_API_KEY'])\n\n# Load below function packs to play with experimental self-building functions\nbabyagi.load_functions(\"drafts/code_writing_functions\")\nbabyagi.load_functions(\"drafts/self_build\")\n\n\nbabyagi.self_build(\"A growth marketer at an enterprise SaaS company.\")\n\n@app.route('/')\ndef home():\n    return f\"Welcome to the main app. Visit <a href=\\\"/dashboard\\\">/dashboard</a> for BabyAGI dashboard.\"\n\nif __name__ == \"__main__\":\n    app = babyagi.create_app('/dashboard')\n    app.run(host='0.0.0.0', port=8080)\n"
  },
  {
    "path": "examples/simple_example.py",
    "content": "# this is a simple example of registering two functions into babyagi, executing the function stored in the database, and loading the dashboard\n\nimport babyagi\nimport os\n\n# Add OpenAI key to enable automated descriptions and embedding of functions.\nbabyagi.add_key_wrapper('openai_api_key',os.environ['OPENAI_API_KEY'])\n\n@babyagi.register_function()\ndef world():\n    return \"world\"\n\n@babyagi.register_function(dependencies=[\"world\"])\ndef hello_world():\n    x = world()\n    return f\"Hello {x}!\"\n\nprint(hello_world())\n\n@app.route('/')\ndef home():\n    return f\"Welcome to the main app. Visit <a href=\\\"/dashboard\\\">/dashboard</a> for BabyAGI dashboard.\"\n\nif __name__ == \"__main__\":\n    app = babyagi.create_app('/dashboard')\n    app.run(host='0.0.0.0', port=8080)\n"
  },
  {
    "path": "examples/trigger_example.py",
    "content": "import babyagi\n\n@babyagi.register_function()\ndef function_a():\n    print(\"Result from function A\")\n    return \"Result from function A\"\n\n@babyagi.register_function(triggers=['function_a'])\ndef function_b(input_data):\n    print(f\"Function B triggered with input: {input_data}\")\n    return f\"Function B triggered with input: {input_data}\"\n\nfunction_a()\n\n@app.route('/')\ndef home():\n    return f\"Welcome to the main app. Visit <a href=\\\"/dashboard\\\">/dashboard</a> for BabyAGI dashboard.\"\n\nif __name__ == \"__main__\":\n    app = babyagi.create_app('/dashboard')\n    app.run(host='0.0.0.0', port=8080)"
  },
  {
    "path": "main.py",
    "content": "import babyagi\nimport os\n\n\napp = babyagi.create_app('/dashboard')\n\n# Add OpenAI key to enable automated descriptions and embedding of functions.\nbabyagi.add_key_wrapper('openai_api_key',os.environ['OPENAI_API_KEY'])\n\n\n@app.route('/')\ndef home():\n    return f\"Welcome to the main app. Visit <a href=\\\"/dashboard\\\">/dashboard</a> for BabyAGI dashboard.\"\n\nif __name__ == \"__main__\":\n    app.run(host='0.0.0.0', port=8080)\n"
  },
  {
    "path": "pyproject.toml",
    "content": "[tool.poetry]\nname = \"babyagi\"\nversion = \"0.0.8\"\ndescription = \"\"\nauthors = [\"Your Name <you@example.com>\"]\n\n[tool.poetry.dependencies]\npython = \">=3.10.0,<3.12\"\ndb = \"^0.1.1\"\nflask = \"^3.0.3\"\nwerkzeug = \"^3.0.4\"\nsetuptools = \"^75.1.0\"\n\n[tool.pyright]\n# https://github.com/microsoft/pyright/blob/main/docs/configuration.md\nuseLibraryCodeForTypes = true\nexclude = [\".cache\"]\n\n[tool.ruff]\n# https://beta.ruff.rs/docs/configuration/\nselect = ['E', 'W', 'F', 'I', 'B', 'C4', 'ARG', 'SIM']\nignore = ['W291', 'W292', 'W293']\n\n[build-system]\nrequires = [\"poetry-core>=1.0.0\"]\nbuild-backend = \"poetry.core.masonry.api\""
  },
  {
    "path": "requirements.txt",
    "content": "Flask>=2.0.0\nsqlalchemy>=1.4,<2.0\ncryptography\nscikit-learn\nlitellm\nopenai"
  },
  {
    "path": "setup.py",
    "content": "from setuptools import setup, find_packages\nimport os\n\n# Read the long description from README.md\nwith open(\"README.md\", \"r\", encoding=\"utf-8\") as fh:\n    long_description = fh.read()\n\n# Read requirements from requirements.txt\ndef parse_requirements(filename):\n    with open(filename, \"r\") as f:\n        lines = f.readlines()\n    # Remove comments and empty lines\n    return [line.strip() for line in lines if line.strip() and not line.startswith(\"#\")]\n\nsetup(\n    name=\"babyagi\",  # Ensure this is the desired package name\n    version=\"0.1.2\",  # Update this version appropriately\n    author=\"Yohei Nakajima\",\n    author_email=\"babyagi@untapped.vc\",\n    description=\"An experimental prototype framework for building self building autonomous agents.\",\n    long_description=  long_description,\n    long_description_content_type=\"text/markdown\",\n    url=\"https://github.com/yoheinakajima/babyagi\",  # Update if necessary\n    packages=find_packages(),\n    include_package_data=True,  # Include package data as specified in MANIFEST.in\n    classifiers=[\n        \"Programming Language :: Python :: 3\",\n        \"License :: OSI Approved :: MIT License\",\n        \"Operating System :: OS Independent\",\n    ],\n    python_requires='>=3.6',\n    install_requires=parse_requirements(\"requirements.txt\"),\n    entry_points={\n        'console_scripts': [\n            'babyagi=babyagi.main:main',  # Example entry point\n        ],\n    },\n    keywords=\"AGI, AI, Framework, Baby AGI\",\n    project_urls={  # Optional\n        \"Author\": \"https://x.com/yoheinakajima\",\n    },\n)\n"
  }
]