Prechádzať zdrojové kódy

#5406 AI Agents revamp: code refactoring

Aleksandr Trofimov 1 mesiac pred
rodič
commit
831d81e6d9

+ 1 - 1
inc/classes/BxDolAIToolChatArtifactSave.php

@@ -46,7 +46,7 @@ class BxDolAIToolChatArtifactSave extends BxDolAITool
         if ($sName === '' || $sValue === '')
             return 'ignored';
 
-        $iHistoryId = (int)BxDolAi::getInstance()->getCurrentChatHistoryId();
+        $iHistoryId = (int)BxDolAiChat::getInstance()->getCurrentChatHistoryId();
         if ($iHistoryId <= 0)
             return 'no_history';
 

+ 1 - 1
inc/classes/BxDolAIToolChatGoalReached.php

@@ -34,7 +34,7 @@ class BxDolAIToolChatGoalReached extends BxDolAITool
 
     public function __invoke(string $sSummary = ''): string
     {
-        $b = BxDolAi::getInstance()->emitConversationClosed('goal', trim((string)$sSummary));
+        $b = BxDolAiChat::getInstance()->emitConversationClosed('goal', trim((string)$sSummary));
         return $b ? 'ok' : 'already_closed';
     }
 }

+ 0 - 166
inc/classes/BxDolAi.php

@@ -12,10 +12,6 @@ class BxDolAi extends BxDolFactory implements iBxDolSingleton
     protected $_oDb;
     protected $_iProfileId;
 
-    protected $_oChat;
-    protected $_oChatUi;
-    protected $_oLimits;
-
     protected function __construct()
     {
         if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
@@ -26,10 +22,6 @@ class BxDolAi extends BxDolFactory implements iBxDolSingleton
         $this->_oDb = new BxDolAiQuery();
 
         $this->_iProfileId = (int)getParam('sys_profile_bot');
-
-        $this->_oChatUi = new BxDolAiChatUi();
-        $this->_oChat = new BxDolAiChat($this->_oDb, $this, $this->_oChatUi);
-        $this->_oLimits = new BxDolAiChatLimits($this->_oDb, $this);
     }
 
     /**
@@ -129,11 +121,6 @@ class BxDolAi extends BxDolFactory implements iBxDolSingleton
         return BxDolAiTrigger::getInstance($sType)->call($aAgent, $mixedParams);
     }
 
-    public function setChatContext($aAgent, $aParams)
-    {
-        $this->_oChat->setChatContext($aAgent, $aParams);
-    }
-
     /**
      * Whether the current (or given) member may interact with the agent
      * via chat, messenger, or form-input. Empty acl_levels means Nobody.
@@ -169,164 +156,11 @@ class BxDolAi extends BxDolFactory implements iBxDolSingleton
         return in_array($aAgent['trigger'] ?? '', ['manual', 'message'], true);
     }
 
-    /**
-     * Runner limits from the agent row. 0 = no cap. Never put these in the prompt.
-     */
-    public function applyChatInputLimit($sPrompt, $aAgent)
-    {
-        return $this->_oLimits->applyChatInputLimit($sPrompt, $aAgent);
-    }
-
-    public function getChatLimitMessage($aAgent)
-    {
-        return $this->_oLimits->getChatLimitMessage($aAgent);
-    }
-
-    public function getChatSessionRateLimitError()
-    {
-        return $this->_oLimits->getChatSessionRateLimitError();
-    }
-
-    public function countChatUserTurns($aUiMessages)
-    {
-        return $this->_oLimits->countChatUserTurns($aUiMessages);
-    }
-
-    public function isChatTurnLimitReached($aAgent, $iTurns, $iRequestUserTurns = 0)
-    {
-        return $this->_oLimits->isChatTurnLimitReached($aAgent, $iTurns, $iRequestUserTurns);
-    }
-
-    public function getChatUserTurnCount($iAgentId, $aParams = [])
-    {
-        return $this->_oLimits->getChatUserTurnCount($iAgentId, $aParams);
-    }
-
-    /**
-     * New chat threads per IP for this agent. 0 on the agent = no cap.
-     * Continuation of an existing thread is not a new session.
-     */
-    public function isChatSessionRateLimited($aAgent, $aParams = [])
-    {
-        return $this->_oLimits->isChatSessionRateLimited($aAgent, $aParams);
-    }
-
     public function extractChatPromptFromRequest($aData)
     {
         return BxDolAiTrigger::getInstance('chat')->extractPromptFromRequest($aData);
     }
 
