Просмотр исходного кода

Studio Agents: protect UNA proxy records (#5914)

Aleksandr Trofimov 4 дней назад
Родитель
Сommit
abaeefecd2

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

@@ -174,11 +174,30 @@ class BxBaseStudioAgentsAgents extends BxDolStudioAgentsAgents
         $oAI = BxDolAi::getInstance();
         $oAI = BxDolAi::getInstance();
 
 
         $iId = $this->_getId();
         $iId = $this->_getId();
-        $aAgent = BxDolAiQuery::getAgentObject($iId);
-
-        $aForm = $this->_getFormEdit($sAction, $aAgent);
-        $oForm = new BxTemplFormView($aForm);
-        $oForm->initChecker();
+        $aAgent = BxDolAiQuery::getAgentObject($iId);
+
+        $aForm = $this->_getFormEdit($sAction, $aAgent);
+        if ($this->_isUnaOperator($aAgent)) {
+            foreach ([
+                'model_id' => $aAgent['model_id'],
+                'trigger' => $aAgent['trigger'],
+                'async' => $aAgent['async'],
+                'vector_store_id' => $aAgent['vector_store_id'],
+            ] as $sField => $mixedValue)
+                $aForm['inputs'][$sField]['attrs']['disabled'] = 'disabled';
+        }
+
+        $oForm = new BxTemplFormView($aForm);
+        if ($oForm->isSubmitted() && $this->_isUnaOperator($aAgent)) {
+            foreach ([
+                'model_id' => $aAgent['model_id'],
+                'trigger' => $aAgent['trigger'],
+                'async' => $aAgent['async'],
+                'vector_store_id' => $aAgent['vector_store_id'],
+            ] as $sField => $mixedValue)
+                BxDolForm::setSubmittedValue($sField, $mixedValue, $oForm->aFormAttrs['method']);
+        }
+        $oForm->initChecker();
 
 
         if ($oForm->isSubmitted() && $oForm->getCleanValue('trigger') == 'message') {
         if ($oForm->isSubmitted() && $oForm->getCleanValue('trigger') == 'message') {
             $aAgent = $this->_getAgentWithProfile($oForm->getCleanValue('profile_id'), $iId);
             $aAgent = $this->_getAgentWithProfile($oForm->getCleanValue('profile_id'), $iId);
@@ -440,15 +459,37 @@ class BxBaseStudioAgentsAgents extends BxDolStudioAgentsAgents
         return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
         return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
     }
     }
     
     
-    protected function _delete ($mixedId)
-    {
-        $mixedResult = parent::_delete($mixedId);
-        $this->_oDb->cleanCache('sys_agents_with_alert');
-        if ($mixedResult)
+    protected function _delete ($mixedId)
+    {
+        $aAgent = $this->_getAgentObjectById((int)$mixedId);
+        if ($this->_isUnaOperator($aAgent))
+            return false;
+
+        $mixedResult = parent::_delete($mixedId);
+        $this->_oDb->cleanCache('sys_agents_with_alert');
+        if ($mixedResult)
             BxDolAiActivity::deleteForAgent((int)$mixedId);
             BxDolAiActivity::deleteForAgent((int)$mixedId);
 
 
-        return $mixedResult;
-    }
+        return $mixedResult;
+    }
+
+    protected function _getAgentObjectById($iId)
+    {
+        return BxDolAiQuery::getAgentObject((int)$iId);
+    }
+
+    protected function _isUnaOperator($aAgent)
+    {
+        return is_array($aAgent) && ($aAgent['name'] ?? '') === 'una_operator';
+    }
+
+    protected function _getActionDelete($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = [])
+    {
+        if ($this->_isUnaOperator($aRow))
+            return '';
+
+        return parent::_getActionDefault($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
 
 
     protected function _getFormEdit($sAction, $aAgent = [])
     protected function _getFormEdit($sAction, $aAgent = [])
     {
     {

+ 18 - 1
studio/template/scripts/BxBaseStudioAgentsModels.php

@@ -53,6 +53,10 @@ class BxBaseStudioAgentsModels extends BxTemplStudioGridAgents
 
 
         $aForm = $this->_getFormEdit($sAction, $aModel);
         $aForm = $this->_getFormEdit($sAction, $aModel);
         $oForm = new BxTemplFormView($aForm);
         $oForm = new BxTemplFormView($aForm);
+        if ($oForm->isSubmitted() && $this->_isUnaProxyModel($aModel)) {
+            BxDolForm::setSubmittedValue('model', $aModel['model'], $oForm->aFormAttrs['method']);
+            BxDolForm::setSubmittedValue('key', $aModel['key'], $oForm->aFormAttrs['method']);
+        }
         $oForm->initChecker();
         $oForm->initChecker();
 
 
         if($oForm->isSubmittedAndValid()) {
         if($oForm->isSubmittedAndValid()) {
@@ -176,11 +180,24 @@ class BxBaseStudioAgentsModels extends BxTemplStudioGridAgents
             ),
             ),
         );
         );
 
 
+        if ($sAction === 'edit' && $this->_isUnaProxyModel($aModel)) {
+            $aForm['inputs']['model']['attrs']['readonly'] = 'readonly';
+            $aForm['inputs']['key']['attrs']['readonly'] = 'readonly';
+        }
+
         return $aForm;
         return $aForm;
     }
     }
 
 
+    protected function _isUnaProxyModel($aModel)
+    {
+        return is_array($aModel) && ($aModel['type'] ?? '') === 'una-proxy';
+    }
+
     protected function _getActionDelete ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
     protected function _getActionDelete ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
     {
     {
+        if ($this->_isUnaProxyModel($aRow))
+            return '';
+
         if ($sType == 'single' && $aRow['duplicate'] == 0)
         if ($sType == 'single' && $aRow['duplicate'] == 0)
             return '';
             return '';
         return parent::_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
         return parent::_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
@@ -189,7 +206,7 @@ class BxBaseStudioAgentsModels extends BxTemplStudioGridAgents
     protected function _delete ($mixedId)
     protected function _delete ($mixedId)
     {
     {
         $aModel = $this->_oDb->getModelsBy(['sample' => 'id', 'id' => $mixedId]);
         $aModel = $this->_oDb->getModelsBy(['sample' => 'id', 'id' => $mixedId]);
-        if (empty($aModel) || $aModel['duplicate'] == 0)
+        if (empty($aModel) || $this->_isUnaProxyModel($aModel) || $aModel['duplicate'] == 0)
             return false;
             return false;
         return parent::_delete($mixedId);
         return parent::_delete($mixedId);
     }
     }

+ 66 - 2
studio/template/scripts/BxBaseStudioAgentsVectorStore.php

@@ -26,6 +26,10 @@ class BxBaseStudioAgentsVectorStore extends BxDolStudioAgentsInstruments
     
     
     public function performActionDuplicate()
     public function performActionDuplicate()
     {
     {
+        $aVectorStore = $this->_oDb->getVectorStoreById((int)$this->_getId());
+        if ($this->_isUnaProxyKnowledge($aVectorStore))
+            return echoJson(['msg' => _t('_sys_txt_error_occured')]);
+
         return parent::_performActionDuplicate('getVectorStoreById', 'insertVectorStore');
         return parent::_performActionDuplicate('getVectorStoreById', 'insertVectorStore');
     }
     }
 
 
@@ -35,6 +39,8 @@ class BxBaseStudioAgentsVectorStore extends BxDolStudioAgentsInstruments
 
 
         $iId = $this->_getId();
         $iId = $this->_getId();
         $aVectorStore = $this->_oDb->getVectorStoreById($iId);
         $aVectorStore = $this->_oDb->getVectorStoreById($iId);
+        if ($this->_isUnaProxyKnowledge($aVectorStore))
+            return echoJson(['msg' => _t('_sys_txt_error_occured')]);
 
 
         $aForm = $this->_getFormAddData($sAction, $aVectorStore);
         $aForm = $this->_getFormAddData($sAction, $aVectorStore);
         $oForm = new BxTemplFormView($aForm);
         $oForm = new BxTemplFormView($aForm);
@@ -89,6 +95,10 @@ class BxBaseStudioAgentsVectorStore extends BxDolStudioAgentsInstruments
 
 
     public function performActionEdit()
     public function performActionEdit()
     {
     {
+        $aVectorStore = $this->_oDb->getVectorStoreById((int)$this->_getId());
+        if ($this->_isUnaProxyKnowledge($aVectorStore))
+            return echoJson(['msg' => _t('_sys_txt_error_occured')]);
+
         return $this->_performActionEdit('getVectorStoreById', '_sys_agents_vector_store_popup_edit');
         return $this->_performActionEdit('getVectorStoreById', '_sys_agents_vector_store_popup_edit');
     }
     }
 
 
@@ -130,7 +140,7 @@ class BxBaseStudioAgentsVectorStore extends BxDolStudioAgentsInstruments
             $aEmbeddingProviders[$k] = $v;
             $aEmbeddingProviders[$k] = $v;
         }
         }
 
 
-        return [
+        $aForm = [
             'form_attrs' => [
             'form_attrs' => [
                 'id' => 'bx_std_agents_vector_store_' . $sAction,
                 'id' => 'bx_std_agents_vector_store_' . $sAction,
                 'action' => BX_DOL_URL_ROOT . 'grid.php?o=sys_studio_agents_vector_store&a=' . $sAction,
                 'action' => BX_DOL_URL_ROOT . 'grid.php?o=sys_studio_agents_vector_store&a=' . $sAction,
@@ -201,6 +211,14 @@ class BxBaseStudioAgentsVectorStore extends BxDolStudioAgentsInstruments
                 'submit' => $this->_getFormControls(),
                 'submit' => $this->_getFormControls(),
             ]
             ]
         ];
         ];
+
+        if ($sAction === 'edit' && $this->_isUnaProxyKnowledge($aVectorStore)) {
+            foreach (['title', 'topk', 'params_user'] as $sField)
+                $aForm['inputs'][$sField]['attrs']['readonly'] = 'readonly';
+            $aForm['inputs']['embedding_provider_id']['attrs']['disabled'] = 'disabled';
+        }
+
+        return $aForm;
     }
     }
 
 
     protected function _getFormAddData(string $sAction, array $aVectorStore)
     protected function _getFormAddData(string $sAction, array $aVectorStore)
