重构前端:添加TabPanel正确语法,创建sessions和config CRUD页面及API
This commit is contained in:
parent
216c21466f
commit
4882ba0290
42
wwwroot/api/config_get.dspy
Normal file
42
wwwroot/api/config_get.dspy
Normal file
@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Get reasoning configuration for current user"""
|
||||
import json
|
||||
|
||||
result = {'success': False, 'config': {}}
|
||||
|
||||
try:
|
||||
dbname = get_module_dbname('harnessed_reasoning')
|
||||
user_id = await get_user()
|
||||
|
||||
sql = """SELECT * FROM harnessed_reasoning_config
|
||||
WHERE user_id = ${user_id}$
|
||||
ORDER BY updated_at DESC
|
||||
LIMIT 1"""
|
||||
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
rows = await sor.sqlExe(sql, {'user_id': user_id})
|
||||
if rows and len(rows) > 0:
|
||||
config = dict(rows[0])
|
||||
# Convert string booleans to actual booleans for UI
|
||||
config['enable_cross_session_search'] = config.get('enable_cross_session_search', '1') == '1'
|
||||
config['enable_skill_auto_loading'] = config.get('enable_skill_auto_loading', '1') == '1'
|
||||
config['enable_error_recovery'] = config.get('enable_error_recovery', '1') == '1'
|
||||
result['config'] = config
|
||||
else:
|
||||
result['config'] = {
|
||||
'max_reasoning_steps': 10,
|
||||
'max_tool_calls_per_step': 5,
|
||||
'enable_cross_session_search': True,
|
||||
'enable_skill_auto_loading': True,
|
||||
'safety_mode': 'strict',
|
||||
'max_context_tokens': 4000,
|
||||
'enable_error_recovery': True,
|
||||
'max_recovery_attempts': 3
|
||||
}
|
||||
result['success'] = True
|
||||
|
||||
except Exception as e:
|
||||
result['error'] = str(e)
|
||||
|
||||
return json.dumps(result, ensure_ascii=False, default=str)
|
||||
80
wwwroot/api/config_save.dspy
Normal file
80
wwwroot/api/config_save.dspy
Normal file
@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Save reasoning configuration for current user"""
|
||||
import json, uuid, time
|
||||
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Error', 'message': 'Invalid request', 'type': 'error'}}
|
||||
|
||||
try:
|
||||
dbname = get_module_dbname('harnessed_reasoning')
|
||||
user_id = await get_user()
|
||||
now = time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
max_reasoning_steps = int(params_kw.get('max_reasoning_steps', 10))
|
||||
max_tool_calls_per_step = int(params_kw.get('max_tool_calls_per_step', 5))
|
||||
enable_cross_session_search = '1' if params_kw.get('enable_cross_session_search') == '1' else '0'
|
||||
enable_skill_auto_loading = '1' if params_kw.get('enable_skill_auto_loading') == '1' else '0'
|
||||
safety_mode = params_kw.get('safety_mode', 'strict').strip()
|
||||
max_context_tokens = int(params_kw.get('max_context_tokens', 4000))
|
||||
enable_error_recovery = '1' if params_kw.get('enable_error_recovery') == '1' else '0'
|
||||
max_recovery_attempts = int(params_kw.get('max_recovery_attempts', 3))
|
||||
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
# Check if config exists
|
||||
rows = await sor.sqlExe("SELECT id FROM harnessed_reasoning_config WHERE user_id = ${user_id}$", {'user_id': user_id})
|
||||
|
||||
if rows and len(rows) > 0:
|
||||
config_id = rows[0]['id']
|
||||
await sor.sqlExe("""UPDATE harnessed_reasoning_config SET
|
||||
max_reasoning_steps = ${max_reasoning_steps}$,
|
||||
max_tool_calls_per_step = ${max_tool_calls_per_step}$,
|
||||
enable_cross_session_search = ${enable_cross_session_search}$,
|
||||
enable_skill_auto_loading = ${enable_skill_auto_loading}$,
|
||||
safety_mode = ${safety_mode}$,
|
||||
max_context_tokens = ${max_context_tokens}$,
|
||||
enable_error_recovery = ${enable_error_recovery}$,
|
||||
max_recovery_attempts = ${max_recovery_attempts}$,
|
||||
updated_at = ${updated_at}$
|
||||
WHERE id = ${id}$""", {
|
||||
'id': config_id,
|
||||
'max_reasoning_steps': max_reasoning_steps,
|
||||
'max_tool_calls_per_step': max_tool_calls_per_step,
|
||||
'enable_cross_session_search': enable_cross_session_search,
|
||||
'enable_skill_auto_loading': enable_skill_auto_loading,
|
||||
'safety_mode': safety_mode,
|
||||
'max_context_tokens': max_context_tokens,
|
||||
'enable_error_recovery': enable_error_recovery,
|
||||
'max_recovery_attempts': max_recovery_attempts,
|
||||
'updated_at': now
|
||||
})
|
||||
else:
|
||||
config_id = str(uuid.uuid4()).replace('-', '')[:32]
|
||||
await sor.sqlExe("""INSERT INTO harnessed_reasoning_config
|
||||
(id, user_id, max_reasoning_steps, max_tool_calls_per_step,
|
||||
enable_cross_session_search, enable_skill_auto_loading, safety_mode,
|
||||
max_context_tokens, enable_error_recovery, max_recovery_attempts,
|
||||
created_at, updated_at)
|
||||
VALUES (${id}$, ${user_id}$, ${max_reasoning_steps}$, ${max_tool_calls_per_step}$,
|
||||
${enable_cross_session_search}$, ${enable_skill_auto_loading}$, ${safety_mode}$,
|
||||
${max_context_tokens}$, ${enable_error_recovery}$, ${max_recovery_attempts}$,
|
||||
${created_at}$, ${updated_at}$)""", {
|
||||
'id': config_id,
|
||||
'user_id': user_id,
|
||||
'max_reasoning_steps': max_reasoning_steps,
|
||||
'max_tool_calls_per_step': max_tool_calls_per_step,
|
||||
'enable_cross_session_search': enable_cross_session_search,
|
||||
'enable_skill_auto_loading': enable_skill_auto_loading,
|
||||
'safety_mode': safety_mode,
|
||||
'max_context_tokens': max_context_tokens,
|
||||
'enable_error_recovery': enable_error_recovery,
|
||||
'max_recovery_attempts': max_recovery_attempts,
|
||||
'created_at': now,
|
||||
'updated_at': now
|
||||
})
|
||||
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '配置保存成功', 'type': 'success'}}
|
||||
|
||||
except Exception as e:
|
||||
result['options'] = {'title': 'Error', 'message': '保存失败: ' + str(e), 'type': 'error'}
|
||||
|
||||
return json.dumps(result, ensure_ascii=False)
|
||||
35
wwwroot/api/sessions_list.dspy
Normal file
35
wwwroot/api/sessions_list.dspy
Normal file
@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Reasoning sessions list API"""
|
||||
import json
|
||||
|
||||
result = {'success': False, 'rows': [], 'total': 0}
|
||||
|
||||
try:
|
||||
dbname = get_module_dbname('harnessed_reasoning')
|
||||
ns = {
|
||||
'page': int(params_kw.get('page', 1)),
|
||||
'rows': int(params_kw.get('rows', 20)),
|
||||
'sort': 'created_at desc'
|
||||
}
|
||||
user_id = await get_user()
|
||||
|
||||
sql = """SELECT id, initial_request, context_summary, status, created_at, updated_at
|
||||
FROM harnessed_reasoning_sessions
|
||||
WHERE user_id = ${user_id}$
|
||||
ORDER BY created_at DESC"""
|
||||
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
data = await sor.sqlExe(sql, {'user_id': user_id})
|
||||
if isinstance(data, dict):
|
||||
result['total'] = data.get('total', 0)
|
||||
result['rows'] = [dict(r) for r in data.get('rows', [])]
|
||||
else:
|
||||
result['rows'] = [dict(r) for r in (data or [])]
|
||||
result['total'] = len(result['rows'])
|
||||
result['success'] = True
|
||||
|
||||
except Exception as e:
|
||||
result['error'] = str(e)
|
||||
|
||||
return json.dumps(result, ensure_ascii=False, default=str)
|
||||
89
wwwroot/harnessed_reasoning_config_view.ui
Normal file
89
wwwroot/harnessed_reasoning_config_view.ui
Normal file
@ -0,0 +1,89 @@
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"width": "100%",
|
||||
"height": "100%",
|
||||
"padding": "16px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Form",
|
||||
"id": "config_form",
|
||||
"options": {
|
||||
"data_url": "{{entire_url('api/config_get.dspy')}}",
|
||||
"data_method": "GET",
|
||||
"submit_url": "{{entire_url('api/config_save.dspy')}}",
|
||||
"method": "POST",
|
||||
"layout": "vertical",
|
||||
"fields": [
|
||||
{
|
||||
"name": "max_reasoning_steps",
|
||||
"label": "最大推理步骤数",
|
||||
"uitype": "int",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "max_tool_calls_per_step",
|
||||
"label": "每步最大工具调用数",
|
||||
"uitype": "int",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "enable_cross_session_search",
|
||||
"label": "启用跨会话搜索",
|
||||
"uitype": "check"
|
||||
},
|
||||
{
|
||||
"name": "enable_skill_auto_loading",
|
||||
"label": "启用技能自动加载",
|
||||
"uitype": "check"
|
||||
},
|
||||
{
|
||||
"name": "safety_mode",
|
||||
"label": "安全模式",
|
||||
"uitype": "code",
|
||||
"required": true,
|
||||
"data": [
|
||||
{"value": "strict", "text": "严格"},
|
||||
{"value": "moderate", "text": "中等"},
|
||||
{"value": "lenient", "text": "宽松"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "max_context_tokens",
|
||||
"label": "最大上下文 token 数",
|
||||
"uitype": "int",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "enable_error_recovery",
|
||||
"label": "启用错误恢复",
|
||||
"uitype": "check"
|
||||
},
|
||||
{
|
||||
"name": "max_recovery_attempts",
|
||||
"label": "最大恢复尝试次数",
|
||||
"uitype": "int",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"buttons": [
|
||||
{
|
||||
"type": "submit",
|
||||
"label": "保存配置",
|
||||
"variant": "primary"
|
||||
}
|
||||
],
|
||||
"maxWidth": "500px"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "submited",
|
||||
"actiontype": "script",
|
||||
"script": "await bricks.show_resp_message_or_error(event.params)"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
38
wwwroot/harnessed_reasoning_sessions_crud.ui
Normal file
38
wwwroot/harnessed_reasoning_sessions_crud.ui
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"widgettype": "Tabular",
|
||||
"options": {
|
||||
"width": "100%",
|
||||
"height": "100%",
|
||||
"data_url": "{{entire_url('api/sessions_list.dspy')}}",
|
||||
"data_method": "GET",
|
||||
"page_rows": 20,
|
||||
"row_options": {
|
||||
"fields": [
|
||||
{"name": "id", "width": 80, "frozen": true},
|
||||
{"name": "initial_request", "title": "请求内容", "width": 300},
|
||||
{"name": "context_summary", "title": "上下文摘要", "width": 200},
|
||||
{
|
||||
"name": "status",
|
||||
"title": "状态",
|
||||
"width": 100,
|
||||
"uitype": "code",
|
||||
"data": [
|
||||
{"value": "pending", "text": "待处理"},
|
||||
{"value": "executing", "text": "执行中"},
|
||||
{"value": "completed", "text": "已完成"},
|
||||
{"value": "failed", "text": "失败"},
|
||||
{"value": "blocked", "text": "已阻止"},
|
||||
{"value": "cancelled", "text": "已取消"}
|
||||
]
|
||||
},
|
||||
{"name": "created_at", "title": "创建时间", "width": 160}
|
||||
],
|
||||
"editexclouded": ["id"]
|
||||
},
|
||||
"editable": {
|
||||
"new_data_url": null,
|
||||
"update_data_url": null,
|
||||
"delete_data_url": null
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,7 @@
|
||||
"options": {
|
||||
"width": "100%",
|
||||
"height": "100%",
|
||||
"css": ""
|
||||
"padding": "0"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
@ -12,47 +12,57 @@
|
||||
"css": "ios-navbar",
|
||||
"items": [
|
||||
{
|
||||
"widgettype": "Label",
|
||||
"text": "Reasoning Engine",
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"css": "ios-navbar-title"
|
||||
"text": "Reasoning Engine",
|
||||
"css": "ios-navbar-title",
|
||||
"fontSize": "18px",
|
||||
"fontWeight": "bold",
|
||||
"color": "#1E40AF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Label",
|
||||
"text": "Manage sessions and system configuration",
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"css": "ios-navbar-subtitle"
|
||||
"text": "Manage sessions and system configuration",
|
||||
"css": "ios-navbar-subtitle",
|
||||
"fontSize": "12px",
|
||||
"color": "#6B7280"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Tab",
|
||||
"widgettype": "TabPanel",
|
||||
"options": {
|
||||
"tabs": [
|
||||
{"title": "Sessions", "icon": "history"},
|
||||
{"title": "Configuration", "icon": "settings"}
|
||||
],
|
||||
"css": "ios-tabbar"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "urlwidget",
|
||||
"options": {
|
||||
"url": "{{entire_url(harnessed_reasoning_sessions_crud)}}",
|
||||
"css": "ios-card"
|
||||
"tab_pos": "top",
|
||||
"css": "tabpanel",
|
||||
"items": [
|
||||
{
|
||||
"name": "sessions",
|
||||
"label": "推理会话",
|
||||
"icon": "history",
|
||||
"content": {
|
||||
"widgettype": "urlwidget",
|
||||
"options": {
|
||||
"url": "{{entire_url('harnessed_reasoning_sessions_crud')}}"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "config",
|
||||
"label": "推理配置",
|
||||
"icon": "settings",
|
||||
"content": {
|
||||
"widgettype": "urlwidget",
|
||||
"options": {
|
||||
"url": "{{entire_url('harnessed_reasoning_config_view')}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "urlwidget",
|
||||
"options": {
|
||||
"url": "{{entire_url(harnessed_reasoning_config_view)}}",
|
||||
"css": "ios-card"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -10,22 +10,12 @@
|
||||
"cwidth":10,
|
||||
"items":[
|
||||
{% if get_user() %}
|
||||
{
|
||||
"name":"reasoning_console",
|
||||
"label":"推理控制台",
|
||||
"url":"{{entire_url('/harnessed_reasoning/hermes_reasoning')}}"
|
||||
},
|
||||
{
|
||||
"name":"reasoning_sessions",
|
||||
"label":"推理会话",
|
||||
"url":"{{entire_url('/harnessed_reasoning/sessions')}}"
|
||||
},
|
||||
{
|
||||
"name":"reasoning_config",
|
||||
"label":"推理配置",
|
||||
"url":"{{entire_url('/harnessed_reasoning/config')}}"
|
||||
}
|
||||
{
|
||||
"name":"hermes_reasoning",
|
||||
"label":"推理控制台",
|
||||
"url":"{{entire_url('hermes_reasoning.ui')}}"
|
||||
}
|
||||
{% endif %}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user