mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-02-10 06:45:28 -05:00
Filters out blocks that are unsuitable for standalone execution from
CoPilot's block search and execution. These blocks serve graph-specific
purposes and will either fail, hang, or confuse users when run outside
of a graph context.
**Important:** This does NOT affect the Builder UI which uses
`load_all_blocks()` directly.
### Changes 🏗️
- **find_block.py**: Added `EXCLUDED_BLOCK_TYPES` and
`EXCLUDED_BLOCK_IDS` constants, skip excluded blocks in search results
- **run_block.py**: Added execution guard that returns clear error
message for excluded blocks
- **content_handlers.py**: Added filtering to
`BlockHandler.get_missing_items()` and `get_stats()` to prevent indexing
excluded blocks
**Excluded by BlockType:**
| BlockType | Reason |
|-----------|--------|
| `INPUT` | Graph interface definition - data enters via chat, not graph
inputs |
| `OUTPUT` | Graph interface definition - data exits via chat, not graph
outputs |
| `WEBHOOK` | Wait for external events - would hang forever in CoPilot |
| `WEBHOOK_MANUAL` | Same as WEBHOOK |
| `NOTE` | Visual annotation only - no runtime behavior |
| `HUMAN_IN_THE_LOOP` | Pauses for human approval - CoPilot IS
human-in-the-loop |
| `AGENT` | AgentExecutorBlock requires graph context - use `run_agent`
tool instead |
**Excluded by ID:**
| Block | Reason |
|-------|--------|
| `SmartDecisionMakerBlock` | Dynamically discovers downstream blocks
via graph topology |
### 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:
- [ ] Search for "input" in CoPilot - should NOT return AgentInputBlock
variants
- [ ] Search for "output" in CoPilot - should NOT return
AgentOutputBlock
- [ ] Search for "webhook" in CoPilot - should NOT return trigger blocks
- [ ] Search for "human" in CoPilot - should NOT return
HumanInTheLoopBlock
- [ ] Search for "decision" in CoPilot - should NOT return
SmartDecisionMakerBlock
- [ ] Verify functional blocks still appear (e.g., "email", "http",
"text")
- [ ] Verify Builder UI still shows ALL blocks (no regression)
#### For configuration changes:
- [x] `.env.default` is updated or already compatible with my changes
- [x] `docker-compose.yml` is updated or already compatible with my
changes
- [x] I have included a list of my configuration changes in the PR
description (under **Changes**)
No configuration changes required.
---
Resolves: [SECRT-1831](https://linear.app/autogpt/issue/SECRT-1831)
🤖 Generated with [Claude Code](https://claude.ai/code)
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Behavior change is limited to CoPilot’s block discovery/execution
guards and is covered by new tests; main risk is inadvertently excluding
a block that should be runnable.
>
> **Overview**
> CoPilot now **filters out graph-only blocks** from `find_block`
results and prevents them from being executed via `run_block`, returning
a clear error when a user attempts to run an excluded block.
>
> `find_block` introduces explicit exclusion lists (by `BlockType` and a
specific block ID), over-fetches search results to maintain up to 10
usable matches after filtering, and adds debug logging when results are
reduced. New unit tests cover both the search filtering and the
`run_block` execution guard; a minor cleanup removes an unused `pytest`
import in `execution_queue_test.py`.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
bc50755dcf. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Nicholas Tindle <ntindle@users.noreply.github.com>
Co-authored-by: Otto <otto@agpt.co>
59 lines
1.3 KiB
Python
59 lines
1.3 KiB
Python
"""Tests for ExecutionQueue thread-safety."""
|
|
|
|
import queue
|
|
import threading
|
|
|
|
from backend.data.execution import ExecutionQueue
|
|
|
|
|
|
def test_execution_queue_uses_stdlib_queue():
|
|
"""Verify ExecutionQueue uses queue.Queue (not multiprocessing)."""
|
|
q = ExecutionQueue()
|
|
assert isinstance(q.queue, queue.Queue)
|
|
|
|
|
|
def test_basic_operations():
|
|
"""Test add, get, empty, and get_or_none."""
|
|
q = ExecutionQueue()
|
|
|
|
assert q.empty() is True
|
|
assert q.get_or_none() is None
|
|
|
|
result = q.add("item1")
|
|
assert result == "item1"
|
|
assert q.empty() is False
|
|
|
|
item = q.get()
|
|
assert item == "item1"
|
|
assert q.empty() is True
|
|
|
|
|
|
def test_thread_safety():
|
|
"""Test concurrent access from multiple threads."""
|
|
q = ExecutionQueue()
|
|
results = []
|
|
num_items = 100
|
|
|
|
def producer():
|
|
for i in range(num_items):
|
|
q.add(f"item_{i}")
|
|
|
|
def consumer():
|
|
count = 0
|
|
while count < num_items:
|
|
item = q.get_or_none()
|
|
if item is not None:
|
|
results.append(item)
|
|
count += 1
|
|
|
|
producer_thread = threading.Thread(target=producer)
|
|
consumer_thread = threading.Thread(target=consumer)
|
|
|
|
producer_thread.start()
|
|
consumer_thread.start()
|
|
|
|
producer_thread.join(timeout=5)
|
|
consumer_thread.join(timeout=5)
|
|
|
|
assert len(results) == num_items
|