Skip to content

feat(copilot): Auto-save binary block outputs to workspace#11968

Closed
Otto-AGPT wants to merge 3 commits intodevfrom
otto/secrt-1887-copilot-auto-save-binary-outputs-from-all-blocks
Closed

feat(copilot): Auto-save binary block outputs to workspace#11968
Otto-AGPT wants to merge 3 commits intodevfrom
otto/secrt-1887-copilot-auto-save-binary-outputs-from-all-blocks

Conversation

@Otto-AGPT
Copy link
Contributor

Summary

When CoPilot executes blocks that produce binary outputs (PDFs, images, charts), the data was previously returned as raw base64 strings. This caused:

  1. Massive token waste — The LLM re-typed entire base64 strings when saving files (observed: 17,000+ output tokens for a single PDF)
  2. Potential data corruption — LLM may truncate or hallucinate characters in long base64 strings
  3. Poor UX — Users waited while the LLM slowly typed out binary data character by character

Solution

This PR intercepts block outputs in run_block.py (the single entry point for all block executions in CoPilot) and:

  1. Detects binary fields (png, jpeg, pdf, svg)
  2. Automatically saves content > 1KB to the user's workspace
  3. Replaces the base64 data with workspace:// references

Implementation

File Change
binary_output_processor.py New module (~80 lines) - handles detection, deduplication, and saving
run_block.py +1 import, +5 lines - integration point
test_binary_output_processor.py New test file (~80 lines)

Key Design Decisions

  • Hash-based deduplication: Same content appearing in multiple output fields saves only once
  • 1KB threshold: Small outputs aren't worth the overhead
  • Graceful degradation: If save fails, original data is preserved
  • Field-name detection: Only processes known binary fields — conservative approach

Expected Impact

Metric Before After
Output tokens for PDF 5,000-17,000+ < 500
Data integrity Risk of corruption 100% intact
File availability Manual save required Immediate

Testing

  • Unit tests cover: base64 decoding, nested structures, deduplication, failure handling
  • Manual verification of imports and core functionality

Fixes SECRT-1887

When blocks produce binary outputs (PNG, JPEG, PDF, SVG), the data is now
automatically saved to the user's workspace and replaced with workspace://
references. This prevents:

- Massive token waste from LLM re-typing base64 strings (17,000+ tokens)
- Potential data corruption from truncation/hallucination
- Poor UX from slow character-by-character output

Implementation:
- New binary_output_processor.py module with hash-based deduplication
- Integration in run_block.py (single entry point for all block executions)
- Graceful degradation: failures preserve original data

Fixes SECRT-1887
@Otto-AGPT Otto-AGPT requested a review from a team as a code owner February 4, 2026 22:26
@Otto-AGPT Otto-AGPT requested review from Pwuts and Swiftyos and removed request for a team February 4, 2026 22:26
@github-project-automation github-project-automation bot moved this to 🆕 Needs initial review in AutoGPT development kanban Feb 4, 2026
@github-actions github-actions bot added platform/backend AutoGPT Platform - Back end size/l labels Feb 4, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 4, 2026

Walkthrough

New code auto-saves large binary/text outputs from block execution to the workspace, replaces them with deterministic workspace:// references (deduplicated by SHA-256), and integrates this processing into the block execution flow before returning outputs.

Changes

Cohort / File(s) Summary
Binary Output Processor
autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py
New module: detects saveable fields (png, jpeg, pdf, svg), uses a 1024-char threshold, recursively traverses outputs, computes SHA-256 dedupe keys, decodes base64 (including data URIs), saves files via WorkspaceManager, and returns workspace:// references. Preserves original content on save/decode failures.
Run Block Integration
autogpt_platform/backend/backend/api/features/chat/tools/run_block.py
Imports process_binary_outputs and WorkspaceManager; after block execution, creates a WorkspaceManager, invokes process_binary_outputs(...), and returns processed outputs in BlockOutputResponse.
Tests
autogpt_platform/backend/backend/api/features/chat/tools/test_binary_output_processor.py
New tests covering base64 decoding variants, large vs small content handling, deduplication, save-failure fallback, nested dict/list traversal, and list item processing using a workspace_manager fixture to mock storage.

Sequence Diagram

