myagent-ai 1.5.7 → 1.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
package/web/api_server.py
CHANGED
|
@@ -1570,26 +1570,15 @@ class ApiServer:
|
|
|
1570
1570
|
pm = self.core.permission_manager
|
|
1571
1571
|
if not pm:
|
|
1572
1572
|
return web.json_response({"error": "权限管理器未初始化"}, status=500)
|
|
1573
|
-
from core.permissions import PERMISSION_LABELS, ALL_PERMISSIONS
|
|
1574
|
-
defaults = pm.get_permissions("__defaults__") if hasattr(pm, 'get_permissions') else {}
|
|
1575
|
-
# 直接读取默认配置
|
|
1576
|
-
default_perms = {}
|
|
1577
1573
|
try:
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
pass
|
|
1587
|
-
return web.json_response({
|
|
1588
|
-
"defaults": default_perms,
|
|
1589
|
-
"agents": agents_perms,
|
|
1590
|
-
"labels": PERMISSION_LABELS,
|
|
1591
|
-
"all_permissions": ALL_PERMISSIONS,
|
|
1592
|
-
})
|
|
1574
|
+
result = pm.get_config_summary()
|
|
1575
|
+
# 前端期望 labels 键名,映射 permission_labels
|
|
1576
|
+
if "permission_labels" in result and "labels" not in result:
|
|
1577
|
+
result["labels"] = result["permission_labels"]
|
|
1578
|
+
except Exception as e:
|
|
1579
|
+
logger.error(f"获取权限配置失败: {e}")
|
|
1580
|
+
return web.json_response({"error": str(e)}, status=500)
|
|
1581
|
+
return web.json_response(result)
|
|
1593
1582
|
|
|
1594
1583
|
async def handle_set_default_permissions(self, request):
|
|
1595
1584
|
"""PUT /api/permissions/defaults - 更新全局默认权限"""
|
|
@@ -1601,7 +1590,7 @@ class ApiServer:
|
|
|
1601
1590
|
# data 格式: {"execution": true, "file_read": false, ...}
|
|
1602
1591
|
if isinstance(data, dict):
|
|
1603
1592
|
for perm, value in data.items():
|
|
1604
|
-
if isinstance(value, bool) and perm in
|
|
1593
|
+
if isinstance(value, bool) and perm in pm.ALL_PERMISSIONS:
|
|
1605
1594
|
pm.set_default_permission(perm, value)
|
|
1606
1595
|
pm.save()
|
|
1607
1596
|
return web.json_response({"ok": True})
|
|
@@ -1616,7 +1605,7 @@ class ApiServer:
|
|
|
1616
1605
|
agent = request.match_info["agent"]
|
|
1617
1606
|
try:
|
|
1618
1607
|
perms = pm.get_permissions(agent)
|
|
1619
|
-
return web.json_response({"agent": agent, "permissions": perms})
|
|
1608
|
+
return web.json_response({"agent": agent, "permissions": perms.to_dict()})
|
|
1620
1609
|
except Exception as e:
|
|
1621
1610
|
return web.json_response({"error": str(e)}, status=500)
|
|
1622
1611
|
|
package/web/ui/index.html
CHANGED
|
@@ -417,10 +417,7 @@ async function openEditAgentModal(path){
|
|
|
417
417
|
<div class="form-group"><label>头像 Emoji</label><input id="eaEmoji" value="${escHtml(a.avatar_emoji||'')}" ${isSys?'disabled':''}></div>
|
|
418
418
|
<div class="form-group"><label>头像颜色</label><div class="flex gap-8 items-center"><input id="eaColor" value="${escHtml(a.avatar_color||'#6366f1')}" type="color" style="width:48px;height:34px;padding:2px" ${isSys?'disabled':''}><input id="eaColorText" value="${escHtml(a.avatar_color||'#6366f1')}" style="flex:1" oninput="$('eaColor').value=this.value" ${isSys?'disabled':''}></div></div>
|
|
419
419
|
</div>
|
|
420
|
-
<div class="form-
|
|
421
|
-
<div class="form-group"><label>执行模式</label><select id="eaExecMode" ${isSys?'disabled':''}><option value="sandbox" ${a.execution_mode==='sandbox'?'selected':''}>沙盒 (Docker)</option><option value="local" ${a.execution_mode==='local'?'selected':''}>本机</option></select></div>
|
|
422
|
-
<div class="form-group"><label>绑定模型</label><select id="eaModelId"><option value="">使用全局默认</option>${modelOpts}</select></div>
|
|
423
|
-
</div>
|
|
420
|
+
<div class="form-group"><label>绑定模型</label><select id="eaModelId"><option value="">使用全局默认</option>${modelOpts}</select></div>
|
|
424
421
|
<div class="form-group"><label>备用模型</label><select id="eaBackupModels" multiple style="min-height:60px">${backupOpts}</select><div style="font-size:11px;color:var(--text2);margin-top:4px">按住 Ctrl/Cmd 多选</div></div>
|
|
425
422
|
<div class="form-row">
|
|
426
423
|
<div class="form-group"><label>Agent ID <span style="color:var(--text2)">(只读)</span></label><input id="eaId" value="${escHtml(a.id||'-')}" disabled></div>
|
|
@@ -485,7 +482,7 @@ function agentTabSwitch(el,tabId){
|
|
|
485
482
|
async function doSaveAgent(path){
|
|
486
483
|
const r=await api(`/api/agents/${encodeURIComponent(path)}`,{method:'PUT',body:JSON.stringify({
|
|
487
484
|
description:$('eaDesc').value,avatar_emoji:$('eaEmoji').value,avatar_color:$('eaColorText').value,
|
|
488
|
-
|
|
485
|
+
model_id:$('eaModelId').value,
|
|
489
486
|
backup_model_ids:Array.from($('eaBackupModels').selectedOptions).map(o=>o.value),
|
|
490
487
|
work_dir:$('eaWorkDir').value,system_prompt:$('eaPrompt').value
|
|
491
488
|
})});
|
|
@@ -572,53 +569,91 @@ async function viewSessionMsgs(sid){
|
|
|
572
569
|
|
|
573
570
|
async function loadAgentPerms(){
|
|
574
571
|
const path=window._currentEditAgentPath;if(!path)return;
|
|
575
|
-
const [agentPerms,globalPerms]=await Promise.all([
|
|
572
|
+
const [agentPerms,globalPerms,agentInfo]=await Promise.all([
|
|
576
573
|
api('/api/permissions/'+encodeURIComponent(path)),
|
|
577
|
-
api('/api/permissions')
|
|
574
|
+
api('/api/permissions'),
|
|
575
|
+
api(`/api/agents/${encodeURIComponent(path)}`)
|
|
578
576
|
]);
|
|
579
577
|
const perms=globalPerms.all_permissions||[];
|
|
580
578
|
const labels=globalPerms.labels||{};
|
|
581
579
|
const defaults=globalPerms.defaults||{};
|
|
582
580
|
const ap=agentPerms.permissions||{};
|
|
583
|
-
|
|
584
|
-
|
|
581
|
+
const execMode=agentInfo.execution_mode||'sandbox';
|
|
582
|
+
const isSys=!!agentInfo.system;
|
|
583
|
+
|
|
584
|
+
// ── 执行模式卡片 ──
|
|
585
|
+
let html='<div class="card" style="margin-bottom:16px">';
|
|
586
|
+
html+='<h3 style="font-size:14px;color:var(--text2);margin-bottom:8px">⚡ 执行环境</h3>';
|
|
587
|
+
html+='<p style="color:var(--text2);font-size:12px;margin-bottom:12px">选择 Agent 代码执行的运行环境。沙盒模式隔离更安全,本机模式可使用全部本地资源。</p>';
|
|
588
|
+
html+='<div style="display:flex;gap:12px">';
|
|
589
|
+
html+=`<label style="flex:1;display:flex;align-items:center;gap:10px;padding:14px 16px;border-radius:var(--radius);border:2px solid ${execMode==='sandbox'?'var(--primary)':'var(--border)'};cursor:pointer;background:${execMode==='sandbox'?'var(--accent-light)':'transparent'};transition:all .15s" onclick="document.getElementById('permExecSandbox').checked=true;updateExecModeUI()">`;
|
|
590
|
+
html+=`<input type="radio" name="permExecMode" id="permExecSandbox" value="sandbox" ${execMode==='sandbox'?'checked':''} style="display:none">`;
|
|
591
|
+
html+=`<span style="font-size:28px">🐳</span><div><div style="font-weight:600;font-size:14px">沙盒模式</div><div style="font-size:11px;color:var(--text2);margin-top:2px">Docker 容器隔离,安全受限</div></div></label>`;
|
|
592
|
+
html+=`<label style="flex:1;display:flex;align-items:center;gap:10px;padding:14px 16px;border-radius:var(--radius);border:2px solid ${execMode==='local'?'var(--primary)':'var(--border)'};cursor:pointer;background:${execMode==='local'?'var(--accent-light)':'transparent'};transition:all .15s" onclick="document.getElementById('permExecLocal').checked=true;updateExecModeUI()">`;
|
|
593
|
+
html+=`<input type="radio" name="permExecMode" id="permExecLocal" value="local" ${execMode==='local'?'checked':''} style="display:none">`;
|
|
594
|
+
html+=`<span style="font-size:28px">💻</span><div><div style="font-weight:600;font-size:14px">本机模式</div><div style="font-size:11px;color:var(--text2);margin-top:2px">直接在本机运行,完整权限</div></div></label>`;
|
|
595
|
+
html+='</div></div>';
|
|
596
|
+
|
|
597
|
+
// ── 功能权限卡片 ──
|
|
598
|
+
html+='<div class="card" style="margin-bottom:16px">';
|
|
599
|
+
html+='<h3 style="font-size:14px;color:var(--text2);margin-bottom:8px">🔑 功能权限</h3>';
|
|
600
|
+
html+='<p style="color:var(--text2);font-size:12px;margin-bottom:12px">精细控制 Agent 的各项能力。未设置的项目将使用全局默认值。</p>';
|
|
585
601
|
html+='<div class="grid" style="grid-template-columns:repeat(3,1fr);gap:12px">';
|
|
586
602
|
for(const p of perms){
|
|
587
603
|
const label=labels[p]||p;
|
|
588
604
|
const defVal=defaults[p]!==false;
|
|
589
605
|
const curVal=ap[p]!==undefined?ap[p]:defVal;
|
|
590
606
|
const checked=curVal?'checked':'';
|
|
591
|
-
const isDefault=ap[p]===undefined?'(默认)':'';
|
|
592
|
-
html+=`<div class="form-group" style="display:flex;align-items:center;gap:10px"><label style="flex:1;font-weight:500">${label}
|
|
607
|
+
const isDefault=ap[p]===undefined?'<span style=\"color:var(--text3);font-size:11px;margin-left:4px\">(默认)</span>':'';
|
|
608
|
+
html+=`<div class="form-group" style="display:flex;align-items:center;gap:10px"><label style="flex:1;font-weight:500">${label}${isDefault}</label><input type="checkbox" id="agent_perm_${p}" ${checked} style="width:18px;height:18px;cursor:pointer"></div>`;
|
|
593
609
|
}
|
|
610
|
+
html+='</div></div>';
|
|
611
|
+
|
|
612
|
+
// ── 操作按钮 ──
|
|
613
|
+
html+='<div class="flex gap-8">';
|
|
614
|
+
html+='<button class="btn btn-primary" onclick="saveAgentPermsFromTab()">💾 保存全部</button>';
|
|
615
|
+
html+='<button class="btn btn-ghost" onclick="resetAgentPermsFromTab()">🔄 重置功能权限为默认</button>';
|
|
594
616
|
html+='</div>';
|
|
595
|
-
html+='<div class="flex gap-8 mt-16"><button class="btn btn-primary" onclick="saveAgentPermsFromTab()">保存权限</button>';
|
|
596
|
-
html+='<button class="btn btn-ghost" onclick="resetAgentPermsFromTab()">重置为默认</button></div>';
|
|
597
617
|
$('atPermsContent').innerHTML=html;
|
|
598
618
|
}
|
|
619
|
+
function updateExecModeUI(){
|
|
620
|
+
const sandbox=document.getElementById('permExecSandbox');
|
|
621
|
+
const local=document.getElementById('permExecLocal');
|
|
622
|
+
if(!sandbox||!local)return;
|
|
623
|
+
const isLocal=local.checked;
|
|
624
|
+
[sandbox.parentElement,local.parentElement].forEach(el=>{
|
|
625
|
+
const radio=el.querySelector('input[type=radio]');
|
|
626
|
+
if(radio.checked){el.style.borderColor='var(--primary)';el.style.background='var(--accent-light)'}
|
|
627
|
+
else{el.style.borderColor='var(--border)';el.style.background='transparent'}
|
|
628
|
+
});
|
|
629
|
+
}
|
|
599
630
|
async function saveAgentPermsFromTab(){
|
|
600
631
|
const path=window._currentEditAgentPath;if(!path)return;
|
|
632
|
+
// 1. 保存执行模式
|
|
633
|
+
const execSandbox=document.getElementById('permExecSandbox');
|
|
634
|
+
const execLocal=document.getElementById('permExecLocal');
|
|
635
|
+
const newExecMode=(execSandbox&&execSandbox.checked)?'sandbox':((execLocal&&execLocal.checked)?'local':'sandbox');
|
|
636
|
+
const execR=await api(`/api/agents/${encodeURIComponent(path)}`,{method:'PUT',body:JSON.stringify({execution_mode:newExecMode})});
|
|
637
|
+
if(execR.error){showToast('执行模式保存失败: '+execR.error,'danger');return}
|
|
638
|
+
|
|
639
|
+
// 2. 保存功能权限
|
|
601
640
|
const [agentPerms,globalPerms]=await Promise.all([
|
|
602
641
|
api('/api/permissions/'+encodeURIComponent(path)),
|
|
603
642
|
api('/api/permissions')
|
|
604
643
|
]);
|
|
605
644
|
const perms=globalPerms.all_permissions||[];
|
|
606
645
|
const defaults=globalPerms.defaults||{};
|
|
607
|
-
const ap=agentPerms.permissions||{};
|
|
608
646
|
const data={};
|
|
609
647
|
for(const p of perms){
|
|
610
648
|
const el=document.getElementById('agent_perm_'+p);
|
|
611
649
|
if(!el)continue;
|
|
612
650
|
const defVal=defaults[p]!==false;
|
|
613
651
|
const curVal=el.checked;
|
|
614
|
-
|
|
615
|
-
if(curVal!==defVal){
|
|
616
|
-
data[p]=curVal;
|
|
617
|
-
}
|
|
652
|
+
if(curVal!==defVal){data[p]=curVal}
|
|
618
653
|
}
|
|
619
654
|
const r=await api('/api/permissions/'+encodeURIComponent(path),{method:'PUT',body:JSON.stringify(data)});
|
|
620
|
-
if(r.error){showToast(r.error,'danger');return}
|
|
621
|
-
showToast('
|
|
655
|
+
if(r.error){showToast('权限保存失败: '+r.error,'danger');return}
|
|
656
|
+
showToast('权限配置已保存','success');
|
|
622
657
|
}
|
|
623
658
|
async function resetAgentPermsFromTab(){
|
|
624
659
|
const path=window._currentEditAgentPath;if(!path)return;
|
|
@@ -821,14 +856,34 @@ async function editAgentPerms(name){
|
|
|
821
856
|
const labels=_permsCache.labels||{};
|
|
822
857
|
const perms=_permsCache.all_permissions||[];
|
|
823
858
|
const defaults=_permsCache.defaults||{};
|
|
824
|
-
// 获取当前 agent
|
|
859
|
+
// 获取当前 agent 权限和 agent 信息(含执行模式)
|
|
825
860
|
let agentPerms={};
|
|
861
|
+
let agentExecMode='sandbox';
|
|
826
862
|
try{
|
|
827
|
-
const r=await
|
|
863
|
+
const [r,ai]=await Promise.all([
|
|
864
|
+
api('/api/permissions/'+encodeURIComponent(name)),
|
|
865
|
+
api('/api/agents/'+encodeURIComponent(name))
|
|
866
|
+
]);
|
|
828
867
|
agentPerms=r.permissions||{};
|
|
868
|
+
agentExecMode=ai.execution_mode||'sandbox';
|
|
829
869
|
}catch(e){agentPerms={...defaults}}
|
|
830
870
|
|
|
831
|
-
let html='<h3>编辑 Agent 权限: '+escHtml(name)+'</h3
|
|
871
|
+
let html='<h3>编辑 Agent 权限: '+escHtml(name)+'</h3>';
|
|
872
|
+
|
|
873
|
+
// 执行模式选择
|
|
874
|
+
html+='<div style="margin-bottom:16px"><div style="font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:600">⚡ 执行环境</div>';
|
|
875
|
+
html+='<div style="display:flex;gap:12px">';
|
|
876
|
+
html+=`<label id="modalExecSandboxLabel" style="flex:1;display:flex;align-items:center;gap:10px;padding:12px 14px;border-radius:var(--radius);border:2px solid ${agentExecMode==='sandbox'?'var(--primary)':'var(--border)'};cursor:pointer;background:${agentExecMode==='sandbox'?'var(--accent-light)':'transparent'};transition:all .15s" onclick="document.getElementById('modalExecSandbox').checked=true;updateModalExecUI()">`;
|
|
877
|
+
html+=`<input type="radio" name="modalExecMode" id="modalExecSandbox" value="sandbox" ${agentExecMode==='sandbox'?'checked':''} style="display:none">`;
|
|
878
|
+
html+=`<span style="font-size:24px">🐳</span><div><div style="font-weight:600;font-size:13px">沙盒模式</div><div style="font-size:11px;color:var(--text2)">Docker 容器隔离</div></div></label>`;
|
|
879
|
+
html+=`<label id="modalExecLocalLabel" style="flex:1;display:flex;align-items:center;gap:10px;padding:12px 14px;border-radius:var(--radius);border:2px solid ${agentExecMode==='local'?'var(--primary)':'var(--border)'};cursor:pointer;background:${agentExecMode==='local'?'var(--accent-light)':'transparent'};transition:all .15s" onclick="document.getElementById('modalExecLocal').checked=true;updateModalExecUI()">`;
|
|
880
|
+
html+=`<input type="radio" name="modalExecMode" id="modalExecLocal" value="local" ${agentExecMode==='local'?'checked':''} style="display:none">`;
|
|
881
|
+
html+=`<span style="font-size:24px">💻</span><div><div style="font-weight:600;font-size:13px">本机模式</div><div style="font-size:11px;color:var(--text2)">完整本地权限</div></div></label>`;
|
|
882
|
+
html+='</div></div>';
|
|
883
|
+
|
|
884
|
+
// 功能权限
|
|
885
|
+
html+='<div style="font-size:13px;color:var(--text2);margin-bottom:8px;font-weight:600">🔑 功能权限</div>';
|
|
886
|
+
html+='<div class="grid" style="grid-template-columns:repeat(3,1fr);gap:12px">';
|
|
832
887
|
for(const p of perms){
|
|
833
888
|
const label=labels[p]||p;
|
|
834
889
|
const defVal=defaults[p]!==false;
|
|
@@ -836,12 +891,33 @@ async function editAgentPerms(name){
|
|
|
836
891
|
const checked=curVal?'checked':'';
|
|
837
892
|
html+=`<div class="form-group" style="display:flex;align-items:center;gap:10px"><label style="flex:1;font-weight:500">${label}</label><input type="checkbox" id="perm_agent_${p}" ${checked} style="width:18px;height:18px;cursor:pointer"></div>`;
|
|
838
893
|
}
|
|
839
|
-
html+='</div><div class="flex gap-8 mt-16"><button class="btn btn-primary" onclick="saveAgentPerms(\''+escHtml(name)+'\')"
|
|
894
|
+
html+='</div><div class="flex gap-8 mt-16"><button class="btn btn-primary" onclick="saveAgentPerms(\''+escHtml(name)+'\')">💾 保存</button><button class="btn btn-ghost" onclick="renderPermissions()">取消</button></div>';
|
|
840
895
|
$('modalContainer').innerHTML='<div class="modal-overlay" onclick="closeModal()"><div class="modal" onclick="event.stopPropagation()">'+html+'</div></div>';
|
|
841
896
|
}
|
|
842
897
|
|
|
898
|
+
function updateModalExecUI(){
|
|
899
|
+
const sandbox=document.getElementById('modalExecSandbox');
|
|
900
|
+
const local=document.getElementById('modalExecLocal');
|
|
901
|
+
if(!sandbox||!local)return;
|
|
902
|
+
[sandbox.parentElement,local.parentElement].forEach(el=>{
|
|
903
|
+
const radio=el.querySelector('input[type=radio]');
|
|
904
|
+
if(radio.checked){el.style.borderColor='var(--primary)';el.style.background='var(--accent-light)'}
|
|
905
|
+
else{el.style.borderColor='var(--border)';el.style.background='transparent'}
|
|
906
|
+
});
|
|
907
|
+
}
|
|
908
|
+
|
|
843
909
|
async function saveAgentPerms(name){
|
|
844
910
|
if(!_permsCache)return;
|
|
911
|
+
// 1. 保存执行模式
|
|
912
|
+
const modalSandbox=document.getElementById('modalExecSandbox');
|
|
913
|
+
const modalLocal=document.getElementById('modalExecLocal');
|
|
914
|
+
if(modalSandbox||modalLocal){
|
|
915
|
+
const newMode=(modalSandbox&&modalSandbox.checked)?'sandbox':((modalLocal&&modalLocal.checked)?'local':null);
|
|
916
|
+
if(newMode){
|
|
917
|
+
await api('/api/agents/'+encodeURIComponent(name),{method:'PUT',body:JSON.stringify({execution_mode:newMode})});
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
// 2. 保存功能权限
|
|
845
921
|
const perms=_permsCache.all_permissions||[];
|
|
846
922
|
const data={};
|
|
847
923
|
for(const p of perms){
|
|
Binary file
|
|
Binary file
|