Repository: Significant-Gravitas/AutoGPT
Pull request #9657: feat(block): Add agent input block subtypes
Author: login: majdyz
Labels: name: size/xl
name: platform/frontend
description: AutoGPT Platform - Front end
name: platform/backend
description: AutoGPT Platform - Back end
name: platform/blocks
name: Review effort 3/5
Created: 2025-03-19T14:27:08Z | Merged: 2025-03-24T03:17:58Z

### Changes 🏗️

Added these types of input blocks:
* TextShort
* TextLong
* Number
* Date
* Time
* FileUpload
* Dropdown
* Toggle

### 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] Test in respective block codes.




Diff:
diff --git a/autogpt_platform/backend/backend/blocks/basic.py b/autogpt_platform/backend/backend/blocks/basic.py
index f52a53a4eb18..30ceeaef6a57 100644
--- a/autogpt_platform/backend/backend/blocks/basic.py
+++ b/autogpt_platform/backend/backend/blocks/basic.py
@@ -6,11 +6,8 @@
 from backend.util import json
 from backend.util.file import MediaFile, store_media_file
 from backend.util.mock import MockObject
-from backend.util.text import TextFormatter
 from backend.util.type import convert
 
-formatter = TextFormatter()
-
 
 class FileStoreBlock(Block):
     class Input(BlockSchema):
@@ -91,29 +88,6 @@ def run(self, input_data: Input, **kwargs) -> BlockOutput:
         yield "output", input_data.data or input_data.input
 
 
-class PrintToConsoleBlock(Block):
-    class Input(BlockSchema):
-        text: str = SchemaField(description="The text to print to the console.")
-
-    class Output(BlockSchema):
-        status: str = SchemaField(description="The status of the print operation.")
-
-    def __init__(self):
-        super().__init__(
-            id="f3b1c1b2-4c4f-4f0d-8d2f-4c4f0d8d2f4c",
-            description="Print the given text to the console, this is used for a debugging purpose.",
-            categories={BlockCategory.BASIC},
-            input_schema=PrintToConsoleBlock.Input,
-            output_schema=PrintToConsoleBlock.Output,
-            test_input={"text": "Hello, World!"},
-            test_output=("status", "printed"),
-        )
-
-    def run(self, input_data: Input, **kwargs) -> BlockOutput:
-        print(">>>>> Print: ", input_data.text)
-        yield "status", "printed"
-
-
 class FindInDictionaryBlock(Block):
     class Input(BlockSchema):
         input: Any = SchemaField(description="Dictionary to lookup from")
@@ -174,188 +148,6 @@ def run(self, input_data: Input, **kwargs) -> BlockOutput:
             yield "missing", input_data.input
 
 
