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>
This commit is contained in:
+47
-3
@@ -1964,7 +1964,14 @@ PROMPT;
|
||||
* Search the shared legal corpus and return top-N passages as a formatted
|
||||
* context string. Returns '' on failure so the caller can degrade gracefully.
|
||||
*/
|
||||
public function corpusContextForSummarize(string $query, int $limit = 8, ?string $persona = null): string
|
||||
public function corpusContextForSummarize(
|
||||
string $query,
|
||||
int $limit = 8,
|
||||
?string $persona = null,
|
||||
int $maxCharsPerPassage = 1800,
|
||||
int $maxTotalChars = 9000,
|
||||
?array &$debug = null
|
||||
): string
|
||||
{
|
||||
try {
|
||||
$client = dbnToolsRequireClient();
|
||||
@@ -1989,14 +1996,51 @@ PROMPT;
|
||||
'search_method' => $searchMethod,
|
||||
'min_private' => 0,
|
||||
'include_beta_website' => true,
|
||||
'reranker_enabled' => true,
|
||||
]));
|
||||
// Bound the injected context: trim each passage and cap the total so a single
|
||||
// oversized chunk cannot eat the budget and starve relevant lower-ranked passages.
|
||||
$parts = [];
|
||||
$total = 0;
|
||||
foreach ($chunks as $c) {
|
||||
$title = (string)($c['title'] ?? ($c['source'] ?? 'Legal source'));
|
||||
$content = (string)($c['content'] ?? ($c['text'] ?? ''));
|
||||
if ($content !== '') {
|
||||
$parts[] = "=== {$title} ===\n{$content}";
|
||||
$rawChars = mb_strlen($content, 'UTF-8');
|
||||
$clean = trim(strip_tags($content));
|
||||
if (mb_strlen($clean, 'UTF-8') > $maxCharsPerPassage) {
|
||||
$clean = rtrim(mb_substr($clean, 0, $maxCharsPerPassage - 1, 'UTF-8')) . '…';
|
||||
}
|
||||
$keptChars = $clean === '' ? 0 : mb_strlen($clean, 'UTF-8');
|
||||
$included = false;
|
||||
if ($clean !== '' && ($total + $keptChars) <= $maxTotalChars) {
|
||||
$parts[] = "=== {$title} ===\n{$clean}";
|
||||
$total += $keptChars;
|
||||
$included = true;
|
||||
}
|
||||
if ($debug !== null) {
|
||||
$debug['chunks'][] = [
|
||||
'title' => $title,
|
||||
'source_name' => $c['source_name'] ?? null,
|
||||
'source_type' => $c['source_type'] ?? null,
|
||||
'source_group' => $c['source_group'] ?? ($c['meta']['source_group'] ?? null),
|
||||
'category' => $c['category'] ?? null,
|
||||
'similarity' => $c['similarity'] ?? null,
|
||||
'reranker_score' => $c['reranker_score'] ?? null,
|
||||
'raw_chars' => $rawChars,
|
||||
'kept_chars' => $included ? $keptChars : 0,
|
||||
'included' => $included,
|
||||
];
|
||||
}
|
||||
}
|
||||
if ($debug !== null) {
|
||||
$debug['raw_total'] = array_sum(array_column($debug['chunks'] ?? [], 'raw_chars'));
|
||||
$debug['used_total'] = $total;
|
||||
$debug['chunk_count'] = count($chunks);
|
||||
$debug['search_method'] = $searchMethod;
|
||||
$debug['reranked'] = !empty(array_filter(
|
||||
$debug['chunks'] ?? [],
|
||||
static fn($r) => $r['reranker_score'] !== null
|
||||
));
|
||||
}
|
||||
return implode("\n\n", $parts);
|
||||
} catch (Throwable $e) {
|
||||
|
||||
Reference in New Issue
Block a user