fix(voice): set MANA_LLM_URL on mana-web — $env/dynamic/private hides PUBLIC_

The first prod deploy of voice quick-add (3b41b39a3) silently fell
back for every transcript: title=transcript verbatim, dueDate=null,
priority=null, labels=[]. The endpoint code was reaching the
fallback() path even though mana-llm was healthy and reachable from
inside the mana-web container.

Root cause: SvelteKit's $env/dynamic/private explicitly excludes any
env var that starts with the public prefix (default PUBLIC_). The
parse-task code read

  env.MANA_LLM_URL || env.PUBLIC_MANA_LLM_URL || 'http://localhost:3025'

expecting to fall back to PUBLIC_MANA_LLM_URL when MANA_LLM_URL was
unset, but $env/dynamic/private treats PUBLIC_MANA_LLM_URL as if it
didn't exist on the server side. So it always fell through to
http://localhost:3025, which from inside mana-web is nothing,
fetch threw, and coerce returned the fallback shape.

Two fixes:

1. docker-compose.macmini.yml — set MANA_LLM_URL (no prefix) on
   mana-web alongside PUBLIC_MANA_LLM_URL. The PUBLIC_ var is still
   needed for the browser-side playground and status page; the
   private one is what the parse endpoints actually read.

2. parse-task and parse-habit — drop the dead env.PUBLIC_MANA_LLM_URL
   fallback so the next dev who reads the code doesn't think it'd
   ever work. Add a comment explaining the SvelteKit gotcha so the
   next person setting up a new env var doesn't repeat this mistake.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-08 17:20:03 +02:00
parent 5af4ddab3c
commit a7f3577ee2
3 changed files with 19 additions and 5 deletions

View file

@ -766,11 +766,20 @@ services:
# Analytics & Error Tracking
PUBLIC_UMAMI_WEBSITE_ID: 32777167-e026-4618-933a-3429120b479b
PUBLIC_GLITCHTIP_DSN: ${GLITCHTIP_DSN_MANA_WEB:-}
# Speech-to-Text proxy: SvelteKit /api/v1/memoro/transcribe and
# /api/v1/dreams/transcribe forward to mana-stt via Cloudflare Tunnel.
# The browser never sees the API key — it stays server-side.
# Speech-to-Text proxy: SvelteKit /api/v1/voice/transcribe forwards
# to mana-stt via Cloudflare Tunnel. The browser never sees the API
# key — it stays server-side.
MANA_STT_URL: https://gpu-stt.mana.how
MANA_STT_API_KEY: ${MANA_STT_API_KEY:-}
# LLM proxy: /api/v1/voice/parse-task and /api/v1/voice/parse-habit
# call mana-llm for structured extraction. Set WITHOUT the PUBLIC_
# prefix because $env/dynamic/private explicitly excludes vars
# that start with the public prefix — so the parse endpoints
# would never see PUBLIC_MANA_LLM_URL even though it's right
# there in the compose env. Both vars exist; the public one
# is read by the browser-side playground and status page.
MANA_LLM_URL: http://mana-llm:3025
MANA_LLM_API_KEY: ${MANA_LLM_API_KEY:-}
ports:
- "5000:5000"
healthcheck: