124 Commits

Author SHA1 Message Date
daveadmin 519bdbb6e5 feat(tools): owner feedback review surface + tool_feedback migration
Adds the missing migration for the tool_feedback table (dobetternorge_maindb)
that the in-result feedback widget writes to, repoints api/feedback.php to
dbnmDb() for consistency with the engine-config table, and adds an owner-only
dashboard (page + read API + nav) summarising ratings and notes by tool/engine.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-21 15:19:45 +02:00
daveadmin 2f05b84b0f feat(tools): DB-backed LLM engine admin (owner-only)
Add an owner-gated dashboard to remap any tool/tier's model live without a
code push. Overrides live in dbn_tool_engine_config (dobetternorge_maindb)
and are consulted by dbnToolsResolveToolRun() + dbnToolsReviewerModel();
no row = unchanged code/.env behaviour (fully back-compatible).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-21 14:55:17 +02:00
daveadmin f270a32056 fix(tools): tier-aware GPU cloud fallback for ask synthesis
When a persona-pinned GPU fine-tune is offline, degrade to the requested
quality tier's Bedrock model (Quick->Haiku, Pro->Sonnet) instead of a
hardcoded gpt-4o, so Pro genuinely differs from Quick while the pod is off.
Legacy/azure engines keep gpt-4o as the floor. Generalize the degraded
notice/trace wording (no longer asserts gpt-4o).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-15 18:50:39 +02:00
daveadmin a4b5b6e3f2 fix(tools): route quick/pro tiers to Haiku/Sonnet on Bedrock
Tier engine strings (claude_haiku/claude_sonnet) were stripped back to
azure_mini by per-method whitelists, so both tiers ran gpt-4o-mini and Pro
charged 2x for the same model. Add a shared DbnBedrockModelRouter::
deploymentForEngine() helper and route the cloud path through it across
summarize, ask, barnevernet, discrepancy, deep-research, and korrespond.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-15 17:35:22 +02:00
daveadmin a8b1bb87a6 feat(tools): converge two-tier Quick/Pro selector onto .no fork
Port the dobetterlegal-tools two-tier quality stack to dobetternorge.no:
QUALITY_TIERS registry + resolveTier (ToolModels), dbnToolsResolveToolRun
(bootstrap), tier read+charge in the 6 analytical endpoints, Quick/Pro
UI + payload.tier on the 6 tool pages/JS, and the bounded
corpusContextForSummarize RAG fix (per-passage trim + total budget +
reranker_enabled). Back-compat: requests without `tier` keep legacy
engine behavior.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-15 12:23:46 +02:00
daveadmin b217f18118 feat(tools): graceful degradation when GPU fine-tune is offline
Persona-pinned legal model (dbn-legal-agent-v3, served from the home GPU
pod) hard-failed ask/legal-analysis whenever the GPU was powered off.
Add a cached health-ping gate plus reactive try/catch fallback: if the
fine-tune is unreachable, transparently route to gpt-4o and surface a
localized notice in what_remains_uncertain that the specialized model is
temporarily offline while corpus, retrieval, and sources remain live.
Cloud models are excluded from the gate so gpt-4o personas never degrade.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-05 06:19:05 +02:00
daveadmin 3f7d4eef13 feat(tools): add letter length + summary depth controls; harden korrespond §-discipline
- Summarize: new depth param (brief/standard/detailed) with depth-aware prompt
  instructions and coverage mandate; wired through API + JS
- Korrespond: new letter length param (concise/standard/detailed) injected as
  Lengde: instruction in draft pass; wired through API + JS
- Korrespond draft prompt: add §-discipline rule (cite only directly relevant §§)
  plus Opphevet guard (aligned with dobetterlegal-tools)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 13:44:02 +02:00
daveadmin 8b99ceec3b feat(rag): add doc-summary pre-filtering to DbnLegalToolsService::search
Before chunk retrieval, embed the query against bnl_doc_summaries Qdrant
collection to identify the most semantically relevant documents. The
resulting document IDs are passed as shared_doc_ids to searchAll(),
narrowing the shared-corpus chunk search to those documents only.

