mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-30 03:00:41 -04:00
### Why / What / How **Why:** Resolves #12875. CoPilot's agent-builder was hardcoding Google Drive file IDs into consuming blocks' `input_default` instead of wiring an `AgentGoogleDriveFileInputBlock`. A beta user hit this across **13 saved versions** of one agent. Root causes: 1. `validate_io_blocks` only accepted the literal base `AgentInputBlock` / `AgentOutputBlock` IDs, so even when CoPilot used a specialized subclass like `AgentGoogleDriveFileInputBlock` as the only input, the validator forced it to keep a throwaway base alongside — entrenching the anti-pattern. 2. Running a Drive consumer directly via CoPilot's `run_block` silently failed because the auto-credentials flow (picker attaches `_credentials_id`) existed only in the graph executor, never in CoPilot's direct-execution path. 3. Drive picker guidance lived in `agent_generation_guide.md` instead of on the blocks themselves, so it duplicated and drifted from the code. 4. Observed in a live session: when asked to read a private sheet, CoPilot refused with "share publicly or use the builder" instead of calling `run_block` and letting the picker render — the prompt rule was buried and the fallback path (omitted required picker field) returned a generic schema preview. **What:** Four coordinated platform + CoPilot improvements. No block-specific validator rules, no Drive-specific code in UI or prompt. **How:** #### 1. `validate_io_blocks` subclass support Accepts any block with `uiType == "Input"` / `"Output"` (populated from `Block.block_type` at registration). `AgentGoogleDriveFileInputBlock`, `AgentDropdownInputBlock`, `AgentTableInputBlock`, etc. stand alone. Base-ID fallback preserved for call sites that pass a minimal blocks list. #### 2. Inline picker via `run_block` - Extracted `_acquire_auto_credentials` from `backend/executor/manager.py` into shared `backend/executor/auto_credentials.py` (exports `acquire_auto_credentials` + `MissingAutoCredentialsError`). - Wired it into `backend/copilot/tools/helpers.py::execute_block`. When `_credentials_id` is present, the block executes with creds injected (chained flows work). When missing/null, `execute_block` returns the existing `SetupRequirementsResponse` — frontend's `FormRenderer` renders the picker inline via the existing `GoogleDrivePickerField`/`GoogleDrivePickerInput`. On pick, the LLM re-invokes `run_block` with the populated input — same continuation pattern as OAuth-missing-credentials. No new response types, no new continuation tool, no new frontend component. - `run_block` now short-circuits to `SetupRequirementsResponse` when missing required fields include a picker-backed field, skipping the schema-preview round trip the LLM would otherwise take. - `get_inputs_from_schema` spreads the full property schema (`**schema`) instead of whitelisting — any `format` / `json_schema_extra` / custom widget config flows through to the generic custom-field dispatch on the frontend. Future picker formats (date pickers, file pickers, etc.) work without backend changes. - Frontend `SetupRequirementsCard/helpers.ts` uses index-signature passthrough for arbitrary schema keys — no widget-specific code in that layer. #### 3. `validate_only` parameter on `run_block` `run_block(id, {})` is not always a safe probe — for blocks with zero required inputs, it executes. New `validate_only: true` parameter returns `BlockDetailsResponse` (schema + missing-input list) without executing, rendering picker cards, or charging credits. Same response shape as the existing schema preview — no new branch, just an extra condition on the existing one. LLM uses this for pre-flight when it's unsure whether a block has required inputs. #### 4. Block-local picker guidance Agent-generation picker guidance relocated from the guide onto the blocks themselves — surfaced at `find_block` time, exactly when the LLM decides to wire a picker-backed consumer: - `GoogleDriveFileField` (shared factory for every Drive field on Sheets/Docs/etc.) appends a standard hint to the caller's description covering: feed from the specialized input block, never hardcode (even one parsed from a URL), picker is the only credential source. - `AgentGoogleDriveFileInputBlock`'s block description now covers when it's required, the `allowed_views` mapping, wiring direction, and a concrete link-shape example. - `agent_generation_guide.md` loses the dedicated 71-line Drive section. The IO-blocks section now tells the LLM specialized subclasses satisfy the requirement and carry their own usage guidance in block/field descriptions — read them when `find_block` surfaces a match. - New "Picker-backed inputs via `run_block`" section in the CoPilot prompt, written generically (picker fields detected via `format` / `auto_credentials` schema hints, no provider names hardcoded) — covers: don't ask the user for URLs/IDs, don't refuse private-resource asks, chained picker objects pass through as-is. - Sharpened `MissingAutoCredentialsError` message so when a bare ID reaches execution, the error explicitly tells the LLM the picker renders inline (not "ask the user for something"). ### Changes 🏗️ - `backend/copilot/tools/agent_generator/validator.py` — `_collect_io_block_ids` + subclass-aware `validate_io_blocks`. - `backend/executor/auto_credentials.py` (new) — shared `acquire_auto_credentials` + `MissingAutoCredentialsError`. - `backend/executor/manager.py` — imports from the shared module, drops the local copy. - `backend/copilot/tools/helpers.py` — `execute_block` calls `acquire_auto_credentials`, merges kwargs, releases locks in `finally`, returns `SetupRequirementsResponse` on missing creds. `get_inputs_from_schema` spreads the full property schema. - `backend/copilot/tools/run_block.py` — picker-field short-circuit + `validate_only` parameter. - `backend/copilot/prompting.py` — "Picker-backed inputs via `run_block`" + "Pre-flight with `validate_only`" sections. - `backend/blocks/google/_drive.py` — `GoogleDriveFileField` appends the agent-builder hint to every Drive consumer's description. - `backend/blocks/io.py` — `AgentGoogleDriveFileInputBlock` description expanded. - `backend/copilot/sdk/agent_generation_guide.md` — Drive section removed, IO-blocks subclass note expanded. - `frontend/.../SetupRequirementsCard/helpers.ts` — index-signature passthrough for arbitrary schema keys; schema fields propagate into the generated RJSF schema. - Tests: new `TestExecuteBlockAutoCredentials` (4 cases) + `validate_only` + picker-short-circuit cases in `run_block_test.py`; `manager_auto_credentials_test.py` moved to new import path; 6 new frontend cases in `SetupRequirementsCard/__tests__/helpers.test.ts` covering schema passthrough. - Also: one-line hoist of `import secrets` in `backend/integrations/managed_providers/ayrshare.py` — ruff E402 introduced by #12883 was blocking our lint post-merge. ### 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: - [x] Backend unit suites: validator_test (48), helpers_test (40), run_block_test (19), manager_auto_credentials_test (15) — **all green** - [x] Frontend `SetupRequirementsCard` helpers — **75/75 pass** (including 6 new passthrough cases) - [x] `poetry run format` (ruff + isort + black) clean on touched files (pre-existing pyright errors in unrelated `graphiti_core` / `StreamEvent` / etc. files not introduced by this PR) - [x] Live CoPilot chat on dev-builder confirmed the setup card renders `custom/google_drive_picker_field` for a Drive consumer block called via `run_block` - [x] Live agent-generation confirmed CoPilot creates a subclass-only agent (`AgentGoogleDriveFileInputBlock` → `GoogleSheetsReadBlock` → `AgentOutputBlock`) with no throwaway base `AgentInputBlock` #### For configuration changes: - [x] N/A — no config changes --------- Co-authored-by: majdyz <zamil.majdy@agpt.co>