myagent-ai 1.27.4 → 1.27.5
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 +1 -1
- package/web/api_server.py +93 -178
package/package.json
CHANGED
package/web/api_server.py
CHANGED
|
@@ -1819,8 +1819,8 @@ window.addEventListener('beforeunload', function() {{
|
|
|
1819
1819
|
if not message:
|
|
1820
1820
|
return web.json_response({"error": "message is required"}, status=400)
|
|
1821
1821
|
|
|
1822
|
-
agent_name = data.get("agent_name", "
|
|
1823
|
-
# 支持 path 格式 (如 "
|
|
1822
|
+
agent_name = data.get("agent_name", "1") or "1"
|
|
1823
|
+
# 支持 path 格式 (如 "3")
|
|
1824
1824
|
agent_path = data.get("agent_path", agent_name)
|
|
1825
1825
|
# 获取数字 agent_id
|
|
1826
1826
|
agent_id = self.core.memory.get_agent_id(agent_path)
|
|
@@ -1984,7 +1984,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
1984
1984
|
if not message and not user_images and not user_files:
|
|
1985
1985
|
return web.Response(text="data: " + json.dumps({"error": "message is required"}) + "\n\n", content_type="text/event-stream")
|
|
1986
1986
|
|
|
1987
|
-
agent_path = data.get("agent_path", data.get("agent_name", "
|
|
1987
|
+
agent_path = data.get("agent_path", data.get("agent_name", "1")) or "1"
|
|
1988
1988
|
# [v1.23.35] 直接使用前端传来的 session_id,不再拼接 agent_path 前缀
|
|
1989
1989
|
session_id = data.get("session_id", "") or "web_default"
|
|
1990
1990
|
chat_mode = data.get("mode", "")
|
|
@@ -2375,7 +2375,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
2375
2375
|
if not message:
|
|
2376
2376
|
return web.json_response({"error": "message is required"}, status=400)
|
|
2377
2377
|
|
|
2378
|
-
agent_path = data.get("agent_path", "
|
|
2378
|
+
agent_path = data.get("agent_path", "1") or "1"
|
|
2379
2379
|
# [v1.23.35] 直接使用前端传来的 session_id,不再拼接 agent_path 前缀
|
|
2380
2380
|
session_id = data.get("session_id", "web_default")
|
|
2381
2381
|
choice = data.get("choice", "queue") # "continue" (插入后继续) 或 "queue" (排队)
|
|
@@ -2423,7 +2423,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
2423
2423
|
if not raw_text:
|
|
2424
2424
|
return web.json_response({"error": "text is required"}, status=400)
|
|
2425
2425
|
|
|
2426
|
-
agent_path = data.get("agent_path", "
|
|
2426
|
+
agent_path = data.get("agent_path", "1") or "1"
|
|
2427
2427
|
session_id = data.get("session_id", "")
|
|
2428
2428
|
chat_mode = data.get("mode", "")
|
|
2429
2429
|
|
|
@@ -3071,7 +3071,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
3071
3071
|
优先使用 session_id 查找(与聊天流存储键一致),
|
|
3072
3072
|
回退到 agent_path 查找(手动创建的任务)。
|
|
3073
3073
|
"""
|
|
3074
|
-
agent_path = request.query.get("agent", "
|
|
3074
|
+
agent_path = request.query.get("agent", "1")
|
|
3075
3075
|
session_id = request.query.get("session", "")
|
|
3076
3076
|
# 优先按 session_id 查找(聊天流生成的任务列表存储在此键下)
|
|
3077
3077
|
if session_id:
|
|
@@ -3085,7 +3085,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
3085
3085
|
async def handle_update_task_plan(self, request):
|
|
3086
3086
|
"""PUT /api/task-plan - Overwrite entire task list."""
|
|
3087
3087
|
data = await request.json()
|
|
3088
|
-
agent_path = data.get("agent", "
|
|
3088
|
+
agent_path = data.get("agent", "1")
|
|
3089
3089
|
session_id = data.get("session", "")
|
|
3090
3090
|
tasks = data.get("tasks", [])
|
|
3091
3091
|
# 优先按 session_id 存储(与聊天流一致),回退到 agent_path
|
|
@@ -3096,7 +3096,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
3096
3096
|
async def handle_add_task_item(self, request):
|
|
3097
3097
|
"""POST /api/task-plan - Add a new task item."""
|
|
3098
3098
|
data = await request.json()
|
|
3099
|
-
agent_path = data.get("agent", "
|
|
3099
|
+
agent_path = data.get("agent", "1")
|
|
3100
3100
|
session_id = data.get("session", "")
|
|
3101
3101
|
text = data.get("text", "").strip()
|
|
3102
3102
|
if not text:
|
|
@@ -3111,7 +3111,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
3111
3111
|
async def handle_delete_task_item(self, request):
|
|
3112
3112
|
"""DELETE /api/task-plan/{idx} - Delete task by index."""
|
|
3113
3113
|
idx = int(request.match_info["idx"])
|
|
3114
|
-
agent_path = request.query.get("agent", "
|
|
3114
|
+
agent_path = request.query.get("agent", "1")
|
|
3115
3115
|
session_id = request.query.get("session", "")
|
|
3116
3116
|
# 优先按 session_id 查找,回退到 agent_path
|
|
3117
3117
|
store_key = session_id or agent_path
|
|
@@ -3157,32 +3157,29 @@ window.addEventListener('beforeunload', function() {{
|
|
|
3157
3157
|
return web.json_response({"ok": True})
|
|
3158
3158
|
|
|
3159
3159
|
# --- Agents (层级体系) ---
|
|
3160
|
-
# 目录结构: agents/
|
|
3161
|
-
# agents/
|
|
3162
|
-
#
|
|
3163
|
-
# agent path = 相对于 agents/ 的路径, 如 "default", "coder", "coder/python-expert"
|
|
3160
|
+
# 目录结构: agents/1/{config.json, soul.md, ...}
|
|
3161
|
+
# agents/2/{config.json, soul.md, ...}
|
|
3162
|
+
# agent path = agent ID, 如 "1", "2", "3"
|
|
3164
3163
|
|
|
3165
3164
|
def _agents_dir(self):
|
|
3166
3165
|
d = self.core.config_mgr.data_dir / "agents"
|
|
3167
3166
|
d.mkdir(parents=True, exist_ok=True)
|
|
3168
3167
|
return d
|
|
3169
3168
|
|
|
3170
|
-
def _agent_dir(self,
|
|
3171
|
-
"""根据 agent
|
|
3172
|
-
return self._agents_dir() /
|
|
3169
|
+
def _agent_dir(self, aid: str) -> Path:
|
|
3170
|
+
"""根据 agent ID 返回目录 (aid 如 '1', '2')"""
|
|
3171
|
+
return self._agents_dir() / aid
|
|
3173
3172
|
|
|
3174
3173
|
def _ensure_default_agent(self):
|
|
3175
|
-
"""确保默认 agent
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
if (ad / "config.json").exists():
|
|
3179
|
-
self._migrate_agent_config("default", "全权Agent")
|
|
3180
|
-
# 迁移后再次检查(损坏文件可能已被删除)
|
|
3174
|
+
"""确保默认 agent 存在(ID=1,名为「全权Agent」,目录名=1)"""
|
|
3175
|
+
aid = "1"
|
|
3176
|
+
ad = self._agent_dir(aid)
|
|
3181
3177
|
if not (ad / "config.json").exists():
|
|
3182
3178
|
ad.mkdir(parents=True, exist_ok=True)
|
|
3183
3179
|
now = _now_iso()
|
|
3184
3180
|
cfg = {
|
|
3185
|
-
"id":
|
|
3181
|
+
"id": 1,
|
|
3182
|
+
"path": aid,
|
|
3186
3183
|
"name": "全权Agent",
|
|
3187
3184
|
"description": "全权Agent - 拥有完整权限的本地助手",
|
|
3188
3185
|
"avatar_color": _agent_color("全权Agent"),
|
|
@@ -3203,49 +3200,26 @@ window.addEventListener('beforeunload', function() {{
|
|
|
3203
3200
|
if not (ad / fn).exists():
|
|
3204
3201
|
(ad / fn).write_text(default, encoding="utf-8")
|
|
3205
3202
|
logger.info("已创建默认 Agent (全权Agent)")
|
|
3206
|
-
else:
|
|
3207
|
-
# 即使已存在也同步其基本配置(如系统提示词可能更新)
|
|
3208
|
-
self._migrate_agent_config("default")
|
|
3209
3203
|
|
|
3210
3204
|
self._ensure_config_helper()
|
|
3211
3205
|
|
|
3212
|
-
def _migrate_agent_config(self,
|
|
3213
|
-
"""为旧 agent config
|
|
3214
|
-
cfg_file = self._agent_dir(
|
|
3206
|
+
def _migrate_agent_config(self, aid: str):
|
|
3207
|
+
"""为旧 agent config 补全缺失字段"""
|
|
3208
|
+
cfg_file = self._agent_dir(aid) / "config.json"
|
|
3215
3209
|
if not cfg_file.exists():
|
|
3216
3210
|
return
|
|
3217
3211
|
try:
|
|
3218
3212
|
cfg = json.loads(cfg_file.read_text(encoding="utf-8"))
|
|
3219
3213
|
except (json.JSONDecodeError, ValueError):
|
|
3220
|
-
logger.warning(f"Agent config JSON
|
|
3221
|
-
try:
|
|
3222
|
-
cfg_file.unlink()
|
|
3223
|
-
except OSError:
|
|
3224
|
-
pass
|
|
3225
|
-
# 如果是 default 或配置助手,由 _ensure_default_agent / _ensure_config_helper 重建
|
|
3226
|
-
if path in ("default", "配置助手", "p"):
|
|
3227
|
-
return
|
|
3228
|
-
# 其他 agent:创建一个最小 config
|
|
3229
|
-
ad = self._agent_dir(path)
|
|
3230
|
-
if ad.exists():
|
|
3231
|
-
now = _now_iso()
|
|
3232
|
-
cfg = {
|
|
3233
|
-
"id": next_agent_id(),
|
|
3234
|
-
"name": path,
|
|
3235
|
-
"description": "",
|
|
3236
|
-
"avatar_emoji": "🤖",
|
|
3237
|
-
"execution_mode": "sandbox",
|
|
3238
|
-
"enabled": True,
|
|
3239
|
-
"created_at": now,
|
|
3240
|
-
"updated_at": now,
|
|
3241
|
-
}
|
|
3242
|
-
cfg_file.write_text(json.dumps(cfg, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
3243
|
-
logger.info(f"已重建 Agent 配置: {path}")
|
|
3214
|
+
logger.warning(f"Agent config JSON 解析失败: {aid}")
|
|
3244
3215
|
return
|
|
3245
3216
|
changed = False
|
|
3246
3217
|
now = _now_iso()
|
|
3247
3218
|
if "id" not in cfg:
|
|
3248
|
-
cfg["id"] = next_agent_id()
|
|
3219
|
+
cfg["id"] = int(aid) if aid.isdigit() else next_agent_id()
|
|
3220
|
+
changed = True
|
|
3221
|
+
if "path" not in cfg:
|
|
3222
|
+
cfg["path"] = aid
|
|
3249
3223
|
changed = True
|
|
3250
3224
|
if "created_at" not in cfg:
|
|
3251
3225
|
cfg["created_at"] = now
|
|
@@ -3253,25 +3227,19 @@ window.addEventListener('beforeunload', function() {{
|
|
|
3253
3227
|
if "updated_at" not in cfg:
|
|
3254
3228
|
cfg["updated_at"] = now
|
|
3255
3229
|
changed = True
|
|
3256
|
-
# 修正旧 default agent 的名字
|
|
3257
|
-
if intended_name and cfg.get("name") == "default":
|
|
3258
|
-
cfg["name"] = intended_name
|
|
3259
|
-
changed = True
|
|
3260
3230
|
if changed:
|
|
3261
3231
|
cfg_file.write_text(json.dumps(cfg, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
3262
3232
|
|
|
3263
3233
|
def _ensure_config_helper(self):
|
|
3264
|
-
"""确保系统级「配置助手」agent
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
if (ad / "config.json").exists():
|
|
3268
|
-
self._migrate_agent_config("配置助手")
|
|
3269
|
-
# 迁移后再次检查(损坏文件可能已被删除)
|
|
3234
|
+
"""确保系统级「配置助手」agent 存在(ID=2,目录名=2)"""
|
|
3235
|
+
aid = "2"
|
|
3236
|
+
ad = self._agent_dir(aid)
|
|
3270
3237
|
if not (ad / "config.json").exists():
|
|
3271
3238
|
ad.mkdir(parents=True, exist_ok=True)
|
|
3272
3239
|
now = _now_iso()
|
|
3273
3240
|
cfg = {
|
|
3274
|
-
"id":
|
|
3241
|
+
"id": 2,
|
|
3242
|
+
"path": aid,
|
|
3275
3243
|
"name": "配置助手",
|
|
3276
3244
|
"description": "MyAgent 智能配置助手 - 内置系统Agent,帮助用户完成初始配置和日常配置管理",
|
|
3277
3245
|
"avatar_color": "#4f46e5",
|
|
@@ -3304,21 +3272,12 @@ window.addEventListener('beforeunload', function() {{
|
|
|
3304
3272
|
except Exception as e:
|
|
3305
3273
|
logger.warning(f"同步配置助手提示词失败: {e}")
|
|
3306
3274
|
|
|
3307
|
-
# 创建快捷方式 p -> 配置助手(符号链接)
|
|
3308
|
-
p_dir = self._agent_dir("p")
|
|
3309
|
-
if not p_dir.exists() and ad.exists():
|
|
3310
|
-
try:
|
|
3311
|
-
# 在 agents 目录下创建 p -> 配置助手 的符号链接
|
|
3312
|
-
p_dir.symlink_to(ad)
|
|
3313
|
-
logger.info("已创建配置助手快捷方式: p -> 配置助手")
|
|
3314
|
-
except OSError as e:
|
|
3315
|
-
logger.debug(f"创建快捷方式 p 失败(非关键): {e}")
|
|
3316
3275
|
# 自动绑定知识库:将 配置使用说明.md 复制到配置助手的知识库目录
|
|
3317
3276
|
self._bind_config_helper_kb()
|
|
3318
3277
|
|
|
3319
3278
|
def _bind_config_helper_kb(self):
|
|
3320
3279
|
"""将 docs/配置使用说明.md 绑定到配置助手的知识库目录"""
|
|
3321
|
-
kb_dir = self._get_agent_knowledge_dir("
|
|
3280
|
+
kb_dir = self._get_agent_knowledge_dir("2")
|
|
3322
3281
|
kb_dir.mkdir(parents=True, exist_ok=True)
|
|
3323
3282
|
target = kb_dir / "配置使用说明.md"
|
|
3324
3283
|
|
|
@@ -3351,8 +3310,8 @@ window.addEventListener('beforeunload', function() {{
|
|
|
3351
3310
|
target.write_text(content, encoding="utf-8")
|
|
3352
3311
|
logger.info(f"配置助手知识库已绑定: {source} -> {target}")
|
|
3353
3312
|
# 刷新 RAG 索引
|
|
3354
|
-
if hasattr(self, '_agent_rags') and "
|
|
3355
|
-
self._agent_rags["
|
|
3313
|
+
if hasattr(self, '_agent_rags') and "2" in self._agent_rags:
|
|
3314
|
+
self._agent_rags["2"].build_index()
|
|
3356
3315
|
else:
|
|
3357
3316
|
logger.warning(f"未找到 配置使用说明.md 源文件,已搜索: {[str(c) for c in source_candidates]}")
|
|
3358
3317
|
|
|
@@ -3416,56 +3375,43 @@ window.addEventListener('beforeunload', function() {{
|
|
|
3416
3375
|
|
|
3417
3376
|
return user_message, agent_system_prompt
|
|
3418
3377
|
|
|
3419
|
-
def _scan_agents_flat(self
|
|
3420
|
-
"""
|
|
3421
|
-
|
|
3422
|
-
base_dir = self._agents_dir()
|
|
3378
|
+
def _scan_agents_flat(self) -> list[dict]:
|
|
3379
|
+
"""扫描所有 agent 目录,返回扁平列表(目录名即为 agent ID)"""
|
|
3380
|
+
base_dir = self._agents_dir()
|
|
3423
3381
|
agents = []
|
|
3424
3382
|
if not base_dir.exists():
|
|
3425
3383
|
return agents
|
|
3426
3384
|
for d in sorted(base_dir.iterdir()):
|
|
3427
|
-
if not d.is_dir():
|
|
3385
|
+
if not d.is_dir() or d.is_symlink():
|
|
3428
3386
|
continue
|
|
3429
3387
|
cfg_file = d / "config.json"
|
|
3430
3388
|
if not cfg_file.exists():
|
|
3431
3389
|
continue
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
if
|
|
3390
|
+
aid = d.name
|
|
3391
|
+
self._migrate_agent_config(aid)
|
|
3392
|
+
if not cfg_file.exists():
|
|
3435
3393
|
continue
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
cfg = json.loads(cfg_file.read_text(encoding="utf-8"))
|
|
3444
|
-
except (json.JSONDecodeError, ValueError):
|
|
3445
|
-
logger.warning(f"Agent config JSON 解析失败,跳过: {agent_path}")
|
|
3446
|
-
continue
|
|
3447
|
-
agent = {"path": agent_path, "name": d.name, **cfg}
|
|
3448
|
-
agent["avatar_color"] = cfg.get("avatar_color") or _agent_color(d.name)
|
|
3449
|
-
agent["depth"] = agent_path.count("/")
|
|
3450
|
-
# [v1.20.13] 自动检测 avatar.png 文件,补全 avatar_image 字段
|
|
3394
|
+
try:
|
|
3395
|
+
cfg = json.loads(cfg_file.read_text(encoding="utf-8"))
|
|
3396
|
+
except (json.JSONDecodeError, ValueError):
|
|
3397
|
+
continue
|
|
3398
|
+
agent = {"path": aid, "id": int(aid) if aid.isdigit() else cfg.get("id", aid), "name": cfg.get("name", aid), **cfg}
|
|
3399
|
+
agent["avatar_color"] = cfg.get("avatar_color") or _agent_color(cfg.get("name", aid))
|
|
3400
|
+
# [v1.20.13] 自动检测 avatar.png
|
|
3451
3401
|
if not agent.get("avatar_image") and (d / "avatar.png").exists():
|
|
3452
|
-
agent["avatar_image"] = f"/api/agents/{
|
|
3402
|
+
agent["avatar_image"] = f"/api/agents/{aid}/avatar.png"
|
|
3453
3403
|
agents.append(agent)
|
|
3454
|
-
# 递归子目录
|
|
3455
|
-
agents.extend(self._scan_agents_flat(d, agent_path))
|
|
3456
3404
|
return agents
|
|
3457
3405
|
|
|
3458
3406
|
def _build_agent_tree(self, agents_flat: list[dict]) -> list[dict]:
|
|
3459
|
-
"""将扁平 agent
|
|
3460
|
-
|
|
3461
|
-
by_path = {a["path"]: {**a, "children": []} for a in agents_flat}
|
|
3407
|
+
"""将扁平 agent 列表构建为树结构(通过 parent 字段关联)"""
|
|
3408
|
+
by_id = {a["path"]: {**a, "children": []} for a in agents_flat}
|
|
3462
3409
|
roots = []
|
|
3463
3410
|
for a in agents_flat:
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
by_path[parent_path]["children"].append(node)
|
|
3411
|
+
parent = a.get("parent", "")
|
|
3412
|
+
node = by_id[a["path"]]
|
|
3413
|
+
if parent and parent in by_id:
|
|
3414
|
+
by_id[parent]["children"].append(node)
|
|
3469
3415
|
else:
|
|
3470
3416
|
roots.append(node)
|
|
3471
3417
|
return roots
|
|
@@ -3525,13 +3471,15 @@ window.addEventListener('beforeunload', function() {{
|
|
|
3525
3471
|
if "/" in name or "\\" in name or name == "default":
|
|
3526
3472
|
return web.json_response({"error": "invalid name (no slashes, cannot be 'default')"}, status=400)
|
|
3527
3473
|
|
|
3528
|
-
|
|
3474
|
+
aid = str(next_agent_id())
|
|
3475
|
+
ad = self._agent_dir(aid)
|
|
3529
3476
|
if (ad / "config.json").exists():
|
|
3530
3477
|
return web.json_response({"error": f"Agent '{name}' already exists"}, status=409)
|
|
3531
3478
|
|
|
3532
3479
|
now = _now_iso()
|
|
3533
3480
|
cfg = {
|
|
3534
|
-
"id":
|
|
3481
|
+
"id": int(aid),
|
|
3482
|
+
"path": aid,
|
|
3535
3483
|
"name": name,
|
|
3536
3484
|
"description": data.get("description", ""),
|
|
3537
3485
|
"avatar_color": data.get("avatar_color") or _agent_color(name),
|
|
@@ -3576,13 +3524,13 @@ window.addEventListener('beforeunload', function() {{
|
|
|
3576
3524
|
if data.get("department"):
|
|
3577
3525
|
try:
|
|
3578
3526
|
dm = self._get_dept_manager()
|
|
3579
|
-
dm.assign_agent(data["department"], agents=[
|
|
3527
|
+
dm.assign_agent(data["department"], agents=[aid], action="add")
|
|
3580
3528
|
logger.info(f"Agent {name} 已自动分配到部门: {data['department']}")
|
|
3581
3529
|
except Exception as e:
|
|
3582
3530
|
logger.warning(f"自动分配 Agent {name} 到部门失败: {e}")
|
|
3583
3531
|
|
|
3584
|
-
logger.info(f"创建 Agent: {name} (
|
|
3585
|
-
return web.json_response({"ok": True, "path":
|
|
3532
|
+
logger.info(f"创建 Agent: {name} (ID={aid})")
|
|
3533
|
+
return web.json_response({"ok": True, "path": aid, "id": int(aid), "name": name, "avatar_color": cfg["avatar_color"]})
|
|
3586
3534
|
|
|
3587
3535
|
async def handle_create_child(self, request):
|
|
3588
3536
|
"""POST /api/agents/{parent}/children - 创建子 agent"""
|
|
@@ -3601,11 +3549,14 @@ window.addEventListener('beforeunload', function() {{
|
|
|
3601
3549
|
return web.json_response({"error": "invalid name (no slashes)"}, status=400)
|
|
3602
3550
|
|
|
3603
3551
|
child_path = f"{parent_path}/{name}"
|
|
3604
|
-
|
|
3552
|
+
child_aid = str(next_agent_id())
|
|
3553
|
+
ad = self._agent_dir(child_aid)
|
|
3605
3554
|
if (ad / "config.json").exists():
|
|
3606
|
-
return web.json_response({"error": f"Agent '{
|
|
3555
|
+
return web.json_response({"error": f"Agent '{name}' already exists"}, status=409)
|
|
3607
3556
|
|
|
3608
3557
|
cfg = {
|
|
3558
|
+
"id": int(child_aid),
|
|
3559
|
+
"path": child_aid,
|
|
3609
3560
|
"name": name,
|
|
3610
3561
|
"parent": parent_path,
|
|
3611
3562
|
"description": data.get("description", ""),
|
|
@@ -3641,30 +3592,18 @@ window.addEventListener('beforeunload', function() {{
|
|
|
3641
3592
|
if not (ad / fn).exists():
|
|
3642
3593
|
(ad / fn).write_text(default, encoding="utf-8")
|
|
3643
3594
|
|
|
3644
|
-
logger.info(f"创建子 Agent: {
|
|
3645
|
-
return web.json_response({"ok": True, "path":
|
|
3595
|
+
logger.info(f"创建子 Agent: {name} (ID={child_aid}, parent={parent_path})")
|
|
3596
|
+
return web.json_response({"ok": True, "path": child_aid, "id": int(child_aid), "name": name, "parent": parent_path, "avatar_color": cfg["avatar_color"]})
|
|
3646
3597
|
|
|
3647
3598
|
async def handle_list_children(self, request):
|
|
3648
|
-
"""GET /api/agents/{parent}/children - 列出子 agent"""
|
|
3599
|
+
"""GET /api/agents/{parent}/children - 列出子 agent(通过 parent 字段)"""
|
|
3649
3600
|
parent_path = request.match_info["name"]
|
|
3650
|
-
|
|
3651
|
-
if not
|
|
3601
|
+
parent_cfg = self._read_agent_config(parent_path)
|
|
3602
|
+
if not parent_cfg:
|
|
3652
3603
|
return web.json_response({"error": f"Agent '{parent_path}' not found"}, status=404)
|
|
3653
3604
|
|
|
3654
|
-
|
|
3655
|
-
if
|
|
3656
|
-
for d in sorted(parent_dir.iterdir()):
|
|
3657
|
-
if d.is_dir() and (d / "config.json").exists():
|
|
3658
|
-
try:
|
|
3659
|
-
cfg = json.loads((d / "config.json").read_text(encoding="utf-8"))
|
|
3660
|
-
except (json.JSONDecodeError, ValueError):
|
|
3661
|
-
logger.warning(f"Agent config JSON 解析失败,跳过: {parent_path}/{d.name}")
|
|
3662
|
-
continue
|
|
3663
|
-
child_path = f"{parent_path}/{d.name}"
|
|
3664
|
-
child = {"path": child_path, "name": d.name, "parent": parent_path, **cfg}
|
|
3665
|
-
child["avatar_color"] = cfg.get("avatar_color") or _agent_color(d.name)
|
|
3666
|
-
child["depth"] = child_path.count("/")
|
|
3667
|
-
children.append(child)
|
|
3605
|
+
all_agents = self._scan_agents_flat()
|
|
3606
|
+
children = [a for a in all_agents if a.get("parent") == parent_path]
|
|
3668
3607
|
return web.json_response(children)
|
|
3669
3608
|
|
|
3670
3609
|
async def handle_get_agent(self, request):
|
|
@@ -3719,8 +3658,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
3719
3658
|
return web.json_response({"error": "config.json 解析失败"}, status=500)
|
|
3720
3659
|
|
|
3721
3660
|
# 系统 Agent(内置 Agent)保护:核心字段不可修改
|
|
3722
|
-
|
|
3723
|
-
is_system = cfg.get("system") or path in ("p",)
|
|
3661
|
+
is_system = cfg.get("system") or path in ("1", "2")
|
|
3724
3662
|
if is_system:
|
|
3725
3663
|
blocked = [k for k in data if k in self._SYSTEM_AGENT_PROTECTED_FIELDS]
|
|
3726
3664
|
if blocked:
|
|
@@ -3772,39 +3710,16 @@ window.addEventListener('beforeunload', function() {{
|
|
|
3772
3710
|
if "soul" in data and not is_system: (ad / "soul.md").write_text(data["soul"], encoding="utf-8")
|
|
3773
3711
|
if "identity" in data and not is_system: (ad / "identity.md").write_text(data["identity"], encoding="utf-8")
|
|
3774
3712
|
if "user" in data: (ad / "user.md").write_text(data["user"], encoding="utf-8")
|
|
3775
|
-
#
|
|
3776
|
-
new_name = data.get("name")
|
|
3777
|
-
renamed_to = None
|
|
3778
|
-
if new_name and new_name != path and not is_system:
|
|
3779
|
-
agents_dir = self._agents_dir()
|
|
3780
|
-
new_ad = agents_dir / new_name
|
|
3781
|
-
if not new_ad.exists():
|
|
3782
|
-
ad.rename(new_ad)
|
|
3783
|
-
logger.info(f"Agent 目录已重命名: {path} -> {new_name}")
|
|
3784
|
-
renamed_to = new_name
|
|
3785
|
-
# [v1.20.2] 重命名后更新 avatar_image URL 中的路径
|
|
3786
|
-
old_avatar = cfg.get("avatar_image", "")
|
|
3787
|
-
if old_avatar and f"/api/agents/{path}/" in old_avatar:
|
|
3788
|
-
cfg["avatar_image"] = old_avatar.replace(f"/api/agents/{path}/", f"/api/agents/{new_name}/")
|
|
3789
|
-
(new_ad / "config.json").write_text(
|
|
3790
|
-
json.dumps(cfg, indent=2, ensure_ascii=False), encoding="utf-8"
|
|
3791
|
-
)
|
|
3792
|
-
else:
|
|
3793
|
-
logger.warning(f"目标目录已存在,无法重命名: {new_name}")
|
|
3713
|
+
# 名字改变不再需要重命名目录(目录名是 agent ID,与名字无关)
|
|
3794
3714
|
logger.info(f"更新 Agent: {path}")
|
|
3795
|
-
|
|
3796
|
-
if renamed_to:
|
|
3797
|
-
result["renamed_to"] = renamed_to
|
|
3798
|
-
return web.json_response(result)
|
|
3715
|
+
return web.json_response({"ok": True, "hot_reload": True})
|
|
3799
3716
|
|
|
3800
3717
|
async def handle_delete_agent(self, request):
|
|
3801
3718
|
"""DELETE /api/agents/{path} - 删除 agent 及其所有子 agent"""
|
|
3802
3719
|
path = request.match_info["name"]
|
|
3803
|
-
if path
|
|
3804
|
-
return web.json_response({"error": "cannot delete default agent"}, status=403)
|
|
3805
|
-
if path in ("配置助手", "p"):
|
|
3720
|
+
if path in ("1", "2"):
|
|
3806
3721
|
return web.json_response({
|
|
3807
|
-
"error":
|
|
3722
|
+
"error": "系统 Agent 不可删除",
|
|
3808
3723
|
"agent_path": path,
|
|
3809
3724
|
}, status=403)
|
|
3810
3725
|
ad = self._agent_dir(path)
|
|
@@ -4318,7 +4233,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
4318
4233
|
if agent:
|
|
4319
4234
|
# [v1.27.2] 先将 agent 路径转为数字 ID,用数字 ID 精确过滤
|
|
4320
4235
|
target_aid = self.core.memory.get_agent_id(agent) if agent else 0
|
|
4321
|
-
if agent == "
|
|
4236
|
+
if agent == "1":
|
|
4322
4237
|
# default agent: agent_id=0(未分配)或 agent_id=1(default 的数字 ID)或 旧格式
|
|
4323
4238
|
rows = conn.execute(
|
|
4324
4239
|
f"""SELECT DISTINCT session_id, COUNT(*) as cnt, MAX(created_at) as last,
|
|
@@ -4387,7 +4302,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
4387
4302
|
return web.json_response({"agent": name, "sessions": []})
|
|
4388
4303
|
# [v1.27.2] 使用数字 agent_id 精确过滤,同时兼容旧数据
|
|
4389
4304
|
target_aid = self.core.memory.get_agent_id(name)
|
|
4390
|
-
if name == "
|
|
4305
|
+
if name == "1":
|
|
4391
4306
|
# default agent: agent_id=0 或 agent_id=1 或 旧格式
|
|
4392
4307
|
rows = self.core.memory._get_conn().execute(
|
|
4393
4308
|
"""SELECT DISTINCT session_id, COUNT(*) as cnt, MAX(created_at) as last FROM memories
|
|
@@ -5472,7 +5387,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
5472
5387
|
else:
|
|
5473
5388
|
# 兜底到全局默认 LLM 配置
|
|
5474
5389
|
chain.append({
|
|
5475
|
-
"id": "
|
|
5390
|
+
"id": "1",
|
|
5476
5391
|
"name": llm_defaults.model,
|
|
5477
5392
|
"provider": llm_defaults.provider,
|
|
5478
5393
|
"api_type": llm_defaults.api_type,
|
|
@@ -5664,7 +5579,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
5664
5579
|
self.core.main_agent._agent_override_path = agent_path
|
|
5665
5580
|
# [v1.23.52] 为非默认 Agent 设置独立工作目录(executor 层面)
|
|
5666
5581
|
_original_exec_work_dir = None
|
|
5667
|
-
if agent_path and agent_path != "
|
|
5582
|
+
if agent_path and agent_path != "1" and self.core.main_agent and self.core.main_agent.executor:
|
|
5668
5583
|
from config import ConfigManager
|
|
5669
5584
|
_cm = ConfigManager()
|
|
5670
5585
|
_agent_wd = _cm.data_dir / "agents" / agent_path / "workspace"
|
|
@@ -5993,7 +5908,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
5993
5908
|
_original_exec_mode = agent.executor.execution_mode
|
|
5994
5909
|
agent.executor.set_execution_mode(_exec_mode)
|
|
5995
5910
|
# [v1.23.52] 为非默认 Agent 设置独立工作目录
|
|
5996
|
-
if agent_path and agent_path != "
|
|
5911
|
+
if agent_path and agent_path != "1" and agent.executor:
|
|
5997
5912
|
from config import ConfigManager
|
|
5998
5913
|
cm = ConfigManager()
|
|
5999
5914
|
agent_work_dir = cm.data_dir / "agents" / agent_path / "workspace"
|
|
@@ -7142,14 +7057,14 @@ window.addEventListener('beforeunload', function() {{
|
|
|
7142
7057
|
needs_setup = not config.llm.api_key
|
|
7143
7058
|
# 确保配置助手存在
|
|
7144
7059
|
self._ensure_config_helper()
|
|
7145
|
-
helper_exists = (self._agent_dir("
|
|
7060
|
+
helper_exists = (self._agent_dir("2") / "config.json").exists()
|
|
7146
7061
|
return web.json_response({
|
|
7147
7062
|
"needs_setup": needs_setup,
|
|
7148
7063
|
"helper_exists": helper_exists,
|
|
7149
7064
|
"has_api_key": bool(config.llm.api_key),
|
|
7150
7065
|
"provider": config.llm.provider,
|
|
7151
7066
|
"model": config.llm.model,
|
|
7152
|
-
"default_agent": "
|
|
7067
|
+
"default_agent": "1",
|
|
7153
7068
|
})
|
|
7154
7069
|
|
|
7155
7070
|
async def handle_setup_complete(self, request):
|
|
@@ -7298,7 +7213,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
7298
7213
|
def _check_org_admin(self, agent_path: str = "") -> bool:
|
|
7299
7214
|
"""检查 agent 是否是组织知识库管理员"""
|
|
7300
7215
|
org_cfg = self.core.config.organization
|
|
7301
|
-
admin = org_cfg.knowledge_admin or "
|
|
7216
|
+
admin = org_cfg.knowledge_admin or "1"
|
|
7302
7217
|
return agent_path == admin
|
|
7303
7218
|
|
|
7304
7219
|
async def handle_get_organization(self, request):
|
|
@@ -7358,7 +7273,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
7358
7273
|
async def handle_upload_org_knowledge(self, request):
|
|
7359
7274
|
"""POST /api/organization/knowledge/upload - 上传文件到组织知识库(支持文件和文件夹上传)"""
|
|
7360
7275
|
# 权限检查
|
|
7361
|
-
agent = request.query.get("agent", "
|
|
7276
|
+
agent = request.query.get("agent", "1")
|
|
7362
7277
|
if not self._check_org_admin(agent):
|
|
7363
7278
|
return web.json_response(
|
|
7364
7279
|
{"ok": False, "error": "权限不足:只有知识库管理员才能上传"},
|
|
@@ -7386,7 +7301,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
7386
7301
|
async def handle_delete_org_knowledge(self, request):
|
|
7387
7302
|
"""DELETE /api/organization/knowledge?path=xxx - 删除组织知识库文件"""
|
|
7388
7303
|
# 权限检查
|
|
7389
|
-
agent = request.query.get("agent", "
|
|
7304
|
+
agent = request.query.get("agent", "1")
|
|
7390
7305
|
if not self._check_org_admin(agent):
|
|
7391
7306
|
return web.json_response(
|
|
7392
7307
|
{"ok": False, "error": "权限不足:只有知识库管理员才能删除"},
|
|
@@ -7728,7 +7643,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
7728
7643
|
name = data.get("name", "").strip()
|
|
7729
7644
|
if not name:
|
|
7730
7645
|
return web.json_response({"error": "群名不能为空"}, status=400)
|
|
7731
|
-
owner = data.get("owner", "
|
|
7646
|
+
owner = data.get("owner", "1")
|
|
7732
7647
|
description = data.get("description", "")
|
|
7733
7648
|
avatar_emoji = data.get("avatar_emoji", "👥")
|
|
7734
7649
|
avatar_color = data.get("avatar_color", "")
|
|
@@ -9042,7 +8957,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
9042
8957
|
return web.json_response({"error": "invalid JSON"}, status=400)
|
|
9043
8958
|
|
|
9044
8959
|
text = data.get("text", "")
|
|
9045
|
-
agent_path = data.get("agent_path", "
|
|
8960
|
+
agent_path = data.get("agent_path", "1") or "1"
|
|
9046
8961
|
filename = data.get("filename", "").strip()
|
|
9047
8962
|
|
|
9048
8963
|
if not text:
|