delete_project: Conform confirm dialog + _sys_delete_project + system action bypass
This commit is contained in:
parent
dedb2a60e1
commit
a2106e4365
@ -161,9 +161,14 @@ async def _exec_tool(sor, tool, params, ctx, uid, org_id):
|
|||||||
return f'OK: 已创建并切换到「{name}」'
|
return f'OK: 已创建并切换到「{name}」'
|
||||||
elif tool == 'delete_project':
|
elif tool == 'delete_project':
|
||||||
name = (p.get('project','') or '').strip()
|
name = (p.get('project','') or '').strip()
|
||||||
confirm = (p.get('confirm','') or '').strip()
|
|
||||||
if not name: return 'FAIL: 需要项目名称'
|
if not name: return 'FAIL: 需要项目名称'
|
||||||
if confirm != name: return f'FAIL: 确认不匹配(需输入"{name}"确认)'
|
proj = await _find_project(sor, name)
|
||||||
|
if not proj: return f'FAIL: 项目「{name}」不存在'
|
||||||
|
# Yield Conform widget — actual deletion happens via _sys_delete_project
|
||||||
|
return json.dumps({"widgettype":"Conform","options":{"message":f"确定要删除项目「{name}」吗?此操作不可撤销,将清除所有关联数据。","conform":{"label":"确认删除","name":"conform"},"discard":{"label":"取消","name":"discard"},"_action":"_sys_delete_project","_payload":{"project":name}}},ensure_ascii=False)
|
||||||
|
elif tool == '_sys_delete_project':
|
||||||
|
name = (p.get('project','') or '').strip()
|
||||||
|
if not name: return 'FAIL: 缺少项目名称'
|
||||||
proj = await _find_project(sor, name)
|
proj = await _find_project(sor, name)
|
||||||
if not proj: return f'FAIL: 项目「{name}」不存在'
|
if not proj: return f'FAIL: 项目「{name}」不存在'
|
||||||
pid = proj.id
|
pid = proj.id
|
||||||
@ -360,6 +365,19 @@ if action == 'send_message':
|
|||||||
user_model_id = inner.get('model_id') or inner.get('llmid') or user_model_id
|
user_model_id = inner.get('model_id') or inner.get('llmid') or user_model_id
|
||||||
if not message_text: return json.dumps({"error":"message_text is required"},ensure_ascii=False)
|
if not message_text: return json.dumps({"error":"message_text is required"},ensure_ascii=False)
|
||||||
|
|
||||||
|
# ── System action: bypass LLM, execute directly ──
|
||||||
|
sys_action = p.get('_system_action', '')
|
||||||
|
if sys_action:
|
||||||
|
async def sys_stream():
|
||||||
|
async with DBPools().sqlorContext(dbname) as sor:
|
||||||
|
uid = await get_user()
|
||||||
|
org_id = await get_userorgid() or '0'
|
||||||
|
ctx = await _load_ctx(sor, uid)
|
||||||
|
result = await _exec_tool(sor, sys_action, p, ctx, uid, org_id)
|
||||||
|
d = json.dumps(_w_text(result), ensure_ascii=False)+'\n'
|
||||||
|
yield d
|
||||||
|
return await stream_response(request, sys_stream, 'text/plain; charset=utf-8')
|
||||||
|
|
||||||
blocked, reason = _security_scan(message_text)
|
blocked, reason = _security_scan(message_text)
|
||||||
if blocked: return json.dumps({"success":True,"agent_reply":f"⚠️ {reason}"},ensure_ascii=False)
|
if blocked: return json.dumps({"success":True,"agent_reply":f"⚠️ {reason}"},ensure_ascii=False)
|
||||||
|
|
||||||
@ -398,8 +416,12 @@ if action == 'send_message':
|
|||||||
debug(f"YIELD progress: {d[:60]}")
|
debug(f"YIELD progress: {d[:60]}")
|
||||||
yield d
|
yield d
|
||||||
result = await _exec_tool(sor, tool, act.get('params',{}), ctx, uid, org_id)
|
result = await _exec_tool(sor, tool, act.get('params',{}), ctx, uid, org_id)
|
||||||
ok = result.startswith("OK:")
|
# If result is a raw widget descriptor, yield it directly
|
||||||
d = json.dumps(_w_card(label, _w_text(result), "success" if ok else "error"), ensure_ascii=False)+'\n'
|
if result.startswith('{"widgettype":'):
|
||||||
|
d = result + '\n'
|
||||||
|
else:
|
||||||
|
ok = result.startswith("OK:")
|
||||||
|
d = json.dumps(_w_card(label, _w_text(result), "success" if ok else "error"), ensure_ascii=False)+'\n'
|
||||||
debug(f"YIELD result: {d[:60]}")
|
debug(f"YIELD result: {d[:60]}")
|
||||||
yield d
|
yield d
|
||||||
msgs.append({"role":"assistant","content":raw})
|
msgs.append({"role":"assistant","content":raw})
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user