BxBaseStudioAgentsAgents.php 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374
  1. <?php defined('BX_DOL') or die('hack attempt');
  2. /**
  3. * Copyright (c) UNA, Inc - https://una.io
  4. * MIT License - https://opensource.org/licenses/MIT
  5. *
  6. * @defgroup UnaView UNA Studio Representation classes
  7. * @ingroup UnaStudio
  8. * @{
  9. */
  10. class BxBaseStudioAgentsAgents extends BxDolStudioAgentsAgents
  11. {
  12. protected $_sUrlPage;
  13. protected $_sFieldName;
  14. public function __construct ($aOptions, $oTemplate = false)
  15. {
  16. parent::__construct ($aOptions, $oTemplate);
  17. $this->_sUrlPage = BX_DOL_URL_STUDIO . 'agents.php?page=agents';
  18. $this->_sFieldName = 'name';
  19. }
  20. public function getPageJsObject()
  21. {
  22. return 'oBxDolStudioPageAgents';
  23. }
  24. public function performActionGetAlert()
  25. {
  26. $aAlert = $this->_getAlertPayload(bx_get('alert'));
  27. echoJson([
  28. 'code' => $aAlert ? 200 : 404,
  29. 'desc' => $aAlert ? $this->_oDb->getAlertDesc(bx_get('alert')) : '',
  30. 'payload' => $aAlert,
  31. ]);
  32. }
  33. public function performActionGetFormInputs()
  34. {
  35. $aFormInputs = $this->_getFormInputs(bx_get('form_object'));
  36. if (!$aFormInputs) {
  37. echoJson(['code' => 404, 'msg' => _t('_sys_not_available')]);
  38. return;
  39. }
  40. echoJson([
  41. 'code' => $aFormInputs ? 200 : 404,
  42. 'form_inputs' => $aFormInputs,
  43. ]);
  44. }
  45. public function performActionManual()
  46. {
  47. $iId = $this->_getId();
  48. $aAgent = BxDolAiQuery::getAgentObject($iId);
  49. if (!$aAgent) {
  50. echoJson(['msg' => _t('_sys_txt_error_occured')]);
  51. return;
  52. }
  53. if (!$aAgent['active']) {
  54. echoJson(['msg' => _t('_sys_txt_agent_inactive')]);
  55. return;
  56. }
  57. $oAi = BxDolAi::getInstance();
  58. try {
  59. $sResponse = $oAi->callAgent('manual', $aAgent);
  60. } catch (Throwable $o) {
  61. echoJson(['msg' => $o->getMessage()]);
  62. return;
  63. }
  64. $oParsedown = new Parsedown();
  65. $oParsedown->setSafeMode(true);
  66. $sMessageHtml = $oParsedown->text($sResponse);
  67. $oTemplate = BxDolStudioTemplate::getInstance();
  68. $sHtml = $oTemplate->parseHtmlByName('agents_manual_response.html', [
  69. 'response' => $sMessageHtml
  70. ]);
  71. echoJson(['msg' => $sHtml]);
  72. }
  73. public function performActionWipeChatHistory()
  74. {
  75. $iId = $this->_getId();
  76. $aAgent = BxDolAiQuery::getAgentObject($iId);
  77. if (!$aAgent) {
  78. echoJson(['msg' => _t('_sys_txt_error_occured')]);
  79. return;
  80. }
  81. $oDb = new BxDolAiQuery();
  82. $oDb->wipeAgentChatHistory($aAgent);
  83. $aRes = ['grid' => $this->getCode(false), 'blink' => $iId];
  84. echoJson($aRes);
  85. }
  86. public function performActionAdd()
  87. {
  88. $sAction = 'add';
  89. $oTemplate = BxDolStudioTemplate::getInstance();
  90. $oAI = BxDolAi::getInstance();
  91. $aForm = $this->_getForm($sAction);
  92. $oForm = new BxTemplFormView($aForm);
  93. $oForm->initChecker();
  94. if ($oForm->isSubmitted() && $oForm->getCleanValue('trigger') == 'message') {
  95. $aAgent = $this->_getAgentWithProfile($oForm->getCleanValue('profile_id'));
  96. if ($aAgent) {
  97. $oForm->aInputs['profile_id']['error'] = _t('_sys_agents_form_field_err_profile_has_agent', $aAgent['name']);
  98. $oForm->setValid(false);
  99. }
  100. }
  101. if($oForm->isSubmittedAndValid()) {
  102. $aValsToAdd = [
  103. 'added' => time()
  104. ];
  105. $sName = $oForm->getCleanValue($this->_sFieldName);
  106. $sName = $this->_getUniqName($sName);
  107. BxDolForm::setSubmittedValue($this->_sFieldName, $sName, $oForm->aFormAttrs['method']);
  108. $iProfileId = $oForm->getCleanValue('profile_id');
  109. if(empty($iProfileId)) {
  110. $iProfileId = (int)getParam('sys_profile_bot');
  111. if(empty($iProfileId))
  112. $iProfileId = current(bx_srv('system', 'get_options_agents_profile', [false], 'TemplServices'))['key'];
  113. $aValsToAdd['profile_id'] = $iProfileId;
  114. }
  115. $iModel = $oForm->getCleanValue('model_id');
  116. $sTrigger = $oForm->getCleanValue('trigger');
  117. $sTools = is_array($oForm->getCleanValue('tools')) ? implode(',', $oForm->getCleanValue('tools')) : '';
  118. $aValsToAdd['tools'] = BxDolAiAgentTools::stripCsv($sTools);
  119. $aValsToAdd['acl_levels'] = (int)$oForm->getCleanValue('acl_levels');
  120. $bIsValid = true;
  121. if($bIsValid) {
  122. if(($iId = $oForm->insert($aValsToAdd)) !== false) {
  123. $this->_oDb->cleanCache('sys_agents_with_alert');
  124. $aRes = ['grid' => $this->getCode(false), 'blink' => $iId];
  125. }
  126. else
  127. $aRes = ['msg' => _t('_sys_txt_error_occured')];
  128. return echoJson($aRes);
  129. }
  130. }
  131. $sFormId = $oForm->getId();
  132. $sContent = BxTemplStudioFunctions::getInstance()->popupBox($sFormId . '_popup', _t('_sys_agents_agents_popup_add'), $this->_oTemplate->parseHtmlByName('agents_agents_form.html', [
  133. 'form_id' => $sFormId,
  134. 'form' => $oForm->getCode(true),
  135. 'object' => $this->_sObject,
  136. 'action' => $sAction
  137. ]));
  138. return echoJson(['popup' => ['html' => $sContent, 'options' => ['closeOnOuterClick' => false]]]);
  139. }
  140. public function performActionEdit()
  141. {
  142. $sAction = 'edit';
  143. $oTemplate = BxDolStudioTemplate::getInstance();
  144. $oAI = BxDolAi::getInstance();
  145. $iId = $this->_getId();
  146. $aAgent = BxDolAiQuery::getAgentObject($iId);
  147. $aForm = $this->_getFormEdit($sAction, $aAgent);
  148. if ($this->_isUnaOperator($aAgent)) {
  149. foreach ([
  150. 'model_id' => $aAgent['model_id'],
  151. 'trigger' => $aAgent['trigger'],
  152. 'async' => $aAgent['async'],
  153. 'vector_store_id' => $aAgent['vector_store_id'],
  154. ] as $sField => $mixedValue)
  155. $aForm['inputs'][$sField]['attrs']['disabled'] = 'disabled';
  156. }
  157. $oForm = new BxTemplFormView($aForm);
  158. if ($oForm->isSubmitted() && $this->_isUnaOperator($aAgent)) {
  159. foreach ([
  160. 'model_id' => $aAgent['model_id'],
  161. 'trigger' => $aAgent['trigger'],
  162. 'async' => $aAgent['async'],
  163. 'vector_store_id' => $aAgent['vector_store_id'],
  164. ] as $sField => $mixedValue)
  165. BxDolForm::setSubmittedValue($sField, $mixedValue, $oForm->aFormAttrs['method']);
  166. }
  167. $oForm->initChecker();
  168. if ($oForm->isSubmitted() && $oForm->getCleanValue('trigger') == 'message') {
  169. $aAgent = $this->_getAgentWithProfile($oForm->getCleanValue('profile_id'), $iId);
  170. if ($aAgent) {
  171. $oForm->aInputs['profile_id']['error'] = _t('_sys_agents_form_field_err_profile_has_agent', $aAgent['name']);
  172. $oForm->setValid(false);
  173. }
  174. }
  175. if($oForm->isSubmittedAndValid()) {
  176. $aValsToAdd = [];
  177. $sName = $oForm->getCleanValue($this->_sFieldName);
  178. $sName = $this->_getUniqName($sName);
  179. BxDolForm::setSubmittedValue($this->_sFieldName, $sName, $oForm->aFormAttrs['method']);
  180. $iProfileId = $oForm->getCleanValue('profile_id');
  181. if(empty($iProfileId)) {
  182. $iProfileId = (int)getParam('sys_profile_bot');
  183. if(empty($iProfileId))
  184. $iProfileId = current(bx_srv('system', 'get_options_agents_profile', [false], 'TemplServices'))['key'];
  185. $aValsToAdd['profile_id'] = $iProfileId;
  186. }
  187. $iModel = $oForm->getCleanValue('model_id');
  188. $sTrigger = $oForm->getCleanValue('trigger');
  189. $sTools = is_array($oForm->getCleanValue('tools')) ? implode(',', $oForm->getCleanValue('tools')) : '';
  190. $aValsToAdd['tools'] = BxDolAiAgentTools::stripCsv($sTools);
  191. $aValsToAdd['acl_levels'] = (int)$oForm->getCleanValue('acl_levels');
  192. $bIsValid = true;
  193. if($bIsValid) {
  194. if(($iId = $oForm->update($iId, $aValsToAdd)) !== false) {
  195. $this->_oDb->cleanCache('sys_agents_with_alert');
  196. $aRes = ['grid' => $this->getCode(false), 'blink' => $iId];
  197. }
  198. else
  199. $aRes = ['msg' => _t('_sys_txt_error_occured')];
  200. return echoJson($aRes);
  201. }
  202. }
  203. $sFormId = $oForm->getId();
  204. $sContent = BxTemplStudioFunctions::getInstance()->popupBox($sFormId . '_popup', _t('_sys_agents_agents_popup_edit', $aAgent['name']), $this->_oTemplate->parseHtmlByName('agents_agents_form.html', [
  205. 'form_id' => $sFormId,
  206. 'form' => $oForm->getCode(true),
  207. 'object' => $this->_sObject,
  208. 'action' => $sAction
  209. ]));
  210. return echoJson(['popup' => ['html' => $sContent, 'options' => ['closeOnOuterClick' => false]]]);
  211. }
  212. public function performActionLogs()
  213. {
  214. $iId = $this->_getId();
  215. $aAgent = BxDolAiQuery::getAgentObject($iId);
  216. if (!$aAgent) {
  217. echoJson(['msg' => _t('_sys_txt_error_occured')]);
  218. return;
  219. }
  220. $oGrid = BxDolGrid::getObjectInstance('sys_studio_agents_logs');
  221. $oGrid->addMarkers(['agent_id' => $iId]);
  222. $oGrid->setBrowseParams(['agent_id' => $iId]);
  223. $sGrid = $oGrid->getCode();
  224. $sContent = BxTemplStudioFunctions::getInstance()->popupBox('popup_files_' . $iId, _t('_sys_agents_logs_popup', $aAgent['name']), $this->_oTemplate->parseHtmlByName('agents_popup_grid.html', [
  225. 'grid' => $sGrid,
  226. ]));
  227. return echoJson(['popup' => ['html' => $sContent, 'options' => ['closeOnOuterClick' => false]]]);
  228. }
  229. public function performActionMessage()
  230. {
  231. $iId = $this->_getId();
  232. $aAgent = BxDolAiQuery::getAgentObject($iId);
  233. if (!$aAgent) {
  234. echoJson(['msg' => _t('_sys_txt_error_occured')]);
  235. return;
  236. }
  237. if (!$aAgent['active']) {
  238. echoJson(['msg' => _t('_sys_txt_agent_inactive')]);
  239. return;
  240. }
  241. $sChatId = 'bx-ai-chat-' . $iId;
  242. $sName = !empty($aAgent['title']) ? $aAgent['title'] : $aAgent['name'];
  243. $aThreadsTpl = [];
  244. $oChat = BxDolAiChat::getInstance();
  245. $aThreads = $oChat->listAgentChatThreads($aAgent);
  246. foreach ($aThreads as $aThread) {
  247. $aThreadsTpl[] = [
  248. 'thread_id' => bx_html_attribute($aThread['thread_id']),
  249. 'writable' => (int)$aThread['writable'],
  250. 'context_pid' => (int)$aThread['context_pid'],
  251. 'title' => bx_process_output($aThread['title']),
  252. 'meta' => bx_process_output($aThread['meta']),
  253. 'class_mine' => $aThread['class_mine'],
  254. ];
  255. }
  256. $sContent = BxTemplStudioFunctions::getInstance()->popupBox('popup_agent_chat_' . $iId, _t('_sys_agents_agents_popup_message', $sName), $this->_oTemplate->parseHtmlByName('agents_popup_chat.html', [
  257. 'chat_id' => $sChatId,
  258. 'agent_id' => (int)$iId,
  259. 'txt_readonly' => _t('_sys_agents_agents_txt_readonly'),
  260. 'txt_chats' => _t('_sys_agents_agents_txt_chats'),
  261. 'txt_search' => bx_html_attribute(_t('_sys_agents_agents_txt_search')),
  262. 'txt_search_empty' => _t('_sys_agents_agents_txt_search_empty'),
  263. 'bx_repeat:threads' => $aThreadsTpl,
  264. ]));
  265. $aThreadsJs = [];
  266. foreach ($aThreads as $aThread)
  267. $aThreadsJs[] = $this->_agentChatThreadJs($aThread);
  268. $sThreadsJson = json_encode($aThreadsJs, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
  269. if ($sThreadsJson === false)
  270. $sThreadsJson = '[]';
  271. $sJsObject = $this->getPageJsObject();
  272. return echoJson(['popup' => [
  273. 'html' => $sContent,
  274. 'options' => [
  275. 'closeOnOuterClick' => false,
  276. 'onShow' => $sJsObject . ".initAgentChat('#" . $sChatId . "', " . (int)$iId . ", " . $sThreadsJson . ");",
  277. 'onHide' => $sJsObject . ".destroyAgentChat();",
  278. ]
  279. ]]);
  280. }
  281. public function performActionGetChatThreads()
  282. {
  283. $iId = $this->_getId();
  284. $aAgent = BxDolAiQuery::getAgentObject($iId);
  285. if (!$aAgent) {
  286. echoJson(['code' => 404, 'threads' => []]);
  287. return;
  288. }
  289. $aThreadsJs = [];
  290. $aThreads = BxDolAiChat::getInstance()->listAgentChatThreads($aAgent);
  291. foreach ($aThreads as $aThread)
  292. $aThreadsJs[] = $this->_agentChatThreadJs($aThread);
  293. echoJson(['code' => 200, 'threads' => $aThreadsJs]);
  294. }
  295. public function performActionGetChatThread()
  296. {
  297. $iId = $this->_getId();
  298. $aAgent = BxDolAiQuery::getAgentObject($iId);
  299. if (!$aAgent) {
  300. echoJson(['code' => 404, 'msg' => _t('_sys_txt_error_occured'), 'messages' => []]);
  301. return;
  302. }
  303. $sThreadId = trim((string)bx_get('thread_id'));
  304. $oChat = BxDolAiChat::getInstance();
  305. $aMessages = $oChat->getChatHistoryUiMessagesByThread($aAgent, $sThreadId);
  306. if ($aMessages === false) {
  307. echoJson(['code' => 404, 'msg' => _t('_sys_txt_error_occured'), 'messages' => []]);
  308. return;
  309. }
  310. echoJson([
  311. 'code' => 200,
  312. 'messages' => $aMessages,
  313. 'writable' => $oChat->isOwnAgentChatThread($aAgent, $sThreadId) ? 1 : 0,
  314. 'artifacts' => $oChat->getChatHistoryArtifactsByThread($aAgent, $sThreadId),
  315. ]);
  316. }
  317. protected function _agentChatThreadJs($aThread)
  318. {
  319. $aArtifacts = [];
  320. if (!empty($aThread['artifacts']) && is_array($aThread['artifacts'])) {
  321. foreach ($aThread['artifacts'] as $aItem) {
  322. if (!is_array($aItem))
  323. continue;
  324. $aArtifacts[] = [
  325. 'field_name' => (string)($aItem['field_name'] ?? ''),
  326. 'field_value' => (string)($aItem['field_value'] ?? ''),
  327. ];
  328. }
  329. }
  330. return [
  331. 'thread_id' => (string)$aThread['thread_id'],
  332. 'writable' => (int)$aThread['writable'],
  333. 'context_pid' => (int)$aThread['context_pid'],
  334. 'title' => (string)$aThread['title'],
  335. 'meta' => (string)$aThread['meta'],
  336. 'status' => (string)($aThread['status'] ?? 'opened'),
  337. 'created_at' => (string)($aThread['created_at'] ?? ''),
  338. 'updated_at' => (string)($aThread['updated_at'] ?? ''),
  339. 'artifacts' => $aArtifacts,
  340. 'messages' => (!empty($aThread['messages']) && is_array($aThread['messages'])) ? array_values($aThread['messages']) : [],
  341. ];
  342. }
  343. protected function _getCellProfileId($mixedValue, $sKey, $aField, $aRow)
  344. {
  345. $mixedValue = BxDolProfile::getInstanceMagic($mixedValue)->getUnit(0, ['template' => 'unit_wo_info']);
  346. return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
  347. }
  348. protected function _getCellIcon($mixedValue, $sKey, $aField, $aRow)
  349. {
  350. $sIcon = '';
  351. if($mixedValue) {
  352. list($sIcon, $sIconUrl, $sIconA, $sIconHtml, $sIconFontWithHtml) = $this->_oTemplate->getTemplateFunctions()->getIcon($mixedValue, ['class' => 'sys-colored']);
  353. if($sIcon)
  354. $sIcon = $this->_oTemplate->parseIcon(BxDolIconset::getObjectInstance()->getIcon($sIcon));
  355. else if($sIconHtml)
  356. $sIcon = $sIconHtml;
  357. else if($sIconUrl)
  358. $sIcon = '<img src="' . bx_html_attribute($sIconUrl) . '" />';
  359. else if($sIconFontWithHtml)
  360. $sIcon = $sIconFontWithHtml;
  361. }
  362. if (!$sIcon)
  363. $sIcon = '<i class="sys-icon robot"></i>';
  364. return parent::_getCellDefault($sIcon, $sKey, $aField, $aRow);
  365. }
  366. protected function _getCellModelId($mixedValue, $sKey, $aField, $aRow)
  367. {
  368. $aModel = $this->_oDb->getModelsBy(['sample' => 'id', 'id' => $mixedValue]);
  369. if(!empty($aModel) && is_array($aModel)) {
  370. $mixedValue = $aModel['icon'];
  371. if (strpos($mixedValue, '.svg') !== false)
  372. $mixedValue = $this->_oTemplate->getIconContent($mixedValue);
  373. } else {
  374. $mixedValue = '';
  375. }
  376. return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
  377. }
  378. protected function _getCellTrigger($mixedValue, $sKey, $aField, $aRow)
  379. {
  380. $mixedValue = $this->_oTemplate->getIconContent('agt-trg-' . $mixedValue . '.svg');
  381. return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
  382. }
  383. protected function _getCellName($mixedValue, $sKey, $aField, $aRow)
  384. {
  385. if (!empty($aRow['title']))
  386. $mixedValue = $aRow['title'];
  387. return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
  388. }
  389. protected function _delete ($mixedId)
  390. {
  391. $aAgent = $this->_getAgentObjectById((int)$mixedId);
  392. if ($this->_isUnaOperator($aAgent))
  393. return false;
  394. $mixedResult = parent::_delete($mixedId);
  395. $this->_oDb->cleanCache('sys_agents_with_alert');
  396. if ($mixedResult)
  397. BxDolAiActivity::deleteForAgent((int)$mixedId);
  398. return $mixedResult;
  399. }
  400. protected function _getAgentObjectById($iId)
  401. {
  402. return BxDolAiQuery::getAgentObject((int)$iId);
  403. }
  404. protected function _isUnaOperator($aAgent)
  405. {
  406. return is_array($aAgent) && ($aAgent['name'] ?? '') === 'una_operator';
  407. }
  408. protected function _getActionDelete($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = [])
  409. {
  410. if ($this->_isUnaOperator($aRow))
  411. return '';
  412. return parent::_getActionDefault($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
  413. }
  414. protected function _getFormEdit($sAction, $aAgent = [])
  415. {
  416. $aForm = $this->_getForm($sAction, $aAgent);
  417. $aForm['form_attrs']['action'] .= '&id=' . $aAgent['id'];
  418. unset($aForm['inputs']['name']);
  419. return $aForm;
  420. }
  421. protected function _getForm($sAction, $aAgent = [])
  422. {
  423. $sJsObject = $this->getPageJsObject();
  424. $aForm = array(
  425. 'form_attrs' => array(
  426. 'id' => 'bx_std_agents_' . $sAction,
  427. 'action' => BX_DOL_URL_ROOT . 'grid.php?o=sys_studio_agents_agents&a=' . $sAction,
  428. 'method' => 'post',
  429. ),
  430. 'params' => array (
  431. 'db' => array(
  432. 'table' => 'sys_agents_agents',
  433. 'key' => 'id',
  434. 'submit_name' => 'do_submit',
  435. ),
  436. ),
  437. 'inputs' => array(
  438. 'title' => [
  439. 'type' => 'text',
  440. 'name' => 'title',
  441. 'caption' => _t('_sys_agents_field_title'),
  442. 'info' => _t('_sys_agents_field_title_info'),
  443. 'value' => $aAgent['title'] ?? '',
  444. 'required' => '1',
  445. 'checker' => [
  446. 'func' => 'Avail',
  447. 'error' => _t('_sys_agents_form_field_err_enter'),
  448. ],
  449. 'db' => [
  450. 'pass' => 'Xss',
  451. ],
  452. ],
  453. 'name' => [
  454. 'type' => 'text',
  455. 'name' => 'name',
  456. 'caption' => _t('_sys_agents_field_name'),
  457. 'info' => _t('_sys_agents_field_name_info'),
  458. 'value' => isset($aAgent['name']) ? $aAgent['name'] : '',
  459. 'required' => '1',
  460. 'checker' => [
  461. 'func' => 'Avail',
  462. 'error' => _t('_sys_agents_form_field_err_enter'),
  463. ],
  464. 'db' => [
  465. 'pass' => 'Xss',
  466. ],
  467. ],
  468. 'description' => [
  469. 'type' => 'textarea',
  470. 'name' => 'description',
  471. 'caption' => _t('_sys_agents_field_description'),
  472. 'info' => _t('_sys_agents_field_description_info'),
  473. 'value' => $aAgent['description'] ?? '',
  474. 'db' => [
  475. 'pass' => 'Xss',
  476. ],
  477. ],
  478. 'icon' => [
  479. 'type' => 'textarea',
  480. 'name' => 'icon',
  481. 'caption' => _t('_sys_agents_field_icon'),
  482. 'info' => _t('_sys_agents_field_icon_info'),
  483. 'value' => $aAgent['icon'] ?? '',
  484. 'code' => 1,
  485. 'db' => [
  486. 'pass' => 'Xss',
  487. ],
  488. ],
  489. 'model_id' => [
  490. 'type' => 'select',
  491. 'name' => 'model_id',
  492. 'caption' => _t('_sys_agents_field_model_id'),
  493. 'info' => _t('_sys_agents_field_model_id_info'),
  494. 'value' => isset($aAgent['model_id']) ? $aAgent['model_id'] : 0,
  495. 'values' => $this->_getModelSelectValues(),
  496. 'required' => '1',
  497. 'checker' => [
  498. 'func' => 'Avail',
  499. 'error' => _t('_sys_agents_form_field_err_select'),
  500. ],
  501. 'db' => [
  502. 'pass' => 'Int',
  503. ],
  504. ],
  505. 'profile_id' => [
  506. 'type' => 'select',
  507. 'name' => 'profile_id',
  508. 'caption' => _t('_sys_agents_field_profile_id'),
  509. 'info' => _t('_sys_agents_field_profile_id_inf'),
  510. 'value' => isset($aAgent['profile_id']) ? $aAgent['profile_id'] : 0,
  511. 'values' => $this->_getProfileSelectValues(),
  512. 'required' => '1',
  513. 'required' => '1',
  514. 'checker' => [
  515. 'func' => 'Avail',
  516. 'error' => _t('_sys_agents_form_field_err_select'),
  517. ],
  518. 'db' => [
  519. 'pass' => 'Int',
  520. ]
  521. ],
  522. 'acl_levels' => [
  523. 'type' => 'checkbox_set',
  524. 'name' => 'acl_levels',
  525. 'caption' => _t('_sys_agents_field_acl_levels'),
  526. 'info' => _t('_sys_agents_field_acl_levels_info'),
  527. 'value' => [],
  528. 'values' => [],
  529. 'db' => [
  530. 'pass' => 'Set',
  531. ]
  532. ],
  533. 'trigger' => [
  534. 'type' => 'select',
  535. 'name' => 'trigger',
  536. 'caption' => _t('_sys_agents_field_trigger'),
  537. 'info' => _t('_sys_agents_field_trigger_info'),
  538. 'value' => isset($aAgent['trigger']) ? $aAgent['trigger'] : 0,
  539. 'values' => [
  540. 'alert' => _t('_sys_agents_field_trigger_alert'),
  541. 'scheduler' => _t('_sys_agents_field_trigger_scheduler'),
  542. 'webhook' => _t('_sys_agents_field_trigger_webhook'),
  543. 'manual' => _t('_sys_agents_field_trigger_manual'),
  544. 'agent' => _t('_sys_agents_field_trigger_agent'),
  545. 'message' => _t('_sys_agents_field_trigger_message'),
  546. 'form-input' => _t('_sys_agents_field_trigger_form_input'),
  547. ],
  548. // 'attrs' => [
  549. // 'onchange' => $this->getPageJsObject() . '.onChangeAgentTrigger(this)',
  550. // ],
  551. 'required' => '1',
  552. 'db' => [
  553. 'pass' => 'Xss',
  554. ]
  555. ],
  556. 'async' => [
  557. 'type' => 'checkbox',
  558. 'name' => 'async',
  559. 'caption' => _t('_sys_agents_field_async'),
  560. 'info' => _t('_sys_agents_field_async_inf'),
  561. 'value' => 1,
  562. 'checked' => isset($aAgent['async']) ? $aAgent['async'] : 0,
  563. 'db' => [
  564. 'pass' => 'Int',
  565. ]
  566. ],
  567. 'alert_section' => [
  568. 'type' => 'block_header',
  569. 'caption' => _t('_sys_agents_block_header_alert'),
  570. 'collapsable' => true,
  571. 'collapsed' => true,
  572. ],
  573. 'alert_sample' => [
  574. 'type' => 'custom',
  575. 'name' => 'alert_sample',
  576. 'caption' => _t('_sys_agents_field_alert_sample'),
  577. 'content' => $this->_oTemplate->parseHtmlByName('agents_agents_alerts_payload.html', [
  578. 'text-visibility' => empty($aAgent['alert']) ? 'block' : 'none',
  579. 'text' => _t('_sys_agents_waiting_for_sample_data_alert'),
  580. 'payload-visibility' => !empty($aAgent['alert']) ? 'block' : 'none',
  581. 'desc' => $aAgent ? $this->_oDb->getAlertDesc($aAgent['alert']) : '',
  582. 'payload' => !empty($aAgent['alert']) ? json_encode($this->_getAlertPayload($aAgent['alert']), JSON_PRETTY_PRINT) : '',
  583. ]),
  584. ],
  585. 'alert' => [
  586. 'type' => 'custom',
  587. 'name' => 'alert',
  588. 'caption' => _t('_sys_agents_field_alert'),
  589. 'info' => _t('_sys_agents_field_alert_info'),
  590. 'content' => $this->_oTemplate->parseHtmlByName('agents_agents_alerts_select.html', $this->_getAlertValues(isset($aAgent['alert']) ? $aAgent['alert'] : '')),
  591. 'db' => [
  592. 'pass' => 'Xss',
  593. ],
  594. ],
  595. 'alert_section_end' => [
  596. 'type' => 'block_end',
  597. ],
  598. 'scheduler_section' => [
  599. 'type' => 'block_header',
  600. 'caption' => _t('_sys_agents_block_header_scheduler'),
  601. 'collapsable' => true,
  602. 'collapsed' => true,
  603. ],
  604. 'scheduler_cron' => [
  605. 'type' => 'text',
  606. 'name' => 'scheduler_cron',
  607. 'caption' => _t('_sys_agents_field_scheduler_cron'),
  608. 'info' => _t('_sys_agents_field_scheduler_cron_info'),
  609. 'value' => isset($aAgent['scheduler_cron']) ? $aAgent['scheduler_cron'] : '',
  610. 'db' => [
  611. 'pass' => 'Xss',
  612. ],
  613. ],
  614. 'scheduler_section_end' => [
  615. 'type' => 'block_end',
  616. ],
  617. 'webhook_section' => [
  618. 'type' => 'block_header',
  619. 'caption' => _t('_sys_agents_block_header_webhook'),
  620. 'collapsable' => true,
  621. 'collapsed' => true,
  622. ],
  623. 'webhook_sample' => [
  624. 'type' => 'custom',
  625. 'name' => 'webhook_sample',
  626. 'caption' => _t('_sys_agents_field_webhook_sample'),
  627. 'content' => isset($aAgent['webhook_sample']) ? $aAgent['webhook_sample'] : _t('_sys_agents_waiting_for_sample_data_webhook'),
  628. ],
  629. 'webhook_key' => [
  630. 'type' => 'text',
  631. 'name' => 'webhook_key',
  632. 'caption' => _t('_sys_agents_field_webhook_key'),
  633. 'info' => _t('_sys_agents_field_webhook_key_info'),
  634. 'value' => isset($aAgent['webhook_key']) ? $aAgent['webhook_key'] : '',
  635. 'db' => [
  636. 'pass' => 'Xss',
  637. ],
  638. ],
  639. 'webhook_section_end' => [
  640. 'type' => 'block_end',
  641. ],
  642. 'message_section' => [
  643. 'type' => 'block_header',
  644. 'caption' => _t('_sys_agents_block_header_message'),
  645. 'collapsable' => true,
  646. 'collapsed' => true,
  647. ],
  648. 'message_profile_id' => [
  649. 'type' => 'select',
  650. 'name' => 'message_profile_id',
  651. 'caption' => _t('_sys_agents_field_message_profile'),
  652. 'info' => _t('_sys_agents_field_message_profile_info'),
  653. 'value' => isset($aAgent['message_profile_id']) ? $aAgent['message_profile_id'] : '',
  654. 'values' => $this->_getProfileSelectValues(true, '_adm_nav_txt_items_visible_for_all'),
  655. 'db' => [
  656. 'pass' => 'Xss',
  657. ],
  658. ],
  659. 'message_section_end' => [
  660. 'type' => 'block_end',
  661. ],
  662. 'form_field_section' => [
  663. 'type' => 'block_header',
  664. 'caption' => _t('_sys_agents_block_header_form_input'),
  665. 'collapsable' => true,
  666. 'collapsed' => true,
  667. ],
  668. 'form_object' => [
  669. 'type' => 'custom',
  670. 'name' => 'form_object',
  671. 'caption' => _t('_sys_agents_form_object'),
  672. 'info' => _t('_sys_agents_form_object_info'),
  673. 'content' => $this->_oTemplate->parseHtmlByName('agents_agents_form_object_select.html', $this->_getFormObjectValues(isset($aAgent['form_object']) ? $aAgent['form_object'] : '')),
  674. 'db' => [
  675. 'pass' => 'Xss',
  676. ],
  677. ],
  678. 'form_input' => [
  679. 'type' => 'custom',
  680. 'name' => 'form_input',
  681. 'caption' => _t('_sys_agents_form_input'),
  682. 'info' => _t('_sys_agents_form_input_info'),
  683. 'content' => $this->_oTemplate->parseHtmlByName('agents_agents_form_input_select.html', $this->_getFormInputValues(isset($aAgent['form_object']) ? $aAgent['form_object'] : '', isset($aAgent['form_input']) ? $aAgent['form_input'] : '')),
  684. 'db' => [
  685. 'pass' => 'Xss',
  686. ],
  687. ],
  688. 'form_field_section_end' => array(
  689. 'type' => 'block_end',
  690. ),
  691. 'manual_section' => [
  692. 'type' => 'block_header',
  693. 'caption' => _t('_sys_agents_block_header_manual'),
  694. 'collapsable' => true,
  695. 'collapsed' => true,
  696. ],
  697. 'max_turns' => [
  698. 'type' => 'text',
  699. 'name' => 'max_turns',
  700. 'caption' => _t('_sys_agents_field_manual_max_turns'),
  701. 'info' => _t('_sys_agents_field_manual_max_turns_info'),
  702. 'value' => $aAgent['max_turns'] ?? 0,
  703. 'required' => '1',
  704. 'db' => [
  705. 'pass' => 'Int',
  706. ],
  707. ],
  708. 'chat_ttl_min' => [
  709. 'type' => 'text',
  710. 'name' => 'chat_ttl_min',
  711. 'caption' => _t('_sys_agents_field_manual_chat_ttl_min'),
  712. 'info' => _t('_sys_agents_field_manual_chat_ttl_min_info'),
  713. 'value' => $aAgent['chat_ttl_min'] ?? 0,
  714. 'required' => '1',
  715. 'db' => [
  716. 'pass' => 'Int',
  717. ],
  718. ],
  719. 'limit_message' => [
  720. 'type' => 'textarea',
  721. 'name' => 'limit_message',
  722. 'caption' => _t('_sys_agents_field_manual_limit_message'),
  723. 'info' => _t('_sys_agents_field_manual_limit_message_info'),
  724. 'value' => $aAgent['limit_message'] ?? '',
  725. 'db' => [
  726. 'pass' => 'Xss',
  727. ],
  728. ],
  729. 'max_input_chars' => [
  730. 'type' => 'text',
  731. 'name' => 'max_input_chars',
  732. 'caption' => _t('_sys_agents_field_manual_max_input_chars'),
  733. 'info' => _t('_sys_agents_field_manual_max_input_chars_info'),
  734. 'value' => $aAgent['max_input_chars'] ?? 0,
  735. 'required' => '1',
  736. 'db' => [
  737. 'pass' => 'Int',
  738. ],
  739. ],
  740. 'max_tokens' => [
  741. 'type' => 'text',
  742. 'name' => 'max_tokens',
  743. 'caption' => _t('_sys_agents_field_manual_max_tokens'),
  744. 'info' => _t('_sys_agents_field_manual_max_tokens_info'),
  745. 'value' => $aAgent['max_tokens'] ?? 0,
  746. 'required' => '1',
  747. 'db' => [
  748. 'pass' => 'Int',
  749. ],
  750. ],
  751. 'max_sessions_per_hour' => [
  752. 'type' => 'text',
  753. 'name' => 'max_sessions_per_hour',
  754. 'caption' => _t('_sys_agents_field_manual_max_sessions_per_hour'),
  755. 'info' => _t('_sys_agents_field_manual_max_sessions_per_hour_info'),
  756. 'value' => $aAgent['max_sessions_per_hour'] ?? 3,
  757. 'required' => '1',
  758. 'db' => [
  759. 'pass' => 'Int',
  760. ],
  761. ],
  762. 'max_sessions_per_day' => [
  763. 'type' => 'text',
  764. 'name' => 'max_sessions_per_day',
  765. 'caption' => _t('_sys_agents_field_manual_max_sessions_per_day'),
  766. 'info' => _t('_sys_agents_field_manual_max_sessions_per_day_info'),
  767. 'value' => $aAgent['max_sessions_per_day'] ?? 10,
  768. 'required' => '1',
  769. 'db' => [
  770. 'pass' => 'Int',
  771. ],
  772. ],
  773. 'hidden_first_message' => [
  774. 'type' => 'text',
  775. 'name' => 'hidden_first_message',
  776. 'caption' => _t('_sys_agents_field_manual_hidden_first_message'),
  777. 'info' => _t('_sys_agents_field_manual_hidden_first_message_info'),
  778. 'value' => $aAgent['hidden_first_message'] ?? '',
  779. 'attrs' => ['maxlength' => 64],
  780. 'db' => [
  781. 'pass' => 'Xss',
  782. ],
  783. ],
  784. 'manual_section_end' => [
  785. 'type' => 'block_end',
  786. ],
  787. 'vector_store_id' => [
  788. 'type' => 'select',
  789. 'name' => 'vector_store_id',
  790. 'caption' => _t('_sys_agents_field_vector_store_id'),
  791. 'info' => _t('_sys_agents_field_vector_store_id_info'),
  792. 'value' => isset($aAgent['vector_store_id']) ? $aAgent['vector_store_id'] : 0,
  793. 'values' => $this->_oDb->getVectorStores(),
  794. 'required' => '1',
  795. 'checker' => [
  796. 'func' => 'Avail',
  797. 'error' => _t('_sys_agents_form_field_err_select'),
  798. ],
  799. 'db' => [
  800. 'pass' => 'Xss',
  801. ],
  802. ],
  803. 'chat_history_context' => [
  804. 'type' => 'text',
  805. 'name' => 'chat_history_context',
  806. 'caption' => _t('_sys_agents_field_chat_history_context'),
  807. 'info' => _t('_sys_agents_field_chat_history_context_info'),
  808. 'value' => isset($aAgent['chat_history_context']) ? $aAgent['chat_history_context'] : 50000,
  809. 'db' => [
  810. 'pass' => 'Int',
  811. ],
  812. ],
  813. 'tools' => [
  814. 'type' => 'custom',
  815. 'name' => 'tools',
  816. 'caption' => _t('_sys_agents_field_tools'),
  817. 'info' => _t('_sys_agents_field_tools_info'),
  818. 'value' => '',
  819. ],
  820. 'tools_max_run' => [
  821. 'type' => 'text',
  822. 'name' => 'tools_max_run',
  823. 'caption' => _t('_sys_agents_field_tools_max_run'),
  824. 'info' => _t('_sys_agents_field_tools_max_run_info'),
  825. 'value' => isset($aAgent['tools_max_run']) ? $aAgent['tools_max_run'] : '10',
  826. 'required' => '1',
  827. 'db' => [
  828. 'pass' => 'Int',
  829. ],
  830. ],
  831. 'prompt_system' => [
  832. 'type' => 'textarea',
  833. 'name' => 'prompt_system',
  834. 'caption' => _t('_sys_agents_field_prompt_system'),
  835. 'info' => _t('_sys_agents_field_prompt_system_info'),
  836. 'value' => isset($aAgent['prompt_system']) ? $aAgent['prompt_system'] : '',
  837. 'db' => [
  838. 'pass' => 'Xss',
  839. ],
  840. ],
  841. 'prompts_section' => array(
  842. 'type' => 'block_header',
  843. 'caption' => 'Other prompts',
  844. 'collapsable' => true,
  845. 'collapsed' => true,
  846. ),
  847. 'prompt_steps' => [
  848. 'type' => 'textarea',
  849. 'name' => 'prompt_steps',
  850. 'caption' => _t('_sys_agents_field_prompt_steps'),
  851. 'info' => _t('_sys_agents_field_prompt_steps_info'),
  852. 'value' => isset($aAgent['prompt_steps']) ? $aAgent['prompt_steps'] : '',
  853. 'db' => [
  854. 'pass' => 'Xss',
  855. ],
  856. ],
  857. 'prompt_output' => [
  858. 'type' => 'textarea',
  859. 'name' => 'prompt_output',
  860. 'caption' => _t('_sys_agents_field_prompt_output'),
  861. 'info' => _t('_sys_agents_field_prompt_output_info'),
  862. 'value' => isset($aAgent['prompt_output']) ? $aAgent['prompt_output'] : '',
  863. 'db' => [
  864. 'pass' => 'Xss',
  865. ],
  866. ],
  867. 'prompt_tools' => [
  868. 'type' => 'textarea',
  869. 'name' => 'prompt_tools',
  870. 'caption' => _t('_sys_agents_field_prompt_tools'),
  871. 'info' => _t('_sys_agents_field_prompt_tools_info'),
  872. 'value' => isset($aAgent['prompt_tools']) ? $aAgent['prompt_tools'] : '',
  873. 'db' => [
  874. 'pass' => 'Xss',
  875. ],
  876. ],
  877. 'prompts_section_end' => array(
  878. 'type' => 'block_end',
  879. ),
  880. 'submit' => $this->_getFormControls(),
  881. ),
  882. );
  883. if(($sFldTitle = 'title') && ($sFldName = 'name') && isset($aForm['inputs'][$sFldTitle], $aForm['inputs'][$sFldName])) {
  884. $aMask = array('mask' => "javascript:%s.agentCheckName(this, '%s', '%s');", $sJsObject, 'title', 'name');
  885. if($sAction == 'edit' && ($iAgentId = $aAgent['id'] ?? false)) {
  886. $aMask['mask'] = "javascript:%s.agentCheckName(this, '%s', '%s', %d);";
  887. $aMask[] = (int)$iAgentId;
  888. }
  889. $sOnBlur = call_user_func_array('sprintf', array_values($aMask));
  890. $aForm['inputs'][$sFldTitle]['attrs']['onblur'] = $sOnBlur;
  891. $aForm['inputs'][$sFldName]['attrs']['onblur'] = $sOnBlur;
  892. }
  893. $this->_getMultiField('tools', $aAgent, 'getTools', 'toolAdd', 'agents_agents_form_tools.html', $aForm);
  894. BxDolStudioUtils::getVisibilityValues(0, $aForm['inputs']['acl_levels']['values'], $aForm['inputs']['acl_levels']['value']);
  895. $aForm['inputs']['acl_levels']['value'] = (int)($aAgent['acl_levels'] ?? 0);
  896. return $aForm;
  897. }
  898. protected function _getAlertPayload($s)
  899. {
  900. $aAlert = $this->_oDb->getAlert($s);
  901. if (!$aAlert)
  902. return '';
  903. return [
  904. 'object_id' => $aAlert['object'],
  905. 'sender_profile_id' => $aAlert['sender'],
  906. 'extra' => json_decode($aAlert['extra'], true),
  907. 'extra_modifiable_keys' => json_decode($aAlert['extra_refs'], true),
  908. ];
  909. }
  910. protected function _getAlertValues($sValue)
  911. {
  912. $aAlerts = $this->_oDb->getAlerts();
  913. $a = [
  914. 'sys_stat_not_available' => _t('_sys_not_available'),
  915. 'grid_object' => $this->_sObject,
  916. 'bx_repeat:alerts' => [
  917. [
  918. 'name' => _t('_sys_please_select'),
  919. 'value' => '',
  920. 'desc' => '',
  921. 'count' => 0,
  922. 'count_per_req' => 0,
  923. 'bx_if:sel' => [
  924. 'condition' => false,
  925. 'content' => ['sel' => '']
  926. ]
  927. ]
  928. ]
  929. ];
  930. foreach ($aAlerts as $k => $r) {
  931. $a['bx_repeat:alerts'][] = [
  932. 'name' => $r['name'],
  933. 'value' => $r['key'],
  934. 'desc' => bx_html_attribute($r['desc']),
  935. 'count' => bx_html_attribute(_t('_sys_agents_count_today', $r['counter_24h'])),
  936. 'count_per_req' => bx_html_attribute(_t('_sys_agents_count_per_req', $r['counter_per_request'])),
  937. 'bx_if:sel' => [
  938. 'condition' => $sValue == $r['key'],
  939. 'content' => [
  940. 'sel' => $sValue == $r['key'] ? 'selected' : '',
  941. ]
  942. ]
  943. ];
  944. }
  945. return $a;
  946. }
  947. protected function _getFormObjectValues($sValue)
  948. {
  949. $aFormObjects = $this->_oDb->getFormObjects();
  950. // add "Please select" option
  951. $a = [
  952. 'sys_stat_not_available' => _t('_sys_not_available'),
  953. 'grid_object' => $this->_sObject,
  954. 'bx_repeat:form_objects' => [
  955. [
  956. 'title' => _t('_sys_please_select'),
  957. 'title_attr' => _t('_sys_please_select'),
  958. 'value' => '',
  959. 'bx_if:sel' => [
  960. 'condition' => false,
  961. 'content' => ['sel' => '']
  962. ]
  963. ]
  964. ]
  965. ];
  966. // add form objects
  967. $bSelected = false;
  968. foreach ($aFormObjects as $k => $r) {
  969. if ($sValue == $r['form_object'])
  970. $bSelected = true;
  971. $a['bx_repeat:form_objects'][] = [
  972. 'title' => $r['module_title'] . ': ' . $r['form_title'],
  973. 'title_attr' => bx_html_attribute($r['module_title'] . ': ' . $r['form_title']),
  974. 'value' => $r['form_object'],
  975. // 'form_id' => $r['form_id'],
  976. // 'module' => $r['module'],
  977. // 'module_title' => $r['module_title'],
  978. // 'form_title' => $r['form_title'],
  979. 'bx_if:sel' => [
  980. 'condition' => $sValue == $r['form_object'],
  981. 'content' => ['sel' => $sValue == $r['form_object'] ? 'selected' : ''],
  982. ]
  983. ];
  984. }
  985. // add selected form object if not found in form objects
  986. if ($sValue && !$bSelected) {
  987. $a['bx_repeat:form_objects'][] = [
  988. 'title' => $sValue,
  989. 'title_attr' => bx_html_attribute($sValue),
  990. 'value' => $sValue,
  991. 'bx_if:sel' => [
  992. 'condition' => true,
  993. 'content' => ['sel' => 'selected'],
  994. ]
  995. ];
  996. }
  997. return $a;
  998. }
  999. protected function _getFormInputs($sFormObject)
  1000. {
  1001. $sDisplay = $this->_oDb->getFormDisplay($sFormObject);
  1002. $oForm = $sDisplay ? BxDolForm::getObjectInstance($sFormObject, $sDisplay) : null;
  1003. $aFormInputs = $oForm ? $oForm->aInputs : [];
  1004. if (!$aFormInputs)
  1005. return [];
  1006. $aRet = [];
  1007. foreach ($aFormInputs as $k => $r) {
  1008. if ($r['type'] == 'text' || $r['type'] == 'textarea') {
  1009. $aRet[$r['name']] = [
  1010. 'name' => $r['name'],
  1011. 'caption' => $r['caption'],
  1012. ];
  1013. }
  1014. }
  1015. return $aRet;
  1016. }
  1017. protected function _getFormInputValues($sFormObject, $sFormInput)
  1018. {
  1019. $aFormInputs = $this->_getFormInputs($sFormObject);
  1020. // add "Please select" option
  1021. $a = [
  1022. 'bx_repeat:form_inputs' => [
  1023. [
  1024. 'title' => _t('_sys_please_select'),
  1025. 'title_attr' => _t('_sys_please_select'),
  1026. 'value' => '',
  1027. 'bx_if:sel' => [
  1028. 'condition' => false,
  1029. 'content' => ['sel' => '']
  1030. ]
  1031. ]
  1032. ]
  1033. ];
  1034. // add form inputs
  1035. $bSelected = false;
  1036. if ($aFormInputs) {
  1037. foreach ($aFormInputs as $k => $r) {
  1038. if ($sFormInput == $r['name'])
  1039. $bSelected = true;
  1040. $a['bx_repeat:form_inputs'][] = [
  1041. 'title' => $r['name'] . ' - ' . $r['caption'],
  1042. 'title_attr' => bx_html_attribute($r['name'] . (!empty($r['caption']) ? ' - ' . $r['caption'] : '')),
  1043. 'value' => $r['name'],
  1044. 'bx_if:sel' => [
  1045. 'condition' => $sFormInput == $r['name'],
  1046. 'content' => [
  1047. 'sel' => $sFormInput == $r['name'] ? 'selected' : '',
  1048. ]
  1049. ]
  1050. ];
  1051. }
  1052. }
  1053. // add selected input if not found in form inputs
  1054. if ($sFormInput && !$bSelected) {
  1055. $a['bx_repeat:form_inputs'][] = [
  1056. 'title' => $sFormInput,
  1057. 'title_attr' => bx_html_attribute($sFormInput),
  1058. 'value' => $sFormInput,
  1059. 'bx_if:sel' => [
  1060. 'condition' => true,
  1061. 'content' => ['sel' => 'selected'],
  1062. ]
  1063. ];
  1064. }
  1065. return $a;
  1066. }
  1067. protected function _getUniqName($sName)
  1068. {
  1069. return uriGenerate($sName, 'sys_agents_agents', 'name', ['lowercase' => false]);
  1070. }
  1071. protected function _getMultiField($sField, $aAgent, $sGetValuesMethod, $sJsAddMethod, $sTemplateName, &$aForm)
  1072. {
  1073. if(!isset($aForm['inputs']['tools']))
  1074. return;
  1075. $sJsObject = $this->getPageJsObject();
  1076. $oForm = new BxTemplFormView([]);
  1077. $aValues = ['0' => _t('_sys_please_select')];
  1078. $a = $this->_oDb->$sGetValuesMethod();
  1079. foreach ($a as $k => $v) {
  1080. $aValues[$k] = $v;
  1081. }
  1082. $aHidden = $sField === 'tools' ? array_flip(BxDolAiAgentTools::hiddenIds()) : [];
  1083. $aTmplVars = [];
  1084. if(!empty($aAgent[$sField])) {
  1085. $a = explode(',', $aAgent[$sField]);
  1086. foreach($a as $v) {
  1087. if (isset($aHidden[(int)$v]))
  1088. continue;
  1089. $aInputSelect = [
  1090. 'type' => 'select',
  1091. 'name' => $sField . '[]',
  1092. 'values' => $aValues,
  1093. 'value' => $v,
  1094. 'attrs' => [
  1095. 'class' => 'bx-def-margin-sec-top-auto'
  1096. ]
  1097. ];
  1098. $sInput = $oForm->genInput($aInputSelect);
  1099. $aInputHidden = [
  1100. 'type' => 'hidden',
  1101. 'name' => $sField . '_ids[]',
  1102. 'value' => $v,
  1103. ];
  1104. $sInput .= $oForm->genInput($aInputHidden);
  1105. $aTmplVars[] = ['js_object' => $sJsObject, 'input_select' => $sInput];
  1106. }
  1107. }
  1108. if (!$aTmplVars) {
  1109. $aInputSelect = [
  1110. 'type' => 'select',
  1111. 'name' => $sField . '[]',
  1112. 'values' => $aValues,
  1113. 'value' => '',
  1114. 'attrs' => [
  1115. 'class' => 'bx-def-margin-sec-top-auto'
  1116. ]
  1117. ];
  1118. $aTmplVars = [
  1119. ['js_object' => $sJsObject, 'input_select' => $oForm->genInput($aInputSelect)],
  1120. ];
  1121. }
  1122. $aInputButton = [
  1123. 'type' => 'button',
  1124. 'name' => $sField . '_add',
  1125. 'value' => _t('_adm_nav_btn_items_add'),
  1126. 'attrs' => [
  1127. 'class' => 'bx-def-margin-sec-top',
  1128. 'onclick' => $sJsObject . ".$sJsAddMethod(this, '" . $sField . "');"
  1129. ]
  1130. ];
  1131. $aForm['inputs'][$sField]['content'] = $this->_oTemplate->parseHtmlByName($sTemplateName, [
  1132. "bx_repeat:$sField" => $aTmplVars,
  1133. 'btn_add' => $oForm->genInputButton($aInputButton)
  1134. ]);
  1135. }
  1136. protected function _getActionManual ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
  1137. {
  1138. if ($aRow['trigger'] != 'manual' && $aRow['trigger'] != 'scheduler')
  1139. return '';
  1140. return parent::_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
  1141. }
  1142. /**
  1143. * Chat history only makes sense for agents people talk to; event agents get "activity" instead.
  1144. */
  1145. protected function _getActionMessage ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
  1146. {
  1147. if (!in_array($aRow['trigger'], ['manual', 'message'], true))
  1148. return '';
  1149. return parent::_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
  1150. }
  1151. protected function _getActionActivity ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
  1152. {
  1153. if (in_array($aRow['trigger'], ['manual', 'message'], true))
  1154. return '';
  1155. return parent::_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
  1156. }
  1157. /**
  1158. * What an event-driven agent did: BxDolAiActivity rows, newest first.
  1159. */
  1160. public function performActionActivity()
  1161. {
  1162. $iId = $this->_getId();
  1163. $aAgent = BxDolAiQuery::getAgentObject($iId);
  1164. if (!$aAgent) {
  1165. echoJson(['msg' => _t('_sys_txt_error_occured')]);
  1166. return;
  1167. }
  1168. $aItems = BxDolAiActivity::listForAgent($iId, 0, 200);
  1169. $sTitle = _t('_sys_agents_agents_popup_activity', !empty($aAgent['title']) ? $aAgent['title'] : $aAgent['name']);
  1170. if (strpos($sTitle, '_sys_agents_agents_popup_activity') === 0)
  1171. $sTitle = 'Activity of "' . (!empty($aAgent['title']) ? $aAgent['title'] : $aAgent['name']) . '"';
  1172. $sEmpty = _t('_sys_agents_agents_txt_activity_empty');
  1173. if ($sEmpty === '_sys_agents_agents_txt_activity_empty')
  1174. $sEmpty = 'Nothing yet';
  1175. $sRows = '';
  1176. foreach ($aItems as $aItem) {
  1177. $sText = bx_process_output($aItem['text']);
  1178. if ($aItem['url'] !== '')
  1179. $sText = '<a href="' . bx_html_attribute($aItem['url']) . '" target="_blank">' . $sText . '</a>';
  1180. $sSummary = $aItem['summary'] !== '' ? '<div class="bx-def-font-small" style="opacity:.75;">' . bx_process_output($aItem['summary']) . '</div>' : '';
  1181. $sRows .= '<div class="bx-def-padding-sec-tb" style="border-bottom:1px solid rgba(127,127,127,.2);' . ($aItem['ok'] ? '' : 'color:#c0392b;') . '">'
  1182. . '<div style="display:flex;gap:1rem;justify-content:space-between;">'
  1183. . '<div>' . $sText . '</div>'
  1184. . '<div class="bx-def-font-small" style="white-space:nowrap;opacity:.6;">' . bx_process_output($aItem['added_formatted']) . '</div>'
  1185. . '</div>'
  1186. . $sSummary
  1187. . '</div>';
  1188. }
  1189. if ($sRows === '')
  1190. $sRows = '<div class="bx-def-padding" style="opacity:.6;">' . bx_process_output($sEmpty) . '</div>';
  1191. $sContent = BxTemplStudioFunctions::getInstance()->popupBox('popup_agent_activity_' . $iId, $sTitle,
  1192. '<div class="bx-agents-popup-activity" style="max-height:70vh;overflow:auto;min-width:40rem;">' . $sRows . '</div>'
  1193. );
  1194. echoJson(['popup' => ['html' => $sContent, 'options' => ['closeOnOuterClick' => false]]]);
  1195. }
  1196. protected function _getAgentWithProfile($iProfileId, $iExcludeAgentId = 0)
  1197. {
  1198. $aAgents = BxDolAi::getInstance()->getAgentsByProfileId($iProfileId);
  1199. foreach($aAgents as $aAgent) {
  1200. if($aAgent['id'] != $iExcludeAgentId)
  1201. return $aAgent;
  1202. }
  1203. return null;
  1204. }
  1205. protected function _getModelSelectValues()
  1206. {
  1207. $aParams = ['sample' => 'all_pairs', 'active' => 1];
  1208. $aModels = $this->_oDb->getModelsBy(array_merge($aParams, ['capabilities' => ['chatvlm', 'chatllm']]));
  1209. if(!$aModels || !is_array($aModels))
  1210. $aModels = $this->_oDb->getModelsBy($aParams);
  1211. return ($aModels && is_array($aModels)) ? $aModels : [];
  1212. }
  1213. protected function _getProfileSelectValues($bSelectOne = true, $sSelectOneLangKey = '_Select_one')
  1214. {
  1215. $aProfiles = bx_srv('system', 'get_options_agents_profile', [$bSelectOne, $sSelectOneLangKey], 'TemplServices');
  1216. if($aProfiles && is_array($aProfiles))
  1217. return $aProfiles;
  1218. $aProfiles = bx_srv('system', 'get_options_profile_bot', [], 'TemplServices');
  1219. return ($aProfiles && is_array($aProfiles)) ? $aProfiles : [];
  1220. }
  1221. protected function _addJsCss()
  1222. {
  1223. parent::_addJsCss();
  1224. $this->_oTemplate->addJs(['select2/js/select2.min.js']);
  1225. $this->_oTemplate->addCss([BX_DIRECTORY_PATH_PLUGINS_PUBLIC . 'select2/css/|select2.min.css']);
  1226. }
  1227. }
  1228. /** @} */