You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(chat): bump pi-ai and validate gateway model ids at startup (#244)
## Summary
Fixes the production crash `Error: Unknown AI Gateway model id:
openai/gpt-5.4-mini`
([JUNIOR-1Q](https://sentry.sentry.io/issues/JUNIOR-1Q)) and adds the
type/runtime guardrails that would have caught it before it shipped.
**Root cause.** #237 switched the default `AI_FAST_MODEL` to
`openai/gpt-5.4-mini`, but `@mariozechner/pi-ai@0.59.0` was pinned and
its generated `vercel-ai-gateway` registry predates that entry. Every
turn where `AI_FAST_MODEL` was unset hit `resolveGatewayModel` in
`packages/junior/src/chat/pi/client.ts`, found no match, and threw.
`openai/gpt-5.4-mini` is the correct gateway id per [Vercel's
catalog](https://vercel.com/ai-gateway/models/gpt-5.4-mini) — 0.68.1 is
just the first pi-ai release that knows about it.
**Fix:**
- Bump `@mariozechner/pi-ai` and `@mariozechner/pi-agent-core` from
`0.59.0` → `0.68.1`. Catalog now includes `openai/gpt-5.4-mini`,
`gpt-5.4-nano`, `gpt-5.3-chat`, etc.
- `Agent.replaceMessages()` was removed in pi-agent-core 0.68; assign
`agent.state.messages` directly instead (the setter copies the top-level
array). One call site in `respond.ts`.
**Guardrails so this doesn't regress silently again** (answering
@dcramer's review question on whether types could have caught this):
- **Compile-time check on default literals.** `config.ts` wraps
`DEFAULT_MODEL_ID` / `DEFAULT_FAST_MODEL_ID` in
`getModel("vercel-ai-gateway", ...)` calls. `getModel`'s second generic
is `TModelId extends keyof (typeof MODELS)[TProvider]`, so a stale
literal becomes a `tsc` error at the call site. Verified by temporarily
swapping in a bogus id — `tsc` emitted `TS2345: Argument of type
'"openai/gpt-5.4-mini-bogus"' is not assignable to parameter of type
'"openai/gpt-5.4" | ... | "zai/glm-5v-turbo"'`.
- **Runtime check on env overrides.** New `toGatewayModelId()` validates
every `AI_MODEL` / `AI_FAST_MODEL` / `AI_VISION_MODEL` against pi-ai's
registry at `readBotConfig` time. A typo in env now throws "Unknown AI
Gateway model id: …" at startup, not mid-turn. New regression test in
`chat-config.test.ts` pins this behavior; existing tests moved from
placeholder ids (`anthropic/custom-model`) to real catalog ids
(`anthropic/claude-opus-4.6`, `anthropic/claude-haiku-4.5`).
We can't go further (i.e. type `BotConfig.fastModelId: GatewayModelId`)
because pi-ai doesn't export `MODELS` from its package entry — the
literal union is not importable as a nameable type. Defaults are
compile-checked and env is runtime-checked at startup, which covers both
observed regression paths.
Fixes JUNIOR-1Q.
## Review & Testing Checklist for Human
- [ ] Skim the pi-ai / pi-agent-core 0.60 → 0.68 changelog for any other
API breaks we haven't hit yet — I verified via full typecheck + `pnpm
test` but didn't walk every intermediate release.
- [ ] After merge, confirm JUNIOR-1Q stops firing in production with the
new release.
- [ ] If any deployed env has a typo in `AI_MODEL` / `AI_FAST_MODEL` /
`AI_VISION_MODEL`, the process will now fail to boot instead of failing
on the first turn. Worth eyeballing current prod env before merge.
### Notes
- `pnpm typecheck`, `pnpm lint`, and `pnpm test` (707 tests) all pass
locally.
- No `BotConfig` signature changes —
`modelId`/`fastModelId`/`visionModelId` stay typed as `string` since we
can't name a `GatewayModelId` union without pi-ai re-exporting `MODELS`.
Link to Devin session:
https://app.devin.ai/sessions/bf10e4f407dd4265a27a7d7f463eb1c3
---------
Co-authored-by: Devin AI <devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: GPT-5 <devin@cognition.ai>
0 commit comments