Applied to the 'shared' and 'both' scope paths (not 'private', which
has no shared corpus). Non-fatal: on any error preFilterDocIds stays
empty and search falls back to current unfiltered chunk retrieval.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 10:15:57 +02:00
daveadmin c84ed2ed78 fix(tools): parse-harden Do Better Legal ask against leaky fine-tune output
The dbn-legal-agent-v3 fine-tune (Track 1 / family) emits a labelled-prose
template — duplicate `answer:` prefixes, markdown-escaped underscores (`\_`),
and a trailing raw JSON blob — rather than the strict JSON the Azure/gpt-4o
path produces via response_format. decodeJsonObject() returned null on that
invalid JSON, so ask() dumped the entire raw blob into `answer`.

Fix at the parse layer (no upstream response_format change, to avoid fighting
the fine-tune's training):
- dbnToolsRepairJsonText(): strip fences, drop only invalid `\_`/`\*` escapes,
  then balanced-brace scan collecting every top-level {...} (longest first) to
  recover an appended JSON object. Shared by both gateways' decodeJsonObject(),
  so all JSON tools benefit.
- dbnToolsParseLabeledFields(): parse labelled-prose into real fields when no
  JSON decodes, tolerating escaped key names and collapsing duplicate prefixes.
- ask() null-fallback now builds clean structured fields from the parsed prose
  instead of dumping raw; what_remains_uncertain becomes a proper list.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 17:36:35 +02:00
daveadmin 7fcd317205 feat(tools): reposition as Do Better Legal two-track Norwegian-law MCP
De-family-ify shared JSON tools (persona-aware routing + neutral base
prompt), make the verification review pick its engine per track
(family/child-welfare -> dbn-legal-agent-v3, others -> gpt-4o interim),
and route product-name strings through dbnToolsProductName(). Rebrand the
MCP/tools surface (mcp.php + i18n mcp_* strings) to Do Better Legal.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 07:45:17 +02:00
daveadmin d156f8cf6b feat(tools): persona selector across standalone tools + dashboard chat
Wire the legal-domain persona picker into corpus, deep-research, korrespond and
the dashboard chat. Each endpoint reads the chosen profile, resolves its packages
against client 57, and scopes retrieval via package_ids (falling back to family
when omitted). New dashboard tenants now subscribe to all DBN domain packages so
persona switching survives the subscription intersection.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 23:03:31 +02:00
daveadmin 662fbf7d6d feat(tools): persona-driven multi-domain corpus + model routing
Generalize the family-locked legal tools into caveauAI persona profiles
(client 57 chat profiles, resolved in-process via the chat_profiles bridge).
Each tool accepts an optional `profile` slug that scopes the corpus package(s),
search method, system prompt and synthesis model; omitting it falls back to the
family-legal package so existing behaviour is unchanged.

- dbnToolsResolvePersona / dbnToolsListPersonas / dbnToolsBootChatProfiles in
  bootstrap.php; new api/personas.php + dbn.list_personas MCP tool.
- LegalTools search/ask/corpusContextForSummarize and the BvjAnalyzer /
  LegalAnalysis / translate paths take the persona's packages + prompt + model.
- Persona <select> on ask/search/summarize (populated from api/personas.php).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 20:49:58 +02:00
daveadmin 5a0ef89dca feat(mcp): expose corpus_search, korrespond_refine, extract_text tools
Restores the 3 tools (manifest + invoke arms + invokeExtract helper),
the citation-atom RAG lever in LegalTools/corpus-search, and the catalog
icons. These were live on prod via rsync but uncommitted, so a git-pull
deploy reverted the manifest from 22 to 19 tools.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 16:45:41 +02:00
daveadmin 88b6da83e5 Add missing i18n keys for folders/trash nav and page titles (en/no/uk/pl) 2026-05-26 23:38:50 +02:00
daveadmin 2e2b0b45fa Full DMS: folders + ACLs, versioning, trash, bulk ops, preview, smart folders
Rebuild the dashboard as a Drive-style document management system on top of
the existing CaveauAI hybrid RAG pipeline.

Backend:
- 5 migrations (versions, trash soft-delete, saved searches, categories, audit)
- DMS helpers (folder ACL walker, disk storage, audit, version snapshot,
  XLSX/PPTX/HTML/CSV/MD extractors)
- New APIs: folders, document-versions, trash, bulk, preview, saved-searches,
  categories, diagnostics
- Extended APIs: documents (folder_id, soft-delete, ACL filter, sort),
  upload (9 file types, version-collision detection with replace/new/keep-both,
  disk persistence), chat-stream (folder scoping + graph related-documents)
- 30-day trash purge cron with Qdrant + disk + graph cleanup

Frontend:
- Drive-style two-pane browser with folder tree, drag-drop, bulk-action bar,
  right-click context menu, multi-select
- New pages: folders (tree + per-folder ACL editor), trash (restore/purge)
- Extended pages: upload (folder picker, version-collision modal, 9 file
  type chips), document (Preview/Versions/Permissions tabs with PDF.js +
  mammoth.js + audio), index (DMS KPIs + activity feed), settings (live
  diagnostics ping MariaDB/Qdrant/LiteLLM/FalkorDB/disk), chat (folder
  scope chips + related-authorities chips)
- New CSS (dms.css) + JS bundle (dms.js) exposing window.DBN_DMS
- Sidebar nav adds Folders + Trash items

All routes return HTTP 200 in local smoke test; all 32 files lint clean.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 22:24:56 +02:00
daveadmin 234ab7278b Timeline: group same-date/actor events, clean badges, Bedrock routing
- renderTimeline(): group consecutive same-date+actor events into one card
  with a bullet list; single events keep their current layout
- Date format: YYYY-MM-DD → "1 Jun 2023" (3-letter month, international)
- Time shown in header when available
- Remove date_type badge; confidence badge replaced by amber ⚠ flag on
  low-confidence events only (high/medium border colour still shows)
- LegalTools.php: resolve azure_full/azure_mini to Bedrock Sonnet/Haiku
  when DbnBedrockGateway is active; claude_sonnet/claude_haiku also handled
- timeline.php + api/timeline.php: engine labels updated (Claude Haiku/Sonnet);
  claude_haiku + claude_sonnet added to valid engine list
- i18n engine labels updated in all 4 languages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 23:21:35 +02:00
daveadmin b2e1bf268d korrespond v1 premiere: Bedrock routing, engine picker, journal auto-save + status
- KorrespondAgent: add resolveDeployment() helper; fix classify/translate to use
  Haiku via Bedrock, draft to use Haiku (quick) or Sonnet (thorough) — fixes broken
  withDeployment('gpt-4o-mini') calls when DBN_BEDROCK_ENABLED=true
- korrespond.php: add Quick/Thorough engine picker (case_toggle already present)
- korrespond.js: pass engine in request payload
- api/korrespond.php: accept user-selected engine, auto-save to case_tool_results
  for paid users after each successful run, update deployment log label
- CaseResults: add korr_status to listForUser SELECT, add updateStatus() method
- result-action.php: add set_status action for correspondence journal
- account.php: show status dropdown (Draft/Sent/Reply received/Resolved) for
  korrespond entries in #analyses, wire JS change handler to result-action.php

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 21:52:09 +02:00
daveadmin a925415ef7 Fix advocate brief truncation: raise synthesis max_tokens to 6K
Haiku synthesis had a hard cap of 2500 tokens which truncated the
advocate JSON response (~4-6K tokens), causing decodeJsonObject() to
fail and rendering the raw JSON string as the brief.

Fix: remove the 2500-token Haiku override; introduce a per-mode limit
(6000 for advocate, 4000 for deep-research) in $opts before the engine
branch so all paths benefit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 21:09:01 +02:00
daveadmin 883d813f1b Fix sub-question expansion timeout + engine routing for Bedrock advocate
- expandQueries(): truncate seedDescription to 2000 chars (full uploads were
  48K+ tokens, exceeding the 35s timeout with Sonnet); switch to Haiku gateway
  when Bedrock is active (fast + adequate for sub-Q generation); timeout → 60s
- interpretSeed(): same Haiku + 60s fix for English non-advocate path
- synthesise(): add explicit azure_mini + Bedrock → Haiku branch so the fast
  engine actually uses Haiku (~20-40s) instead of falling through to Sonnet (~180s)
- advocate.php: relabel azure_mini as "Claude Haiku 4.5 (fast)" with accurate
  timing; relabel claude_sonnet as "(thorough)" to reflect the distinction

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 20:50:37 +02:00
daveadmin b78ab1e257 Fix Bedrock advocate synthesis: engine guard, response_format, Claude engine option
- DeepResearchAgent: engine guard now accepts dbn_legal_v3, claude_sonnet, claude_haiku
  (previously stripped these to azure_mini, breaking dbn_legal_v3 selection and
  preventing Claude engines from reaching the correct synthesis branch)
- DbnBedrockGateway: remove response_format=json_object from chat payload — LiteLLM
  converts this to a tool-use constraint for Bedrock, routing output into tool_calls
  instead of content (root cause of the {} empty brief)
- advocate.php: add Claude Sonnet 4.6 (AWS Bedrock) engine option
- account, billing, dashboard, nav, min-sak: pending UI/flow changes from prior sessions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 20:22:12 +02:00
daveadmin 8205a22205 Fix legal analysis issue extraction for long documents 2026-05-25 19:06:23 +02:00
daveadmin 190f639784 Make dbn-legal-agent-v3 checker context-aware; wire into LegalAnalysisAgent
Three fixes:
1. bootstrap.php dbnToolsRunLegalCheck(): prepend first 350 chars of synthesis text
   to the v3 user message so it validates actual content, not just general law.
2. BvjAnalyzerAgent: fix engine guard — was skipping check for claude_sonnet/haiku;
   now skips only when dbn_legal_v3 is the synthesis model (it already IS the check).
3. LegalAnalysisAgent: add post-synthesis dbnToolsRunLegalCheck() call after Pass 3;
   add 'legal_check' key to runFullAnalysis() return.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 16:45:41 +02:00
daveadmin 8a11001bff Add AWS Bedrock three-tier gateway routing (LiteLLM via Colin)
Routes AI tools across three tiers based on task complexity:
- Azure GPT-4o-mini always: redact, translate, timeline-basic, search-legal (mechanical tasks)
- Claude Haiku 4.5 (Bedrock): ask, summarize, timeline-deep, citations (Norwegian nuance)
- Claude Sonnet 4.6 (Bedrock): korrespond, legal-analysis, deep-research, barnevernet-analyze,
  discrepancy-find, advocate (public-facing legal output)

No AWS credentials in app — credentials live in LiteLLM on Colin (same as nova-lite).
Rollback: DBN_BEDROCK_ENABLED=false in .env, no code push needed.

Includes extended thinking support for Pro deep-research via chatWithThinking().
Claude Opus 4.7 constant added for future premium tier (needs litellm_config.yaml entry).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 15:22:48 +02:00
daveadmin 17ad54cf36 Add chunked timeline routing 2026-05-25 12:34:41 +02:00
daveadmin 75b19f1dcf Add timeline engine size routing 2026-05-25 11:33:47 +02:00
daveadmin 3ad8f4843c Harden timeline quick extraction 2026-05-25 11:14:21 +02:00
daveadmin 983c423740 Fix nova-lite JSON: drop response_format, strip markdown fences
nova-lite ignores json_object constraint and returns {} empty; without
it, it wraps output in ```json fences. Strip fences before decodeJsonObject.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 10:51:24 +02:00
daveadmin f00d3d68e5 Add Quick mode (nova-lite/Bedrock) as 3rd tier for timeline tool
Timeline now offers Quick/Standard/Deep: nova_lite routes to Amazon
Bedrock nova-lite via LiteLLM (1 credit, ~2s faster), azure_mini stays
gpt-4o-mini (1 credit), azure_full stays gpt-4o (2 credits, Pro only).
ToolModels tier rules: free→nova_lite only, plus→quick/standard,
pro→all three.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 10:26:07 +02:00
daveadmin d47024ed67 timeline: remove GPU, add SSE status updates, DOCX export, single-file, engine-aware credits
- Remove GPU/cuttlefish engine from timeline.php, api/timeline.php, LegalTools.php, tools.js (all 4 langs)
- Add engine-aware credit cost: gpt-4o-mini=1 credit, gpt-4o=2 credits (matches redact pattern)
- Remove multiple attribute from file input (single document only)
- New api/timeline-stream.php: SSE endpoint emitting status events + final result
- New api/timeline-download.php: DOCX export of timeline events
- LegalTools::timeline() gains ?callable $onProgress for live status updates
- tools.js: spinner on run, SSE streaming fetch, Export to Word button
- Save to My Docs was already wired (showSaveResultButton at line 1136)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 09:32:28 +02:00
daveadmin 56cd87dd7b redact: UX overhaul — engine simplification, credits, spinner, save-to-docs, badges
- Remove GPU/regex engine options; keep only azure_mini (1 credit) and azure_full (2 credits)
- Variable credit cost: engine-aware pre-check and charge in api/redact.php; PricingCatalog base = 1
- Fix ATTORNEY not preserved when keepOfficials=true: add to LLM prompt, generic-tag, pseudonym regexes
- Replace Azure credits hint with per-engine credit cost text (all 4 languages)
- Single-file upload only (was: up to 5); simplify status messages
- Clear previous redaction output and show pulsing spinner when a new run starts
- Add "Save to My Docs" button in redact output panel (corpus-save.js path)
- corpus-save.js: capture source_doc_ids from button dataset, pass in POST payload
- api/save-to-corpus.php: accept source_doc_ids, store first as source_url=corpus-doc:{id}
- doc-picker.js: show "✂ Redacted" badge for documents saved from the redact tool
- CSS: .redact-working spinner, doc-item__badge--redact pill styles

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 08:18:51 +02:00
daveadmin 61425d7f17 Fix footer library and MCP pricing links 2026-05-24 19:54:02 +02:00
daveadmin b912ff22bc Dashboard account section, profile API, and CSS account panels
- SSO session auth gating on all protected pages
- dashboard.php: account section (profile form + workspace panel),
  onboarding prompt modal, overview bar extracted to CSS classes,
  dashboard.css linked in page head
- api/profile.php: save/dismiss endpoint for optional profile fields
- assets/css/dashboard.css: account grid, dash-account-panel,
  dash-profile-form, profile-prompt-backdrop modal, overview bar
  classes, dash-section-kicker, dash-tier-badge base styles
- includes/bootstrap.php: dbnToolsMainUserProfile,
  dbnToolsProfileNeedsPrompt, dbnToolsRequirePageAuth
- scripts/sql/004_user_profile_fields.sql: nullable phone, address,
  and profile_prompt_dismissed_at columns

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 18:49:34 +02:00
daveadmin c090a05644 Bump context bar font size and add it to dashboard, pricing, min-sak pages
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 14:51:55 +02:00
daveadmin 7df3b7f8d3 Replace manifesto bar with compact context bar + add privacy page
- layout.php: replace large manifesto section (eyebrow/title/sub/4 stats) with
  a slim dbn-context-bar strip linking to why-ours, pricing, MCP, and privacy
- i18n.php: add context_bar_* + footer_privacy_link + privacy_page_title keys
  to all 4 language blocks (en, no, uk, pl)
- dbn-tools-redesign.css: add .dbn-context-bar styles with mobile wrap
- privacy.php: new standalone page in 4 languages covering in-memory processing,
  metadata-only logging, My Case opt-in storage, EU data locations, and HTTPS transport
- footer.php: add Privacy link to first footer column

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 14:44:44 +02:00
daveadmin b21bfb2f1d Add NOK pricing catalog, credit ledger, success-based charging, and tier-gated model routing
- PricingCatalog.php: single source of truth for plans (free/plus/pro), top-ups,
  Stripe price env keys, tool costs (0–6 credits), STT variable billing, feature limits
- FreeTier.php: monthly-first credit deduction, ledger (user_tool_credit_ledger),
  STT reservation/settle/release, monthly reset, trial logic
- StripeClient.php: canonical SKUs (plus/pro/topup_100/300/1000), legacy aliases kept
- stripe-checkout.php: subscription vs payment mode, trial gating, catalog metadata
- stripe-webhook.php: idempotent via stripe_events, handles subscription lifecycle +
  invoice.paid renewal + one-time topup credit grants
- All API tools: success-based credit deduction (check before, charge after)
- transcribe.php: file-size heuristic reservation, settle from actual provider duration
- ask.php + LegalTools.php: ToolModels engine resolution — Pro gets gpt-4o
- KorrespondAgent.php + korrespond.php: tier-gated draft deployment —
  Free/Plus gets gpt-4o-mini, Pro gets gpt-4o
- pricing.php: NOK-only, plan cards, top-up packs, Organisation contact card,
  tool cost table, separate monthly/prepaid balance display
- 003_pricing_credit_catalog.sql: ledger and STT reservation tables

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 13:42:27 +02:00
daveadmin 88555eb8a7 Fix docPickerBtn/audioPickerBtn i18n — add missing translation keys
Add doc_picker_btn/audio_picker_btn to i18n.php (en/no/uk/pl), add
docPickerBtn to REDACT_I18N + TIMELINE_I18N and audioPickerBtn to
TRANSCRIBE_I18N in tools.js. PHP-render picker labels in legal-analysis,
translate, summarize, tool_form, and layout_footer using dbnToolsT().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 12:41:09 +02:00
daveadmin 1eb55a8384 Fix language switcher dropping query params (e.g. ?tool= on mcp-tool.php)
Preserve all existing GET params when building lang switcher URLs so that
switching language on /mcp-tool.php?tool=dbn.redact stays on that tool.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 12:16:16 +02:00
daveadmin 96fbe4398a Fix gate card visibility, add 5 missing tool SVGs, update pricing to EUR 4-tier
Gate cards: remove .lt-gate__card from paper-card override so dark navy
backgrounds restore; drop blue title colour override for gate cards.

SVGs: add translate (bilingual doc), citations (citation graph), korrespond
(formal letter), summarize (doc→extracted bullets), legal-analysis (issue
sections + dbn-legal-agent-v3 badge).

Pricing: 3 NOK tiers → 4 EUR tiers (Free €0 / Light €9 / Pro €29 / Pro+ €79);
Pro+ is new; "Plus" references updated to "Light" throughout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 12:09:37 +02:00
daveadmin 1bfafa9908 Localize mcp.php + add mcp-tool.php detail pages for all 19 MCP tools
- Replace all hardcoded English strings in mcp.php with dbnToolsT() calls
- Add 44 MCP UI chrome translation keys to includes/i18n.php (en/no/uk/pl)
- Generate includes/mcp-tool-translations.php with tool names, descriptions,
  and parameter docs translated into Norwegian, Ukrainian, and Polish via Azure OpenAI
- Create mcp-tool.php: parameterized detail page (?tool=dbn.slug) with parameter
  table, example request/response JSON, and privacy section, all localized
- Add "View details →" links on tool cards in mcp.php (shown on expand)
- Add translations/mcp-chrome.php and scripts/generate-mcp-translations.php

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 12:05:07 +02:00
daveadmin e09ee62c62 Apply Do Better Norge tools brand redesign (CSS + all tool pages)
New dbn-tools-redesign.css with warm paper surface, navy tools nav, gold
accent, and per-tool themes via body[data-active-tool]. Updated all 21 tool
PHP pages, shared layout/nav/footer includes, and advocate route (new).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 11:26:39 +02:00
daveadmin c997f204b5 feat: add Do Better Norge MCP server — token system, runtime API, interactive setup page
- UserMcpTokens: per-user SHA256-hashed token mint/validate/revoke (Plus/Pro only)
- DbnMcpRuntime: 19 MCP tools (search, ask, summarize, timeline, redact, translate,
  legal_analysis, korrespond, barnevernet_analyze, advocate_brief, deep_research,
  discrepancy_find, transcribe_audio, corpus_stats, list_documents, get_document,
  citation_graph, case_workbench_plan, save_to_case)
- api/mcp/user/: session/tools/invoke HTTP endpoints with Bearer token auth
- api/mcp-tokens.php: token create/revoke/list REST API
- mcp.php: interactive setup page with token management, 5-client config tabs,
  auto-fill on token creation, tool catalog grid, privacy notice
- account.php: simplified MCP section with link to mcp.php
- nav.php: MCP nav link
- .htaccess: Authorization header passthrough, MCP route rewrite, CORS

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 11:01:13 +02:00
daveadmin effd3289b4 feat: add Legal Translation tool (translate.php)
New dedicated tool for translating Norwegian legal documents (Barnevernet
letters, court decisions, correspondence) into the user's chosen language
with legal-terminology annotations.

- translate.php: new tool page with source/target language selectors,
  4-way UI lang switcher, file upload, doc picker, streaming results
- api/translate.php: NDJSON streaming endpoint; Azure GPT-4o-mini with
  legal-aware prompt that preserves Norwegian statute refs verbatim and
  annotates terms with no target-language equivalent; 2-credit cost
- assets/js/translate.js: form handler, NDJSON stream reader, copy button
- assets/css/tools.css: .lt-* styles for translation result + annotations
- includes/i18n.php: 22 lt_* keys × 4 languages; translate entry in nav
- includes/FreeTier.php: translate → 2 credits
- includes/CaseResults.php + case-result.php: translate in eligible tools,
  toolLabel, toolIcon, deriveTitle, rendering block, rerun map

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 09:59:06 +02:00
daveadmin 21c092e0d0 Legal Analysis: full language follow-through (UI + LLM)
The tool now respects the chosen UI language end-to-end — even if the
source document is Norwegian, a user on EN/UK/PL gets the analysis in
their language. Norwegian statute references (barnevernsloven § 4-25,
EMK Art. 8) and case names (Strand Lobben mot Norge 37283/13) are kept
verbatim because they are proper nouns.

LLM (LegalAnalysisAgent.php):
- extractIssues: prompt asks for question + brief_context in user's
  language; statute refs preserved
- answerIssue: Norwegian core system prompt (keeps fine-tune precision)
  + language-coercion line for non-NO; localised context/source labels
- synthesise: overall_assessment, next_steps, disclaimer in user's
  language; explicit per-language disclaimer text
- runFullAnalysis empty-case fallback also localised
- what_to_check translated per language

UI:
- 40 new la_* translation keys in i18n.php × 4 languages (NO/EN/UK/PL)
- legal-analysis.php: 4-way lang switcher, dbnToolsT() for every label,
  emits window.DBN_LA_I18N for runtime JS strings
- legal-analysis.js: t() helper reads from window.DBN_LA_I18N
- layout_footer.php: emits window.DBN_CURRENT_LANG +
  window.DBN_ADDON_I18N so the legal-analysis add-on button works in
  the page's language no matter which tool it's invoked from
- tools.js add-on: reads from DBN_ADDON_I18N, passes DBN_CURRENT_LANG
  to /api/legal-analysis.php so server responds in same language

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 08:43:15 +02:00
daveadmin 7e6463ed22 Add Legal Analysis tool — two-pass DBN-legal pipeline
Restores the dbn-legal-agent-v3 fine-tune on ocelot (was silently aliased
to plain qwen2.5:14b in LiteLLM since the viper retirement) and ships a
new tool that uses it via a two-pass flow:

  Pass 1 (Azure 4o-mini)  → extract up to 5 distinct legal issues
  Pass 2 (ocelot v3 only) → answer each issue, ≤350 tokens, with corpus
  Pass 3 (Azure 4o-mini)  → synthesise overall assessment + next steps

The 12GB-VRAM constraint motivates the split: dbn-legal-agent-v3 stays
hot in VRAM through the 5 sequential per-issue calls because issue
extraction and synthesis run on Azure, not on ocelot.

New surface:
  - includes/LegalAnalysisAgent.php
  - api/legal-analysis.php           (NDJSON streaming endpoint)
  - legal-analysis.php               (dedicated tool page)
  - assets/js/legal-analysis.js      (streamed UI with per-issue cards)
  - Save-result + case-result.php rendering for legal-analysis output
  - Nav registration in all four UI languages

Add-on integration: a "⚖️🇳🇴 Run deep legal analysis on this text"
button now appears on Summarize, Ask, and Redact result pages and
streams the same pipeline inline below the existing result.

Existing tools relabelled: the misleading "🇳🇴 Norwegian specialist v3 "
option on advocate/deep-research/discrepancy/barnevernet is now honestly
"DBN Legal Agent" — now that the real fine-tune is actually deployed,
the label finally matches reality. The advocate.php v2 option was
removed since the v2 GGUF is retired.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 04:21:01 +02:00
daveadmin 2013648ee0 Add manual 'Save result' to all tools — replaces auto-save
All tool results can now be saved to My Case manually. Users click
'Save result', type a description, and confirm. This replaces the
previous silent auto-save on barnevernet/timeline/etc., giving users
control over what stays and what it's called (supports multiple runs
of the same tool with different titles).

- CaseResults: extend ELIGIBLE_TOOLS to include summarize, ask, redact,
  transcribe; add toolLabel/toolIcon entries; support explicit title
  via meta['title'] in save()
- api/case/save-result.php: new client-initiated save endpoint;
  accepts tool + title + input_payload + output_payload + meta
- Remove CaseResults::save() auto-save from barnevernet, deep-research,
  discrepancy, korrespond, timeline API endpoints
- tools.js: add showSaveResultButton() (exposed as window.dbnShowSaveResultButton);
  wire for ask, redact, timeline, transcribe (both file-upload and
  stored-audio paths)
- barnevernet.js: wire save button after final result render
- summarize.js: wire save button after renderFinal(); passes sumResults
  container so widget appears in the correct #sumResults div
- case-result.php: rich tool-specific rendering for summarize, ask,
  redact, transcribe, timeline; update re-run link map to include all
  new tools
- tools.css: styles for .save-result-widget and its states (idle,
  prompt, done, error)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 01:27:26 +02:00
daveadmin fa42c7223a fix: remove browser-native required validation blocking doc picker submissions
Forms lacked novalidate and textareas had required, so the browser fired
HTML5 validation before tools.js could intercept — blocking submissions
where text came from the doc picker or file upload rather than the textarea.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 00:34:38 +02:00
daveadmin 2e8fda72d2 fix: fetch doc content from client_documents when no chunks exist
Documents saved via save-from-tool or case-upload store content directly
in client_documents.content without being chunked into client_chunks.
dbnToolsFetchDocChunks now falls back to client_documents.content for
any requested doc_ids that returned no rows from client_chunks.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 00:24:57 +02:00
daveadmin e768662efe Add Summarize Document tool — engine selector, file upload, optional corpus enrichment
- summarize.php: full custom inline form (replaces tool_form.php wrapper) with
  lang switcher, azure_mini/azure_full/gpu engine selector, 8 corpus-slice
  toggles (all off by default), doc picker, file upload zone, and textarea
- api/summarize.php: rewritten to streaming NDJSON (matches barnevernet pattern);
  accepts JSON payload with text, language, engine, slices[], doc_ids[]
- includes/LegalTools.php: adds corpusContextForSummarize() (keyword search via
  ClientRagPipeline) and summarizeWithContext() (engine-aware LLM call with
  optional corpus prepend); returns structured JSON matching existing summarize format
- assets/js/summarize.js: self-contained IIFE handling file upload via
  api/extract.php, slice toggles, NDJSON stream reader, result rendering,
  and trace panel update
- includes/i18n.php: adds 'summarize' to nav in all 4 languages (EN/NO/UK/PL),
  inserted after 'redact' in the tool order with icon 'SZ'

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 23:25:40 +02:00
daveadmin 8587ec372f fix: expose DBN_USER_TIER so plus/pro SSO users can use doc picker
isPaidUser() was checking DBN_FREE_TIER_BALANCE === undefined, which
is only true for CaveauAI sessions. SSO users (even plus/pro) always
have DBN_FREE_TIER_BALANCE set, so the picker was showing the upgrade
modal for everyone in the SSO flow. Now reads DBN_USER_TIER explicitly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 22:45:57 +02:00
daveadmin f383ad5b74 feat: document & audio corpus picker for all tools
- Add "Select from My Docs" button to all text tool forms; free-tier
  users see an upgrade modal, paid (CaveauAI) users get a searchable
  multi-select modal backed by /api/dashboard/documents.php
- Add "Select from My Audio" picker on Transcribe with single-select
  and a "Save to My Audio" button for persisting uploaded clips
- New PHP helpers in bootstrap.php: dbnToolsFetchDocChunks,
  dbnToolsClientIdFromSession, dbnToolsInjectDocContent
- timeline, ask, redact APIs prepend selected document content
  (fetched from client_chunks SQL) before the textarea text
- api/dashboard/audio-upload.php stores audio files on server and
  creates a client_documents row with source_type='audio'
- api/transcribe.php falls back to stored audio via audio_doc_id POST
  field when no file is uploaded
- api/dashboard/documents.php supports ?source_type= filter
- tools.js: doc_ids added to JSON payload; stored-audio transcribe path
- New assets/css/doc-picker.css, assets/js/doc-picker.js
- SQL migration: scripts/sql/audio_docs_column.sql

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 21:38:04 +02:00