sequenceDiagram
    participant Client as Client/Caller
    participant RunBlock as run_block
    participant BinProc as binary_output_processor
    participant WorkspaceMgr as WorkspaceManager
    participant FileStore as File Storage

    Client->>RunBlock: Execute block
    RunBlock->>RunBlock: Run block logic -> collect outputs
    RunBlock->>BinProc: process_binary_outputs(outputs, workspace_manager, block_name)
    BinProc->>BinProc: Traverse outputs (dicts/lists), identify saveable fields & size
    alt Large content
        BinProc->>BinProc: Compute SHA-256 hash
        alt Not cached
            BinProc->>BinProc: Decode base64 if needed
            BinProc->>WorkspaceMgr: request save (filename, data)
            WorkspaceMgr->>FileStore: write_file(filename, data)
            FileStore-->>WorkspaceMgr: success / failure
            WorkspaceMgr-->>BinProc: workspace:// reference / error
            BinProc->>BinProc: Cache reference if success
        else Cached
            BinProc->>BinProc: Reuse cached reference
        end
        BinProc->>BinProc: Replace content with workspace:// reference
    else Small or non-saveable
        BinProc->>BinProc: Leave content unchanged
    end
    BinProc-->>RunBlock: processed_outputs
    RunBlock-->>Client: BlockOutputResponse(processed_outputs)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 I nibble bytes and hide them deep,

