From d77e00bf9a257baa99aa4aee3724d9bc1526eb23 Mon Sep 17 00:00:00 2001 From: Anish KB Date: Thu, 27 Aug 2026 21:14:04 +0530 Subject: [PATCH 1/4] Replace decommissioned Groq model, add CI Groq retired llama-3.3-70b-versatile. The three routes using it (goal-plan, voice-pep, weekly-insight) returned 500 with "model does not exist or you do not have access to it". Switched them to openai/gpt-oss-20b, which coach, daily-plan and weekly-dungeon were already using successfully. All six routes verified live against production after this change. Also adds a CI workflow (npm ci, tsc --noEmit, lint, build) on push and PR to main. The production build was silently broken for ~32 days after the Snyk bump to next 16.2.9 left node_modules drifted from the lockfile; nothing surfaced it. npm ci in CI catches exactly that. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 32 ++++++++++++++++++++++++++++++++ app/api/goal-plan/route.ts | 2 +- app/api/voice-pep/route.ts | 2 +- app/api/weekly-insight/route.ts | 2 +- 4 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..3cda460 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,32 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + # `npm ci` installs strictly from package-lock.json. A drifted node_modules + # is exactly what broke the build for a month without anyone noticing. + - name: Install + run: npm ci + + - name: Typecheck + run: npx tsc --noEmit + + - name: Lint + run: npm run lint + + - name: Build + run: npm run build diff --git a/app/api/goal-plan/route.ts b/app/api/goal-plan/route.ts index 1ab00d5..e58217f 100644 --- a/app/api/goal-plan/route.ts +++ b/app/api/goal-plan/route.ts @@ -2,7 +2,7 @@ import { groq } from '@ai-sdk/groq'; import { generateText } from 'ai'; import { z } from 'zod'; -const MODEL = groq('llama-3.3-70b-versatile'); +const MODEL = groq('openai/gpt-oss-20b'); export const maxDuration = 30; diff --git a/app/api/voice-pep/route.ts b/app/api/voice-pep/route.ts index f231695..9441283 100644 --- a/app/api/voice-pep/route.ts +++ b/app/api/voice-pep/route.ts @@ -4,7 +4,7 @@ import { z } from 'zod'; export const maxDuration = 30; -const TEXT_MODEL = groq('llama-3.3-70b-versatile'); +const TEXT_MODEL = groq('openai/gpt-oss-20b'); // ElevenLabs free-tier starter voice. Override with ELEVENLABS_VOICE_ID env to swap. const DEFAULT_VOICE_ID = 'EXAVITQu4vr4xnSDxMaL'; // Sarah - warm, calm female diff --git a/app/api/weekly-insight/route.ts b/app/api/weekly-insight/route.ts index 847f67b..e1809e9 100644 --- a/app/api/weekly-insight/route.ts +++ b/app/api/weekly-insight/route.ts @@ -2,7 +2,7 @@ import { groq } from '@ai-sdk/groq'; import { generateText } from 'ai'; import { z } from 'zod'; -const MODEL = groq('llama-3.3-70b-versatile'); +const MODEL = groq('openai/gpt-oss-20b'); export const maxDuration = 30; From 39f7e328dc8b6d861598c32bf1fe03e51028f09c Mon Sep 17 00:00:00 2001 From: Anish KB Date: Thu, 27 Aug 2026 21:30:26 +0530 Subject: [PATCH 2/4] CI: run on Node 22, not 20 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @ai-sdk/gateway, @ai-sdk/groq and @ai-sdk/provider all declare "node": ">=22". On Node 20 the install emitted EBADENGINE for each, and npm 10 (bundled with Node 20) installed @ai-sdk/*@4.0.0 — versions the committed lockfile does not contain — which broke the build with "The export serializeModelOptions was not found". A fresh clone of this branch on Node 22 with npm 11 installs exactly what the lockfile pins (@ai-sdk/groq@3.0.38) and builds clean. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3cda460..d222373 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,10 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: 20 + # @ai-sdk/* declare "node": ">=22". Node 20 is unsupported by our own + # dependencies and npm 10 (bundled with 20) resolved packages the + # lockfile does not contain, breaking the build. + node-version: 22 cache: npm # `npm ci` installs strictly from package-lock.json. A drifted node_modules From 2bec6518777ab66f3614c35b019e50db74f3d063 Mon Sep 17 00:00:00 2001 From: Anish KB Date: Thu, 27 Aug 2026 21:36:49 +0530 Subject: [PATCH 3/4] CI: print resolved AI SDK versions to diagnose lockfile mismatch Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d222373..0dd5664 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,6 +25,15 @@ jobs: - name: Install run: npm ci + # Diagnostic: CI installs 377 packages where macOS installs 369 from the + # same byte-identical lockfile, pulling @ai-sdk/*@4.0.0 which the lock + # does not contain. Print the resolved tree so the mismatch is visible. + - name: Show resolved AI SDK versions + run: | + node -v && npm -v + npm ls @ai-sdk/groq @ai-sdk/gateway @ai-sdk/provider @ai-sdk/provider-utils ai || true + cat .npmrc 2>/dev/null || echo "(no repo .npmrc)" + - name: Typecheck run: npx tsc --noEmit From 389546c81e859dd797ba1ba17c81ac91efb420a5 Mon Sep 17 00:00:00 2001 From: Anish KB Date: Fri, 28 Aug 2026 15:54:56 +0530 Subject: [PATCH 4/4] Fix unbuildable main: lift @ai-sdk/provider-utils override to ^5.0.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two Snyk changes on main contradict each other: - PR #2 bumped @ai-sdk/groq to ^4.0.0. groq@4.0.0 depends on @ai-sdk/provider-utils 5.0.0. - An earlier SSRF fix added overrides["@ai-sdk/provider-utils"]="^4.0.41". The override caps provider-utils below what groq@4 needs. 4.0.41 does not export serializeModelOptions, which groq@4.0.0 imports, so every build since a899a87 failed with: The export serializeModelOptions was not found in module @ai-sdk/provider-utils This is why the last successful Vercel deploy was 32 days ago. Lifting the override to ^5.0.0 resolves provider-utils@5.0.32, which groq@4 requires. npm audit confirms the ai-sdk and undici advisories the override was protecting against remain resolved — a newer version supersedes the pin, so no security regression. Verified: tsc --noEmit exit 0, next build compiles all six routes. Co-Authored-By: Claude Opus 5 (1M context) --- package-lock.json | 50 +++++++++++++++++++++++++++-------------------- package.json | 2 +- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/package-lock.json b/package-lock.json index ac9edc9..83211ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -73,33 +73,34 @@ } }, "node_modules/@ai-sdk/provider-utils": { - "version": "4.0.41", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-4.0.41.tgz", - "integrity": "sha512-I7hhjfw01yEI8NkuAsT8Mv6xbWFr/lqLXMdaJQ2zWfXEpxog1eT7skDcv1+RY29/+5btzH8wD+vVvy48bk9oNQ==", + "version": "5.0.32", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-5.0.32.tgz", + "integrity": "sha512-MZUhlINn6FzKIWuX3T36h+yM9d7bG+yatH+kC99ZCe0DHxXfP73KwaoLiLcZDPQDamFyO3umPPBLJieZJyG4DQ==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider": "3.0.14", + "@ai-sdk/provider": "4.0.8", "@standard-schema/spec": "^1.1.0", + "@workflow/serde": "4.1.0", "eventsource-parser": "^3.0.8", - "undici": "^5.29.0" + "undici": "^7.28.0" }, "engines": { - "node": ">=18" + "node": ">=22" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "node_modules/@ai-sdk/provider-utils/node_modules/@ai-sdk/provider": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.14.tgz", - "integrity": "sha512-5X1k57JBJ4H7H1QjX7CnJYAB1I19r/trVZTMcSms7/kLNZ8RaU4Nt2agcwZzv82Hfx6Q7/TOLU7agAKeFfc8cA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-4.0.8.tgz", + "integrity": "sha512-aWO7iwhFUGf347tCwNGggggfmZigaSu7TF739IZSrWWABUp7zkb4Cr3fMqvBe5EIS7ABJJu3Cadn0g/zs1G0QQ==", "license": "Apache-2.0", "dependencies": { "json-schema": "^0.4.0" }, "engines": { - "node": ">=18" + "node": ">=22" } }, "node_modules/@alloc/quick-lru": { @@ -146,6 +147,7 @@ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", @@ -1319,17 +1321,6 @@ "node": ">=12.4.0" } }, - "node_modules/@opentelemetry/api": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", - "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -1671,6 +1662,7 @@ "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -1730,6 +1722,7 @@ "integrity": "sha512-plR3pp6D+SSUn1HM7xvSkx12/DhoHInI2YF35KAcVFNZvlC0gtrWqx7Qq1oH2Ssgi0vlFRCTbP+DZc7B9+TtsQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.59.2", "@typescript-eslint/types": "8.59.2", @@ -2258,12 +2251,19 @@ "node": ">= 20" } }, + "node_modules/@workflow/serde": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@workflow/serde/-/serde-4.1.0.tgz", + "integrity": "sha512-pav4F2BoirECWR7Nf1TKt+2eETcBj7jj4cBefQ8VXQCA6NPkaKeLfj/zMgi+3zYV5ZIBT4GuUiphsj0/b9hPQQ==", + "license": "Apache-2.0" + }, "node_modules/acorn": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2624,6 +2624,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.44", "caniuse-lite": "^1.0.30001806", @@ -3191,6 +3192,7 @@ "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -3376,6 +3378,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -5548,6 +5551,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -5557,6 +5561,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -6248,6 +6253,7 @@ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -6410,6 +6416,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -6693,6 +6700,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index 10dc9a0..1485f4b 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ }, "overrides": { "postcss": "^8.5.15", - "@ai-sdk/provider-utils": "^4.0.41", + "@ai-sdk/provider-utils": "^5.0.0", "undici": "^6.21.1" }, "devDependencies": {