-    /**
-     * Guests: UNA session id. Members: profile id.
-     * Guest chats remember agent ids in session so login can adopt those threads.
-     */
-    public function resolveChatHistoryParams($iAgentId = 0)
-    {
-        return $this->_oChat->resolveChatHistoryParams($iAgentId);
-    }
-
-    /**
-     * `{trigger}:{agentId}:{contextPid}:{userSubindex}`.
-     * Context is omitted when 0 so existing site-wide threads still load.
-     * User suffix (session id or profile id) stays last so adopt can replace it.
-     */
-    public static function chatHistoryThreadId($aAgent, $aParams = [])
-    {
-        return BxDolAiChat::threadId($aAgent, $aParams);
-    }
-
-    public function getChatHistoryRowId($aAgent, $aParams = [])
-    {
-        return $this->_oChat->getChatHistoryRowId($aAgent, $aParams);
-    }
-
-    public function getCurrentChatHistoryId()
-    {
-        return $this->_oChat->getCurrentChatHistoryId();
-    }
-
-    public function emitConversationClosed($sReason, $sSummary = '', $aAgent = null, $aParams = null)
-    {
-        return $this->_oChat->emitConversationClosed($sReason, $sSummary, $aAgent, $aParams);
-    }
-
-    /**
-     * @return array{thread_id:string,chat_history_context_pid:int,chat_history_subindex:string}|false
-     */
-    public static function parseChatHistoryThreadId($aAgent, $sThreadId)
-    {
-        return BxDolAiChat::parseThreadId($aAgent, $sThreadId);
-    }
-
-    public function isOwnAgentChatThread($aAgent, $sThreadId)
-    {
-        return $this->_oChat->isOwnAgentChatThread($aAgent, $sThreadId);
-    }
-
-    public function storedChatJsonToUiMessages($sJson)
-    {
-        return $this->_oChatUi->storedChatJsonToUiMessages($sJson);
-    }
-
-    public function getChatHistoryUiMessagesByThread($aAgent, $sThreadId)
-    {
-        return $this->_oChat->getChatHistoryUiMessagesByThread($aAgent, $sThreadId);
-    }
-
-    public function getChatHistoryArtifactsByThread($aAgent, $sThreadId)
-    {
-        return $this->_oChat->getChatHistoryArtifactsByThread($aAgent, $sThreadId);
-    }
-
-    public function listAgentChatThreads($aAgent)
-    {
-        return $this->_oChat->listAgentChatThreads($aAgent);
-    }
-
-    /**
-     * Context from chat HTTP (`?context=`). Missing/0 = site-wide. Invalid/denied = false (403).
-     * Posting in a group is not the same as viewing it; chat requires post by default.
-     * @return int|false
-     */
-    public function resolveChatHistoryContextPid($bRequirePost = true)
-    {
-        return $this->_oChat->resolveChatHistoryContextPid($bRequirePost);
-    }
-
-    /**
-     * Context of the current page (AI agent block).
-     * `bx_get_page_info()` reads the URL; App page JSON merges `i`/`id` into $_GET instead.
-     * @param bool $bRequirePost also require posting into the context (membership / post ACL)
-     */
-    public function resolveChatHistoryContextPidFromPage($bRequirePost = false)
-    {
-        return $this->_oChat->resolveChatHistoryContextPidFromPage($bRequirePost);
-    }
-
-    public function filterContextPid($iPid, $bRequirePost = false)
-    {
-        return $this->_oChat->filterContextPid($iPid, $bRequirePost);
-    }
-
-    /**
-     * Transcript for TanStack `useChat` hydrate / `initialMessages`.
-     * Loads the same NeuronAI chat history the agent uses when streaming.
-     *
-     * @param bool $bAppendLimitMessage when the session is at max_turns, append limit_message for the UI
-     */
-    public function getChatHistoryUiMessages($iAgentId, $aParams = [], $bAppendLimitMessage = true)
-    {
-        return $this->_oChat->getChatHistoryUiMessages($iAgentId, $aParams, $bAppendLimitMessage);
-    }
-
-    /**
-     * @return array{content: string, actions: array}|null
-     */
-    public function parseAssistantChatPayload($sText)
-    {
-        return $this->_oChatUi->parseAssistantChatPayload($sText);
-    }
-
     public function streamAgentChat($iAgentId, $sPrompt, $aParams = [], $sThreadId = null)
     {
         return BxDolAiTrigger::getInstance('chat')->stream($iAgentId, $sPrompt, $aParams, $sThreadId);

+ 1 - 1
inc/classes/BxDolAiAgent.php

@@ -129,7 +129,7 @@ class BxDolAiAgent extends RAG
 
     protected function getСhatHistoryThreadId(): string
     {
-        return BxDolAi::chatHistoryThreadId($this->aAgent, $this->aParams);
+        return BxDolAiChat::threadId($this->aAgent, $this->aParams);
     }
 
     protected function getAlertTriggerModifyableKeys(): string

+ 14 - 7
inc/classes/BxDolAiChat.php

@@ -10,15 +10,21 @@
 class BxDolAiChat
 {
     protected $_oDb;
-    protected $_oAi;
     protected $_oUi;
     protected $_aChatContext;
 
-    public function __construct(BxDolAiQuery $oDb, BxDolAi $oAi, BxDolAiChatUi $oUi)
+    public static function getInstance()
     {
-        $this->_oDb = $oDb;
-        $this->_oAi = $oAi;
-        $this->_oUi = $oUi;
+        if (!isset($GLOBALS['bxDolClasses'][__CLASS__]))
+            $GLOBALS['bxDolClasses'][__CLASS__] = new self();
+
+        return $GLOBALS['bxDolClasses'][__CLASS__];
+    }
+
+    public function __construct()
+    {
+        $this->_oDb = new BxDolAiQuery();
+        $this->_oUi = BxDolAiChatUi::getInstance();
         $this->_aChatContext = null;
     }
 
@@ -344,11 +350,12 @@ class BxDolAiChat
         }
 
         $aResult = $this->_oUi->neuronMessagesToUiMessages($o->getChatHistory()->getMessages());
-        if ($bAppendLimitMessage && $this->_oAi->isChatTurnLimitReached($aAgent, $this->_oAi->countChatUserTurns($aResult))) {
+        $oLimits = BxDolAiChatLimits::getInstance();
+        if ($bAppendLimitMessage && $oLimits->isChatTurnLimitReached($aAgent, $oLimits->countChatUserTurns($aResult))) {
             $aResult[] = [
                 'id' => 'agent_limit_message',
                 'role' => 'assistant',
-                'parts' => [['type' => 'text', 'content' => $this->_oAi->getChatLimitMessage($aAgent)]],
+                'parts' => [['type' => 'text', 'content' => $oLimits->getChatLimitMessage($aAgent)]],
             ];
         }
 

+ 13 - 7
inc/classes/BxDolAiChatLimits.php

@@ -10,12 +10,18 @@
 class BxDolAiChatLimits
 {
     protected $_oDb;
-    protected $_oAi;
 
-    public function __construct(BxDolAiQuery $oDb, BxDolAi $oAi)
+    public static function getInstance()
     {
-        $this->_oDb = $oDb;
-        $this->_oAi = $oAi;
+        if (!isset($GLOBALS['bxDolClasses'][__CLASS__]))
+            $GLOBALS['bxDolClasses'][__CLASS__] = new self();
+
+        return $GLOBALS['bxDolClasses'][__CLASS__];
+    }
+
+    public function __construct()
+    {
+        $this->_oDb = new BxDolAiQuery();
     }
 
     /**
@@ -77,7 +83,7 @@ class BxDolAiChatLimits
     public function getChatUserTurnCount($iAgentId, $aParams = [])
     {
         if (!isset($aParams['chat_history_subindex']))
-            $aParams = array_merge($this->_oAi->resolveChatHistoryParams($iAgentId), $aParams);
+            $aParams = array_merge(BxDolAiChat::getInstance()->resolveChatHistoryParams($iAgentId), $aParams);
 
         try {
             $o = BxDolAi::getAgentInstance((int)$iAgentId, $aParams);
@@ -110,9 +116,9 @@ class BxDolAiChatLimits
             return false;
 
         if (!isset($aParams['chat_history_subindex']))
-            $aParams = array_merge($this->_oAi->resolveChatHistoryParams((int)($aAgent['id'] ?? 0)), $aParams);
+            $aParams = array_merge(BxDolAiChat::getInstance()->resolveChatHistoryParams((int)($aAgent['id'] ?? 0)), $aParams);
 
-        $sThreadId = BxDolAi::chatHistoryThreadId($aAgent, $aParams);
+        $sThreadId = BxDolAiChat::threadId($aAgent, $aParams);
         if (!$this->_oDb->isNewChatSession($sThreadId))
             return false;
 

+ 8 - 0
inc/classes/BxDolAiChatUi.php

@@ -9,6 +9,14 @@
 
 class BxDolAiChatUi
 {
+    public static function getInstance()
+    {
+        if (!isset($GLOBALS['bxDolClasses'][__CLASS__]))
+            $GLOBALS['bxDolClasses'][__CLASS__] = new self();
+
+        return $GLOBALS['bxDolClasses'][__CLASS__];
+    }
+
     public function storedChatJsonToUiMessages($sJson)
     {
         $aStored = json_decode((string)$sJson, true);

+ 11 - 9
inc/classes/BxDolAiTrigger.php

@@ -83,17 +83,19 @@ class BxDolAiTrigger extends BxDol implements iBxDolAiTrigger
         $aParams = $this->getCallChatHistoryParams($aAgent, $mixedParams);
         $sParams = $this->limitCallInput($aAgent, $mixedParams, $sParams);
 
+        $oLimits = BxDolAiChatLimits::getInstance();
+        $oChat = BxDolAiChat::getInstance();
         if ($this->appliesChatLimits()) {
-            if ($oAi->isChatTurnLimitReached($aAgent, $oAi->getChatUserTurnCount($aAgent['id'], $aParams))) {
-                $oAi->emitConversationClosed('limit', '', $aAgent, $aParams);
-                return $oAi->getChatLimitMessage($aAgent);
+            if ($oLimits->isChatTurnLimitReached($aAgent, $oLimits->getChatUserTurnCount($aAgent['id'], $aParams))) {
+                $oChat->emitConversationClosed('limit', '', $aAgent, $aParams);
+                return $oLimits->getChatLimitMessage($aAgent);
             }
 
-            if ($oAi->isChatSessionRateLimited($aAgent, $aParams))
-                throw new Exception($oAi->getChatSessionRateLimitError());
+            if ($oLimits->isChatSessionRateLimited($aAgent, $aParams))
+                throw new Exception($oLimits->getChatSessionRateLimitError());
         }
 
-        $oAi->setChatContext($aAgent, $aParams);
+        $oChat->setChatContext($aAgent, $aParams);
 
         $mixed = '';
         try {
@@ -144,14 +146,14 @@ class BxDolAiTrigger extends BxDol implements iBxDolAiTrigger
         if (!$this->appliesChatLimits())
             return $sParams;
 
-        $oAi = $this->getAi();
+        $oLimits = BxDolAiChatLimits::getInstance();
         if (is_array($mixedParams) && isset($mixedParams['message_text'])) {
-            $mixedParams['message_text'] = $oAi->applyChatInputLimit((string)$mixedParams['message_text'], $aAgent);
+            $mixedParams['message_text'] = $oLimits->applyChatInputLimit((string)$mixedParams['message_text'], $aAgent);
             return json_encode($mixedParams);
         }
 
         if (is_string($mixedParams))
-            return $oAi->applyChatInputLimit($sParams, $aAgent);
+            return $oLimits->applyChatInputLimit($sParams, $aAgent);
 
         return $sParams;
     }

+ 25 - 24
inc/classes/BxDolAiTriggerChat.php

@@ -53,7 +53,7 @@ class BxDolAiTriggerChat extends BxDolAiTrigger
         if (!$aParams)
             return echoJson(['code' => 403, 'msg' => _t('_sys_agents_unauthorized')]);
 
-        $aParams['request_user_turns'] = $oAi->countChatUserTurns($aData['messages'] ?? []);
+        $aParams['request_user_turns'] = BxDolAiChatLimits::getInstance()->countChatUserTurns($aData['messages'] ?? []);
 
         $sThreadId = !empty($aData['threadId']) ? $aData['threadId'] : null;
 
@@ -109,9 +109,10 @@ class BxDolAiTriggerChat extends BxDolAiTrigger
 
     public function stream($iAgentId, $sPrompt, $aParams = [], $sThreadId = null)
     {
-        $oAi = $this->getAi();
-        if ($oAi && !isset($aParams['chat_history_subindex']))
-            $aParams = array_merge($oAi->resolveChatHistoryParams($iAgentId), $aParams);
+        $oChat = BxDolAiChat::getInstance();
+        $oLimits = BxDolAiChatLimits::getInstance();
+        if (!isset($aParams['chat_history_subindex']))
+            $aParams = array_merge($oChat->resolveChatHistoryParams($iAgentId), $aParams);
 
         // Staging header.inc.php dumps HTML on fatals and warns on null error_get_last().
         // Any HTML after SSE is parsed by TanStack as "unterminated trailing data".
@@ -140,26 +141,26 @@ class BxDolAiTriggerChat extends BxDolAiTrigger
         };
 
         $aAgent = BxDolAiQuery::getAgentObject((int)$iAgentId);
-        if ($aAgent && $oAi)
-            $oAi->setChatContext($aAgent, $aParams);
+        if ($aAgent)
+            $oChat->setChatContext($aAgent, $aParams);
 
-        if ($aAgent && $oAi && $oAi->isChatSessionRateLimited($aAgent, $aParams)) {
-            $this->emitErrorSse($oAdapter, $fEmit, $oAi->getChatSessionRateLimitError());
+        if ($aAgent && $oLimits->isChatSessionRateLimited($aAgent, $aParams)) {
+            $this->emitErrorSse($oAdapter, $fEmit, $oLimits->getChatSessionRateLimitError());
             error_clear_last();
             @ini_set('display_errors', '0');
             exit;
         }
 
         $iRequestTurns = (int)($aParams['request_user_turns'] ?? 0);
-        if ($aAgent && $oAi && $oAi->isChatTurnLimitReached($aAgent, $oAi->getChatUserTurnCount((int)$iAgentId, $aParams), $iRequestTurns)) {
-            $oAi->emitConversationClosed('limit', '', $aAgent, $aParams);
-            $this->emitLimitSse($oAdapter, $fEmit, $oAi->getChatLimitMessage($aAgent));
+        if ($aAgent && $oLimits->isChatTurnLimitReached($aAgent, $oLimits->getChatUserTurnCount((int)$iAgentId, $aParams), $iRequestTurns)) {
+            $oChat->emitConversationClosed('limit', '', $aAgent, $aParams);
+            $this->emitLimitSse($oAdapter, $fEmit, $oLimits->getChatLimitMessage($aAgent));
             error_clear_last();
             @ini_set('display_errors', '0');
             exit;
         }
 
-        $sPrompt = $oAi ? $oAi->applyChatInputLimit((string)$sPrompt, $aAgent ?: []) : (string)$sPrompt;
+        $sPrompt = $oLimits->applyChatInputLimit((string)$sPrompt, $aAgent ?: []);
 
         $bStarted = false;
         $aSseState = $this->resetActionsSseState();
@@ -176,8 +177,8 @@ class BxDolAiTriggerChat extends BxDolAiTrigger
             $this->flushActionsSseState($aSseState, $fEmit);
             $this->persistAssistantActions($o);
 
-            if ($aAgent && $oAi && $oAi->isChatTurnLimitReached($aAgent, $oAi->getChatUserTurnCount((int)$iAgentId, $aParams)))
-                $oAi->emitConversationClosed('limit', '', $aAgent, $aParams);
+            if ($aAgent && $oLimits->isChatTurnLimitReached($aAgent, $oLimits->getChatUserTurnCount((int)$iAgentId, $aParams)))
+                $oChat->emitConversationClosed('limit', '', $aAgent, $aParams);
         } catch (Throwable $oException) {
             bx_log('sys_agents', "Stream exception for agent {$iAgentId}: " . $oException->getMessage() . " INPUT:" . $sPrompt);
             $this->flushActionsSseState($aSseState, $fEmit);
@@ -217,7 +218,7 @@ class BxDolAiTriggerChat extends BxDolAiTrigger
             return echoJson(['code' => 403, 'msg' => _t('_sys_agents_unauthorized'), 'messages' => [], 'activeRun' => null, 'interrupts' => null]);
 
         try {
-            $aMessages = $oAi->getChatHistoryUiMessages($aAgent['id'], $aParams);
+            $aMessages = BxDolAiChat::getInstance()->getChatHistoryUiMessages($aAgent['id'], $aParams);
         } catch (Throwable $o) {
             $aMessages = [];
         }
@@ -238,12 +239,12 @@ class BxDolAiTriggerChat extends BxDolAiTrigger
      */
     protected function historyParams($aAgent)
     {
-        $oAi = $this->getAi();
-        $mixedContext = $oAi->resolveChatHistoryContextPid();
+        $oChat = BxDolAiChat::getInstance();
+        $mixedContext = $oChat->resolveChatHistoryContextPid();
         if ($mixedContext === false)
             return false;
 
-        $aParams = $oAi->resolveChatHistoryParams((int)$aAgent['id']);
+        $aParams = $oChat->resolveChatHistoryParams((int)$aAgent['id']);
         $aParams['chat_history_context_pid'] = (int)$mixedContext;
         return $aParams;
     }
@@ -325,7 +326,7 @@ class BxDolAiTriggerChat extends BxDolAiTrigger
 
     protected function processActionsSseEvent($sEvent, &$aState, $fEmit)
     {
-        $oAi = $this->getAi();
+        $oUi = BxDolAiChatUi::getInstance();
         $aPayload = $this->parseSseEvent($sEvent);
         $sType = is_array($aPayload) ? (string)($aPayload['type'] ?? '') : '';
 
@@ -360,7 +361,7 @@ class BxDolAiTriggerChat extends BxDolAiTrigger
         }
 
         if ($sType === 'TEXT_MESSAGE_END') {
-            $aParsed = $oAi->parseAssistantChatPayload($aState['buf']);
+            $aParsed = $oUi->parseAssistantChatPayload($aState['buf']);
             if ($aParsed && ($aState['mode'] === 'json' || $aState['mode'] === 'undecided')) {
                 $this->emitParsedActionsSse($aState, $fEmit, $aParsed);
                 return;
@@ -396,11 +397,11 @@ class BxDolAiTriggerChat extends BxDolAiTrigger
 
     protected function flushActionsSseState(&$aState, $fEmit)
     {
-        $oAi = $this->getAi();
+        $oUi = BxDolAiChatUi::getInstance();
         if ($aState['buf'] === '' && !$aState['held'])
             return;
 
-        $aParsed = $oAi->parseAssistantChatPayload($aState['buf']);
+        $aParsed = $oUi->parseAssistantChatPayload($aState['buf']);
         if ($aParsed && $aState['mode'] !== 'text') {
             $this->emitParsedActionsSse($aState, $fEmit, $aParsed);
             return;
@@ -412,7 +413,7 @@ class BxDolAiTriggerChat extends BxDolAiTrigger
 
     protected function persistAssistantActions($oAgent)
     {
-        $oAi = $this->getAi();
+        $oUi = BxDolAiChatUi::getInstance();
         if (!is_object($oAgent) || !method_exists($oAgent, 'getChatHistory'))
             return;
 
@@ -436,7 +437,7 @@ class BxDolAiTriggerChat extends BxDolAiTrigger
             if ($sRole !== 'assistant')
                 return;
 
-            $aParsed = $oAi->parseAssistantChatPayload((string)$oMessage->getContent());
+            $aParsed = $oUi->parseAssistantChatPayload((string)$oMessage->getContent());
             if (!$aParsed)
                 return;
 

+ 7 - 12
studio/template/scripts/BxBaseStudioAgentsAgents.php

@@ -272,8 +272,8 @@ class BxBaseStudioAgentsAgents extends BxDolStudioAgentsAgents
         $sChatId = 'bx-ai-chat-' . $iId;
         $sName = !empty($aAgent['title']) ? $aAgent['title'] : $aAgent['name'];
         $aThreadsTpl = [];
-        $oAi = BxDolAi::getInstance();
-        $aThreads = $oAi ? $oAi->listAgentChatThreads($aAgent) : [];
+        $oChat = BxDolAiChat::getInstance();
+        $aThreads = $oChat->listAgentChatThreads($aAgent);
         foreach ($aThreads as $aThread) {
             $aThreadsTpl[] = [
                 'thread_id' => bx_html_attribute($aThread['thread_id']),
@@ -321,8 +321,7 @@ class BxBaseStudioAgentsAgents extends BxDolStudioAgentsAgents
         }
 
         $aThreadsJs = [];
-        $oAi = BxDolAi::getInstance();
-        $aThreads = $oAi ? $oAi->listAgentChatThreads($aAgent) : [];
+        $aThreads = BxDolAiChat::getInstance()->listAgentChatThreads($aAgent);
         foreach ($aThreads as $aThread)
             $aThreadsJs[] = $this->_agentChatThreadJs($aThread);
 
@@ -339,13 +338,9 @@ class BxBaseStudioAgentsAgents extends BxDolStudioAgentsAgents
         }
 
         $sThreadId = trim((string)bx_get('thread_id'));
-        $oAi = BxDolAi::getInstance();
-        if (!$oAi) {
-            echoJson(['code' => 503, 'msg' => _t('_sys_txt_error_occured'), 'messages' => []]);
-            return;
-        }
+        $oChat = BxDolAiChat::getInstance();
 
-        $aMessages = $oAi->getChatHistoryUiMessagesByThread($aAgent, $sThreadId);
+        $aMessages = $oChat->getChatHistoryUiMessagesByThread($aAgent, $sThreadId);
         if ($aMessages === false) {
             echoJson(['code' => 404, 'msg' => _t('_sys_txt_error_occured'), 'messages' => []]);
             return;
@@ -354,8 +349,8 @@ class BxBaseStudioAgentsAgents extends BxDolStudioAgentsAgents
         echoJson([
             'code' => 200,
             'messages' => $aMessages,
-            'writable' => $oAi->isOwnAgentChatThread($aAgent, $sThreadId) ? 1 : 0,
-            'artifacts' => $oAi->getChatHistoryArtifactsByThread($aAgent, $sThreadId),
+            'writable' => $oChat->isOwnAgentChatThread($aAgent, $sThreadId) ? 1 : 0,
+            'artifacts' => $oChat->getChatHistoryArtifactsByThread($aAgent, $sThreadId),
         ]);
     }
 

+ 3 - 2
template/scripts/BxBaseServices.php

@@ -873,11 +873,12 @@ class BxBaseServices extends BxDol implements iBxDolProfileService
             return $bIsApi ? [] : '';
 
         $oAi = BxDolAi::getInstance();
+        $oChat = BxDolAiChat::getInstance();
         $bRequirePost = (bool)$bRequirePost;
         if ($mixedContextPid === false || $mixedContextPid === null || $mixedContextPid === '')
-            $iContextPid = $oAi ? (int)$oAi->resolveChatHistoryContextPidFromPage($bRequirePost) : 0;
+            $iContextPid = $oAi ? (int)$oChat->resolveChatHistoryContextPidFromPage($bRequirePost) : 0;
         else
-            $iContextPid = $oAi ? $oAi->filterContextPid((int)$mixedContextPid, $bRequirePost) : 0;
+            $iContextPid = $oAi ? $oChat->filterContextPid((int)$mixedContextPid, $bRequirePost) : 0;
 
         if ($bIsApi)
             return [bx_api_get_block('ai_agent', [