Skip to content

Commit 7889415

Browse files
committed
#5654 AI agents improvements (split non-logged)
1 parent af854c6 commit 7889415

4 files changed

Lines changed: 126 additions & 10 deletions

File tree

inc/classes/BxDolAI.php

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -487,13 +487,54 @@ public function extractChatPromptFromRequest($aData)
487487
return '';
488488
}
489489

490+
/**
491+
* Guest threads: `g:{clientKey}` (NEO header) or `s:{memberSession}` (UNA cookie).
492+
* Members: profile id. Guest key is kept in session and adopted on login.
493+
*/
494+
public function resolveChatHistoryParams()
495+
{
496+
$iProfileId = (int)bx_get_logged_profile_id();
497+
$oSession = BxDolSession::getInstance();
498+
$sHeaderKey = $this->readAiGuestKeyFromRequest();
499+
$sSessionKey = 'ai_chat_guest_subindex';
500+
501+
if ($iProfileId) {
502+
$sGuest = $sHeaderKey ? ('g:' . $sHeaderKey) : '';
503+
if ($sGuest === '') {
504+
$sStored = $oSession->getValue($sSessionKey);
505+
if ($this->isAiGuestSubindex($sStored))
506+
$sGuest = $sStored;
507+
}
508+
if ($sGuest !== '')
509+
$this->_oDb->adoptGuestChatHistory($sGuest, $iProfileId);
510+
if ($oSession->isValue($sSessionKey))
511+
$oSession->unsetValue($sSessionKey);
512+
513+
return [
514+
'sender_profile_id' => $iProfileId,
515+
'chat_history_subindex' => (string)$iProfileId,
516+
];
517+
}
518+
519+
$oSession->start(true);
520+
$sSessionId = (string)$oSession->getId();
521+
$sSubindex = $sHeaderKey ? ('g:' . $sHeaderKey) : ('s:' . ($sSessionId !== '' ? $sSessionId : '0'));
522+
$oSession->setValue($sSessionKey, $sSubindex);
523+
524+
return [
525+
'sender_profile_id' => 0,
526+
'chat_history_subindex' => $sSubindex,
527+
];
528+
}
529+
490530
/**
491531
* Transcript for TanStack `useChat` hydrate / `initialMessages`.
492532
* Loads the same NeuronAI chat history the agent uses when streaming.
493533
*/
494534
public function getChatHistoryUiMessages($iAgentId, $aParams = [])
495535
{
496-
$aParams['chat_history_subindex'] = (int)($aParams['sender_profile_id'] ?? 0);
536+
if (!isset($aParams['chat_history_subindex']))
537+
$aParams = array_merge($this->resolveChatHistoryParams(), $aParams);
497538

498539
$aAgent = BxDolAiQuery::getAgentObject((int)$iAgentId);
499540
if (!$aAgent || empty($aAgent['chat_history_context']))
@@ -567,9 +608,38 @@ protected function neuronMessagesToUiMessages($aMessages)
567608
return $aResult;
568609
}
569610

611+
protected function readAiGuestKeyFromRequest()
612+
{
613+
$s = $_SERVER['HTTP_X_UNA_AI_GUEST_KEY'] ?? '';
614+
if ($s === '' && function_exists('apache_request_headers')) {
615+
foreach (apache_request_headers() as $sName => $sValue) {
616+
if (strtolower((string)$sName) === 'x-una-ai-guest-key') {
617+
$s = $sValue;
618+
break;
619+
}
620+
}
621+
}
622+
return $this->sanitizeAiGuestKey($s);
623+
}
624+
625+
protected function sanitizeAiGuestKey($s)
626+
{
627+
$s = is_string($s) ? $s : '';
628+
return preg_match('/^[A-Za-z0-9_-]{16,64}$/', $s) ? $s : '';
629+
}
630+
631+
protected function isAiGuestSubindex($s)
632+
{
633+
$s = is_string($s) ? $s : '';
634+
if ($s === '' || (strncmp($s, 'g:', 2) !== 0 && strncmp($s, 's:', 2) !== 0))
635+
return false;
636+
return $this->sanitizeAiGuestKey(substr($s, 2)) !== '';
637+
}
638+
570639
public function streamAgentChat($iAgentId, $sPrompt, $aParams = [], $sThreadId = null)
571640
{
572-
$aParams['chat_history_subindex'] = (int)($aParams['sender_profile_id'] ?? 0);
641+
if (!isset($aParams['chat_history_subindex']))
642+
$aParams = array_merge($this->resolveChatHistoryParams(), $aParams);
573643

574644
$oAdapter = new NeuronAI\Chat\Messages\Stream\Adapters\AGUIAdapter($sThreadId);
575645

inc/classes/BxDolAIQuery.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,56 @@ public function wipeAgentChatHistory($aAgent)
986986
return $iAffected;
987987
}
988988

