mirror of
https://github.com/Significant-Gravitas/Auto-GPT.git
synced 2025-01-07 03:17:23 +08:00
feat(blocks): Add depends_on
support for input fields (#8852)
- Resolves part of #8731 ### Changes - Added `depends_on` parameter to SchemaField in `model.py` to specify field dependencies. - Updated `useAgentGraph` hook to validate input fields based on their dependencies, ensuring required fields are set when dependent fields are filled. - Modified `BlockIOSubSchemaMeta` to include `depends_on` as an optional property. https://github.com/user-attachments/assets/64fd47b3-34dc-48fa-ad90-1c9c5cd4c4a3 --------- Co-authored-by: Zamil Majdy <zamil.majdy@agpt.co> Co-authored-by: Nicholas Tindle <nicholas.tindle@agpt.co>
This commit is contained in:
parent
2fe6eb1df1
commit
569222e9cd
@ -257,7 +257,7 @@ class GraphModel(Graph):
|
||||
for link in self.links:
|
||||
input_links[link.sink_id].append(link)
|
||||
|
||||
# Nodes: required fields are filled or connected
|
||||
# Nodes: required fields are filled or connected and dependencies are satisfied
|
||||
for node in self.nodes:
|
||||
block = get_block(node.block_id)
|
||||
if block is None:
|
||||
@ -278,6 +278,38 @@ class GraphModel(Graph):
|
||||
f"Node {block.name} #{node.id} required input missing: `{name}`"
|
||||
)
|
||||
|
||||
# Get input schema properties and check dependencies
|
||||
input_schema = block.input_schema.model_fields
|
||||
required_fields = block.input_schema.get_required_fields()
|
||||
|
||||
def has_value(name):
|
||||
return (
|
||||
node is not None
|
||||
and name in node.input_default
|
||||
and node.input_default[name] is not None
|
||||
and str(node.input_default[name]).strip() != ""
|
||||
) or (name in input_schema and input_schema[name].default is not None)
|
||||
|
||||
# Validate dependencies between fields
|
||||
for field_name, field_info in input_schema.items():
|
||||
|
||||
# Apply input dependency validation only on run & field with depends_on
|
||||
json_schema_extra = field_info.json_schema_extra or {}
|
||||
dependencies = json_schema_extra.get("depends_on", [])
|
||||
if not for_run or not dependencies:
|
||||
continue
|
||||
|
||||
# Check if dependent field has value in input_default
|
||||
field_has_value = has_value(field_name)
|
||||
field_is_required = field_name in required_fields
|
||||
|
||||
# Check for missing dependencies when dependent field is present
|
||||
missing_deps = [dep for dep in dependencies if not has_value(dep)]
|
||||
if missing_deps and (field_has_value or field_is_required):
|
||||
raise ValueError(
|
||||
f"Node {block.name} #{node.id}: Field `{field_name}` requires [{', '.join(missing_deps)}] to be set"
|
||||
)
|
||||
|
||||
node_map = {v.id: v for v in self.nodes}
|
||||
|
||||
def is_static_output_block(nid: str) -> bool:
|
||||
|
@ -138,6 +138,7 @@ def SchemaField(
|
||||
secret: bool = False,
|
||||
exclude: bool = False,
|
||||
hidden: Optional[bool] = None,
|
||||
depends_on: list[str] | None = None,
|
||||
**kwargs,
|
||||
) -> T:
|
||||
json_extra = {
|
||||
@ -147,6 +148,7 @@ def SchemaField(
|
||||
"secret": secret,
|
||||
"advanced": advanced,
|
||||
"hidden": hidden,
|
||||
"depends_on": depends_on,
|
||||
}.items()
|
||||
if v is not None
|
||||
}
|
||||
|
@ -404,6 +404,54 @@ export default function useAgentGraph(
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Object.entries(node.data.inputSchema.properties || {}).forEach(
|
||||
([key, schema]) => {
|
||||
if (schema.depends_on) {
|
||||
const dependencies = schema.depends_on;
|
||||
|
||||
// Check if dependent field has value
|
||||
const hasValue =
|
||||
inputData[key] != null ||
|
||||
("default" in schema && schema.default != null);
|
||||
|
||||
const mustHaveValue = node.data.inputSchema.required?.includes(key);
|
||||
|
||||
// Check for missing dependencies when dependent field is present
|
||||
const missingDependencies = dependencies.filter(
|
||||
(dep) =>
|
||||
!inputData[dep as keyof typeof inputData] ||
|
||||
String(inputData[dep as keyof typeof inputData]).trim() === "",
|
||||
);
|
||||
|
||||
if ((hasValue || mustHaveValue) && missingDependencies.length > 0) {
|
||||
setNestedProperty(
|
||||
errors,
|
||||
key,
|
||||
`Requires ${missingDependencies.join(", ")} to be set`,
|
||||
);
|
||||
errorMessage = `Field ${key} requires ${missingDependencies.join(", ")} to be set`;
|
||||
}
|
||||
|
||||
// Check if field is required when dependencies are present
|
||||
const hasAllDependencies = dependencies.every(
|
||||
(dep) =>
|
||||
inputData[dep as keyof typeof inputData] &&
|
||||
String(inputData[dep as keyof typeof inputData]).trim() !== "",
|
||||
);
|
||||
|
||||
if (hasAllDependencies && !hasValue) {
|
||||
setNestedProperty(
|
||||
errors,
|
||||
key,
|
||||
`${key} is required when ${dependencies.join(", ")} are set`,
|
||||
);
|
||||
errorMessage = `${key} is required when ${dependencies.join(", ")} are set`;
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Set errors
|
||||
setNodes((nodes) => {
|
||||
return nodes.map((n) => {
|
||||
|
@ -56,6 +56,7 @@ export type BlockIOSubSchemaMeta = {
|
||||
description?: string;
|
||||
placeholder?: string;
|
||||
advanced?: boolean;
|
||||
depends_on?: string[];
|
||||
hidden?: boolean;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user