Files
AutoGPT/docs/content/server/new_blocks.md
Bently 2dc673614f feat(doc): Update node creation docs (#7462)
* 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>
2024-07-18 20:01:40 -05:00

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.