989+
/**
990+
* Rename guest threads (`…:g:{key}` / `…:s:{session}`) onto a profile id.
991+
* If the member thread already has messages, drop the guest copy.
992+
*/
993+
public function adoptGuestChatHistory($sGuestSubindex, $iProfileId)
994+
{
995+
$sGuestSubindex = (string)$sGuestSubindex;
996+
$iProfileId = (int)$iProfileId;
997+
if ($sGuestSubindex === '' || !$iProfileId)
998+
return 0;
999+
1000+
$aRows = $this->getAll("SELECT `thread_id` FROM `sys_agents_chat_history`");
1001+
if (!$aRows)
1002+
return 0;
1003+
1004+
$sSuffix = ':' . $sGuestSubindex;
1005+
$iSuffixLen = strlen($sSuffix);
1006+
$iAffected = 0;
1007+
foreach ($aRows as $aRow) {
1008+
$sOld = $aRow['thread_id'] ?? '';
1009+
if ($sOld === '' || substr($sOld, -$iSuffixLen) !== $sSuffix)
1010+
continue;
1011+
1012+
$sNew = substr($sOld, 0, -$iSuffixLen) . ':' . $iProfileId;
1013+
if ($sNew === $sOld)
1014+
continue;
1015+
1016+
$sExisting = $this->getOne("SELECT `messages` FROM `sys_agents_chat_history` WHERE `thread_id` = :t", [
1017+
't' => $sNew,
1018+
]);
1019+
$aExisting = json_decode((string)$sExisting, true);
1020+
if (is_array($aExisting) && $aExisting !== []) {
1021+
$iAffected += (int)$this->query("DELETE FROM `sys_agents_chat_history` WHERE `thread_id` = :t", [
1022+
't' => $sOld,
1023+
]);
1024+
continue;
1025+
}
1026+
1027+
if ($sExisting !== false && $sExisting !== null)
1028+
$this->query("DELETE FROM `sys_agents_chat_history` WHERE `thread_id` = :t", ['t' => $sNew]);
1029+
1030+
$iAffected += (int)$this->query("UPDATE `sys_agents_chat_history` SET `thread_id` = :n WHERE `thread_id` = :o", [
1031+
'n' => $sNew,
1032+
'o' => $sOld,
1033+
]);
1034+
}
1035+
1036+
return $iAffected;
1037+
}
1038+
9891039
static public function getAlert($s) {
9901040
if (!$s)
9911041
return false;

inc/classes/BxDolAiAgent.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,8 @@ protected function resolveToolErrorHandler(): ?callable
124124
protected function getСhatHistoryThreadId(): string
125125
{
126126
$s = $this->aAgent['trigger'] . ':' . $this->aAgent['id'];
127-
if (isset($this->aParams['chat_history_subindex']))
128-
$s .= ':' . $this->aParams['chat_history_subindex'];
127+
if (isset($this->aParams['chat_history_subindex']) && $this->aParams['chat_history_subindex'] !== '')
128+
$s .= ':' . (string)$this->aParams['chat_history_subindex'];
129129
return $s;
130130
}
131131

template/scripts/BxBaseServices.php

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1827,9 +1827,7 @@ public function serviceAiChat($iAgentId)
18271827
if (!$sPrompt)
18281828
return echoJson(['code' => 400, 'msg' => _t('_sys_agents_json_field_err')]);
18291829

1830-
$oAi->streamAgentChat($aAgent['id'], $sPrompt, [
1831-
'sender_profile_id' => bx_get_logged_profile_id(),
1832-
], $aData['threadId'] ?? null);
1830+
$oAi->streamAgentChat($aAgent['id'], $sPrompt, $oAi->resolveChatHistoryParams(), $aData['threadId'] ?? null);
18331831
}
18341832

18351833
/**
@@ -1847,9 +1845,7 @@ protected function _aiChatHydrate($iAgentId)
18471845

18481846
$oAi = BxDolAI::getInstance();
18491847
return echoJson([
1850-
'messages' => $oAi->getChatHistoryUiMessages($aAgent['id'], [
1851-
'sender_profile_id' => bx_get_logged_profile_id(),
1852-
]),
1848+
'messages' => $oAi->getChatHistoryUiMessages($aAgent['id'], $oAi->resolveChatHistoryParams()),
18531849
'activeRun' => null,
18541850
'interrupts' => null,
18551851
]);

0 commit comments

Comments
 (0)