添加代理执行和模型配置:创建代理执行控制台UI和API,扩展config模型添加default_model/default_temperature/enable_streaming字段

This commit is contained in:
yumoqing 2026-05-06 15:05:57 +08:00
parent ee4b416b50
commit 3e33bc0924
8 changed files with 439 additions and 20 deletions

View File

@ -80,6 +80,29 @@
"nullable": "no", "nullable": "no",
"default": "30" "default": "30"
}, },
{
"name": "default_model",
"title": "Default LLM model for agent tasks",
"type": "str",
"length": 64,
"nullable": "yes",
"default": "qwen3-max"
},
{
"name": "default_temperature",
"title": "Default temperature for LLM calls",
"type": "float",
"nullable": "no",
"default": "0.7"
},
{
"name": "enable_streaming",
"title": "Enable streaming response for LLM calls",
"type": "str",
"length": "1",
"nullable": "no",
"default": "1"
},
{ {
"name": "created_at", "name": "created_at",
"title": "Creation timestamp", "title": "Creation timestamp",

View File

@ -12,10 +12,14 @@
"css": "ios-navbar", "css": "ios-navbar",
"items": [ "items": [
{ {
"text": "Configuration", "widgettype": "Text",
"icon": "settings", "options": {
"css": "ios-navbar-title", "text": "Configuration",
"disabled": true "css": "ios-navbar-title",
"fontSize": "18px",
"fontWeight": "bold",
"color": "#059669"
}
} }
] ]
} }
@ -23,7 +27,7 @@
{ {
"widgettype": "urlwidget", "widgettype": "urlwidget",
"options": { "options": {
"url": "{{entire_url('harnessed_agent_config_view')}}", "url": "{{entire_url('agent_config_form.ui')}}",
"width": "100%", "width": "100%",
"height": "100%" "height": "100%"
} }

View File

@ -0,0 +1,114 @@
{
"widgettype": "TabPanel",
"options": {
"tab_pos": "top",
"items": [
{
"name": "agent_config",
"label": "代理配置",
"icon": "settings",
"content": {
"widgettype": "VBox",
"options": {
"padding": "16px"
},
"subwidgets": [
{
"widgettype": "Form",
"id": "agent_config_form",
"options": {
"data_url": "{{entire_url('../api/agent_config_get.dspy')}}",
"data_method": "GET",
"submit_url": "{{entire_url('../api/agent_config_save.dspy')}}",
"method": "POST",
"layout": "vertical",
"fields": [
{
"name": "work_dir",
"label": "工作目录",
"uitype": "text",
"required": true
},
{
"name": "skills_path",
"label": "技能路径",
"uitype": "text",
"required": true
},
{
"name": "max_memory_tokens",
"label": "最大记忆 token 数",
"uitype": "int",
"required": true
},
{
"name": "default_priority",
"label": "默认优先级",
"uitype": "int",
"required": true
},
{
"name": "high_priority_threshold",
"label": "高优先级阈值",
"uitype": "int",
"required": true
},
{
"name": "low_priority_threshold",
"label": "低优先级阈值",
"uitype": "int",
"required": true
},
{
"name": "auto_cleanup_enabled",
"label": "启用自动清理",
"uitype": "check"
},
{
"name": "min_retention_days",
"label": "最小保留天数",
"uitype": "int",
"required": true
},
{
"name": "default_model",
"label": "默认模型",
"uitype": "text",
"placeholder": "qwen3-max"
},
{
"name": "default_temperature",
"label": "默认温度",
"uitype": "float",
"required": true
},
{
"name": "enable_streaming",
"label": "启用流式输出",
"uitype": "check"
}
],
"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)"
}
]
}
]
}
}
]
}
}

88
wwwroot/agent_console.ui Normal file
View File

@ -0,0 +1,88 @@
{
"widgettype": "VBox",
"options": {
"width": "100%",
"height": "100%",
"padding": "16px",
"spacing": "16px"
},
"subwidgets": [
{
"widgettype": "Text",
"options": {
"text": "代理执行控制台",
"fontSize": "20px",
"fontWeight": "bold",
"color": "#059669"
}
},
{
"widgettype": "Form",
"id": "agent_execute_form",
"options": {
"submit_url": "{{entire_url('api/agent_execute.dspy')}}",
"method": "POST",
"layout": "vertical",
"fields": [
{
"name": "tool_name",
"label": "工具名称",
"uitype": "text",
"required": true,
"placeholder": "例如: memory, skill_view, terminal, read_file"
},
{
"name": "parameters",
"label": "工具参数 (JSON)",
"uitype": "textarea",
"rows": 6,
"placeholder": "{\"key\": \"value\"}"
}
],
"buttons": [
{
"type": "submit",
"label": "执行工具",
"variant": "primary"
}
],
"maxWidth": "700px"
},
"binds": [
{
"wid": "self",
"event": "submited",
"actiontype": "script",
"script": "await bricks.show_resp_message_or_error(event.params)"
}
]
},
{
"widgettype": "VBox",
"options": {
"width": "100%",
"padding": "16px"
},
"subwidgets": [
{
"widgettype": "Text",
"options": {
"text": "可用工具列表",
"fontSize": "16px",
"fontWeight": "bold",
"color": "#374151",
"marginBottom": "8px"
}
},
{
"widgettype": "Text",
"options": {
"text": "memory: 保存和检索记忆 | skill_view: 查看技能 | skill_manage: 管理技能 | session_search: 搜索历史会话 | delegate_task: 委托任务 | execute_code: 执行代码 | terminal: 运行命令 | read_file: 读取文件 | write_file: 写入文件 | search_files: 搜索文件 | patch: 修改文件 | vision_analyze: 图像分析 | cronjob: 定时任务 | todo: 任务管理",
"fontSize": "12px",
"color": "#6B7280"
}
}
]
}
]
}

View File

@ -0,0 +1,43 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Get agent configuration for current user"""
import json
result = {'success': False, 'config': {}}
try:
dbname = get_module_dbname('harnessed_agent')
user_id = await get_user()
sql = """SELECT * FROM harnessed_agent_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])
config['auto_cleanup_enabled'] = config.get('auto_cleanup_enabled', '1') == '1'
config['enable_streaming'] = config.get('enable_streaming', '1') == '1'
result['config'] = config
else:
result['config'] = {
'work_dir': './hermes_work',
'skills_path': '~/.hermes/skills',
'max_memory_tokens': 2000,
'default_priority': 50,
'high_priority_threshold': 70,
'low_priority_threshold': 30,
'auto_cleanup_enabled': True,
'min_retention_days': 30,
'default_model': 'qwen3-max',
'default_temperature': 0.7,
'enable_streaming': True
}
result['success'] = True
except Exception as e:
result['error'] = str(e)
return json.dumps(result, ensure_ascii=False, default=str)