I store the big ones safe to keep.
No long base64 to slow the pace,
Just workspace links in tidy place.
Hooray — a rabbit's clever sweep!

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(copilot): Auto-save binary block outputs to workspace' accurately and concisely summarizes the main change - automatically saving binary outputs to workspace instead of returning raw base64.
Description check ✅ Passed The description provides comprehensive context about the problem, solution, implementation details, design decisions, expected impact, and testing, all directly related to the changeset.
Linked Issues check ✅ Passed The PR fully addresses SECRT-1887 requirements: auto-saves binary outputs (PNG, JPEG, PDF, SVG) to workspace, returns workspace:// references, implements graceful degradation, and processes all block outputs via run_block.py.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the linked issue SECRT-1887: new binary_output_processor.py module, integration in run_block.py, and comprehensive tests for the feature with no extraneous modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch otto/secrt-1887-copilot-auto-save-binary-outputs-from-all-blocks

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py`:
- Around line 112-118: The _decode_base64 function should perform strict base64
validation and normalize padding before decoding: if value starts with "data:"
strip the prefix as before, then normalize padding by adding '=' characters so
len(value) % 4 == 0, and call base64.b64decode(value, validate=True) to enforce
strict character checking; catch binascii.Error and ValueError and return None
on any failure so corrupted inputs are not silently decoded. Ensure these
changes are implemented inside _decode_base64 (preserving the data URI handling)
and that no exceptions escape.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c1aa684 and 96ca9da.

📒 Files selected for processing (3)
  • autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py
  • autogpt_platform/backend/backend/api/features/chat/tools/run_block.py
  • autogpt_platform/backend/backend/api/features/chat/tools/test_binary_output_processor.py
🧰 Additional context used
📓 Path-based instructions (7)
autogpt_platform/backend/**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

autogpt_platform/backend/**/*.py: Use Python 3.11 (required; managed by Poetry via pyproject.toml) for backend development
Always run 'poetry run format' (Black + isort) before linting in backend development
Always run 'poetry run lint' (ruff) after formatting in backend development

Files:

  • autogpt_platform/backend/backend/api/features/chat/tools/run_block.py
  • autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py
  • autogpt_platform/backend/backend/api/features/chat/tools/test_binary_output_processor.py
autogpt_platform/backend/backend/api/features/**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Update routes in '/backend/backend/api/features/' and add/update Pydantic models in the same directory for API development

When modifying API routes, update corresponding Pydantic models in the same directory and write tests alongside the route file

Files:

  • autogpt_platform/backend/backend/api/features/chat/tools/run_block.py
  • autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py
  • autogpt_platform/backend/backend/api/features/chat/tools/test_binary_output_processor.py
autogpt_platform/backend/**/*.{py,txt}

📄 CodeRabbit inference engine (autogpt_platform/backend/CLAUDE.md)

Use poetry run prefix for all Python commands, including testing, linting, formatting, and migrations

Files:

  • autogpt_platform/backend/backend/api/features/chat/tools/run_block.py
  • autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py
  • autogpt_platform/backend/backend/api/features/chat/tools/test_binary_output_processor.py
autogpt_platform/backend/backend/api/**/*.py

📄 CodeRabbit inference engine (autogpt_platform/backend/CLAUDE.md)

autogpt_platform/backend/backend/api/**/*.py: Use FastAPI for building REST and WebSocket endpoints
Use JWT-based authentication with Supabase integration

Files:

  • autogpt_platform/backend/backend/api/features/chat/tools/run_block.py
  • autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py
  • autogpt_platform/backend/backend/api/features/chat/tools/test_binary_output_processor.py
autogpt_platform/backend/backend/**/*.py

📄 CodeRabbit inference engine (autogpt_platform/backend/CLAUDE.md)

Use Prisma ORM for database operations in PostgreSQL with pgvector for embeddings

Files:

  • autogpt_platform/backend/backend/api/features/chat/tools/run_block.py
  • autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py
  • autogpt_platform/backend/backend/api/features/chat/tools/test_binary_output_processor.py
autogpt_platform/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Format Python code with poetry run format

Files:

  • autogpt_platform/backend/backend/api/features/chat/tools/run_block.py
  • autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py
  • autogpt_platform/backend/backend/api/features/chat/tools/test_binary_output_processor.py
autogpt_platform/backend/**/*test*.py

📄 CodeRabbit inference engine (AGENTS.md)

Run poetry run test for backend testing (runs pytest with docker based postgres + prisma)

Files:

  • autogpt_platform/backend/backend/api/features/chat/tools/test_binary_output_processor.py
🧠 Learnings (6)
📚 Learning: 2026-02-04T16:50:20.494Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/backend/CLAUDE.md:0-0
Timestamp: 2026-02-04T16:50:20.494Z
Learning: Applies to autogpt_platform/backend/backend/blocks/*.py : When adding new blocks, analyze block interfaces to ensure inputs and outputs tie well together for productive graph-based editor connections

Applied to files:

  • autogpt_platform/backend/backend/api/features/chat/tools/run_block.py
📚 Learning: 2026-02-04T16:50:20.494Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/backend/CLAUDE.md:0-0
Timestamp: 2026-02-04T16:50:20.494Z
Learning: Applies to autogpt_platform/backend/backend/blocks/*.py : Never hardcode workspace checks when using `store_media_file()` - let `for_block_output` handle context adaptation automatically

Applied to files:

  • autogpt_platform/backend/backend/api/features/chat/tools/run_block.py
  • autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py
📚 Learning: 2026-02-04T16:49:42.476Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.476Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Implement 'run' method with proper error handling in backend blocks

Applied to files:

  • autogpt_platform/backend/backend/api/features/chat/tools/run_block.py
📚 Learning: 2026-02-04T16:49:42.476Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.476Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Inherit from 'Block' base class with input/output schemas when adding new blocks in backend

Applied to files:

  • autogpt_platform/backend/backend/api/features/chat/tools/run_block.py
📚 Learning: 2026-02-04T16:49:56.176Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/CLAUDE.md:0-0
Timestamp: 2026-02-04T16:49:56.176Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Backend architecture uses Blocks in `backend/backend/blocks/` as reusable components that perform specific tasks

Applied to files:

  • autogpt_platform/backend/backend/api/features/chat/tools/run_block.py
📚 Learning: 2026-02-04T16:50:20.494Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/backend/CLAUDE.md:0-0
Timestamp: 2026-02-04T16:50:20.494Z
Learning: Applies to autogpt_platform/backend/backend/blocks/*.py : Implement blocks with an async `run` method and generate unique block IDs using `uuid.uuid4()`

Applied to files:

  • autogpt_platform/backend/backend/api/features/chat/tools/run_block.py
🧬 Code graph analysis (3)
autogpt_platform/backend/backend/api/features/chat/tools/run_block.py (3)
autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py (1)
  • process_binary_outputs (20-41)
autogpt_platform/backend/backend/data/workspace.py (1)
  • get_or_create_workspace (19-40)
autogpt_platform/backend/backend/util/workspace.py (1)
  • WorkspaceManager (30-419)
autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py (2)
autogpt_platform/backend/backend/util/workspace.py (2)
  • WorkspaceManager (30-419)
  • write_file (155-287)
autogpt_platform/backend/backend/api/features/chat/tools/test_binary_output_processor.py (1)
  • workspace_manager (13-16)
autogpt_platform/backend/backend/api/features/chat/tools/test_binary_output_processor.py (2)
autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py (2)
  • _decode_base64 (112-119)
  • process_binary_outputs (20-41)
autogpt_platform/backend/backend/util/workspace.py (1)
  • write_file (155-287)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: types
  • GitHub Check: Seer Code Review
  • GitHub Check: test (3.13)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.12)
  • GitHub Check: Check PR Status
🔇 Additional comments (7)
autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py (3)

20-41: Solid post-processing + dedup flow.
Clear, minimal traversal and cache usage; matches the intended behavior.


44-88: Recursive traversal looks correct.
Handles dict/list nesting without mutating originals; good.


91-109: Save path + graceful fallback are good.
The error handling preserves original data as intended.

autogpt_platform/backend/backend/api/features/chat/tools/test_binary_output_processor.py (3)

12-16: Good test fixture setup.
Clean AsyncMock usage for workspace writes.


19-28: Decode tests are concise and effective.
Covers raw, data URI, and invalid inputs.


31-92: Comprehensive processing coverage.
Covers size threshold, dedup, failure fallback, nesting, and lists.

autogpt_platform/backend/backend/api/features/chat/tools/run_block.py (1)

328-341: Integration looks correct.
Processing outputs before returning the response fits the intended flow.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@Torantulino
Copy link
Member

@claude please review this PR

@Torantulino Torantulino requested a review from ntindle February 4, 2026 22:54
@claude
Copy link
Contributor

claude bot commented Feb 4, 2026

Claude finished @Torantulino's task in 2m 23s —— View job


PR Review: Auto-save binary block outputs to workspace

  • Read changed files and gather context
  • Review binary_output_processor.py
  • Review run_block.py changes
  • Review test file
  • Post review findings

Overall this is a well-scoped change that solves a real problem — the code executor block's png/jpeg/pdf/svg fields returning raw base64 through the LLM path. The approach is clean: intercept at the single choke point (run_block.py), save to workspace, return references. A few items worth addressing:


Issues

1. Strict base64 validation (binary_output_processor.py:112-119)

As CodeRabbit also flagged: base64.b64decode() without validate=True silently discards non-alphabet characters before decoding, which means corrupted or partially-valid input could decode to garbage bytes and get saved as a file. This should use strict validation with padding normalization:

def _decode_base64(value: str) -> bytes | None:
    try:
        if value.startswith("data:"):
            value = value.split(",", 1)[1] if "," in value else value
        padded = value + "=" * (-len(value) % 4)
        return base64.b64decode(padded, validate=True)
    except (binascii.Error, ValueError):
        return None

Fix this →

2. Hashing the base64 string vs. decoded content (binary_output_processor.py:68)

The deduplication hash is computed on the raw base64 string (value.encode()), not the decoded content. This means the same binary content encoded differently (e.g., with vs. without a data URI prefix, or with different line-wrapping) will hash differently and be saved twice. Since _save already strips the data URI prefix and decodes, hashing should ideally happen on the decoded bytes. This is a minor issue in practice since the same block will likely produce identically-formatted base64, but it's worth noting as a correctness gap.

3. Missing docstrings — 25% coverage flagged by pre-merge check

_process_item and _process_dict are missing docstrings. The pre-merge check requires 80% coverage. Even brief one-liners would satisfy this.


Observations (non-blocking)

4. Overlap with store_media_file pattern

Most other image-producing blocks (screenshotone, ai_image_generator, flux_kontext, bannerbear, etc.) already use store_media_file() with return_format="for_block_output" to handle binary persistence at the block level. This PR adds a second mechanism at the run_block layer, which is appropriate for the code executor block (since it mirrors raw E2B output fields), but it's worth being aware that two systems now handle binary output persistence. A comment in run_block.py noting this catches the "code executor" case specifically would help future maintainers.

5. Test file location

The test file is placed at backend/api/features/chat/tools/test_binary_output_processor.py (co-located with the source). Other test files in this repo use various locations — some co-located, some in test/ or backend/blocks/test/. This is fine for consistency with the nearby code, but verify pytest discovers it (the pytest.ini or pyproject.toml test path config should include this directory).

6. _decode_base64 is imported in tests as a private function

test_binary_output_processor.py:8 imports _decode_base64 directly. This works but creates a coupling to an internal implementation detail. Consider either making it non-private (rename to decode_base64) or testing it only through process_binary_outputs. Minor style point.

7. Filename truncation is somewhat arbitrary (binary_output_processor.py:102)

block.lower().replace(' ', '_')[:20] truncates the block name to 20 chars. This is reasonable but could mid-word-truncate in confusing ways. Not a bug, just an observation.


Summary

The architecture is sound — a single-point interception that cleanly handles the token-waste problem for code executor outputs. The main actionable item is the base64 validation fix (issue #1), which prevents silently saving corrupted binary data. The docstring coverage (issue #3) will need to be addressed for the pre-merge check to pass.

Addresses CodeRabbit review feedback:
- Add padding normalization before decoding
- Use validate=True to reject invalid characters instead of silently discarding

This prevents corrupted data from being saved to workspace.
Adds docstrings to _process_item and _process_dict to meet
the 80% docstring coverage requirement.
@Otto-AGPT
Copy link
Contributor Author

Thanks for the thorough review!

Addressed:

Declined:

  • Issue #2 (hash decoded content) — As you noted, this is "minor in practice" since blocks produce identically-formatted base64. Changing this would add complexity (decode → hash → decode again to save) for negligible benefit. Keeping current approach.

Non-blocking observations acknowledged — Good points for future reference, no changes needed.

@qodo-code-review
Copy link

ⓘ Your monthly quota for Qodo has expired. Upgrade your plan
ⓘ Paying users. Check that your Qodo account is linked with this Git user account

and isinstance(value, str)
and len(value) > SIZE_THRESHOLD
):
content_hash = hashlib.sha256(value.encode()).hexdigest()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Deduplication fails because it hashes the raw base64 string before decoding, causing identical binary content with different string formats (e.g., with/without a data URI prefix) to be saved as separate files.
Severity: MEDIUM

Suggested Fix

The base64 string value should be decoded into its binary form before the hash is computed. This ensures that the hash represents the actual content, not its string representation, allowing for correct deduplication across different base64 formats.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location:
autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py#L70

Potential issue: The deduplication logic in `binary_output_processor.py` computes a
SHA256 hash on the raw base64 string representation of binary data at line 70. However,
the same binary content can be represented by different strings, such as raw base64
(`"ABC..."`) or a data URI (`"data:image/png;base64,ABC..."`). Because the hashing
occurs before the string is decoded, these different representations produce different
hashes for the same underlying data. This causes the deduplication to fail, leading to
redundant storage of identical binary files in the workspace and defeating the feature's
purpose of reducing storage and token overhead.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py`:
- Around line 103-107: The filename construction uses the raw block value and
only lower()/replace(' ', '_'), which allows path separators and unsafe
characters to reach storage backends; update the filename creation in
binary_output_processor.py to sanitize the block first (e.g., strip or replace
path separators, remove or percent/underscore non-alphanumeric characters, allow
only [a-z0-9_-], and truncate to the desired length) before building filename =
f"{...}_{field}_{uuid...}.{ext}"; apply this sanitized_block when calling
wm.write_file so both LocalWorkspaceStorage and GCSWorkspaceStorage receive a
safe filename (you can reuse or call an existing sanitize_filename helper if
available, or add a small sanitizer function used by the code that creates the
filename).
🧹 Nitpick comments (1)
autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py (1)

