feat(agent_builder, agent_server): Add customizable placeholders for input fields (#7451)

- Add `SchemaField` that works like Pydantic `Field` but allows to add extra json schema values. This PR adds `placeholder` entry but it could be extended with other data.
- Render `placeholder` inside input fields if available.
- Restyle placeholders so they are visually distinct from user-entered values
This commit is contained in:
Krzysztof Czerwinski
2024-07-16 20:08:43 +01:00
committed by GitHub
parent 420e6cae2f
commit 555e113706
3 changed files with 43 additions and 7 deletions

View File

@@ -13,6 +13,9 @@ type Schema = {
enum?: string[];
items?: Schema;
additionalProperties?: { type: string };
description?: string;
placeholder?: string;
title?: string;
allOf?: any[];
anyOf?: any[];
oneOf?: any[];
@@ -168,9 +171,9 @@ const CustomNode: FC<NodeProps<CustomNodeData>> = ({ data, id }) => {
return <div className="connected-input">Connected</div>;
}
const renderClickableInput = (displayValue: string) => (
const renderClickableInput = (value: string | null = null, placeholder: string = "") => (
<div className="clickable-input" onClick={() => handleInputClick(fullKey)}>
{displayValue}
{value || <i className="text-gray-500">{placeholder}</i>}
</div>
);
@@ -259,7 +262,7 @@ const CustomNode: FC<NodeProps<CustomNodeData>> = ({ data, id }) => {
if (types.includes('string') && types.includes('null')) {
return (
<div key={fullKey} className="input-container">
{renderClickableInput(value || `Enter ${key} (optional)`)}
{renderClickableInput(value, schema.placeholder || `Enter ${key} (optional)`)}
{error && <span className="error-message">{error}</span>}
</div>
);
@@ -312,7 +315,7 @@ const CustomNode: FC<NodeProps<CustomNodeData>> = ({ data, id }) => {
</div>
) : (
<div key={fullKey} className="input-container">
{renderClickableInput(value || `Enter ${key}`)}
{renderClickableInput(value, schema.placeholder || `Enter ${key}`)}
{error && <span className="error-message">{error}</span>}
</div>
);
@@ -373,7 +376,7 @@ const CustomNode: FC<NodeProps<CustomNodeData>> = ({ data, id }) => {
default:
return (
<div key={fullKey} className="input-container">
{renderClickableInput(value ? `${key} (Complex)` : `Enter ${key} (Complex)`)}
{renderClickableInput(value ? `${key} (Complex)` : null, `Enter ${key} (Complex)`)}
{error && <span className="error-message">{error}</span>}
</div>
);

View File

@@ -8,6 +8,7 @@ from typing import TYPE_CHECKING, Iterator
from autogpt.agents.agent import Agent, AgentSettings
from autogpt.app.config import ConfigBuilder
from autogpt_server.data.block import Block, BlockFieldSecret, BlockOutput, BlockSchema
from autogpt_server.data.model import SchemaField
from forge.agent.components import AgentComponent
from forge.agent.protocols import (
CommandProvider,
@@ -76,8 +77,8 @@ class BlockAgent(Agent):
class AutoGPTAgentBlock(Block):
class Input(BlockSchema):
task: str
input: str
task: str = SchemaField(display_name="Agent Task", placeholder="e.g. Make calculation and use Output command")
input: str = SchemaField(display_name="Input data", placeholder="8 + 5")
openai_api_key: BlockFieldSecret = BlockFieldSecret(key="openai_api_key")
enabled_components: list[str] = Field(default_factory=lambda: [OutputComponent.__name__])
disabled_commands: list[str] = Field(default_factory=list)

View File

@@ -0,0 +1,32 @@
from typing import Any, Callable, Optional, TypeVar
from pydantic import Field
from pydantic_core import PydanticUndefined, PydanticUndefinedType
T = TypeVar("T")
def SchemaField(
default: T | PydanticUndefinedType = PydanticUndefined,
*args,
default_factory: Optional[Callable[[], T]] = None,
title: str = "",
description: str = "",
placeholder: str = "",
exclude: bool = False,
**kwargs,
) -> T:
json_extra: dict[str, Any] = {}
if placeholder:
json_extra["placeholder"] = placeholder
return Field(
default,
*args,
default_factory=default_factory,
title=title,
description=description,
exclude=exclude,
json_schema_extra=json_extra,
**kwargs,
)