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>
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>
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>
Round-2 bake-off confirms haiku dominates on every dimension (summarize 100/100/100,
timeline date_acc 95.8%). Flip UI defaults from azure_mini to claude_haiku for both
tools. Azure options remain available.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
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>
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>
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>
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>
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>
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>
- New: transcribe-about.php, transcribe-guide.php, transcribe-tech.php
with full en/no/uk/pl translations (3-engine cascade, diarization, vocab)
- New: translations/transcribe-about|guide|tech.php (4-lang strings)
- New: scripts/translate-pages.php (Azure gpt-4o CLI translation helper)
- Add korr-doc-links nav to transcribe.php
- Refresh redact-about|guide|tech.php — point to assets/images/redact/
- Fix all "never written to disk" wording in redact translations
- Add Min Sak/corpus save workflow to redact guide and tech privacy section
- redact.php upload hint: correct in-memory wording
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
GPU and DBN Legal Agent v3 are unsuitable for advocate synthesis (4-6K token
structured JSON output at 20-30 tok/s = 3-5 min on RTX 3060, plus both fall
through to Sonnet when Bedrock is enabled anyway). Reduce to two honest options:
Haiku (~2-4 min) and Sonnet (~3-5 min), with accurate description of why
time is dominated by multi-pass question answering, not synthesis.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
- 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>
- 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>
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>
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>
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>
- 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>
- Remove js-save-corpus button from redact output (was failing with 'no_workspace'
for users without a linked CaveauAI workspace)
- Single save path now goes through showSaveResultButton() → api/case/save-result.php,
which works for all paid (Plus/Pro) users without workspace dependency
- Relabel 'Save result' → 'Save to My Docs' and update success message
- Fix DOCX: contentTypesXml() had wrong ContentType for docProps/core.xml
(application/package/... → application/vnd.openxmlformats-package.core-properties+xml);
Word validates this strictly and was rejecting the file
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
Cards, status row, account bar, and pricing tiers were rendering at
.78–.94rem with 18–20px padding — felt microscopic on 1440+ viewports.
Lift every token ~12–15% and widen card padding so the Crimson Pro /
IBM Plex editorial character reads as intended.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Restored min-height:200px + display:flex on .dashboard-tool-card in CSS,
and removed the conflicting min-height:0 inline overrides on each card div.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace manifesto section with compact account overview bar (tier badge,
credits breakdown, next refill/billing date, upgrade/manage/top-up CTAs)
- Convert tool cards from <a> to keyboard-accessible <div> with footer bar
showing Open link, About link (advocate/timeline/korrespond), MCP slug copy button
- Add collapsible MCP quick-start section: token prefix fetch, stdio config,
remote HTTP config, copy buttons, link to full mcp.php docs
- Add 3-column tool reference section for Advocate / Timeline / Korrespond
with about/guide/tech links, description, and copyable MCP slug
- All new sections fully localised: en / no / uk / pl
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
The redesign CSS was forcing .kdoc-hero__title to var(--dbn-blue) (#00205b)
— the same color as the hero background, making it invisible. The kicker
was also overridden to red, which clashed with the dark navy overlay.
Added more-specific .kdoc-hero .kdoc-hero__* overrides to restore white text.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>