@@ -305,6 +323,9 @@ class BxBaseStudioAgentsVectorStore extends BxDolStudioAgentsInstruments
 
 
     protected function _getCellEmbeddingProviderId($mixedValue, $sKey, $aField, $aRow) 
     protected function _getCellEmbeddingProviderId($mixedValue, $sKey, $aField, $aRow) 
     {
     {
+        if ($this->_isUnaProxyKnowledge($aRow))
+            return parent::_getCellDefault('', $sKey, $aField, $aRow);
+
         $aProvider = $this->_oDb->getModelsBy(['sample' => 'id', 'id' => $mixedValue]);
         $aProvider = $this->_oDb->getModelsBy(['sample' => 'id', 'id' => $mixedValue]);
         $s = !empty($aProvider) ? $aProvider['title'] : _t('_undefined');
         $s = !empty($aProvider) ? $aProvider['title'] : _t('_undefined');
         return parent::_getCellDefault($s, $sKey, $aField, $aRow);
         return parent::_getCellDefault($s, $sKey, $aField, $aRow);
@@ -312,6 +333,12 @@ class BxBaseStudioAgentsVectorStore extends BxDolStudioAgentsInstruments
     
     
     protected function _getCellFilesNum($mixedValue, $sKey, $aField, $aRow)
     protected function _getCellFilesNum($mixedValue, $sKey, $aField, $aRow)
     {
     {
+        if ($this->_isUnaProxyKnowledge($aRow)) {
+            $sLabel = _t('_sys_not_available');
+            $s = '<i class="sys-icon circle col-gray" role="img" aria-label="' . bx_html_attribute($sLabel) . '" title="' . bx_html_attribute($sLabel) . '"></i>';
+            return parent::_getCellDefault($s, $sKey, $aField, $aRow);
+        }
+
         $s = $this->_oDb->getVectorStoreDataNum($aRow['id']);
         $s = $this->_oDb->getVectorStoreDataNum($aRow['id']);
         if ((int)$s !== 0)
         if ((int)$s !== 0)
             $s = '<a href="javascript:void(0)" onclick="glGrids.' . $this->_sObject . '.actionWithId (' . $aRow['id'] . ', \'files\', {}, \'\', false, 0);">' . $s . '</a>';
             $s = '<a href="javascript:void(0)" onclick="glGrids.' . $this->_sObject . '.actionWithId (' . $aRow['id'] . ', \'files\', {}, \'\', false, 0);">' . $s . '</a>';
@@ -321,13 +348,50 @@ class BxBaseStudioAgentsVectorStore extends BxDolStudioAgentsInstruments
     protected function _delete ($mixedId)
     protected function _delete ($mixedId)
     {
     {
         $aModel = $this->_oDb->getVectorStoreById($mixedId);
         $aModel = $this->_oDb->getVectorStoreById($mixedId);
-        if (empty($aModel) || $aModel['duplicate'] == 0)
+        if (empty($aModel) || $this->_isUnaProxyKnowledge($aModel) || $aModel['duplicate'] == 0)
             return false;
             return false;
 
 
         // TODO: delete actual vector store data if needed
         // TODO: delete actual vector store data if needed
 
 
         return parent::_delete($mixedId);
         return parent::_delete($mixedId);
     }
     }
+
+    protected function _isUnaProxyKnowledge($aVectorStore)
+    {
+        return is_array($aVectorStore) && ($aVectorStore['type'] ?? '') === 'una-proxy';
+    }
+
+    protected function _getActionAddData($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = [])
+    {
+        if ($this->_isUnaProxyKnowledge($aRow))
+            return '';
+
+        return parent::_getActionDefault($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _getActionDuplicate($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = [])
+    {
+        if ($this->_isUnaProxyKnowledge($aRow))
+            return '';
+
+        return parent::_getActionDefault($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _getActionEdit($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = [])
+    {
+        if ($this->_isUnaProxyKnowledge($aRow))
+            return '';
+
+        return parent::_getActionDefault($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _getActionDelete($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = [])
+    {
+        if ($this->_isUnaProxyKnowledge($aRow))
+            return '';
+
+        return parent::_getActionDelete($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
 }
 }
 
 
 /** @} */
 /** @} */

+ 78 - 0
tests/units/studio/BxDolStudioAgentsProtectedRecordsTest.php

@@ -0,0 +1,78 @@
+<?php
+
+class BxDolStudioAgentsProtectedRecordsAgentsProxy extends BxBaseStudioAgentsAgents
+{
+    public function deleteRecord($iId)
+    {
+        return $this->_delete($iId);
+    }
+
+    protected function _getAgentObjectById($iId)
+    {
+        return ['id' => $iId, 'name' => 'una_operator'];
+    }
+}
+
+class BxDolStudioAgentsProtectedRecordsModelsProxy extends BxBaseStudioAgentsModels
+{
+    public function deleteRecord($iId)
+    {
+        return $this->_delete($iId);
+    }
+}
+
+class BxDolStudioAgentsProtectedRecordsKnowledgeProxy extends BxBaseStudioAgentsVectorStore
+{
+    public function deleteRecord($iId)
+    {
+        return $this->_delete($iId);
+    }
+}
+
+class BxDolStudioAgentsProtectedRecordsTest extends BxDolTestCase
+{
+    public function testUnaOperatorCannotBeDeletedThroughGridHandler()
+    {
+        $oGrid = (new ReflectionClass(BxDolStudioAgentsProtectedRecordsAgentsProxy::class))->newInstanceWithoutConstructor();
+
+        $this->assertFalse($oGrid->deleteRecord(1));
+        $this->assertSame('', $this->bxCallProtected($oGrid, '_getActionDelete', 'single', 'delete', [], true, false, ['name' => 'una_operator']));
+    }
+
+    public function testUnaProxyModelCannotBeDeletedThroughGridHandler()
+    {
+        $oDb = $this->getMockBuilder(BxDolStudioAgentsQuery::class)
+            ->disableOriginalConstructor()
+            ->onlyMethods(['getModelsBy'])
+            ->getMock();
+        $oDb->expects($this->once())
+            ->method('getModelsBy')
+            ->willReturn(['id' => 1, 'type' => 'una-proxy', 'duplicate' => 1]);
+
+        $oGrid = (new ReflectionClass(BxDolStudioAgentsProtectedRecordsModelsProxy::class))->newInstanceWithoutConstructor();
+        $this->bxSetProtected($oGrid, '_oDb', $oDb, BxDolStudioGridAgents::class);
+
+        $this->assertFalse($oGrid->deleteRecord(1));
+        $this->assertSame('', $this->bxCallProtected($oGrid, '_getActionDelete', 'single', 'delete', [], true, false, ['type' => 'una-proxy', 'duplicate' => 1]));
+    }
+
+    public function testUnaProxyKnowledgeCannotBeDeletedThroughGridHandler()
+    {
+        $oDb = $this->getMockBuilder(BxDolStudioAgentsQuery::class)
+            ->disableOriginalConstructor()
+            ->onlyMethods(['getVectorStoreById'])
+            ->getMock();
+        $oDb->expects($this->once())
+            ->method('getVectorStoreById')
+            ->willReturn(['id' => 1, 'type' => 'una-proxy', 'duplicate' => 1]);
+
+        $oGrid = (new ReflectionClass(BxDolStudioAgentsProtectedRecordsKnowledgeProxy::class))->newInstanceWithoutConstructor();
+        $this->bxSetProtected($oGrid, '_oDb', $oDb, BxDolStudioGridAgents::class);
+
+        $this->assertFalse($oGrid->deleteRecord(1));
+        $this->assertSame('', $this->bxCallProtected($oGrid, '_getActionDelete', 'single', 'delete', [], true, false, ['type' => 'una-proxy', 'duplicate' => 1]));
+        $this->assertSame('', $this->bxCallProtected($oGrid, '_getActionAddData', 'single', 'add_data', [], true, false, ['type' => 'una-proxy']));
+        $this->assertSame('', $this->bxCallProtected($oGrid, '_getActionDuplicate', 'single', 'duplicate', [], true, false, ['type' => 'una-proxy']));
+        $this->assertSame('', $this->bxCallProtected($oGrid, '_getActionEdit', 'single', 'edit', [], true, false, ['type' => 'una-proxy']));
+    }
+}