Skip to content

Commit cfc975d

Browse files
kczeAbhi1992002
andauthored
feat(backend): Type for API block data response (#10763)
Moving to auto-generated frontend types caused returned blocks data to no longer have proper typing. ### Changes 🏗️ - Add `BlockInfo` model and `get_info` function that returns it to the `Block` class, including costs - Move `BlockCost` and `BlockCostType` to `block.py` to prevent circular imports ### Checklist 📋 #### For code changes: - [x] I have clearly listed my changes in the PR description - [x] I have made a test plan - [x] I have tested my changes according to the test plan: - [x] Endpoints using the new type work correctly Co-authored-by: Abhimanyu Yadav <[email protected]>
1 parent 46e0f6c commit cfc975d

File tree

13 files changed

+169
-71
lines changed

13 files changed

+169
-71
lines changed

autogpt_platform/backend/backend/data/block.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,45 @@ def dict(self) -> dict[str, str]:
9191
return {"category": self.name, "description": self.value}
9292

9393

94+
class BlockCostType(str, Enum):
95+
RUN = "run" # cost X credits per run
96+
BYTE = "byte" # cost X credits per byte
97+
SECOND = "second" # cost X credits per second
98+
99+
100+
class BlockCost(BaseModel):
101+
cost_amount: int
102+
cost_filter: BlockInput
103+
cost_type: BlockCostType
104+
105+
def __init__(
106+
self,
107+
cost_amount: int,
108+
cost_type: BlockCostType = BlockCostType.RUN,
109+
cost_filter: Optional[BlockInput] = None,
110+
**data: Any,
111+
) -> None:
112+
super().__init__(
113+
cost_amount=cost_amount,
114+
cost_filter=cost_filter or {},
115+
cost_type=cost_type,
116+
**data,
117+
)
118+
119+
120+
class BlockInfo(BaseModel):
121+
id: str
122+
name: str
123+
inputSchema: dict[str, Any]
124+
outputSchema: dict[str, Any]
125+
costs: list[BlockCost]
126+
description: str
127+
categories: list[dict[str, str]]
128+
contributors: list[dict[str, Any]]
129+
staticOutput: bool
130+
uiType: str
131+
132+
94133
class BlockSchema(BaseModel):
95134
cached_jsonschema: ClassVar[dict[str, Any]]
96135

@@ -454,6 +493,24 @@ def to_dict(self):
454493
"uiType": self.block_type.value,
455494
}
456495

496+
def get_info(self) -> BlockInfo:
497+
from backend.data.credit import get_block_cost
498+
499+
return BlockInfo(
500+
id=self.id,
501+
name=self.name,
502+
inputSchema=self.input_schema.jsonschema(),
503+
outputSchema=self.output_schema.jsonschema(),
504+
costs=get_block_cost(self),
505+
description=self.description,
506+
categories=[category.dict() for category in self.categories],
507+
contributors=[
508+
contributor.model_dump() for contributor in self.contributors
509+
],
510+
staticOutput=self.static_output,
511+
uiType=self.block_type.value,
512+
)
513+
457514
async def execute(self, input_data: BlockInput, **kwargs) -> BlockOutput:
458515
if error := self.input_schema.validate_data(input_data):
459516
raise ValueError(

autogpt_platform/backend/backend/data/block_cost_config.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@
2929
from backend.blocks.smart_decision_maker import SmartDecisionMakerBlock
3030
from backend.blocks.talking_head import CreateTalkingAvatarVideoBlock
3131
from backend.blocks.text_to_speech_block import UnrealTextToSpeechBlock
32-
from backend.data.block import Block
33-
from backend.data.cost import BlockCost, BlockCostType
32+
from backend.data.block import Block, BlockCost, BlockCostType
3433
from backend.integrations.credentials_store import (
3534
aiml_api_credentials,
3635
anthropic_credentials,

autogpt_platform/backend/backend/data/cost.py

Lines changed: 0 additions & 32 deletions
This file was deleted.

autogpt_platform/backend/backend/data/credit.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from abc import ABC, abstractmethod
33
from collections import defaultdict
44
from datetime import datetime, timezone
5-
from typing import Any, cast
5+
from typing import TYPE_CHECKING, Any, cast
66

77
import stripe
88
from prisma import Json
@@ -23,7 +23,6 @@
2323

2424
from backend.data import db
2525
from backend.data.block_cost_config import BLOCK_COSTS
26-
from backend.data.cost import BlockCost
2726
from backend.data.model import (
2827
AutoTopUpConfig,
2928
RefundRequest,
@@ -41,6 +40,9 @@
4140
from backend.util.retry import func_retry
4241
from backend.util.settings import Settings
4342

43+
if TYPE_CHECKING:
44+
from backend.data.block import Block, BlockCost
45+
4446
settings = Settings()
4547
stripe.api_key = settings.secrets.stripe_api_key
4648
logger = logging.getLogger(__name__)
@@ -997,10 +999,14 @@ def get_user_credit_model() -> UserCreditBase:
997999
return UserCredit()
9981000

9991001

1000-
def get_block_costs() -> dict[str, list[BlockCost]]:
1002+
def get_block_costs() -> dict[str, list["BlockCost"]]:
10011003
return {block().id: costs for block, costs in BLOCK_COSTS.items()}
10021004

10031005

1006+
def get_block_cost(block: "Block") -> list["BlockCost"]:
1007+
return BLOCK_COSTS.get(block.__class__, [])
1008+
1009+
10041010
async def get_stripe_customer_id(user_id: str) -> str:
10051011
user = await get_user_by_id(user_id)
10061012

autogpt_platform/backend/backend/executor/utils.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,15 @@
1010

1111
from backend.data import execution as execution_db
1212
from backend.data import graph as graph_db
13-
from backend.data.block import Block, BlockInput, BlockOutputEntry, BlockType, get_block
13+
from backend.data.block import (
14+
Block,
15+
BlockCostType,
16+
BlockInput,
17+
BlockOutputEntry,
18+
BlockType,
19+
get_block,
20+
)
1421
from backend.data.block_cost_config import BLOCK_COSTS
15-
from backend.data.cost import BlockCostType
1622
from backend.data.db import prisma
1723
from backend.data.execution import (
1824
ExecutionStatus,

autogpt_platform/backend/backend/sdk/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363

6464
# Cost System
6565
try:
66-
from backend.data.cost import BlockCost, BlockCostType
66+
from backend.data.block import BlockCost, BlockCostType
6767
except ImportError:
6868
from backend.data.block_cost_config import BlockCost, BlockCostType
6969

autogpt_platform/backend/backend/sdk/builder.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from pydantic import SecretStr
1010

11-
from backend.data.cost import BlockCost, BlockCostType
11+
from backend.data.block import BlockCost, BlockCostType
1212
from backend.data.model import (
1313
APIKeyCredentials,
1414
Credentials,

autogpt_platform/backend/backend/sdk/cost_integration.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@
88
import logging
99
from typing import List, Type
1010

11-
from backend.data.block import Block
11+
from backend.data.block import Block, BlockCost
1212
from backend.data.block_cost_config import BLOCK_COSTS
13-
from backend.data.cost import BlockCost
1413
from backend.sdk.registry import AutoRegistry
1514

1615
logger = logging.getLogger(__name__)

autogpt_platform/backend/backend/sdk/provider.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from pydantic import BaseModel, SecretStr
99

10-
from backend.data.cost import BlockCost
10+
from backend.data.block import BlockCost
1111
from backend.data.model import (
1212
APIKeyCredentials,
1313
Credentials,

autogpt_platform/backend/backend/server/v2/builder/db.py

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,10 @@
77
import backend.data.block
88
from backend.blocks import load_all_blocks
99
from backend.blocks.llm import LlmModel
10-
from backend.data.block import Block, BlockCategory, BlockSchema
11-
from backend.data.credit import get_block_costs
10+
from backend.data.block import Block, BlockCategory, BlockInfo, BlockSchema
1211
from backend.integrations.providers import ProviderName
1312
from backend.server.v2.builder.model import (
1413
BlockCategoryResponse,
15-
BlockData,
1614
BlockResponse,
1715
BlockType,
1816
CountResponse,
@@ -25,7 +23,7 @@
2523
logger = logging.getLogger(__name__)
2624
llm_models = [name.name.lower().replace("_", " ") for name in LlmModel]
2725
_static_counts_cache: dict | None = None
28-
_suggested_blocks: list[BlockData] | None = None
26+
_suggested_blocks: list[BlockInfo] | None = None
2927

3028

3129
def get_block_categories(category_blocks: int = 3) -> list[BlockCategoryResponse]:
@@ -53,7 +51,7 @@ def get_block_categories(category_blocks: int = 3) -> list[BlockCategoryResponse
5351

5452
# Append if the category has less than the specified number of blocks
5553
if len(categories[category].blocks) < category_blocks:
56-
categories[category].blocks.append(block.to_dict())
54+
categories[category].blocks.append(block.get_info())
5755

5856
# Sort categories by name
5957
return sorted(categories.values(), key=lambda x: x.name)
@@ -109,10 +107,8 @@ def get_blocks(
109107
take -= 1
110108
blocks.append(block)
111109

112-
costs = get_block_costs()
113-
114110
return BlockResponse(
115-
blocks=[{**b.to_dict(), "costs": costs.get(b.id, [])} for b in blocks],
111+
blocks=[b.get_info() for b in blocks],
116112
pagination=Pagination(
117113
total_items=total,
118114
total_pages=(total + page_size - 1) // page_size,
@@ -174,11 +170,9 @@ def search_blocks(
174170
take -= 1
175171
blocks.append(block)
176172

177-
costs = get_block_costs()
178-
179173
return SearchBlocksResponse(
180174
blocks=BlockResponse(
181-
blocks=[{**b.to_dict(), "costs": costs.get(b.id, [])} for b in blocks],
175+
blocks=[b.get_info() for b in blocks],
182176
pagination=Pagination(
183177
total_items=total,
184178
total_pages=(total + page_size - 1) // page_size,
@@ -323,7 +317,7 @@ def _get_all_providers() -> dict[ProviderName, Provider]:
323317
return providers
324318

325319

326-
async def get_suggested_blocks(count: int = 5) -> list[BlockData]:
320+
async def get_suggested_blocks(count: int = 5) -> list[BlockInfo]:
327321
global _suggested_blocks
328322

329323
if _suggested_blocks is not None and len(_suggested_blocks) >= count:
@@ -351,7 +345,7 @@ async def get_suggested_blocks(count: int = 5) -> list[BlockData]:
351345

352346
# Get the top blocks based on execution count
353347
# But ignore Input and Output blocks
354-
blocks: list[tuple[BlockData, int]] = []
348+
blocks: list[tuple[BlockInfo, int]] = []
355349

356350
for block_type in load_all_blocks().values():
357351
block: Block[BlockSchema, BlockSchema] = block_type()
@@ -366,7 +360,7 @@ async def get_suggested_blocks(count: int = 5) -> list[BlockData]:
366360
(row["execution_count"] for row in results if row["block_id"] == block.id),
367361
0,
368362
)
369-
blocks.append((block.to_dict(), execution_count))
363+
blocks.append((block.get_info(), execution_count))
370364
# Sort blocks by execution count
371365
blocks.sort(key=lambda x: x[1], reverse=True)
372366

0 commit comments

Comments
 (0)