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:
@@ -208,20 +208,40 @@ final class CorpusProvision
|
||||
return (int)$db->lastInsertId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Slugs every DBN dashboard tenant is subscribed to, so persona-scoped
|
||||
* retrieval (which intersects requested package_ids with the tenant's
|
||||
* subscriptions) resolves for any domain persona. family-legal stays the
|
||||
* default; the dbn-* packages back the other personas.
|
||||
*/
|
||||
public const DBN_PACKAGE_SLUGS = [
|
||||
'family-legal',
|
||||
'dbn-child-welfare',
|
||||
'dbn-immigration',
|
||||
'dbn-labour',
|
||||
'dbn-consumer-tenancy',
|
||||
'dbn-general',
|
||||
];
|
||||
|
||||
private static function subscribeIncludedPackages(PDO $db, int $clientId): void
|
||||
{
|
||||
$packageSlug = dbnToolsRequiredPackageSlug();
|
||||
$stmt = $db->prepare('SELECT id FROM corpus_packages WHERE slug = ? AND is_active = 1 LIMIT 1');
|
||||
$stmt->execute([$packageSlug]);
|
||||
$packageId = (int)($stmt->fetchColumn() ?: 0);
|
||||
if ($packageId === 0) {
|
||||
$placeholders = implode(',', array_fill(0, count(self::DBN_PACKAGE_SLUGS), '?'));
|
||||
$stmt = $db->prepare(
|
||||
"SELECT id FROM corpus_packages WHERE slug IN ($placeholders) AND is_active = 1"
|
||||
);
|
||||
$stmt->execute(self::DBN_PACKAGE_SLUGS);
|
||||
$packageIds = array_map('intval', $stmt->fetchAll(PDO::FETCH_COLUMN));
|
||||
if (!$packageIds) {
|
||||
return;
|
||||
}
|
||||
$db->prepare(
|
||||
$insert = $db->prepare(
|
||||
"INSERT IGNORE INTO client_corpus_subscriptions
|
||||
(client_id, package_id, is_active, source, subscribed_at)
|
||||
VALUES (?, ?, 1, 'dbn_dashboard', NOW())"
|
||||
)->execute([$clientId, $packageId]);
|
||||
);
|
||||
foreach ($packageIds as $packageId) {
|
||||
$insert->execute([$clientId, $packageId]);
|
||||
}
|
||||
}
|
||||
|
||||
private static function uniqueSlug(PDO $db, string $base): string
|
||||
|
||||
@@ -36,7 +36,8 @@ final class DbnDeepResearchAgent
|
||||
string $advocateRole = '',
|
||||
?array $priorContext = null,
|
||||
string $branchNotes = '',
|
||||
array $subQuestionsOverride = []
|
||||
array $subQuestionsOverride = [],
|
||||
?string $persona = null
|
||||
): array {
|
||||
$seedQuery = trim($seedQuery);
|
||||
$pastedText = trim($pastedText);
|
||||
@@ -50,7 +51,15 @@ final class DbnDeepResearchAgent
|
||||
}
|
||||
|
||||
$client = dbnToolsRequireClient();
|
||||
$package = $this->requireFamilyPackage((int)$client['id']);
|
||||
$personaResolved = dbnToolsResolvePersona((int)$client['id'], $persona);
|
||||
$packageIds = array_values(array_filter(
|
||||
array_map('intval', $personaResolved['package_ids'] ?? []),
|
||||
static fn(int $id): bool => $id > 0
|
||||
));
|
||||
if (!$packageIds) {
|
||||
// Persona resolved without a package → fall back to the legacy family package.
|
||||
$packageIds = [(int)$this->requireFamilyPackage((int)$client['id'])['id']];
|
||||
}
|
||||
|
||||
dbnToolsBootCaveau();
|
||||
$aiPortalRoot = dbnToolsAiPortalRoot();
|
||||
@@ -230,7 +239,7 @@ final class DbnDeepResearchAgent
|
||||
[
|
||||
'search_private' => false,
|
||||
'search_shared' => true,
|
||||
'package_ids' => [(int)$package['id']],
|
||||
'package_ids' => $packageIds,
|
||||
'shared_doc_ids' => $sharedDocIds,
|
||||
'chunk_limit' => $controls['chunk_limit'],
|
||||
'search_method' => 'hybrid',
|
||||
|
||||
@@ -243,7 +243,7 @@ PROMPT;
|
||||
*
|
||||
* @return array Final result payload (matches NDJSON 'final' event shape).
|
||||
*/
|
||||
public function generate(array $intake, array $classify, ?callable $emit = null, string $engine = 'azure_mini'): array
|
||||
public function generate(array $intake, array $classify, ?callable $emit = null, string $engine = 'azure_mini', ?string $persona = null): array
|
||||
{
|
||||
$draftDeployment = ($this->azure instanceof DbnBedrockGateway)
|
||||
? (($engine === 'claude_sonnet' || $engine === 'azure_full')
|
||||
@@ -259,7 +259,7 @@ PROMPT;
|
||||
|
||||
// ── Retrieve law ────────────────────────────────────────────────────────
|
||||
if ($emit) { $emit('progress', ['detail' => self::L('fetching_law', $userLang)]); }
|
||||
$retrieval = $this->retrieveLaw($body, $classify['applicable_acts'] ?? []);
|
||||
$retrieval = $this->retrieveLaw($body, $classify['applicable_acts'] ?? [], $persona);
|
||||
if ($emit) {
|
||||
$emit('retrieval', [
|
||||
'sources_count' => count($retrieval['sources']),
|
||||
@@ -420,12 +420,20 @@ PROMPT;
|
||||
*
|
||||
* @return array{sources:array, applied_slices:string[]}
|
||||
*/
|
||||
private function retrieveLaw(string $body, array $applicableActs): array
|
||||
private function retrieveLaw(string $body, array $applicableActs, ?string $persona = null): array
|
||||
{
|
||||
$client = dbnToolsRequireClient();
|
||||
$package = dbnToolsFetchPackage(dbnToolsRequiredPackageSlug());
|
||||
if (!$package) {
|
||||
return ['sources' => [], 'applied_slices' => []];
|
||||
$personaResolved = dbnToolsResolvePersona((int)$client['id'], $persona);
|
||||
$packageIds = array_values(array_filter(
|
||||
array_map('intval', $personaResolved['package_ids'] ?? []),
|
||||
static fn(int $id): bool => $id > 0
|
||||
));
|
||||
if (!$packageIds) {
|
||||
$package = dbnToolsFetchPackage(dbnToolsRequiredPackageSlug());
|
||||
if (!$package) {
|
||||
return ['sources' => [], 'applied_slices' => []];
|
||||
}
|
||||
$packageIds = [(int)$package['id']];
|
||||
}
|
||||
|
||||
dbnToolsBootCaveau();
|
||||
@@ -476,7 +484,7 @@ PROMPT;
|
||||
$chunks = $rag->searchAll($q, 5, null, [
|
||||
'search_private' => false,
|
||||
'search_shared' => true,
|
||||
'package_ids' => [(int)$package['id']],
|
||||
'package_ids' => $packageIds,
|
||||
'shared_doc_ids' => $sharedDocIds,
|
||||
'chunk_limit' => 5,
|
||||
'search_method' => 'hybrid',
|
||||
|
||||
Reference in New Issue
Block a user