Skip to content

feat(aio): add screenshot attachments to sandbox conversations - #40

Open
lordspline wants to merge 2 commits into
masterfrom
capy/add-screenshot-attachments-to
Open

feat(aio): add screenshot attachments to sandbox conversations#40
lordspline wants to merge 2 commits into
masterfrom
capy/add-screenshot-attachments-to

Conversation

@lordspline

@lordspline lordspline commented Aug 20, 2026

Copy link
Copy Markdown

📑 Summary

People using PostHog AI sandbox conversations cannot attach screenshots, so the agent cannot inspect visual context with a prompt.

Closes PostHog#62926.

🪄 Changes

  • Adds PNG and JPEG previews, drag-and-drop, paste, retry, removal, and upload progress to the sandbox composer.
  • Validates and normalizes uploads before promoting opaque attachment IDs into the task run.
  • Scopes staged uploads by team, user, conversation, task, and run, with per-file, message, and user quotas.
  • Hides pending artifacts from human APIs until workflow dispatch succeeds, while task-bound sandbox agents can hydrate them.
  • Hydrates validated images for Claude and Pi without moving bytes or signed URLs through Temporal.
  • Documents the supported formats, limits, and sandbox behavior.

Before:

flowchart LR
    A[Composer] -->|text| B[Sandbox agent]
    style A fill:#e8d5ff,stroke:#6b21a8,color:#111
    style B fill:#fde68a,stroke:#92400e,color:#111
Loading

After:

flowchart LR
    A[Composer] -->|signed upload| B[Staging storage]
    B --> C[Validation and normalization]
    C -->|opaque attachment IDs| D[Task artifact manifest]
    D --> E[Sandbox agent]
    style A fill:#e8d5ff,stroke:#6b21a8,color:#111
    style B fill:#bae6fd,stroke:#0369a1,color:#111
    style C fill:#bbf7d0,stroke:#166534,color:#111
    style D fill:#fde68a,stroke:#92400e,color:#111
    style E fill:#fecaca,stroke:#991b1b,color:#111
Loading

Screenshot

🧪 How did you test this code?

  • Backend tests cover upload validation, scope isolation, quotas, promotion rollback, pending visibility, and first-message and follow-up routing.
  • Frontend tests cover selection limits, upload lifecycle, previews, send locking, and attachment IDs on sandbox requests.
  • Desktop tests cover manifest re-resolution, bounded downloads, image signatures, and Claude and Pi hydration.
  • Repository-wide mypy, frontend TypeScript, strict preflight, OpenAPI generation, and all focused suites pass locally.
  • I loaded PNG and JPEG previews in the local composer. Full agent consumption remains unchecked because local sandbox provisioning failed before agent startup.

✅ Checklist

  • The change works locally.
  • I added tests for my changes.
  • I updated the docs in the repository.
  • I added a feature flag (if required).
  • I added an entry to the changelog (if required).

🤖 Agent context

Capy implementation details
  • Autonomy: Human-driven agent-assisted.
  • Tools: Capy coding agent in the linked Capy workspace session.
  • Skills: /improving-drf-endpoints, /adopting-generated-api-types, /writing-ui-components, /writing-tests, /writing-user-facing-copy, /writing-code-comments, /security-audit, and /writing-pr-descriptions.
  • Workflow: The agent inspected repository contracts, implemented backend, frontend, and desktop paths, generated clients, ran focused checks, and verified local previews.
  • Decisions: Direct signed uploads keep image bytes outside Django, Temporal, and JSON-RPC payloads. Only scoped opaque IDs cross service boundaries.
  • Decisions: Pending delivery markers keep promoted artifacts hidden from human APIs until workflow dispatch succeeds.
  • Review: Please focus on the attachment lifecycle, promotion rollback, and pending visibility rules.
  • Public artifacts: All fixtures and screenshots use generated local test data. No customer material was used.

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown

🦔 Hogbox preview · ❌ build failed

The preview didn't come up for commit 3327934. See the build log for the failing step. It'll retry on the next push.

Previews are optional and never block merging. A failure here is often a hogland or tailnet hiccup rather than anything in your PR, so the check stays green and this comment is the status.

@github-actions

Copy link
Copy Markdown

🤖 CI report

Docs preview — preview build failed to start

The docs preview build could not be triggered. View the workflow logs for details.

@github-actions

Copy link
Copy Markdown

React Doctor found no issues in the changed files. 🎉

Reviewed by React Doctor for commit 3327934.

attachments=data["attachments"],
)
except AttachmentValidationError as error:
raise ValidationError(str(error)) from error
except AttachmentValidationError as error:
raise ValidationError(str(error)) from error
except AttachmentStorageError as error:
raise ValidationError(str(error)) from error
attachment_id=str(data["attachment_id"]),
)
except AttachmentNotFoundError as error:
raise NotFound(str(error)) from error
except AttachmentNotFoundError as error:
raise NotFound(str(error)) from error
except AttachmentValidationError as error:
raise ValidationError(str(error)) from error
except AttachmentValidationError as error:
raise ValidationError(str(error)) from error
except AttachmentStorageError as error:
raise ValidationError(str(error)) from error
attachment_ids=attachment_ids,
)
except (AttachmentNotFoundError, AttachmentValidationError) as error:
raise exceptions.ValidationError(str(error)) from error
attachment_ids=attachment_ids,
)
except (AttachmentNotFoundError, AttachmentValidationError) as error:
raise exceptions.ValidationError(str(error)) from error
attachment_ids=attachment_ids,
)
except (AttachmentNotFoundError, AttachmentValidationError) as error:
raise exceptions.ValidationError(str(error)) from error
attachment_ids=attachment_ids,
)
except (AttachmentNotFoundError, AttachmentValidationError) as error:
raise exceptions.ValidationError(str(error)) from error
attachment_ids=attachment_ids,
)
except (AttachmentNotFoundError, AttachmentValidationError) as error:
raise exceptions.ValidationError(str(error)) from error
Object.defineProperty(URL, 'revokeObjectURL', { configurable: true, value: jest.fn() })
const baseFetch = global.fetch.bind(global)
global.fetch = jest.fn((input: RequestInfo | URL, init?: RequestInit) => {
if (typeof input === 'string' && input.startsWith('https://upload.test')) {
Object.defineProperty(URL, 'revokeObjectURL', { configurable: true, value: jest.fn() })
const baseFetch = global.fetch.bind(global)
global.fetch = jest.fn((input: RequestInfo | URL, init?: RequestInit) => {
if (typeof input === 'string' && input.startsWith('https://upload.test')) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PostHog AI: let users attach files for additional context

2 participants