View File

@ -0,0 +1,91 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Save agent 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_agent')
user_id = await get_user()
now = time.strftime('%Y-%m-%d %H:%M:%S')
work_dir = params_kw.get('work_dir', './hermes_work').strip()
skills_path = params_kw.get('skills_path', '~/.hermes/skills').strip()
max_memory_tokens = int(params_kw.get('max_memory_tokens', 2000))
default_priority = int(params_kw.get('default_priority', 50))
high_priority_threshold = int(params_kw.get('high_priority_threshold', 70))
low_priority_threshold = int(params_kw.get('low_priority_threshold', 30))
auto_cleanup_enabled = '1' if params_kw.get('auto_cleanup_enabled') == '1' else '0'
min_retention_days = int(params_kw.get('min_retention_days', 30))
default_model = params_kw.get('default_model', 'qwen3-max').strip()
default_temperature = float(params_kw.get('default_temperature', 0.7))
enable_streaming = '1' if params_kw.get('enable_streaming') == '1' else '0'
async with DBPools().sqlorContext(dbname) as sor:
rows = await sor.sqlExe("SELECT id FROM harnessed_agent_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_agent_config SET
work_dir = ${work_dir}$,
skills_path = ${skills_path}$,
max_memory_tokens = ${max_memory_tokens}$,
default_priority = ${default_priority}$,
high_priority_threshold = ${high_priority_threshold}$,
low_priority_threshold = ${low_priority_threshold}$,
auto_cleanup_enabled = ${auto_cleanup_enabled}$,
min_retention_days = ${min_retention_days}$,
default_model = ${default_model}$,
default_temperature = ${default_temperature}$,
enable_streaming = ${enable_streaming}$,
updated_at = ${updated_at}$
WHERE id = ${id}$""", {
'id': config_id,
'work_dir': work_dir,
'skills_path': skills_path,
'max_memory_tokens': max_memory_tokens,
'default_priority': default_priority,
'high_priority_threshold': high_priority_threshold,
'low_priority_threshold': low_priority_threshold,
'auto_cleanup_enabled': auto_cleanup_enabled,
'min_retention_days': min_retention_days,
'default_model': default_model,
'default_temperature': default_temperature,
'enable_streaming': enable_streaming,
'updated_at': now
})
else:
config_id = str(uuid.uuid4()).replace('-', '')[:32]
await sor.sqlExe("""INSERT INTO harnessed_agent_config
(id, user_id, work_dir, skills_path, max_memory_tokens,
default_priority, high_priority_threshold, low_priority_threshold,
auto_cleanup_enabled, min_retention_days, default_model,
default_temperature, enable_streaming, created_at, updated_at)
VALUES (${id}$, ${user_id}$, ${work_dir}$, ${skills_path}$, ${max_memory_tokens}$,
${default_priority}$, ${high_priority_threshold}$, ${low_priority_threshold}$,
${auto_cleanup_enabled}$, ${min_retention_days}$, ${default_model}$,
${default_temperature}$, ${enable_streaming}$, ${created_at}$, ${updated_at}$)""", {
'id': config_id,
'user_id': user_id,
'work_dir': work_dir,
'skills_path': skills_path,
'max_memory_tokens': max_memory_tokens,
'default_priority': default_priority,
'high_priority_threshold': high_priority_threshold,
'low_priority_threshold': low_priority_threshold,
'auto_cleanup_enabled': auto_cleanup_enabled,
'min_retention_days': min_retention_days,
'default_model': default_model,
'default_temperature': default_temperature,
'enable_streaming': enable_streaming,
'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)

View File

@ -0,0 +1,51 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Execute agent task - call tool/skill with given parameters"""
import json, time
result = {'widgettype': 'Message', 'options': {'title': 'Error', 'message': 'Invalid request', 'type': 'error'}}
try:
tool_name = params_kw.get('tool_name', '').strip()
parameters = params_kw.get('parameters', '{}').strip()
if not tool_name:
result['options'] = {'title': 'Error', 'message': '请指定工具名称', 'type': 'error'}
else:
user_id = await get_user()
try:
tool_params = json.loads(parameters)
except:
tool_params = {}
context = {'user_id': user_id}
# Call agent tool execution
exec_result = await harnessed_execute_tool(
tool_name=tool_name,
parameters=tool_params,
context=context
)
if exec_result.get('success'):
output = json.dumps(exec_result, ensure_ascii=False, indent=2)
result = {
'widgettype': 'Message',
'options': {
'title': '执行成功',
'message': f'工具: {tool_name}\n\n结果:\n{output}',
'type': 'success'
}
}
else:
result['options'] = {
'title': '执行失败',
'message': exec_result.get('error', '未知错误'),
'type': 'error'
}
except Exception as e:
result['options'] = {'title': 'Error', 'message': '执行异常: ' + str(e), 'type': 'error'}
return json.dumps(result, ensure_ascii=False)

View File

@ -10,6 +10,21 @@
"cwidth":10, "cwidth":10,
"items":[ "items":[
{% if get_user() %} {% if get_user() %}
{
"name":"hermes_agent",
"label":"代理控制台",
"url":"{{entire_url('/harnessed_agent/hermes_agent.ui')}}"
},
{
"name":"agent_console",
"label":"代理执行",
"url":"{{entire_url('/harnessed_agent/agent_console.ui')}}"
},
{
"name":"agent_config",
"label":"代理配置",
"url":"{{entire_url('/harnessed_agent/agent_config.ui')}}"
},
{ {
"name":"sessions", "name":"sessions",
"label":"会话管理", "label":"会话管理",
@ -25,31 +40,21 @@
"label":"记忆管理", "label":"记忆管理",
"url":"{{entire_url('/harnessed_agent/hermes_memory')}}" "url":"{{entire_url('/harnessed_agent/hermes_memory')}}"
}, },
{
"name":"tasks",
"label":"任务管理",
"url":"{{entire_url('/harnessed_agent/hermes_tasks')}}"
},
{ {
"name":"workflows", "name":"workflows",
"label":"工作流管理", "label":"工作流管理",
"url":"{{entire_url('/harnessed_agent/hermes_workflows')}}" "url":"{{entire_url('/harnessed_agent/hermes_workflows')}}"
}, },
{
"name":"tasks",
"label":"任务管理",
"url":"{{entire_url('/harnessed_agent/hermes_tasks')}}"
},
{ {
"name":"remote_skills", "name":"remote_skills",
"label":"远程技能", "label":"远程技能",
"url":"{{entire_url('/harnessed_agent/harnessed_remote_skills')}}" "url":"{{entire_url('/harnessed_agent/harnessed_remote_skills')}}"
}, },
{
"name":"agent_config",
"label":"代理配置",
"url":"{{entire_url('/harnessed_agent/harnessed_agent_config_view')}}"
},
{
"name":"hermes_agent",
"label":"代理控制台",
"url":"{{entire_url('/harnessed_agent/hermes_agent.ui')}}"
},
{ {
"name":"tools", "name":"tools",
"label":"工具管理", "label":"工具管理",