| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- <?php defined('BX_DOL') or die('hack attempt');
- /**
- * Copyright (c) UNA, Inc - https://una.io
- * MIT License - https://opensource.org/licenses/MIT
- *
- * @defgroup UnaCore UNA Core
- * @{
- */
- interface iBxDolAiTrigger
- {
- public function getType();
- /**
- * Host entry point (alert, cron, webhook, HTTP).
- * @param mixed $mixed host-specific context
- */
- public function handle($mixed = null);
- /**
- * Run one agent. Used by handle() and background jobs.
- */
- public function call($aAgent, $mixedParams = []);
- }
- class BxDolAiTrigger extends BxDol implements iBxDolAiTrigger
- {
- protected $_sType = '';
- public static function getInstance($sType)
- {
- if ('chat' === $sType)
- $sType = 'manual';
- $aMap = [
- 'alert' => '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);
- }
- }
- /** @} */
|