Persona isolation and image input
Implemented on codex/persona-vision, then rebased on codex/persona-vision-release onto origin/main 3f51af9e7 before release, preserving the latest story-memory reservation, conversation-floor fixes and admin activity chart changes. The original working copy was left untouched. This release requires no database migration. Validation uses no production data or paid generation calls.
Approved interface
The user approved option A on 2026-09-22 and explicitly requested clipboard paste and preservation of the original plus menu. The composer adds an adjacent image button and removable thumbnails. The existing continue, restart, persona, share and branch actions remain. Image-capable models carry an image icon and Vision/读图 label. Unsupported selections preserve drafts and offer the existing model picker. At the user's request, the actual composer and model picker were rendered in an isolated local preview; the user reviewed the result and explicitly approved deployment. The preview entry is packages/app/preview/vision.html and is excluded from the production application build.
Behavior
- Selecting a persona from a game changes only that save and enables its override. Following the profile is explicit. The legacy session-selection endpoint is fixed too; it can no longer write the account default. Profile selection and shared persona editing retain their existing behavior.
- Normal chat accepts image-only messages, image plus text, file selection and image clipboard paste. File validation allows PNG/JPEG/WebP/GIF, up to four images, 8 MB each and 16 MB total. Plain text paste and IME/keyboard preferences remain intact.
- Originals are stored through the existing storage facade under an owner-scoped content hash. Database messages hold a permanent CDN reference and storage key. Retries reuse the same object. Images are restored by message ID after history trimming for send/regenerate/continue, including copied branch messages. Legacy truncated image placeholders cannot be recovered; the model is told they are unavailable instead of being sent corrupt bytes.
- Creator sendMessage accepts an optional attachments array. Creator ai.complete accepts the same attachments on user messages, or ordered text/image_url content parts. Data URLs and the platform's public /cdn/key/ URLs are supported; arbitrary remote URLs are not fetched. Existing cards that only display an image must pass its bytes/reference to this API. The creator assistant's TSX/front-UI references now explain that requirement.
- Image input capability comes from provider metadata, plus a dated OpenRouter snapshot for known official model IDs. Custom endpoints with unknown capabilities receive no unverified badge; image parts remain intact and the endpoint validates them. Known text-only models are rejected. The existing free-model fallback chain already has vision-capable alternatives, and now sees image-bearing history on every generation path.
- Image transport bytes are not counted as textual prompt tokens. The engine remains framework-agnostic and accepts a host-supplied image-token estimate for history trimming. Actual provider-reported usage continues to determine billing.
Validation
Regression tests cover account/save/persona ownership isolation, explicit no-persona and follow mode; image storage, reload, branch-style copies, prompt ID association and trimming; invalid MIME/base64/count and foreign URLs; ordered creator image parts; clipboard paste and the original plus menu; incompatible models and failed-draft restoration; native request payloads for OpenRouter, OpenAI, Anthropic, Google, Ollama and custom providers; and the vision fallback chain.
After rebasing onto the latest main: pnpm build passed all five tasks and pnpm typecheck passed all eight tasks. The full app suite passed 1,516 tests; the engine suite passed 1,199 and shared suite passed 81. The route regression suite passed three tests covering rejected historical images without losing turns or leaving generation busy. Earlier focused checks covered the composer/persona UI (24 tests), server helpers (14), and provider/vision fallbacks (65, with overlap). Tests use isolated in-memory PGlite and mocked model requests. The actual rendered composer, image preview, original plus menu and model badges were visually verified and approved. A paid live vision response was not run.
Final full server run: 3,789 tests, 3,773 passing, 13 skipped, and three failures (two obsolete global-persona assertions and one private model-catalog TTL regression). All three were corrected; the complete affected test files plus image rejection/retired-model routes were rerun together: 17 passing, zero failures. The remaining full-suite tests passed. The full server suite was not repeated after these targeted corrections.
