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>
This commit is contained in:
@@ -48,6 +48,26 @@ $history = array_values(array_filter($history, fn($m) => is_array($m)
|
||||
$category = trim((string)($input['category'] ?? '')) ?: null;
|
||||
$language = in_array($input['language'] ?? 'no', ['no', 'en'], true) ? $input['language'] : 'no';
|
||||
|
||||
// Persona (legal-domain) scope: resolve the chosen persona's packages against the
|
||||
// DBN client (57, the package owner). The dashboard tenant is subscribed to the
|
||||
// DBN package set (provisioning + migration 177), so these package_ids survive the
|
||||
// subscription intersection in ClientRagPipeline and scope shared-law retrieval.
|
||||
$personaSlug = (isset($input['profile']) && is_string($input['profile']) && trim($input['profile']) !== '')
|
||||
? trim($input['profile']) : null;
|
||||
$personaPackageIds = [];
|
||||
if ($personaSlug !== null) {
|
||||
try {
|
||||
$dbnClient = dbnToolsFetchClient();
|
||||
if ($dbnClient) {
|
||||
$persona = dbnToolsResolvePersona((int)$dbnClient['id'], $personaSlug);
|
||||
$personaPackageIds = array_values(array_filter(
|
||||
array_map('intval', $persona['package_ids'] ?? []),
|
||||
static fn(int $id): bool => $id > 0
|
||||
));
|
||||
}
|
||||
} catch (Throwable $e) { /* tolerated — fall back to default package scope */ }
|
||||
}
|
||||
|
||||
// Folder scope: limit retrieval to a folder subtree, ACL-checked.
|
||||
$folderScopeRaw = $input['folder_id'] ?? null;
|
||||
$folderScope = null;
|
||||
@@ -84,6 +104,10 @@ try {
|
||||
'user_role' => 'owner',
|
||||
];
|
||||
|
||||
if ($personaPackageIds) {
|
||||
$options['package_ids'] = $personaPackageIds;
|
||||
}
|
||||
|
||||
// Apply folder scoping via allowed_folder_ids (supported by ClientRagPipeline).
|
||||
if ($folderScope !== null) {
|
||||
if ($folderScope === 0) {
|
||||
|
||||
@@ -70,6 +70,9 @@ try {
|
||||
$priorContext = is_array($input['prior_context'] ?? null) ? $input['prior_context'] : null;
|
||||
$branchNotes = mb_substr(trim((string)($input['branch_notes'] ?? '')), 0, 1000, 'UTF-8');
|
||||
$subQsOverride = is_array($input['sub_questions_override'] ?? null) ? $input['sub_questions_override'] : [];
|
||||
$personaSlug = (isset($input['profile']) && is_string($input['profile']) && trim($input['profile']) !== '')
|
||||
? trim($input['profile'])
|
||||
: null;
|
||||
|
||||
if (mb_strlen($seedQuery, 'UTF-8') > 4000) {
|
||||
throw new DbnToolsHttpException('Query is too long.', 422, 'query_too_long');
|
||||
@@ -139,7 +142,8 @@ try {
|
||||
$advocateRole,
|
||||
$priorContext,
|
||||
$branchNotes,
|
||||
$subQsOverride
|
||||
$subQsOverride,
|
||||
$personaSlug
|
||||
);
|
||||
|
||||
$result['ok'] = true;
|
||||
|
||||
+5
-1
@@ -174,8 +174,12 @@ try {
|
||||
$ftRemaining = dbnToolsFreeTierDeduct($ftUid, 'korrespond');
|
||||
$creditDeducted = true;
|
||||
|
||||
$personaSlug = (isset($input['profile']) && is_string($input['profile']) && trim($input['profile']) !== '')
|
||||
? trim($input['profile'])
|
||||
: null;
|
||||
|
||||
// ── Pass 2: retrieve law → draft → self-check → translate ──────────────────
|
||||
$result = $agent->generate($intake, $classify, $emit, $engine);
|
||||
$result = $agent->generate($intake, $classify, $emit, $engine, $personaSlug);
|
||||
$result['ok'] = true;
|
||||
$result['latency_ms'] = (int)round((microtime(true) - $startTime) * 1000);
|
||||
if ($ftRemaining >= 0) {
|
||||
|
||||
Reference in New Issue
Block a user