-
Notifications
You must be signed in to change notification settings - Fork 46.1k
feat(platform): add Human In The Loop block with review workflow #11380
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
majdyz
wants to merge
49
commits into
dev
Choose a base branch
from
feat/human-in-the-loop-block
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+3,155
−93
Open
Changes from 39 commits
Commits
Show all changes
49 commits
Select commit
Hold shift + click to select a range
b8cb244
feat(platform): add Human In The Loop block with review workflow
majdyz a27a445
feat(platform): Implement Human In The Loop block with comprehensive …
majdyz a82449c
fix(backend): Fix HumanInTheLoopBlock test failure due to missing gra…
majdyz 72f757b
fix(backend): Address critical security and reliability issues in Hum…
majdyz 807f6e2
fix(backend): Fix critical mock issue - block now uses real workflow …
majdyz d2597c4
feat(backend/frontend): Address critical HITL security and UX issues
majdyz 480489c
style: apply lint fixes
majdyz 96219aa
style: apply lint fixes to manager.py
majdyz a625fc0
fix(backend): optimize execution queue and fix API route conflicts
majdyz e0ef5e3
feat(frontend): Add maxLength validation to HITL review message textarea
majdyz b494f3e
fix(frontend): Include WAITING_FOR_REVIEW in active status for Activi…
majdyz 120746a
fix(backend): Improve HITL block execution status handling
majdyz 599582e
feat(backend): Use Literal type for HITL block status field
majdyz ee7edc5
refactor(backend): Move HITL database operations to data layer
majdyz 8780290
feat(backend): Add status transition validation and improve architecture
majdyz 59df230
remove init
majdyz 8cade32
refactor(backend): Improve Human In The Loop block architecture and d…
majdyz d2e630a
refactor(backend/executor): Simplify node status update using batch p…
majdyz f05d480
refactor(backend/data): Inline wrapper methods in human_review.py
majdyz 28ca485
refactor(backend): Major cleanup of human_review.py and execution.py
majdyz e33a362
cleanuo
majdyz 6f17a95
refactor(backend): Replace chaotic union type with structured Pending…
majdyz d13a5db
refactor(backend): Clean up review model with proper from_db pattern
majdyz 9998610
style(backend): Apply code formatting to review models
majdyz 5dc4a0e
refactor(backend): Restructure human review data model to eliminate c…
majdyz 6de947f
refactor(backend): Improve consistency and remove unnecessary complexity
majdyz d70d536
refactor(backend): Inline single-use functions
majdyz f8dd0c0
refactor(backend): Optimize HITL system with improved database patterns
majdyz 9ae926f
cleanuo
majdyz 38b080c
cleanuo
majdyz ea05cf4
fix(frontend): Update PendingReviewCard to match API response structure
majdyz 48add47
fix(frontend): Update components to use regenerated API types
majdyz 796c27e
refactor(platform): Improve API design and exception handling
majdyz a8fead6
fix(frontend): Fix stale closure issue in FloatingReviewsPanel
majdyz 75a98b7
Merge branch 'dev' into feat/human-in-the-loop-block
majdyz 4b0e971
fix(backend): Add critical security fixes for human review system
majdyz 5dda783
fix(backend): Add missing INCOMPLETE status transition rules
majdyz 81de4e5
feat(platform): Enhance Human-in-the-Loop execution resume functionality
majdyz d0ff313
Merge branch 'dev' of github.com:Significant-Gravitas/AutoGPT into fe…
majdyz 12145fa
Merge branch 'dev' of github.com:Significant-Gravitas/AutoGPT into fe…
majdyz f600574
feat(platform): enhance human-in-the-loop functionality with real-tim…
majdyz 55b9113
fix ci
majdyz 9f1e27a
revert(backend): revert unintended store changes from HITL implementa…
majdyz 23e93fc
feat(frontend): add Human-in-the-Loop block to beta blocks feature flag
majdyz 4ce2f45
Merge branch 'dev' into feat/human-in-the-loop-block
majdyz 39ec38f
Merge branch 'feat/human-in-the-loop-block' of github.com:Significant…
majdyz 8fa5762
feat(platform): enhance Human-in-the-Loop block with improved review UX
majdyz 3c71761
fix(frontend): remove unused reviewData prop from PendingReviewsList
majdyz 0422173
refactor(frontend): critical simplification and cleanup of HITL compo…
majdyz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
156 changes: 156 additions & 0 deletions
156
autogpt_platform/backend/backend/blocks/human_in_the_loop.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,156 @@ | ||
| import logging | ||
| from typing import Any, Literal | ||
|
|
||
| from prisma.enums import ReviewStatus | ||
|
|
||
| from backend.data.block import ( | ||
| Block, | ||
| BlockCategory, | ||
| BlockOutput, | ||
| BlockSchemaInput, | ||
| BlockSchemaOutput, | ||
| ) | ||
| from backend.data.execution import ExecutionStatus | ||
| from backend.data.human_review import ReviewResult | ||
| from backend.data.model import SchemaField | ||
| from backend.util.clients import get_database_manager_async_client | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| class HumanInTheLoopBlock(Block): | ||
| """ | ||
| This block pauses execution and waits for human approval or modification of the data. | ||
|
|
||
| When executed, it creates a pending review entry and sets the node execution status | ||
| to REVIEW. The execution will remain paused until a human user either: | ||
| - Approves the data (with or without modifications) | ||
| - Rejects the data | ||
|
|
||
| This is useful for workflows that require human validation or intervention before | ||
| proceeding to the next steps. | ||
| """ | ||
|
|
||
| class Input(BlockSchemaInput): | ||
| data: Any = SchemaField(description="The data to be reviewed by a human user") | ||
| message: str = SchemaField( | ||
| description="Instructions or message for the human reviewer", | ||
| default="Please review and approve or modify the following data:", | ||
| ) | ||
| editable: bool = SchemaField( | ||
| description="Whether the human reviewer can edit the data", | ||
| default=True, | ||
| advanced=True, | ||
| ) | ||
|
|
||
| class Output(BlockSchemaOutput): | ||
| reviewed_data: Any = SchemaField( | ||
| description="The data after human review (may be modified)" | ||
| ) | ||
| status: Literal["approved", "rejected"] = SchemaField( | ||
| description="Status of the review: 'approved' or 'rejected'" | ||
| ) | ||
| review_message: str = SchemaField( | ||
| description="Any message provided by the reviewer", default="" | ||
| ) | ||
|
|
||
| def __init__(self): | ||
| super().__init__( | ||
| id="8b2a7b3c-6e9d-4a5f-8c1b-2e3f4a5b6c7d", | ||
| description="Pause execution and wait for human approval or modification of data", | ||
| categories={BlockCategory.BASIC}, | ||
| input_schema=HumanInTheLoopBlock.Input, | ||
| output_schema=HumanInTheLoopBlock.Output, | ||
| test_input={ | ||
| "data": {"name": "John Doe", "age": 30}, | ||
| "message": "Please verify this user data", | ||
| "editable": True, | ||
| }, | ||
| test_output=[ | ||
| ("reviewed_data", {"name": "John Doe", "age": 30}), | ||
| ("status", "approved"), | ||
| ("review_message", ""), | ||
| ], | ||
| test_mock={ | ||
| "get_or_create_human_review": lambda *args, **kwargs: ReviewResult( | ||
| data={"name": "John Doe", "age": 30}, | ||
| status=ReviewStatus.APPROVED, | ||
| message="", | ||
| processed=False, | ||
| node_exec_id="test-node-exec-id", | ||
| ), | ||
| "update_node_execution_status": lambda *args, **kwargs: None, | ||
| }, | ||
| ) | ||
|
|
||
| async def run( | ||
| self, | ||
| input_data: Input, | ||
| *, | ||
| user_id: str, | ||
| node_exec_id: str, | ||
| graph_exec_id: str, | ||
| graph_id: str, | ||
| graph_version: int, | ||
| **kwargs, | ||
| ) -> BlockOutput: | ||
| """ | ||
| Execute the Human In The Loop block. | ||
|
|
||
| This method uses one function to handle the complete workflow - checking existing reviews | ||
| and creating pending ones as needed. | ||
| """ | ||
| try: | ||
| logger.debug(f"HITL block executing for node {node_exec_id}") | ||
|
|
||
| # Use the data layer to handle the complete workflow | ||
| db_client = get_database_manager_async_client() | ||
| result = await db_client.get_or_create_human_review( | ||
| user_id=user_id, | ||
| node_exec_id=node_exec_id, | ||
| graph_exec_id=graph_exec_id, | ||
| graph_id=graph_id, | ||
| graph_version=graph_version, | ||
| input_data=input_data.data, | ||
| message=input_data.message, | ||
| editable=input_data.editable, | ||
| ) | ||
| except Exception as e: | ||
| logger.error(f"Error in HITL block for node {node_exec_id}: {str(e)}") | ||
| raise | ||
|
|
||
| # Check if we're waiting for human input | ||
| if result is None: | ||
| logger.info( | ||
| f"HITL block pausing execution for node {node_exec_id} - awaiting human review" | ||
| ) | ||
| try: | ||
| # Set node status to REVIEW so execution manager can't mark it as COMPLETED | ||
| # The VALID_STATUS_TRANSITIONS will then prevent any unwanted status changes | ||
| await db_client.update_node_execution_status( | ||
| node_exec_id=node_exec_id, | ||
| status=ExecutionStatus.REVIEW, | ||
| ) | ||
| # Execution pauses here until API routes process the review | ||
| return | ||
| except Exception as e: | ||
| logger.error( | ||
| f"Failed to update node status for HITL block {node_exec_id}: {str(e)}" | ||
| ) | ||
| raise | ||
|
|
||
| # Review is complete (approved or rejected) - check if unprocessed | ||
| if not result.processed: | ||
| # Mark as processed before yielding | ||
| await db_client.update_review_processed_status( | ||
| node_exec_id=node_exec_id, processed=True | ||
| ) | ||
|
|
||
| # Yield the results | ||
| if result.status == ReviewStatus.APPROVED: | ||
| yield "reviewed_data", result.data | ||
| yield "status", "approved" | ||
| yield "review_message", result.message | ||
| elif result.status == ReviewStatus.REJECTED: | ||
| yield "status", "rejected" | ||
| yield "review_message", result.message | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.