'BxDolAiTriggerAlert', 'message' => 'BxDolAiTriggerMessage', 'webhook' => 'BxDolAiTriggerWebhook', 'scheduler' => 'BxDolAiTriggerScheduler', 'form-input' => 'BxDolAiTriggerFormInput', 'manual' => 'BxDolAiTriggerChat', ]; $sClass = $aMap[$sType] ?? 'BxDolAiTrigger'; $sKey = __CLASS__ . '_' . $sType; if (!isset($GLOBALS['bxDolClasses'][$sKey])) { $o = new $sClass(); if ('BxDolAiTrigger' === $sClass) $o->_sType = $sType; $GLOBALS['bxDolClasses'][$sKey] = $o; } return $GLOBALS['bxDolClasses'][$sKey]; } public function getType() { return $this->_sType; } public function handle($mixed = null) { return false; } public function call($aAgent, $mixedParams = []) { $oAi = $this->getAi(); if (!$oAi) return false; if ($mixedParams) $sParams = is_string($mixedParams) ? $mixedParams : json_encode($mixedParams); else $sParams = 'START'; $sSampleField = $this->getSampleField(); if ($sSampleField && empty($aAgent[$sSampleField])) { $oDb = new BxDolAiQuery(); $oDb->updateAgentField($aAgent['id'], $sSampleField, $sParams); } $aParams = $this->getCallChatHistoryParams($aAgent, $mixedParams); $sParams = $this->limitCallInput($aAgent, $mixedParams, $sParams); $oLimits = BxDolAiChatLimits::getInstance(); $oChat = BxDolAiChat::getInstance(); if ($this->appliesChatLimits()) { if ($oLimits->isChatTurnLimitReached($aAgent, $oLimits->getChatUserTurnCount($aAgent['id'], $aParams))) { $oChat->emitConversationClosed('limit', '', $aAgent, $aParams); return $this->getChatLimitReply($aAgent); } if ($oLimits->isChatSessionRateLimited($aAgent, $aParams)) throw new Exception($oLimits->getChatSessionRateLimitError()); } $oChat->setChatContext($aAgent, $aParams); $mixed = ''; try { $o = BxDolAi::getAgentInstance($aAgent['id'], $aParams); if (!$o) return false; $oMessage = $o->chat(new NeuronAI\Chat\Messages\UserMessage($sParams))->getMessage(); $mixed = $oMessage->getContent(); } catch (Exception $exception) { bx_log('sys_agents', "Exception in '{$aAgent['name']}' agent: " . $exception->getMessage() . " INPUT:" . $sParams, BX_LOG_ERR); $mixed = isAdmin() ? self::visibleError($exception) : _t('_sys_agents_exception'); } return $mixed; } /** * Provider failures keep their full text in the log. Operators see the * provider's own message, such as an authentication error. */ public static function visibleError(Throwable $oException): string { $s = trim($oException->getMessage()); if ($s === '') return _t('_sys_agents_exception'); $iJson = bx_mb_strpos($s, '{'); if ($iJson !== false) { $sJson = get_mb_substr($s, $iJson, get_mb_len($s) - $iJson); $a = json_decode($sJson, true); if (is_array($a)) { $sMessage = trim((string)($a['error']['message'] ?? '')); if ($sMessage !== '') return $sMessage; } } return $s; } protected function getAi() { return BxDolAi::getInstance(); } protected function getSampleField() { return ''; } protected function usesSenderChatHistory() { return false; } protected function appliesChatLimits() { return false; } /** * What call() returns when the thread is at max_turns; null = reply with nothing. */ protected function getChatLimitReply($aAgent) { return BxDolAiChatLimits::getInstance()->getChatLimitMessage($aAgent); } protected function getCallChatHistoryParams($aAgent, $mixedParams) { if (!$this->usesSenderChatHistory() || !is_array($mixedParams)) return []; return ['chat_history_subindex' => (int)($mixedParams['sender_profile_id'] ?? 0)]; } protected function limitCallInput($aAgent, $mixedParams, $sParams) { if (!$this->appliesChatLimits()) return $sParams; $oLimits = BxDolAiChatLimits::getInstance(); if (is_array($mixedParams) && isset($mixedParams['message_text'])) { $mixedParams['message_text'] = $oLimits->applyChatInputLimit((string)$mixedParams['message_text'], $aAgent); return json_encode($mixedParams); } if (is_string($mixedParams)) return $oLimits->applyChatInputLimit($sParams, $aAgent); return $sParams; } protected function enqueue($aAgent, $mixedParams) { BxDolBackgroundJobs::getInstance()->add(bin2hex(random_bytes(16)), [ 'system', 'call_agent', [$this->getType(), $aAgent, $mixedParams], 'TemplServices' ]); } protected function runOrEnqueue($aAgent, $mixedParams) { if (!empty($aAgent['async'])) { $this->enqueue($aAgent, $mixedParams); return null; } return $this->call($aAgent, $mixedParams); } } /** @} */