Files
Keysat 7a62690a4a v1.1.0:4 — multi-config AI, background generation, ollama auto-detect, system prompt overhaul
User-feedback-driven release after testing v1.1.0:3. Nine themes:

1. Multi-config persistence
   - New AIConfigProfile table (per-user). Save N configs, toggle one
     active. Switching providers no longer wipes the previous setup.
   - UserPreferences gains activeAIConfigId; legacy single-config
     columns are mirrored from the active profile so existing reads
     keep working without conditional logic.
   - Idempotent boot migration lifts any existing single-config row
     into a default profile.

2. Ollama auto-detect
   - The "Add config" form probes /api/tags on the StartOS internal
     addresses (ollama.startos / ollama.embassy on :11434). If
     reachable: URL pre-fills, model field becomes a dropdown of
     installed models. Fixes the copy-paste UX.

3. Curated model dropdowns for major providers
   - Claude: Opus 4.7, Sonnet 4.6 (1M ctx), Haiku 4.5
   - OpenAI: GPT-5.5, 5.4, 5.4-mini, 5.4-nano
   - Gemini: 3.1-pro-preview, 2.5-pro, 2.5-flash, etc.
   - "Other (type your own)" stays for niche models.
   - Fixes "I tried gemini-3.0-pro and got 404."

4. Background generation
   - lib/ai/generationRunner.ts: detached runner with in-memory
     pub/sub bus. POST /api/ai/generate kicks it off and returns
     immediately. SSE stream attaches by id. The runner survives
     request cancellation; navigating away no longer kills it.
   - New AIGeneration columns: progressText (in-flight stream),
     durationMs (final wall-clock).
   - Generate UI shows a banner explaining background-safety.
   - History detail page polls progress + renders partial JSON
     live for cross-process resume (page refresh, new tab).

5. System prompt overhaul
   - lib/ai/systemPromptBase.ts: structural contract prepended to
     every template. Forces JSON-only output, library-exerciseId
     usage (kills "exerciseId doesn't belong to this user" errors),
     and per-resistance-exercise suggestedWeight (with-history vs
     without-history variants).
   - aiExerciseSchema + ProgramExercise gain suggestedWeight +
     suggestedWeightUnit. Starting a workout from a ProgramDay
     pre-populates SetLog.weight from the suggestion.

6. Test connection improvements
   - Latency in seconds (was ms — confusing for slow Ollama).
   - Stale "✓ Connected" clears on form change.
   - Per-config Test (no need to activate first).
   - Generous maxOutputTokens for thinking models.
   - Gemini surfaces finishReason on empty response (e.g. "blocked
     by safety filter") instead of generic "empty response."
   - Test endpoint accepts a draft body so you can verify before
     saving + before activating.

7. History detail view
   - Click row → full program tree + exact prompts sent. Apply from
     here without re-generating. Pending rows poll for progress.

8. Sidebar sub-navigation
   - AI: Generate / History / Templates
   - Settings: General / Password / Sessions / AI integration /
     Export / Instance (admin) / Danger zone, with anchor scroll.

9. API key UX
   - "Key saved" indicator on saved configs (was confusing to see
     an empty input after a successful save).

Schema migrations (additive, idempotent in entrypoint):
  - AIConfigProfile table created
  - UserPreferences.activeAIConfigId
  - AIGeneration.progressText + durationMs
  - ProgramExercise.suggestedWeight + suggestedWeightUnit

Tests: 16 new (systemPromptBase, modelMenu, generationRunner). 177
total pass.
2026-05-11 08:09:01 -05:00

110 lines
6.0 KiB
TypeScript

import { IMPOSSIBLE, VersionInfo } from '@start9labs/start-sdk'
/**
* v1.1.0:4 — multi-config AI integration, background generation,
* ollama auto-detect, system-prompt overhaul, history
* detail view, sidebar sub-nav.
*
* Driven by post-v1.1.0:3 user feedback. The biggest themes:
*
* 1) Multi-config persistence
* - You can save N AI configs (one per provider, or several of the
* same provider with different models/keys), toggle one as the
* "active" config, and per-config "Test connection" to verify
* before activating. Switching providers no longer means losing
* the previous setup.
* - New schema: AIConfigProfile table (per-user). UserPreferences
* grows `activeAIConfigId`; the legacy single-config columns are
* kept and mirrored from the active profile so any old code path
* that reads from prefs continues to work.
* - On boot, any user who already had a single-config setup gets
* that config lifted into a default AIConfigProfile + activated.
* Idempotent.
*
* 2) Ollama auto-detect
* - The "Add AI config" form probes /api/tags on the StartOS
* internal addresses (ollama.startos:11434, ollama.embassy:11434).
* If reachable, the URL field auto-fills and the model field
* becomes a dropdown of installed models. No more memorizing
* "the right URL" or pasting a model tag.
*
* 3) Model dropdowns for the leading providers
* - Settings now offers a curated dropdown of recommended models
* for Claude (Opus 4.7, Sonnet 4.6, Haiku 4.5), OpenAI (GPT-5.5,
* 5.4, 5.4-mini, 5.4-nano), and Gemini (3.1-pro-preview, 2.5-pro,
* 2.5-flash). "Other (type your own)" stays available for power
* users on niche models. Fixes the "I tried gemini-3.0-pro and
* got 404" footgun.
*
* 4) Background generation
* - Generation now runs server-side via a detached runner. Closing
* the page or navigating away no longer kills it — the row keeps
* filling in. The Generate UI surfaces a banner explaining this.
* - The new History detail page polls progress + renders the
* partial JSON live; reload-during-streaming "just works." Useful
* for slow local Ollama runs.
* - New AIGeneration columns: progressText (in-flight stream),
* durationMs (final wall-clock).
*
* 5) System prompt overhaul
* - lib/ai/systemPromptBase.ts: a structural contract prepended to
* every template. Forces JSON-only output (no markdown fences),
* forces use of library exerciseIds (no more "exerciseId doesn't
* belong to this user" on apply), and forces a suggestedWeight
* per resistance exercise — both with-history (relative to user's
* lifts) and without-history (% of typical 1RM) variants.
* - aiExerciseSchema gains suggestedWeight + suggestedWeightUnit.
* ProgramExercise gains the same columns. Starting a workout from
* a ProgramDay now pre-populates SetLog.weight from the suggestion
* so users have a target on day 1 instead of a blank field.
*
* 6) Test connection improvements
* - Latency reported in seconds (was ms — confusing for slow Ollama).
* - Stale "✓ Connected" no longer lingers when you change the form.
* - Gemini surfaces finishReason when the response is empty (e.g.
* "blocked by safety filter") instead of the generic "empty
* response — check the model name."
* - Test ping uses generous maxOutputTokens so thinking models
* (Gemini 2.5/3.x, OpenAI o-series) actually emit text after
* reasoning instead of running out of budget.
* - Per-config Test button (no need to activate first).
*
* 7) History detail view
* - Click any AIGeneration row → full read-only program tree, plus
* the exact prompts sent. Apply from here without re-generating.
* - In-flight rows poll for live progress.
*
* 8) Sidebar sub-navigation
* - "AI" expands to Generate / History / Templates.
* - "Settings" expands to General / Password / Sessions /
* AI integration / Export / Instance / Danger zone, with
* anchor scroll to the matching section.
*
* 9) API key UX
* - "Key saved" indicator on saved configs (was confusing to see
* an empty input field after a successful save).
*
* Migrations:
* - AIConfigProfile table created.
* - UserPreferences.activeAIConfigId added.
* - AIGeneration.progressText + .durationMs added.
* - ProgramExercise.suggestedWeight + .suggestedWeightUnit added.
* - One-shot lift of the legacy single-config row into a default
* AIConfigProfile per user.
*
* /data is unchanged in spirit — all migrations are additive ALTERs
* via the boot entrypoint. Existing programs/workouts/exercises stay
* exactly as they were.
*/
export const v_1_1_0_4 = VersionInfo.of({
version: '1.1.0:4',
releaseNotes: {
en_US:
'AI integration overhauled based on user testing: (1) save MULTIPLE AI configs and switch between them — Claude, OpenAI, Gemini, custom OpenAI-compatible, Ollama all coexist with one toggled active; (2) Ollama auto-detect — the form probes ollama.startos:11434 and shows your installed models in a dropdown, no copy-paste; (3) curated model dropdowns for Claude / OpenAI / Gemini with current 2026 models (Claude Opus 4.7, Sonnet 4.6, GPT-5.5, Gemini 3.1 Pro Preview, etc.); (4) generation now runs in the BACKGROUND — close the page, come back, find your program in History; (5) system prompt rewritten so the model picks library exercises only (no more "exerciseId doesn\'t belong to this user" errors) and suggests starting weights per exercise (which seed your first workout when you start a program day); (6) generation duration shown alongside cost; (7) Gemini "empty response" now reports the actual finishReason (safety filter, max tokens, etc.); (8) sidebar shows sub-navigation for AI + Settings sections; (9) click any History row to see the full program tree without applying it. No data loss; the schema migration runs additively at boot.',
},
migrations: {
up: async () => {},
down: IMPOSSIBLE,
},
})