feat(frontend): Add field extraction handle for block with object output (#8900)

This addresses
https://github.com/Significant-Gravitas/AutoGPT/issues/8741

We have quite a few blocks with (object) outputs. The only way to really
use these is to use a "Find In Dictionary" block to pick out that
property.

If the structure of the output object is known, we should expose the
properties of the object directly as sub-outputs. This will make a huge
difference in UX and make using these blocks much much easier.

### Changes 🏗️

Recursively flatten object fields into output node handles

<img width="637" alt="image"
src="https://github.com/user-attachments/assets/dac1f691-9866-4bb7-96b7-20fa6ddbb616">
<img width="773" alt="image"
src="https://github.com/user-attachments/assets/f8e7f97c-b245-40bd-b84f-2c044f5f9e23">


### Checklist 📋

#### For code changes:
- [ ] I have clearly listed my changes in the PR description
- [ ] I have made a test plan
- [ ] I have tested my changes according to the test plan:
  <!-- Put your test plan here: -->
  - [ ] ...

<details>
  <summary>Example test plan</summary>
  
  - [ ] Create from scratch and execute an agent with at least 3 blocks
- [ ] Import an agent from file upload, and confirm it executes
correctly
  - [ ] Upload agent to marketplace
- [ ] Import an agent from marketplace and confirm it executes correctly
  - [ ] Edit an agent from monitor, and confirm it executes correctly
</details>

#### For configuration changes:
- [ ] `.env.example` is updated or already compatible with my changes
- [ ] `docker-compose.yml` is updated or already compatible with my
changes
- [ ] I have included a list of my configuration changes in the PR
description (under **Changes**)

<details>
  <summary>Examples of configuration changes</summary>

  - Changing ports
  - Adding new services that need to communicate with each other
  - Secrets or environment variable changes
  - New or infrastructure changes such as databases
</details>

Co-authored-by: Nicholas Tindle <nicholas.tindle@agpt.co>
This commit is contained in:
Zamil Majdy 2024-12-09 15:47:48 -06:00 committed by GitHub
parent e6d728b081
commit 79c0c314e2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 36 additions and 12 deletions

View File

@ -13,6 +13,7 @@ import InputModalComponent from "./InputModalComponent";
import OutputModalComponent from "./OutputModalComponent";
import {
BlockIORootSchema,
BlockIOSubSchema,
BlockIOStringSubSchema,
Category,
NodeExecutionResult,
@ -167,17 +168,38 @@ export function CustomNode({
nodeType === BlockUIType.NOTE
)
return null;
const keys = Object.keys(schema.properties);
return keys.map((key) => (
<div key={key}>
<NodeHandle
keyName={key}
isConnected={isOutputHandleConnected(key)}
schema={schema.properties[key]}
side="right"
/>
</div>
));
const renderHandles = (
propSchema: { [key: string]: BlockIOSubSchema },
keyPrefix = "",
titlePrefix = "",
) => {
return Object.keys(propSchema).map((propKey) => {
const fieldSchema = propSchema[propKey];
const fieldTitle =
titlePrefix + (fieldSchema.title || beautifyString(propKey));
return (
<div key={propKey}>
<NodeHandle
title={fieldTitle}
keyName={`${keyPrefix}${propKey}`}
isConnected={isOutputHandleConnected(propKey)}
schema={fieldSchema}
side="right"
/>
{"properties" in fieldSchema &&
renderHandles(
fieldSchema.properties,
`${keyPrefix}${propKey}_#_`,
`${fieldTitle}.`,
)}
</div>
);
});
};
return renderHandles(schema.properties);
};
const generateInputHandles = (

View File

@ -10,6 +10,7 @@ type HandleProps = {
isConnected: boolean;
isRequired?: boolean;
side: "left" | "right";
title?: string;
};
const NodeHandle: FC<HandleProps> = ({
@ -18,6 +19,7 @@ const NodeHandle: FC<HandleProps> = ({
isConnected,
isRequired,
side,
title,
}) => {
const typeName: Record<string, string> = {
string: "text",
@ -34,7 +36,7 @@ const NodeHandle: FC<HandleProps> = ({
const label = (
<div className="flex flex-grow flex-row">
<span className="text-m green flex items-end pr-2 text-gray-900">
{schema.title || beautifyString(keyName.toLowerCase())}
{title || schema.title || beautifyString(keyName.toLowerCase())}
{isRequired ? "*" : ""}
</span>
<span className={`${typeClass} flex items-end`}>