64-78: Hash binary content after decoding to improve dedup.

Right now the hash is computed on the base64 string, so identical bytes encoded differently (e.g., data URI vs raw, differing padding) won’t deduplicate. Consider hashing decoded bytes for binary fields before caching.

♻️ Suggested change
-            content_hash = hashlib.sha256(value.encode()).hexdigest()
+            if key in BINARY_FIELDS:
+                decoded = _decode_base64(value)
+                if decoded is None:
+                    result[key] = value
+                    continue
+                content_hash = hashlib.sha256(decoded).hexdigest()
+            else:
+                content_hash = hashlib.sha256(value.encode()).hexdigest()
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4769a28 and e5aad86.

📒 Files selected for processing (1)
  • autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py
🧰 Additional context used
📓 Path-based instructions (6)
autogpt_platform/backend/**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

autogpt_platform/backend/**/*.py: Use Python 3.11 (required; managed by Poetry via pyproject.toml) for backend development
Always run 'poetry run format' (Black + isort) before linting in backend development
Always run 'poetry run lint' (ruff) after formatting in backend development

Files:

  • autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py
autogpt_platform/backend/backend/api/features/**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Update routes in '/backend/backend/api/features/' and add/update Pydantic models in the same directory for API development

When modifying API routes, update corresponding Pydantic models in the same directory and write tests alongside the route file

Files:

  • autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py
autogpt_platform/backend/**/*.{py,txt}

📄 CodeRabbit inference engine (autogpt_platform/backend/CLAUDE.md)

Use poetry run prefix for all Python commands, including testing, linting, formatting, and migrations

Files:

  • autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py
autogpt_platform/backend/backend/api/**/*.py

📄 CodeRabbit inference engine (autogpt_platform/backend/CLAUDE.md)

autogpt_platform/backend/backend/api/**/*.py: Use FastAPI for building REST and WebSocket endpoints
Use JWT-based authentication with Supabase integration

Files:

  • autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py
autogpt_platform/backend/backend/**/*.py

📄 CodeRabbit inference engine (autogpt_platform/backend/CLAUDE.md)

Use Prisma ORM for database operations in PostgreSQL with pgvector for embeddings

Files:

  • autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py
autogpt_platform/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Format Python code with poetry run format

Files:

  • autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/backend/CLAUDE.md:0-0
Timestamp: 2026-02-04T16:50:20.494Z
Learning: Applies to autogpt_platform/backend/backend/blocks/*.py : Never hardcode workspace checks when using `store_media_file()` - let `for_block_output` handle context adaptation automatically
📚 Learning: 2026-02-04T16:50:20.494Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/backend/CLAUDE.md:0-0
Timestamp: 2026-02-04T16:50:20.494Z
Learning: Applies to autogpt_platform/backend/backend/blocks/*.py : Never hardcode workspace checks when using `store_media_file()` - let `for_block_output` handle context adaptation automatically

Applied to files:

  • autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py
🧬 Code graph analysis (1)
autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py (2)
autogpt_platform/backend/backend/util/workspace.py (2)
  • WorkspaceManager (30-419)
  • write_file (155-287)
autogpt_platform/backend/backend/api/features/chat/tools/test_binary_output_processor.py (1)
  • workspace_manager (13-16)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: types
  • GitHub Check: Seer Code Review
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.13)
  • GitHub Check: Check PR Status
🔇 Additional comments (4)
autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py (4)

14-18: Clear field taxonomy and threshold.

Nice, concise separation of binary vs text saveables, and the threshold is explicit.


20-41: Top-level processing flow looks solid.

Clean traversal and single-call dedup cache are easy to reason about.


44-55: Recursive item handling is straightforward.

List/dict recursion is clear and keeps non-collection items untouched.


114-123: LGTM on the strict decode guardrails.

The failure path is contained and keeps original data intact.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +103 to +107
ext = {"jpeg": "jpg"}.get(field, field)
filename = f"{block.lower().replace(' ', '_')[:20]}_{field}_{uuid.uuid4().hex[:12]}.{ext}"

file = await wm.write_file(content=content, filename=filename)
return f"workspace://{file.id}"
Copy link
Contributor

@coderabbitai coderabbitai bot Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find autogpt_platform/backend -name "workspace.py" -type f

Repository: Significant-Gravitas/AutoGPT

Length of output: 173


🏁 Script executed:

rg -n "def write_file" autogpt_platform/backend --type py -A 10 | head -50

Repository: Significant-Gravitas/AutoGPT

Length of output: 947


🏁 Script executed:

cat autogpt_platform/backend/backend/util/workspace.py | head -200

Repository: Significant-Gravitas/AutoGPT

Length of output: 6735


🏁 Script executed:

sed -n '155,250p' autogpt_platform/backend/backend/util/workspace.py

Repository: Significant-Gravitas/AutoGPT

Length of output: 3777


🏁 Script executed:

sed -n '215,240p' autogpt_platform/backend/backend/util/workspace.py

Repository: Significant-Gravitas/AutoGPT

Length of output: 951


🏁 Script executed:

find autogpt_platform/backend -name "workspace_storage.py" -type f

Repository: Significant-Gravitas/AutoGPT

Length of output: 130


🏁 Script executed:

rg -n "def store\|class.*Storage" autogpt_platform/backend/backend/util/workspace_storage.py -A 5 | head -80

Repository: Significant-Gravitas/AutoGPT

Length of output: 54


🏁 Script executed:

cat autogpt_platform/backend/backend/util/workspace_storage.py | head -300

Repository: Significant-Gravitas/AutoGPT

Length of output: 10397


🏁 Script executed:

rg -n "def sanitize_filename" autogpt_platform/backend --type py -A 15

Repository: Significant-Gravitas/AutoGPT

Length of output: 1471


🏁 Script executed:

cat autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py | head -120

Repository: Significant-Gravitas/AutoGPT

Length of output: 4119


Sanitize block parameter before using in filename.

The block parameter is only cleaned with .lower().replace(' ', '_'), which leaves path separators (/, \) and other unsafe characters. While LocalWorkspaceStorage mitigates this via sanitize_filename(), GCSWorkspaceStorage passes the filename directly to blob paths without sanitization, allowing malformed blob paths in cloud deployments.

Sanitize block before constructing the filename:

Suggested fix
+from backend.util.file import sanitize_filename
+
         ext = {"jpeg": "jpg"}.get(field, field)
-        filename = f"{block.lower().replace(' ', '_')[:20]}_{field}_{uuid.uuid4().hex[:12]}.{ext}"
+        safe_block = sanitize_filename(block.lower())[:20]
+        filename = f"{safe_block}_{field}_{uuid.uuid4().hex[:12]}.{ext}"
🤖 Prompt for AI Agents
In
`@autogpt_platform/backend/backend/api/features/chat/tools/binary_output_processor.py`
around lines 103 - 107, The filename construction uses the raw block value and
only lower()/replace(' ', '_'), which allows path separators and unsafe
characters to reach storage backends; update the filename creation in
binary_output_processor.py to sanitize the block first (e.g., strip or replace
path separators, remove or percent/underscore non-alphanumeric characters, allow
only [a-z0-9_-], and truncate to the desired length) before building filename =
f"{...}_{field}_{uuid...}.{ext}"; apply this sanitized_block when calling
wm.write_file so both LocalWorkspaceStorage and GCSWorkspaceStorage receive a
safe filename (you can reuse or call an existing sanitize_filename helper if
available, or add a small sanitizer function used by the code that creates the
filename).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is true 80% cnfidence

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ntindle Thank you for confirming! Since the block parameter comes from user-controlled input (block names), sanitizing it before filename construction will help ensure safe filenames across both local and cloud storage backends.

The suggested fix using sanitize_filename from backend.util.file should handle path separators, special characters, and other unsafe inputs. Let me know if you'd like me to help with anything else related to this change! 👍


🧠 Learnings used
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/backend/CLAUDE.md:0-0
Timestamp: 2026-02-04T16:50:20.494Z
Learning: Applies to autogpt_platform/backend/backend/blocks/*.py : Never hardcode workspace checks when using `store_media_file()` - let `for_block_output` handle context adaptation automatically

Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/backend/CLAUDE.md:0-0
Timestamp: 2026-02-04T16:50:20.494Z
Learning: Applies to autogpt_platform/backend/backend/blocks/*.py : Always use `for_block_output` format in `store_media_file()` for block outputs unless there is a specific reason not to

Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/backend/CLAUDE.md:0-0
Timestamp: 2026-02-04T16:50:20.494Z
Learning: Applies to autogpt_platform/backend/backend/blocks/*.py : When working with files in blocks, use `store_media_file()` from `backend.util.file` with appropriate `return_format` parameter: `for_local_processing` for local tools, `for_external_api` for external APIs, `for_block_output` for block outputs

Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.476Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Generate block UUID using 'uuid.uuid4()' when creating new blocks in backend

@qodo-code-review
Copy link

ⓘ Your monthly quota for Qodo has expired. Upgrade your plan
ⓘ Paying users. Check that your Qodo account is linked with this Git user account

@Torantulino Torantulino marked this pull request as draft February 4, 2026 23:53
@Torantulino Torantulino closed this Feb 5, 2026
@github-project-automation github-project-automation bot moved this from 🆕 Needs initial review to ✅ Done in AutoGPT development kanban Feb 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

platform/backend AutoGPT Platform - Back end size/l

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants