Monorepo for Aesthetic.Computer aesthetic.computer

/api/ask: the model you reach depends on who is asking master

Aesthetic Computer has been buying inference for strangers. `/api/ask` proxies api.anthropic.com and api.openai.com on AC's own keys, and the whole of its authorization was a CORS origin allowlist — a browser convention, not a check. Anything that is not a browser sets the header and walks through. `make`, `paint`, `translate` and the prompt system all run on it, so this is not a forgotten endpoint: it is the AI service, already shipped, with no door. Worse than unmetered: the model came from `hint`, which is caller-supplied. There was no ceiling on what a stranger could spend per request, only on how many tokens came back. Anonymous callers are now clamped to gpt-4o-mini and 512 tokens no matter what `hint` asks for. They still get an answer — a front page that cannot demo itself to someone who has never logged in is worse than the bill — but they get it on the cheap tier, which is roughly a tenth the cost per stranger. A request carrying a valid token resolves to an @handle and reaches the model it asked for. That is the first thing a handle actually buys. Auth failure is deliberately anonymous rather than rejected. Failing closed would break `make` and `paint` for signed-in users during an Auth0 outage; failing open is the bug being fixed. The cheap tier is the safe middle, and a three-second race keeps a slow identity provider from becoming a slow endpoint. Client side, Conversation is built in five places with only a store and a slug and had no route to a token, so `setAskTokenProvider` takes one from disk.mjs at boot instead of threading it through every caller. It resolves at call time, so signing in or out is picked up on the next ask with no cache to invalidate. A missing token is not an error — it is the anonymous path. This is the gate only. Metering per handle, a daily budget, and the paid tier above it are next; the counter wants the day-bucket shape piece-hits.mjs already uses, and the entitlement lookup wants the Redis-cached shape sotce-net.mjs already uses. Worker bundle rebuilt: disk.worker.73ef99a8f734.mjs, verified, 56 sources. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1xZ1BonXHyds6EzF5H9Hb


+231 -155
5 changed files