feat(cloud): attach images to a cloud workspace at create

Merged
SA
2mo ago
+165-64

Second of three. Stacked on #7620 — review that first.

Attaching an image on mobile failed with a flat refusal, which was honest but not useful:

// useCreateCloudWorkspace.ts
throw new Error("Attachments are not supported for cloud workspaces yet");

The reason was real: an attachment is a file on a host, resolved at launch by resolveAttachmentPath(id) into a path pasted into the prompt. A cloud workspace has no host when you press send.

The change

Almost none of this needed inventing — the pieces were already there and simply weren't connected:

  • the composer already PUTs attachments to R2 before the create, so the bytes are in cloud storage regardless of where they are going
  • host-service already knows how to pull them back (attachments.importFromCloud → api.attachment.resolve → download → local attachment store)
  • runAgentInWorkspace already takes attachmentIds and builds the # Attached files block

So the file ids travel with the launch (SUPERSET_SANDBOX_AGENT_ATTACHMENTS), and the box does its own import in launchSandboxAgentOnce once host-service is up, handing the agent in-box paths through the same prompt block every other host uses.

importFromCloud's body is extracted as importCloudAttachments, shared by the procedure and by a sandbox that has the ids in its environment and no client to call it. A failed download logs and drops the attachments — never the prompt.

On mobile, both create paths now settle uploads before branching on the target; the cloud branch previously returned ahead of awaitAttachmentUploads.

One trap worth knowing

renderSandboxConf does sandboxIdentitySchema.parse(identity), and zod strips unknown keys. A new identity variable that isn't declared in that schema is dropped on the way to the box with no error anywhere. claim.ts casts the launch env as Partial<SandboxIdentity>, so TypeScript won't catch it either. Declared it; flagging it because the next person adding a variable will hit this.

Verified

  • shared, trpc, host-service, sandbox, apps/mobile all typecheck clean
  • bun test src/runtime/sandbox-self-seed src/trpc/router/attachments in packages/host-service: 22 pass / 0 fail
  • Not yet exercised end-to-end in a box: this needs a bundle publish + image release to reach one, same as #7620. I'll run both and verify an image actually reaches the agent before either is called done.

https://claude.ai/code/session_01FK6rLzBEUiHHXZWNmpQ2BP


Summary by cubic

Attaching images to a cloud workspace at create now works end to end; previously mobile refused with "Attachments are not supported for cloud workspaces yet".

  • The attachment ids travel in SUPERSET_SANDBOX_AGENT_ATTACHMENTS, and the sandbox pulls the bytes from cloud storage once host-service is up.
  • importFromCloud's body is now importCloudAttachments, shared by the procedure and the sandbox's first-boot launch.
  • Both mobile create paths settle uploads before branching on the target, and the create call now actually gets the uploaded ids instead of dropping them.
  • A failed download logs and drops the attachment; the prompt always launches.

Note for reviewers

  • New identity env vars must be declared in sandboxIdentitySchema; renderSandboxConf strips unknown keys silently.

Summary by CodeRabbit

  • New Features

    • Cloud workspaces can now be created with uploaded attachments, which are made available to launched agents.
    • Workspace repositories now support creating working branches from specified base branches.
    • Cloud workspace launches support up to 10 uploaded attachments.
  • Bug Fixes

    • Attachments are uploaded before cloud workspace creation, ensuring they are included reliably.
    • Failed attachment imports no longer prevent an agent from launching.
  • Documentation

    • Clarified workspace checkout and branch behavior.