Skip to content

Handle workspace:// URLs in regular markdown links - #12166

Merged
0ubbe merged 5 commits into
devfrom
claude/debug-upload-blocked-RFGA7
Feb 25, 2026
Merged

Handle workspace:// URLs in regular markdown links#12166
0ubbe merged 5 commits into
devfrom
claude/debug-upload-blocked-RFGA7

Conversation

@ntindle

@ntindle ntindle commented Feb 19, 2026

Copy link
Copy Markdown
Member

Changes 🏗️

Extended the resolveWorkspaceUrls function to handle both image syntax (![alt](workspace://id#mime)) and regular link syntax ([text](workspace://id)).

Previously, only image links were being resolved. Regular workspace links were being blocked by Streamdown's rehype-harden sanitizer because workspace:// is not in the allowed URL-scheme whitelist, causing "[blocked]" to appear next to link text.

The fix:

  • Refactored the function to process image links first (existing behavior)
  • Added a second regex replacement to handle regular links using a negative lookbehind ((?<!!)) to avoid matching image syntax
  • Both patterns now resolve workspace:// URLs to proxy download URLs via /api/proxy
  • Updated JSDoc comments to clarify the dual handling

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:
    • Verified image links with MIME type hints still resolve correctly
    • Verified regular workspace links now resolve to proxy URLs instead of being blocked
    • Confirmed negative lookbehind prevents double-processing of image syntax

https://claude.ai/code/session_0184TVJJcEoB8wbX9htCnv4b


Note

Low Risk
Low risk: a small, localized frontend markdown preprocessing change that only rewrites workspace:// URLs to existing /api/proxy download URLs; main risk is regex edge cases affecting link rendering.

Overview
Updates resolveWorkspaceUrls in ChatMessagesContainer to rewrite both workspace:// image markdown and regular markdown links into /api/proxy download URLs so Streamdown sanitization no longer shows [blocked] for workspace links.

Image handling is preserved (including #video/* MIME hints via video: alt text), and a second regex pass with a negative lookbehind avoids double-processing image syntax when rewriting plain links.

Written by Cursor Bugbot for commit e17749b. This will update automatically on new commits. Configure here.

resolveWorkspaceUrls() only handled image syntax ![alt](workspace://id)
but not regular link syntax [text](workspace://id). When the AI returned
file download links using workspace:// protocol, Streamdown's
rehype-harden sanitizer blocked them because "workspace://" is not in
the allowed URL-scheme whitelist, causing "[blocked]" to appear next to
the file name in the chat UI.

Add a second replace pass that catches regular markdown links with
workspace:// and rewrites them to the /api/proxy download path, matching
the existing image-link handling.

https://claude.ai/code/session_0184TVJJcEoB8wbX9htCnv4b
@ntindle
ntindle requested a review from a team as a code owner February 19, 2026 16:12
@ntindle
ntindle requested review from 0ubbe and kcze and removed request for a team February 19, 2026 16:12
@github-project-automation github-project-automation Bot moved this to 🆕 Needs initial review in AutoGPT development kanban Feb 19, 2026
@github-actions github-actions Bot added the platform/frontend AutoGPT Platform - Front end label Feb 19, 2026
@coderabbitai

coderabbitai Bot commented Feb 19, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Expanded resolveWorkspaceUrls to convert workspace:// URIs in both image and regular link markdown: image syntax preserves mime-based video detection; regular links are rewritten to proxied /api/proxy URLs and default link text is set when missing to avoid sanitizer blocking.

Changes

Cohort / File(s) Summary
URL Resolution Enhancement
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
Added handling for ![alt](workspace://...) and [text](workspace://...) forms: image path resolution preserves mimeHint and prefixes alt with video: for video/*; regular links are rewritten to /api/proxy?... and use "Download file" when link text is empty to work around sanitizer blocking.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I nibble links both near and far,

workspace paths I patch and star,
Videos tagged so they can play,
Downloads found when words stray,
A happy hop through proxied way. 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: extending the function to handle workspace:// URLs in regular markdown links, which is the core objective of this PR.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, clearly explaining the problem, solution, testing performed, and risk assessment.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/debug-upload-blocked-RFGA7

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.

@github-actions

github-actions Bot commented Feb 19, 2026

Copy link
Copy Markdown
Contributor

🔍 PR Overlap Detection

This check compares your PR against all other open PRs targeting the same branch to detect potential merge conflicts early.

🔴 Merge Conflicts Detected

The following PRs have been tested and will have merge conflicts if merged after this PR. Consider coordinating with the authors.

  • chore(frontend): Fix react-doctor warnings + add CI job #12163 (0ubbe · updated 1d ago)
    • 📁 autogpt_platform/frontend/src/app/(platform)/copilot/
      • components/ChatMessagesContainer/ChatMessagesContainer.tsx (1 conflict, ~6 lines)
      • tools/RunAgent/components/AgentDetailsCard/AgentDetailsCard.tsx (2 conflicts, ~117 lines)

🟢 Low Risk — File Overlap Only

These PRs touch the same files but different sections (click to expand)

Summary: 1 conflict(s), 0 medium risk, 1 low risk (out of 2 PRs with file overlap)


Auto-generated on push. Ignores: openapi.json, lock files.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx (1)

60-67: Optional: third capture group in the second regex is unused — make it non-capturing.

The replacement callback for the regular-link pass only destructures linkText and fileId (groups 1 and 2). The third group ([^)\s]*) capturing the MIME hint is never consumed, so it silently drops the #fragment from the source text without applying it anywhere — which is intentional, but the capturing group is misleadingly parallel to the first pass and adds unnecessary overhead.

♻️ Proposed refactor
   resolved = resolved.replace(
-    /(?<!!)\[([^\]]*)\]\(workspace:\/\/([^)#\s]+)(?:#([^)\s]*))?\)/g,
+    /(?<!!)\[([^\]]*)\]\(workspace:\/\/([^)#\s]+)(?:#[^)\s]*)?\)/g,
     (_match, linkText: string, fileId: string) => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
around lines 60 - 67, The regex in the replacement for resolved is currently
capturing a third group for the MIME fragment but the replacement callback only
uses linkText and fileId; update the pattern in ChatMessagesContainer.tsx to
make the third group non-capturing (change `([^)\s]*)` to `(?:[^)\s]*)`) so the
fragment is not captured unnecessarily; keep the rest of the logic in the
resolved.replace call and the replacement callback that calls
getGetWorkspaceDownloadFileByIdUrl(fileId) and builds `/api/proxy${apiPath}`
unchanged.
📜 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 aeca4db and e17749b.

📒 Files selected for processing (1)
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
🧰 Additional context used
📓 Path-based instructions (10)
autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}

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

autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}: Use Node.js 21+ with pnpm package manager for frontend development
Always run 'pnpm format' for formatting and linting code in frontend development

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{tsx,ts}

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

autogpt_platform/frontend/**/*.{tsx,ts}: Use function declarations for components and handlers (not arrow functions) in React components
Only use arrow functions for small inline lambdas (map, filter, etc.) in React components
Use PascalCase for component names and camelCase with 'use' prefix for hook names in React
Use Tailwind CSS utilities only for styling in frontend components
Use design system components from 'src/components/' (atoms, molecules, organisms) in frontend development
Never use 'src/components/legacy/' in frontend code
Only use Phosphor Icons (@phosphor-icons/react) for icons in frontend components
Use generated API hooks from '@/app/api/generated/endpoints/' instead of deprecated 'BackendAPI' or 'src/lib/autogpt-server-api/
'
Use React Query for server state (via generated hooks) in frontend development
Default to client components ('use client') in Next.js; only use server components for SEO or extreme TTFB needs
Use '' component for rendering errors in frontend UI; use toast notifications for mutation errors; use 'Sentry.captureException()' for manual exceptions
Separate render logic from data/behavior in React components; keep comments minimal (code should be self-documenting)

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{ts,tsx}

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

autogpt_platform/frontend/**/*.{ts,tsx}: No barrel files or 'index.ts' re-exports in frontend code
Regenerate API hooks with 'pnpm generate:api' after backend OpenAPI spec changes in frontend development

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/**/*.{ts,tsx}

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

autogpt_platform/frontend/src/**/*.{ts,tsx}: Fully capitalize acronyms in symbols, e.g. graphID, useBackendAPI
Use function declarations (not arrow functions) for components and handlers
Separate render logic (.tsx) from business logic (use*.ts hooks)
Use shadcn/ui (Radix UI primitives) with Tailwind CSS styling for UI components
Use Phosphor Icons only for icons
Use ErrorCard for render errors, toast for mutations, and Sentry for exceptions
Use design system components from src/components/ (atoms, molecules, organisms)
Never use src/components/__legacy__/* components
Use generated API hooks from @/app/api/__generated__/endpoints/ with pattern use{Method}{Version}{OperationName}
Use Tailwind CSS only for styling, with design tokens
Do not use useCallback or useMemo unless asked to optimize a given function
Never type with any unless a variable/attribute can ACTUALLY be of any type

autogpt_platform/frontend/src/**/*.{ts,tsx}: Structure components as ComponentName/ComponentName.tsx + useComponentName.ts + helpers.ts and use design system components from src/components/ (atoms, molecules, organisms)
Use generated API hooks from @/app/api/__generated__/endpoints/ with pattern use{Method}{Version}{OperationName} and regenerate with pnpm generate:api
Use function declarations (not arrow functions) for components and handlers
Separate render logic from business logic with component.tsx + useComponent.ts + helpers.ts structure
Colocate state when possible, avoid creating large components, use sub-components in local /components folder
Avoid large hooks, abstract logic into helpers.ts files when sensible
Use arrow functions only for callbacks, not for component declarations
Avoid comments at all times unless the code is very complex
Do not use useCallback or useMemo unless asked to optimize a given function

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/app/(platform)/**/components/**/*.{ts,tsx}

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

Put sub-components in local components/ folder within feature directories

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/**/*.tsx

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

Component props should be type Props = { ... } (not exported) unless it needs to be used outside the component

Component props should be interface Props { ... } (not exported) unless the interface needs to be used outside the component

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

autogpt_platform/frontend/**/*.{js,jsx,ts,tsx}: Format frontend code using pnpm format
Never use components from src/components/__legacy__/*

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{js,jsx,ts,tsx,css}

📄 CodeRabbit inference engine (AGENTS.md)

Use Tailwind CSS only for styling, use design tokens, and use Phosphor Icons only

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never type with any, if no types available use unknown

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/app/(platform)/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

If adding protected frontend routes, update frontend/lib/supabase/middleware.ts

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
⏰ 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). (5)
  • GitHub Check: Seer Code Review
  • GitHub Check: types
  • GitHub Check: end-to-end tests
  • GitHub Check: Cursor Bugbot
  • GitHub Check: Check PR Status
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx:
- Around line 60-67: The regex in the replacement for resolved is currently
capturing a third group for the MIME fragment but the replacement callback only
uses linkText and fileId; update the pattern in ChatMessagesContainer.tsx to
make the third group non-capturing (change `([^)\s]*)` to `(?:[^)\s]*)`) so the
fragment is not captured unnecessarily; keep the rest of the logic in the
resolved.replace call and the replacement callback that calls
getGetWorkspaceDownloadFileByIdUrl(fileId) and builds `/api/proxy${apiPath}`
unchanged.

@greptile-apps

greptile-apps Bot commented Feb 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Extended resolveWorkspaceUrls to handle regular markdown links [text](workspace://id) in addition to image syntax, preventing Streamdown's sanitizer from blocking them.

Key changes:

  • Added second regex pass with negative lookbehind to process non-image workspace links
  • Both patterns now resolve workspace:// URLs to /api/proxy download URLs
  • Updated JSDoc to document dual handling

Issues found:

  • Negative lookbehind (?<!!) fails when ! appears in text before link (e.g., "Important![link](...)"), causing legitimate links to be skipped
  • Nested brackets in link text/alt break pattern matching (regex stops at first ])
  • Multiple # symbols in URL are captured in MIME hint instead of stopping at first

The core functionality works for common cases, but regex patterns need refinement for edge cases.

Confidence Score: 3/5

  • Safe to merge with caution - works for common cases but has regex edge case bugs
  • The implementation correctly solves the core problem (regular workspace links being blocked), and the two-pass approach is sound. However, the regex patterns have three logical bugs: negative lookbehind fails when ! appears before [ in normal text, nested brackets in link text break matching, and multiple # symbols aren't handled correctly. These are edge cases that likely won't affect typical usage but could cause issues in specific scenarios. No security vulnerabilities, no test coverage added.
  • Pay close attention to ChatMessagesContainer.tsx regex patterns if users report workspace links not resolving

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Markdown text with workspace:// URLs] --> B[resolveWorkspaceUrls function]
    B --> C[Pass 1: Replace image links]
    C --> D{Contains image pattern?}
    D -->|Yes| E[Extract fileId and mimeHint]
    E --> F{mimeHint starts with video/?}
    F -->|Yes| G[Prefix alt with video:]
    F -->|No| H[Keep alt unchanged]
    G --> I[Replace with /api/proxy URL]
    H --> I
    D -->|No| J[Pass 2: Replace regular links]
    J --> K{Contains link pattern without leading !?}
    K -->|Yes| L[Extract fileId only]
    L --> M[Replace with /api/proxy URL]
    K -->|No| N[Return resolved text]
    I --> J
    M --> N
    N --> O[Render in MessageResponse with WorkspaceMediaImage component]
Loading

Last reviewed commit: e17749b

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

1 file reviewed, 4 comments

Edit Code Review Agent Settings | Greptile

0ubbe
0ubbe previously approved these changes Feb 20, 2026
@0ubbe
0ubbe enabled auto-merge February 25, 2026 10:59
@0ubbe
0ubbe disabled auto-merge February 25, 2026 11:00

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx (1)

59-66: Hash fragment from regular links is silently discarded.

The regex on line 60 captures an optional #fragment (group 3), but the callback on line 61 doesn't bind or forward it. If a regular link like [file](workspace://id#application/pdf) is encountered, the fragment is silently dropped — unlike the image path where it's used for MIME-type detection.

If you intentionally ignore it for regular links, consider removing the capture group from this regex to signal intent. Otherwise, you may want to pass it through as a query parameter or keep it on the URL.

Option A: Remove the unused capture group to clarify intent
   resolved = resolved.replace(
-    /(?<!!)\[([^\]]*)\]\(workspace:\/\/([^)#\s]+)(?:#([^)\s]*))?\)/g,
+    /(?<!!)\[([^\]]*)\]\(workspace:\/\/([^)#\s]+)(?:#[^)\s]*)?\)/g,
     (_match, linkText: string, fileId: string) => {

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e17749b and 2ab975b.

📒 Files selected for processing (1)
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (10)
autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}

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

autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}: Use Node.js 21+ with pnpm package manager for frontend development
Always run 'pnpm format' for formatting and linting code in frontend development

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{tsx,ts}

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

autogpt_platform/frontend/**/*.{tsx,ts}: Use function declarations for components and handlers (not arrow functions) in React components
Only use arrow functions for small inline lambdas (map, filter, etc.) in React components
Use PascalCase for component names and camelCase with 'use' prefix for hook names in React
Use Tailwind CSS utilities only for styling in frontend components
Use design system components from 'src/components/' (atoms, molecules, organisms) in frontend development
Never use 'src/components/legacy/' in frontend code
Only use Phosphor Icons (@phosphor-icons/react) for icons in frontend components
Use generated API hooks from '@/app/api/generated/endpoints/' instead of deprecated 'BackendAPI' or 'src/lib/autogpt-server-api/
'
Use React Query for server state (via generated hooks) in frontend development
Default to client components ('use client') in Next.js; only use server components for SEO or extreme TTFB needs
Use '' component for rendering errors in frontend UI; use toast notifications for mutation errors; use 'Sentry.captureException()' for manual exceptions
Separate render logic from data/behavior in React components; keep comments minimal (code should be self-documenting)

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{ts,tsx}

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

autogpt_platform/frontend/**/*.{ts,tsx}: No barrel files or 'index.ts' re-exports in frontend code
Regenerate API hooks with 'pnpm generate:api' after backend OpenAPI spec changes in frontend development

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/**/*.{ts,tsx}

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

autogpt_platform/frontend/src/**/*.{ts,tsx}: Fully capitalize acronyms in symbols, e.g. graphID, useBackendAPI
Use function declarations (not arrow functions) for components and handlers
Separate render logic (.tsx) from business logic (use*.ts hooks)
Use shadcn/ui (Radix UI primitives) with Tailwind CSS styling for UI components
Use Phosphor Icons only for icons
Use ErrorCard for render errors, toast for mutations, and Sentry for exceptions
Use design system components from src/components/ (atoms, molecules, organisms)
Never use src/components/__legacy__/* components
Use generated API hooks from @/app/api/__generated__/endpoints/ with pattern use{Method}{Version}{OperationName}
Use Tailwind CSS only for styling, with design tokens
Do not use useCallback or useMemo unless asked to optimize a given function
Never type with any unless a variable/attribute can ACTUALLY be of any type

autogpt_platform/frontend/src/**/*.{ts,tsx}: Structure components as ComponentName/ComponentName.tsx + useComponentName.ts + helpers.ts and use design system components from src/components/ (atoms, molecules, organisms)
Use generated API hooks from @/app/api/__generated__/endpoints/ with pattern use{Method}{Version}{OperationName} and regenerate with pnpm generate:api
Use function declarations (not arrow functions) for components and handlers
Separate render logic from business logic with component.tsx + useComponent.ts + helpers.ts structure
Colocate state when possible, avoid creating large components, use sub-components in local /components folder
Avoid large hooks, abstract logic into helpers.ts files when sensible
Use arrow functions only for callbacks, not for component declarations
Avoid comments at all times unless the code is very complex
Do not use useCallback or useMemo unless asked to optimize a given function

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/app/(platform)/**/components/**/*.{ts,tsx}

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

Put sub-components in local components/ folder within feature directories

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/**/*.tsx

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

Component props should be type Props = { ... } (not exported) unless it needs to be used outside the component

Component props should be interface Props { ... } (not exported) unless the interface needs to be used outside the component

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

autogpt_platform/frontend/**/*.{js,jsx,ts,tsx}: Format frontend code using pnpm format
Never use components from src/components/__legacy__/*

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{js,jsx,ts,tsx,css}

📄 CodeRabbit inference engine (AGENTS.md)

Use Tailwind CSS only for styling, use design tokens, and use Phosphor Icons only

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never type with any, if no types available use unknown

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/app/(platform)/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

If adding protected frontend routes, update frontend/lib/supabase/middleware.ts

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
🔇 Additional comments (3)
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx (3)

33-40: LGTM — JSDoc accurately documents the dual-handling behavior.


41-53: LGTM — Image link handling cleanly refactored to enable the two-pass approach.


59-66: Negative lookbehind only checks a single ! — consider whether nested/escaped brackets could slip through.

(?<!!) correctly prevents matching standard image syntax ![alt](...). However, any markdown edge case where [text](workspace://...) is preceded by a single ! for non-image reasons (e.g., not! immediately before the bracket with no space) would also be skipped. This is extremely unlikely in practice and the current approach is sound for real-world markdown — just noting it for awareness.

Stop MIME hint capture at `#` to prevent multi-fragment leakage, and
make the unused third capture group in the regular-link regex
non-capturing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx (1)

59-66: Nit: Consider extracting the proxy URL construction into a helper to reduce duplication.

Both the image regex callback (lines 46-47) and the regular-link regex callback (lines 62-63) repeat the same getGetWorkspaceDownloadFileByIdUrl/api/proxy${apiPath} pattern. A small helper (e.g., workspaceFileUrl(fileId)) would DRY this up and make future changes (like adjusting the proxy path) a single-point edit.

♻️ Optional refactor
 function resolveWorkspaceUrls(text: string): string {
+  function proxyUrl(fileId: string): string {
+    return `/api/proxy${getGetWorkspaceDownloadFileByIdUrl(fileId)}`;
+  }
+
   // Handle image links: ![alt](workspace://id#mime)
   let resolved = text.replace(
     /!\[([^\]]*)\]\(workspace:\/\/([^)#\s]+)(?:#([^)#\s]*))?\)/g,
     (_match, alt: string, fileId: string, mimeHint?: string) => {
-      const apiPath = getGetWorkspaceDownloadFileByIdUrl(fileId);
-      const url = `/api/proxy${apiPath}`;
+      const url = proxyUrl(fileId);
       if (mimeHint?.startsWith("video/")) {
         return `![video:${alt || "Video"}](${url})`;
       }
       return `![${alt || "Image"}](${url})`;
     },
   );

   resolved = resolved.replace(
     /(?<!!)\[([^\]]*)\]\(workspace:\/\/([^)#\s]+)(?:#[^)#\s]*)?\)/g,
     (_match, linkText: string, fileId: string) => {
-      const apiPath = getGetWorkspaceDownloadFileByIdUrl(fileId);
-      const url = `/api/proxy${apiPath}`;
+      const url = proxyUrl(fileId);
       return `[${linkText || "Download file"}](${url})`;
     },
   );

   return resolved;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
around lines 59 - 66, Extract the repeated proxy URL construction into a small
helper (e.g., workspaceFileUrl) and use it in both regex callbacks: replace
repeated calls to getGetWorkspaceDownloadFileByIdUrl(fileId) followed by
`/api/proxy${apiPath}` with a single function that accepts fileId, calls
getGetWorkspaceDownloadFileByIdUrl, prefixes `/api/proxy`, and returns the final
URL; then update the image regex callback and the regular-link regex callback
(the resolved.replace handlers) to call workspaceFileUrl(fileId) instead of
duplicating the logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx:
- Around line 59-66: Extract the repeated proxy URL construction into a small
helper (e.g., workspaceFileUrl) and use it in both regex callbacks: replace
repeated calls to getGetWorkspaceDownloadFileByIdUrl(fileId) followed by
`/api/proxy${apiPath}` with a single function that accepts fileId, calls
getGetWorkspaceDownloadFileByIdUrl, prefixes `/api/proxy`, and returns the final
URL; then update the image regex callback and the regular-link regex callback
(the resolved.replace handlers) to call workspaceFileUrl(fileId) instead of
duplicating the logic.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2ab975b and 984a741.

📒 Files selected for processing (1)
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (10)
autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}

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

autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}: Use Node.js 21+ with pnpm package manager for frontend development
Always run 'pnpm format' for formatting and linting code in frontend development

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{tsx,ts}

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

autogpt_platform/frontend/**/*.{tsx,ts}: Use function declarations for components and handlers (not arrow functions) in React components
Only use arrow functions for small inline lambdas (map, filter, etc.) in React components
Use PascalCase for component names and camelCase with 'use' prefix for hook names in React
Use Tailwind CSS utilities only for styling in frontend components
Use design system components from 'src/components/' (atoms, molecules, organisms) in frontend development
Never use 'src/components/legacy/' in frontend code
Only use Phosphor Icons (@phosphor-icons/react) for icons in frontend components
Use generated API hooks from '@/app/api/generated/endpoints/' instead of deprecated 'BackendAPI' or 'src/lib/autogpt-server-api/
'
Use React Query for server state (via generated hooks) in frontend development
Default to client components ('use client') in Next.js; only use server components for SEO or extreme TTFB needs
Use '' component for rendering errors in frontend UI; use toast notifications for mutation errors; use 'Sentry.captureException()' for manual exceptions
Separate render logic from data/behavior in React components; keep comments minimal (code should be self-documenting)

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{ts,tsx}

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

autogpt_platform/frontend/**/*.{ts,tsx}: No barrel files or 'index.ts' re-exports in frontend code
Regenerate API hooks with 'pnpm generate:api' after backend OpenAPI spec changes in frontend development

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/**/*.{ts,tsx}

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

autogpt_platform/frontend/src/**/*.{ts,tsx}: Fully capitalize acronyms in symbols, e.g. graphID, useBackendAPI
Use function declarations (not arrow functions) for components and handlers
Separate render logic (.tsx) from business logic (use*.ts hooks)
Use shadcn/ui (Radix UI primitives) with Tailwind CSS styling for UI components
Use Phosphor Icons only for icons
Use ErrorCard for render errors, toast for mutations, and Sentry for exceptions
Use design system components from src/components/ (atoms, molecules, organisms)
Never use src/components/__legacy__/* components
Use generated API hooks from @/app/api/__generated__/endpoints/ with pattern use{Method}{Version}{OperationName}
Use Tailwind CSS only for styling, with design tokens
Do not use useCallback or useMemo unless asked to optimize a given function
Never type with any unless a variable/attribute can ACTUALLY be of any type

autogpt_platform/frontend/src/**/*.{ts,tsx}: Structure components as ComponentName/ComponentName.tsx + useComponentName.ts + helpers.ts and use design system components from src/components/ (atoms, molecules, organisms)
Use generated API hooks from @/app/api/__generated__/endpoints/ with pattern use{Method}{Version}{OperationName} and regenerate with pnpm generate:api
Use function declarations (not arrow functions) for components and handlers
Separate render logic from business logic with component.tsx + useComponent.ts + helpers.ts structure
Colocate state when possible, avoid creating large components, use sub-components in local /components folder
Avoid large hooks, abstract logic into helpers.ts files when sensible
Use arrow functions only for callbacks, not for component declarations
Avoid comments at all times unless the code is very complex
Do not use useCallback or useMemo unless asked to optimize a given function

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/app/(platform)/**/components/**/*.{ts,tsx}

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

Put sub-components in local components/ folder within feature directories

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/**/*.tsx

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

Component props should be type Props = { ... } (not exported) unless it needs to be used outside the component

Component props should be interface Props { ... } (not exported) unless the interface needs to be used outside the component

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

autogpt_platform/frontend/**/*.{js,jsx,ts,tsx}: Format frontend code using pnpm format
Never use components from src/components/__legacy__/*

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{js,jsx,ts,tsx,css}

📄 CodeRabbit inference engine (AGENTS.md)

Use Tailwind CSS only for styling, use design tokens, and use Phosphor Icons only

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never type with any, if no types available use unknown

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/app/(platform)/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

If adding protected frontend routes, update frontend/lib/supabase/middleware.ts

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
🔇 Additional comments (2)
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx (2)

33-53: LGTM — image regex handling and JSDoc update.

The refactor to store the intermediate result in resolved for multi-pass processing is clean. The image regex correctly captures alt text, file ID, and optional MIME hint. JSDoc accurately reflects the dual handling.


54-68: Solid approach — two-pass strategy with lookbehind is correct.

Processing image links first (which strips workspace:// from them) and then applying the regular-link regex with the (?<!!) lookbehind is a sound double-safety against double-processing. The inline comments explaining the sanitizer motivation (lines 55-58) are helpful given the non-obvious reason for this second pass.

One minor observation: the #fragment portion is matched but intentionally not captured in the second regex (discarded for regular links). This is fine since MIME hints are only meaningful for image/video rendering, but it's worth being aware that a workspace://id#something regular link silently drops the fragment.

@0ubbe

0ubbe commented Feb 25, 2026

Copy link
Copy Markdown
Contributor

Addressed Greptile/CodeRabbit review comments

Pushed 984a741 with two targeted regex fixes in resolveWorkspaceUrls:

Fixed

  1. MIME capture tightened (Greptile comment 3 + CodeRabbit): Changed [^)\s]*[^)#\s]* in both regex patterns so the MIME hint capture stops at a second # character. Prevents hypothetical multi-fragment leakage like workspace://id#video/mp4#extra.
  2. Unused capture group removed (CodeRabbit nitpick, both reviews): Made the third capture group in the regular-link regex non-capturing since the callback only uses linkText and fileId.

Not changed (with reasoning)

  1. Negative lookbehind (?<!!) (Greptile comment 1): The suggested offset-based approach solves a non-problem. In markdown, Important![link](workspace://id) is parsed as text Important + image ![link](...) — the first regex pass handles it correctly, and the lookbehind correctly avoids double-matching. The behavior is correct as-is.
  2. Nested brackets [^\]]*[^\[\]]* (Greptile comments 2 & 4): This would actually make behavior worse. With [^\]]*, the regex can still partially match via backtracking on nested brackets. With [^\[\]]*, it would fail entirely. Either way, nested brackets in workspace link text is unrealistic in practice.

@0ubbe
0ubbe enabled auto-merge February 25, 2026 12:23
@0ubbe
0ubbe added this pull request to the merge queue Feb 25, 2026
Merged via the queue into dev with commit 77fb441 Feb 25, 2026
23 checks passed
@0ubbe
0ubbe deleted the claude/debug-upload-blocked-RFGA7 branch February 25, 2026 12:50
@github-project-automation github-project-automation Bot moved this to Done in Frontend Feb 25, 2026
@github-project-automation github-project-automation Bot moved this from 👍🏼 Mergeable to ✅ Done in AutoGPT development kanban Feb 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

platform/frontend AutoGPT Platform - Front end size/m

Projects

Status: ✅ Done
Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants