Skip to content

v0.2.70

Choose a tag to compare

@larryro larryro released this 11 May 01:37
bd13c99

v0.2.70 — Data-protection hardening, self-hosted docs, provider passthrough

This release lands a 14-phase data-protection and retention hardening cornerstone (legal hold, audit-chain checkpoints, RAG bearer auth + SSRF guards, GDPR Art. 17 erasure end-to-end, per-category retention floors), replaces Mintlify-hosted docs with a self-hosted tale-docs service that shares chrome and i18n with the marketing site, and adds providerOptions passthrough so OpenRouter quantization, OpenAI service_tier, Together safety_model, and similar provider features can be configured without code changes.

🔒 Security

  • Data-protection & retention hardening (14 phases) — opt-in RAG bearer auth (RAG_AUTH_TOKEN), 169.254.0.0/16 + 0.0.0.0/8 + fc00::/7 CIDR blocklist + cloud-metadata hostname blocklist on RAG_URL (with redirect: 'manual' to block IMDS pivots), audit-log HMAC-SHA256 chain with checkpoint rows, env-tunable per-category retention floors (audit min hardcoded at 365d), legal hold with maker-checker release flow, cascade-correct thread deletion, RLS gap fix for trashed/expired threads (#1676)
  • Provider host policy + developer-settings gate — IMDS hard-block + RFC1918 opt-in (TALE_ALLOW_PRIVATE_PROVIDER_HOSTS) on provider base URLs, developerSettings ability gate on all provider mutations/probes, secrets-first delete order, audit logging on provider changes (#1694)
  • Quantization variant validation — agent JSON @quant suffixes validated against declared quantizations; bogus variants rejected with UNKNOWN_MODEL_VARIANT (#1697)

🤖 Model & Provider

  • providerOptions passthrough — provider- and model-level JSON forwarded verbatim into LLM request bodies (OpenRouter quantization/routing, OpenAI service_tier, Together safety_model); Zod deny-list blocks body-overwrite keys (model, messages, max_tokens, …) (#1694)
  • Quantization variants as first-class selectable models — each quantizations entry shows up as its own pickable model (e.g. GLM 5.1 FP8 vs GLM 5.1 FP4) in chat, arena, and agent editors; encoded as provider:base@quant end-to-end (#1697)
  • Catalog refresh — GLM 5.1 / 5-turbo / 5v-turbo, Kimi K2.6, Qwen 3.6 max-preview/plus/flash/35b-a3b, Gemma 4 31b-it / 26b-a4b-it added to OpenRouter (#1694)
  • OpenRouter model list, prices, and pricing adjustments refreshed (multiple chore commits)
  • nvidia/nemotron-3-super repointed to the live OpenRouter id nvidia/nemotron-3-super-120b-a12b; pricing aligned with the live API

🚀 Features

  • GDPR Art. 17 admin UI — self-serve data-subject-requests page under Settings > Governance, structured reasonCode capture, single-grant Art. 12(3) extension (1–60 days), SLA countdown badge, audit timeline, inline legal-hold block panel (#1696)
  • Self-hosted docs service — Mintlify Cloud replaced by services/docs/ (TanStack Start), shared @tale/webui chrome with the marketing site, Mintlify-compatible MDX components, ⌘K search, per-page .md endpoints, /llms.txt + /llms-full.txt, AI page-actions menu (Open in ChatGPT/Claude/Cursor) (#1680)
  • Server-side locale detection + cross-subdomain cookie redirect — first-time de/fr browsers get 302'd to /de / /fr and a tale_locale cookie is set; cookie domain configurable via LOCALE_COOKIE_DOMAIN so tale.dev and docs.tale.dev share the preference (#1690)
  • Legal pages moved to marketing site with PDF downloads — privacy-policy, terms-of-service, DPA, personalization now at /legal/<slug> with a Playwright-generated dist/<slug>.pdf per locale (#1679)
  • Pricing-page user-count slider — 25–1000 with manual override; per-user breakdown on the Enterprise card (#1677)
  • Standalone tale-web / tale-docs container publishing — both sites get independent compose stacks and ship to ghcr.io/tale-project/tale/tale-{web,docs} on tagged releases; Discord webhook replaces Microsoft Teams for marketing form submissions (#1683)

⚡ Performance

  • Docs cold-load cut ~60%mermaid-vendor (719 KB gzipped) stripped from the entry preload graph and lazy-loaded only when a Mermaid diagram is on the page; ~30 individual lucide-react icon chunks coalesced into a single lucide-vendor chunk (#1689)

🛠 Improvements

  • Multi-language provider/model descriptionsresolveProviderLocale + resolveModelLocale mirror the agent-resolver fallback chain; per-locale tab editor in the provider edit panel; every model description in examples/providers/*.json translated into de + fr
  • Provider models search + UX polish — search input + empty state on the provider detail page (filters id, display name, description, tags — raw + localized); separate "Default models" panel; "Webhook" renamed to "Workers" in agent settings (#1693)
  • @tale/markdown package extracted — chat, docs, and marketing share one Shiki singleton, one component set, and one styling pass; streaming primitives (incremental reveal, mid-stream repair, CJK plugin) move in; fixes code-block line-number drift on trailing-newline blocks and Mermaid parse-error fragment accumulation (#1692)
  • Docs URL configurableWEB_DOCS_URL, DOCS_BASE_URL, DOCS_SITE_URL Dockerfile build args let docs mount at any path on any host; WEB_DOCS_URL now applies to the mobile-nav button and dist/robots.txt (#1684, #1685, #1686, #1687)
  • Toast positioning + automations table polish — top-center toasts for auth flows (log in, sign up, 2FA, forgot-password); automations table replaces version column with localized created date; raw <select>/<input> migrated to shared Select / Input / SearchableSelect; click-to-toast hint replaces forgot-password helper text (#1678)

🐛 Fixes

  • Prefixed-locale routes + /docs redirectsservices/web switches base: './'base: '/' so the SPA shell is self-contained at any depth (fixes blank /de/pricing after locale rollout); services/docs now prepends DOCS_BASE_URL to the Location header so Caddy-mounted /docs no longer redirects to the wrong origin (#1691)
  • Web header/footer styling restored + /llms{,-full}.txt served in devglobals.css now imports @tale/webui/globals.css so its @source directive picks up shared layout utilities; LLM artifacts written into public/ so Vite dev serves them (#1682)

💥 Breaking Changes

  • de-AT and fr-CH locale tracks removed — only de, fr, and de-CH remain across @tale/webui, services/{platform,docs,web}, agent terminology, and the plop service template. Agents and user profiles previously pinned to de-AT or fr-CH should be re-targeted to de or fr (#1682)
  • Audit-log retention floor enforced at 365 days — orgs with auditLogRetentionDays < 365 are runtime-clamped to 365 with a one-time warn log per org; explicit re-configuration via the new bounded retention editor required to silence the warning (#1676)

📝 Other

  • CI builds container images once and reuses them across smoke/validate/scan jobs (#1695)
  • All CI jobs moved to free GitHub-hosted runners (#1674)
  • Design file refresh: AI providers, personalization, integrations panels (#1681)

Migration Guide

Most operators only need:

tale upgrade
tale deploy

If you fall into any of the cases below, take the corresponding action before or right after tale deploy:

1. Enable RAG bearer auth (recommended for production)

The RAG service gains opt-in Bearer-token auth. Behavior is presence-based — no token is baked into the image:

  • Unset (default): RAG accepts unauthenticated requests on the container network; both RAG and platform log a one-time [SECURITY] RAG_AUTH_TOKEN unset warning at startup. Existing deployments continue to work without changes.
  • Set: Every platform → RAG request carries Authorization: Bearer ${RAG_AUTH_TOKEN}; RAG rejects mismatches with 401.

For production posture, set the same value on both containers:

# In your .env or compose override (same value on both)
RAG_AUTH_TOKEN=<a long random secret>

The token is re-read from the env on every call, so rotation takes effect on the next request without a process restart.

2. RAG_URL private-host check

RAG_URL is now validated against the IMDS (169.254.0.0/16) and the "this network" (0.0.0.0/8) blocklists at platform startup. If your RAG_URL points to anything in those ranges (it should not under any normal deployment), update it to a routable internal address before deploying.

3. Audit-log retention floor (operators with auditLogRetentionDays < 365)

Orgs with auditLogRetentionDays under the new 365-day floor will be runtime-clamped on first read and a warn log emitted. To fix permanently, open Settings > Governance > Retention and re-save with a value >= 365 (the editor now enforces bounds and shows the floor inline).

4. de-AT / fr-CH locales removed

If any agents, users, or org-level defaults were pinned to de-AT or fr-CH, repoint them to de or fr respectively (or to de-CH if you want the Swiss German overlay). The narrow-BCP-47 resolver still falls back to the base locale at runtime, so nothing 500s — but text that previously came from de-AT.json / fr-CH.json will now come from de.json / fr.json.

5. Docs deployment (self-hosters who pointed external DNS at docs.tale.dev Mintlify)

If you previously had a CNAME pointing at Mintlify Cloud for your docs subdomain, switch it to your Caddy/reverse-proxy host. The bundled compose.docs.yml brings up the new tale-docs service on port 3002; Caddy is already configured for docs.tale.dev in Caddyfile. No action needed if you don't expose a public docs site.

Upgrade

tale upgrade
tale deploy

Contributors

@larryro, @AdeolaAdekoya, @Israeltheminer, @yannickmonney


Full Changelog: v0.2.69...v0.2.70