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>
This commit is contained in:
@@ -3,7 +3,6 @@ declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../includes/bootstrap.php';
|
||||
require_once __DIR__ . '/../includes/BvjAnalyzerAgent.php';
|
||||
require_once __DIR__ . '/../includes/CaseResults.php';
|
||||
require_once __DIR__ . '/../includes/ToolModels.php';
|
||||
|
||||
dbnToolsRequireMethod('POST');
|
||||
@@ -151,19 +150,6 @@ try {
|
||||
'bvj_doc_type' => $result['doc_meta']['doc_type'] ?? null,
|
||||
]);
|
||||
|
||||
if ($ftUid > 0) {
|
||||
$ownerId = CaseStore::caseResolveClientId($ftUid);
|
||||
$resultId = CaseResults::save($ftUid, $ownerId, 'barnevernet', $input, $result, [
|
||||
'used_case_context' => $useMyCase ? 1 : 0,
|
||||
'case_doc_ids' => dbnToolsLastCaseDocIds(),
|
||||
'model' => $result['trace_metadata']['deployment'] ?? $engine,
|
||||
'latency_ms' => $result['latency_ms'],
|
||||
'credits_charged' => FreeTier::cost('barnevernet'),
|
||||
]);
|
||||
if ($resultId > 0) {
|
||||
$result['result_id'] = $resultId;
|
||||
}
|
||||
}
|
||||
|
||||
$emit('final', ['result' => $result]);
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../../includes/bootstrap.php';
|
||||
require_once __DIR__ . '/../../includes/CaseResults.php';
|
||||
|
||||
dbnToolsRequireMethod('POST');
|
||||
dbnToolsRequireAuth();
|
||||
|
||||
if (!dbnToolsIsFreeTier()) {
|
||||
dbnToolsError('Saved analyses are SSO-only.', 403, 'sso_only');
|
||||
}
|
||||
|
||||
$userId = (int)($_SESSION['dbn_tools_sso_uid'] ?? 0);
|
||||
if ($userId <= 0) {
|
||||
dbnToolsError('Missing user id.', 401, 'no_user');
|
||||
}
|
||||
|
||||
if (!CaseResults::isEnabled($userId)) {
|
||||
dbnToolsError('Saving results requires a Plus or Pro plan.', 403, 'not_paid');
|
||||
}
|
||||
|
||||
$input = dbnToolsJsonInput(800000);
|
||||
$tool = (string)($input['tool'] ?? '');
|
||||
$title = mb_substr(trim((string)($input['title'] ?? '')), 0, 200, 'UTF-8');
|
||||
$inputPayload = $input['input_payload'] ?? [];
|
||||
$outputPayload = $input['output_payload'] ?? [];
|
||||
$meta = is_array($input['meta'] ?? null) ? $input['meta'] : [];
|
||||
|
||||
if (!in_array($tool, CaseResults::ELIGIBLE_TOOLS, true)) {
|
||||
dbnToolsError('Unknown tool: ' . $tool, 400, 'bad_tool');
|
||||
}
|
||||
if (!is_array($inputPayload) || !is_array($outputPayload)) {
|
||||
dbnToolsError('input_payload and output_payload must be objects.', 400, 'bad_payload');
|
||||
}
|
||||
|
||||
if ($title !== '') {
|
||||
$meta['title'] = $title;
|
||||
}
|
||||
|
||||
// Normalise case_doc_ids from the input payload if not provided in meta.
|
||||
if (empty($meta['case_doc_ids'])) {
|
||||
$ids = $inputPayload['doc_ids'] ?? [];
|
||||
$meta['case_doc_ids'] = is_array($ids) ? $ids : [];
|
||||
}
|
||||
|
||||
$ownerId = CaseStore::caseResolveClientId($userId);
|
||||
$resultId = CaseResults::save($userId, $ownerId, $tool, $inputPayload, $outputPayload, $meta);
|
||||
|
||||
if ($resultId <= 0) {
|
||||
dbnToolsError('Could not save result. Check that your plan supports saved analyses.', 500, 'save_failed');
|
||||
}
|
||||
|
||||
dbnToolsRespond(['ok' => true, 'result_id' => $resultId]);
|
||||
@@ -3,7 +3,6 @@ declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../includes/bootstrap.php';
|
||||
require_once __DIR__ . '/../includes/DeepResearchAgent.php';
|
||||
require_once __DIR__ . '/../includes/CaseResults.php';
|
||||
require_once __DIR__ . '/../includes/ToolModels.php';
|
||||
|
||||
dbnToolsRequireMethod('POST');
|
||||
@@ -156,20 +155,6 @@ try {
|
||||
'advocate_role' => $advocateRole !== '' ? $advocateRole : null,
|
||||
]);
|
||||
|
||||
if ($ftUid > 0) {
|
||||
$toolSlug = $advocateRole !== '' ? 'advocate' : 'deep-research';
|
||||
$ownerId = CaseStore::caseResolveClientId($ftUid);
|
||||
$resultId = CaseResults::save($ftUid, $ownerId, $toolSlug, $input, $result, [
|
||||
'used_case_context' => $useMyCase ? 1 : 0,
|
||||
'case_doc_ids' => dbnToolsLastCaseDocIds(),
|
||||
'model' => $result['trace_metadata']['deployment'] ?? $engine,
|
||||
'latency_ms' => $result['latency_ms'],
|
||||
'credits_charged' => FreeTier::cost($toolSlug),
|
||||
]);
|
||||
if ($resultId > 0) {
|
||||
$result['result_id'] = $resultId;
|
||||
}
|
||||
}
|
||||
|
||||
$emit('final', ['result' => $result]);
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../includes/bootstrap.php';
|
||||
require_once __DIR__ . '/../includes/DiscrepancyAgent.php';
|
||||
require_once __DIR__ . '/../includes/CaseResults.php';
|
||||
require_once __DIR__ . '/../includes/ToolModels.php';
|
||||
|
||||
dbnToolsRequireMethod('POST');
|
||||
@@ -147,19 +146,6 @@ try {
|
||||
'deployment' => $result['trace_metadata']['deployment'] ?? null,
|
||||
]);
|
||||
|
||||
if ($ftUid > 0) {
|
||||
$ownerId = CaseStore::caseResolveClientId($ftUid);
|
||||
$resultId = CaseResults::save($ftUid, $ownerId, 'discrepancy', $input, $result, [
|
||||
'used_case_context' => $useMyCase ? 1 : 0,
|
||||
'case_doc_ids' => dbnToolsLastCaseDocIds(),
|
||||
'model' => $result['trace_metadata']['deployment'] ?? $engine,
|
||||
'latency_ms' => $result['latency_ms'],
|
||||
'credits_charged' => FreeTier::cost('discrepancy'),
|
||||
]);
|
||||
if ($resultId > 0) {
|
||||
$result['result_id'] = $resultId;
|
||||
}
|
||||
}
|
||||
|
||||
$emit('final', ['result' => $result]);
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../includes/bootstrap.php';
|
||||
require_once __DIR__ . '/../includes/KorrespondAgent.php';
|
||||
require_once __DIR__ . '/../includes/CaseResults.php';
|
||||
|
||||
dbnToolsRequireMethod('POST');
|
||||
dbnToolsRequireAuth();
|
||||
@@ -185,20 +184,6 @@ try {
|
||||
'deployment' => 'gpt-4o',
|
||||
]);
|
||||
|
||||
// Premium: persist the run for paid (Plus/Pro) users so it shows up in Min Sak → Saved analyses.
|
||||
if ($ftUid > 0) {
|
||||
$ownerId = CaseStore::caseResolveClientId($ftUid);
|
||||
$resultId = CaseResults::save($ftUid, $ownerId, 'korrespond', $input, $result, [
|
||||
'used_case_context' => !empty($intake['use_my_case']) ? 1 : 0,
|
||||
'case_doc_ids' => dbnToolsLastCaseDocIds(),
|
||||
'model' => 'gpt-4o',
|
||||
'latency_ms' => $result['latency_ms'],
|
||||
'credits_charged' => FreeTier::cost('korrespond'),
|
||||
]);
|
||||
if ($resultId > 0) {
|
||||
$result['result_id'] = $resultId;
|
||||
}
|
||||
}
|
||||
|
||||
$emit('final', ['result' => $result]);
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../includes/LegalTools.php';
|
||||
require_once __DIR__ . '/../includes/CaseResults.php';
|
||||
require_once __DIR__ . '/../includes/ToolModels.php';
|
||||
|
||||
dbnToolsRequireMethod('POST');
|
||||
@@ -47,19 +46,5 @@ dbnToolsWithTelemetry('timeline', $language, function () use ($input, $language,
|
||||
|
||||
$result = (new DbnLegalToolsService())->timeline($text, $language, $engine, $focus, $confidenceFilter, $includeRelative, $includeBackground, $userNotes);
|
||||
|
||||
// Persist for paid users (silently no-op for free)
|
||||
if ($ftUid > 0) {
|
||||
$ownerId = CaseStore::caseResolveClientId($ftUid);
|
||||
$resultId = CaseResults::save($ftUid, $ownerId, 'timeline', $input, $result, [
|
||||
'used_case_context' => $useMyCase ? 1 : 0,
|
||||
'case_doc_ids' => dbnToolsLastCaseDocIds(),
|
||||
'model' => $engine,
|
||||
'latency_ms' => (int)($result['latency_ms'] ?? 0),
|
||||
'credits_charged' => FreeTier::cost('timeline'),
|
||||
]);
|
||||
if ($resultId > 0) {
|
||||
$result['result_id'] = $resultId;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user