-class AgentInputBlock(Block):
-    """
-    This block is used to provide input to the graph.
-
-    It takes in a value, name, description, default values list and bool to limit selection to default values.
-
-    It Outputs the value passed as input.
-    """
-
-    class Input(BlockSchema):
-        name: str = SchemaField(description="The name of the input.")
-        value: Any = SchemaField(
-            description="The value to be passed as input.",
-            default=None,
-        )
-        title: str | None = SchemaField(
-            description="The title of the input.", default=None, advanced=True
-        )
-        description: str | None = SchemaField(
-            description="The description of the input.",
-            default=None,
-            advanced=True,
-        )
-        placeholder_values: List[Any] = SchemaField(
-            description="The placeholder values to be passed as input.",
-            default=[],
-            advanced=True,
-        )
-        limit_to_placeholder_values: bool = SchemaField(
-            description="Whether to limit the selection to placeholder values.",
-            default=False,
-            advanced=True,
-        )
-        advanced: bool = SchemaField(
-            description="Whether to show the input in the advanced section, if the field is not required.",
-            default=False,
-            advanced=True,
-        )
-        secret: bool = SchemaField(
-            description="Whether the input should be treated as a secret.",
-            default=False,
-            advanced=True,
-        )
-
-    class Output(BlockSchema):
-        result: Any = SchemaField(description="The value passed as input.")
-
-    def __init__(self):
-        super().__init__(
-            id="c0a8e994-ebf1-4a9c-a4d8-89d09c86741b",
-            description="This block is used to provide input to the graph.",
-            input_schema=AgentInputBlock.Input,
-            output_schema=AgentInputBlock.Output,
-            test_input=[
-                {
-                    "value": "Hello, World!",
-                    "name": "input_1",
-                    "description": "This is a test input.",
-                    "placeholder_values": [],
-                    "limit_to_placeholder_values": False,
-                },
-                {
-                    "value": "Hello, World!",
-                    "name": "input_2",
-                    "description": "This is a test input.",
-                    "placeholder_values": ["Hello, World!"],
-                    "limit_to_placeholder_values": True,
-                },
-            ],
-            test_output=[
-                ("result", "Hello, World!"),
-                ("result", "Hello, World!"),
-            ],
-            categories={BlockCategory.INPUT, BlockCategory.BASIC},
-            block_type=BlockType.INPUT,
-            static_output=True,
-        )
-
-    def run(self, input_data: Input, **kwargs) -> BlockOutput:
-        yield "result", input_data.value
-
-
-class AgentOutputBlock(Block):
-    """
-    Records the output of the graph for users to see.
-
-    Behavior:
-        If `format` is provided and the `value` is of a type that can be formatted,
-        the block attempts to format the recorded_value using the `format`.
-        If formatting fails or no `format` is provided, the raw `value` is output.
-    """
-
-    class Input(BlockSchema):
-        value: Any = SchemaField(
-            description="The value to be recorded as output.",
-            default=None,
-            advanced=False,
-        )
-        name: str = SchemaField(description="The name of the output.")
-        title: str | None = SchemaField(
-            description="The title of the output.",
-            default=None,
-            advanced=True,
-        )
-        description: str | None = SchemaField(
-            description="The description of the output.",
-            default=None,
-            advanced=True,
-        )
-        format: str = SchemaField(
-            description="The format string to be used to format the recorded_value. Use Jinja2 syntax.",
-            default="",
-            advanced=True,
-        )
-        advanced: bool = SchemaField(
-            description="Whether to treat the output as advanced.",
-            default=False,
-            advanced=True,
-        )
-        secret: bool = SchemaField(
-            description="Whether the output should be treated as a secret.",
-            default=False,
-            advanced=True,
-        )
-
-    class Output(BlockSchema):
-        output: Any = SchemaField(description="The value recorded as output.")
-        name: Any = SchemaField(description="The name of the value recorded as output.")
-
-    def __init__(self):
-        super().__init__(
-            id="363ae599-353e-4804-937e-b2ee3cef3da4",
-            description="Stores the output of the graph for users to see.",
-            input_schema=AgentOutputBlock.Input,
-            output_schema=AgentOutputBlock.Output,
-            test_input=[
-                {
-                    "value": "Hello, World!",
-                    "name": "output_1",
-                    "description": "This is a test output.",
-                    "format": "{{ output_1 }}!!",
-                },
-                {
-                    "value": "42",
-                    "name": "output_2",
-                    "description": "This is another test output.",
-                    "format": "{{ output_2 }}",
-                },
-                {
-                    "value": MockObject(value="!!", key="key"),
-                    "name": "output_3",
-                    "description": "This is a test output with a mock object.",
-                    "format": "{{ output_3 }}",
-                },
-            ],
-            test_output=[
-                ("output", "Hello, World!!!"),
-                ("output", "42"),
-                ("output", MockObject(value="!!", key="key")),
-            ],
-            categories={BlockCategory.OUTPUT, BlockCategory.BASIC},
-            block_type=BlockType.OUTPUT,
-            static_output=True,
-        )
-
-    def run(self, input_data: Input, **kwargs) -> BlockOutput:
-        """
-        Attempts to format the recorded_value using the fmt_string if provided.
-        If formatting fails or no fmt_string is given, returns the original recorded_value.
-        """
-        if input_data.format:
-            try:
-                yield "output", formatter.format_string(
-                    input_data.format, {input_data.name: input_data.value}
-                )
-            except Exception as e:
-                yield "output", f"Error: {e}, {input_data.value}"
-        else:
-            yield "output", input_data.value
-            yield "name", input_data.name
-
-
 class AddToDictionaryBlock(Block):
     class Input(BlockSchema):
         dictionary: dict[Any, Any] = SchemaField(
diff --git a/autogpt_platform/backend/backend/blocks/io.py b/autogpt_platform/backend/backend/blocks/io.py
new file mode 100644
index 000000000000..73219c8db184
--- /dev/null
+++ b/autogpt_platform/backend/backend/blocks/io.py
@@ -0,0 +1,511 @@
+from datetime import date, time
+from typing import Any
+
+from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema, BlockType
+from backend.data.model import SchemaField
+from backend.util.file import MediaFile, store_media_file
+from backend.util.mock import MockObject
+from backend.util.text import TextFormatter
+
+formatter = TextFormatter()
+
+
+class AgentInputBlock(Block):
+    """
+    This block is used to provide input to the graph.
+
+    It takes in a value, name, description, default values list and bool to limit selection to default values.
+
+    It Outputs the value passed as input.
+    """
+
+    class Input(BlockSchema):
+        name: str = SchemaField(description="The name of the input.")
+        value: Any = SchemaField(
+            description="The value to be passed as input.",
+            default=None,
+        )
+        title: str | None = SchemaField(
+            description="The title of the input.", default=None, advanced=True
+        )
+        description: str | None = SchemaField(
+            description="The description of the input.",
+            default=None,
+            advanced=True,
+        )
+        placeholder_values: list = SchemaField(
+            description="The placeholder values to be passed as input.",
+            default=[],
+            advanced=True,
+        )
+        limit_to_placeholder_values: bool = SchemaField(
+            description="Whether to limit the selection to placeholder values.",
+            default=False,
+            advanced=True,
+        )
+        advanced: bool = SchemaField(
+            description="Whether to show the input in the advanced section, if the field is not required.",
+            default=False,
+            advanced=True,
+        )
+        secret: bool = SchemaField(
+            description="Whether the input should be treated as a secret.",
+            default=False,
+            advanced=True,
+        )
+
+    class Output(BlockSchema):
+        result: Any = SchemaField(description="The value passed as input.")
+
+    def __init__(self, **kwargs):
+        super().__init__(
+            **{
+                "id": "c0a8e994-ebf1-4a9c-a4d8-89d09c86741b",
+                "description": "Base block for user inputs.",
+                "input_schema": AgentInputBlock.Input,
+                "output_schema": AgentInputBlock.Output,
+                "test_input": [
+                    {
+                        "value": "Hello, World!",
+                        "name": "input_1",
+                        "description": "Example test input.",
+                        "placeholder_values": [],
+                        "limit_to_placeholder_values": False,
+                    },
+                    {
+                        "value": "Hello, World!",
+                        "name": "input_2",
+                        "description": "Example test input with placeholders.",
+                        "placeholder_values": ["Hello, World!"],
+                        "limit_to_placeholder_values": True,
+                    },
+                ],
+                "test_output": [
+                    ("result", "Hello, World!"),
+                    ("result", "Hello, World!"),
+                ],
+                "categories": {BlockCategory.INPUT, BlockCategory.BASIC},
+                "block_type": BlockType.INPUT,
+                "static_output": True,
+                **kwargs,
+            }
+        )
+
+    def run(self, input_data: Input, *args, **kwargs) -> BlockOutput:
+        yield "result", input_data.value
+
+
+class AgentOutputBlock(Block):
+    """
+    Records the output of the graph for users to see.
+
+    Behavior:
+        If `format` is provided and the `value` is of a type that can be formatted,
+        the block attempts to format the recorded_value using the `format`.
+        If formatting fails or no `format` is provided, the raw `value` is output.
+    """
+
+    class Input(BlockSchema):
+        value: Any = SchemaField(
+            description="The value to be recorded as output.",
+            default=None,
+            advanced=False,
+        )
+        name: str = SchemaField(description="The name of the output.")
+        title: str | None = SchemaField(
+            description="The title of the output.",
+            default=None,
+            advanced=True,
+        )
+        description: str | None = SchemaField(
+            description="The description of the output.",
+            default=None,
+            advanced=True,
+        )
+        format: str = SchemaField(
+            description="The format string to be used to format the recorded_value. Use Jinja2 syntax.",
+            default="",
+            advanced=True,
+        )
+        advanced: bool = SchemaField(
+            description="Whether to treat the output as advanced.",
+            default=False,
+            advanced=True,
+        )
+        secret: bool = SchemaField(
+            description="Whether the output should be treated as a secret.",
+            default=False,
+            advanced=True,
+        )
+
+    class Output(BlockSchema):
+        output: Any = SchemaField(description="The value recorded as output.")
+        name: Any = SchemaField(description="The name of the value recorded as output.")
+
+    def __init__(self):
+        super().__init__(
+            id="363ae599-353e-4804-937e-b2ee3cef3da4",
+            description="Stores the output of the graph for users to see.",
+            input_schema=AgentOutputBlock.Input,
+            output_schema=AgentOutputBlock.Output,
+            test_input=[
+                {
+                    "value": "Hello, World!",
+                    "name": "output_1",
+                    "description": "This is a test output.",
+                    "format": "{{ output_1 }}!!",
+                },
+                {
+                    "value": "42",
+                    "name": "output_2",
+                    "description": "This is another test output.",
+                    "format": "{{ output_2 }}",
+                },
+                {
+                    "value": MockObject(value="!!", key="key"),
+                    "name": "output_3",
+                    "description": "This is a test output with a mock object.",
+                    "format": "{{ output_3 }}",
+                },
+            ],
+            test_output=[
+                ("output", "Hello, World!!!"),
+                ("output", "42"),
+                ("output", MockObject(value="!!", key="key")),
+            ],
+            categories={BlockCategory.OUTPUT, BlockCategory.BASIC},
+            block_type=BlockType.OUTPUT,
+            static_output=True,
+        )
+
+    def run(self, input_data: Input, *args, **kwargs) -> BlockOutput:
+        """
+        Attempts to format the recorded_value using the fmt_string if provided.
+        If formatting fails or no fmt_string is given, returns the original recorded_value.
+        """
+        if input_data.format:
+            try:
+                yield "output", formatter.format_string(
+                    input_data.format, {input_data.name: input_data.value}
+                )
+            except Exception as e:
+                yield "output", f"Error: {e}, {input_data.value}"
+        else:
+            yield "output", input_data.value
+            yield "name", input_data.name
+
+
+class AgentShortTextInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: str = SchemaField(
+            description="Short text input.",
+            default="Short text",
+            json_schema_extra={"format": "short-text"},
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: str = SchemaField(description="Short text result.")
+
+    def __init__(self):
+        super().__init__(
+            id="7fcd3bcb-8e1b-4e69-903d-32d3d4a92158",
+            description="Block for short text input (single-line).",
+            input_schema=AgentShortTextInputBlock.Input,
+            output_schema=AgentShortTextInputBlock.Output,
+            test_input=[
+                {
+                    "value": "Hello",
+                    "name": "short_text_1",
+                    "description": "Short text example 1",
+                    "placeholder_values": [],
+                    "limit_to_placeholder_values": False,
+                },
+                {
+                    "value": "Quick test",
+                    "name": "short_text_2",
+                    "description": "Short text example 2",
+                    "placeholder_values": ["Quick test", "Another option"],
+                    "limit_to_placeholder_values": True,
+                },
+            ],
+            test_output=[
+                ("result", "Hello"),
+                ("result", "Quick test"),
+            ],
+        )
+
+
+class AgentLongTextInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: str = SchemaField(
+            description="Long text input (potentially multi-line).",
+            default="Longer text can go here.",
+            json_schema_extra={"format": "long-text"},
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: str = SchemaField(description="Long text result.")
+
+    def __init__(self):
+        super().__init__(
+            id="90a56ffb-7024-4b2b-ab50-e26c5e5ab8ba",
+            description="Block for long text input (multi-line).",
+            input_schema=AgentLongTextInputBlock.Input,
+            output_schema=AgentLongTextInputBlock.Output,
+            test_input=[
+                {
+                    "value": "Lorem ipsum dolor sit amet...",
+                    "name": "long_text_1",
+                    "description": "Long text example 1",
+                    "placeholder_values": [],
+                    "limit_to_placeholder_values": False,
+                },
+                {
+                    "value": "Another multiline text input.",
+                    "name": "long_text_2",
+                    "description": "Long text example 2",
+                    "placeholder_values": ["Another multiline text input."],
+                    "limit_to_placeholder_values": True,
+                },
+            ],
+            test_output=[
+                ("result", "Lorem ipsum dolor sit amet..."),
+                ("result", "Another multiline text input."),
+            ],
+        )
+
+
+class AgentNumberInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: int = SchemaField(description="Number input.")
+
+    class Output(AgentInputBlock.Output):
+        result: int = SchemaField(description="Number result.")
+
+    def __init__(self):
+        super().__init__(
+            id="96dae2bb-97a2-41c2-bd2f-13a3b5a8ea98",
+            description="Block for number input.",
+            input_schema=AgentNumberInputBlock.Input,
+            output_schema=AgentNumberInputBlock.Output,
+            test_input=[
+                {
+                    "value": 42,
+                    "name": "number_input_1",
+                    "description": "Number example 1",
+                    "placeholder_values": [],
+                    "limit_to_placeholder_values": False,
+                },
+                {
+                    "value": 314,
+                    "name": "number_input_2",
+                    "description": "Number example 2",
+                    "placeholder_values": [314, 2718],
+                    "limit_to_placeholder_values": True,
+                },
+            ],
+            test_output=[
+                ("result", 42),
+                ("result", 314),
+            ],
+        )
+
+
+class AgentDateInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: date = SchemaField(
+            description="Date input (YYYY-MM-DD).",
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: date = SchemaField(description="Date result.")
+
+    def __init__(self):
+        super().__init__(
+            id="7e198b09-4994-47db-8b4d-952d98241817",
+            description="Block for date input.",
+            input_schema=AgentDateInputBlock.Input,
+            output_schema=AgentDateInputBlock.Output,
+            test_input=[
+                {
+                    # If your system can parse JSON date strings to date objects
+                    "value": str(date(2025, 3, 19)),
+                    "name": "date_input_1",
+                    "description": "Example date input 1",
+                },
+                {
+                    "value": str(date(2023, 12, 31)),
+                    "name": "date_input_2",
+                    "description": "Example date input 2",
+                },
+            ],
+            test_output=[
+                ("result", date(2025, 3, 19)),
+                ("result", date(2023, 12, 31)),
+            ],
+        )
+
+
+class AgentTimeInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: time = SchemaField(
+            description="Time input (HH:MM:SS).",
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: time = SchemaField(description="Time result.")
+
+    def __init__(self):
+        super().__init__(
+            id="2a1c757e-86cf-4c7e-aacf-060dc382e434",
+            description="Block for time input.",
+            input_schema=AgentTimeInputBlock.Input,
+            output_schema=AgentTimeInputBlock.Output,
+            test_input=[
+                {
+                    "value": str(time(9, 30, 0)),
+                    "name": "time_input_1",
+                    "description": "Time example 1",
+                },
+                {
+                    "value": str(time(23, 59, 59)),
+                    "name": "time_input_2",
+                    "description": "Time example 2",
+                },
+            ],
+            test_output=[
+                ("result", time(9, 30, 0)),
+                ("result", time(23, 59, 59)),
+            ],
+        )
+
+
+class AgentFileInputBlock(AgentInputBlock):
+    """
+    A simplified file-upload block. In real usage, you might have a custom
+    file type or handle binary data. Here, we'll store a string path as the example.
+    """
+
+    class Input(AgentInputBlock.Input):
+        value: MediaFile = SchemaField(
+            description="Path or reference to an uploaded file.",
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: str = SchemaField(description="File reference/path result.")
+
+    def __init__(self):
+        super().__init__(
+            id="95ead23f-8283-4654-aef3-10c053b74a31",
+            description="Block for file upload input (string path for example).",
+            input_schema=AgentFileInputBlock.Input,
+            output_schema=AgentFileInputBlock.Output,
+            test_input=[
+                {
+                    "value": "data:image/png;base64,MQ==",
+                    "name": "file_upload_1",
+                    "description": "Example file upload 1",
+                },
+            ],
+            test_output=[
+                ("result", str),
+            ],
+        )
+
+    def run(
+        self,
+        input_data: Input,
+        *,
+        graph_exec_id: str,
+        **kwargs,
+    ) -> BlockOutput:
+        file_path = store_media_file(
+            graph_exec_id=graph_exec_id,
+            file=input_data.value,
+            return_content=False,
+        )
+        yield "result", file_path
+
+
+class AgentDropdownInputBlock(AgentInputBlock):
+    """
+    A specialized text input block that relies on placeholder_values +
+    limit_to_placeholder_values to present a dropdown.
+    """
+
+    class Input(AgentInputBlock.Input):
+        value: str = SchemaField(
+            description="Text selected from a dropdown.", default="Option A"
+        )
+        placeholder_values: list = SchemaField(
+            description="Possible placeholder values for the input.",
+            default=["Option A", "Option B", "Option C"],
+            advanced=False,
+        )
+        limit_to_placeholder_values: bool = SchemaField(
+            description="Whether the selection is limited to placeholder values.",
+            default=True,
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: str = SchemaField(description="Selected dropdown value.")
+
+    def __init__(self):
+        super().__init__(
+            id="655d6fdf-a334-421c-b733-520549c07cd1",
+            description="Block for dropdown text selection.",
+            input_schema=AgentDropdownInputBlock.Input,
+            output_schema=AgentDropdownInputBlock.Output,
+            test_input=[
+                {
+                    "value": "Option A",
+                    "name": "dropdown_1",
+                    "placeholder_values": ["Option A", "Option B", "Option C"],
+                    "limit_to_placeholder_values": True,
+                    "description": "Dropdown example 1",
+                },
+                {
+                    "value": "Option C",
+                    "name": "dropdown_2",
+                    "placeholder_values": ["Option A", "Option B", "Option C"],
+                    "limit_to_placeholder_values": True,
+                    "description": "Dropdown example 2",
+                },
+            ],
+            test_output=[
+                ("result", "Option A"),
+                ("result", "Option C"),
+            ],
+        )
+
+
+class AgentToggleInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: bool = SchemaField(description="Boolean toggle input.", default=False)
+
+    class Output(AgentInputBlock.Output):
+        result: bool = SchemaField(description="Boolean toggle result.")
+
+    def __init__(self):
+        super().__init__(
+            id="cbf36ab5-df4a-43b6-8a7f-f7ed8652116e",
+            description="Block for boolean toggle input.",
+            input_schema=AgentToggleInputBlock.Input,
+            output_schema=AgentToggleInputBlock.Output,
+            test_input=[
+                {
+                    "value": True,
+                    "name": "toggle_1",
+                    "description": "Toggle example 1",
+                },
+                {
+                    "value": False,
+                    "name": "toggle_2",
+                    "description": "Toggle example 2",
+                },
+            ],
+            test_output=[
+                ("result", True),
+                ("result", False),
+            ],
+        )
diff --git a/autogpt_platform/backend/backend/blocks/screenshotone.py b/autogpt_platform/backend/backend/blocks/screenshotone.py
index 8cad4816e57a..6e113e76060d 100644
--- a/autogpt_platform/backend/backend/blocks/screenshotone.py
+++ b/autogpt_platform/backend/backend/blocks/screenshotone.py
@@ -142,7 +142,9 @@ def take_screenshot(
         return {
             "image": store_media_file(
                 graph_exec_id=graph_exec_id,
-                file=f"data:image/{format.value};base64,{b64encode(response.content).decode('utf-8')}",
+                file=MediaFile(
+                    f"data:image/{format.value};base64,{b64encode(response.content).decode('utf-8')}"
+                ),
                 return_content=True,
             )
         }
diff --git a/autogpt_platform/backend/backend/data/graph.py b/autogpt_platform/backend/backend/data/graph.py
index 8fa7a9cf07db..0dbaefa6630e 100644
--- a/autogpt_platform/backend/backend/data/graph.py
+++ b/autogpt_platform/backend/backend/data/graph.py
@@ -17,7 +17,7 @@
 from pydantic.fields import Field, computed_field
 
 from backend.blocks.agent import AgentExecutorBlock
-from backend.blocks.basic import AgentInputBlock, AgentOutputBlock
+from backend.blocks.io import AgentInputBlock, AgentOutputBlock
 from backend.util import type as type_utils
 
 from .block import Block, BlockInput, BlockSchema, BlockType, get_block, get_blocks
@@ -229,20 +229,28 @@ def from_db(_graph_exec: AgentGraphExecution):
                 # inputs from Agent Input Blocks
                 exec.input_data["name"]: exec.input_data.get("value")
                 for exec in node_executions
-                if exec.block_id == _INPUT_BLOCK_ID
+                if (
+                    (block := get_block(exec.block_id))
+                    and block.block_type == BlockType.INPUT
+                )
             },
             **{
                 # input from webhook-triggered block
                 "payload": exec.input_data["payload"]
                 for exec in node_executions
-                if (block := get_block(exec.block_id))
-                and block.block_type in [BlockType.WEBHOOK, BlockType.WEBHOOK_MANUAL]
+                if (
+                    (block := get_block(exec.block_id))
+                    and block.block_type
+                    in [BlockType.WEBHOOK, BlockType.WEBHOOK_MANUAL]
+                )
             },
         }
 
         outputs: dict[str, list] = defaultdict(list)
         for exec in node_executions:
-            if exec.block_id == _OUTPUT_BLOCK_ID:
+            if (
+                block := get_block(exec.block_id)
+            ) and block.block_type == BlockType.OUTPUT:
                 outputs[exec.input_data["name"]].append(
                     exec.input_data.get("value", None)
                 )
diff --git a/autogpt_platform/backend/backend/data/model.py b/autogpt_platform/backend/backend/data/model.py
index b1f3a74dc00b..373869e6cf60 100644
--- a/autogpt_platform/backend/backend/data/model.py
+++ b/autogpt_platform/backend/backend/data/model.py
@@ -144,6 +144,7 @@ def SchemaField(
     depends_on: list[str] | None = None,
     image_upload: Optional[bool] = None,
     image_output: Optional[bool] = None,
+    json_schema_extra: dict[str, Any] | None = None,
     **kwargs,
 ) -> T:
     if default is PydanticUndefined and default_factory is None:
@@ -151,7 +152,7 @@ def SchemaField(
     elif advanced is None:
         advanced = True
 
-    json_extra = {
+    json_schema_extra = {
         k: v
         for k, v in {
             "placeholder": placeholder,
@@ -161,6 +162,7 @@ def SchemaField(
             "depends_on": depends_on,
             "image_upload": image_upload,
             "image_output": image_output,
+            **(json_schema_extra or {}),
         }.items()
         if v is not None
     }
@@ -172,7 +174,7 @@ def SchemaField(
         title=title,
         description=description,
         exclude=exclude,
-        json_schema_extra=json_extra,
+        json_schema_extra=json_schema_extra,
         **kwargs,
     )  # type: ignore
 
diff --git a/autogpt_platform/backend/backend/exec.py b/autogpt_platform/backend/backend/exec.py
index 336f99485774..46101a742af9 100644
--- a/autogpt_platform/backend/backend/exec.py
+++ b/autogpt_platform/backend/backend/exec.py
@@ -1,5 +1,5 @@
 from backend.app import run_processes
-from backend.executor import DatabaseManager, ExecutionManager
+from backend.executor import ExecutionManager
 
 
 def main():
diff --git a/autogpt_platform/backend/backend/executor/manager.py b/autogpt_platform/backend/backend/executor/manager.py
index fdadfe04a5fb..c9b7e22601ec 100644
--- a/autogpt_platform/backend/backend/executor/manager.py
+++ b/autogpt_platform/backend/backend/executor/manager.py
@@ -12,7 +12,7 @@
 
 from redis.lock import Lock as RedisLock
 
-from backend.blocks.basic import AgentOutputBlock
+from backend.blocks.io import AgentOutputBlock
 from backend.data.model import GraphExecutionStats, NodeExecutionStats
 from backend.data.notifications import (
     AgentRunData,
diff --git a/autogpt_platform/backend/backend/usecases/sample.py b/autogpt_platform/backend/backend/usecases/sample.py
index e19357fb4a59..39b0724bb543 100644
--- a/autogpt_platform/backend/backend/usecases/sample.py
+++ b/autogpt_platform/backend/backend/usecases/sample.py
@@ -1,6 +1,7 @@
 from prisma.models import User
 
-from backend.blocks.basic import AgentInputBlock, PrintToConsoleBlock
+from backend.blocks.basic import StoreValueBlock
+from backend.blocks.io import AgentInputBlock
 from backend.blocks.text import FillTextTemplateBlock
 from backend.data import graph
 from backend.data.graph import create_graph
@@ -29,7 +30,7 @@ def create_test_graph() -> graph.Graph:
     """
     InputBlock
                \
-                 ---- FillTextTemplateBlock ---- PrintToConsoleBlock
+                 ---- FillTextTemplateBlock ---- StoreValueBlock
                /
     InputBlock
     """
@@ -52,7 +53,7 @@ def create_test_graph() -> graph.Graph:
                 "values_#_c": "!!!",
             },
         ),
-        graph.Node(block_id=PrintToConsoleBlock().id),
+        graph.Node(block_id=StoreValueBlock().id),
     ]
     links = [
         graph.Link(
@@ -71,7 +72,7 @@ def create_test_graph() -> graph.Graph:
             source_id=nodes[2].id,
             sink_id=nodes[3].id,
             source_name="output",
-            sink_name="text",
+            sink_name="input",
         ),
     ]
 
@@ -93,11 +94,7 @@ async def sample_agent():
             user_id=test_user.id,
             node_input=input_data,
         )
-        print(response)
-        result = await wait_execution(
-            test_user.id, test_graph.id, response.graph_exec_id, 10
-        )
-        print(result)
+        await wait_execution(test_user.id, test_graph.id, response.graph_exec_id, 10)
 
 
 if __name__ == "__main__":
diff --git a/autogpt_platform/backend/backend/util/file.py b/autogpt_platform/backend/backend/util/file.py
index 6b3d976abcf3..2fd47a03f661 100644
--- a/autogpt_platform/backend/backend/util/file.py
+++ b/autogpt_platform/backend/backend/util/file.py
@@ -29,15 +29,25 @@ def clean_exec_files(graph_exec_id: str, file: str = "") -> None:
         shutil.rmtree(exec_path)
 
 
-"""
-MediaFile is a string that represents a file. It can be one of the following:
-    - Data URI: base64 encoded media file. See https://developer.mozilla.org/en-US/docs/Web/URI/Schemes/data/
-    - URL: Media file hosted on the internet, it starts with http:// or https://.
-    - Local path (anything else): A temporary file path living within graph execution time.
-    
-Note: Replace this type alias into a proper class, when more information is needed.
-"""
-MediaFile = str
+class MediaFile(str):
+    """
+    MediaFile is a string that represents a file. It can be one of the following:
+        - Data URI: base64 encoded media file. See https://developer.mozilla.org/en-US/docs/Web/URI/Schemes/data/
+        - URL: Media file hosted on the internet, it starts with http:// or https://.
+        - Local path (anything else): A temporary file path living within graph execution time.
+
+    Note: Replace this type alias into a proper class, when more information is needed.
+    """
+
+    @classmethod
+    def __get_pydantic_core_schema__(cls, source_type, handler):
+        return handler(str)
+
+    @classmethod
+    def __get_pydantic_json_schema__(cls, core_schema, handler):
+        json_schema = handler(core_schema)
+        json_schema["format"] = "file"
+        return json_schema
 
 
 def store_media_file(
diff --git a/autogpt_platform/backend/test/data/test_graph.py b/autogpt_platform/backend/test/data/test_graph.py
index f2f133d1ad68..0b599944958f 100644
--- a/autogpt_platform/backend/test/data/test_graph.py
+++ b/autogpt_platform/backend/test/data/test_graph.py
@@ -6,7 +6,8 @@
 import pytest
 
 import backend.server.v2.store.model as store
-from backend.blocks.basic import AgentInputBlock, AgentOutputBlock, StoreValueBlock
+from backend.blocks.basic import StoreValueBlock
+from backend.blocks.io import AgentInputBlock, AgentOutputBlock
 from backend.data.block import BlockSchema
 from backend.data.graph import Graph, Link, Node
 from backend.data.model import SchemaField
diff --git a/autogpt_platform/backend/test/executor/test_manager.py b/autogpt_platform/backend/test/executor/test_manager.py
index 6094f4b66b31..90fa4d7d606b 100644
--- a/autogpt_platform/backend/test/executor/test_manager.py
+++ b/autogpt_platform/backend/test/executor/test_manager.py
@@ -7,7 +7,8 @@
 
 import backend.server.v2.library.model
 import backend.server.v2.store.model
-from backend.blocks.basic import AgentInputBlock, FindInDictionaryBlock, StoreValueBlock
+from backend.blocks.basic import FindInDictionaryBlock, StoreValueBlock
+from backend.blocks.io import AgentInputBlock
 from backend.blocks.maths import CalculatorBlock, Operation
 from backend.data import execution, graph
 from backend.server.model import CreateGraph
@@ -123,8 +124,8 @@ async def assert_sample_graph_executions(
     logger.info(f"Checking PrintToConsoleBlock execution: {exec}")
     assert exec.status == execution.ExecutionStatus.COMPLETED
     assert exec.graph_exec_id == graph_exec_id
-    assert exec.output_data == {"status": ["printed"]}
-    assert exec.input_data == {"text": "Hello, World!!!"}
+    assert exec.output_data == {"output": ["Hello, World!!!"]}
+    assert exec.input_data == {"input": "Hello, World!!!"}
     assert exec.node_id == test_graph.nodes[3].id
 
 
diff --git a/autogpt_platform/frontend/src/components/edit/control/BlocksControl.tsx b/autogpt_platform/frontend/src/components/edit/control/BlocksControl.tsx
index d7320646bb59..a664f55381a5 100644
--- a/autogpt_platform/frontend/src/components/edit/control/BlocksControl.tsx
+++ b/autogpt_platform/frontend/src/components/edit/control/BlocksControl.tsx
@@ -246,6 +246,7 @@ export const BlocksControl: React.FC<BlocksControlProps> = ({
                       <span
                         className="block truncate pb-1 text-sm font-semibold dark:text-white"
                         data-id={`block-name-${block.id}`}
+                        data-type={block.uiType}
                         data-testid={`block-name-${block.id}`}
                       >
                         <TextRenderer
diff --git a/autogpt_platform/frontend/src/components/node-input-components.tsx b/autogpt_platform/frontend/src/components/node-input-components.tsx
index ea414fafd49d..25a0f0dfd0fc 100644
--- a/autogpt_platform/frontend/src/components/node-input-components.tsx
+++ b/autogpt_platform/frontend/src/components/node-input-components.tsx
@@ -5,7 +5,7 @@ import {
   PopoverTrigger,
 } from "@/components/ui/popover";
 import { format } from "date-fns";
-import { CalendarIcon, Clock } from "lucide-react";
+import { CalendarIcon } from "lucide-react";
 import { Cross2Icon, Pencil2Icon, PlusIcon } from "@radix-ui/react-icons";
 import { beautifyString, cn } from "@/lib/utils";
 import {
@@ -196,6 +196,8 @@ const NodeDateTimeInput: FC<{
   handleInputChange: NodeObjectInputTreeProps["handleInputChange"];
   className?: string;
   displayName: string;
+  hideDate?: boolean;
+  hideTime?: boolean;
 }> = ({
   selfKey,
   schema,
@@ -204,6 +206,8 @@ const NodeDateTimeInput: FC<{
   handleInputChange,
   className,
   displayName,
+  hideDate = false,
+  hideTime = false,
 }) => {
   const date = value ? new Date(value) : new Date();
   const [timeInput, setTimeInput] = useState(
@@ -213,16 +217,28 @@ const NodeDateTimeInput: FC<{
   const handleDateSelect = (newDate: Date | undefined) => {
     if (!newDate) return;
 
-    const [hours, minutes] = timeInput.split(":").map(Number);
-    newDate.setHours(hours, minutes);
-    handleInputChange(selfKey, newDate.toISOString());
+    if (hideTime) {
+      // Only pass YYYY-MM-DD if time is hidden
+      handleInputChange(selfKey, format(newDate, "yyyy-MM-dd"));
+    } else {
+      // Otherwise pass full date/time, but still incorporate time
+      const [hours, minutes] = timeInput.split(":").map(Number);
+      newDate.setHours(hours, minutes);
+      handleInputChange(selfKey, newDate.toISOString());
+    }
   };
 
   const handleTimeChange = (e: React.ChangeEvent<HTMLInputElement>) => {
     const newTime = e.target.value;
     setTimeInput(newTime);
 
-    if (value) {
+    if (!value) return;
+
+    if (hideDate) {
+      // Only pass HH:mm if date is hidden
+      handleInputChange(selfKey, newTime);
+    } else {
+      // Otherwise pass full date/time
       const [hours, minutes] = newTime.split(":").map(Number);
       const newDate = new Date(value);
       newDate.setHours(hours, minutes);
@@ -232,34 +248,131 @@ const NodeDateTimeInput: FC<{
 
   return (
     <div className={cn("flex flex-col gap-2", className)}>
-      <Popover>
-        <PopoverTrigger asChild>
+      {hideDate || (
+        <Popover>
+          <PopoverTrigger asChild>
+            <Button
+              variant="outline"
+              className={cn(
+                "w-full justify-start text-left font-normal",
+                !value && "text-muted-foreground",
+              )}
+            >
+              <CalendarIcon className="mr-2 h-4 w-4" />
+              {value ? format(date, "PPP") : <span>Pick a date</span>}
+            </Button>
+          </PopoverTrigger>
+          <PopoverContent className="w-auto p-0" align="start">
+            <Calendar
+              mode="single"
+              selected={date}
+              onSelect={handleDateSelect}
+              initialFocus
+            />
+          </PopoverContent>
+        </Popover>
+      )}
+      {hideTime || (
+        <LocalValuedInput
+          type="time"
+          value={timeInput}
+          onChange={handleTimeChange}
+          className="w-full"
+        />
+      )}
+      {error && <span className="error-message">{error}</span>}
+    </div>
+  );
+};
+
+const NodeFileInput: FC<{
+  selfKey: string;
+  schema: BlockIOStringSubSchema;
+  value?: string;
+  error?: string;
+  handleInputChange: NodeObjectInputTreeProps["handleInputChange"];
+  className?: string;
+  displayName: string;
+}> = ({
+  selfKey,
+  schema,
+  value = "",
+  error,
+  handleInputChange,
+  className,
+  displayName,
+}) => {
+  const handleFileChange = useCallback(
+    (event: React.ChangeEvent<HTMLInputElement>) => {
+      const file = event.target.files?.[0];
+      if (!file) return;
+
+      const reader = new FileReader();
+      reader.onload = (e) => {
+        const base64String = e.target?.result as string;
+        handleInputChange(selfKey, base64String);
+      };
+      reader.readAsDataURL(file);
+    },
+    [selfKey, handleInputChange],
+  );
+
+  const getFileLabel = useCallback((value: string) => {
+    if (value.startsWith("data:")) {
+      const matches = value.match(/^data:([^;]+);/);
+      if (matches?.[1]) {
+        const mimeParts = matches[1].split("/");
+        if (mimeParts.length > 1) {
+          return `${mimeParts[1].toUpperCase()} file`;
+        }
+        return `${matches[1]} file`;
+      }
+    } else {
+      const pathParts = value.split(".");
+      if (pathParts.length > 1) {
+        const ext = pathParts.pop();
+        if (ext) return `${ext.toUpperCase()} file`;
+      }
+    }
+    return "File";
+  }, []);
+
+  return (
+    <div className={cn("flex flex-col gap-2", className)}>
+      <div className="nodrag flex flex-col gap-2">
+        <div className="flex items-center gap-2">
           <Button
             variant="outline"
-            className={cn(
-              "w-full justify-start text-left font-normal",
-              !value && "text-muted-foreground",
-            )}
+            onClick={() =>
+              document.getElementById(`${selfKey}-upload`)?.click()
+            }
+            className="w-full"
           >
-            <CalendarIcon className="mr-2 h-4 w-4" />
-            {value ? format(date, "PPP") : <span>Pick a date</span>}
+            {value ? `Change ${displayName}` : `Upload ${displayName}`}
           </Button>
-        </PopoverTrigger>
-        <PopoverContent className="w-auto p-0" align="start">
-          <Calendar
-            mode="single"
-            selected={date}
-            onSelect={handleDateSelect}
-            initialFocus
-          />
-        </PopoverContent>
-      </Popover>
-      <LocalValuedInput
-        type="time"
-        value={timeInput}
-        onChange={handleTimeChange}
-        className="w-full"
-      />
+          {value && (
+            <Button
+              variant="ghost"
+              className="text-red-500 hover:text-red-700"
+              onClick={() => handleInputChange(selfKey, "")}
+            >
+              <Cross2Icon className="h-4 w-4" />
+            </Button>
+          )}
+        </div>
+        <input
+          id={`${selfKey}-upload`}
+          type="file"
+          accept="*/*"
+          onChange={handleFileChange}
+          className="hidden"
+        />
+        {value && (
+          <div className="break-all rounded-md border border-gray-300 p-2 dark:border-gray-600">
+            <small>{getFileLabel(value)}</small>
+          </div>
+        )}
+      </div>
       {error && <span className="error-message">{error}</span>}
     </div>
   );
@@ -410,10 +523,14 @@ export const NodeGenericInputField: FC<{
 
       if (
         "format" in propSchema.anyOf[0] &&
-        propSchema.anyOf[0].format === "date-time"
+        ["date-time", "date", "time"].includes(
+          propSchema.anyOf[0].format as string,
+        )
       ) {
         return (
           <NodeDateTimeInput
+            hideDate={propSchema.anyOf[0].format === "time"}
+            hideTime={propSchema.anyOf[0].format === "date"}
             selfKey={propKey}
             schema={propSchema.anyOf[0]}
             value={currentValue}
@@ -425,6 +542,23 @@ export const NodeGenericInputField: FC<{
         );
       }
 
+      if (
+        "format" in propSchema.anyOf[0] &&
+        propSchema.anyOf[0].format === "file"
+      ) {
+        return (
+          <NodeFileInput
+            selfKey={propKey}
+            schema={propSchema.anyOf[0] as BlockIOStringSubSchema}
+            value={currentValue}
+            error={errors[propKey]}
+            handleInputChange={handleInputChange}
+            className={className}
+            displayName={displayName}
+          />
+        );
+      }
+
       return (
         <NodeStringInput
           selfKey={propKey}
@@ -597,9 +731,14 @@ export const NodeGenericInputField: FC<{
           />
         );
       }
-      if ("format" in propSchema && propSchema.format === "date-time") {
+      if (
+        "format" in propSchema &&
+        ["date-time", "date", "time"].includes(propSchema.format as string)
+      ) {
         return (
           <NodeDateTimeInput
+            hideDate={propSchema.format === "time"}
+            hideTime={propSchema.format === "date"}
             selfKey={propKey}
             schema={propSchema}
             value={currentValue}
@@ -610,6 +749,19 @@ export const NodeGenericInputField: FC<{
           />
         );
       }
+      if ("format" in propSchema && propSchema.format === "file") {
+        return (
+          <NodeFileInput
+            selfKey={propKey}
+            schema={propSchema}
+            value={currentValue}
+            error={errors[propKey]}
+            handleInputChange={handleInputChange}
+            className={className}
+            displayName={displayName}
+          />
+        );
+      }
       return (
         <NodeStringInput
           selfKey={propKey}
@@ -1390,15 +1542,10 @@ const NodeBooleanInput: FC<{
   value ||= schema.default ?? false;
   return (
     <div className={className}>
-      <div className="nodrag flex items-center">
-        <Switch
-          defaultChecked={value}
-          onCheckedChange={(v) => handleInputChange(selfKey, v)}
-        />
-        {displayName && (
-          <span className="ml-3 dark:text-gray-300">{displayName}</span>
-        )}
-      </div>
+      <Switch
+        defaultChecked={value}
+        onCheckedChange={(v) => handleInputChange(selfKey, v)}
+      />
       {error && <span className="error-message">{error}</span>}
     </div>
   );
diff --git a/autogpt_platform/frontend/src/lib/autogpt-server-api/types.ts b/autogpt_platform/frontend/src/lib/autogpt-server-api/types.ts
index 26561c889ec1..19ffa27f89d1 100644
--- a/autogpt_platform/frontend/src/lib/autogpt-server-api/types.ts
+++ b/autogpt_platform/frontend/src/lib/autogpt-server-api/types.ts
@@ -500,11 +500,11 @@ export enum BlockUIType {
   WEBHOOK = "Webhook",
   WEBHOOK_MANUAL = "Webhook (manual)",
   AGENT = "Agent",
+  AI = "AI",
 }
 
 export enum SpecialBlockID {
   AGENT = "e189baac-8c20-45a1-94a7-55177ea42565",
-  INPUT = "c0a8e994-ebf1-4a9c-a4d8-89d09c86741b",
   OUTPUT = "363ae599-353e-4804-937e-b2ee3cef3da4",
 }
 
diff --git a/autogpt_platform/frontend/src/tests/build.spec.ts b/autogpt_platform/frontend/src/tests/build.spec.ts
index b5893a573dc9..c6793c46e3e1 100644
--- a/autogpt_platform/frontend/src/tests/build.spec.ts
+++ b/autogpt_platform/frontend/src/tests/build.spec.ts
@@ -51,14 +51,16 @@ test.describe("Build", () => { //(1)!
     await buildPage.openBlocksPanel();
     const blocks = await buildPage.getBlocks();
 
-    const blocksToSkip = await buildPage.getBlocksToSkip();
+    const blockIdsToSkip = await buildPage.getBlocksToSkip();
+    const blockTypesToSkip = ["Input", "Output", "Agent", "AI"];
 
     // add all the blocks in order except for the agent executor block
     for (const block of blocks) {
       if (block.name[0].toLowerCase() >= "m") {
         continue;
       }
-      if (!blocksToSkip.some((b) => b === block.id)) {
+      if (!blockIdsToSkip.some((b) => b === block.id) && !blockTypesToSkip.some((b) => block.type === b)) {
+        console.log("Adding block:", block.name, block.id, block.type, " skipping types:", blockTypesToSkip);
         await buildPage.addBlock(block);
       }
     }
@@ -68,8 +70,8 @@ test.describe("Build", () => { //(1)!
       if (block.name[0].toLowerCase() >= "m") {
         continue;
       }
-      if (!blocksToSkip.some((b) => b === block.id)) {
-        console.log("Checking block:", block.name);
+      if (!blockIdsToSkip.some((b) => b === block.id) && !blockTypesToSkip.some((b) => block.type === b)) {
+        console.log("Checking block:", block.name, block.id, block.type, " skipping types:", blockTypesToSkip);
         await test.expect(buildPage.hasBlock(block)).resolves.toBeTruthy();
       }
     }
@@ -89,14 +91,16 @@ test.describe("Build", () => { //(1)!
     await buildPage.openBlocksPanel();
     const blocks = await buildPage.getBlocks();
 
-    const blocksToSkip = await buildPage.getBlocksToSkip();
+    const blockIdsToSkip = await buildPage.getBlocksToSkip();
+    const blockTypesToSkip = ["Input", "Output", "Agent", "AI"];
 
     // add all the blocks in order except for the agent executor block
     for (const block of blocks) {
       if (block.name[0].toLowerCase() < "m") {
         continue;
       }
-      if (!blocksToSkip.some((b) => b === block.id)) {
+      if (!blockIdsToSkip.some((b) => b === block.id) && !blockTypesToSkip.some((b) => block.type === b)) {
+        console.log("Adding block:", block.name, block.id, block.type, " skipping types:", blockTypesToSkip);
         await buildPage.addBlock(block);
       }
     }
@@ -106,7 +110,8 @@ test.describe("Build", () => { //(1)!
       if (block.name[0].toLowerCase() < "m") {
         continue;
       }
-      if (!blocksToSkip.some((b) => b === block.id)) {
+      if (!blockIdsToSkip.some((b) => b === block.id) && !blockTypesToSkip.some((b) => block.type === b)) {
+        console.log("Checking block:", block.name, block.id, block.type, " skipping types:", blockTypesToSkip);
         await test.expect(buildPage.hasBlock(block)).resolves.toBeTruthy();
       }
     }
@@ -141,11 +146,13 @@ test.describe("Build", () => { //(1)!
       id: "1ff065e9-88e8-4358-9d82-8dc91f622ba9",
       name: "Store Value 1",
       description: "Store Value Block 1",
+      type: "Standard",
     };
     const block2 = {
       id: "1ff065e9-88e8-4358-9d82-8dc91f622ba9",
       name: "Store Value 2",
       description: "Store Value Block 2",
+      type: "Standard",
     };
 
     // Add the blocks
diff --git a/autogpt_platform/frontend/src/tests/pages/build.page.ts b/autogpt_platform/frontend/src/tests/pages/build.page.ts
index ccb26991a239..023bfc0ebb2d 100644
--- a/autogpt_platform/frontend/src/tests/pages/build.page.ts
+++ b/autogpt_platform/frontend/src/tests/pages/build.page.ts
@@ -5,6 +5,7 @@ export interface Block {
   id: string;
   name: string;
   description: string;
+  type: string;
 }
 
 export class BuildPage extends BasePage {
@@ -72,10 +73,12 @@ export class BuildPage extends BasePage {
 
             const name = (await nameElement.textContent()) || "";
             const description = (await descriptionElement.textContent()) || "";
+            const type = (await nameElement.getAttribute("data-type")) || "";
 
             return {
               id,
               name: name.trim(),
+              type: type.trim(),
               description: description.trim(),
             };
           } catch (elementError) {
@@ -358,6 +361,7 @@ export class BuildPage extends BasePage {
       id: "31d1064e-7446-4693-a7d4-65e5ca1180d1",
       name: "Add to Dictionary",
       description: "Add to Dictionary",
+      type: "Standard",
     };
   }
 
@@ -375,30 +379,7 @@ export class BuildPage extends BasePage {
       id: "b1ab9b19-67a6-406d-abf5-2dba76d00c79",
       name: "Calculator",
       description: "Calculator",
-    };
-  }
-
-  async getAgentExecutorBlockDetails(): Promise<Block> {
-    return {
-      id: "e189baac-8c20-45a1-94a7-55177ea42565",
-      name: "Agent Executor",
-      description: "Executes an existing agent inside your agent",
-    };
-  }
-
-  async getAgentOutputBlockDetails(): Promise<Block> {
-    return {
-      id: "363ae599-353e-4804-937e-b2ee3cef3da4",
-      name: "Agent Output",
-      description: "This block is used to output the result of an agent.",
-    };
-  }
-
-  async getAgentInputBlockDetails(): Promise<Block> {
-    return {
-      id: "c0a8e994-ebf1-4a9c-a4d8-89d09c86741b",
-      name: "Agent Input",
-      description: "This block is used to provide input to the graph.",
+      type: "Standard",
     };
   }
 
@@ -408,15 +389,7 @@ export class BuildPage extends BasePage {
       name: "Github Trigger",
       description:
         "This block triggers on pull request events and outputs the event type and payload.",
-    };
-  }
-
-  async getSmartDecisionMakerBlockDetails(): Promise<Block> {
-    return {
-      id: "3b191d9f-356f-482d-8238-ba04b6d18381",
-      name: "Smart Decision Maker",
-      description:
-        "This block is used to make a decision based on the input and the available tools.",
+      type: "Standard",
     };
   }
 
@@ -491,13 +464,7 @@ export class BuildPage extends BasePage {
   }
 
   async getBlocksToSkip(): Promise<string[]> {
-    return [
-      (await this.getAgentExecutorBlockDetails()).id,
-      (await this.getAgentInputBlockDetails()).id,
-      (await this.getAgentOutputBlockDetails()).id,
-      (await this.getGithubTriggerBlockDetails()).id,
-      (await this.getSmartDecisionMakerBlockDetails()).id,
-    ];
+    return [(await this.getGithubTriggerBlockDetails()).id];
   }
 
   async waitForRunTutorialButton(): Promise<void> {


Reviews:
user: login: Pwuts
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T11:58:31Z
user: login: Pwuts
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T12:02:36Z
user: login: Pwuts
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T12:03:53Z
user: login: Pwuts
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T12:05:07Z
user: login: Pwuts
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T12:06:44Z
user: login: Pwuts
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T12:07:30Z
user: login: Pwuts
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T12:08:27Z
user: login: Pwuts
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T12:15:02Z
user: login: Pwuts
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T12:21:57Z
user: login: majdyz
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T12:45:29Z
user: login: majdyz
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T13:07:27Z
user: login: majdyz
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T13:08:44Z
user: login: majdyz
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T13:10:07Z
user: login: majdyz
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T13:10:29Z
user: login: majdyz
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T13:10:44Z
user: login: majdyz
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T13:10:58Z
user: login: majdyz
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T13:11:11Z
user: login: majdyz
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T13:13:43Z
user: login: Torantulino
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T16:29:22Z
user: login: ntindle
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-24T01:14:04Z

Review comments:
diff_hunk: @@ -144,6 +144,7 @@ def SchemaField(
     depends_on: list[str] | None = None,
     image_upload: Optional[bool] = None,
     image_output: Optional[bool] = None,
+    json_extra: dict[str, Any] | None = None,
path: autogpt_platform/backend/backend/data/model.py
user: login: Pwuts
body: ```suggestion
    json_schema_extra: dict[str, Any] | None = None,
```
created_at: 2025-03-21T11:58:31Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,515 @@
+from datetime import date, time
+from typing import Any, List
+
+from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema, BlockType
+from backend.data.model import SchemaField
+from backend.util.file import MediaFile, store_media_file
+from backend.util.mock import MockObject
+from backend.util.text import TextFormatter
+
+formatter = TextFormatter()
+
+
+class AgentInputBlock(Block):
+    """
+    This block is used to provide input to the graph.
+
+    It takes in a value, name, description, default values list and bool to limit selection to default values.
+
+    It Outputs the value passed as input.
+    """
+
+    class Input(BlockSchema):
+        name: str = SchemaField(description="The name of the input.")
+        value: Any = SchemaField(
+            description="The value to be passed as input.",
+            default=None,
+        )
+        title: str | None = SchemaField(
+            description="The title of the input.", default=None, advanced=True
+        )
+        description: str | None = SchemaField(
+            description="The description of the input.",
+            default=None,
+            advanced=True,
+        )
+        placeholder_values: List[Any] = SchemaField(
+            description="The placeholder values to be passed as input.",
+            default=[],
+            advanced=True,
+        )
+        limit_to_placeholder_values: bool = SchemaField(
+            description="Whether to limit the selection to placeholder values.",
+            default=False,
+            advanced=True,
+        )
+        advanced: bool = SchemaField(
+            description="Whether to show the input in the advanced section, if the field is not required.",
+            default=False,
+            advanced=True,
+        )
+        secret: bool = SchemaField(
+            description="Whether the input should be treated as a secret.",
+            default=False,
+            advanced=True,
+        )
+
+    class Output(BlockSchema):
+        result: Any = SchemaField(description="The value passed as input.")
+
+    def __init__(self, **kwargs):
+        super().__init__(
+            **{
+                "id": "c0a8e994-ebf1-4a9c-a4d8-89d09c86741b",
+                "description": "Base block for user inputs.",
+                "input_schema": AgentInputBlock.Input,
+                "output_schema": AgentInputBlock.Output,
+                "test_input": [
+                    {
+                        "value": "Hello, World!",
+                        "name": "input_1",
+                        "description": "Example test input.",
+                        "placeholder_values": [],
+                        "limit_to_placeholder_values": False,
+                    },
+                    {
+                        "value": "Hello, World!",
+                        "name": "input_2",
+                        "description": "Example test input with placeholders.",
+                        "placeholder_values": ["Hello, World!"],
+                        "limit_to_placeholder_values": True,
+                    },
+                ],
+                "test_output": [
+                    ("result", "Hello, World!"),
+                    ("result", "Hello, World!"),
+                ],
+                "categories": {BlockCategory.INPUT, BlockCategory.BASIC},
+                "block_type": BlockType.INPUT,
+                "static_output": True,
+                **kwargs,
+            }
+        )
+
+    def run(self, input_data: Input, *args, **kwargs) -> BlockOutput:
+        yield "result", input_data.value
+
+
+class AgentOutputBlock(Block):
+    """
+    Records the output of the graph for users to see.
+
+    Behavior:
+        If `format` is provided and the `value` is of a type that can be formatted,
+        the block attempts to format the recorded_value using the `format`.
+        If formatting fails or no `format` is provided, the raw `value` is output.
+    """
+
+    class Input(BlockSchema):
+        value: Any = SchemaField(
+            description="The value to be recorded as output.",
+            default=None,
+            advanced=False,
+        )
+        name: str = SchemaField(description="The name of the output.")
+        title: str | None = SchemaField(
+            description="The title of the output.",
+            default=None,
+            advanced=True,
+        )
+        description: str | None = SchemaField(
+            description="The description of the output.",
+            default=None,
+            advanced=True,
+        )
+        format: str = SchemaField(
+            description="The format string to be used to format the recorded_value. Use Jinja2 syntax.",
+            default="",
+            advanced=True,
+        )
+        advanced: bool = SchemaField(
+            description="Whether to treat the output as advanced.",
+            default=False,
+            advanced=True,
+        )
+        secret: bool = SchemaField(
+            description="Whether the output should be treated as a secret.",
+            default=False,
+            advanced=True,
+        )
+
+    class Output(BlockSchema):
+        output: Any = SchemaField(description="The value recorded as output.")
+        name: Any = SchemaField(description="The name of the value recorded as output.")
+
+    def __init__(self):
+        super().__init__(
+            id="363ae599-353e-4804-937e-b2ee3cef3da4",
+            description="Stores the output of the graph for users to see.",
+            input_schema=AgentOutputBlock.Input,
+            output_schema=AgentOutputBlock.Output,
+            test_input=[
+                {
+                    "value": "Hello, World!",
+                    "name": "output_1",
+                    "description": "This is a test output.",
+                    "format": "{{ output_1 }}!!",
+                },
+                {
+                    "value": "42",
+                    "name": "output_2",
+                    "description": "This is another test output.",
+                    "format": "{{ output_2 }}",
+                },
+                {
+                    "value": MockObject(value="!!", key="key"),
+                    "name": "output_3",
+                    "description": "This is a test output with a mock object.",
+                    "format": "{{ output_3 }}",
+                },
+            ],
+            test_output=[
+                ("output", "Hello, World!!!"),
+                ("output", "42"),
+                ("output", MockObject(value="!!", key="key")),
+            ],
+            categories={BlockCategory.OUTPUT, BlockCategory.BASIC},
+            block_type=BlockType.OUTPUT,
+            static_output=True,
+        )
+
+    def run(self, input_data: Input, *args, **kwargs) -> BlockOutput:
+        """
+        Attempts to format the recorded_value using the fmt_string if provided.
+        If formatting fails or no fmt_string is given, returns the original recorded_value.
+        """
+        if input_data.format:
+            try:
+                yield "output", formatter.format_string(
+                    input_data.format, {input_data.name: input_data.value}
+                )
+            except Exception as e:
+                yield "output", f"Error: {e}, {input_data.value}"
+        else:
+            yield "output", input_data.value
+            yield "name", input_data.name
+
+
+class ShortTextAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: str = SchemaField(
+            description="Short text input.",
+            default="Short text",
+            json_extra={"format": "short-text"},
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: str = SchemaField(description="Short text result.")
+
+    def __init__(self):
+        super().__init__(
+            id="7fcd3bcb-8e1b-4e69-903d-32d3d4a92158",
+            description="Block for short text input (single-line).",
+            input_schema=ShortTextAgentInputBlock.Input,
+            output_schema=ShortTextAgentInputBlock.Output,
+            test_input=[
+                {
+                    "value": "Hello",
+                    "name": "short_text_1",
+                    "description": "Short text example 1",
+                    "placeholder_values": [],
+                    "limit_to_placeholder_values": False,
+                },
+                {
+                    "value": "Quick test",
+                    "name": "short_text_2",
+                    "description": "Short text example 2",
+                    "placeholder_values": ["Quick test", "Another option"],
+                    "limit_to_placeholder_values": True,
+                },
+            ],
+            test_output=[
+                ("result", "Hello"),
+                ("result", "Quick test"),
+            ],
+        )
+
+
+class LongTextAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: str = SchemaField(
+            description="Long text input (potentially multi-line).",
+            default="Longer text can go here.",
+            json_extra={"format": "long-text"},
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: str = SchemaField(description="Long text result.")
+
+    def __init__(self):
+        super().__init__(
+            id="90a56ffb-7024-4b2b-ab50-e26c5e5ab8ba",
+            description="Block for long text input (multi-line).",
+            input_schema=LongTextAgentInputBlock.Input,
+            output_schema=LongTextAgentInputBlock.Output,
+            test_input=[
+                {
+                    "value": "Lorem ipsum dolor sit amet...",
+                    "name": "long_text_1",
+                    "description": "Long text example 1",
+                    "placeholder_values": [],
+                    "limit_to_placeholder_values": False,
+                },
+                {
+                    "value": "Another multiline text input.",
+                    "name": "long_text_2",
+                    "description": "Long text example 2",
+                    "placeholder_values": ["Another multiline text input."],
+                    "limit_to_placeholder_values": True,
+                },
+            ],
+            test_output=[
+                ("result", "Lorem ipsum dolor sit amet..."),
+                ("result", "Another multiline text input."),
+            ],
+        )
+
+
+class NumberAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: int = SchemaField(
+            description="Number input.",
+            default=42,
path: autogpt_platform/backend/backend/blocks/io.py
user: login: Pwuts
body: I don't think this should have a default value
created_at: 2025-03-21T12:02:35Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,515 @@
+from datetime import date, time
+from typing import Any, List
+
+from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema, BlockType
+from backend.data.model import SchemaField
+from backend.util.file import MediaFile, store_media_file
+from backend.util.mock import MockObject
+from backend.util.text import TextFormatter
+
+formatter = TextFormatter()
+
+
+class AgentInputBlock(Block):
+    """
+    This block is used to provide input to the graph.
+
+    It takes in a value, name, description, default values list and bool to limit selection to default values.
+
+    It Outputs the value passed as input.
+    """
+
+    class Input(BlockSchema):
+        name: str = SchemaField(description="The name of the input.")
+        value: Any = SchemaField(
+            description="The value to be passed as input.",
+            default=None,
+        )
+        title: str | None = SchemaField(
+            description="The title of the input.", default=None, advanced=True
+        )
+        description: str | None = SchemaField(
+            description="The description of the input.",
+            default=None,
+            advanced=True,
+        )
+        placeholder_values: List[Any] = SchemaField(
+            description="The placeholder values to be passed as input.",
+            default=[],
+            advanced=True,
+        )
+        limit_to_placeholder_values: bool = SchemaField(
+            description="Whether to limit the selection to placeholder values.",
+            default=False,
+            advanced=True,
+        )
+        advanced: bool = SchemaField(
+            description="Whether to show the input in the advanced section, if the field is not required.",
+            default=False,
+            advanced=True,
+        )
+        secret: bool = SchemaField(
+            description="Whether the input should be treated as a secret.",
+            default=False,
+            advanced=True,
+        )
+
+    class Output(BlockSchema):
+        result: Any = SchemaField(description="The value passed as input.")
+
+    def __init__(self, **kwargs):
+        super().__init__(
+            **{
+                "id": "c0a8e994-ebf1-4a9c-a4d8-89d09c86741b",
+                "description": "Base block for user inputs.",
+                "input_schema": AgentInputBlock.Input,
+                "output_schema": AgentInputBlock.Output,
+                "test_input": [
+                    {
+                        "value": "Hello, World!",
+                        "name": "input_1",
+                        "description": "Example test input.",
+                        "placeholder_values": [],
+                        "limit_to_placeholder_values": False,
+                    },
+                    {
+                        "value": "Hello, World!",
+                        "name": "input_2",
+                        "description": "Example test input with placeholders.",
+                        "placeholder_values": ["Hello, World!"],
+                        "limit_to_placeholder_values": True,
+                    },
+                ],
+                "test_output": [
+                    ("result", "Hello, World!"),
+                    ("result", "Hello, World!"),
+                ],
+                "categories": {BlockCategory.INPUT, BlockCategory.BASIC},
+                "block_type": BlockType.INPUT,
+                "static_output": True,
+                **kwargs,
+            }
+        )
+
+    def run(self, input_data: Input, *args, **kwargs) -> BlockOutput:
+        yield "result", input_data.value
+
+
+class AgentOutputBlock(Block):
+    """
+    Records the output of the graph for users to see.
+
+    Behavior:
+        If `format` is provided and the `value` is of a type that can be formatted,
+        the block attempts to format the recorded_value using the `format`.
+        If formatting fails or no `format` is provided, the raw `value` is output.
+    """
+
+    class Input(BlockSchema):
+        value: Any = SchemaField(
+            description="The value to be recorded as output.",
+            default=None,
+            advanced=False,
+        )
+        name: str = SchemaField(description="The name of the output.")
+        title: str | None = SchemaField(
+            description="The title of the output.",
+            default=None,
+            advanced=True,
+        )
+        description: str | None = SchemaField(
+            description="The description of the output.",
+            default=None,
+            advanced=True,
+        )
+        format: str = SchemaField(
+            description="The format string to be used to format the recorded_value. Use Jinja2 syntax.",
+            default="",
+            advanced=True,
+        )
+        advanced: bool = SchemaField(
+            description="Whether to treat the output as advanced.",
+            default=False,
+            advanced=True,
+        )
+        secret: bool = SchemaField(
+            description="Whether the output should be treated as a secret.",
+            default=False,
+            advanced=True,
+        )
+
+    class Output(BlockSchema):
+        output: Any = SchemaField(description="The value recorded as output.")
+        name: Any = SchemaField(description="The name of the value recorded as output.")
+
+    def __init__(self):
+        super().__init__(
+            id="363ae599-353e-4804-937e-b2ee3cef3da4",
+            description="Stores the output of the graph for users to see.",
+            input_schema=AgentOutputBlock.Input,
+            output_schema=AgentOutputBlock.Output,
+            test_input=[
+                {
+                    "value": "Hello, World!",
+                    "name": "output_1",
+                    "description": "This is a test output.",
+                    "format": "{{ output_1 }}!!",
+                },
+                {
+                    "value": "42",
+                    "name": "output_2",
+                    "description": "This is another test output.",
+                    "format": "{{ output_2 }}",
+                },
+                {
+                    "value": MockObject(value="!!", key="key"),
+                    "name": "output_3",
+                    "description": "This is a test output with a mock object.",
+                    "format": "{{ output_3 }}",
+                },
+            ],
+            test_output=[
+                ("output", "Hello, World!!!"),
+                ("output", "42"),
+                ("output", MockObject(value="!!", key="key")),
+            ],
+            categories={BlockCategory.OUTPUT, BlockCategory.BASIC},
+            block_type=BlockType.OUTPUT,
+            static_output=True,
+        )
+
+    def run(self, input_data: Input, *args, **kwargs) -> BlockOutput:
+        """
+        Attempts to format the recorded_value using the fmt_string if provided.
+        If formatting fails or no fmt_string is given, returns the original recorded_value.
+        """
+        if input_data.format:
+            try:
+                yield "output", formatter.format_string(
+                    input_data.format, {input_data.name: input_data.value}
+                )
+            except Exception as e:
+                yield "output", f"Error: {e}, {input_data.value}"
+        else:
+            yield "output", input_data.value
+            yield "name", input_data.name
+
+
+class ShortTextAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: str = SchemaField(
+            description="Short text input.",
+            default="Short text",
+            json_extra={"format": "short-text"},
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: str = SchemaField(description="Short text result.")
+
+    def __init__(self):
+        super().__init__(
+            id="7fcd3bcb-8e1b-4e69-903d-32d3d4a92158",
+            description="Block for short text input (single-line).",
+            input_schema=ShortTextAgentInputBlock.Input,
+            output_schema=ShortTextAgentInputBlock.Output,
+            test_input=[
+                {
+                    "value": "Hello",
+                    "name": "short_text_1",
+                    "description": "Short text example 1",
+                    "placeholder_values": [],
+                    "limit_to_placeholder_values": False,
+                },
+                {
+                    "value": "Quick test",
+                    "name": "short_text_2",
+                    "description": "Short text example 2",
+                    "placeholder_values": ["Quick test", "Another option"],
+                    "limit_to_placeholder_values": True,
+                },
+            ],
+            test_output=[
+                ("result", "Hello"),
+                ("result", "Quick test"),
+            ],
+        )
+
+
+class LongTextAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: str = SchemaField(
+            description="Long text input (potentially multi-line).",
+            default="Longer text can go here.",
+            json_extra={"format": "long-text"},
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: str = SchemaField(description="Long text result.")
+
+    def __init__(self):
+        super().__init__(
+            id="90a56ffb-7024-4b2b-ab50-e26c5e5ab8ba",
+            description="Block for long text input (multi-line).",
+            input_schema=LongTextAgentInputBlock.Input,
+            output_schema=LongTextAgentInputBlock.Output,
+            test_input=[
+                {
+                    "value": "Lorem ipsum dolor sit amet...",
+                    "name": "long_text_1",
+                    "description": "Long text example 1",
+                    "placeholder_values": [],
+                    "limit_to_placeholder_values": False,
+                },
+                {
+                    "value": "Another multiline text input.",
+                    "name": "long_text_2",
+                    "description": "Long text example 2",
+                    "placeholder_values": ["Another multiline text input."],
+                    "limit_to_placeholder_values": True,
+                },
+            ],
+            test_output=[
+                ("result", "Lorem ipsum dolor sit amet..."),
+                ("result", "Another multiline text input."),
+            ],
+        )
+
+
+class NumberAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: int = SchemaField(
+            description="Number input.",
+            default=42,
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: int = SchemaField(description="Number result.")
+
+    def __init__(self):
+        super().__init__(
+            id="96dae2bb-97a2-41c2-bd2f-13a3b5a8ea98",
+            description="Block for number input.",
+            input_schema=NumberAgentInputBlock.Input,
+            output_schema=NumberAgentInputBlock.Output,
+            test_input=[
+                {
+                    "value": 42,
+                    "name": "number_input_1",
+                    "description": "Number example 1",
+                    "placeholder_values": [],
+                    "limit_to_placeholder_values": False,
+                },
+                {
+                    "value": 314,
+                    "name": "number_input_2",
+                    "description": "Number example 2",
+                    "placeholder_values": [314, 2718],
+                    "limit_to_placeholder_values": True,
+                },
+            ],
+            test_output=[
+                ("result", 42),
+                ("result", 314),
+            ],
+        )
+
+
+class DateAgentInputBlock(AgentInputBlock):
path: autogpt_platform/backend/backend/blocks/io.py
user: login: Pwuts
body: This will show up as "Date Agent Input", right? I suggest changing this to either of
- Agent Date Input
- Date Input

same for the other input blocks with this naming pattern
created_at: 2025-03-21T12:03:53Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,515 @@
+from datetime import date, time
+from typing import Any, List
+
+from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema, BlockType
+from backend.data.model import SchemaField
+from backend.util.file import MediaFile, store_media_file
+from backend.util.mock import MockObject
+from backend.util.text import TextFormatter
+
+formatter = TextFormatter()
+
+
+class AgentInputBlock(Block):
+    """
+    This block is used to provide input to the graph.
+
+    It takes in a value, name, description, default values list and bool to limit selection to default values.
+
+    It Outputs the value passed as input.
+    """
+
+    class Input(BlockSchema):
+        name: str = SchemaField(description="The name of the input.")
+        value: Any = SchemaField(
+            description="The value to be passed as input.",
+            default=None,
+        )
+        title: str | None = SchemaField(
+            description="The title of the input.", default=None, advanced=True
+        )
+        description: str | None = SchemaField(
+            description="The description of the input.",
+            default=None,
+            advanced=True,
+        )
+        placeholder_values: List[Any] = SchemaField(
+            description="The placeholder values to be passed as input.",
+            default=[],
+            advanced=True,
+        )
+        limit_to_placeholder_values: bool = SchemaField(
+            description="Whether to limit the selection to placeholder values.",
+            default=False,
+            advanced=True,
+        )
+        advanced: bool = SchemaField(
+            description="Whether to show the input in the advanced section, if the field is not required.",
+            default=False,
+            advanced=True,
+        )
+        secret: bool = SchemaField(
+            description="Whether the input should be treated as a secret.",
+            default=False,
+            advanced=True,
+        )
+
+    class Output(BlockSchema):
+        result: Any = SchemaField(description="The value passed as input.")
+
+    def __init__(self, **kwargs):
+        super().__init__(
+            **{
+                "id": "c0a8e994-ebf1-4a9c-a4d8-89d09c86741b",
+                "description": "Base block for user inputs.",
+                "input_schema": AgentInputBlock.Input,
+                "output_schema": AgentInputBlock.Output,
+                "test_input": [
+                    {
+                        "value": "Hello, World!",
+                        "name": "input_1",
+                        "description": "Example test input.",
+                        "placeholder_values": [],
+                        "limit_to_placeholder_values": False,
+                    },
+                    {
+                        "value": "Hello, World!",
+                        "name": "input_2",
+                        "description": "Example test input with placeholders.",
+                        "placeholder_values": ["Hello, World!"],
+                        "limit_to_placeholder_values": True,
+                    },
+                ],
+                "test_output": [
+                    ("result", "Hello, World!"),
+                    ("result", "Hello, World!"),
+                ],
+                "categories": {BlockCategory.INPUT, BlockCategory.BASIC},
+                "block_type": BlockType.INPUT,
+                "static_output": True,
+                **kwargs,
+            }
+        )
+
+    def run(self, input_data: Input, *args, **kwargs) -> BlockOutput:
+        yield "result", input_data.value
+
+
+class AgentOutputBlock(Block):
+    """
+    Records the output of the graph for users to see.
+
+    Behavior:
+        If `format` is provided and the `value` is of a type that can be formatted,
+        the block attempts to format the recorded_value using the `format`.
+        If formatting fails or no `format` is provided, the raw `value` is output.
+    """
+
+    class Input(BlockSchema):
+        value: Any = SchemaField(
+            description="The value to be recorded as output.",
+            default=None,
+            advanced=False,
+        )
+        name: str = SchemaField(description="The name of the output.")
+        title: str | None = SchemaField(
+            description="The title of the output.",
+            default=None,
+            advanced=True,
+        )
+        description: str | None = SchemaField(
+            description="The description of the output.",
+            default=None,
+            advanced=True,
+        )
+        format: str = SchemaField(
+            description="The format string to be used to format the recorded_value. Use Jinja2 syntax.",
+            default="",
+            advanced=True,
+        )
+        advanced: bool = SchemaField(
+            description="Whether to treat the output as advanced.",
+            default=False,
+            advanced=True,
+        )
+        secret: bool = SchemaField(
+            description="Whether the output should be treated as a secret.",
+            default=False,
+            advanced=True,
+        )
+
+    class Output(BlockSchema):
+        output: Any = SchemaField(description="The value recorded as output.")
+        name: Any = SchemaField(description="The name of the value recorded as output.")
+
+    def __init__(self):
+        super().__init__(
+            id="363ae599-353e-4804-937e-b2ee3cef3da4",
+            description="Stores the output of the graph for users to see.",
+            input_schema=AgentOutputBlock.Input,
+            output_schema=AgentOutputBlock.Output,
+            test_input=[
+                {
+                    "value": "Hello, World!",
+                    "name": "output_1",
+                    "description": "This is a test output.",
+                    "format": "{{ output_1 }}!!",
+                },
+                {
+                    "value": "42",
+                    "name": "output_2",
+                    "description": "This is another test output.",
+                    "format": "{{ output_2 }}",
+                },
+                {
+                    "value": MockObject(value="!!", key="key"),
+                    "name": "output_3",
+                    "description": "This is a test output with a mock object.",
+                    "format": "{{ output_3 }}",
+                },
+            ],
+            test_output=[
+                ("output", "Hello, World!!!"),
+                ("output", "42"),
+                ("output", MockObject(value="!!", key="key")),
+            ],
+            categories={BlockCategory.OUTPUT, BlockCategory.BASIC},
+            block_type=BlockType.OUTPUT,
+            static_output=True,
+        )
+
+    def run(self, input_data: Input, *args, **kwargs) -> BlockOutput:
+        """
+        Attempts to format the recorded_value using the fmt_string if provided.
+        If formatting fails or no fmt_string is given, returns the original recorded_value.
+        """
+        if input_data.format:
+            try:
+                yield "output", formatter.format_string(
+                    input_data.format, {input_data.name: input_data.value}
+                )
+            except Exception as e:
+                yield "output", f"Error: {e}, {input_data.value}"
+        else:
+            yield "output", input_data.value
+            yield "name", input_data.name
+
+
+class ShortTextAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: str = SchemaField(
+            description="Short text input.",
+            default="Short text",
+            json_extra={"format": "short-text"},
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: str = SchemaField(description="Short text result.")
+
+    def __init__(self):
+        super().__init__(
+            id="7fcd3bcb-8e1b-4e69-903d-32d3d4a92158",
+            description="Block for short text input (single-line).",
+            input_schema=ShortTextAgentInputBlock.Input,
+            output_schema=ShortTextAgentInputBlock.Output,
+            test_input=[
+                {
+                    "value": "Hello",
+                    "name": "short_text_1",
+                    "description": "Short text example 1",
+                    "placeholder_values": [],
+                    "limit_to_placeholder_values": False,
+                },
+                {
+                    "value": "Quick test",
+                    "name": "short_text_2",
+                    "description": "Short text example 2",
+                    "placeholder_values": ["Quick test", "Another option"],
+                    "limit_to_placeholder_values": True,
+                },
+            ],
+            test_output=[
+                ("result", "Hello"),
+                ("result", "Quick test"),
+            ],
+        )
+
+
+class LongTextAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: str = SchemaField(
+            description="Long text input (potentially multi-line).",
+            default="Longer text can go here.",
+            json_extra={"format": "long-text"},
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: str = SchemaField(description="Long text result.")
+
+    def __init__(self):
+        super().__init__(
+            id="90a56ffb-7024-4b2b-ab50-e26c5e5ab8ba",
+            description="Block for long text input (multi-line).",
+            input_schema=LongTextAgentInputBlock.Input,
+            output_schema=LongTextAgentInputBlock.Output,
+            test_input=[
+                {
+                    "value": "Lorem ipsum dolor sit amet...",
+                    "name": "long_text_1",
+                    "description": "Long text example 1",
+                    "placeholder_values": [],
+                    "limit_to_placeholder_values": False,
+                },
+                {
+                    "value": "Another multiline text input.",
+                    "name": "long_text_2",
+                    "description": "Long text example 2",
+                    "placeholder_values": ["Another multiline text input."],
+                    "limit_to_placeholder_values": True,
+                },
+            ],
+            test_output=[
+                ("result", "Lorem ipsum dolor sit amet..."),
+                ("result", "Another multiline text input."),
+            ],
+        )
+
+
+class NumberAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: int = SchemaField(
+            description="Number input.",
+            default=42,
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: int = SchemaField(description="Number result.")
+
+    def __init__(self):
+        super().__init__(
+            id="96dae2bb-97a2-41c2-bd2f-13a3b5a8ea98",
+            description="Block for number input.",
+            input_schema=NumberAgentInputBlock.Input,
+            output_schema=NumberAgentInputBlock.Output,
+            test_input=[
+                {
+                    "value": 42,
+                    "name": "number_input_1",
+                    "description": "Number example 1",
+                    "placeholder_values": [],
+                    "limit_to_placeholder_values": False,
+                },
+                {
+                    "value": 314,
+                    "name": "number_input_2",
+                    "description": "Number example 2",
+                    "placeholder_values": [314, 2718],
+                    "limit_to_placeholder_values": True,
+                },
+            ],
+            test_output=[
+                ("result", 42),
+                ("result", 314),
+            ],
+        )
+
+
+class DateAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: date = SchemaField(
+            description="Date input (YYYY-MM-DD).",
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: date = SchemaField(description="Date result.")
+
+    def __init__(self):
+        super().__init__(
+            id="7e198b09-4994-47db-8b4d-952d98241817",
+            description="Block for date input.",
+            input_schema=DateAgentInputBlock.Input,
+            output_schema=DateAgentInputBlock.Output,
+            test_input=[
+                {
+                    # If your system can parse JSON date strings to date objects
+                    "value": str(date(2025, 3, 19)),
+                    "name": "date_input_1",
+                    "description": "Example date input 1",
+                },
+                {
+                    "value": str(date(2023, 12, 31)),
+                    "name": "date_input_2",
+                    "description": "Example date input 2",
+                },
+            ],
+            test_output=[
+                ("result", date(2025, 3, 19)),
+                ("result", date(2023, 12, 31)),
+            ],
+        )
+
+
+class TimeAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: time = SchemaField(
+            description="Time input (HH:MM:SS).",
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: time = SchemaField(description="Time result.")
+
+    def __init__(self):
+        super().__init__(
+            id="2a1c757e-86cf-4c7e-aacf-060dc382e434",
+            description="Block for time input.",
+            input_schema=TimeAgentInputBlock.Input,
+            output_schema=TimeAgentInputBlock.Output,
+            test_input=[
+                {
+                    "value": str(time(9, 30, 0)),
+                    "name": "time_input_1",
+                    "description": "Time example 1",
+                },
+                {
+                    "value": str(time(23, 59, 59)),
+                    "name": "time_input_2",
+                    "description": "Time example 2",
+                },
+            ],
+            test_output=[
+                ("result", time(9, 30, 0)),
+                ("result", time(23, 59, 59)),
+            ],
+        )
+
+
+class FileUploadAgentInputBlock(AgentInputBlock):
+    """
+    A simplified file-upload block. In real usage, you might have a custom
+    file type or handle binary data. Here, we'll store a string path as the example.
+    """
+
+    class Input(AgentInputBlock.Input):
+        value: MediaFile = SchemaField(
+            description="Path or reference to an uploaded file.",
+            default=MediaFile("path/to/file.txt"),
path: autogpt_platform/backend/backend/blocks/io.py
user: login: Pwuts
body: This probably also shouldn't have a default value.
```suggestion
```
created_at: 2025-03-21T12:05:07Z
author_association: MEMBER
path: autogpt_platform/backend/backend/blocks/io.py
user: login: Pwuts
body: These are agent input blocks: can we let the graph author specify a default value rather than hard-coding it?
created_at: 2025-03-21T12:06:44Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,515 @@
+from datetime import date, time
+from typing import Any, List
path: autogpt_platform/backend/backend/blocks/io.py
user: login: Pwuts
body: nit: use `list` instead of `List` and avoid the unnecessary import
```suggestion
from typing import Any
```

Also, `list[Any]` is equivalent to just `list` afaik
created_at: 2025-03-21T12:07:30Z
author_association: MEMBER
path: autogpt_platform/backend/backend/blocks/io.py
user: login: Pwuts
body: I see a date input and a time input, but no datetime input?
created_at: 2025-03-21T12:08:27Z
author_association: MEMBER
diff_hunk: @@ -232,34 +248,131 @@ const NodeDateTimeInput: FC<{
 
   return (
     <div className={cn("flex flex-col gap-2", className)}>
-      <Popover>
-        <PopoverTrigger asChild>
+      {hideDate || (
+        <Popover>
+          <PopoverTrigger asChild>
+            <Button
+              variant="outline"
+              className={cn(
+                "w-full justify-start text-left font-normal",
+                !value && "text-muted-foreground",
+              )}
+            >
+              <CalendarIcon className="mr-2 h-4 w-4" />
+              {value ? format(date, "PPP") : <span>Pick a date</span>}
+            </Button>
+          </PopoverTrigger>
+          <PopoverContent className="w-auto p-0" align="start">
+            <Calendar
+              mode="single"
+              selected={date}
+              onSelect={handleDateSelect}
+              initialFocus
+            />
+          </PopoverContent>
+        </Popover>
+      )}
+      {hideTime || (
+        <LocalValuedInput
+          type="time"
+          value={timeInput}
+          onChange={handleTimeChange}
+          className="w-full"
+        />
+      )}
+      {error && <span className="error-message">{error}</span>}
+    </div>
+  );
+};
+
+const NodeFileInput: FC<{
+  selfKey: string;
+  schema: BlockIOStringSubSchema;
+  value?: string;
+  error?: string;
+  handleInputChange: NodeObjectInputTreeProps["handleInputChange"];
+  className?: string;
+  displayName: string;
+}> = ({
+  selfKey,
+  schema,
+  value = "",
+  error,
+  handleInputChange,
+  className,
+  displayName,
+}) => {
+  const handleFileChange = useCallback(
+    (event: React.ChangeEvent<HTMLInputElement>) => {
+      const file = event.target.files?.[0];
+      if (!file) return;
+
+      const reader = new FileReader();
+      reader.onload = (e) => {
+        const base64String = e.target?.result as string;
+        handleInputChange(selfKey, base64String);
+      };
+      reader.readAsDataURL(file);
+    },
+    [selfKey, handleInputChange],
+  );
+
+  const getFileLabel = useCallback((value: string) => {
+    if (value.startsWith("data:")) {
+      const matches = value.match(/^data:([^;]+);/);
+      if (matches?.[1]) {
+        const mimeParts = matches[1].split("/");
+        if (mimeParts.length > 1) {
+          return `${mimeParts[1].toUpperCase()} file`;
+        }
+        return `${matches[1]} file`;
+      }
+    } else {
+      const pathParts = value.split(".");
+      if (pathParts.length > 1) {
+        const ext = pathParts.pop();
+        if (ext) return `${ext.toUpperCase()} file`;
+      }
+    }
+    return "File";
+  }, []);
+
+  return (
+    <div className={cn("flex flex-col gap-2", className)}>
+      <div className="nodrag flex flex-col gap-2">
+        <div className="flex items-center gap-2">
           <Button
             variant="outline"
-            className={cn(
-              "w-full justify-start text-left font-normal",
-              !value && "text-muted-foreground",
-            )}
+            onClick={() =>
+              document.getElementById(`${selfKey}-upload`)?.click()
+            }
+            className="w-full"
           >
-            <CalendarIcon className="mr-2 h-4 w-4" />
-            {value ? format(date, "PPP") : <span>Pick a date</span>}
+            {value ? `Change ${displayName}` : `Upload ${displayName}`}
           </Button>
-        </PopoverTrigger>
-        <PopoverContent className="w-auto p-0" align="start">
-          <Calendar
-            mode="single"
-            selected={date}
-            onSelect={handleDateSelect}
-            initialFocus
-          />
-        </PopoverContent>
-      </Popover>
-      <LocalValuedInput
-        type="time"
-        value={timeInput}
-        onChange={handleTimeChange}
-        className="w-full"
-      />
+          {value && (
+            <Button
+              variant="ghost"
+              className="text-red-500 hover:text-red-700"
+              onClick={() => handleInputChange(selfKey, "")}
+            >
+              <Cross2Icon className="h-4 w-4" />
+            </Button>
+          )}
+        </div>
+        <input
+          id={`${selfKey}-upload`}
+          type="file"
+          accept="*/*"
+          onChange={handleFileChange}
+          className="hidden"
+        />
path: autogpt_platform/frontend/src/components/node-input-components.tsx
user: login: Pwuts
body: https://ui.shadcn.com/docs/components/input#file
created_at: 2025-03-21T12:15:02Z
author_association: MEMBER
diff_hunk: @@ -500,11 +500,11 @@ export enum BlockUIType {
   WEBHOOK = "Webhook",
   WEBHOOK_MANUAL = "Webhook (manual)",
   AGENT = "Agent",
+  AI = "AI",
path: autogpt_platform/frontend/src/lib/autogpt-server-api/types.ts
user: login: Pwuts
body: I don't see this being used anywhere, was this included by accident?
created_at: 2025-03-21T12:21:57Z
author_association: MEMBER
diff_hunk: @@ -500,11 +500,11 @@ export enum BlockUIType {
   WEBHOOK = "Webhook",
   WEBHOOK_MANUAL = "Webhook (manual)",
   AGENT = "Agent",
+  AI = "AI",
path: autogpt_platform/frontend/src/lib/autogpt-server-api/types.ts
user: login: majdyz
body: It's just a new type block that is introduced in the backend but not introduced here.
created_at: 2025-03-21T12:45:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -232,34 +248,131 @@ const NodeDateTimeInput: FC<{
 
   return (
     <div className={cn("flex flex-col gap-2", className)}>
-      <Popover>
-        <PopoverTrigger asChild>
+      {hideDate || (
+        <Popover>
+          <PopoverTrigger asChild>
+            <Button
+              variant="outline"
+              className={cn(
+                "w-full justify-start text-left font-normal",
+                !value && "text-muted-foreground",
+              )}
+            >
+              <CalendarIcon className="mr-2 h-4 w-4" />
+              {value ? format(date, "PPP") : <span>Pick a date</span>}
+            </Button>
+          </PopoverTrigger>
+          <PopoverContent className="w-auto p-0" align="start">
+            <Calendar
+              mode="single"
+              selected={date}
+              onSelect={handleDateSelect}
+              initialFocus
+            />
+          </PopoverContent>
+        </Popover>
+      )}
+      {hideTime || (
+        <LocalValuedInput
+          type="time"
+          value={timeInput}
+          onChange={handleTimeChange}
+          className="w-full"
+        />
+      )}
+      {error && <span className="error-message">{error}</span>}
+    </div>
+  );
+};
+
+const NodeFileInput: FC<{
+  selfKey: string;
+  schema: BlockIOStringSubSchema;
+  value?: string;
+  error?: string;
+  handleInputChange: NodeObjectInputTreeProps["handleInputChange"];
+  className?: string;
+  displayName: string;
+}> = ({
+  selfKey,
+  schema,
+  value = "",
+  error,
+  handleInputChange,
+  className,
+  displayName,
+}) => {
+  const handleFileChange = useCallback(
+    (event: React.ChangeEvent<HTMLInputElement>) => {
+      const file = event.target.files?.[0];
+      if (!file) return;
+
+      const reader = new FileReader();
+      reader.onload = (e) => {
+        const base64String = e.target?.result as string;
+        handleInputChange(selfKey, base64String);
+      };
+      reader.readAsDataURL(file);
+    },
+    [selfKey, handleInputChange],
+  );
+
+  const getFileLabel = useCallback((value: string) => {
+    if (value.startsWith("data:")) {
+      const matches = value.match(/^data:([^;]+);/);
+      if (matches?.[1]) {
+        const mimeParts = matches[1].split("/");
+        if (mimeParts.length > 1) {
+          return `${mimeParts[1].toUpperCase()} file`;
+        }
+        return `${matches[1]} file`;
+      }
+    } else {
+      const pathParts = value.split(".");
+      if (pathParts.length > 1) {
+        const ext = pathParts.pop();
+        if (ext) return `${ext.toUpperCase()} file`;
+      }
+    }
+    return "File";
+  }, []);
+
+  return (
+    <div className={cn("flex flex-col gap-2", className)}>
+      <div className="nodrag flex flex-col gap-2">
+        <div className="flex items-center gap-2">
           <Button
             variant="outline"
-            className={cn(
-              "w-full justify-start text-left font-normal",
-              !value && "text-muted-foreground",
-            )}
+            onClick={() =>
+              document.getElementById(`${selfKey}-upload`)?.click()
+            }
+            className="w-full"
           >
-            <CalendarIcon className="mr-2 h-4 w-4" />
-            {value ? format(date, "PPP") : <span>Pick a date</span>}
+            {value ? `Change ${displayName}` : `Upload ${displayName}`}
           </Button>
-        </PopoverTrigger>
-        <PopoverContent className="w-auto p-0" align="start">
-          <Calendar
-            mode="single"
-            selected={date}
-            onSelect={handleDateSelect}
-            initialFocus
-          />
-        </PopoverContent>
-      </Popover>
-      <LocalValuedInput
-        type="time"
-        value={timeInput}
-        onChange={handleTimeChange}
-        className="w-full"
-      />
+          {value && (
+            <Button
+              variant="ghost"
+              className="text-red-500 hover:text-red-700"
+              onClick={() => handleInputChange(selfKey, "")}
+            >
+              <Cross2Icon className="h-4 w-4" />
+            </Button>
+          )}
+        </div>
+        <input
+          id={`${selfKey}-upload`}
+          type="file"
+          accept="*/*"
+          onChange={handleFileChange}
+          className="hidden"
+        />
path: autogpt_platform/frontend/src/components/node-input-components.tsx
user: login: majdyz
body: The whole UI for the file input will be eventually redone, note that the actual input is hidden.
created_at: 2025-03-21T13:07:27Z
author_association: CONTRIBUTOR
path: autogpt_platform/backend/backend/blocks/io.py
user: login: majdyz
body: I guess we can combine date and time input?
cc @Torantulino do we want datetime input ?
created_at: 2025-03-21T13:08:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,515 @@
+from datetime import date, time
+from typing import Any, List
path: autogpt_platform/backend/backend/blocks/io.py
user: login: majdyz
body: updated
created_at: 2025-03-21T13:10:07Z
author_association: CONTRIBUTOR
path: autogpt_platform/backend/backend/blocks/io.py
user: login: majdyz
body: updated except the dropdown input
created_at: 2025-03-21T13:10:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,515 @@
+from datetime import date, time
+from typing import Any, List
+
+from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema, BlockType
+from backend.data.model import SchemaField
+from backend.util.file import MediaFile, store_media_file
+from backend.util.mock import MockObject
+from backend.util.text import TextFormatter
+
+formatter = TextFormatter()
+
+
+class AgentInputBlock(Block):
+    """
+    This block is used to provide input to the graph.
+
+    It takes in a value, name, description, default values list and bool to limit selection to default values.
+
+    It Outputs the value passed as input.
+    """
+
+    class Input(BlockSchema):
+        name: str = SchemaField(description="The name of the input.")
+        value: Any = SchemaField(
+            description="The value to be passed as input.",
+            default=None,
+        )
+        title: str | None = SchemaField(
+            description="The title of the input.", default=None, advanced=True
+        )
+        description: str | None = SchemaField(
+            description="The description of the input.",
+            default=None,
+            advanced=True,
+        )
+        placeholder_values: List[Any] = SchemaField(
+            description="The placeholder values to be passed as input.",
+            default=[],
+            advanced=True,
+        )
+        limit_to_placeholder_values: bool = SchemaField(
+            description="Whether to limit the selection to placeholder values.",
+            default=False,
+            advanced=True,
+        )
+        advanced: bool = SchemaField(
+            description="Whether to show the input in the advanced section, if the field is not required.",
+            default=False,
+            advanced=True,
+        )
+        secret: bool = SchemaField(
+            description="Whether the input should be treated as a secret.",
+            default=False,
+            advanced=True,
+        )
+
+    class Output(BlockSchema):
+        result: Any = SchemaField(description="The value passed as input.")
+
+    def __init__(self, **kwargs):
+        super().__init__(
+            **{
+                "id": "c0a8e994-ebf1-4a9c-a4d8-89d09c86741b",
+                "description": "Base block for user inputs.",
+                "input_schema": AgentInputBlock.Input,
+                "output_schema": AgentInputBlock.Output,
+                "test_input": [
+                    {
+                        "value": "Hello, World!",
+                        "name": "input_1",
+                        "description": "Example test input.",
+                        "placeholder_values": [],
+                        "limit_to_placeholder_values": False,
+                    },
+                    {
+                        "value": "Hello, World!",
+                        "name": "input_2",
+                        "description": "Example test input with placeholders.",
+                        "placeholder_values": ["Hello, World!"],
+                        "limit_to_placeholder_values": True,
+                    },
+                ],
+                "test_output": [
+                    ("result", "Hello, World!"),
+                    ("result", "Hello, World!"),
+                ],
+                "categories": {BlockCategory.INPUT, BlockCategory.BASIC},
+                "block_type": BlockType.INPUT,
+                "static_output": True,
+                **kwargs,
+            }
+        )
+
+    def run(self, input_data: Input, *args, **kwargs) -> BlockOutput:
+        yield "result", input_data.value
+
+
+class AgentOutputBlock(Block):
+    """
+    Records the output of the graph for users to see.
+
+    Behavior:
+        If `format` is provided and the `value` is of a type that can be formatted,
+        the block attempts to format the recorded_value using the `format`.
+        If formatting fails or no `format` is provided, the raw `value` is output.
+    """
+
+    class Input(BlockSchema):
+        value: Any = SchemaField(
+            description="The value to be recorded as output.",
+            default=None,
+            advanced=False,
+        )
+        name: str = SchemaField(description="The name of the output.")
+        title: str | None = SchemaField(
+            description="The title of the output.",
+            default=None,
+            advanced=True,
+        )
+        description: str | None = SchemaField(
+            description="The description of the output.",
+            default=None,
+            advanced=True,
+        )
+        format: str = SchemaField(
+            description="The format string to be used to format the recorded_value. Use Jinja2 syntax.",
+            default="",
+            advanced=True,
+        )
+        advanced: bool = SchemaField(
+            description="Whether to treat the output as advanced.",
+            default=False,
+            advanced=True,
+        )
+        secret: bool = SchemaField(
+            description="Whether the output should be treated as a secret.",
+            default=False,
+            advanced=True,
+        )
+
+    class Output(BlockSchema):
+        output: Any = SchemaField(description="The value recorded as output.")
+        name: Any = SchemaField(description="The name of the value recorded as output.")
+
+    def __init__(self):
+        super().__init__(
+            id="363ae599-353e-4804-937e-b2ee3cef3da4",
+            description="Stores the output of the graph for users to see.",
+            input_schema=AgentOutputBlock.Input,
+            output_schema=AgentOutputBlock.Output,
+            test_input=[
+                {
+                    "value": "Hello, World!",
+                    "name": "output_1",
+                    "description": "This is a test output.",
+                    "format": "{{ output_1 }}!!",
+                },
+                {
+                    "value": "42",
+                    "name": "output_2",
+                    "description": "This is another test output.",
+                    "format": "{{ output_2 }}",
+                },
+                {
+                    "value": MockObject(value="!!", key="key"),
+                    "name": "output_3",
+                    "description": "This is a test output with a mock object.",
+                    "format": "{{ output_3 }}",
+                },
+            ],
+            test_output=[
+                ("output", "Hello, World!!!"),
+                ("output", "42"),
+                ("output", MockObject(value="!!", key="key")),
+            ],
+            categories={BlockCategory.OUTPUT, BlockCategory.BASIC},
+            block_type=BlockType.OUTPUT,
+            static_output=True,
+        )
+
+    def run(self, input_data: Input, *args, **kwargs) -> BlockOutput:
+        """
+        Attempts to format the recorded_value using the fmt_string if provided.
+        If formatting fails or no fmt_string is given, returns the original recorded_value.
+        """
+        if input_data.format:
+            try:
+                yield "output", formatter.format_string(
+                    input_data.format, {input_data.name: input_data.value}
+                )
+            except Exception as e:
+                yield "output", f"Error: {e}, {input_data.value}"
+        else:
+            yield "output", input_data.value
+            yield "name", input_data.name
+
+
+class ShortTextAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: str = SchemaField(
+            description="Short text input.",
+            default="Short text",
+            json_extra={"format": "short-text"},
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: str = SchemaField(description="Short text result.")
+
+    def __init__(self):
+        super().__init__(
+            id="7fcd3bcb-8e1b-4e69-903d-32d3d4a92158",
+            description="Block for short text input (single-line).",
+            input_schema=ShortTextAgentInputBlock.Input,
+            output_schema=ShortTextAgentInputBlock.Output,
+            test_input=[
+                {
+                    "value": "Hello",
+                    "name": "short_text_1",
+                    "description": "Short text example 1",
+                    "placeholder_values": [],
+                    "limit_to_placeholder_values": False,
+                },
+                {
+                    "value": "Quick test",
+                    "name": "short_text_2",
+                    "description": "Short text example 2",
+                    "placeholder_values": ["Quick test", "Another option"],
+                    "limit_to_placeholder_values": True,
+                },
+            ],
+            test_output=[
+                ("result", "Hello"),
+                ("result", "Quick test"),
+            ],
+        )
+
+
+class LongTextAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: str = SchemaField(
+            description="Long text input (potentially multi-line).",
+            default="Longer text can go here.",
+            json_extra={"format": "long-text"},
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: str = SchemaField(description="Long text result.")
+
+    def __init__(self):
+        super().__init__(
+            id="90a56ffb-7024-4b2b-ab50-e26c5e5ab8ba",
+            description="Block for long text input (multi-line).",
+            input_schema=LongTextAgentInputBlock.Input,
+            output_schema=LongTextAgentInputBlock.Output,
+            test_input=[
+                {
+                    "value": "Lorem ipsum dolor sit amet...",
+                    "name": "long_text_1",
+                    "description": "Long text example 1",
+                    "placeholder_values": [],
+                    "limit_to_placeholder_values": False,
+                },
+                {
+                    "value": "Another multiline text input.",
+                    "name": "long_text_2",
+                    "description": "Long text example 2",
+                    "placeholder_values": ["Another multiline text input."],
+                    "limit_to_placeholder_values": True,
+                },
+            ],
+            test_output=[
+                ("result", "Lorem ipsum dolor sit amet..."),
+                ("result", "Another multiline text input."),
+            ],
+        )
+
+
+class NumberAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: int = SchemaField(
+            description="Number input.",
+            default=42,
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: int = SchemaField(description="Number result.")
+
+    def __init__(self):
+        super().__init__(
+            id="96dae2bb-97a2-41c2-bd2f-13a3b5a8ea98",
+            description="Block for number input.",
+            input_schema=NumberAgentInputBlock.Input,
+            output_schema=NumberAgentInputBlock.Output,
+            test_input=[
+                {
+                    "value": 42,
+                    "name": "number_input_1",
+                    "description": "Number example 1",
+                    "placeholder_values": [],
+                    "limit_to_placeholder_values": False,
+                },
+                {
+                    "value": 314,
+                    "name": "number_input_2",
+                    "description": "Number example 2",
+                    "placeholder_values": [314, 2718],
+                    "limit_to_placeholder_values": True,
+                },
+            ],
+            test_output=[
+                ("result", 42),
+                ("result", 314),
+            ],
+        )
+
+
+class DateAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: date = SchemaField(
+            description="Date input (YYYY-MM-DD).",
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: date = SchemaField(description="Date result.")
+
+    def __init__(self):
+        super().__init__(
+            id="7e198b09-4994-47db-8b4d-952d98241817",
+            description="Block for date input.",
+            input_schema=DateAgentInputBlock.Input,
+            output_schema=DateAgentInputBlock.Output,
+            test_input=[
+                {
+                    # If your system can parse JSON date strings to date objects
+                    "value": str(date(2025, 3, 19)),
+                    "name": "date_input_1",
+                    "description": "Example date input 1",
+                },
+                {
+                    "value": str(date(2023, 12, 31)),
+                    "name": "date_input_2",
+                    "description": "Example date input 2",
+                },
+            ],
+            test_output=[
+                ("result", date(2025, 3, 19)),
+                ("result", date(2023, 12, 31)),
+            ],
+        )
+
+
+class TimeAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: time = SchemaField(
+            description="Time input (HH:MM:SS).",
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: time = SchemaField(description="Time result.")
+
+    def __init__(self):
+        super().__init__(
+            id="2a1c757e-86cf-4c7e-aacf-060dc382e434",
+            description="Block for time input.",
+            input_schema=TimeAgentInputBlock.Input,
+            output_schema=TimeAgentInputBlock.Output,
+            test_input=[
+                {
+                    "value": str(time(9, 30, 0)),
+                    "name": "time_input_1",
+                    "description": "Time example 1",
+                },
+                {
+                    "value": str(time(23, 59, 59)),
+                    "name": "time_input_2",
+                    "description": "Time example 2",
+                },
+            ],
+            test_output=[
+                ("result", time(9, 30, 0)),
+                ("result", time(23, 59, 59)),
+            ],
+        )
+
+
+class FileUploadAgentInputBlock(AgentInputBlock):
+    """
+    A simplified file-upload block. In real usage, you might have a custom
+    file type or handle binary data. Here, we'll store a string path as the example.
+    """
+
+    class Input(AgentInputBlock.Input):
+        value: MediaFile = SchemaField(
+            description="Path or reference to an uploaded file.",
+            default=MediaFile("path/to/file.txt"),
path: autogpt_platform/backend/backend/blocks/io.py
user: login: majdyz
body: Removed
created_at: 2025-03-21T13:10:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,515 @@
+from datetime import date, time
+from typing import Any, List
+
+from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema, BlockType
+from backend.data.model import SchemaField
+from backend.util.file import MediaFile, store_media_file
+from backend.util.mock import MockObject
+from backend.util.text import TextFormatter
+
+formatter = TextFormatter()
+
+
+class AgentInputBlock(Block):
+    """
+    This block is used to provide input to the graph.
+
+    It takes in a value, name, description, default values list and bool to limit selection to default values.
+
+    It Outputs the value passed as input.
+    """
+
+    class Input(BlockSchema):
+        name: str = SchemaField(description="The name of the input.")
+        value: Any = SchemaField(
+            description="The value to be passed as input.",
+            default=None,
+        )
+        title: str | None = SchemaField(
+            description="The title of the input.", default=None, advanced=True
+        )
+        description: str | None = SchemaField(
+            description="The description of the input.",
+            default=None,
+            advanced=True,
+        )
+        placeholder_values: List[Any] = SchemaField(
+            description="The placeholder values to be passed as input.",
+            default=[],
+            advanced=True,
+        )
+        limit_to_placeholder_values: bool = SchemaField(
+            description="Whether to limit the selection to placeholder values.",
+            default=False,
+            advanced=True,
+        )
+        advanced: bool = SchemaField(
+            description="Whether to show the input in the advanced section, if the field is not required.",
+            default=False,
+            advanced=True,
+        )
+        secret: bool = SchemaField(
+            description="Whether the input should be treated as a secret.",
+            default=False,
+            advanced=True,
+        )
+
+    class Output(BlockSchema):
+        result: Any = SchemaField(description="The value passed as input.")
+
+    def __init__(self, **kwargs):
+        super().__init__(
+            **{
+                "id": "c0a8e994-ebf1-4a9c-a4d8-89d09c86741b",
+                "description": "Base block for user inputs.",
+                "input_schema": AgentInputBlock.Input,
+                "output_schema": AgentInputBlock.Output,
+                "test_input": [
+                    {
+                        "value": "Hello, World!",
+                        "name": "input_1",
+                        "description": "Example test input.",
+                        "placeholder_values": [],
+                        "limit_to_placeholder_values": False,
+                    },
+                    {
+                        "value": "Hello, World!",
+                        "name": "input_2",
+                        "description": "Example test input with placeholders.",
+                        "placeholder_values": ["Hello, World!"],
+                        "limit_to_placeholder_values": True,
+                    },
+                ],
+                "test_output": [
+                    ("result", "Hello, World!"),
+                    ("result", "Hello, World!"),
+                ],
+                "categories": {BlockCategory.INPUT, BlockCategory.BASIC},
+                "block_type": BlockType.INPUT,
+                "static_output": True,
+                **kwargs,
+            }
+        )
+
+    def run(self, input_data: Input, *args, **kwargs) -> BlockOutput:
+        yield "result", input_data.value
+
+
+class AgentOutputBlock(Block):
+    """
+    Records the output of the graph for users to see.
+
+    Behavior:
+        If `format` is provided and the `value` is of a type that can be formatted,
+        the block attempts to format the recorded_value using the `format`.
+        If formatting fails or no `format` is provided, the raw `value` is output.
+    """
+
+    class Input(BlockSchema):
+        value: Any = SchemaField(
+            description="The value to be recorded as output.",
+            default=None,
+            advanced=False,
+        )
+        name: str = SchemaField(description="The name of the output.")
+        title: str | None = SchemaField(
+            description="The title of the output.",
+            default=None,
+            advanced=True,
+        )
+        description: str | None = SchemaField(
+            description="The description of the output.",
+            default=None,
+            advanced=True,
+        )
+        format: str = SchemaField(
+            description="The format string to be used to format the recorded_value. Use Jinja2 syntax.",
+            default="",
+            advanced=True,
+        )
+        advanced: bool = SchemaField(
+            description="Whether to treat the output as advanced.",
+            default=False,
+            advanced=True,
+        )
+        secret: bool = SchemaField(
+            description="Whether the output should be treated as a secret.",
+            default=False,
+            advanced=True,
+        )
+
+    class Output(BlockSchema):
+        output: Any = SchemaField(description="The value recorded as output.")
+        name: Any = SchemaField(description="The name of the value recorded as output.")
+
+    def __init__(self):
+        super().__init__(
+            id="363ae599-353e-4804-937e-b2ee3cef3da4",
+            description="Stores the output of the graph for users to see.",
+            input_schema=AgentOutputBlock.Input,
+            output_schema=AgentOutputBlock.Output,
+            test_input=[
+                {
+                    "value": "Hello, World!",
+                    "name": "output_1",
+                    "description": "This is a test output.",
+                    "format": "{{ output_1 }}!!",
+                },
+                {
+                    "value": "42",
+                    "name": "output_2",
+                    "description": "This is another test output.",
+                    "format": "{{ output_2 }}",
+                },
+                {
+                    "value": MockObject(value="!!", key="key"),
+                    "name": "output_3",
+                    "description": "This is a test output with a mock object.",
+                    "format": "{{ output_3 }}",
+                },
+            ],
+            test_output=[
+                ("output", "Hello, World!!!"),
+                ("output", "42"),
+                ("output", MockObject(value="!!", key="key")),
+            ],
+            categories={BlockCategory.OUTPUT, BlockCategory.BASIC},
+            block_type=BlockType.OUTPUT,
+            static_output=True,
+        )
+
+    def run(self, input_data: Input, *args, **kwargs) -> BlockOutput:
+        """
+        Attempts to format the recorded_value using the fmt_string if provided.
+        If formatting fails or no fmt_string is given, returns the original recorded_value.
+        """
+        if input_data.format:
+            try:
+                yield "output", formatter.format_string(
+                    input_data.format, {input_data.name: input_data.value}
+                )
+            except Exception as e:
+                yield "output", f"Error: {e}, {input_data.value}"
+        else:
+            yield "output", input_data.value
+            yield "name", input_data.name
+
+
+class ShortTextAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: str = SchemaField(
+            description="Short text input.",
+            default="Short text",
+            json_extra={"format": "short-text"},
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: str = SchemaField(description="Short text result.")
+
+    def __init__(self):
+        super().__init__(
+            id="7fcd3bcb-8e1b-4e69-903d-32d3d4a92158",
+            description="Block for short text input (single-line).",
+            input_schema=ShortTextAgentInputBlock.Input,
+            output_schema=ShortTextAgentInputBlock.Output,
+            test_input=[
+                {
+                    "value": "Hello",
+                    "name": "short_text_1",
+                    "description": "Short text example 1",
+                    "placeholder_values": [],
+                    "limit_to_placeholder_values": False,
+                },
+                {
+                    "value": "Quick test",
+                    "name": "short_text_2",
+                    "description": "Short text example 2",
+                    "placeholder_values": ["Quick test", "Another option"],
+                    "limit_to_placeholder_values": True,
+                },
+            ],
+            test_output=[
+                ("result", "Hello"),
+                ("result", "Quick test"),
+            ],
+        )
+
+
+class LongTextAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: str = SchemaField(
+            description="Long text input (potentially multi-line).",
+            default="Longer text can go here.",
+            json_extra={"format": "long-text"},
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: str = SchemaField(description="Long text result.")
+
+    def __init__(self):
+        super().__init__(
+            id="90a56ffb-7024-4b2b-ab50-e26c5e5ab8ba",
+            description="Block for long text input (multi-line).",
+            input_schema=LongTextAgentInputBlock.Input,
+            output_schema=LongTextAgentInputBlock.Output,
+            test_input=[
+                {
+                    "value": "Lorem ipsum dolor sit amet...",
+                    "name": "long_text_1",
+                    "description": "Long text example 1",
+                    "placeholder_values": [],
+                    "limit_to_placeholder_values": False,
+                },
+                {
+                    "value": "Another multiline text input.",
+                    "name": "long_text_2",
+                    "description": "Long text example 2",
+                    "placeholder_values": ["Another multiline text input."],
+                    "limit_to_placeholder_values": True,
+                },
+            ],
+            test_output=[
+                ("result", "Lorem ipsum dolor sit amet..."),
+                ("result", "Another multiline text input."),
+            ],
+        )
+
+
+class NumberAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: int = SchemaField(
+            description="Number input.",
+            default=42,
path: autogpt_platform/backend/backend/blocks/io.py
user: login: majdyz
body: Removed
created_at: 2025-03-21T13:10:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -144,6 +144,7 @@ def SchemaField(
     depends_on: list[str] | None = None,
     image_upload: Optional[bool] = None,
     image_output: Optional[bool] = None,
+    json_extra: dict[str, Any] | None = None,
path: autogpt_platform/backend/backend/data/model.py
user: login: majdyz
body: Updated
created_at: 2025-03-21T13:11:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,515 @@
+from datetime import date, time
+from typing import Any, List
+
+from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema, BlockType
+from backend.data.model import SchemaField
+from backend.util.file import MediaFile, store_media_file
+from backend.util.mock import MockObject
+from backend.util.text import TextFormatter
+
+formatter = TextFormatter()
+
+
+class AgentInputBlock(Block):
+    """
+    This block is used to provide input to the graph.
+
+    It takes in a value, name, description, default values list and bool to limit selection to default values.
+
+    It Outputs the value passed as input.
+    """
+
+    class Input(BlockSchema):
+        name: str = SchemaField(description="The name of the input.")
+        value: Any = SchemaField(
+            description="The value to be passed as input.",
+            default=None,
+        )
+        title: str | None = SchemaField(
+            description="The title of the input.", default=None, advanced=True
+        )
+        description: str | None = SchemaField(
+            description="The description of the input.",
+            default=None,
+            advanced=True,
+        )
+        placeholder_values: List[Any] = SchemaField(
+            description="The placeholder values to be passed as input.",
+            default=[],
+            advanced=True,
+        )
+        limit_to_placeholder_values: bool = SchemaField(
+            description="Whether to limit the selection to placeholder values.",
+            default=False,
+            advanced=True,
+        )
+        advanced: bool = SchemaField(
+            description="Whether to show the input in the advanced section, if the field is not required.",
+            default=False,
+            advanced=True,
+        )
+        secret: bool = SchemaField(
+            description="Whether the input should be treated as a secret.",
+            default=False,
+            advanced=True,
+        )
+
+    class Output(BlockSchema):
+        result: Any = SchemaField(description="The value passed as input.")
+
+    def __init__(self, **kwargs):
+        super().__init__(
+            **{
+                "id": "c0a8e994-ebf1-4a9c-a4d8-89d09c86741b",
+                "description": "Base block for user inputs.",
+                "input_schema": AgentInputBlock.Input,
+                "output_schema": AgentInputBlock.Output,
+                "test_input": [
+                    {
+                        "value": "Hello, World!",
+                        "name": "input_1",
+                        "description": "Example test input.",
+                        "placeholder_values": [],
+                        "limit_to_placeholder_values": False,
+                    },
+                    {
+                        "value": "Hello, World!",
+                        "name": "input_2",
+                        "description": "Example test input with placeholders.",
+                        "placeholder_values": ["Hello, World!"],
+                        "limit_to_placeholder_values": True,
+                    },
+                ],
+                "test_output": [
+                    ("result", "Hello, World!"),
+                    ("result", "Hello, World!"),
+                ],
+                "categories": {BlockCategory.INPUT, BlockCategory.BASIC},
+                "block_type": BlockType.INPUT,
+                "static_output": True,
+                **kwargs,
+            }
+        )
+
+    def run(self, input_data: Input, *args, **kwargs) -> BlockOutput:
+        yield "result", input_data.value
+
+
+class AgentOutputBlock(Block):
+    """
+    Records the output of the graph for users to see.
+
+    Behavior:
+        If `format` is provided and the `value` is of a type that can be formatted,
+        the block attempts to format the recorded_value using the `format`.
+        If formatting fails or no `format` is provided, the raw `value` is output.
+    """
+
+    class Input(BlockSchema):
+        value: Any = SchemaField(
+            description="The value to be recorded as output.",
+            default=None,
+            advanced=False,
+        )
+        name: str = SchemaField(description="The name of the output.")
+        title: str | None = SchemaField(
+            description="The title of the output.",
+            default=None,
+            advanced=True,
+        )
+        description: str | None = SchemaField(
+            description="The description of the output.",
+            default=None,
+            advanced=True,
+        )
+        format: str = SchemaField(
+            description="The format string to be used to format the recorded_value. Use Jinja2 syntax.",
+            default="",
+            advanced=True,
+        )
+        advanced: bool = SchemaField(
+            description="Whether to treat the output as advanced.",
+            default=False,
+            advanced=True,
+        )
+        secret: bool = SchemaField(
+            description="Whether the output should be treated as a secret.",
+            default=False,
+            advanced=True,
+        )
+
+    class Output(BlockSchema):
+        output: Any = SchemaField(description="The value recorded as output.")
+        name: Any = SchemaField(description="The name of the value recorded as output.")
+
+    def __init__(self):
+        super().__init__(
+            id="363ae599-353e-4804-937e-b2ee3cef3da4",
+            description="Stores the output of the graph for users to see.",
+            input_schema=AgentOutputBlock.Input,
+            output_schema=AgentOutputBlock.Output,
+            test_input=[
+                {
+                    "value": "Hello, World!",
+                    "name": "output_1",
+                    "description": "This is a test output.",
+                    "format": "{{ output_1 }}!!",
+                },
+                {
+                    "value": "42",
+                    "name": "output_2",
+                    "description": "This is another test output.",
+                    "format": "{{ output_2 }}",
+                },
+                {
+                    "value": MockObject(value="!!", key="key"),
+                    "name": "output_3",
+                    "description": "This is a test output with a mock object.",
+                    "format": "{{ output_3 }}",
+                },
+            ],
+            test_output=[
+                ("output", "Hello, World!!!"),
+                ("output", "42"),
+                ("output", MockObject(value="!!", key="key")),
+            ],
+            categories={BlockCategory.OUTPUT, BlockCategory.BASIC},
+            block_type=BlockType.OUTPUT,
+            static_output=True,
+        )
+
+    def run(self, input_data: Input, *args, **kwargs) -> BlockOutput:
+        """
+        Attempts to format the recorded_value using the fmt_string if provided.
+        If formatting fails or no fmt_string is given, returns the original recorded_value.
+        """
+        if input_data.format:
+            try:
+                yield "output", formatter.format_string(
+                    input_data.format, {input_data.name: input_data.value}
+                )
+            except Exception as e:
+                yield "output", f"Error: {e}, {input_data.value}"
+        else:
+            yield "output", input_data.value
+            yield "name", input_data.name
+
+
+class ShortTextAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: str = SchemaField(
+            description="Short text input.",
+            default="Short text",
+            json_extra={"format": "short-text"},
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: str = SchemaField(description="Short text result.")
+
+    def __init__(self):
+        super().__init__(
+            id="7fcd3bcb-8e1b-4e69-903d-32d3d4a92158",
+            description="Block for short text input (single-line).",
+            input_schema=ShortTextAgentInputBlock.Input,
+            output_schema=ShortTextAgentInputBlock.Output,
+            test_input=[
+                {
+                    "value": "Hello",
+                    "name": "short_text_1",
+                    "description": "Short text example 1",
+                    "placeholder_values": [],
+                    "limit_to_placeholder_values": False,
+                },
+                {
+                    "value": "Quick test",
+                    "name": "short_text_2",
+                    "description": "Short text example 2",
+                    "placeholder_values": ["Quick test", "Another option"],
+                    "limit_to_placeholder_values": True,
+                },
+            ],
+            test_output=[
+                ("result", "Hello"),
+                ("result", "Quick test"),
+            ],
+        )
+
+
+class LongTextAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: str = SchemaField(
+            description="Long text input (potentially multi-line).",
+            default="Longer text can go here.",
+            json_extra={"format": "long-text"},
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: str = SchemaField(description="Long text result.")
+
+    def __init__(self):
+        super().__init__(
+            id="90a56ffb-7024-4b2b-ab50-e26c5e5ab8ba",
+            description="Block for long text input (multi-line).",
+            input_schema=LongTextAgentInputBlock.Input,
+            output_schema=LongTextAgentInputBlock.Output,
+            test_input=[
+                {
+                    "value": "Lorem ipsum dolor sit amet...",
+                    "name": "long_text_1",
+                    "description": "Long text example 1",
+                    "placeholder_values": [],
+                    "limit_to_placeholder_values": False,
+                },
+                {
+                    "value": "Another multiline text input.",
+                    "name": "long_text_2",
+                    "description": "Long text example 2",
+                    "placeholder_values": ["Another multiline text input."],
+                    "limit_to_placeholder_values": True,
+                },
+            ],
+            test_output=[
+                ("result", "Lorem ipsum dolor sit amet..."),
+                ("result", "Another multiline text input."),
+            ],
+        )
+
+
+class NumberAgentInputBlock(AgentInputBlock):
+    class Input(AgentInputBlock.Input):
+        value: int = SchemaField(
+            description="Number input.",
+            default=42,
+        )
+
+    class Output(AgentInputBlock.Output):
+        result: int = SchemaField(description="Number result.")
+
+    def __init__(self):
+        super().__init__(
+            id="96dae2bb-97a2-41c2-bd2f-13a3b5a8ea98",
+            description="Block for number input.",
+            input_schema=NumberAgentInputBlock.Input,
+            output_schema=NumberAgentInputBlock.Output,
+            test_input=[
+                {
+                    "value": 42,
+                    "name": "number_input_1",
+                    "description": "Number example 1",
+                    "placeholder_values": [],
+                    "limit_to_placeholder_values": False,
+                },
+                {
+                    "value": 314,
+                    "name": "number_input_2",
+                    "description": "Number example 2",
+                    "placeholder_values": [314, 2718],
+                    "limit_to_placeholder_values": True,
+                },
+            ],
+            test_output=[
+                ("result", 42),
+                ("result", 314),
+            ],
+        )
+
+
+class DateAgentInputBlock(AgentInputBlock):
path: autogpt_platform/backend/backend/blocks/io.py
user: login: majdyz
body: Updated
created_at: 2025-03-21T13:13:42Z
author_association: CONTRIBUTOR
path: autogpt_platform/backend/backend/blocks/io.py
user: login: Torantulino
body: We'll add some more going forward for sure but let's proceed with these for the first version and iterate as these are the one's Olivia is expecting.
created_at: 2025-03-21T16:29:22Z
author_association: MEMBER

PR comments:
user: login: netlify[bot]
created_at: 2025-03-19T14:27:24Z
body: ### <span aria-hidden="true">✅</span> Deploy Preview for *auto-gpt-docs-dev* canceled.


|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | d8ddc4af42abe31f02dfc13d2ecf6e74e7e76ade |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/auto-gpt-docs-dev/deploys/67dd66433287b20008e23207 |
author_association: NONE
user: login: qodo-code-review[bot]
created_at: 2025-03-19T14:27:29Z
body: ## PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

<table>
<tr><td>⏱️&nbsp;<strong>Estimated effort to review</strong>: 3 🔵🔵🔵⚪⚪</td></tr>
<tr><td>🧪&nbsp;<strong>PR contains tests</strong></td></tr>
<tr><td>🔒&nbsp;<strong>Security concerns</strong><br><br>

<strong>File upload vulnerability:</strong><br> The FileUploadAgentInputBlock implementation accepts any file type without validation in both the backend and frontend components. This could allow users to upload potentially malicious files. The frontend component (NodeFileInput) uses accept="*/*" which doesn't restrict file types, and there's no size limitation or content validation on the uploaded files.</td></tr>
<tr><td>⚡&nbsp;<strong>Recommended focus areas for review</strong><br><br>

<details><summary><a href='https://github.com/Significant-Gravitas/AutoGPT/pull/9657/files#diff-fa447a0f103a2933b578df696199c4ca3f306ed9719efa4adc648314093152a6R423-R436'><strong>File Upload Implementation</strong></a>

The FileUploadAgentInputBlock's run method doesn't match its Output schema. It yields "output" but the schema defines "result" as the output field. This mismatch could cause issues when the block is used.
</summary>

```python
def run(
    self,
    input_data: Input,
    *,
    graph_exec_id: str,
    **kwargs,
) -> BlockOutput:
    file_path = store_media_file(
        graph_exec_id=graph_exec_id,
        file=input_data.value,
        return_content=False,
    )
    yield "output", file_path

```

</details>

<details><summary><a href='https://github.com/Significant-Gravitas/AutoGPT/pull/9657/files#diff-b158851412132077ccf30a4e33e927307b91831dcb7c41eae1a37c2214695df5R217-R229'><strong>Incomplete Date Handling</strong></a>

The handleDateSelect function in NodeDateTimeInput doesn't actually update the date when hideTime is false. The function sets up the conditional logic but doesn't call handleInputChange in the else branch.
</summary>

```typescriptreact
const handleDateSelect = (newDate: Date | undefined) => {
  if (!newDate) return;

  if (hideTime) {
    // Only pass YYYY-MM-DD if time is hidden
    handleInputChange(selfKey, format(newDate, "yyyy-MM-dd"));
  } else {
    // Otherwise pass full date/time, but still incorporate time
    const [hours, minutes] = timeInput.split(":").map(Number);
    newDate.setHours(hours, minutes);
    handleInputChange(selfKey, newDate.toISOString());
  }
};
```

</details>

</td></tr>
</table>

author_association: NONE
user: login: AutoGPT-Agent
created_at: 2025-03-19T14:27:51Z
body: The PR has several issues:
1. The author missed checking/filling out some important information in the PR template - specifically details about their testing plan beyond just saying 'Test in respective block codes'
2. The title follows conventional commit format correctly
3. The changes are well documented in the description
4. The commits seem focused on the scope mentioned
5. No out of scope changes detected
6. Since these are new input components, no user_id check issues
7. No new frontend base routes added
author_association: CONTRIBUTOR
user: login: netlify[bot]
created_at: 2025-03-19T14:28:14Z
body: ### <span aria-hidden="true">✅</span> Deploy Preview for *auto-gpt-docs* ready!


|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | 9d138e4662f1e7345b8ae6fc57821fae748e6fb1 |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/auto-gpt-docs/deploys/67dad43fe290830008e8e4f7 |
|<span aria-hidden="true">😎</span> Deploy Preview | [https://deploy-preview-9657--auto-gpt-docs.netlify.app](https://deploy-preview-9657--auto-gpt-docs.netlify.app) |
|<span aria-hidden="true">📱</span> Preview on mobile | <details><summary> Toggle QR Code... </summary><br /><br />![QR Code](https://app.netlify.com/qr-code/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL2RlcGxveS1wcmV2aWV3LTk2NTctLWF1dG8tZ3B0LWRvY3MubmV0bGlmeS5hcHAifQ.pQdOrZ7J5J_JtNdcx-RA5qcX7NUbLuLCsqjYCcyx4Fc)<br /><br />_Use your smartphone camera to open QR code link._</details> |
---
<!-- [auto-gpt-docs Preview](https://deploy-preview-9657--auto-gpt-docs.netlify.app) -->
_To edit notification comments on pull requests, go to your [Netlify site configuration](https://app.netlify.com/sites/auto-gpt-docs/configuration/notifications#deploy-webhooks)._
author_association: NONE
user: login: deepsource-io[bot]
created_at: 2025-03-19T14:28:18Z
body: <div><p>Here's the code health analysis summary for commits <code>f01b318..d8ddc4a</code>. <a href="https://app.deepsource.com/gh/Significant-Gravitas/AutoGPT/run/bcd4d1ce-64f2-4def-81ec-3d85758eea6c/">View details on DeepSource</a>&nbsp;↗.</p><h3>Analysis Summary</h3><table><thead><tr><th>Analyzer</th><th>Status</th><th>Summary</th><th>Link</th></tr></thead><tbody><tr><td><img src="https://static.deepsource.com/analyzer_logos/javascript.svg" alt="DeepSource JavaScript Logo" width="16px" height="16px"/><strong>JavaScript</strong></td><td><span>✅&nbsp;</span><span>Success</span></td><td><div>❗ 9 occurences introduced</div><div>🎯 23 occurences resolved</div></td><td><a href="https://app.deepsource.com/gh/Significant-Gravitas/AutoGPT/run/bcd4d1ce-64f2-4def-81ec-3d85758eea6c/javascript/">View Check</a>&nbsp;↗</td></tr><tr><td><img src="https://static.deepsource.com/analyzer_logos/python.svg" alt="DeepSource Python Logo" width="16px" height="16px"/><strong>Python</strong></td><td><span>✅&nbsp;</span><span>Success</span></td><td><div>❗ 26 occurences introduced</div><div>🎯 26 occurences resolved</div></td><td><a href="https://app.deepsource.com/gh/Significant-Gravitas/AutoGPT/run/bcd4d1ce-64f2-4def-81ec-3d85758eea6c/python/">View Check</a>&nbsp;↗</td></tr></tbody></table><hr/><blockquote><div>💡 If you’re a repository administrator, you can configure the quality gates from the <a href="https://app.deepsource.com/gh/Significant-Gravitas/AutoGPT/settings/reporting">settings</a>.</div></blockquote></div>

author_association: NONE
user: login: netlify[bot]
created_at: 2025-03-19T14:29:22Z
body: ### <span aria-hidden="true">✅</span> Deploy Preview for *auto-gpt-docs* canceled.


|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | d8ddc4af42abe31f02dfc13d2ecf6e74e7e76ade |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/auto-gpt-docs/deploys/67dd6643b6a79500088a301f |
author_association: NONE
user: login: AutoGPT-Agent
created_at: 2025-03-19T14:49:27Z
body: While the PR has some positive aspects like moving input/output blocks to a dedicated io.py file and adding new input block types, the PR fails to meet the requirements in a few ways: 1) The scope in the title (block) is too vague and should be more specific like 'input-blocks' 2) The changes checklist only marks the code section items but doesn't remove the configuration section which is not applicable 3) The test plan is very minimal just saying 'Test in respective block codes' without specifics. However, these are relatively minor issues that can be addressed with updates.
author_association: CONTRIBUTOR