v0.0.56 — AI Keys → Connectors + dashboards chat mode
Released: 2026-05-06.
AI Keys folded into Connectors
Per-org BYO LLM keys now live in honeyframe.data_connectors (category='llm', connector_type in openai_llm / anthropic_llm / ollama_llm) alongside every other connector. The legacy /ai-keys page and honeyframe.org_llm_credentials table are retired.
Operator impact:
- The
/ai-keysURL now 301-redirects to/connectors. Old bookmarks keep working. - The
org_llm.pyrouter endpoints (GET / PUT / DELETE /api/org/llm-keys) return HTTP 410 Gone with a detail string naming the new home. Old curl-based admin scripts see "moved" instead of a generic 404 — drop their use in v0.0.57+. - A two-step migration runs automatically on
honeyframe update: a Python backfill decrypts each legacy row and re-encrypts it as a connector secret; a conditional SQL drop removesorg_llm_credentialsonce every legacy row has a matching connector row. Partial backfills preserve the table for ops to investigate.
The platform's services/llm_credentials.resolve_for_org() is now single-source: data_connectors → platform default → None.
See Connectors → Non-queryable types for the LLM-provider catalog.
Dashboards — chat-primary mode (Phase 1+2+3)
Three architectural pillars of the Figma-Make-style dashboard redesign land behind a feature flag (HONEYFRAME_DASHBOARD_MUTATIONS=1). All work is additive; the existing toolbar keeps working unchanged. The only visible UI change for users is a new Chat mode toggle in the dashboard header.
Phase 1 — typed mutation endpoint
POST /api/dashboards/{id}/mutations accepts a batch of typed Mutation envelopes and applies them atomically. Eight types cover every legacy toolbar action: set_period, add_filter, remove_filter, add_card, remove_card, update_card_config, change_card_type, set_layout. One config UPDATE and one forced snapshot per batch — chat batches what counts as "one change" and the server honors that boundary.
Phase 2 — chat thread persistence
New honeyframe.dashboard_chat_messages table persists per-dashboard conversation with mutation_ids + revision_number backrefs so each turn is a navigable change-log entry. POST /api/dashboards/ai-chat refactored: create emits add_card mutations; modify emits change_card_type + update_card_config. Both flow through apply_mutations() so chat-driven and toolbar-driven edits reach the database via the same code path. GET /api/dashboards/{id}/chat-thread hydrates the panel.
Phase 3 — chat panel + Chat mode toggle
A new DashboardChatPanel renders in two modes — fixed-position overlay (legacy) or in-flow flex rail (chat-primary). The hook auto-detects the server flag via 404 — the panel hides itself on tenants where HONEYFRAME_DASHBOARD_MUTATIONS is unset. The composer carries a model picker fed by /api/chat/models; selection persists to localStorage and threads through to /ai-chat via an optional model field on AIChatRequest. The header Chat mode toggle wraps the page in a flex shell and hides the toolbar Row 2 + sticky AI bar; toggling off restores the legacy UI instantly.
honeyframe update actually runs migrate.py on existing tenants
Both honeyframe install and honeyframe update previously hard-coded /opt/honeyframe/venv/bin/python (the legacy in-tree venv retired 2026-04-18) and required install.conf (only present on fresh installs from setup-customer.sh). Existing tenants who upgraded from older versions silently skipped every migration since the migration was added.
A new _run_migrations() helper:
- Picks
/opt/honeyframe/venv/bin/pythonif it exists, else falls back to systempython3. - Tries
install.conffirst; falls back to deriving--db-host/--db-port/--db-name/--db-user/--db-passfrompaas/backend/.env. - Prints a recovery hint when neither is available — never silently no-ops.
Existing tenants need their missing v0.0.54+ seeds (seed_role_aligned_groups, seed_connector_permissions) applied manually before the next update; subsequent updates run cleanly through the new helper.
migrate.py survives partial failure
Every migration SQL file is wrapped in BEGIN … COMMIT. When a statement fails, psycopg2 leaves the connection in current transaction is aborted state until ROLLBACK. The runner loop's next BEGIN then fails with commands ignored until end of transaction block — and so does every subsequent migration. One bad migration nuked the rest.
cursor.execute("ROLLBACK") is now explicit in both the FAIL and the WARN-downgrade paths, so the connection is clean for the next migration. Verified end-to-end on test ECS:
- Before:
Done: 6 applied, 0 skipped, 6 failed (5 cascade) - After:
Done: 10 applied, 1 skipped, 4 failed (4 legit)