mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-02-17 18:21:46 -05:00
* feat(doc): Update node creation docs * small fixes * fix formatting * remove mention of registering a block * Update docs/content/server/new_blocks.md Co-authored-by: Nicholas Tindle <nicholas.tindle@agpt.co> --------- Co-authored-by: Nicholas Tindle <nicholas.tindle@agpt.co>
150 lines
7.3 KiB
Markdown
150 lines
7.3 KiB
Markdown
# Contributing to AutoGPT Agent Server: Creating and Testing Blocks
|
|
|
|
This guide will walk you through the process of creating and testing a new block for the AutoGPT Agent Server, using the WikipediaSummaryBlock as an example.
|
|
|
|
## Understanding Blocks and Testing
|
|
|
|
Blocks are reusable components that can be connected to form a graph representing an agent's behavior. Each block has inputs, outputs, and a specific function. Proper testing is crucial to ensure blocks work correctly and consistently.
|
|
|
|
## Creating and Testing a New Block
|
|
|
|
Follow these steps to create and test a new block:
|
|
|
|
1. **Create a new Python file** in the `autogpt_server/blocks` directory. Name it descriptively and use snake_case. For example: `get_wikipedia_summary.py`.
|
|
|
|
2. **Import necessary modules and create a class that inherits from `Block`**. Make sure to include all necessary imports for your block.
|
|
|
|
Every block should contain the following:
|
|
|
|
```python
|
|
from autogpt_server.data.block import Block, BlockSchema, BlockOutput
|
|
```
|
|
|
|
Example for the Wikipedia summary block:
|
|
|
|
```python
|
|
from autogpt_server.data.block import Block, BlockSchema, BlockOutput
|
|
from autogpt_server.utils.get_request import GetRequest
|
|
import requests
|
|
|
|
class WikipediaSummaryBlock(Block, GetRequest):
|
|
# Block implementation will go here
|
|
```
|
|
|
|
3. **Define the input and output schemas** using `BlockSchema`. These schemas specify the data structure that the block expects to receive (input) and produce (output).
|
|
|
|
- The input schema defines the structure of the data the block will process. Each field in the schema represents a required piece of input data.
|
|
- The output schema defines the structure of the data the block will return after processing. Each field in the schema represents a piece of output data.
|
|
|
|
Example:
|
|
|
|
```python
|
|
class Input(BlockSchema):
|
|
topic: str # The topic to get the Wikipedia summary for
|
|
|
|
class Output(BlockSchema):
|
|
summary: str # The summary of the topic from Wikipedia
|
|
error: str # Any error message if the request fails
|
|
```
|
|
|
|
4. **Implement the `__init__` method, including test data and mocks:**
|
|
|
|
```python
|
|
def __init__(self):
|
|
super().__init__(
|
|
# Unique ID for the block
|
|
# you can generate this with this python one liner
|
|
# print(__import__('uuid').uuid4())
|
|
id="h5e7f8g9-1b2c-3d4e-5f6g-7h8i9j0k1l2m",
|
|
input_schema=WikipediaSummaryBlock.Input, # Assign input schema
|
|
output_schema=WikipediaSummaryBlock.Output, # Assign output schema
|
|
|
|
# Provide sample input, output and test mock for testing the block
|
|
|
|
test_input={"topic": "Artificial Intelligence"},
|
|
test_output=("summary", "summary content"),
|
|
test_mock={"get_request": lambda url, json: {"extract": "summary content"}},
|
|
)
|
|
```
|
|
|
|
- `id`: A unique identifier for the block.
|
|
|
|
- `input_schema` and `output_schema`: Define the structure of the input and output data.
|
|
|
|
Let's break down the testing components:
|
|
|
|
- `test_input`: This is a sample input that will be used to test the block. It should be a valid input according to your Input schema.
|
|
|
|
- `test_output`: This is the expected output when running the block with the `test_input`. It should match your Output schema. For non-deterministic outputs or when you only want to assert the type, you can use Python types instead of specific values. In this example, `("summary", str)` asserts that the output key is "summary" and its value is a string.
|
|
|
|
- `test_mock`: This is crucial for blocks that make network calls. It provides a mock function that replaces the actual network call during testing.
|
|
|
|
In this case, we're mocking the `get_request` method to always return a dictionary with an 'extract' key, simulating a successful API response. This allows us to test the block's logic without making actual network requests, which could be slow, unreliable, or rate-limited.
|
|
|
|
5. **Implement the `run` method with error handling:**, this should contain the main logic of the block:
|
|
|
|
```python
|
|
def run(self, input_data: Input) -> BlockOutput:
|
|
try:
|
|
topic = input_data.topic
|
|
url = f"https://en.wikipedia.org/api/rest_v1/page/summary/{topic}"
|
|
|
|
response = self.get_request(url, json=True)
|
|
yield "summary", response['extract']
|
|
|
|
except requests.exceptions.HTTPError as http_err:
|
|
yield "error", f"HTTP error occurred: {http_err}"
|
|
except requests.RequestException as e:
|
|
yield "error", f"Request to Wikipedia failed: {e}"
|
|
except KeyError as e:
|
|
yield "error", f"Error parsing Wikipedia response: {e}"
|
|
```
|
|
|
|
- **Try block**: Contains the main logic to fetch and process the Wikipedia summary.
|
|
- **API request**: Send a GET request to the Wikipedia API.
|
|
- **Error handling**: Handle various exceptions that might occur during the API request and data processing.
|
|
- **Yield**: Use `yield` to output the results.
|
|
|
|
## Key Points to Remember
|
|
|
|
- **Unique ID**: Give your block a unique ID in the **init** method.
|
|
- **Input and Output Schemas**: Define clear input and output schemas.
|
|
- **Error Handling**: Implement error handling in the `run` method.
|
|
- **Output Results**: Use `yield` to output results in the `run` method.
|
|
- **Testing**: Provide test input and output in the **init** method for automatic testing.
|
|
|
|
## Understanding the Testing Process
|
|
|
|
The testing of blocks is handled by `test_block.py`, which does the following:
|
|
|
|
1. It calls the block with the provided `test_input`.
|
|
2. If a `test_mock` is provided, it temporarily replaces the specified methods with the mock functions.
|
|
3. It then asserts that the output matches the `test_output`.
|
|
|
|
For the WikipediaSummaryBlock:
|
|
|
|
- The test will call the block with the topic "Artificial Intelligence".
|
|
- Instead of making a real API call, it will use the mock function, which returns `{"extract": "summary content"}`.
|
|
- It will then check if the output key is "summary" and its value is a string.
|
|
|
|
This approach allows us to test the block's logic comprehensively without relying on external services, while also accommodating non-deterministic outputs.
|
|
|
|
## Tips for Effective Block Testing
|
|
|
|
1. **Provide realistic test_input**: Ensure your test input covers typical use cases.
|
|
|
|
2. **Define appropriate test_output**:
|
|
- For deterministic outputs, use specific expected values.
|
|
- For non-deterministic outputs or when only the type matters, use Python types (e.g., `str`, `int`, `dict`).
|
|
- You can mix specific values and types, e.g., `("key1", str), ("key2", 42)`.
|
|
|
|
3. **Use test_mock for network calls**: This prevents tests from failing due to network issues or API changes.
|
|
|
|
4. **Consider omitting test_mock for blocks without external dependencies**: If your block doesn't make network calls or use external resources, you might not need a mock.
|
|
|
|
5. **Consider edge cases**: Include tests for potential error conditions in your `run` method.
|
|
|
|
6. **Update tests when changing block behavior**: If you modify your block, ensure the tests are updated accordingly.
|
|
|
|
By following these steps, you can create new blocks that extend the functionality of the AutoGPT Agent Server.
|