Files
imagen/AGENTS.md
T

3.6 KiB

AGENTS.md

Bun + TypeScript single-file server that exposes an OpenAI-compatible image generation endpoint and serves a small vanilla HTML/JS playground.

Runtime

  • Bun, not Node. See CLAUDE.md for the full Bun-vs-Node cheatsheet (prefer Bun.serve, Bun.file, bun:test, Bun.sql, etc.). Do not add dotenv — Bun loads .env automatically.
  • Bun version baseline: 1.3.13 (per README.md).

Commands

  • Install: bun install
  • Dev (HMR): bun run devbun --hot ./index.ts
  • Start: bun run startbun ./index.ts
  • Typecheck: no script defined. Use bunx tsc --noEmit (tsconfig already sets noEmit: true, so plain bunx tsc works too).
  • Tests / lint / formatter: none configured. If adding tests, use bun test.

The server binds 0.0.0.0 (see index.ts:61), so it is reachable from other hosts on the network when running locally — be mindful when entering API keys.

Architecture

  • index.ts — the entire backend. One Bun.serve instance with:
    • / serves index.html via Bun's HTML import (import index from "./index.html").
    • POST /api/generate accepts { baseURL, apiKey, model, prompt, size, referenceImages? }. It returns { images: string[] } where each entry is a data: URL (base64).
    • Two code paths inside the handler:
      1. No referenceImages → uses @ai-sdk/openai-compatible + generateImage from ai.
      2. referenceImages present → hand-rolled multipart/form-data POST to ${baseURL}/images/edits (see generateWithReference). The AI SDK does not currently expose image edits for OpenAI-compatible providers, so this path bypasses it on purpose. The edits endpoint is gpt-image series only (see UI hint in index.html).
  • index.html — self-contained UI: inline CSS, plain DOM JS, no build step. Text fields (baseURL, apiKey, model, size, prompt) persist in localStorage under the aip:<field> prefix. Reference images are kept in an in-memory refImages array as base64 data URLs and are not persisted — refreshing the page drops them. There is no React code despite react / react-dom / @types/react* being in package.json — treat those deps as latent. Do not invent a React frontend unless asked.
  • No router, no DB, no auth. API key is supplied per-request by the browser and never stored server-side.

TypeScript conventions

tsconfig.json is strict with bundler-mode resolution:

  • strict, noUncheckedIndexedAccess, noImplicitOverride, noFallthroughCasesInSwitch are on — array/object index access is T | undefined and must be narrowed.
  • verbatimModuleSyntax + moduleDetection: "force" — use import type for type-only imports; every file is a module.
  • allowImportingTsExtensions is on; .ts extensions in imports are fine.
  • jsx: "react-jsx" is set but unused (see frontend note above).

When extending the API

  • Add new routes inside the routes object in index.ts; keep the { POST: async (req) => … } shape used by /api/generate.
  • Return JSON with Response.json(...). Validate the request body shape explicitly — the existing handler asserts required fields and returns 400 before calling the model.
  • The AI SDK image type is loose; the current handler casts to { mediaType?: string; base64?: string }. Mirror that pattern rather than trusting field presence.
  • For anything the AI SDK does not cover (e.g. image edits, masks, variations), follow generateWithReference: build FormData with Blobs decoded from the incoming data URLs and fetch the upstream endpoint directly with the caller's Authorization: Bearer <apiKey>.