diff --git a/.github/workflows/claude-ci-failure-auto-fix.yml b/.github/workflows/claude-ci-failure-auto-fix.yml
index 070a4acd14..ab07c8ae10 100644
--- a/.github/workflows/claude-ci-failure-auto-fix.yml
+++ b/.github/workflows/claude-ci-failure-auto-fix.yml
@@ -22,7 +22,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
ref: ${{ github.event.workflow_run.head_branch }}
fetch-depth: 0
diff --git a/.github/workflows/claude-dependabot.yml b/.github/workflows/claude-dependabot.yml
index 6dbe068c3d..da37df6de7 100644
--- a/.github/workflows/claude-dependabot.yml
+++ b/.github/workflows/claude-dependabot.yml
@@ -30,7 +30,7 @@ jobs:
actions: read # Required for CI access
steps:
- name: Checkout code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
fetch-depth: 1
diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml
index 8e165b823e..ee901fe5d4 100644
--- a/.github/workflows/claude.yml
+++ b/.github/workflows/claude.yml
@@ -40,7 +40,7 @@ jobs:
actions: read # Required for CI access
steps:
- name: Checkout code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
fetch-depth: 1
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index a6c36ed86c..966243323c 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -58,7 +58,7 @@ jobs:
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml
index eae6eea5d2..dad99cb8d9 100644
--- a/.github/workflows/copilot-setup-steps.yml
+++ b/.github/workflows/copilot-setup-steps.yml
@@ -27,7 +27,7 @@ jobs:
# If you do not check out your code, Copilot will do this for you.
steps:
- name: Checkout code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
fetch-depth: 0
submodules: true
diff --git a/.github/workflows/docs-block-sync.yml b/.github/workflows/docs-block-sync.yml
index 4977877b19..32f205019f 100644
--- a/.github/workflows/docs-block-sync.yml
+++ b/.github/workflows/docs-block-sync.yml
@@ -23,7 +23,7 @@ jobs:
steps:
- name: Checkout code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
fetch-depth: 1
diff --git a/.github/workflows/docs-claude-review.yml b/.github/workflows/docs-claude-review.yml
index 1643fe1c49..ca2788b387 100644
--- a/.github/workflows/docs-claude-review.yml
+++ b/.github/workflows/docs-claude-review.yml
@@ -23,7 +23,7 @@ jobs:
steps:
- name: Checkout code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
fetch-depth: 0
diff --git a/.github/workflows/docs-enhance.yml b/.github/workflows/docs-enhance.yml
index 4baa882cd1..52607fa5df 100644
--- a/.github/workflows/docs-enhance.yml
+++ b/.github/workflows/docs-enhance.yml
@@ -28,7 +28,7 @@ jobs:
steps:
- name: Checkout code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
fetch-depth: 1
diff --git a/.github/workflows/platform-autogpt-deploy-dev.yaml b/.github/workflows/platform-autogpt-deploy-dev.yaml
index 6e1e23d3eb..b415fb1b7b 100644
--- a/.github/workflows/platform-autogpt-deploy-dev.yaml
+++ b/.github/workflows/platform-autogpt-deploy-dev.yaml
@@ -25,7 +25,7 @@ jobs:
steps:
- name: Checkout code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
ref: ${{ github.event.inputs.git_ref || github.ref_name }}
@@ -52,7 +52,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Trigger deploy workflow
- uses: peter-evans/repository-dispatch@v3
+ uses: peter-evans/repository-dispatch@v4
with:
token: ${{ secrets.DEPLOY_TOKEN }}
repository: Significant-Gravitas/AutoGPT_cloud_infrastructure
diff --git a/.github/workflows/platform-autogpt-deploy-prod.yml b/.github/workflows/platform-autogpt-deploy-prod.yml
index 4d7c16d710..e0c524d8d2 100644
--- a/.github/workflows/platform-autogpt-deploy-prod.yml
+++ b/.github/workflows/platform-autogpt-deploy-prod.yml
@@ -17,7 +17,7 @@ jobs:
steps:
- name: Checkout code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
ref: ${{ github.ref_name || 'master' }}
@@ -45,7 +45,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Trigger deploy workflow
- uses: peter-evans/repository-dispatch@v3
+ uses: peter-evans/repository-dispatch@v4
with:
token: ${{ secrets.DEPLOY_TOKEN }}
repository: Significant-Gravitas/AutoGPT_cloud_infrastructure
diff --git a/.github/workflows/platform-backend-ci.yml b/.github/workflows/platform-backend-ci.yml
index a301477ecf..1f0c6da3dd 100644
--- a/.github/workflows/platform-backend-ci.yml
+++ b/.github/workflows/platform-backend-ci.yml
@@ -68,7 +68,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
fetch-depth: 0
submodules: true
diff --git a/.github/workflows/platform-dev-deploy-event-dispatcher.yml b/.github/workflows/platform-dev-deploy-event-dispatcher.yml
index b5324b7c2c..1a581c55c2 100644
--- a/.github/workflows/platform-dev-deploy-event-dispatcher.yml
+++ b/.github/workflows/platform-dev-deploy-event-dispatcher.yml
@@ -82,7 +82,7 @@ jobs:
- name: Dispatch Deploy Event
if: steps.check_status.outputs.should_deploy == 'true'
- uses: peter-evans/repository-dispatch@v3
+ uses: peter-evans/repository-dispatch@v4
with:
token: ${{ secrets.DISPATCH_TOKEN }}
repository: Significant-Gravitas/AutoGPT_cloud_infrastructure
@@ -110,7 +110,7 @@ jobs:
- name: Dispatch Undeploy Event (from comment)
if: steps.check_status.outputs.should_undeploy == 'true'
- uses: peter-evans/repository-dispatch@v3
+ uses: peter-evans/repository-dispatch@v4
with:
token: ${{ secrets.DISPATCH_TOKEN }}
repository: Significant-Gravitas/AutoGPT_cloud_infrastructure
@@ -168,7 +168,7 @@ jobs:
github.event_name == 'pull_request' &&
github.event.action == 'closed' &&
steps.check_pr_close.outputs.should_undeploy == 'true'
- uses: peter-evans/repository-dispatch@v3
+ uses: peter-evans/repository-dispatch@v4
with:
token: ${{ secrets.DISPATCH_TOKEN }}
repository: Significant-Gravitas/AutoGPT_cloud_infrastructure
diff --git a/.github/workflows/platform-frontend-ci.yml b/.github/workflows/platform-frontend-ci.yml
index 669a775934..6410daae9f 100644
--- a/.github/workflows/platform-frontend-ci.yml
+++ b/.github/workflows/platform-frontend-ci.yml
@@ -31,7 +31,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
- name: Check for component changes
uses: dorny/paths-filter@v3
@@ -71,7 +71,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
- name: Set up Node.js
uses: actions/setup-node@v6
@@ -107,7 +107,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
fetch-depth: 0
@@ -148,7 +148,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
submodules: recursive
@@ -277,7 +277,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
submodules: recursive
diff --git a/.github/workflows/platform-fullstack-ci.yml b/.github/workflows/platform-fullstack-ci.yml
index ab483b98af..b4724245dc 100644
--- a/.github/workflows/platform-fullstack-ci.yml
+++ b/.github/workflows/platform-fullstack-ci.yml
@@ -29,7 +29,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
- name: Set up Node.js
uses: actions/setup-node@v6
@@ -63,7 +63,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
submodules: recursive
diff --git a/.github/workflows/repo-workflow-checker.yml b/.github/workflows/repo-workflow-checker.yml
index 35536ba922..aa94622d31 100644
--- a/.github/workflows/repo-workflow-checker.yml
+++ b/.github/workflows/repo-workflow-checker.yml
@@ -11,7 +11,7 @@ jobs:
steps:
# - name: Wait some time for all actions to start
# run: sleep 30
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
# with:
# fetch-depth: 0
- name: Set up Python
diff --git a/autogpt_platform/backend/backend/api/external/v1/routes.py b/autogpt_platform/backend/backend/api/external/v1/routes.py
index 00933c1899..bae61124e2 100644
--- a/autogpt_platform/backend/backend/api/external/v1/routes.py
+++ b/autogpt_platform/backend/backend/api/external/v1/routes.py
@@ -10,13 +10,13 @@ from typing_extensions import TypedDict
import backend.api.features.store.cache as store_cache
import backend.api.features.store.model as store_model
-import backend.data.block
+import backend.blocks
from backend.api.external.middleware import require_permission
+from backend.blocks._base import BlockInput, CompletedBlockOutput
from backend.data import execution as execution_db
from backend.data import graph as graph_db
from backend.data import user as user_db
from backend.data.auth.base import APIAuthorizationInfo
-from backend.data.block import BlockInput, CompletedBlockOutput
from backend.executor.utils import add_graph_execution
from backend.util.settings import Settings
@@ -67,7 +67,7 @@ async def get_user_info(
dependencies=[Security(require_permission(APIKeyPermission.READ_BLOCK))],
)
async def get_graph_blocks() -> Sequence[dict[Any, Any]]:
- blocks = [block() for block in backend.data.block.get_blocks().values()]
+ blocks = [block() for block in backend.blocks.get_blocks().values()]
return [b.to_dict() for b in blocks if not b.disabled]
@@ -83,7 +83,7 @@ async def execute_graph_block(
require_permission(APIKeyPermission.EXECUTE_BLOCK)
),
) -> CompletedBlockOutput:
- obj = backend.data.block.get_block(block_id)
+ obj = backend.blocks.get_block(block_id)
if not obj:
raise HTTPException(status_code=404, detail=f"Block #{block_id} not found.")
if obj.disabled:
diff --git a/autogpt_platform/backend/backend/api/features/builder/db.py b/autogpt_platform/backend/backend/api/features/builder/db.py
index 7177fa4dc6..7b228c043d 100644
--- a/autogpt_platform/backend/backend/api/features/builder/db.py
+++ b/autogpt_platform/backend/backend/api/features/builder/db.py
@@ -10,10 +10,10 @@ import backend.api.features.library.db as library_db
import backend.api.features.library.model as library_model
import backend.api.features.store.db as store_db
import backend.api.features.store.model as store_model
-import backend.data.block
+import backend.blocks._base
from backend.blocks import load_all_blocks
+from backend.blocks._base import AnyBlockSchema, BlockCategory, BlockInfo, BlockSchema
from backend.blocks.llm import LlmModel
-from backend.data.block import AnyBlockSchema, BlockCategory, BlockInfo, BlockSchema
from backend.data.db import query_raw_with_schema
from backend.integrations.providers import ProviderName
from backend.util.cache import cached
@@ -669,9 +669,9 @@ async def get_suggested_blocks(count: int = 5) -> list[BlockInfo]:
for block_type in load_all_blocks().values():
block: AnyBlockSchema = block_type()
if block.disabled or block.block_type in (
- backend.data.block.BlockType.INPUT,
- backend.data.block.BlockType.OUTPUT,
- backend.data.block.BlockType.AGENT,
+ backend.blocks._base.BlockType.INPUT,
+ backend.blocks._base.BlockType.OUTPUT,
+ backend.blocks._base.BlockType.AGENT,
):
continue
# Find the execution count for this block
diff --git a/autogpt_platform/backend/backend/api/features/builder/model.py b/autogpt_platform/backend/backend/api/features/builder/model.py
index fcd19dba94..f9b883d5bc 100644
--- a/autogpt_platform/backend/backend/api/features/builder/model.py
+++ b/autogpt_platform/backend/backend/api/features/builder/model.py
@@ -4,7 +4,7 @@ from pydantic import BaseModel
import backend.api.features.library.model as library_model
import backend.api.features.store.model as store_model
-from backend.data.block import BlockInfo
+from backend.blocks._base import BlockInfo
from backend.integrations.providers import ProviderName
from backend.util.models import Pagination
diff --git a/autogpt_platform/backend/backend/api/features/library/db.py b/autogpt_platform/backend/backend/api/features/library/db.py
index 32479c18a3..1c7219cd6e 100644
--- a/autogpt_platform/backend/backend/api/features/library/db.py
+++ b/autogpt_platform/backend/backend/api/features/library/db.py
@@ -12,7 +12,7 @@ import backend.api.features.store.image_gen as store_image_gen
import backend.api.features.store.media as store_media
import backend.data.graph as graph_db
import backend.data.integrations as integrations_db
-from backend.data.block import BlockInput
+from backend.blocks._base import BlockInput
from backend.data.db import transaction
from backend.data.execution import get_graph_execution
from backend.data.graph import GraphSettings
diff --git a/autogpt_platform/backend/backend/api/features/library/model.py b/autogpt_platform/backend/backend/api/features/library/model.py
index c6bc0e0427..69bbe85486 100644
--- a/autogpt_platform/backend/backend/api/features/library/model.py
+++ b/autogpt_platform/backend/backend/api/features/library/model.py
@@ -6,7 +6,7 @@ import prisma.enums
import prisma.models
import pydantic
-from backend.data.block import BlockInput
+from backend.blocks._base import BlockInput
from backend.data.graph import GraphModel, GraphSettings, GraphTriggerInfo
from backend.data.model import CredentialsMetaInput, is_credentials_field_name
from backend.util.json import loads as json_loads
diff --git a/autogpt_platform/backend/backend/api/features/otto/service.py b/autogpt_platform/backend/backend/api/features/otto/service.py
index 5f00022ff2..992021c0ca 100644
--- a/autogpt_platform/backend/backend/api/features/otto/service.py
+++ b/autogpt_platform/backend/backend/api/features/otto/service.py
@@ -5,8 +5,8 @@ from typing import Optional
import aiohttp
from fastapi import HTTPException
+from backend.blocks import get_block
from backend.data import graph as graph_db
-from backend.data.block import get_block
from backend.util.settings import Settings
from .models import ApiResponse, ChatRequest, GraphData
diff --git a/autogpt_platform/backend/backend/api/features/store/content_handlers.py b/autogpt_platform/backend/backend/api/features/store/content_handlers.py
index cbbdcfbebf..38fc1e27d0 100644
--- a/autogpt_platform/backend/backend/api/features/store/content_handlers.py
+++ b/autogpt_platform/backend/backend/api/features/store/content_handlers.py
@@ -152,7 +152,7 @@ class BlockHandler(ContentHandler):
async def get_missing_items(self, batch_size: int) -> list[ContentItem]:
"""Fetch blocks without embeddings."""
- from backend.data.block import get_blocks
+ from backend.blocks import get_blocks
# Get all available blocks
all_blocks = get_blocks()
@@ -249,7 +249,7 @@ class BlockHandler(ContentHandler):
async def get_stats(self) -> dict[str, int]:
"""Get statistics about block embedding coverage."""
- from backend.data.block import get_blocks
+ from backend.blocks import get_blocks
all_blocks = get_blocks()
diff --git a/autogpt_platform/backend/backend/api/features/store/content_handlers_test.py b/autogpt_platform/backend/backend/api/features/store/content_handlers_test.py
index fee879fae0..c552e44a9d 100644
--- a/autogpt_platform/backend/backend/api/features/store/content_handlers_test.py
+++ b/autogpt_platform/backend/backend/api/features/store/content_handlers_test.py
@@ -93,7 +93,7 @@ async def test_block_handler_get_missing_items(mocker):
mock_existing = []
with patch(
- "backend.data.block.get_blocks",
+ "backend.blocks.get_blocks",
return_value=mock_blocks,
):
with patch(
@@ -135,7 +135,7 @@ async def test_block_handler_get_stats(mocker):
mock_embedded = [{"count": 2}]
with patch(
- "backend.data.block.get_blocks",
+ "backend.blocks.get_blocks",
return_value=mock_blocks,
):
with patch(
@@ -327,7 +327,7 @@ async def test_block_handler_handles_missing_attributes():
mock_blocks = {"block-minimal": mock_block_class}
with patch(
- "backend.data.block.get_blocks",
+ "backend.blocks.get_blocks",
return_value=mock_blocks,
):
with patch(
@@ -360,7 +360,7 @@ async def test_block_handler_skips_failed_blocks():
mock_blocks = {"good-block": good_block, "bad-block": bad_block}
with patch(
- "backend.data.block.get_blocks",
+ "backend.blocks.get_blocks",
return_value=mock_blocks,
):
with patch(
diff --git a/autogpt_platform/backend/backend/api/features/store/embeddings.py b/autogpt_platform/backend/backend/api/features/store/embeddings.py
index 434f2fe2ce..921e103618 100644
--- a/autogpt_platform/backend/backend/api/features/store/embeddings.py
+++ b/autogpt_platform/backend/backend/api/features/store/embeddings.py
@@ -662,7 +662,7 @@ async def cleanup_orphaned_embeddings() -> dict[str, Any]:
)
current_ids = {row["id"] for row in valid_agents}
elif content_type == ContentType.BLOCK:
- from backend.data.block import get_blocks
+ from backend.blocks import get_blocks
current_ids = set(get_blocks().keys())
elif content_type == ContentType.DOCUMENTATION:
diff --git a/autogpt_platform/backend/backend/api/features/v1.py b/autogpt_platform/backend/backend/api/features/v1.py
index a8610702cc..713bbaa7d6 100644
--- a/autogpt_platform/backend/backend/api/features/v1.py
+++ b/autogpt_platform/backend/backend/api/features/v1.py
@@ -40,10 +40,11 @@ from backend.api.model import (
UpdateTimezoneRequest,
UploadFileResponse,
)
+from backend.blocks import get_block, get_blocks
+from backend.blocks._base import BlockInput, CompletedBlockOutput
from backend.data import execution as execution_db
from backend.data import graph as graph_db
from backend.data.auth import api_key as api_key_db
-from backend.data.block import BlockInput, CompletedBlockOutput, get_block, get_blocks
from backend.data.credit import (
AutoTopUpConfig,
RefundRequest,
diff --git a/autogpt_platform/backend/backend/blocks/__init__.py b/autogpt_platform/backend/backend/blocks/__init__.py
index a6c16393c7..5876be0893 100644
--- a/autogpt_platform/backend/backend/blocks/__init__.py
+++ b/autogpt_platform/backend/backend/blocks/__init__.py
@@ -3,7 +3,7 @@ import logging
import os
import re
from pathlib import Path
-from typing import TYPE_CHECKING, TypeVar
+from typing import TYPE_CHECKING, Sequence, Type, TypeVar
from backend.util.cache import cached
@@ -11,14 +11,14 @@ logger = logging.getLogger(__name__)
if TYPE_CHECKING:
- from backend.data.block import Block
+ from backend.blocks._base import AnyBlockSchema, BlockType
T = TypeVar("T")
@cached(ttl_seconds=3600)
-def load_all_blocks() -> dict[str, type["Block"]]:
- from backend.data.block import Block
+def load_all_blocks() -> dict[str, type["AnyBlockSchema"]]:
+ from backend.blocks._base import Block
from backend.util.settings import Config
# Check if example blocks should be loaded from settings
@@ -50,8 +50,8 @@ def load_all_blocks() -> dict[str, type["Block"]]:
importlib.import_module(f".{module}", package=__name__)
# Load all Block instances from the available modules
- available_blocks: dict[str, type["Block"]] = {}
- for block_cls in all_subclasses(Block):
+ available_blocks: dict[str, type["AnyBlockSchema"]] = {}
+ for block_cls in _all_subclasses(Block):
class_name = block_cls.__name__
if class_name.endswith("Base"):
@@ -64,7 +64,7 @@ def load_all_blocks() -> dict[str, type["Block"]]:
"please name the class with 'Base' at the end"
)
- block = block_cls.create()
+ block = block_cls() # pyright: ignore[reportAbstractUsage]
if not isinstance(block.id, str) or len(block.id) != 36:
raise ValueError(
@@ -105,7 +105,7 @@ def load_all_blocks() -> dict[str, type["Block"]]:
available_blocks[block.id] = block_cls
# Filter out blocks with incomplete auth configs, e.g. missing OAuth server secrets
- from backend.data.block import is_block_auth_configured
+ from ._utils import is_block_auth_configured
filtered_blocks = {}
for block_id, block_cls in available_blocks.items():
@@ -115,11 +115,48 @@ def load_all_blocks() -> dict[str, type["Block"]]:
return filtered_blocks
-__all__ = ["load_all_blocks"]
-
-
-def all_subclasses(cls: type[T]) -> list[type[T]]:
+def _all_subclasses(cls: type[T]) -> list[type[T]]:
subclasses = cls.__subclasses__()
for subclass in subclasses:
- subclasses += all_subclasses(subclass)
+ subclasses += _all_subclasses(subclass)
return subclasses
+
+
+# ============== Block access helper functions ============== #
+
+
+def get_blocks() -> dict[str, Type[AnyBlockSchema]]:
+ return load_all_blocks()
+
+
+# Note on the return type annotation: https://github.com/microsoft/pyright/issues/10281
+def get_block(block_id: str) -> AnyBlockSchema | None:
+ cls = get_blocks().get(block_id)
+ return cls() if cls else None
+
+
+@cached(ttl_seconds=3600)
+def get_webhook_block_ids() -> Sequence[str]:
+ return [
+ id
+ for id, B in get_blocks().items()
+ if B().block_type in (BlockType.WEBHOOK, BlockType.WEBHOOK_MANUAL)
+ ]
+
+
+@cached(ttl_seconds=3600)
+def get_io_block_ids() -> Sequence[str]:
+ return [
+ id
+ for id, B in get_blocks().items()
+ if B().block_type in (BlockType.INPUT, BlockType.OUTPUT)
+ ]
+
+
+@cached(ttl_seconds=3600)
+def get_human_in_the_loop_block_ids() -> Sequence[str]:
+ return [
+ id
+ for id, B in get_blocks().items()
+ if B().block_type == BlockType.HUMAN_IN_THE_LOOP
+ ]
diff --git a/autogpt_platform/backend/backend/blocks/_base.py b/autogpt_platform/backend/backend/blocks/_base.py
new file mode 100644
index 0000000000..626b99fc9f
--- /dev/null
+++ b/autogpt_platform/backend/backend/blocks/_base.py
@@ -0,0 +1,744 @@
+import inspect
+import logging
+from abc import ABC, abstractmethod
+from collections.abc import AsyncGenerator as AsyncGen
+from enum import Enum
+from typing import (
+ TYPE_CHECKING,
+ Any,
+ Callable,
+ ClassVar,
+ Generic,
+ Optional,
+ Type,
+ TypeAlias,
+ TypeVar,
+ cast,
+ get_origin,
+)
+
+import jsonref
+import jsonschema
+from pydantic import BaseModel
+
+from backend.integrations.providers import ProviderName
+from backend.util import json
+from backend.util.exceptions import (
+ BlockError,
+ BlockExecutionError,
+ BlockInputError,
+ BlockOutputError,
+ BlockUnknownError,
+)
+from backend.util.settings import Config
+
+from ..data.model import (
+ ContributorDetails,
+ Credentials,
+ CredentialsFieldInfo,
+ CredentialsMetaInput,
+ SchemaField,
+ is_credentials_field_name,
+)
+
+logger = logging.getLogger(__name__)
+
+if TYPE_CHECKING:
+ from backend.data.execution import ExecutionContext
+ from backend.data.model import NodeExecutionStats
+
+ from ..data.graph import Link
+
+app_config = Config()
+
+BlockInput = dict[str, Any] # Input: 1 input pin consumes 1 data.
+BlockOutputEntry = tuple[str, Any] # Output data should be a tuple of (name, value).
+BlockOutput = AsyncGen[BlockOutputEntry, None] # Output: 1 output pin produces n data.
+BlockTestOutput = BlockOutputEntry | tuple[str, Callable[[Any], bool]]
+CompletedBlockOutput = dict[str, list[Any]] # Completed stream, collected as a dict.
+
+
+class BlockType(Enum):
+ STANDARD = "Standard"
+ INPUT = "Input"
+ OUTPUT = "Output"
+ NOTE = "Note"
+ WEBHOOK = "Webhook"
+ WEBHOOK_MANUAL = "Webhook (manual)"
+ AGENT = "Agent"
+ AI = "AI"
+ AYRSHARE = "Ayrshare"
+ HUMAN_IN_THE_LOOP = "Human In The Loop"
+
+
+class BlockCategory(Enum):
+ AI = "Block that leverages AI to perform a task."
+ SOCIAL = "Block that interacts with social media platforms."
+ TEXT = "Block that processes text data."
+ SEARCH = "Block that searches or extracts information from the internet."
+ BASIC = "Block that performs basic operations."
+ INPUT = "Block that interacts with input of the graph."
+ OUTPUT = "Block that interacts with output of the graph."
+ LOGIC = "Programming logic to control the flow of your agent"
+ COMMUNICATION = "Block that interacts with communication platforms."
+ DEVELOPER_TOOLS = "Developer tools such as GitHub blocks."
+ DATA = "Block that interacts with structured data."
+ HARDWARE = "Block that interacts with hardware."
+ AGENT = "Block that interacts with other agents."
+ CRM = "Block that interacts with CRM services."
+ SAFETY = (
+ "Block that provides AI safety mechanisms such as detecting harmful content"
+ )
+ PRODUCTIVITY = "Block that helps with productivity"
+ ISSUE_TRACKING = "Block that helps with issue tracking"
+ MULTIMEDIA = "Block that interacts with multimedia content"
+ MARKETING = "Block that helps with marketing"
+
+ def dict(self) -> dict[str, str]:
+ return {"category": self.name, "description": self.value}
+
+
+class BlockCostType(str, Enum):
+ RUN = "run" # cost X credits per run
+ BYTE = "byte" # cost X credits per byte
+ SECOND = "second" # cost X credits per second
+
+
+class BlockCost(BaseModel):
+ cost_amount: int
+ cost_filter: BlockInput
+ cost_type: BlockCostType
+
+ def __init__(
+ self,
+ cost_amount: int,
+ cost_type: BlockCostType = BlockCostType.RUN,
+ cost_filter: Optional[BlockInput] = None,
+ **data: Any,
+ ) -> None:
+ super().__init__(
+ cost_amount=cost_amount,
+ cost_filter=cost_filter or {},
+ cost_type=cost_type,
+ **data,
+ )
+
+
+class BlockInfo(BaseModel):
+ id: str
+ name: str
+ inputSchema: dict[str, Any]
+ outputSchema: dict[str, Any]
+ costs: list[BlockCost]
+ description: str
+ categories: list[dict[str, str]]
+ contributors: list[dict[str, Any]]
+ staticOutput: bool
+ uiType: str
+
+
+class BlockSchema(BaseModel):
+ cached_jsonschema: ClassVar[dict[str, Any]]
+
+ @classmethod
+ def jsonschema(cls) -> dict[str, Any]:
+ if cls.cached_jsonschema:
+ return cls.cached_jsonschema
+
+ model = jsonref.replace_refs(cls.model_json_schema(), merge_props=True)
+
+ def ref_to_dict(obj):
+ if isinstance(obj, dict):
+ # OpenAPI <3.1 does not support sibling fields that has a $ref key
+ # So sometimes, the schema has an "allOf"/"anyOf"/"oneOf" with 1 item.
+ keys = {"allOf", "anyOf", "oneOf"}
+ one_key = next((k for k in keys if k in obj and len(obj[k]) == 1), None)
+ if one_key:
+ obj.update(obj[one_key][0])
+
+ return {
+ key: ref_to_dict(value)
+ for key, value in obj.items()
+ if not key.startswith("$") and key != one_key
+ }
+ elif isinstance(obj, list):
+ return [ref_to_dict(item) for item in obj]
+
+ return obj
+
+ cls.cached_jsonschema = cast(dict[str, Any], ref_to_dict(model))
+
+ return cls.cached_jsonschema
+
+ @classmethod
+ def validate_data(cls, data: BlockInput) -> str | None:
+ return json.validate_with_jsonschema(
+ schema=cls.jsonschema(),
+ data={k: v for k, v in data.items() if v is not None},
+ )
+
+ @classmethod
+ def get_mismatch_error(cls, data: BlockInput) -> str | None:
+ return cls.validate_data(data)
+
+ @classmethod
+ def get_field_schema(cls, field_name: str) -> dict[str, Any]:
+ model_schema = cls.jsonschema().get("properties", {})
+ if not model_schema:
+ raise ValueError(f"Invalid model schema {cls}")
+
+ property_schema = model_schema.get(field_name)
+ if not property_schema:
+ raise ValueError(f"Invalid property name {field_name}")
+
+ return property_schema
+
+ @classmethod
+ def validate_field(cls, field_name: str, data: BlockInput) -> str | None:
+ """
+ Validate the data against a specific property (one of the input/output name).
+ Returns the validation error message if the data does not match the schema.
+ """
+ try:
+ property_schema = cls.get_field_schema(field_name)
+ jsonschema.validate(json.to_dict(data), property_schema)
+ return None
+ except jsonschema.ValidationError as e:
+ return str(e)
+
+ @classmethod
+ def get_fields(cls) -> set[str]:
+ return set(cls.model_fields.keys())
+
+ @classmethod
+ def get_required_fields(cls) -> set[str]:
+ return {
+ field
+ for field, field_info in cls.model_fields.items()
+ if field_info.is_required()
+ }
+
+ @classmethod
+ def __pydantic_init_subclass__(cls, **kwargs):
+ """Validates the schema definition. Rules:
+ - Fields with annotation `CredentialsMetaInput` MUST be
+ named `credentials` or `*_credentials`
+ - Fields named `credentials` or `*_credentials` MUST be
+ of type `CredentialsMetaInput`
+ """
+ super().__pydantic_init_subclass__(**kwargs)
+
+ # Reset cached JSON schema to prevent inheriting it from parent class
+ cls.cached_jsonschema = {}
+
+ credentials_fields = cls.get_credentials_fields()
+
+ for field_name in cls.get_fields():
+ if is_credentials_field_name(field_name):
+ if field_name not in credentials_fields:
+ raise TypeError(
+ f"Credentials field '{field_name}' on {cls.__qualname__} "
+ f"is not of type {CredentialsMetaInput.__name__}"
+ )
+
+ CredentialsMetaInput.validate_credentials_field_schema(
+ cls.get_field_schema(field_name), field_name
+ )
+
+ elif field_name in credentials_fields:
+ raise KeyError(
+ f"Credentials field '{field_name}' on {cls.__qualname__} "
+ "has invalid name: must be 'credentials' or *_credentials"
+ )
+
+ @classmethod
+ def get_credentials_fields(cls) -> dict[str, type[CredentialsMetaInput]]:
+ return {
+ field_name: info.annotation
+ for field_name, info in cls.model_fields.items()
+ if (
+ inspect.isclass(info.annotation)
+ and issubclass(
+ get_origin(info.annotation) or info.annotation,
+ CredentialsMetaInput,
+ )
+ )
+ }
+
+ @classmethod
+ def get_auto_credentials_fields(cls) -> dict[str, dict[str, Any]]:
+ """
+ Get fields that have auto_credentials metadata (e.g., GoogleDriveFileInput).
+
+ Returns a dict mapping kwarg_name -> {field_name, auto_credentials_config}
+
+ Raises:
+ ValueError: If multiple fields have the same kwarg_name, as this would
+ cause silent overwriting and only the last field would be processed.
+ """
+ result: dict[str, dict[str, Any]] = {}
+ schema = cls.jsonschema()
+ properties = schema.get("properties", {})
+
+ for field_name, field_schema in properties.items():
+ auto_creds = field_schema.get("auto_credentials")
+ if auto_creds:
+ kwarg_name = auto_creds.get("kwarg_name", "credentials")
+ if kwarg_name in result:
+ raise ValueError(
+ f"Duplicate auto_credentials kwarg_name '{kwarg_name}' "
+ f"in fields '{result[kwarg_name]['field_name']}' and "
+ f"'{field_name}' on {cls.__qualname__}"
+ )
+ result[kwarg_name] = {
+ "field_name": field_name,
+ "config": auto_creds,
+ }
+ return result
+
+ @classmethod
+ def get_credentials_fields_info(cls) -> dict[str, CredentialsFieldInfo]:
+ result = {}
+
+ # Regular credentials fields
+ for field_name in cls.get_credentials_fields().keys():
+ result[field_name] = CredentialsFieldInfo.model_validate(
+ cls.get_field_schema(field_name), by_alias=True
+ )
+
+ # Auto-generated credentials fields (from GoogleDriveFileInput etc.)
+ for kwarg_name, info in cls.get_auto_credentials_fields().items():
+ config = info["config"]
+ # Build a schema-like dict that CredentialsFieldInfo can parse
+ auto_schema = {
+ "credentials_provider": [config.get("provider", "google")],
+ "credentials_types": [config.get("type", "oauth2")],
+ "credentials_scopes": config.get("scopes"),
+ }
+ result[kwarg_name] = CredentialsFieldInfo.model_validate(
+ auto_schema, by_alias=True
+ )
+
+ return result
+
+ @classmethod
+ def get_input_defaults(cls, data: BlockInput) -> BlockInput:
+ return data # Return as is, by default.
+
+ @classmethod
+ def get_missing_links(cls, data: BlockInput, links: list["Link"]) -> set[str]:
+ input_fields_from_nodes = {link.sink_name for link in links}
+ return input_fields_from_nodes - set(data)
+
+ @classmethod
+ def get_missing_input(cls, data: BlockInput) -> set[str]:
+ return cls.get_required_fields() - set(data)
+
+
+class BlockSchemaInput(BlockSchema):
+ """
+ Base schema class for block inputs.
+ All block input schemas should extend this class for consistency.
+ """
+
+ pass
+
+
+class BlockSchemaOutput(BlockSchema):
+ """
+ Base schema class for block outputs that includes a standard error field.
+ All block output schemas should extend this class to ensure consistent error handling.
+ """
+
+ error: str = SchemaField(
+ description="Error message if the operation failed", default=""
+ )
+
+
+BlockSchemaInputType = TypeVar("BlockSchemaInputType", bound=BlockSchemaInput)
+BlockSchemaOutputType = TypeVar("BlockSchemaOutputType", bound=BlockSchemaOutput)
+
+
+class EmptyInputSchema(BlockSchemaInput):
+ pass
+
+
+class EmptyOutputSchema(BlockSchemaOutput):
+ pass
+
+
+# For backward compatibility - will be deprecated
+EmptySchema = EmptyOutputSchema
+
+
+# --8<-- [start:BlockWebhookConfig]
+class BlockManualWebhookConfig(BaseModel):
+ """
+ Configuration model for webhook-triggered blocks on which
+ the user has to manually set up the webhook at the provider.
+ """
+
+ provider: ProviderName
+ """The service provider that the webhook connects to"""
+
+ webhook_type: str
+ """
+ Identifier for the webhook type. E.g. GitHub has repo and organization level hooks.
+
+ Only for use in the corresponding `WebhooksManager`.
+ """
+
+ event_filter_input: str = ""
+ """
+ Name of the block's event filter input.
+ Leave empty if the corresponding webhook doesn't have distinct event/payload types.
+ """
+
+ event_format: str = "{event}"
+ """
+ Template string for the event(s) that a block instance subscribes to.
+ Applied individually to each event selected in the event filter input.
+
+ Example: `"pull_request.{event}"` -> `"pull_request.opened"`
+ """
+
+
+class BlockWebhookConfig(BlockManualWebhookConfig):
+ """
+ Configuration model for webhook-triggered blocks for which
+ the webhook can be automatically set up through the provider's API.
+ """
+
+ resource_format: str
+ """
+ Template string for the resource that a block instance subscribes to.
+ Fields will be filled from the block's inputs (except `payload`).
+
+ Example: `f"{repo}/pull_requests"` (note: not how it's actually implemented)
+
+ Only for use in the corresponding `WebhooksManager`.
+ """
+ # --8<-- [end:BlockWebhookConfig]
+
+
+class Block(ABC, Generic[BlockSchemaInputType, BlockSchemaOutputType]):
+ def __init__(
+ self,
+ id: str = "",
+ description: str = "",
+ contributors: list[ContributorDetails] = [],
+ categories: set[BlockCategory] | None = None,
+ input_schema: Type[BlockSchemaInputType] = EmptyInputSchema,
+ output_schema: Type[BlockSchemaOutputType] = EmptyOutputSchema,
+ test_input: BlockInput | list[BlockInput] | None = None,
+ test_output: BlockTestOutput | list[BlockTestOutput] | None = None,
+ test_mock: dict[str, Any] | None = None,
+ test_credentials: Optional[Credentials | dict[str, Credentials]] = None,
+ disabled: bool = False,
+ static_output: bool = False,
+ block_type: BlockType = BlockType.STANDARD,
+ webhook_config: Optional[BlockWebhookConfig | BlockManualWebhookConfig] = None,
+ is_sensitive_action: bool = False,
+ ):
+ """
+ Initialize the block with the given schema.
+
+ Args:
+ id: The unique identifier for the block, this value will be persisted in the
+ DB. So it should be a unique and constant across the application run.
+ Use the UUID format for the ID.
+ description: The description of the block, explaining what the block does.
+ contributors: The list of contributors who contributed to the block.
+ input_schema: The schema, defined as a Pydantic model, for the input data.
+ output_schema: The schema, defined as a Pydantic model, for the output data.
+ test_input: The list or single sample input data for the block, for testing.
+ test_output: The list or single expected output if the test_input is run.
+ test_mock: function names on the block implementation to mock on test run.
+ disabled: If the block is disabled, it will not be available for execution.
+ static_output: Whether the output links of the block are static by default.
+ """
+ from backend.data.model import NodeExecutionStats
+
+ self.id = id
+ self.input_schema = input_schema
+ self.output_schema = output_schema
+ self.test_input = test_input
+ self.test_output = test_output
+ self.test_mock = test_mock
+ self.test_credentials = test_credentials
+ self.description = description
+ self.categories = categories or set()
+ self.contributors = contributors or set()
+ self.disabled = disabled
+ self.static_output = static_output
+ self.block_type = block_type
+ self.webhook_config = webhook_config
+ self.is_sensitive_action = is_sensitive_action
+ self.execution_stats: "NodeExecutionStats" = NodeExecutionStats()
+
+ if self.webhook_config:
+ if isinstance(self.webhook_config, BlockWebhookConfig):
+ # Enforce presence of credentials field on auto-setup webhook blocks
+ if not (cred_fields := self.input_schema.get_credentials_fields()):
+ raise TypeError(
+ "credentials field is required on auto-setup webhook blocks"
+ )
+ # Disallow multiple credentials inputs on webhook blocks
+ elif len(cred_fields) > 1:
+ raise ValueError(
+ "Multiple credentials inputs not supported on webhook blocks"
+ )
+
+ self.block_type = BlockType.WEBHOOK
+ else:
+ self.block_type = BlockType.WEBHOOK_MANUAL
+
+ # Enforce shape of webhook event filter, if present
+ if self.webhook_config.event_filter_input:
+ event_filter_field = self.input_schema.model_fields[
+ self.webhook_config.event_filter_input
+ ]
+ if not (
+ isinstance(event_filter_field.annotation, type)
+ and issubclass(event_filter_field.annotation, BaseModel)
+ and all(
+ field.annotation is bool
+ for field in event_filter_field.annotation.model_fields.values()
+ )
+ ):
+ raise NotImplementedError(
+ f"{self.name} has an invalid webhook event selector: "
+ "field must be a BaseModel and all its fields must be boolean"
+ )
+
+ # Enforce presence of 'payload' input
+ if "payload" not in self.input_schema.model_fields:
+ raise TypeError(
+ f"{self.name} is webhook-triggered but has no 'payload' input"
+ )
+
+ # Disable webhook-triggered block if webhook functionality not available
+ if not app_config.platform_base_url:
+ self.disabled = True
+
+ @abstractmethod
+ async def run(self, input_data: BlockSchemaInputType, **kwargs) -> BlockOutput:
+ """
+ Run the block with the given input data.
+ Args:
+ input_data: The input data with the structure of input_schema.
+
+ Kwargs: Currently 14/02/2025 these include
+ graph_id: The ID of the graph.
+ node_id: The ID of the node.
+ graph_exec_id: The ID of the graph execution.
+ node_exec_id: The ID of the node execution.
+ user_id: The ID of the user.
+
+ Returns:
+ A Generator that yields (output_name, output_data).
+ output_name: One of the output name defined in Block's output_schema.
+ output_data: The data for the output_name, matching the defined schema.
+ """
+ # --- satisfy the type checker, never executed -------------
+ if False: # noqa: SIM115
+ yield "name", "value" # pyright: ignore[reportMissingYield]
+ raise NotImplementedError(f"{self.name} does not implement the run method.")
+
+ async def run_once(
+ self, input_data: BlockSchemaInputType, output: str, **kwargs
+ ) -> Any:
+ async for item in self.run(input_data, **kwargs):
+ name, data = item
+ if name == output:
+ return data
+ raise ValueError(f"{self.name} did not produce any output for {output}")
+
+ def merge_stats(self, stats: "NodeExecutionStats") -> "NodeExecutionStats":
+ self.execution_stats += stats
+ return self.execution_stats
+
+ @property
+ def name(self):
+ return self.__class__.__name__
+
+ def to_dict(self):
+ return {
+ "id": self.id,
+ "name": self.name,
+ "inputSchema": self.input_schema.jsonschema(),
+ "outputSchema": self.output_schema.jsonschema(),
+ "description": self.description,
+ "categories": [category.dict() for category in self.categories],
+ "contributors": [
+ contributor.model_dump() for contributor in self.contributors
+ ],
+ "staticOutput": self.static_output,
+ "uiType": self.block_type.value,
+ }
+
+ def get_info(self) -> BlockInfo:
+ from backend.data.credit import get_block_cost
+
+ return BlockInfo(
+ id=self.id,
+ name=self.name,
+ inputSchema=self.input_schema.jsonschema(),
+ outputSchema=self.output_schema.jsonschema(),
+ costs=get_block_cost(self),
+ description=self.description,
+ categories=[category.dict() for category in self.categories],
+ contributors=[
+ contributor.model_dump() for contributor in self.contributors
+ ],
+ staticOutput=self.static_output,
+ uiType=self.block_type.value,
+ )
+
+ async def execute(self, input_data: BlockInput, **kwargs) -> BlockOutput:
+ try:
+ async for output_name, output_data in self._execute(input_data, **kwargs):
+ yield output_name, output_data
+ except Exception as ex:
+ if isinstance(ex, BlockError):
+ raise ex
+ else:
+ raise (
+ BlockExecutionError
+ if isinstance(ex, ValueError)
+ else BlockUnknownError
+ )(
+ message=str(ex),
+ block_name=self.name,
+ block_id=self.id,
+ ) from ex
+
+ async def is_block_exec_need_review(
+ self,
+ input_data: BlockInput,
+ *,
+ user_id: str,
+ node_id: str,
+ node_exec_id: str,
+ graph_exec_id: str,
+ graph_id: str,
+ graph_version: int,
+ execution_context: "ExecutionContext",
+ **kwargs,
+ ) -> tuple[bool, BlockInput]:
+ """
+ Check if this block execution needs human review and handle the review process.
+
+ Returns:
+ Tuple of (should_pause, input_data_to_use)
+ - should_pause: True if execution should be paused for review
+ - input_data_to_use: The input data to use (may be modified by reviewer)
+ """
+ if not (
+ self.is_sensitive_action and execution_context.sensitive_action_safe_mode
+ ):
+ return False, input_data
+
+ from backend.blocks.helpers.review import HITLReviewHelper
+
+ # Handle the review request and get decision
+ decision = await HITLReviewHelper.handle_review_decision(
+ input_data=input_data,
+ user_id=user_id,
+ node_id=node_id,
+ node_exec_id=node_exec_id,
+ graph_exec_id=graph_exec_id,
+ graph_id=graph_id,
+ graph_version=graph_version,
+ block_name=self.name,
+ editable=True,
+ )
+
+ if decision is None:
+ # We're awaiting review - pause execution
+ return True, input_data
+
+ if not decision.should_proceed:
+ # Review was rejected, raise an error to stop execution
+ raise BlockExecutionError(
+ message=f"Block execution rejected by reviewer: {decision.message}",
+ block_name=self.name,
+ block_id=self.id,
+ )
+
+ # Review was approved - use the potentially modified data
+ # ReviewResult.data must be a dict for block inputs
+ reviewed_data = decision.review_result.data
+ if not isinstance(reviewed_data, dict):
+ raise BlockExecutionError(
+ message=f"Review data must be a dict for block input, got {type(reviewed_data).__name__}",
+ block_name=self.name,
+ block_id=self.id,
+ )
+ return False, reviewed_data
+
+ async def _execute(self, input_data: BlockInput, **kwargs) -> BlockOutput:
+ # Check for review requirement only if running within a graph execution context
+ # Direct block execution (e.g., from chat) skips the review process
+ has_graph_context = all(
+ key in kwargs
+ for key in (
+ "node_exec_id",
+ "graph_exec_id",
+ "graph_id",
+ "execution_context",
+ )
+ )
+ if has_graph_context:
+ should_pause, input_data = await self.is_block_exec_need_review(
+ input_data, **kwargs
+ )
+ if should_pause:
+ return
+
+ # Validate the input data (original or reviewer-modified) once
+ if error := self.input_schema.validate_data(input_data):
+ raise BlockInputError(
+ message=f"Unable to execute block with invalid input data: {error}",
+ block_name=self.name,
+ block_id=self.id,
+ )
+
+ # Use the validated input data
+ async for output_name, output_data in self.run(
+ self.input_schema(**{k: v for k, v in input_data.items() if v is not None}),
+ **kwargs,
+ ):
+ if output_name == "error":
+ raise BlockExecutionError(
+ message=output_data, block_name=self.name, block_id=self.id
+ )
+ if self.block_type == BlockType.STANDARD and (
+ error := self.output_schema.validate_field(output_name, output_data)
+ ):
+ raise BlockOutputError(
+ message=f"Block produced an invalid output data: {error}",
+ block_name=self.name,
+ block_id=self.id,
+ )
+ yield output_name, output_data
+
+ def is_triggered_by_event_type(
+ self, trigger_config: dict[str, Any], event_type: str
+ ) -> bool:
+ if not self.webhook_config:
+ raise TypeError("This method can't be used on non-trigger blocks")
+ if not self.webhook_config.event_filter_input:
+ return True
+ event_filter = trigger_config.get(self.webhook_config.event_filter_input)
+ if not event_filter:
+ raise ValueError("Event filter is not configured on trigger")
+ return event_type in [
+ self.webhook_config.event_format.format(event=k)
+ for k in event_filter
+ if event_filter[k] is True
+ ]
+
+
+# Type alias for any block with standard input/output schemas
+AnyBlockSchema: TypeAlias = Block[BlockSchemaInput, BlockSchemaOutput]
diff --git a/autogpt_platform/backend/backend/blocks/_utils.py b/autogpt_platform/backend/backend/blocks/_utils.py
new file mode 100644
index 0000000000..bec033bd2c
--- /dev/null
+++ b/autogpt_platform/backend/backend/blocks/_utils.py
@@ -0,0 +1,122 @@
+import logging
+import os
+
+from backend.integrations.providers import ProviderName
+
+from ._base import AnyBlockSchema
+
+logger = logging.getLogger(__name__)
+
+
+def is_block_auth_configured(
+ block_cls: type[AnyBlockSchema],
+) -> bool:
+ """
+ Check if a block has a valid authentication method configured at runtime.
+
+ For example if a block is an OAuth-only block and there env vars are not set,
+ do not show it in the UI.
+
+ """
+ from backend.sdk.registry import AutoRegistry
+
+ # Create an instance to access input_schema
+ try:
+ block = block_cls()
+ except Exception as e:
+ # If we can't create a block instance, assume it's not OAuth-only
+ logger.error(f"Error creating block instance for {block_cls.__name__}: {e}")
+ return True
+ logger.debug(
+ f"Checking if block {block_cls.__name__} has a valid provider configured"
+ )
+
+ # Get all credential inputs from input schema
+ credential_inputs = block.input_schema.get_credentials_fields_info()
+ required_inputs = block.input_schema.get_required_fields()
+ if not credential_inputs:
+ logger.debug(
+ f"Block {block_cls.__name__} has no credential inputs - Treating as valid"
+ )
+ return True
+
+ # Check credential inputs
+ if len(required_inputs.intersection(credential_inputs.keys())) == 0:
+ logger.debug(
+ f"Block {block_cls.__name__} has only optional credential inputs"
+ " - will work without credentials configured"
+ )
+
+ # Check if the credential inputs for this block are correctly configured
+ for field_name, field_info in credential_inputs.items():
+ provider_names = field_info.provider
+ if not provider_names:
+ logger.warning(
+ f"Block {block_cls.__name__} "
+ f"has credential input '{field_name}' with no provider options"
+ " - Disabling"
+ )
+ return False
+
+ # If a field has multiple possible providers, each one needs to be usable to
+ # prevent breaking the UX
+ for _provider_name in provider_names:
+ provider_name = _provider_name.value
+ if provider_name in ProviderName.__members__.values():
+ logger.debug(
+ f"Block {block_cls.__name__} credential input '{field_name}' "
+ f"provider '{provider_name}' is part of the legacy provider system"
+ " - Treating as valid"
+ )
+ break
+
+ provider = AutoRegistry.get_provider(provider_name)
+ if not provider:
+ logger.warning(
+ f"Block {block_cls.__name__} credential input '{field_name}' "
+ f"refers to unknown provider '{provider_name}' - Disabling"
+ )
+ return False
+
+ # Check the provider's supported auth types
+ if field_info.supported_types != provider.supported_auth_types:
+ logger.warning(
+ f"Block {block_cls.__name__} credential input '{field_name}' "
+ f"has mismatched supported auth types (field <> Provider): "
+ f"{field_info.supported_types} != {provider.supported_auth_types}"
+ )
+
+ if not (supported_auth_types := provider.supported_auth_types):
+ # No auth methods are been configured for this provider
+ logger.warning(
+ f"Block {block_cls.__name__} credential input '{field_name}' "
+ f"provider '{provider_name}' "
+ "has no authentication methods configured - Disabling"
+ )
+ return False
+
+ # Check if provider supports OAuth
+ if "oauth2" in supported_auth_types:
+ # Check if OAuth environment variables are set
+ if (oauth_config := provider.oauth_config) and bool(
+ os.getenv(oauth_config.client_id_env_var)
+ and os.getenv(oauth_config.client_secret_env_var)
+ ):
+ logger.debug(
+ f"Block {block_cls.__name__} credential input '{field_name}' "
+ f"provider '{provider_name}' is configured for OAuth"
+ )
+ else:
+ logger.error(
+ f"Block {block_cls.__name__} credential input '{field_name}' "
+ f"provider '{provider_name}' "
+ "is missing OAuth client ID or secret - Disabling"
+ )
+ return False
+
+ logger.debug(
+ f"Block {block_cls.__name__} credential input '{field_name}' is valid; "
+ f"supported credential types: {', '.join(field_info.supported_types)}"
+ )
+
+ return True
diff --git a/autogpt_platform/backend/backend/blocks/agent.py b/autogpt_platform/backend/backend/blocks/agent.py
index 0efc0a3369..574dbc2530 100644
--- a/autogpt_platform/backend/backend/blocks/agent.py
+++ b/autogpt_platform/backend/backend/blocks/agent.py
@@ -1,7 +1,7 @@
import logging
-from typing import Any, Optional
+from typing import TYPE_CHECKING, Any, Optional
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockInput,
@@ -9,13 +9,15 @@ from backend.data.block import (
BlockSchema,
BlockSchemaInput,
BlockType,
- get_block,
)
from backend.data.execution import ExecutionContext, ExecutionStatus, NodesInputMasks
from backend.data.model import NodeExecutionStats, SchemaField
from backend.util.json import validate_with_jsonschema
from backend.util.retry import func_retry
+if TYPE_CHECKING:
+ from backend.executor.utils import LogMetadata
+
_logger = logging.getLogger(__name__)
@@ -124,9 +126,10 @@ class AgentExecutorBlock(Block):
graph_version: int,
graph_exec_id: str,
user_id: str,
- logger,
+ logger: "LogMetadata",
) -> BlockOutput:
+ from backend.blocks import get_block
from backend.data.execution import ExecutionEventType
from backend.executor import utils as execution_utils
@@ -198,7 +201,7 @@ class AgentExecutorBlock(Block):
self,
graph_exec_id: str,
user_id: str,
- logger,
+ logger: "LogMetadata",
) -> None:
from backend.executor import utils as execution_utils
diff --git a/autogpt_platform/backend/backend/blocks/ai_condition.py b/autogpt_platform/backend/backend/blocks/ai_condition.py
index 2a5cdcdeec..c28c1e9f7d 100644
--- a/autogpt_platform/backend/backend/blocks/ai_condition.py
+++ b/autogpt_platform/backend/backend/blocks/ai_condition.py
@@ -1,5 +1,11 @@
from typing import Any
+from backend.blocks._base import (
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.llm import (
DEFAULT_LLM_MODEL,
TEST_CREDENTIALS,
@@ -11,12 +17,6 @@ from backend.blocks.llm import (
LLMResponse,
llm_call,
)
-from backend.data.block import (
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import APIKeyCredentials, NodeExecutionStats, SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/ai_image_customizer.py b/autogpt_platform/backend/backend/blocks/ai_image_customizer.py
index 91be33a60e..402e520ea0 100644
--- a/autogpt_platform/backend/backend/blocks/ai_image_customizer.py
+++ b/autogpt_platform/backend/backend/blocks/ai_image_customizer.py
@@ -6,7 +6,7 @@ from pydantic import SecretStr
from replicate.client import Client as ReplicateClient
from replicate.helpers import FileOutput
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/ai_image_generator_block.py b/autogpt_platform/backend/backend/blocks/ai_image_generator_block.py
index e40731cd97..fcea24fb01 100644
--- a/autogpt_platform/backend/backend/blocks/ai_image_generator_block.py
+++ b/autogpt_platform/backend/backend/blocks/ai_image_generator_block.py
@@ -5,7 +5,12 @@ from pydantic import SecretStr
from replicate.client import Client as ReplicateClient
from replicate.helpers import FileOutput
-from backend.data.block import Block, BlockCategory, BlockSchemaInput, BlockSchemaOutput
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.data.execution import ExecutionContext
from backend.data.model import (
APIKeyCredentials,
diff --git a/autogpt_platform/backend/backend/blocks/ai_music_generator.py b/autogpt_platform/backend/backend/blocks/ai_music_generator.py
index 1ecb78f95e..9a0639a9c0 100644
--- a/autogpt_platform/backend/backend/blocks/ai_music_generator.py
+++ b/autogpt_platform/backend/backend/blocks/ai_music_generator.py
@@ -6,7 +6,7 @@ from typing import Literal
from pydantic import SecretStr
from replicate.client import Client as ReplicateClient
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/ai_shortform_video_block.py b/autogpt_platform/backend/backend/blocks/ai_shortform_video_block.py
index eb60843185..2c53748fde 100644
--- a/autogpt_platform/backend/backend/blocks/ai_shortform_video_block.py
+++ b/autogpt_platform/backend/backend/blocks/ai_shortform_video_block.py
@@ -6,7 +6,7 @@ from typing import Literal
from pydantic import SecretStr
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/apollo/organization.py b/autogpt_platform/backend/backend/blocks/apollo/organization.py
index 93acbff0b8..6722de4a79 100644
--- a/autogpt_platform/backend/backend/blocks/apollo/organization.py
+++ b/autogpt_platform/backend/backend/blocks/apollo/organization.py
@@ -1,3 +1,10 @@
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.apollo._api import ApolloClient
from backend.blocks.apollo._auth import (
TEST_CREDENTIALS,
@@ -10,13 +17,6 @@ from backend.blocks.apollo.models import (
PrimaryPhone,
SearchOrganizationsRequest,
)
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import CredentialsField, SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/apollo/people.py b/autogpt_platform/backend/backend/blocks/apollo/people.py
index a58321ecfc..b5059a2a26 100644
--- a/autogpt_platform/backend/backend/blocks/apollo/people.py
+++ b/autogpt_platform/backend/backend/blocks/apollo/people.py
@@ -1,5 +1,12 @@
import asyncio
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.apollo._api import ApolloClient
from backend.blocks.apollo._auth import (
TEST_CREDENTIALS,
@@ -14,13 +21,6 @@ from backend.blocks.apollo.models import (
SearchPeopleRequest,
SenorityLevels,
)
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import CredentialsField, SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/apollo/person.py b/autogpt_platform/backend/backend/blocks/apollo/person.py
index 84b86d2bfd..4d586175e0 100644
--- a/autogpt_platform/backend/backend/blocks/apollo/person.py
+++ b/autogpt_platform/backend/backend/blocks/apollo/person.py
@@ -1,3 +1,10 @@
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.apollo._api import ApolloClient
from backend.blocks.apollo._auth import (
TEST_CREDENTIALS,
@@ -6,13 +13,6 @@ from backend.blocks.apollo._auth import (
ApolloCredentialsInput,
)
from backend.blocks.apollo.models import Contact, EnrichPersonRequest
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import CredentialsField, SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/ayrshare/_util.py b/autogpt_platform/backend/backend/blocks/ayrshare/_util.py
index 8d0b9914f9..231239310f 100644
--- a/autogpt_platform/backend/backend/blocks/ayrshare/_util.py
+++ b/autogpt_platform/backend/backend/blocks/ayrshare/_util.py
@@ -3,7 +3,7 @@ from typing import Optional
from pydantic import BaseModel, Field
-from backend.data.block import BlockSchemaInput
+from backend.blocks._base import BlockSchemaInput
from backend.data.model import SchemaField, UserIntegrations
from backend.integrations.ayrshare import AyrshareClient
from backend.util.clients import get_database_manager_async_client
diff --git a/autogpt_platform/backend/backend/blocks/basic.py b/autogpt_platform/backend/backend/blocks/basic.py
index 95193b3feb..f129d2707b 100644
--- a/autogpt_platform/backend/backend/blocks/basic.py
+++ b/autogpt_platform/backend/backend/blocks/basic.py
@@ -1,7 +1,7 @@
import enum
from typing import Any
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/block.py b/autogpt_platform/backend/backend/blocks/block.py
index 95c92a41ab..d3f482fc65 100644
--- a/autogpt_platform/backend/backend/blocks/block.py
+++ b/autogpt_platform/backend/backend/blocks/block.py
@@ -2,7 +2,7 @@ import os
import re
from typing import Type
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/branching.py b/autogpt_platform/backend/backend/blocks/branching.py
index e9177a8b65..fa4d8089ff 100644
--- a/autogpt_platform/backend/backend/blocks/branching.py
+++ b/autogpt_platform/backend/backend/blocks/branching.py
@@ -1,7 +1,7 @@
from enum import Enum
from typing import Any
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/claude_code.py b/autogpt_platform/backend/backend/blocks/claude_code.py
index 4ef44603b2..1919406c6f 100644
--- a/autogpt_platform/backend/backend/blocks/claude_code.py
+++ b/autogpt_platform/backend/backend/blocks/claude_code.py
@@ -6,7 +6,7 @@ from typing import Literal, Optional
from e2b import AsyncSandbox as BaseAsyncSandbox
from pydantic import BaseModel, SecretStr
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/code_executor.py b/autogpt_platform/backend/backend/blocks/code_executor.py
index be6f2bba55..766f44b7bb 100644
--- a/autogpt_platform/backend/backend/blocks/code_executor.py
+++ b/autogpt_platform/backend/backend/blocks/code_executor.py
@@ -6,7 +6,7 @@ from e2b_code_interpreter import Result as E2BExecutionResult
from e2b_code_interpreter.charts import Chart as E2BExecutionResultChart
from pydantic import BaseModel, Field, JsonValue, SecretStr
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/code_extraction_block.py b/autogpt_platform/backend/backend/blocks/code_extraction_block.py
index 98f40c7a8b..bde4bc9fc6 100644
--- a/autogpt_platform/backend/backend/blocks/code_extraction_block.py
+++ b/autogpt_platform/backend/backend/blocks/code_extraction_block.py
@@ -1,6 +1,6 @@
import re
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/codex.py b/autogpt_platform/backend/backend/blocks/codex.py
index 1b907cafce..07dffec39f 100644
--- a/autogpt_platform/backend/backend/blocks/codex.py
+++ b/autogpt_platform/backend/backend/blocks/codex.py
@@ -6,7 +6,7 @@ from openai import AsyncOpenAI
from openai.types.responses import Response as OpenAIResponse
from pydantic import SecretStr
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/compass/triggers.py b/autogpt_platform/backend/backend/blocks/compass/triggers.py
index f6ac8dfd81..2afd03852e 100644
--- a/autogpt_platform/backend/backend/blocks/compass/triggers.py
+++ b/autogpt_platform/backend/backend/blocks/compass/triggers.py
@@ -1,6 +1,6 @@
from pydantic import BaseModel
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockManualWebhookConfig,
diff --git a/autogpt_platform/backend/backend/blocks/count_words_and_char_block.py b/autogpt_platform/backend/backend/blocks/count_words_and_char_block.py
index 20a5077a2d..041f1bfaa1 100644
--- a/autogpt_platform/backend/backend/blocks/count_words_and_char_block.py
+++ b/autogpt_platform/backend/backend/blocks/count_words_and_char_block.py
@@ -1,4 +1,4 @@
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/data_manipulation.py b/autogpt_platform/backend/backend/blocks/data_manipulation.py
index 1014236b8c..a8f25ecb18 100644
--- a/autogpt_platform/backend/backend/blocks/data_manipulation.py
+++ b/autogpt_platform/backend/backend/blocks/data_manipulation.py
@@ -1,6 +1,6 @@
from typing import Any, List
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/decoder_block.py b/autogpt_platform/backend/backend/blocks/decoder_block.py
index 7a7406bd1a..b9eb56e48f 100644
--- a/autogpt_platform/backend/backend/blocks/decoder_block.py
+++ b/autogpt_platform/backend/backend/blocks/decoder_block.py
@@ -1,6 +1,6 @@
import codecs
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/discord/bot_blocks.py b/autogpt_platform/backend/backend/blocks/discord/bot_blocks.py
index 4438af1955..4ec3d0eec2 100644
--- a/autogpt_platform/backend/backend/blocks/discord/bot_blocks.py
+++ b/autogpt_platform/backend/backend/blocks/discord/bot_blocks.py
@@ -8,7 +8,7 @@ from typing import Any, Literal, cast
import discord
from pydantic import SecretStr
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/discord/oauth_blocks.py b/autogpt_platform/backend/backend/blocks/discord/oauth_blocks.py
index ca20eb6337..74e9229776 100644
--- a/autogpt_platform/backend/backend/blocks/discord/oauth_blocks.py
+++ b/autogpt_platform/backend/backend/blocks/discord/oauth_blocks.py
@@ -2,7 +2,7 @@
Discord OAuth-based blocks.
"""
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/email_block.py b/autogpt_platform/backend/backend/blocks/email_block.py
index fad2f411cb..626bb6cdac 100644
--- a/autogpt_platform/backend/backend/blocks/email_block.py
+++ b/autogpt_platform/backend/backend/blocks/email_block.py
@@ -7,7 +7,7 @@ from typing import Literal
from pydantic import BaseModel, ConfigDict, SecretStr
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/encoder_block.py b/autogpt_platform/backend/backend/blocks/encoder_block.py
index b60a4ae828..bfab8f4555 100644
--- a/autogpt_platform/backend/backend/blocks/encoder_block.py
+++ b/autogpt_platform/backend/backend/blocks/encoder_block.py
@@ -2,7 +2,7 @@
import codecs
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/enrichlayer/linkedin.py b/autogpt_platform/backend/backend/blocks/enrichlayer/linkedin.py
index 974ad28eed..de06230c00 100644
--- a/autogpt_platform/backend/backend/blocks/enrichlayer/linkedin.py
+++ b/autogpt_platform/backend/backend/blocks/enrichlayer/linkedin.py
@@ -8,7 +8,7 @@ which provides access to LinkedIn profile data and related information.
import logging
from typing import Optional
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/fal/ai_video_generator.py b/autogpt_platform/backend/backend/blocks/fal/ai_video_generator.py
index c2079ef159..945e53578c 100644
--- a/autogpt_platform/backend/backend/blocks/fal/ai_video_generator.py
+++ b/autogpt_platform/backend/backend/blocks/fal/ai_video_generator.py
@@ -3,6 +3,13 @@ import logging
from enum import Enum
from typing import Any
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.fal._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -10,13 +17,6 @@ from backend.blocks.fal._auth import (
FalCredentialsField,
FalCredentialsInput,
)
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.execution import ExecutionContext
from backend.data.model import SchemaField
from backend.util.file import store_media_file
diff --git a/autogpt_platform/backend/backend/blocks/flux_kontext.py b/autogpt_platform/backend/backend/blocks/flux_kontext.py
index d56baa6d92..f2b35aee40 100644
--- a/autogpt_platform/backend/backend/blocks/flux_kontext.py
+++ b/autogpt_platform/backend/backend/blocks/flux_kontext.py
@@ -5,7 +5,7 @@ from pydantic import SecretStr
from replicate.client import Client as ReplicateClient
from replicate.helpers import FileOutput
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/github/checks.py b/autogpt_platform/backend/backend/blocks/github/checks.py
index 02bc8d2400..99feefec88 100644
--- a/autogpt_platform/backend/backend/blocks/github/checks.py
+++ b/autogpt_platform/backend/backend/blocks/github/checks.py
@@ -3,7 +3,7 @@ from typing import Optional
from pydantic import BaseModel
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/github/ci.py b/autogpt_platform/backend/backend/blocks/github/ci.py
index 8ba58e389e..c717be96e7 100644
--- a/autogpt_platform/backend/backend/blocks/github/ci.py
+++ b/autogpt_platform/backend/backend/blocks/github/ci.py
@@ -5,7 +5,7 @@ from typing import Optional
from typing_extensions import TypedDict
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/github/issues.py b/autogpt_platform/backend/backend/blocks/github/issues.py
index 22b4149663..7269c44f73 100644
--- a/autogpt_platform/backend/backend/blocks/github/issues.py
+++ b/autogpt_platform/backend/backend/blocks/github/issues.py
@@ -3,7 +3,7 @@ from urllib.parse import urlparse
from typing_extensions import TypedDict
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/github/pull_requests.py b/autogpt_platform/backend/backend/blocks/github/pull_requests.py
index 9049037716..b336c7bfa3 100644
--- a/autogpt_platform/backend/backend/blocks/github/pull_requests.py
+++ b/autogpt_platform/backend/backend/blocks/github/pull_requests.py
@@ -2,7 +2,7 @@ import re
from typing_extensions import TypedDict
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/github/repo.py b/autogpt_platform/backend/backend/blocks/github/repo.py
index 78ce26bfad..9b1e60b00c 100644
--- a/autogpt_platform/backend/backend/blocks/github/repo.py
+++ b/autogpt_platform/backend/backend/blocks/github/repo.py
@@ -2,7 +2,7 @@ import base64
from typing_extensions import TypedDict
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/github/reviews.py b/autogpt_platform/backend/backend/blocks/github/reviews.py
index 11718d1402..932362c09a 100644
--- a/autogpt_platform/backend/backend/blocks/github/reviews.py
+++ b/autogpt_platform/backend/backend/blocks/github/reviews.py
@@ -4,7 +4,7 @@ from typing import Any, List, Optional
from typing_extensions import TypedDict
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/github/statuses.py b/autogpt_platform/backend/backend/blocks/github/statuses.py
index 42826a8a51..caa1282a9b 100644
--- a/autogpt_platform/backend/backend/blocks/github/statuses.py
+++ b/autogpt_platform/backend/backend/blocks/github/statuses.py
@@ -3,7 +3,7 @@ from typing import Optional
from pydantic import BaseModel
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/github/triggers.py b/autogpt_platform/backend/backend/blocks/github/triggers.py
index 2fc568a468..e35dbb4123 100644
--- a/autogpt_platform/backend/backend/blocks/github/triggers.py
+++ b/autogpt_platform/backend/backend/blocks/github/triggers.py
@@ -4,7 +4,7 @@ from pathlib import Path
from pydantic import BaseModel
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/google/calendar.py b/autogpt_platform/backend/backend/blocks/google/calendar.py
index 55c41f047c..b9fda2cf31 100644
--- a/autogpt_platform/backend/backend/blocks/google/calendar.py
+++ b/autogpt_platform/backend/backend/blocks/google/calendar.py
@@ -8,7 +8,7 @@ from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from pydantic import BaseModel
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/google/docs.py b/autogpt_platform/backend/backend/blocks/google/docs.py
index 7840cbae73..33aab4638d 100644
--- a/autogpt_platform/backend/backend/blocks/google/docs.py
+++ b/autogpt_platform/backend/backend/blocks/google/docs.py
@@ -7,14 +7,14 @@ from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from gravitas_md2gdocs import to_requests
-from backend.blocks.google._drive import GoogleDriveFile, GoogleDriveFileField
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
BlockSchemaInput,
BlockSchemaOutput,
)
+from backend.blocks.google._drive import GoogleDriveFile, GoogleDriveFileField
from backend.data.model import SchemaField
from backend.util.settings import Settings
diff --git a/autogpt_platform/backend/backend/blocks/google/gmail.py b/autogpt_platform/backend/backend/blocks/google/gmail.py
index 2040cabe3f..2051f86b9e 100644
--- a/autogpt_platform/backend/backend/blocks/google/gmail.py
+++ b/autogpt_platform/backend/backend/blocks/google/gmail.py
@@ -14,7 +14,7 @@ from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from pydantic import BaseModel, Field
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/google/sheets.py b/autogpt_platform/backend/backend/blocks/google/sheets.py
index da541d3bf5..6e21008a23 100644
--- a/autogpt_platform/backend/backend/blocks/google/sheets.py
+++ b/autogpt_platform/backend/backend/blocks/google/sheets.py
@@ -7,14 +7,14 @@ from enum import Enum
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
-from backend.blocks.google._drive import GoogleDriveFile, GoogleDriveFileField
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
BlockSchemaInput,
BlockSchemaOutput,
)
+from backend.blocks.google._drive import GoogleDriveFile, GoogleDriveFileField
from backend.data.model import SchemaField
from backend.util.settings import Settings
diff --git a/autogpt_platform/backend/backend/blocks/google_maps.py b/autogpt_platform/backend/backend/blocks/google_maps.py
index 2ee2959326..bab0841c5d 100644
--- a/autogpt_platform/backend/backend/blocks/google_maps.py
+++ b/autogpt_platform/backend/backend/blocks/google_maps.py
@@ -3,7 +3,7 @@ from typing import Literal
import googlemaps
from pydantic import BaseModel, SecretStr
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/http.py b/autogpt_platform/backend/backend/blocks/http.py
index 77e7fe243f..21c2964412 100644
--- a/autogpt_platform/backend/backend/blocks/http.py
+++ b/autogpt_platform/backend/backend/blocks/http.py
@@ -8,7 +8,7 @@ from typing import Literal
import aiofiles
from pydantic import SecretStr
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/hubspot/company.py b/autogpt_platform/backend/backend/blocks/hubspot/company.py
index dee9169e59..543d16db0c 100644
--- a/autogpt_platform/backend/backend/blocks/hubspot/company.py
+++ b/autogpt_platform/backend/backend/blocks/hubspot/company.py
@@ -1,15 +1,15 @@
-from backend.blocks.hubspot._auth import (
- HubSpotCredentials,
- HubSpotCredentialsField,
- HubSpotCredentialsInput,
-)
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
BlockSchemaInput,
BlockSchemaOutput,
)
+from backend.blocks.hubspot._auth import (
+ HubSpotCredentials,
+ HubSpotCredentialsField,
+ HubSpotCredentialsInput,
+)
from backend.data.model import SchemaField
from backend.util.request import Requests
diff --git a/autogpt_platform/backend/backend/blocks/hubspot/contact.py b/autogpt_platform/backend/backend/blocks/hubspot/contact.py
index b4451c3b8b..1cdbf99b39 100644
--- a/autogpt_platform/backend/backend/blocks/hubspot/contact.py
+++ b/autogpt_platform/backend/backend/blocks/hubspot/contact.py
@@ -1,15 +1,15 @@
-from backend.blocks.hubspot._auth import (
- HubSpotCredentials,
- HubSpotCredentialsField,
- HubSpotCredentialsInput,
-)
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
BlockSchemaInput,
BlockSchemaOutput,
)
+from backend.blocks.hubspot._auth import (
+ HubSpotCredentials,
+ HubSpotCredentialsField,
+ HubSpotCredentialsInput,
+)
from backend.data.model import SchemaField
from backend.util.request import Requests
diff --git a/autogpt_platform/backend/backend/blocks/hubspot/engagement.py b/autogpt_platform/backend/backend/blocks/hubspot/engagement.py
index 683607c5b3..9408a543b6 100644
--- a/autogpt_platform/backend/backend/blocks/hubspot/engagement.py
+++ b/autogpt_platform/backend/backend/blocks/hubspot/engagement.py
@@ -1,17 +1,17 @@
from datetime import datetime, timedelta
-from backend.blocks.hubspot._auth import (
- HubSpotCredentials,
- HubSpotCredentialsField,
- HubSpotCredentialsInput,
-)
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
BlockSchemaInput,
BlockSchemaOutput,
)
+from backend.blocks.hubspot._auth import (
+ HubSpotCredentials,
+ HubSpotCredentialsField,
+ HubSpotCredentialsInput,
+)
from backend.data.model import SchemaField
from backend.util.request import Requests
diff --git a/autogpt_platform/backend/backend/blocks/human_in_the_loop.py b/autogpt_platform/backend/backend/blocks/human_in_the_loop.py
index 568ac4b33f..a8e5b97004 100644
--- a/autogpt_platform/backend/backend/blocks/human_in_the_loop.py
+++ b/autogpt_platform/backend/backend/blocks/human_in_the_loop.py
@@ -3,8 +3,7 @@ from typing import Any
from prisma.enums import ReviewStatus
-from backend.blocks.helpers.review import HITLReviewHelper
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
@@ -12,6 +11,7 @@ from backend.data.block import (
BlockSchemaOutput,
BlockType,
)
+from backend.blocks.helpers.review import HITLReviewHelper
from backend.data.execution import ExecutionContext
from backend.data.human_review import ReviewResult
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/ideogram.py b/autogpt_platform/backend/backend/blocks/ideogram.py
index 09a384c74a..5aed4aa5a9 100644
--- a/autogpt_platform/backend/backend/blocks/ideogram.py
+++ b/autogpt_platform/backend/backend/blocks/ideogram.py
@@ -3,7 +3,7 @@ from typing import Any, Dict, Literal, Optional
from pydantic import SecretStr
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/io.py b/autogpt_platform/backend/backend/blocks/io.py
index a9c3859490..94542790ef 100644
--- a/autogpt_platform/backend/backend/blocks/io.py
+++ b/autogpt_platform/backend/backend/blocks/io.py
@@ -2,9 +2,7 @@ import copy
from datetime import date, time
from typing import Any, Optional
-# Import for Google Drive file input block
-from backend.blocks.google._drive import AttachmentView, GoogleDriveFile
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
@@ -12,6 +10,9 @@ from backend.data.block import (
BlockSchemaInput,
BlockType,
)
+
+# Import for Google Drive file input block
+from backend.blocks.google._drive import AttachmentView, GoogleDriveFile
from backend.data.execution import ExecutionContext
from backend.data.model import SchemaField
from backend.util.file import store_media_file
diff --git a/autogpt_platform/backend/backend/blocks/iteration.py b/autogpt_platform/backend/backend/blocks/iteration.py
index 441f73fc4a..a35bcac9c1 100644
--- a/autogpt_platform/backend/backend/blocks/iteration.py
+++ b/autogpt_platform/backend/backend/blocks/iteration.py
@@ -1,6 +1,6 @@
from typing import Any
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/jina/chunking.py b/autogpt_platform/backend/backend/blocks/jina/chunking.py
index 9a9b242aae..c248e3dd24 100644
--- a/autogpt_platform/backend/backend/blocks/jina/chunking.py
+++ b/autogpt_platform/backend/backend/blocks/jina/chunking.py
@@ -1,15 +1,15 @@
-from backend.blocks.jina._auth import (
- JinaCredentials,
- JinaCredentialsField,
- JinaCredentialsInput,
-)
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
BlockSchemaInput,
BlockSchemaOutput,
)
+from backend.blocks.jina._auth import (
+ JinaCredentials,
+ JinaCredentialsField,
+ JinaCredentialsInput,
+)
from backend.data.model import SchemaField
from backend.util.request import Requests
diff --git a/autogpt_platform/backend/backend/blocks/jina/embeddings.py b/autogpt_platform/backend/backend/blocks/jina/embeddings.py
index 0f6cf68c6c..f787de03b3 100644
--- a/autogpt_platform/backend/backend/blocks/jina/embeddings.py
+++ b/autogpt_platform/backend/backend/blocks/jina/embeddings.py
@@ -1,15 +1,15 @@
-from backend.blocks.jina._auth import (
- JinaCredentials,
- JinaCredentialsField,
- JinaCredentialsInput,
-)
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
BlockSchemaInput,
BlockSchemaOutput,
)
+from backend.blocks.jina._auth import (
+ JinaCredentials,
+ JinaCredentialsField,
+ JinaCredentialsInput,
+)
from backend.data.model import SchemaField
from backend.util.request import Requests
diff --git a/autogpt_platform/backend/backend/blocks/jina/fact_checker.py b/autogpt_platform/backend/backend/blocks/jina/fact_checker.py
index 3367ab99e6..df73ef94b1 100644
--- a/autogpt_platform/backend/backend/blocks/jina/fact_checker.py
+++ b/autogpt_platform/backend/backend/blocks/jina/fact_checker.py
@@ -3,18 +3,18 @@ from urllib.parse import quote
from typing_extensions import TypedDict
-from backend.blocks.jina._auth import (
- JinaCredentials,
- JinaCredentialsField,
- JinaCredentialsInput,
-)
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
BlockSchemaInput,
BlockSchemaOutput,
)
+from backend.blocks.jina._auth import (
+ JinaCredentials,
+ JinaCredentialsField,
+ JinaCredentialsInput,
+)
from backend.data.model import SchemaField
from backend.util.request import Requests
diff --git a/autogpt_platform/backend/backend/blocks/jina/search.py b/autogpt_platform/backend/backend/blocks/jina/search.py
index 05cddcc1df..22a883fa03 100644
--- a/autogpt_platform/backend/backend/blocks/jina/search.py
+++ b/autogpt_platform/backend/backend/blocks/jina/search.py
@@ -1,5 +1,12 @@
from urllib.parse import quote
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.jina._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -8,13 +15,6 @@ from backend.blocks.jina._auth import (
JinaCredentialsInput,
)
from backend.blocks.search import GetRequest
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import SchemaField
from backend.util.exceptions import BlockExecutionError
diff --git a/autogpt_platform/backend/backend/blocks/llm.py b/autogpt_platform/backend/backend/blocks/llm.py
index 7a020593d7..1272a9ec1b 100644
--- a/autogpt_platform/backend/backend/blocks/llm.py
+++ b/autogpt_platform/backend/backend/blocks/llm.py
@@ -15,7 +15,7 @@ from anthropic.types import ToolParam
from groq import AsyncGroq
from pydantic import BaseModel, SecretStr
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/maths.py b/autogpt_platform/backend/backend/blocks/maths.py
index ad6dc67bbe..0f94075277 100644
--- a/autogpt_platform/backend/backend/blocks/maths.py
+++ b/autogpt_platform/backend/backend/blocks/maths.py
@@ -2,7 +2,7 @@ import operator
from enum import Enum
from typing import Any
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/medium.py b/autogpt_platform/backend/backend/blocks/medium.py
index d54062d3ab..f511f19329 100644
--- a/autogpt_platform/backend/backend/blocks/medium.py
+++ b/autogpt_platform/backend/backend/blocks/medium.py
@@ -3,7 +3,7 @@ from typing import List, Literal
from pydantic import SecretStr
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/mem0.py b/autogpt_platform/backend/backend/blocks/mem0.py
index b8dc11064a..ba0bd24290 100644
--- a/autogpt_platform/backend/backend/blocks/mem0.py
+++ b/autogpt_platform/backend/backend/blocks/mem0.py
@@ -3,7 +3,7 @@ from typing import Any, Literal, Optional, Union
from mem0 import MemoryClient
from pydantic import BaseModel, SecretStr
-from backend.data.block import Block, BlockOutput, BlockSchemaInput, BlockSchemaOutput
+from backend.blocks._base import Block, BlockOutput, BlockSchemaInput, BlockSchemaOutput
from backend.data.model import (
APIKeyCredentials,
CredentialsField,
diff --git a/autogpt_platform/backend/backend/blocks/notion/create_page.py b/autogpt_platform/backend/backend/blocks/notion/create_page.py
index 5edef144e3..315730d37c 100644
--- a/autogpt_platform/backend/backend/blocks/notion/create_page.py
+++ b/autogpt_platform/backend/backend/blocks/notion/create_page.py
@@ -4,7 +4,7 @@ from typing import Any, Dict, List, Optional
from pydantic import model_validator
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/notion/read_database.py b/autogpt_platform/backend/backend/blocks/notion/read_database.py
index 5720bea2f8..7b1dcf7be4 100644
--- a/autogpt_platform/backend/backend/blocks/notion/read_database.py
+++ b/autogpt_platform/backend/backend/blocks/notion/read_database.py
@@ -2,7 +2,7 @@ from __future__ import annotations
from typing import Any, Dict, List, Optional
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/notion/read_page.py b/autogpt_platform/backend/backend/blocks/notion/read_page.py
index 400fd2a929..a2b5273ad9 100644
--- a/autogpt_platform/backend/backend/blocks/notion/read_page.py
+++ b/autogpt_platform/backend/backend/blocks/notion/read_page.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/notion/read_page_markdown.py b/autogpt_platform/backend/backend/blocks/notion/read_page_markdown.py
index 7ed87eaef9..cad3e85e79 100644
--- a/autogpt_platform/backend/backend/blocks/notion/read_page_markdown.py
+++ b/autogpt_platform/backend/backend/blocks/notion/read_page_markdown.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/notion/search.py b/autogpt_platform/backend/backend/blocks/notion/search.py
index 1983763537..71af844b64 100644
--- a/autogpt_platform/backend/backend/blocks/notion/search.py
+++ b/autogpt_platform/backend/backend/blocks/notion/search.py
@@ -4,7 +4,7 @@ from typing import List, Optional
from pydantic import BaseModel
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/nvidia/deepfake.py b/autogpt_platform/backend/backend/blocks/nvidia/deepfake.py
index f60b649839..06b05ebc50 100644
--- a/autogpt_platform/backend/backend/blocks/nvidia/deepfake.py
+++ b/autogpt_platform/backend/backend/blocks/nvidia/deepfake.py
@@ -1,15 +1,15 @@
-from backend.blocks.nvidia._auth import (
- NvidiaCredentials,
- NvidiaCredentialsField,
- NvidiaCredentialsInput,
-)
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
BlockSchemaInput,
BlockSchemaOutput,
)
+from backend.blocks.nvidia._auth import (
+ NvidiaCredentials,
+ NvidiaCredentialsField,
+ NvidiaCredentialsInput,
+)
from backend.data.model import SchemaField
from backend.util.request import Requests
from backend.util.type import MediaFileType
diff --git a/autogpt_platform/backend/backend/blocks/perplexity.py b/autogpt_platform/backend/backend/blocks/perplexity.py
index e2796718a9..270081a3a8 100644
--- a/autogpt_platform/backend/backend/blocks/perplexity.py
+++ b/autogpt_platform/backend/backend/blocks/perplexity.py
@@ -6,7 +6,7 @@ from typing import Any, Literal
import openai
from pydantic import SecretStr
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/persistence.py b/autogpt_platform/backend/backend/blocks/persistence.py
index a327fd22c7..7584993beb 100644
--- a/autogpt_platform/backend/backend/blocks/persistence.py
+++ b/autogpt_platform/backend/backend/blocks/persistence.py
@@ -1,7 +1,7 @@
import logging
from typing import Any, Literal
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/pinecone.py b/autogpt_platform/backend/backend/blocks/pinecone.py
index 878f6f72fb..f882212ab2 100644
--- a/autogpt_platform/backend/backend/blocks/pinecone.py
+++ b/autogpt_platform/backend/backend/blocks/pinecone.py
@@ -3,7 +3,7 @@ from typing import Any, Literal
from pinecone import Pinecone, ServerlessSpec
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/reddit.py b/autogpt_platform/backend/backend/blocks/reddit.py
index 1109d568db..6544c698a3 100644
--- a/autogpt_platform/backend/backend/blocks/reddit.py
+++ b/autogpt_platform/backend/backend/blocks/reddit.py
@@ -6,7 +6,7 @@ import praw
from praw.models import Comment, MoreComments, Submission
from pydantic import BaseModel, SecretStr
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/replicate/flux_advanced.py b/autogpt_platform/backend/backend/blocks/replicate/flux_advanced.py
index c112ce75c4..e7a0a82cce 100644
--- a/autogpt_platform/backend/backend/blocks/replicate/flux_advanced.py
+++ b/autogpt_platform/backend/backend/blocks/replicate/flux_advanced.py
@@ -4,19 +4,19 @@ from enum import Enum
from pydantic import SecretStr
from replicate.client import Client as ReplicateClient
-from backend.blocks.replicate._auth import (
- TEST_CREDENTIALS,
- TEST_CREDENTIALS_INPUT,
- ReplicateCredentialsInput,
-)
-from backend.blocks.replicate._helper import ReplicateOutputs, extract_result
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
BlockSchemaInput,
BlockSchemaOutput,
)
+from backend.blocks.replicate._auth import (
+ TEST_CREDENTIALS,
+ TEST_CREDENTIALS_INPUT,
+ ReplicateCredentialsInput,
+)
+from backend.blocks.replicate._helper import ReplicateOutputs, extract_result
from backend.data.model import APIKeyCredentials, CredentialsField, SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/replicate/replicate_block.py b/autogpt_platform/backend/backend/blocks/replicate/replicate_block.py
index 7ee054d02e..2758c7cd06 100644
--- a/autogpt_platform/backend/backend/blocks/replicate/replicate_block.py
+++ b/autogpt_platform/backend/backend/blocks/replicate/replicate_block.py
@@ -4,19 +4,19 @@ from typing import Optional
from pydantic import SecretStr
from replicate.client import Client as ReplicateClient
-from backend.blocks.replicate._auth import (
- TEST_CREDENTIALS,
- TEST_CREDENTIALS_INPUT,
- ReplicateCredentialsInput,
-)
-from backend.blocks.replicate._helper import ReplicateOutputs, extract_result
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
BlockSchemaInput,
BlockSchemaOutput,
)
+from backend.blocks.replicate._auth import (
+ TEST_CREDENTIALS,
+ TEST_CREDENTIALS_INPUT,
+ ReplicateCredentialsInput,
+)
+from backend.blocks.replicate._helper import ReplicateOutputs, extract_result
from backend.data.model import APIKeyCredentials, CredentialsField, SchemaField
from backend.util.exceptions import BlockExecutionError, BlockInputError
diff --git a/autogpt_platform/backend/backend/blocks/rss.py b/autogpt_platform/backend/backend/blocks/rss.py
index a23b3ee25c..5d26bc592c 100644
--- a/autogpt_platform/backend/backend/blocks/rss.py
+++ b/autogpt_platform/backend/backend/blocks/rss.py
@@ -6,7 +6,7 @@ from typing import Any
import feedparser
import pydantic
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/sampling.py b/autogpt_platform/backend/backend/blocks/sampling.py
index b4463947a7..eb5f47e80e 100644
--- a/autogpt_platform/backend/backend/blocks/sampling.py
+++ b/autogpt_platform/backend/backend/blocks/sampling.py
@@ -3,7 +3,7 @@ from collections import defaultdict
from enum import Enum
from typing import Any, Dict, List, Optional, Union
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/screenshotone.py b/autogpt_platform/backend/backend/blocks/screenshotone.py
index ee998f8da2..1ce133af83 100644
--- a/autogpt_platform/backend/backend/blocks/screenshotone.py
+++ b/autogpt_platform/backend/backend/blocks/screenshotone.py
@@ -4,7 +4,7 @@ from typing import Literal
from pydantic import SecretStr
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/search.py b/autogpt_platform/backend/backend/blocks/search.py
index 09e16034a3..61acb2108e 100644
--- a/autogpt_platform/backend/backend/blocks/search.py
+++ b/autogpt_platform/backend/backend/blocks/search.py
@@ -3,14 +3,14 @@ from urllib.parse import quote
from pydantic import SecretStr
-from backend.blocks.helpers.http import GetRequest
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
BlockSchemaInput,
BlockSchemaOutput,
)
+from backend.blocks.helpers.http import GetRequest
from backend.data.model import (
APIKeyCredentials,
CredentialsField,
diff --git a/autogpt_platform/backend/backend/blocks/slant3d/base.py b/autogpt_platform/backend/backend/blocks/slant3d/base.py
index e368a1b451..3ce24f8ddc 100644
--- a/autogpt_platform/backend/backend/blocks/slant3d/base.py
+++ b/autogpt_platform/backend/backend/blocks/slant3d/base.py
@@ -1,6 +1,6 @@
from typing import Any, Dict
-from backend.data.block import Block
+from backend.blocks._base import Block
from backend.util.request import Requests
from ._api import Color, CustomerDetails, OrderItem, Profile
diff --git a/autogpt_platform/backend/backend/blocks/slant3d/filament.py b/autogpt_platform/backend/backend/blocks/slant3d/filament.py
index f2b9eae38d..723ebff59e 100644
--- a/autogpt_platform/backend/backend/blocks/slant3d/filament.py
+++ b/autogpt_platform/backend/backend/blocks/slant3d/filament.py
@@ -1,6 +1,6 @@
from typing import List
-from backend.data.block import BlockOutput, BlockSchemaInput, BlockSchemaOutput
+from backend.blocks._base import BlockOutput, BlockSchemaInput, BlockSchemaOutput
from backend.data.model import APIKeyCredentials, SchemaField
from ._api import (
diff --git a/autogpt_platform/backend/backend/blocks/slant3d/order.py b/autogpt_platform/backend/backend/blocks/slant3d/order.py
index 4ece3fc51e..36d2705ea5 100644
--- a/autogpt_platform/backend/backend/blocks/slant3d/order.py
+++ b/autogpt_platform/backend/backend/blocks/slant3d/order.py
@@ -1,7 +1,7 @@
import uuid
from typing import List
-from backend.data.block import BlockOutput, BlockSchemaInput, BlockSchemaOutput
+from backend.blocks._base import BlockOutput, BlockSchemaInput, BlockSchemaOutput
from backend.data.model import APIKeyCredentials, SchemaField
from backend.util.settings import BehaveAs, Settings
diff --git a/autogpt_platform/backend/backend/blocks/slant3d/slicing.py b/autogpt_platform/backend/backend/blocks/slant3d/slicing.py
index 1952b162d2..8740f9504f 100644
--- a/autogpt_platform/backend/backend/blocks/slant3d/slicing.py
+++ b/autogpt_platform/backend/backend/blocks/slant3d/slicing.py
@@ -1,4 +1,4 @@
-from backend.data.block import BlockOutput, BlockSchemaInput, BlockSchemaOutput
+from backend.blocks._base import BlockOutput, BlockSchemaInput, BlockSchemaOutput
from backend.data.model import APIKeyCredentials, SchemaField
from ._api import (
diff --git a/autogpt_platform/backend/backend/blocks/slant3d/webhook.py b/autogpt_platform/backend/backend/blocks/slant3d/webhook.py
index e5a2d72568..f2cb86ec09 100644
--- a/autogpt_platform/backend/backend/blocks/slant3d/webhook.py
+++ b/autogpt_platform/backend/backend/blocks/slant3d/webhook.py
@@ -1,6 +1,6 @@
from pydantic import BaseModel
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/smart_decision_maker.py b/autogpt_platform/backend/backend/blocks/smart_decision_maker.py
index ff6042eaab..5e6b11eebd 100644
--- a/autogpt_platform/backend/backend/blocks/smart_decision_maker.py
+++ b/autogpt_platform/backend/backend/blocks/smart_decision_maker.py
@@ -7,8 +7,7 @@ from typing import TYPE_CHECKING, Any
from pydantic import BaseModel
import backend.blocks.llm as llm
-from backend.blocks.agent import AgentExecutorBlock
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockInput,
@@ -17,6 +16,7 @@ from backend.data.block import (
BlockSchemaOutput,
BlockType,
)
+from backend.blocks.agent import AgentExecutorBlock
from backend.data.dynamic_fields import (
extract_base_field_name,
get_dynamic_field_description,
diff --git a/autogpt_platform/backend/backend/blocks/smartlead/campaign.py b/autogpt_platform/backend/backend/blocks/smartlead/campaign.py
index c3bf930068..302a38f4db 100644
--- a/autogpt_platform/backend/backend/blocks/smartlead/campaign.py
+++ b/autogpt_platform/backend/backend/blocks/smartlead/campaign.py
@@ -1,3 +1,10 @@
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.smartlead._api import SmartLeadClient
from backend.blocks.smartlead._auth import (
TEST_CREDENTIALS,
@@ -16,13 +23,6 @@ from backend.blocks.smartlead.models import (
SaveSequencesResponse,
Sequence,
)
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import CredentialsField, SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/spreadsheet.py b/autogpt_platform/backend/backend/blocks/spreadsheet.py
index a13f9e2f6d..2bbfd6776f 100644
--- a/autogpt_platform/backend/backend/blocks/spreadsheet.py
+++ b/autogpt_platform/backend/backend/blocks/spreadsheet.py
@@ -1,6 +1,6 @@
from pathlib import Path
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/system/library_operations.py b/autogpt_platform/backend/backend/blocks/system/library_operations.py
index 116da64599..b2433ce220 100644
--- a/autogpt_platform/backend/backend/blocks/system/library_operations.py
+++ b/autogpt_platform/backend/backend/blocks/system/library_operations.py
@@ -3,7 +3,7 @@ from typing import Any
from pydantic import BaseModel
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/system/store_operations.py b/autogpt_platform/backend/backend/blocks/system/store_operations.py
index e9b7a01ebe..88958a5707 100644
--- a/autogpt_platform/backend/backend/blocks/system/store_operations.py
+++ b/autogpt_platform/backend/backend/blocks/system/store_operations.py
@@ -3,7 +3,7 @@ from typing import Literal
from pydantic import BaseModel
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/talking_head.py b/autogpt_platform/backend/backend/blocks/talking_head.py
index e01e3d4023..f199d030ff 100644
--- a/autogpt_platform/backend/backend/blocks/talking_head.py
+++ b/autogpt_platform/backend/backend/blocks/talking_head.py
@@ -3,7 +3,7 @@ from typing import Literal
from pydantic import SecretStr
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/test/test_block.py b/autogpt_platform/backend/backend/blocks/test/test_block.py
index 7a1fdbcc73..c7f3ca62f2 100644
--- a/autogpt_platform/backend/backend/blocks/test/test_block.py
+++ b/autogpt_platform/backend/backend/blocks/test/test_block.py
@@ -2,7 +2,8 @@ from typing import Any, Type
import pytest
-from backend.data.block import Block, BlockSchemaInput, get_blocks
+from backend.blocks import get_blocks
+from backend.blocks._base import Block, BlockSchemaInput
from backend.data.model import SchemaField
from backend.util.test import execute_block_test
diff --git a/autogpt_platform/backend/backend/blocks/text.py b/autogpt_platform/backend/backend/blocks/text.py
index 359e22a84f..4276ff3a45 100644
--- a/autogpt_platform/backend/backend/blocks/text.py
+++ b/autogpt_platform/backend/backend/blocks/text.py
@@ -4,7 +4,7 @@ from typing import Any
import regex # Has built-in timeout support
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/text_to_speech_block.py b/autogpt_platform/backend/backend/blocks/text_to_speech_block.py
index 8fe9e1cda7..a408c8772f 100644
--- a/autogpt_platform/backend/backend/blocks/text_to_speech_block.py
+++ b/autogpt_platform/backend/backend/blocks/text_to_speech_block.py
@@ -2,7 +2,7 @@ from typing import Any, Literal
from pydantic import SecretStr
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/time_blocks.py b/autogpt_platform/backend/backend/blocks/time_blocks.py
index 3a1f4c678e..5ee13db30b 100644
--- a/autogpt_platform/backend/backend/blocks/time_blocks.py
+++ b/autogpt_platform/backend/backend/blocks/time_blocks.py
@@ -7,7 +7,7 @@ from zoneinfo import ZoneInfo
from pydantic import BaseModel
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/todoist/comments.py b/autogpt_platform/backend/backend/blocks/todoist/comments.py
index f11534cbe3..dc8eef3919 100644
--- a/autogpt_platform/backend/backend/blocks/todoist/comments.py
+++ b/autogpt_platform/backend/backend/blocks/todoist/comments.py
@@ -4,6 +4,13 @@ from pydantic import BaseModel
from todoist_api_python.api import TodoistAPI
from typing_extensions import Optional
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.todoist._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -12,13 +19,6 @@ from backend.blocks.todoist._auth import (
TodoistCredentialsField,
TodoistCredentialsInput,
)
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/todoist/labels.py b/autogpt_platform/backend/backend/blocks/todoist/labels.py
index 8107459567..0b0f26cc77 100644
--- a/autogpt_platform/backend/backend/blocks/todoist/labels.py
+++ b/autogpt_platform/backend/backend/blocks/todoist/labels.py
@@ -1,6 +1,13 @@
from todoist_api_python.api import TodoistAPI
from typing_extensions import Optional
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.todoist._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -10,13 +17,6 @@ from backend.blocks.todoist._auth import (
TodoistCredentialsInput,
)
from backend.blocks.todoist._types import Colors
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/todoist/projects.py b/autogpt_platform/backend/backend/blocks/todoist/projects.py
index c6d345c116..a35bd3d41e 100644
--- a/autogpt_platform/backend/backend/blocks/todoist/projects.py
+++ b/autogpt_platform/backend/backend/blocks/todoist/projects.py
@@ -1,6 +1,13 @@
from todoist_api_python.api import TodoistAPI
from typing_extensions import Optional
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.todoist._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -10,13 +17,6 @@ from backend.blocks.todoist._auth import (
TodoistCredentialsInput,
)
from backend.blocks.todoist._types import Colors
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/todoist/sections.py b/autogpt_platform/backend/backend/blocks/todoist/sections.py
index 52dceb70b9..23cabdb661 100644
--- a/autogpt_platform/backend/backend/blocks/todoist/sections.py
+++ b/autogpt_platform/backend/backend/blocks/todoist/sections.py
@@ -1,6 +1,13 @@
from todoist_api_python.api import TodoistAPI
from typing_extensions import Optional
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.todoist._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -9,13 +16,6 @@ from backend.blocks.todoist._auth import (
TodoistCredentialsField,
TodoistCredentialsInput,
)
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/todoist/tasks.py b/autogpt_platform/backend/backend/blocks/todoist/tasks.py
index 183a3340b3..6aaf766114 100644
--- a/autogpt_platform/backend/backend/blocks/todoist/tasks.py
+++ b/autogpt_platform/backend/backend/blocks/todoist/tasks.py
@@ -4,6 +4,13 @@ from todoist_api_python.api import TodoistAPI
from todoist_api_python.models import Task
from typing_extensions import Optional
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.todoist._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -12,13 +19,6 @@ from backend.blocks.todoist._auth import (
TodoistCredentialsField,
TodoistCredentialsInput,
)
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/twitter/_types.py b/autogpt_platform/backend/backend/blocks/twitter/_types.py
index 88050ed545..ead54677be 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/_types.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/_types.py
@@ -3,7 +3,7 @@ from enum import Enum
from pydantic import BaseModel
-from backend.data.block import BlockSchemaInput
+from backend.blocks._base import BlockSchemaInput
from backend.data.model import SchemaField
# -------------- Tweets -----------------
diff --git a/autogpt_platform/backend/backend/blocks/twitter/direct_message/direct_message_lookup.py b/autogpt_platform/backend/backend/blocks/twitter/direct_message/direct_message_lookup.py
index 0ce8e08535..f4b07ca53e 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/direct_message/direct_message_lookup.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/direct_message/direct_message_lookup.py
@@ -4,8 +4,8 @@
# import tweepy
# from tweepy.client import Response
+# from backend.blocks._base import Block, BlockCategory, BlockOutput, BlockSchema, BlockSchemaInput, BlockSchemaOutput
# from backend.blocks.twitter._serializer import IncludesSerializer, ResponseDataSerializer
-# from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema, BlockSchemaInput, BlockSchemaOutput
# from backend.data.model import SchemaField
# from backend.blocks.twitter._builders import DMExpansionsBuilder
# from backend.blocks.twitter._types import DMEventExpansion, DMEventExpansionInputs, DMEventType, DMMediaField, DMTweetField, TweetUserFields
diff --git a/autogpt_platform/backend/backend/blocks/twitter/direct_message/manage_direct_message.py b/autogpt_platform/backend/backend/blocks/twitter/direct_message/manage_direct_message.py
index cbbe019f37..0104e3e9c5 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/direct_message/manage_direct_message.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/direct_message/manage_direct_message.py
@@ -5,7 +5,7 @@
# import tweepy
# from tweepy.client import Response
-# from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema, BlockSchemaInput, BlockSchemaOutput
+# from backend.blocks._base import Block, BlockCategory, BlockOutput, BlockSchema, BlockSchemaInput, BlockSchemaOutput
# from backend.data.model import SchemaField
# from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
# from backend.blocks.twitter._auth import (
diff --git a/autogpt_platform/backend/backend/blocks/twitter/lists/list_follows.py b/autogpt_platform/backend/backend/blocks/twitter/lists/list_follows.py
index 5616e0ce14..93dfaef919 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/lists/list_follows.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/lists/list_follows.py
@@ -1,6 +1,13 @@
# from typing import cast
import tweepy
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.twitter._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -13,13 +20,6 @@ from backend.blocks.twitter._auth import (
# from backend.blocks.twitter._builders import UserExpansionsBuilder
# from backend.blocks.twitter._types import TweetFields, TweetUserFields, UserExpansionInputs, UserExpansions
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import SchemaField
# from tweepy.client import Response
diff --git a/autogpt_platform/backend/backend/blocks/twitter/lists/list_lookup.py b/autogpt_platform/backend/backend/blocks/twitter/lists/list_lookup.py
index 6b46f00a37..a6a5607196 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/lists/list_lookup.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/lists/list_lookup.py
@@ -3,6 +3,7 @@ from typing import cast
import tweepy
from tweepy.client import Response
+from backend.blocks._base import Block, BlockCategory, BlockOutput, BlockSchemaOutput
from backend.blocks.twitter._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -23,7 +24,6 @@ from backend.blocks.twitter._types import (
TweetUserFieldsFilter,
)
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
-from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchemaOutput
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/twitter/lists/list_members.py b/autogpt_platform/backend/backend/blocks/twitter/lists/list_members.py
index 32ffb9e5b6..5505f1457a 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/lists/list_members.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/lists/list_members.py
@@ -3,6 +3,13 @@ from typing import cast
import tweepy
from tweepy.client import Response
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.twitter._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -29,13 +36,6 @@ from backend.blocks.twitter._types import (
UserExpansionsFilter,
)
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/twitter/lists/list_tweets_lookup.py b/autogpt_platform/backend/backend/blocks/twitter/lists/list_tweets_lookup.py
index e43980683e..57dc6579c9 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/lists/list_tweets_lookup.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/lists/list_tweets_lookup.py
@@ -3,6 +3,7 @@ from typing import cast
import tweepy
from tweepy.client import Response
+from backend.blocks._base import Block, BlockCategory, BlockOutput, BlockSchemaOutput
from backend.blocks.twitter._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -26,7 +27,6 @@ from backend.blocks.twitter._types import (
TweetUserFieldsFilter,
)
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
-from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchemaOutput
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/twitter/lists/manage_lists.py b/autogpt_platform/backend/backend/blocks/twitter/lists/manage_lists.py
index 4092fbaa93..9bab05e98b 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/lists/manage_lists.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/lists/manage_lists.py
@@ -3,6 +3,13 @@ from typing import cast
import tweepy
from tweepy.client import Response
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.twitter._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -12,13 +19,6 @@ from backend.blocks.twitter._auth import (
TwitterCredentialsInput,
)
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/twitter/lists/pinned_lists.py b/autogpt_platform/backend/backend/blocks/twitter/lists/pinned_lists.py
index 7bc5bb543f..0ebe9503b0 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/lists/pinned_lists.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/lists/pinned_lists.py
@@ -3,6 +3,13 @@ from typing import cast
import tweepy
from tweepy.client import Response
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.twitter._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -23,13 +30,6 @@ from backend.blocks.twitter._types import (
TweetUserFieldsFilter,
)
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/twitter/spaces/search_spaces.py b/autogpt_platform/backend/backend/blocks/twitter/spaces/search_spaces.py
index bd013cecc1..a38dc5452e 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/spaces/search_spaces.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/spaces/search_spaces.py
@@ -3,6 +3,7 @@ from typing import cast
import tweepy
from tweepy.client import Response
+from backend.blocks._base import Block, BlockCategory, BlockOutput, BlockSchemaOutput
from backend.blocks.twitter._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -24,7 +25,6 @@ from backend.blocks.twitter._types import (
TweetUserFieldsFilter,
)
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
-from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchemaOutput
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/twitter/spaces/spaces_lookup.py b/autogpt_platform/backend/backend/blocks/twitter/spaces/spaces_lookup.py
index 2c99d3ba3a..c31f0efd38 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/spaces/spaces_lookup.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/spaces/spaces_lookup.py
@@ -4,6 +4,7 @@ import tweepy
from pydantic import BaseModel
from tweepy.client import Response
+from backend.blocks._base import Block, BlockCategory, BlockOutput, BlockSchemaOutput
from backend.blocks.twitter._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -36,7 +37,6 @@ from backend.blocks.twitter._types import (
UserExpansionsFilter,
)
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
-from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchemaOutput
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/twitter/tweets/bookmark.py b/autogpt_platform/backend/backend/blocks/twitter/tweets/bookmark.py
index b69002837e..9d8bfccad9 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/tweets/bookmark.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/tweets/bookmark.py
@@ -3,6 +3,13 @@ from typing import cast
import tweepy
from tweepy.client import Response
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.twitter._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -26,13 +33,6 @@ from backend.blocks.twitter._types import (
TweetUserFieldsFilter,
)
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/twitter/tweets/hide.py b/autogpt_platform/backend/backend/blocks/twitter/tweets/hide.py
index f9992ea7c0..72ed2096a7 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/tweets/hide.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/tweets/hide.py
@@ -1,5 +1,12 @@
import tweepy
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.twitter._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -9,13 +16,6 @@ from backend.blocks.twitter._auth import (
TwitterCredentialsInput,
)
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/twitter/tweets/like.py b/autogpt_platform/backend/backend/blocks/twitter/tweets/like.py
index 2d499257a9..c2a920276c 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/tweets/like.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/tweets/like.py
@@ -3,6 +3,13 @@ from typing import cast
import tweepy
from tweepy.client import Response
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.twitter._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -31,13 +38,6 @@ from backend.blocks.twitter._types import (
UserExpansionsFilter,
)
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/twitter/tweets/manage.py b/autogpt_platform/backend/backend/blocks/twitter/tweets/manage.py
index 875e22738b..68e379b895 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/tweets/manage.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/tweets/manage.py
@@ -5,6 +5,13 @@ import tweepy
from pydantic import BaseModel
from tweepy.client import Response
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.twitter._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -35,13 +42,6 @@ from backend.blocks.twitter._types import (
TweetUserFieldsFilter,
)
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/twitter/tweets/quote.py b/autogpt_platform/backend/backend/blocks/twitter/tweets/quote.py
index fc6c336e20..be8d5b3125 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/tweets/quote.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/tweets/quote.py
@@ -3,6 +3,7 @@ from typing import cast
import tweepy
from tweepy.client import Response
+from backend.blocks._base import Block, BlockCategory, BlockOutput, BlockSchemaOutput
from backend.blocks.twitter._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -27,7 +28,6 @@ from backend.blocks.twitter._types import (
TweetUserFieldsFilter,
)
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
-from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchemaOutput
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/twitter/tweets/retweet.py b/autogpt_platform/backend/backend/blocks/twitter/tweets/retweet.py
index 1f65f90ea3..606e3b8a74 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/tweets/retweet.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/tweets/retweet.py
@@ -3,6 +3,13 @@ from typing import cast
import tweepy
from tweepy.client import Response
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.twitter._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -23,13 +30,6 @@ from backend.blocks.twitter._types import (
UserExpansionsFilter,
)
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/twitter/tweets/timeline.py b/autogpt_platform/backend/backend/blocks/twitter/tweets/timeline.py
index 9f07beba66..347ff5aee1 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/tweets/timeline.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/tweets/timeline.py
@@ -4,6 +4,7 @@ from typing import cast
import tweepy
from tweepy.client import Response
+from backend.blocks._base import Block, BlockCategory, BlockOutput, BlockSchemaOutput
from backend.blocks.twitter._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -31,7 +32,6 @@ from backend.blocks.twitter._types import (
TweetUserFieldsFilter,
)
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
-from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchemaOutput
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/twitter/tweets/tweet_lookup.py b/autogpt_platform/backend/backend/blocks/twitter/tweets/tweet_lookup.py
index 540aa1395f..f452848288 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/tweets/tweet_lookup.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/tweets/tweet_lookup.py
@@ -3,6 +3,7 @@ from typing import cast
import tweepy
from tweepy.client import Response
+from backend.blocks._base import Block, BlockCategory, BlockOutput, BlockSchemaOutput
from backend.blocks.twitter._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -26,7 +27,6 @@ from backend.blocks.twitter._types import (
TweetUserFieldsFilter,
)
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
-from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchemaOutput
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/twitter/users/blocks.py b/autogpt_platform/backend/backend/blocks/twitter/users/blocks.py
index 1c192aa6b5..12df24cfe2 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/users/blocks.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/users/blocks.py
@@ -3,6 +3,7 @@ from typing import cast
import tweepy
from tweepy.client import Response
+from backend.blocks._base import Block, BlockCategory, BlockOutput, BlockSchemaOutput
from backend.blocks.twitter._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -20,7 +21,6 @@ from backend.blocks.twitter._types import (
UserExpansionsFilter,
)
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
-from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchemaOutput
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/twitter/users/follows.py b/autogpt_platform/backend/backend/blocks/twitter/users/follows.py
index 537aea6031..20276b19b4 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/users/follows.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/users/follows.py
@@ -3,6 +3,13 @@ from typing import cast
import tweepy
from tweepy.client import Response
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.twitter._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -23,13 +30,6 @@ from backend.blocks.twitter._types import (
UserExpansionsFilter,
)
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/twitter/users/mutes.py b/autogpt_platform/backend/backend/blocks/twitter/users/mutes.py
index e22aec94dc..31927e2b71 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/users/mutes.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/users/mutes.py
@@ -3,6 +3,13 @@ from typing import cast
import tweepy
from tweepy.client import Response
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.twitter._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -23,13 +30,6 @@ from backend.blocks.twitter._types import (
UserExpansionsFilter,
)
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/twitter/users/user_lookup.py b/autogpt_platform/backend/backend/blocks/twitter/users/user_lookup.py
index 67c7d14c9b..8d01876955 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/users/user_lookup.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/users/user_lookup.py
@@ -4,6 +4,7 @@ import tweepy
from pydantic import BaseModel
from tweepy.client import Response
+from backend.blocks._base import Block, BlockCategory, BlockOutput, BlockSchemaOutput
from backend.blocks.twitter._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -24,7 +25,6 @@ from backend.blocks.twitter._types import (
UserExpansionsFilter,
)
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
-from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchemaOutput
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/video/add_audio.py b/autogpt_platform/backend/backend/blocks/video/add_audio.py
index ebd4ab94f2..f91a82a758 100644
--- a/autogpt_platform/backend/backend/blocks/video/add_audio.py
+++ b/autogpt_platform/backend/backend/blocks/video/add_audio.py
@@ -3,14 +3,14 @@
from moviepy.audio.io.AudioFileClip import AudioFileClip
from moviepy.video.io.VideoFileClip import VideoFileClip
-from backend.blocks.video._utils import extract_source_name, strip_chapters_inplace
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
BlockSchemaInput,
BlockSchemaOutput,
)
+from backend.blocks.video._utils import extract_source_name, strip_chapters_inplace
from backend.data.execution import ExecutionContext
from backend.data.model import SchemaField
from backend.util.file import MediaFileType, get_exec_file_path, store_media_file
diff --git a/autogpt_platform/backend/backend/blocks/video/clip.py b/autogpt_platform/backend/backend/blocks/video/clip.py
index 05deea6530..990a8b2f31 100644
--- a/autogpt_platform/backend/backend/blocks/video/clip.py
+++ b/autogpt_platform/backend/backend/blocks/video/clip.py
@@ -4,18 +4,18 @@ from typing import Literal
from moviepy.video.io.VideoFileClip import VideoFileClip
-from backend.blocks.video._utils import (
- extract_source_name,
- get_video_codecs,
- strip_chapters_inplace,
-)
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
BlockSchemaInput,
BlockSchemaOutput,
)
+from backend.blocks.video._utils import (
+ extract_source_name,
+ get_video_codecs,
+ strip_chapters_inplace,
+)
from backend.data.execution import ExecutionContext
from backend.data.model import SchemaField
from backend.util.exceptions import BlockExecutionError
diff --git a/autogpt_platform/backend/backend/blocks/video/concat.py b/autogpt_platform/backend/backend/blocks/video/concat.py
index b49854fb40..3bf2b5142b 100644
--- a/autogpt_platform/backend/backend/blocks/video/concat.py
+++ b/autogpt_platform/backend/backend/blocks/video/concat.py
@@ -6,18 +6,18 @@ from moviepy import concatenate_videoclips
from moviepy.video.fx import CrossFadeIn, CrossFadeOut, FadeIn, FadeOut
from moviepy.video.io.VideoFileClip import VideoFileClip
-from backend.blocks.video._utils import (
- extract_source_name,
- get_video_codecs,
- strip_chapters_inplace,
-)
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
BlockSchemaInput,
BlockSchemaOutput,
)
+from backend.blocks.video._utils import (
+ extract_source_name,
+ get_video_codecs,
+ strip_chapters_inplace,
+)
from backend.data.execution import ExecutionContext
from backend.data.model import SchemaField
from backend.util.exceptions import BlockExecutionError
diff --git a/autogpt_platform/backend/backend/blocks/video/download.py b/autogpt_platform/backend/backend/blocks/video/download.py
index 4046d5df42..c6d2617f73 100644
--- a/autogpt_platform/backend/backend/blocks/video/download.py
+++ b/autogpt_platform/backend/backend/blocks/video/download.py
@@ -9,7 +9,7 @@ import yt_dlp
if typing.TYPE_CHECKING:
from yt_dlp import _Params
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/video/duration.py b/autogpt_platform/backend/backend/blocks/video/duration.py
index 9e05d35b00..ff904ad650 100644
--- a/autogpt_platform/backend/backend/blocks/video/duration.py
+++ b/autogpt_platform/backend/backend/blocks/video/duration.py
@@ -3,14 +3,14 @@
from moviepy.audio.io.AudioFileClip import AudioFileClip
from moviepy.video.io.VideoFileClip import VideoFileClip
-from backend.blocks.video._utils import strip_chapters_inplace
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
BlockSchemaInput,
BlockSchemaOutput,
)
+from backend.blocks.video._utils import strip_chapters_inplace
from backend.data.execution import ExecutionContext
from backend.data.model import SchemaField
from backend.util.file import MediaFileType, get_exec_file_path, store_media_file
diff --git a/autogpt_platform/backend/backend/blocks/video/loop.py b/autogpt_platform/backend/backend/blocks/video/loop.py
index 461610f713..0cb360a5b2 100644
--- a/autogpt_platform/backend/backend/blocks/video/loop.py
+++ b/autogpt_platform/backend/backend/blocks/video/loop.py
@@ -5,14 +5,14 @@ from typing import Optional
from moviepy.video.fx.Loop import Loop
from moviepy.video.io.VideoFileClip import VideoFileClip
-from backend.blocks.video._utils import extract_source_name, strip_chapters_inplace
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
BlockSchemaInput,
BlockSchemaOutput,
)
+from backend.blocks.video._utils import extract_source_name, strip_chapters_inplace
from backend.data.execution import ExecutionContext
from backend.data.model import SchemaField
from backend.util.file import MediaFileType, get_exec_file_path, store_media_file
diff --git a/autogpt_platform/backend/backend/blocks/video/narration.py b/autogpt_platform/backend/backend/blocks/video/narration.py
index adf41753c8..39b9c481b0 100644
--- a/autogpt_platform/backend/backend/blocks/video/narration.py
+++ b/autogpt_platform/backend/backend/blocks/video/narration.py
@@ -8,6 +8,13 @@ from moviepy import CompositeAudioClip
from moviepy.audio.io.AudioFileClip import AudioFileClip
from moviepy.video.io.VideoFileClip import VideoFileClip
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.elevenlabs._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -19,13 +26,6 @@ from backend.blocks.video._utils import (
get_video_codecs,
strip_chapters_inplace,
)
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.execution import ExecutionContext
from backend.data.model import CredentialsField, SchemaField
from backend.util.exceptions import BlockExecutionError
diff --git a/autogpt_platform/backend/backend/blocks/video/text_overlay.py b/autogpt_platform/backend/backend/blocks/video/text_overlay.py
index cb7cfe0420..86dd30318c 100644
--- a/autogpt_platform/backend/backend/blocks/video/text_overlay.py
+++ b/autogpt_platform/backend/backend/blocks/video/text_overlay.py
@@ -5,18 +5,18 @@ from typing import Literal
from moviepy import CompositeVideoClip, TextClip
from moviepy.video.io.VideoFileClip import VideoFileClip
-from backend.blocks.video._utils import (
- extract_source_name,
- get_video_codecs,
- strip_chapters_inplace,
-)
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
BlockSchemaInput,
BlockSchemaOutput,
)
+from backend.blocks.video._utils import (
+ extract_source_name,
+ get_video_codecs,
+ strip_chapters_inplace,
+)
from backend.data.execution import ExecutionContext
from backend.data.model import SchemaField
from backend.util.exceptions import BlockExecutionError
diff --git a/autogpt_platform/backend/backend/blocks/xml_parser.py b/autogpt_platform/backend/backend/blocks/xml_parser.py
index 223f8ea367..a1274fa562 100644
--- a/autogpt_platform/backend/backend/blocks/xml_parser.py
+++ b/autogpt_platform/backend/backend/blocks/xml_parser.py
@@ -1,7 +1,7 @@
from gravitasml.parser import Parser
from gravitasml.token import Token, tokenize
-from backend.data.block import Block, BlockOutput, BlockSchemaInput, BlockSchemaOutput
+from backend.blocks._base import Block, BlockOutput, BlockSchemaInput, BlockSchemaOutput
from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/backend/blocks/youtube.py b/autogpt_platform/backend/backend/blocks/youtube.py
index 6d81a86b4c..6ce705e4f5 100644
--- a/autogpt_platform/backend/backend/blocks/youtube.py
+++ b/autogpt_platform/backend/backend/blocks/youtube.py
@@ -9,7 +9,7 @@ from youtube_transcript_api._transcripts import FetchedTranscript
from youtube_transcript_api.formatters import TextFormatter
from youtube_transcript_api.proxies import WebshareProxyConfig
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockOutput,
diff --git a/autogpt_platform/backend/backend/blocks/zerobounce/validate_emails.py b/autogpt_platform/backend/backend/blocks/zerobounce/validate_emails.py
index fa5283f324..6a461b4aa8 100644
--- a/autogpt_platform/backend/backend/blocks/zerobounce/validate_emails.py
+++ b/autogpt_platform/backend/backend/blocks/zerobounce/validate_emails.py
@@ -7,6 +7,13 @@ from zerobouncesdk.zb_validate_response import (
ZBValidateSubStatus,
)
+from backend.blocks._base import (
+ Block,
+ BlockCategory,
+ BlockOutput,
+ BlockSchemaInput,
+ BlockSchemaOutput,
+)
from backend.blocks.zerobounce._api import ZeroBounceClient
from backend.blocks.zerobounce._auth import (
TEST_CREDENTIALS,
@@ -14,13 +21,6 @@ from backend.blocks.zerobounce._auth import (
ZeroBounceCredentials,
ZeroBounceCredentialsInput,
)
-from backend.data.block import (
- Block,
- BlockCategory,
- BlockOutput,
- BlockSchemaInput,
- BlockSchemaOutput,
-)
from backend.data.model import CredentialsField, SchemaField
diff --git a/autogpt_platform/backend/backend/copilot/tools/find_block.py b/autogpt_platform/backend/backend/copilot/tools/find_block.py
index ef9314eb5a..d192efcf0d 100644
--- a/autogpt_platform/backend/backend/copilot/tools/find_block.py
+++ b/autogpt_platform/backend/backend/copilot/tools/find_block.py
@@ -3,6 +3,8 @@ from typing import Any
from prisma.enums import ContentType
+from backend.blocks import get_block
+from backend.blocks._base import BlockType
from backend.copilot.model import ChatSession
from backend.copilot.tools.base import BaseTool, ToolResponseBase
from backend.copilot.tools.models import (
@@ -12,7 +14,6 @@ from backend.copilot.tools.models import (
ErrorResponse,
NoResultsResponse,
)
-from backend.data.block import BlockType, get_block
from backend.data.db_accessors import search
logger = logging.getLogger(__name__)
diff --git a/autogpt_platform/backend/backend/copilot/tools/find_block_test.py b/autogpt_platform/backend/backend/copilot/tools/find_block_test.py
index ef4c63e7f9..1547626b87 100644
--- a/autogpt_platform/backend/backend/copilot/tools/find_block_test.py
+++ b/autogpt_platform/backend/backend/copilot/tools/find_block_test.py
@@ -4,13 +4,13 @@ from unittest.mock import AsyncMock, MagicMock, patch
import pytest
+from backend.blocks._base import BlockType
from backend.copilot.tools.find_block import (
COPILOT_EXCLUDED_BLOCK_IDS,
COPILOT_EXCLUDED_BLOCK_TYPES,
FindBlockTool,
)
from backend.copilot.tools.models import BlockListResponse
-from backend.data.block import BlockType
from ._test_data import make_session
diff --git a/autogpt_platform/backend/backend/copilot/tools/run_block.py b/autogpt_platform/backend/backend/copilot/tools/run_block.py
index 56b664a77a..e8b243ffa5 100644
--- a/autogpt_platform/backend/backend/copilot/tools/run_block.py
+++ b/autogpt_platform/backend/backend/copilot/tools/run_block.py
@@ -7,12 +7,13 @@ from typing import Any
from pydantic_core import PydanticUndefined
+from backend.blocks import get_block
+from backend.blocks._base import AnyBlockSchema
from backend.copilot.model import ChatSession
from backend.copilot.tools.find_block import (
COPILOT_EXCLUDED_BLOCK_IDS,
COPILOT_EXCLUDED_BLOCK_TYPES,
)
-from backend.data.block import AnyBlockSchema, get_block
from backend.data.db_accessors import workspace_db
from backend.data.execution import ExecutionContext
from backend.data.model import CredentialsFieldInfo, CredentialsMetaInput
diff --git a/autogpt_platform/backend/backend/copilot/tools/run_block_test.py b/autogpt_platform/backend/backend/copilot/tools/run_block_test.py
index 1f9e2a397e..1e54edf7a5 100644
--- a/autogpt_platform/backend/backend/copilot/tools/run_block_test.py
+++ b/autogpt_platform/backend/backend/copilot/tools/run_block_test.py
@@ -4,9 +4,9 @@ from unittest.mock import MagicMock, patch
import pytest
+from backend.blocks._base import BlockType
from backend.copilot.tools.models import ErrorResponse
from backend.copilot.tools.run_block import RunBlockTool
-from backend.data.block import BlockType
from ._test_data import make_session
diff --git a/autogpt_platform/backend/backend/data/block.py b/autogpt_platform/backend/backend/data/block.py
index f67134ceb3..78c817f547 100644
--- a/autogpt_platform/backend/backend/data/block.py
+++ b/autogpt_platform/backend/backend/data/block.py
@@ -1,878 +1,14 @@
-import inspect
import logging
-import os
-from abc import ABC, abstractmethod
-from collections.abc import AsyncGenerator as AsyncGen
-from enum import Enum
-from typing import (
- TYPE_CHECKING,
- Any,
- Callable,
- ClassVar,
- Generic,
- Optional,
- Sequence,
- Type,
- TypeAlias,
- TypeVar,
- cast,
- get_origin,
-)
-import jsonref
-import jsonschema
from prisma.models import AgentBlock
from prisma.types import AgentBlockCreateInput
-from pydantic import BaseModel
-from backend.data.model import NodeExecutionStats
-from backend.integrations.providers import ProviderName
+from backend.blocks import get_blocks
+from backend.blocks._base import Block
from backend.util import json
-from backend.util.cache import cached
-from backend.util.exceptions import (
- BlockError,
- BlockExecutionError,
- BlockInputError,
- BlockOutputError,
- BlockUnknownError,
-)
-from backend.util.settings import Config
-
-from .model import (
- ContributorDetails,
- Credentials,
- CredentialsFieldInfo,
- CredentialsMetaInput,
- SchemaField,
- is_credentials_field_name,
-)
logger = logging.getLogger(__name__)
-if TYPE_CHECKING:
- from backend.data.execution import ExecutionContext
-
- from .graph import Link
-
-app_config = Config()
-
-BlockInput = dict[str, Any] # Input: 1 input pin consumes 1 data.
-BlockOutputEntry = tuple[str, Any] # Output data should be a tuple of (name, value).
-BlockOutput = AsyncGen[BlockOutputEntry, None] # Output: 1 output pin produces n data.
-BlockTestOutput = BlockOutputEntry | tuple[str, Callable[[Any], bool]]
-CompletedBlockOutput = dict[str, list[Any]] # Completed stream, collected as a dict.
-
-
-class BlockType(Enum):
- STANDARD = "Standard"
- INPUT = "Input"
- OUTPUT = "Output"
- NOTE = "Note"
- WEBHOOK = "Webhook"
- WEBHOOK_MANUAL = "Webhook (manual)"
- AGENT = "Agent"
- AI = "AI"
- AYRSHARE = "Ayrshare"
- HUMAN_IN_THE_LOOP = "Human In The Loop"
-
-
-class BlockCategory(Enum):
- AI = "Block that leverages AI to perform a task."
- SOCIAL = "Block that interacts with social media platforms."
- TEXT = "Block that processes text data."
- SEARCH = "Block that searches or extracts information from the internet."
- BASIC = "Block that performs basic operations."
- INPUT = "Block that interacts with input of the graph."
- OUTPUT = "Block that interacts with output of the graph."
- LOGIC = "Programming logic to control the flow of your agent"
- COMMUNICATION = "Block that interacts with communication platforms."
- DEVELOPER_TOOLS = "Developer tools such as GitHub blocks."
- DATA = "Block that interacts with structured data."
- HARDWARE = "Block that interacts with hardware."
- AGENT = "Block that interacts with other agents."
- CRM = "Block that interacts with CRM services."
- SAFETY = (
- "Block that provides AI safety mechanisms such as detecting harmful content"
- )
- PRODUCTIVITY = "Block that helps with productivity"
- ISSUE_TRACKING = "Block that helps with issue tracking"
- MULTIMEDIA = "Block that interacts with multimedia content"
- MARKETING = "Block that helps with marketing"
-
- def dict(self) -> dict[str, str]:
- return {"category": self.name, "description": self.value}
-
-
-class BlockCostType(str, Enum):
- RUN = "run" # cost X credits per run
- BYTE = "byte" # cost X credits per byte
- SECOND = "second" # cost X credits per second
-
-
-class BlockCost(BaseModel):
- cost_amount: int
- cost_filter: BlockInput
- cost_type: BlockCostType
-
- def __init__(
- self,
- cost_amount: int,
- cost_type: BlockCostType = BlockCostType.RUN,
- cost_filter: Optional[BlockInput] = None,
- **data: Any,
- ) -> None:
- super().__init__(
- cost_amount=cost_amount,
- cost_filter=cost_filter or {},
- cost_type=cost_type,
- **data,
- )
-
-
-class BlockInfo(BaseModel):
- id: str
- name: str
- inputSchema: dict[str, Any]
- outputSchema: dict[str, Any]
- costs: list[BlockCost]
- description: str
- categories: list[dict[str, str]]
- contributors: list[dict[str, Any]]
- staticOutput: bool
- uiType: str
-
-
-class BlockSchema(BaseModel):
- cached_jsonschema: ClassVar[dict[str, Any]]
-
- @classmethod
- def jsonschema(cls) -> dict[str, Any]:
- if cls.cached_jsonschema:
- return cls.cached_jsonschema
-
- model = jsonref.replace_refs(cls.model_json_schema(), merge_props=True)
-
- def ref_to_dict(obj):
- if isinstance(obj, dict):
- # OpenAPI <3.1 does not support sibling fields that has a $ref key
- # So sometimes, the schema has an "allOf"/"anyOf"/"oneOf" with 1 item.
- keys = {"allOf", "anyOf", "oneOf"}
- one_key = next((k for k in keys if k in obj and len(obj[k]) == 1), None)
- if one_key:
- obj.update(obj[one_key][0])
-
- return {
- key: ref_to_dict(value)
- for key, value in obj.items()
- if not key.startswith("$") and key != one_key
- }
- elif isinstance(obj, list):
- return [ref_to_dict(item) for item in obj]
-
- return obj
-
- cls.cached_jsonschema = cast(dict[str, Any], ref_to_dict(model))
-
- return cls.cached_jsonschema
-
- @classmethod
- def validate_data(cls, data: BlockInput) -> str | None:
- return json.validate_with_jsonschema(
- schema=cls.jsonschema(),
- data={k: v for k, v in data.items() if v is not None},
- )
-
- @classmethod
- def get_mismatch_error(cls, data: BlockInput) -> str | None:
- return cls.validate_data(data)
-
- @classmethod
- def get_field_schema(cls, field_name: str) -> dict[str, Any]:
- model_schema = cls.jsonschema().get("properties", {})
- if not model_schema:
- raise ValueError(f"Invalid model schema {cls}")
-
- property_schema = model_schema.get(field_name)
- if not property_schema:
- raise ValueError(f"Invalid property name {field_name}")
-
- return property_schema
-
- @classmethod
- def validate_field(cls, field_name: str, data: BlockInput) -> str | None:
- """
- Validate the data against a specific property (one of the input/output name).
- Returns the validation error message if the data does not match the schema.
- """
- try:
- property_schema = cls.get_field_schema(field_name)
- jsonschema.validate(json.to_dict(data), property_schema)
- return None
- except jsonschema.ValidationError as e:
- return str(e)
-
- @classmethod
- def get_fields(cls) -> set[str]:
- return set(cls.model_fields.keys())
-
- @classmethod
- def get_required_fields(cls) -> set[str]:
- return {
- field
- for field, field_info in cls.model_fields.items()
- if field_info.is_required()
- }
-
- @classmethod
- def __pydantic_init_subclass__(cls, **kwargs):
- """Validates the schema definition. Rules:
- - Fields with annotation `CredentialsMetaInput` MUST be
- named `credentials` or `*_credentials`
- - Fields named `credentials` or `*_credentials` MUST be
- of type `CredentialsMetaInput`
- """
- super().__pydantic_init_subclass__(**kwargs)
-
- # Reset cached JSON schema to prevent inheriting it from parent class
- cls.cached_jsonschema = {}
-
- credentials_fields = cls.get_credentials_fields()
-
- for field_name in cls.get_fields():
- if is_credentials_field_name(field_name):
- if field_name not in credentials_fields:
- raise TypeError(
- f"Credentials field '{field_name}' on {cls.__qualname__} "
- f"is not of type {CredentialsMetaInput.__name__}"
- )
-
- CredentialsMetaInput.validate_credentials_field_schema(
- cls.get_field_schema(field_name), field_name
- )
-
- elif field_name in credentials_fields:
- raise KeyError(
- f"Credentials field '{field_name}' on {cls.__qualname__} "
- "has invalid name: must be 'credentials' or *_credentials"
- )
-
- @classmethod
- def get_credentials_fields(cls) -> dict[str, type[CredentialsMetaInput]]:
- return {
- field_name: info.annotation
- for field_name, info in cls.model_fields.items()
- if (
- inspect.isclass(info.annotation)
- and issubclass(
- get_origin(info.annotation) or info.annotation,
- CredentialsMetaInput,
- )
- )
- }
-
- @classmethod
- def get_auto_credentials_fields(cls) -> dict[str, dict[str, Any]]:
- """
- Get fields that have auto_credentials metadata (e.g., GoogleDriveFileInput).
-
- Returns a dict mapping kwarg_name -> {field_name, auto_credentials_config}
-
- Raises:
- ValueError: If multiple fields have the same kwarg_name, as this would
- cause silent overwriting and only the last field would be processed.
- """
- result: dict[str, dict[str, Any]] = {}
- schema = cls.jsonschema()
- properties = schema.get("properties", {})
-
- for field_name, field_schema in properties.items():
- auto_creds = field_schema.get("auto_credentials")
- if auto_creds:
- kwarg_name = auto_creds.get("kwarg_name", "credentials")
- if kwarg_name in result:
- raise ValueError(
- f"Duplicate auto_credentials kwarg_name '{kwarg_name}' "
- f"in fields '{result[kwarg_name]['field_name']}' and "
- f"'{field_name}' on {cls.__qualname__}"
- )
- result[kwarg_name] = {
- "field_name": field_name,
- "config": auto_creds,
- }
- return result
-
- @classmethod
- def get_credentials_fields_info(cls) -> dict[str, CredentialsFieldInfo]:
- result = {}
-
- # Regular credentials fields
- for field_name in cls.get_credentials_fields().keys():
- result[field_name] = CredentialsFieldInfo.model_validate(
- cls.get_field_schema(field_name), by_alias=True
- )
-
- # Auto-generated credentials fields (from GoogleDriveFileInput etc.)
- for kwarg_name, info in cls.get_auto_credentials_fields().items():
- config = info["config"]
- # Build a schema-like dict that CredentialsFieldInfo can parse
- auto_schema = {
- "credentials_provider": [config.get("provider", "google")],
- "credentials_types": [config.get("type", "oauth2")],
- "credentials_scopes": config.get("scopes"),
- }
- result[kwarg_name] = CredentialsFieldInfo.model_validate(
- auto_schema, by_alias=True
- )
-
- return result
-
- @classmethod
- def get_input_defaults(cls, data: BlockInput) -> BlockInput:
- return data # Return as is, by default.
-
- @classmethod
- def get_missing_links(cls, data: BlockInput, links: list["Link"]) -> set[str]:
- input_fields_from_nodes = {link.sink_name for link in links}
- return input_fields_from_nodes - set(data)
-
- @classmethod
- def get_missing_input(cls, data: BlockInput) -> set[str]:
- return cls.get_required_fields() - set(data)
-
-
-class BlockSchemaInput(BlockSchema):
- """
- Base schema class for block inputs.
- All block input schemas should extend this class for consistency.
- """
-
- pass
-
-
-class BlockSchemaOutput(BlockSchema):
- """
- Base schema class for block outputs that includes a standard error field.
- All block output schemas should extend this class to ensure consistent error handling.
- """
-
- error: str = SchemaField(
- description="Error message if the operation failed", default=""
- )
-
-
-BlockSchemaInputType = TypeVar("BlockSchemaInputType", bound=BlockSchemaInput)
-BlockSchemaOutputType = TypeVar("BlockSchemaOutputType", bound=BlockSchemaOutput)
-
-
-class EmptyInputSchema(BlockSchemaInput):
- pass
-
-
-class EmptyOutputSchema(BlockSchemaOutput):
- pass
-
-
-# For backward compatibility - will be deprecated
-EmptySchema = EmptyOutputSchema
-
-
-# --8<-- [start:BlockWebhookConfig]
-class BlockManualWebhookConfig(BaseModel):
- """
- Configuration model for webhook-triggered blocks on which
- the user has to manually set up the webhook at the provider.
- """
-
- provider: ProviderName
- """The service provider that the webhook connects to"""
-
- webhook_type: str
- """
- Identifier for the webhook type. E.g. GitHub has repo and organization level hooks.
-
- Only for use in the corresponding `WebhooksManager`.
- """
-
- event_filter_input: str = ""
- """
- Name of the block's event filter input.
- Leave empty if the corresponding webhook doesn't have distinct event/payload types.
- """
-
- event_format: str = "{event}"
- """
- Template string for the event(s) that a block instance subscribes to.
- Applied individually to each event selected in the event filter input.
-
- Example: `"pull_request.{event}"` -> `"pull_request.opened"`
- """
-
-
-class BlockWebhookConfig(BlockManualWebhookConfig):
- """
- Configuration model for webhook-triggered blocks for which
- the webhook can be automatically set up through the provider's API.
- """
-
- resource_format: str
- """
- Template string for the resource that a block instance subscribes to.
- Fields will be filled from the block's inputs (except `payload`).
-
- Example: `f"{repo}/pull_requests"` (note: not how it's actually implemented)
-
- Only for use in the corresponding `WebhooksManager`.
- """
- # --8<-- [end:BlockWebhookConfig]
-
-
-class Block(ABC, Generic[BlockSchemaInputType, BlockSchemaOutputType]):
- def __init__(
- self,
- id: str = "",
- description: str = "",
- contributors: list[ContributorDetails] = [],
- categories: set[BlockCategory] | None = None,
- input_schema: Type[BlockSchemaInputType] = EmptyInputSchema,
- output_schema: Type[BlockSchemaOutputType] = EmptyOutputSchema,
- test_input: BlockInput | list[BlockInput] | None = None,
- test_output: BlockTestOutput | list[BlockTestOutput] | None = None,
- test_mock: dict[str, Any] | None = None,
- test_credentials: Optional[Credentials | dict[str, Credentials]] = None,
- disabled: bool = False,
- static_output: bool = False,
- block_type: BlockType = BlockType.STANDARD,
- webhook_config: Optional[BlockWebhookConfig | BlockManualWebhookConfig] = None,
- is_sensitive_action: bool = False,
- ):
- """
- Initialize the block with the given schema.
-
- Args:
- id: The unique identifier for the block, this value will be persisted in the
- DB. So it should be a unique and constant across the application run.
- Use the UUID format for the ID.
- description: The description of the block, explaining what the block does.
- contributors: The list of contributors who contributed to the block.
- input_schema: The schema, defined as a Pydantic model, for the input data.
- output_schema: The schema, defined as a Pydantic model, for the output data.
- test_input: The list or single sample input data for the block, for testing.
- test_output: The list or single expected output if the test_input is run.
- test_mock: function names on the block implementation to mock on test run.
- disabled: If the block is disabled, it will not be available for execution.
- static_output: Whether the output links of the block are static by default.
- """
- self.id = id
- self.input_schema = input_schema
- self.output_schema = output_schema
- self.test_input = test_input
- self.test_output = test_output
- self.test_mock = test_mock
- self.test_credentials = test_credentials
- self.description = description
- self.categories = categories or set()
- self.contributors = contributors or set()
- self.disabled = disabled
- self.static_output = static_output
- self.block_type = block_type
- self.webhook_config = webhook_config
- self.is_sensitive_action = is_sensitive_action
- self.execution_stats: NodeExecutionStats = NodeExecutionStats()
-
- if self.webhook_config:
- if isinstance(self.webhook_config, BlockWebhookConfig):
- # Enforce presence of credentials field on auto-setup webhook blocks
- if not (cred_fields := self.input_schema.get_credentials_fields()):
- raise TypeError(
- "credentials field is required on auto-setup webhook blocks"
- )
- # Disallow multiple credentials inputs on webhook blocks
- elif len(cred_fields) > 1:
- raise ValueError(
- "Multiple credentials inputs not supported on webhook blocks"
- )
-
- self.block_type = BlockType.WEBHOOK
- else:
- self.block_type = BlockType.WEBHOOK_MANUAL
-
- # Enforce shape of webhook event filter, if present
- if self.webhook_config.event_filter_input:
- event_filter_field = self.input_schema.model_fields[
- self.webhook_config.event_filter_input
- ]
- if not (
- isinstance(event_filter_field.annotation, type)
- and issubclass(event_filter_field.annotation, BaseModel)
- and all(
- field.annotation is bool
- for field in event_filter_field.annotation.model_fields.values()
- )
- ):
- raise NotImplementedError(
- f"{self.name} has an invalid webhook event selector: "
- "field must be a BaseModel and all its fields must be boolean"
- )
-
- # Enforce presence of 'payload' input
- if "payload" not in self.input_schema.model_fields:
- raise TypeError(
- f"{self.name} is webhook-triggered but has no 'payload' input"
- )
-
- # Disable webhook-triggered block if webhook functionality not available
- if not app_config.platform_base_url:
- self.disabled = True
-
- @classmethod
- def create(cls: Type["Block"]) -> "Block":
- return cls()
-
- @abstractmethod
- async def run(self, input_data: BlockSchemaInputType, **kwargs) -> BlockOutput:
- """
- Run the block with the given input data.
- Args:
- input_data: The input data with the structure of input_schema.
-
- Kwargs: Currently 14/02/2025 these include
- graph_id: The ID of the graph.
- node_id: The ID of the node.
- graph_exec_id: The ID of the graph execution.
- node_exec_id: The ID of the node execution.
- user_id: The ID of the user.
-
- Returns:
- A Generator that yields (output_name, output_data).
- output_name: One of the output name defined in Block's output_schema.
- output_data: The data for the output_name, matching the defined schema.
- """
- # --- satisfy the type checker, never executed -------------
- if False: # noqa: SIM115
- yield "name", "value" # pyright: ignore[reportMissingYield]
- raise NotImplementedError(f"{self.name} does not implement the run method.")
-
- async def run_once(
- self, input_data: BlockSchemaInputType, output: str, **kwargs
- ) -> Any:
- async for item in self.run(input_data, **kwargs):
- name, data = item
- if name == output:
- return data
- raise ValueError(f"{self.name} did not produce any output for {output}")
-
- def merge_stats(self, stats: NodeExecutionStats) -> NodeExecutionStats:
- self.execution_stats += stats
- return self.execution_stats
-
- @property
- def name(self):
- return self.__class__.__name__
-
- def to_dict(self):
- return {
- "id": self.id,
- "name": self.name,
- "inputSchema": self.input_schema.jsonschema(),
- "outputSchema": self.output_schema.jsonschema(),
- "description": self.description,
- "categories": [category.dict() for category in self.categories],
- "contributors": [
- contributor.model_dump() for contributor in self.contributors
- ],
- "staticOutput": self.static_output,
- "uiType": self.block_type.value,
- }
-
- def get_info(self) -> BlockInfo:
- from backend.data.credit import get_block_cost
-
- return BlockInfo(
- id=self.id,
- name=self.name,
- inputSchema=self.input_schema.jsonschema(),
- outputSchema=self.output_schema.jsonschema(),
- costs=get_block_cost(self),
- description=self.description,
- categories=[category.dict() for category in self.categories],
- contributors=[
- contributor.model_dump() for contributor in self.contributors
- ],
- staticOutput=self.static_output,
- uiType=self.block_type.value,
- )
-
- async def execute(self, input_data: BlockInput, **kwargs) -> BlockOutput:
- try:
- async for output_name, output_data in self._execute(input_data, **kwargs):
- yield output_name, output_data
- except Exception as ex:
- if isinstance(ex, BlockError):
- raise ex
- else:
- raise (
- BlockExecutionError
- if isinstance(ex, ValueError)
- else BlockUnknownError
- )(
- message=str(ex),
- block_name=self.name,
- block_id=self.id,
- ) from ex
-
- async def is_block_exec_need_review(
- self,
- input_data: BlockInput,
- *,
- user_id: str,
- node_id: str,
- node_exec_id: str,
- graph_exec_id: str,
- graph_id: str,
- graph_version: int,
- execution_context: "ExecutionContext",
- **kwargs,
- ) -> tuple[bool, BlockInput]:
- """
- Check if this block execution needs human review and handle the review process.
-
- Returns:
- Tuple of (should_pause, input_data_to_use)
- - should_pause: True if execution should be paused for review
- - input_data_to_use: The input data to use (may be modified by reviewer)
- """
- if not (
- self.is_sensitive_action and execution_context.sensitive_action_safe_mode
- ):
- return False, input_data
-
- from backend.blocks.helpers.review import HITLReviewHelper
-
- # Handle the review request and get decision
- decision = await HITLReviewHelper.handle_review_decision(
- input_data=input_data,
- user_id=user_id,
- node_id=node_id,
- node_exec_id=node_exec_id,
- graph_exec_id=graph_exec_id,
- graph_id=graph_id,
- graph_version=graph_version,
- block_name=self.name,
- editable=True,
- )
-
- if decision is None:
- # We're awaiting review - pause execution
- return True, input_data
-
- if not decision.should_proceed:
- # Review was rejected, raise an error to stop execution
- raise BlockExecutionError(
- message=f"Block execution rejected by reviewer: {decision.message}",
- block_name=self.name,
- block_id=self.id,
- )
-
- # Review was approved - use the potentially modified data
- # ReviewResult.data must be a dict for block inputs
- reviewed_data = decision.review_result.data
- if not isinstance(reviewed_data, dict):
- raise BlockExecutionError(
- message=f"Review data must be a dict for block input, got {type(reviewed_data).__name__}",
- block_name=self.name,
- block_id=self.id,
- )
- return False, reviewed_data
-
- async def _execute(self, input_data: BlockInput, **kwargs) -> BlockOutput:
- # Check for review requirement only if running within a graph execution context
- # Direct block execution (e.g., from chat) skips the review process
- has_graph_context = all(
- key in kwargs
- for key in (
- "node_exec_id",
- "graph_exec_id",
- "graph_id",
- "execution_context",
- )
- )
- if has_graph_context:
- should_pause, input_data = await self.is_block_exec_need_review(
- input_data, **kwargs
- )
- if should_pause:
- return
-
- # Validate the input data (original or reviewer-modified) once
- if error := self.input_schema.validate_data(input_data):
- raise BlockInputError(
- message=f"Unable to execute block with invalid input data: {error}",
- block_name=self.name,
- block_id=self.id,
- )
-
- # Use the validated input data
- async for output_name, output_data in self.run(
- self.input_schema(**{k: v for k, v in input_data.items() if v is not None}),
- **kwargs,
- ):
- if output_name == "error":
- raise BlockExecutionError(
- message=output_data, block_name=self.name, block_id=self.id
- )
- if self.block_type == BlockType.STANDARD and (
- error := self.output_schema.validate_field(output_name, output_data)
- ):
- raise BlockOutputError(
- message=f"Block produced an invalid output data: {error}",
- block_name=self.name,
- block_id=self.id,
- )
- yield output_name, output_data
-
- def is_triggered_by_event_type(
- self, trigger_config: dict[str, Any], event_type: str
- ) -> bool:
- if not self.webhook_config:
- raise TypeError("This method can't be used on non-trigger blocks")
- if not self.webhook_config.event_filter_input:
- return True
- event_filter = trigger_config.get(self.webhook_config.event_filter_input)
- if not event_filter:
- raise ValueError("Event filter is not configured on trigger")
- return event_type in [
- self.webhook_config.event_format.format(event=k)
- for k in event_filter
- if event_filter[k] is True
- ]
-
-
-# Type alias for any block with standard input/output schemas
-AnyBlockSchema: TypeAlias = Block[BlockSchemaInput, BlockSchemaOutput]
-
-
-# ======================= Block Helper Functions ======================= #
-
-
-def get_blocks() -> dict[str, Type[Block]]:
- from backend.blocks import load_all_blocks
-
- return load_all_blocks()
-
-
-def is_block_auth_configured(
- block_cls: type[AnyBlockSchema],
-) -> bool:
- """
- Check if a block has a valid authentication method configured at runtime.
-
- For example if a block is an OAuth-only block and there env vars are not set,
- do not show it in the UI.
-
- """
- from backend.sdk.registry import AutoRegistry
-
- # Create an instance to access input_schema
- try:
- block = block_cls()
- except Exception as e:
- # If we can't create a block instance, assume it's not OAuth-only
- logger.error(f"Error creating block instance for {block_cls.__name__}: {e}")
- return True
- logger.debug(
- f"Checking if block {block_cls.__name__} has a valid provider configured"
- )
-
- # Get all credential inputs from input schema
- credential_inputs = block.input_schema.get_credentials_fields_info()
- required_inputs = block.input_schema.get_required_fields()
- if not credential_inputs:
- logger.debug(
- f"Block {block_cls.__name__} has no credential inputs - Treating as valid"
- )
- return True
-
- # Check credential inputs
- if len(required_inputs.intersection(credential_inputs.keys())) == 0:
- logger.debug(
- f"Block {block_cls.__name__} has only optional credential inputs"
- " - will work without credentials configured"
- )
-
- # Check if the credential inputs for this block are correctly configured
- for field_name, field_info in credential_inputs.items():
- provider_names = field_info.provider
- if not provider_names:
- logger.warning(
- f"Block {block_cls.__name__} "
- f"has credential input '{field_name}' with no provider options"
- " - Disabling"
- )
- return False
-
- # If a field has multiple possible providers, each one needs to be usable to
- # prevent breaking the UX
- for _provider_name in provider_names:
- provider_name = _provider_name.value
- if provider_name in ProviderName.__members__.values():
- logger.debug(
- f"Block {block_cls.__name__} credential input '{field_name}' "
- f"provider '{provider_name}' is part of the legacy provider system"
- " - Treating as valid"
- )
- break
-
- provider = AutoRegistry.get_provider(provider_name)
- if not provider:
- logger.warning(
- f"Block {block_cls.__name__} credential input '{field_name}' "
- f"refers to unknown provider '{provider_name}' - Disabling"
- )
- return False
-
- # Check the provider's supported auth types
- if field_info.supported_types != provider.supported_auth_types:
- logger.warning(
- f"Block {block_cls.__name__} credential input '{field_name}' "
- f"has mismatched supported auth types (field <> Provider): "
- f"{field_info.supported_types} != {provider.supported_auth_types}"
- )
-
- if not (supported_auth_types := provider.supported_auth_types):
- # No auth methods are been configured for this provider
- logger.warning(
- f"Block {block_cls.__name__} credential input '{field_name}' "
- f"provider '{provider_name}' "
- "has no authentication methods configured - Disabling"
- )
- return False
-
- # Check if provider supports OAuth
- if "oauth2" in supported_auth_types:
- # Check if OAuth environment variables are set
- if (oauth_config := provider.oauth_config) and bool(
- os.getenv(oauth_config.client_id_env_var)
- and os.getenv(oauth_config.client_secret_env_var)
- ):
- logger.debug(
- f"Block {block_cls.__name__} credential input '{field_name}' "
- f"provider '{provider_name}' is configured for OAuth"
- )
- else:
- logger.error(
- f"Block {block_cls.__name__} credential input '{field_name}' "
- f"provider '{provider_name}' "
- "is missing OAuth client ID or secret - Disabling"
- )
- return False
-
- logger.debug(
- f"Block {block_cls.__name__} credential input '{field_name}' is valid; "
- f"supported credential types: {', '.join(field_info.supported_types)}"
- )
-
- return True
-
async def initialize_blocks() -> None:
from backend.sdk.cost_integration import sync_all_provider_costs
@@ -932,36 +68,3 @@ async def initialize_blocks() -> None:
f"Failed to sync {len(failed_blocks)} block(s) to database: "
f"{', '.join(failed_blocks)}. These blocks are still available in memory."
)
-
-
-# Note on the return type annotation: https://github.com/microsoft/pyright/issues/10281
-def get_block(block_id: str) -> AnyBlockSchema | None:
- cls = get_blocks().get(block_id)
- return cls() if cls else None
-
-
-@cached(ttl_seconds=3600)
-def get_webhook_block_ids() -> Sequence[str]:
- return [
- id
- for id, B in get_blocks().items()
- if B().block_type in (BlockType.WEBHOOK, BlockType.WEBHOOK_MANUAL)
- ]
-
-
-@cached(ttl_seconds=3600)
-def get_io_block_ids() -> Sequence[str]:
- return [
- id
- for id, B in get_blocks().items()
- if B().block_type in (BlockType.INPUT, BlockType.OUTPUT)
- ]
-
-
-@cached(ttl_seconds=3600)
-def get_human_in_the_loop_block_ids() -> Sequence[str]:
- return [
- id
- for id, B in get_blocks().items()
- if B().block_type == BlockType.HUMAN_IN_THE_LOOP
- ]
diff --git a/autogpt_platform/backend/backend/data/block_cost_config.py b/autogpt_platform/backend/backend/data/block_cost_config.py
index ec35afa401..c7fb12deb6 100644
--- a/autogpt_platform/backend/backend/data/block_cost_config.py
+++ b/autogpt_platform/backend/backend/data/block_cost_config.py
@@ -1,5 +1,6 @@
from typing import Type
+from backend.blocks._base import Block, BlockCost, BlockCostType
from backend.blocks.ai_image_customizer import AIImageCustomizerBlock, GeminiImageModel
from backend.blocks.ai_image_generator_block import AIImageGeneratorBlock, ImageGenModel
from backend.blocks.ai_music_generator import AIMusicGeneratorBlock
@@ -37,7 +38,6 @@ from backend.blocks.smart_decision_maker import SmartDecisionMakerBlock
from backend.blocks.talking_head import CreateTalkingAvatarVideoBlock
from backend.blocks.text_to_speech_block import UnrealTextToSpeechBlock
from backend.blocks.video.narration import VideoNarrationBlock
-from backend.data.block import Block, BlockCost, BlockCostType
from backend.integrations.credentials_store import (
aiml_api_credentials,
anthropic_credentials,
diff --git a/autogpt_platform/backend/backend/data/credit.py b/autogpt_platform/backend/backend/data/credit.py
index f3c5365446..04f91d8d61 100644
--- a/autogpt_platform/backend/backend/data/credit.py
+++ b/autogpt_platform/backend/backend/data/credit.py
@@ -38,7 +38,7 @@ from backend.util.retry import func_retry
from backend.util.settings import Settings
if TYPE_CHECKING:
- from backend.data.block import Block, BlockCost
+ from backend.blocks._base import Block, BlockCost
settings = Settings()
stripe.api_key = settings.secrets.stripe_api_key
diff --git a/autogpt_platform/backend/backend/data/credit_test.py b/autogpt_platform/backend/backend/data/credit_test.py
index 2b10c62882..cb5973c74f 100644
--- a/autogpt_platform/backend/backend/data/credit_test.py
+++ b/autogpt_platform/backend/backend/data/credit_test.py
@@ -4,8 +4,8 @@ import pytest
from prisma.enums import CreditTransactionType
from prisma.models import CreditTransaction, UserBalance
+from backend.blocks import get_block
from backend.blocks.llm import AITextGeneratorBlock
-from backend.data.block import get_block
from backend.data.credit import BetaUserCredit, UsageTransactionMetadata
from backend.data.execution import ExecutionContext, NodeExecutionEntry
from backend.data.user import DEFAULT_USER_ID
diff --git a/autogpt_platform/backend/backend/data/execution.py b/autogpt_platform/backend/backend/data/execution.py
index def3d14fda..800edb00e3 100644
--- a/autogpt_platform/backend/backend/data/execution.py
+++ b/autogpt_platform/backend/backend/data/execution.py
@@ -39,6 +39,8 @@ from prisma.types import (
from pydantic import BaseModel, ConfigDict, JsonValue, ValidationError
from pydantic.fields import Field
+from backend.blocks import get_block, get_io_block_ids, get_webhook_block_ids
+from backend.blocks._base import BlockInput, BlockType, CompletedBlockOutput
from backend.util import type as type_utils
from backend.util.exceptions import DatabaseError
from backend.util.json import SafeJson
@@ -47,14 +49,6 @@ from backend.util.retry import func_retry
from backend.util.settings import Config
from backend.util.truncate import truncate
-from .block import (
- BlockInput,
- BlockType,
- CompletedBlockOutput,
- get_block,
- get_io_block_ids,
- get_webhook_block_ids,
-)
from .db import BaseDbModel, query_raw_with_schema
from .event_bus import AsyncRedisEventBus, RedisEventBus
from .includes import (
diff --git a/autogpt_platform/backend/backend/data/graph.py b/autogpt_platform/backend/backend/data/graph.py
index 0dc3eea887..1de7335773 100644
--- a/autogpt_platform/backend/backend/data/graph.py
+++ b/autogpt_platform/backend/backend/data/graph.py
@@ -23,6 +23,14 @@ from prisma.types import (
from pydantic import BaseModel, BeforeValidator, Field
from pydantic.fields import computed_field
+from backend.blocks import get_block, get_blocks
+from backend.blocks._base import (
+ AnyBlockSchema,
+ Block,
+ BlockInput,
+ BlockType,
+ EmptySchema,
+)
from backend.blocks.agent import AgentExecutorBlock
from backend.blocks.io import AgentInputBlock, AgentOutputBlock
from backend.blocks.llm import LlmModel
@@ -40,15 +48,6 @@ from backend.util.exceptions import GraphNotAccessibleError, GraphNotInLibraryEr
from backend.util.json import SafeJson
from backend.util.models import Pagination
-from .block import (
- AnyBlockSchema,
- Block,
- BlockInput,
- BlockType,
- EmptySchema,
- get_block,
- get_blocks,
-)
from .db import BaseDbModel, query_raw_with_schema, transaction
from .includes import AGENT_GRAPH_INCLUDE, AGENT_NODE_INCLUDE
@@ -743,6 +742,11 @@ class GraphModel(Graph, GraphMeta):
# For invalid blocks, we still raise immediately as this is a structural issue
raise ValueError(f"Invalid block {node.block_id} for node #{node.id}")
+ if block.disabled:
+ raise ValueError(
+ f"Block {node.block_id} is disabled and cannot be used in graphs"
+ )
+
node_input_mask = (
nodes_input_masks.get(node.id, {}) if nodes_input_masks else {}
)
diff --git a/autogpt_platform/backend/backend/data/graph_test.py b/autogpt_platform/backend/backend/data/graph_test.py
index 8b7eadb887..2272049446 100644
--- a/autogpt_platform/backend/backend/data/graph_test.py
+++ b/autogpt_platform/backend/backend/data/graph_test.py
@@ -9,9 +9,9 @@ from pytest_snapshot.plugin import Snapshot
import backend.api.features.store.model as store
from backend.api.model import CreateGraph
+from backend.blocks._base import BlockSchema, BlockSchemaInput
from backend.blocks.basic import StoreValueBlock
from backend.blocks.io import AgentInputBlock, AgentOutputBlock
-from backend.data.block import BlockSchema, BlockSchemaInput
from backend.data.graph import Graph, Link, Node
from backend.data.model import SchemaField
from backend.data.user import DEFAULT_USER_ID
diff --git a/autogpt_platform/backend/backend/executor/activity_status_generator.py b/autogpt_platform/backend/backend/executor/activity_status_generator.py
index d7ec7beb49..dd5d7ddfc4 100644
--- a/autogpt_platform/backend/backend/executor/activity_status_generator.py
+++ b/autogpt_platform/backend/backend/executor/activity_status_generator.py
@@ -13,8 +13,8 @@ except ImportError:
from pydantic import SecretStr
+from backend.blocks import get_block
from backend.blocks.llm import AIStructuredResponseGeneratorBlock, LlmModel
-from backend.data.block import get_block
from backend.data.execution import ExecutionStatus, NodeExecutionResult
from backend.data.model import APIKeyCredentials, GraphExecutionStats
from backend.util.feature_flag import Flag, is_feature_enabled
diff --git a/autogpt_platform/backend/backend/executor/manager.py b/autogpt_platform/backend/backend/executor/manager.py
index 440d794509..bb6cd8faed 100644
--- a/autogpt_platform/backend/backend/executor/manager.py
+++ b/autogpt_platform/backend/backend/executor/manager.py
@@ -16,16 +16,11 @@ from pika.spec import Basic, BasicProperties
from prometheus_client import Gauge, start_http_server
from redis.asyncio.lock import Lock as AsyncRedisLock
+from backend.blocks import get_block
+from backend.blocks._base import BlockInput, BlockOutput, BlockOutputEntry, BlockSchema
from backend.blocks.agent import AgentExecutorBlock
from backend.blocks.io import AgentOutputBlock
from backend.data import redis_client as redis
-from backend.data.block import (
- BlockInput,
- BlockOutput,
- BlockOutputEntry,
- BlockSchema,
- get_block,
-)
from backend.data.credit import UsageTransactionMetadata
from backend.data.dynamic_fields import parse_execution_output
from backend.data.execution import (
@@ -216,6 +211,9 @@ async def execute_node(
block_name=node_block.name,
)
+ if node_block.disabled:
+ raise ValueError(f"Block {node_block.id} is disabled and cannot be executed")
+
# Sanity check: validate the execution input.
input_data, error = validate_exec(node, data.inputs, resolve_input=False)
if input_data is None:
diff --git a/autogpt_platform/backend/backend/executor/scheduler.py b/autogpt_platform/backend/backend/executor/scheduler.py
index cbdc441718..b0609827e6 100644
--- a/autogpt_platform/backend/backend/executor/scheduler.py
+++ b/autogpt_platform/backend/backend/executor/scheduler.py
@@ -24,7 +24,7 @@ from dotenv import load_dotenv
from pydantic import BaseModel, Field, ValidationError
from sqlalchemy import MetaData, create_engine
-from backend.data.block import BlockInput
+from backend.blocks._base import BlockInput
from backend.data.execution import GraphExecutionWithNodes
from backend.data.model import CredentialsMetaInput
from backend.executor import utils as execution_utils
diff --git a/autogpt_platform/backend/backend/executor/utils.py b/autogpt_platform/backend/backend/executor/utils.py
index d26424aefc..68def74706 100644
--- a/autogpt_platform/backend/backend/executor/utils.py
+++ b/autogpt_platform/backend/backend/executor/utils.py
@@ -8,19 +8,19 @@ from typing import Mapping, Optional, cast
from pydantic import BaseModel, JsonValue, ValidationError
-from backend.data import execution as execution_db
-from backend.data import graph as graph_db
-from backend.data import human_review as human_review_db
-from backend.data import onboarding as onboarding_db
-from backend.data import user as user_db
-from backend.data.block import (
+from backend.blocks import get_block
+from backend.blocks._base import (
Block,
BlockCostType,
BlockInput,
BlockOutputEntry,
BlockType,
- get_block,
)
+from backend.data import execution as execution_db
+from backend.data import graph as graph_db
+from backend.data import human_review as human_review_db
+from backend.data import onboarding as onboarding_db
+from backend.data import user as user_db
from backend.data.block_cost_config import BLOCK_COSTS
from backend.data.db import prisma
diff --git a/autogpt_platform/backend/backend/integrations/webhooks/graph_lifecycle_hooks.py b/autogpt_platform/backend/backend/integrations/webhooks/graph_lifecycle_hooks.py
index 5fb9198c4d..c656d67eac 100644
--- a/autogpt_platform/backend/backend/integrations/webhooks/graph_lifecycle_hooks.py
+++ b/autogpt_platform/backend/backend/integrations/webhooks/graph_lifecycle_hooks.py
@@ -2,7 +2,7 @@ import asyncio
import logging
from typing import TYPE_CHECKING, Optional, cast, overload
-from backend.data.block import BlockSchema
+from backend.blocks._base import BlockSchema
from backend.data.graph import set_node_webhook
from backend.integrations.creds_manager import IntegrationCredentialsManager
diff --git a/autogpt_platform/backend/backend/integrations/webhooks/utils.py b/autogpt_platform/backend/backend/integrations/webhooks/utils.py
index 79316c4c0e..ffe910a2eb 100644
--- a/autogpt_platform/backend/backend/integrations/webhooks/utils.py
+++ b/autogpt_platform/backend/backend/integrations/webhooks/utils.py
@@ -9,7 +9,7 @@ from backend.util.settings import Config
from . import get_webhook_manager, supports_webhooks
if TYPE_CHECKING:
- from backend.data.block import AnyBlockSchema
+ from backend.blocks._base import AnyBlockSchema
from backend.data.integrations import Webhook
from backend.data.model import Credentials
from backend.integrations.providers import ProviderName
@@ -42,7 +42,7 @@ async def setup_webhook_for_block(
Webhook: The created or found webhook object, if successful.
str: A feedback message, if any required inputs are missing.
"""
- from backend.data.block import BlockWebhookConfig
+ from backend.blocks._base import BlockWebhookConfig
if not (trigger_base_config := trigger_block.webhook_config):
raise ValueError(f"Block #{trigger_block.id} does not have a webhook_config")
diff --git a/autogpt_platform/backend/backend/monitoring/block_error_monitor.py b/autogpt_platform/backend/backend/monitoring/block_error_monitor.py
index ffd2ffc888..07565a37e8 100644
--- a/autogpt_platform/backend/backend/monitoring/block_error_monitor.py
+++ b/autogpt_platform/backend/backend/monitoring/block_error_monitor.py
@@ -6,7 +6,7 @@ from datetime import datetime, timedelta, timezone
from pydantic import BaseModel
-from backend.data.block import get_block
+from backend.blocks import get_block
from backend.data.execution import ExecutionStatus, NodeExecutionResult
from backend.util.clients import (
get_database_manager_client,
diff --git a/autogpt_platform/backend/backend/sdk/__init__.py b/autogpt_platform/backend/backend/sdk/__init__.py
index b3a23dc735..dc7260d08f 100644
--- a/autogpt_platform/backend/backend/sdk/__init__.py
+++ b/autogpt_platform/backend/backend/sdk/__init__.py
@@ -17,7 +17,7 @@ This module provides:
from pydantic import BaseModel, Field, SecretStr
# === CORE BLOCK SYSTEM ===
-from backend.data.block import (
+from backend.blocks._base import (
Block,
BlockCategory,
BlockManualWebhookConfig,
@@ -65,7 +65,7 @@ except ImportError:
# Cost System
try:
- from backend.data.block import BlockCost, BlockCostType
+ from backend.blocks._base import BlockCost, BlockCostType
except ImportError:
from backend.data.block_cost_config import BlockCost, BlockCostType
diff --git a/autogpt_platform/backend/backend/sdk/builder.py b/autogpt_platform/backend/backend/sdk/builder.py
index 09949b256f..28dd4023f0 100644
--- a/autogpt_platform/backend/backend/sdk/builder.py
+++ b/autogpt_platform/backend/backend/sdk/builder.py
@@ -8,7 +8,7 @@ from typing import Callable, List, Optional, Type
from pydantic import SecretStr
-from backend.data.block import BlockCost, BlockCostType
+from backend.blocks._base import BlockCost, BlockCostType
from backend.data.model import (
APIKeyCredentials,
Credentials,
diff --git a/autogpt_platform/backend/backend/sdk/cost_integration.py b/autogpt_platform/backend/backend/sdk/cost_integration.py
index 04c027ffa3..2eec1aece0 100644
--- a/autogpt_platform/backend/backend/sdk/cost_integration.py
+++ b/autogpt_platform/backend/backend/sdk/cost_integration.py
@@ -8,7 +8,7 @@ BLOCK_COSTS configuration used by the execution system.
import logging
from typing import List, Type
-from backend.data.block import Block, BlockCost
+from backend.blocks._base import Block, BlockCost
from backend.data.block_cost_config import BLOCK_COSTS
from backend.sdk.registry import AutoRegistry
diff --git a/autogpt_platform/backend/backend/sdk/provider.py b/autogpt_platform/backend/backend/sdk/provider.py
index 98afbf05d5..2933121703 100644
--- a/autogpt_platform/backend/backend/sdk/provider.py
+++ b/autogpt_platform/backend/backend/sdk/provider.py
@@ -7,7 +7,7 @@ from typing import Any, Callable, List, Optional, Set, Type
from pydantic import BaseModel, SecretStr
-from backend.data.block import BlockCost
+from backend.blocks._base import BlockCost
from backend.data.model import (
APIKeyCredentials,
Credentials,
diff --git a/autogpt_platform/backend/backend/util/test.py b/autogpt_platform/backend/backend/util/test.py
index e9336dd679..26b255e019 100644
--- a/autogpt_platform/backend/backend/util/test.py
+++ b/autogpt_platform/backend/backend/util/test.py
@@ -8,8 +8,9 @@ from typing import Sequence, cast
from autogpt_libs.auth import get_user_id
from backend.api.rest_api import AgentServer
+from backend.blocks._base import Block, BlockSchema
from backend.data import db
-from backend.data.block import Block, BlockSchema, initialize_blocks
+from backend.data.block import initialize_blocks
from backend.data.db_manager import DatabaseManager
from backend.data.execution import (
ExecutionContext,
diff --git a/autogpt_platform/backend/poetry.lock b/autogpt_platform/backend/poetry.lock
index 09d4d4225d..53b5030da6 100644
--- a/autogpt_platform/backend/poetry.lock
+++ b/autogpt_platform/backend/poetry.lock
@@ -46,14 +46,14 @@ pycares = ">=4.9.0,<5"
[[package]]
name = "aiofiles"
-version = "24.1.0"
+version = "25.1.0"
description = "File support for asyncio."
optional = false
-python-versions = ">=3.8"
+python-versions = ">=3.9"
groups = ["main"]
files = [
- {file = "aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5"},
- {file = "aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c"},
+ {file = "aiofiles-25.1.0-py3-none-any.whl", hash = "sha256:abe311e527c862958650f9438e859c1fa7568a141b22abcd015e120e86a85695"},
+ {file = "aiofiles-25.1.0.tar.gz", hash = "sha256:a8d728f0a29de45dc521f18f07297428d56992a742f0cd2701ba86e44d23d5b2"},
]
[[package]]
@@ -8440,4 +8440,4 @@ cffi = ["cffi (>=1.17,<2.0) ; platform_python_implementation != \"PyPy\" and pyt
[metadata]
lock-version = "2.1"
python-versions = ">=3.10,<3.14"
-content-hash = "fc135114e01de39c8adf70f6132045e7d44a19473c1279aee0978de65aad1655"
+content-hash = "c06e96ad49388ba7a46786e9ea55ea2c1a57408e15613237b4bee40a592a12af"
diff --git a/autogpt_platform/backend/pyproject.toml b/autogpt_platform/backend/pyproject.toml
index 267b054e10..db62fd7f89 100644
--- a/autogpt_platform/backend/pyproject.toml
+++ b/autogpt_platform/backend/pyproject.toml
@@ -76,7 +76,7 @@ yt-dlp = "2025.12.08"
zerobouncesdk = "^1.1.2"
# NOTE: please insert new dependencies in their alphabetical location
pytest-snapshot = "^0.9.0"
-aiofiles = "^24.1.0"
+aiofiles = "^25.1.0"
tiktoken = "^0.12.0"
aioclamd = "^1.0.0"
setuptools = "^80.9.0"
diff --git a/autogpt_platform/backend/test/load_store_agents.py b/autogpt_platform/backend/test/load_store_agents.py
index b9d8e0478e..dfc5beb453 100644
--- a/autogpt_platform/backend/test/load_store_agents.py
+++ b/autogpt_platform/backend/test/load_store_agents.py
@@ -49,7 +49,7 @@ async def initialize_blocks(db: Prisma) -> set[str]:
Returns a set of block IDs that exist in the database.
"""
- from backend.data.block import get_blocks
+ from backend.blocks import get_blocks
print(" Initializing agent blocks...")
blocks = get_blocks()
diff --git a/autogpt_platform/backend/test/sdk/test_sdk_registry.py b/autogpt_platform/backend/test/sdk/test_sdk_registry.py
index f82abd57cb..ab384ca955 100644
--- a/autogpt_platform/backend/test/sdk/test_sdk_registry.py
+++ b/autogpt_platform/backend/test/sdk/test_sdk_registry.py
@@ -377,7 +377,7 @@ class TestProviderBuilder:
def test_provider_builder_with_base_cost(self):
"""Test building a provider with base costs."""
- from backend.data.block import BlockCostType
+ from backend.blocks._base import BlockCostType
provider = (
ProviderBuilder("cost_test")
@@ -418,7 +418,7 @@ class TestProviderBuilder:
def test_provider_builder_complete_example(self):
"""Test building a complete provider with all features."""
- from backend.data.block import BlockCostType
+ from backend.blocks._base import BlockCostType
class TestOAuth(BaseOAuthHandler):
PROVIDER_NAME = ProviderName.GITHUB
diff --git a/autogpt_platform/frontend/src/app/(platform)/copilot/CopilotPage.tsx b/autogpt_platform/frontend/src/app/(platform)/copilot/CopilotPage.tsx
index cd1033f535..0d403b1a79 100644
--- a/autogpt_platform/frontend/src/app/(platform)/copilot/CopilotPage.tsx
+++ b/autogpt_platform/frontend/src/app/(platform)/copilot/CopilotPage.tsx
@@ -1,11 +1,11 @@
"use client";
-import { LoadingSpinner } from "@/components/atoms/LoadingSpinner/LoadingSpinner";
import { SidebarProvider } from "@/components/ui/sidebar";
import { ChatContainer } from "./components/ChatContainer/ChatContainer";
import { ChatSidebar } from "./components/ChatSidebar/ChatSidebar";
import { MobileDrawer } from "./components/MobileDrawer/MobileDrawer";
import { MobileHeader } from "./components/MobileHeader/MobileHeader";
+import { ScaleLoader } from "./components/ScaleLoader/ScaleLoader";
import { useCopilotPage } from "./useCopilotPage";
export function CopilotPage() {
@@ -34,7 +34,11 @@ export function CopilotPage() {
} = useCopilotPage();
if (isUserLoading || !isLoggedIn) {
- return
diff --git a/autogpt_platform/frontend/src/app/(platform)/copilot/components/ScaleLoader/ScaleLoader.module.css b/autogpt_platform/frontend/src/app/(platform)/copilot/components/ScaleLoader/ScaleLoader.module.css new file mode 100644 index 0000000000..3e7e71d66b --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/copilot/components/ScaleLoader/ScaleLoader.module.css @@ -0,0 +1,35 @@ +.loader { + width: 48px; + height: 48px; + display: inline-block; + position: relative; +} + +.loader::after, +.loader::before { + content: ""; + box-sizing: border-box; + width: 100%; + height: 100%; + border-radius: 50%; + background: currentColor; + position: absolute; + left: 0; + top: 0; + animation: animloader 2s linear infinite; +} + +.loader::after { + animation-delay: 1s; +} + +@keyframes animloader { + 0% { + transform: scale(0); + opacity: 1; + } + 100% { + transform: scale(1); + opacity: 0; + } +} diff --git a/autogpt_platform/frontend/src/app/(platform)/copilot/components/ScaleLoader/ScaleLoader.tsx b/autogpt_platform/frontend/src/app/(platform)/copilot/components/ScaleLoader/ScaleLoader.tsx new file mode 100644 index 0000000000..a395b21319 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/copilot/components/ScaleLoader/ScaleLoader.tsx @@ -0,0 +1,16 @@ +import { cn } from "@/lib/utils"; +import styles from "./ScaleLoader.module.css"; + +interface Props { + size?: number; + className?: string; +} + +export function ScaleLoader({ size = 48, className }: Props) { + return ( +
+ ); +} diff --git a/autogpt_platform/frontend/src/app/(platform)/copilot/components/ToolAccordion/AccordionContent.tsx b/autogpt_platform/frontend/src/app/(platform)/copilot/components/ToolAccordion/AccordionContent.tsx index 987941eee1..dab8f49257 100644 --- a/autogpt_platform/frontend/src/app/(platform)/copilot/components/ToolAccordion/AccordionContent.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/copilot/components/ToolAccordion/AccordionContent.tsx @@ -30,7 +30,7 @@ export function ContentCard({ return (BlockWebhookConfig definition