Skip to content

Commit 0a21aac

Browse files
committed
Remove freebuff waiting room flag
1 parent b5e8086 commit 0a21aac

17 files changed

Lines changed: 35 additions & 239 deletions

File tree

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ LINKUP_API_KEY=dummy_linkup_key
3232
LOOPS_API_KEY=dummy_loops_key
3333
ZEROCLICK_API_KEY=dummy_zeroclick_key
3434

35+
# Freebuff
36+
FREEBUFF_SESSION_LENGTH_MS=3600000
37+
3538
# Discord Integration
3639
DISCORD_PUBLIC_KEY=dummy_discord_public_key
3740
DISCORD_BOT_TOKEN=dummy_discord_bot_token

cli/src/app.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ export const App = ({
261261
}
262262

263263
// Render project picker FIRST when at home directory or outside a project.
264-
// This deliberately precedes the login/auth and waiting-room gates so the
264+
// This deliberately precedes the login/auth and freebuff session gate so the
265265
// user always gets to pick a working directory before anything else — auth
266266
// failures or a banned/queued freebuff session would otherwise replace the
267267
// picker mid-flash and look like being kicked out of the app.
@@ -340,7 +340,7 @@ interface AuthedSurfaceProps {
340340
}
341341

342342
/**
343-
* Rendered only after auth is confirmed. Owns the freebuff waiting-room gate
343+
* Rendered only after auth is confirmed. Owns the freebuff session gate
344344
* so `useFreebuffSession` runs exactly once per authed session (not before
345345
* we have a token).
346346
*/

cli/src/components/waiting-room-screen.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -496,11 +496,11 @@ export const WaitingRoomScreen: React.FC<WaitingRoomScreenProps> = ({
496496
</box>
497497
)}
498498

499-
{/* Server says the waiting room is disabled — this screen should not
500-
normally render in that case, but show a minimal message just in
501-
case App.tsx's guard is bypassed. */}
499+
{/* Compatibility fallback for older servers without the session
500+
endpoint. This should not normally render because App.tsx treats
501+
it as admitted. */}
502502
{session?.status === 'disabled' && (
503-
<text style={{ fg: theme.muted }}>Waiting room disabled.</text>
503+
<text style={{ fg: theme.muted }}>Session gate unavailable.</text>
504504
)}
505505

506506
{/* Country outside the free-mode allowlist. Terminal — polling has

cli/src/hooks/helpers/send-message.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ export const handleRunError = (params: {
523523
}
524524

525525
/**
526-
* Surface + recover from a waiting-room gate rejection. The server rejected
526+
* Surface + recover from a freebuff session gate rejection. The server rejected
527527
* the request because our seat is no longer valid; update local state so the
528528
* UI reflects reality and we stop sending requests until we re-admit.
529529
*/

cli/src/hooks/use-freebuff-session.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,7 @@ async function callSession(
7373
signal: opts.signal,
7474
})
7575
// 404 = endpoint not deployed on this server (older web build). Treat as
76-
// "waiting room disabled" so a newer CLI against an older server still
77-
// works, rather than stranding users in a waiting room forever.
76+
// a compatibility bypass so a newer CLI against an older server still works.
7877
if (resp.status === 404) {
7978
return { status: 'disabled' }
8079
}

cli/src/utils/error-handling.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export const getCountryBlockFromFreeModeError = (
9696
}
9797

9898
/**
99-
* Freebuff waiting-room gate errors returned by /api/v1/chat/completions.
99+
* Freebuff session gate errors returned by /api/v1/chat/completions.
100100
*
101101
* Contract (see docs/freebuff-waiting-room.md):
102102
* - 428 `waiting_room_required` — no session row exists; POST /session to join.

common/src/types/freebuff-session.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
import type { FreebuffAccessTier } from '../constants/freebuff-models'
22

33
/**
4-
* Wire-level shapes returned by `/api/v1/freebuff/session`. Source of truth
5-
* for the CLI (which deserializes these) and the server (which serializes
6-
* them) — keep both in sync by importing this module from either side.
7-
*
8-
* The CLI uses these shapes directly; there are no client-only states.
4+
* Shapes used by `/api/v1/freebuff/session` and the CLI. Most variants are
5+
* wire-level responses serialized by the server; explicitly documented
6+
* compatibility variants may be synthesized by the CLI for older servers.
97
*/
108

119
/**
@@ -67,8 +65,8 @@ export type FreebuffIpPrivacySignal =
6765

6866
export type FreebuffSessionServerResponse =
6967
| {
70-
/** Waiting room is globally off; free-mode requests flow through
71-
* unchanged. Client should treat this as "admitted forever". */
68+
/** Compatibility fallback for older servers without the session
69+
* endpoint. Client should treat this as "admitted forever". */
7270
status: 'disabled'
7371
}
7472
| {

docs/freebuff-waiting-room.md

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,14 @@ The waiting room is the admission control layer for **free-mode** requests again
88
2. **Gate on per-deployment health and hours** — a single fleet probe per tick (`getFleetHealth` in `web/src/server/free-session/fireworks-health.ts`) hits the Fireworks metrics endpoint and classifies each dedicated deployment as `healthy | degraded | unhealthy`. Only models whose deployment is `healthy` and currently available admit that tick; GLM 5.1 is available during 9am ET-5pm PT on weekdays, while MiniMax M2.7 is serverless and always available.
99
3. **One instance per account** — prevent a single user from running N concurrent freebuff CLIs to get N× throughput.
1010

11-
Users who cannot be admitted immediately are placed in the queue for their chosen model and given an estimated wait time. Admitted users get a fixed-length session (default 1h) bound to the model they were admitted on; chat completions use that model for the life of the session.
11+
Users who cannot be admitted immediately are placed in the queue for their chosen model and given an estimated wait time. With the current high instant-admit capacities, most users go straight from model selection to an active session; the queue only appears when a model is actually saturated. Admitted users get a fixed-length session (default 1h) bound to the model they were admitted on; chat completions use that model for the life of the session.
1212

13-
The entire system is gated by the env flag `FREEBUFF_WAITING_ROOM_ENABLED`. When `false`, the gate is a no-op and the admission ticker does not start; free-mode traffic flows through unchanged.
14-
15-
## Kill Switch
13+
## Configuration
1614

1715
```bash
18-
# Disable entirely (both the gate on chat/completions and the admission loop)
19-
FREEBUFF_WAITING_ROOM_ENABLED=false
20-
21-
# Other knob (only read when enabled)
2216
FREEBUFF_SESSION_LENGTH_MS=3600000 # 1 hour
2317
```
2418

25-
Flipping the flag is safe at runtime: existing rows stay in the DB and will be admitted / expired correctly whenever the flag is flipped back on.
26-
2719
## Architecture
2820

2921
```mermaid
@@ -186,9 +178,6 @@ Before any of those state transitions, the handler requires a resolved allowlist
186178
Response shapes:
187179

188180
```jsonc
189-
// Waiting room disabled — CLI should treat this as "always admitted"
190-
{ "status": "disabled" }
191-
192181
// In queue
193182
{
194183
"status": "queued",
@@ -272,9 +261,7 @@ For free-mode requests (`codebuff_metadata.cost_mode === 'free'`), `_post.ts` ca
272261
| 409 | `session_superseded` | Claimed `instance_id` does not match stored one — another CLI took over. |
273262
| 410 | `session_expired` | `expires_at + grace < now()` (past the hard cutoff). Client should POST /session to re-queue. |
274263

275-
Successful results carry one of three reasons: `disabled` (gate is off), `active` (`expires_at > now()`, `remainingMs` provided), or `draining` (`expires_at <= now() < expires_at + grace`, `gracePeriodRemainingMs` provided). The CLI should treat `draining` as "let any in-flight agent run finish, but block new user prompts" — see [Drain / Grace Window](#drain--grace-window) below. The corresponding wire status from `getSessionState` is `ended`.
276-
277-
When the waiting room is disabled, the gate returns `{ ok: true, reason: 'disabled' }` without touching the DB.
264+
Successful results carry one of two reasons: `active` (`expires_at > now()`, `remainingMs` provided), or `draining` (`expires_at <= now() < expires_at + grace`, `gracePeriodRemainingMs` provided). The CLI should treat `draining` as "let any in-flight agent run finish, but block new user prompts" — see [Drain / Grace Window](#drain--grace-window) below. The corresponding wire status from `getSessionState` is `ended`.
278265

279266
## Drain / Grace Window
280267

@@ -314,8 +301,6 @@ The CLI:
314301
8. **Handles chat-gate errors:** the same statuses are reachable via the gate's 409/410/428/429 for fast in-flight feedback, and the CLI calls the matching `markFreebuff*` helper to flip local state without waiting for the next poll.
315302
9. **On clean exit**, calls `DELETE /api/v1/freebuff/session` so the next user can be admitted sooner.
316303

317-
The `disabled` response means the server has the waiting room turned off. CLI treats it identically to `active` with infinite remaining time — no countdown, and chat requests can omit `freebuff_instance_id` entirely.
318-
319304
## Multi-pod Behavior
320305

321306
- **`/api/v1/freebuff/session` routes** are stateless per pod; all state lives in Postgres. Any pod can serve any request.

packages/internal/src/env-schema.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,6 @@ export const serverEnvSchema = clientEnvSchema.extend({
5656
// sweep but risks rate-limiting.
5757
BOT_SWEEP_GITHUB_TOKEN: z.string().min(1).optional(),
5858

59-
// Freebuff waiting room. Defaults to OFF so the feature requires explicit
60-
// opt-in per environment — the CLI/SDK do not yet send
61-
// freebuff_instance_id, so enabling this before they ship would reject
62-
// every free-mode request with 428 waiting_room_required.
63-
FREEBUFF_WAITING_ROOM_ENABLED: z
64-
.enum(['true', 'false'])
65-
.default('false')
66-
.transform((v) => v === 'true'),
6759
FREEBUFF_SESSION_LENGTH_MS: z.coerce
6860
.number()
6961
.int()
@@ -136,8 +128,7 @@ export const serverProcessEnv: ServerInput = {
136128
BOT_SWEEP_SECRET: process.env.BOT_SWEEP_SECRET,
137129
BOT_SWEEP_GITHUB_TOKEN: process.env.BOT_SWEEP_GITHUB_TOKEN,
138130

139-
// Freebuff waiting room
140-
FREEBUFF_WAITING_ROOM_ENABLED: process.env.FREEBUFF_WAITING_ROOM_ENABLED,
131+
// Freebuff session gate
141132
FREEBUFF_SESSION_LENGTH_MS: process.env.FREEBUFF_SESSION_LENGTH_MS,
142133
FREEBUFF_DEV_FORCE_LIMITED: process.env.FREEBUFF_DEV_FORCE_LIMITED,
143134
}

web/src/app/api/v1/chat/completions/__tests__/completions.test.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,10 @@ describe('/api/v1/chat/completions POST endpoint', () => {
8282
let mockInsertMessageBigquery: InsertMessageBigqueryFn
8383
let nextQuotaReset: string
8484

85-
// Bypasses the freebuff waiting-room gate in tests that exercise free-mode
86-
// flow without seeding a session. Matches the real return for the disabled
87-
// path so downstream logic proceeds normally.
85+
// Bypasses the freebuff session gate in tests that exercise free-mode flow
86+
// without seeding a session.
8887
const mockCheckSessionAdmissibleAllow = async () =>
89-
({ ok: true, reason: 'disabled' }) as const
88+
({ ok: true, reason: 'active', remainingMs: 60 * 60 * 1000 }) as const
9089
const mockResolveFreeModeCountryAccess = async (
9190
_userId: string,
9291
req: Parameters<typeof getFreeModeCountryAccess>[0],

0 commit comments

Comments
 (0)