myagent-ai 1.27.5 → 1.27.7
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/agents/main_agent.py +5 -5
- package/communication/channel.py +2 -2
- package/communication/peer.py +1 -1
- package/config.py +8 -8
- package/core/agent_storage.py +3 -3
- package/core/context_builder.py +9 -9
- package/core/context_manager.py +2 -2
- package/core/llm.py +3 -3
- package/core/task_persistence.py +1 -1
- package/core/tool_dispatcher.py +12 -12
- package/core/web_control.py +3 -3
- package/groups/manager.py +5 -5
- package/package.json +2 -2
- package/web/api_server.py +46 -47
- package/web/ui/admin/admin-memory.js +3 -3
- package/web/ui/chat/chat_main.js +2 -2
- package/web/ui/chat/flow_engine.js +11 -11
- package/web/ui/chat/groupchat.js +2 -2
package/agents/main_agent.py
CHANGED
|
@@ -226,9 +226,9 @@ class MainAgent(BaseAgent):
|
|
|
226
226
|
def init_context_builder(self, memory_manager=None, skill_registry=None, knowledge_base_dir=None, context_window=None):
|
|
227
227
|
"""初始化 Context Builder(在系统启动后调用,注入依赖)"""
|
|
228
228
|
if context_window is None and self.llm:
|
|
229
|
-
context_window = getattr(self.llm, 'context_window',
|
|
229
|
+
context_window = getattr(self.llm, 'context_window', 200000)
|
|
230
230
|
if context_window is None:
|
|
231
|
-
context_window =
|
|
231
|
+
context_window = 200000
|
|
232
232
|
self.context_builder = ContextBuilder(
|
|
233
233
|
memory_manager=memory_manager,
|
|
234
234
|
skill_registry=skill_registry,
|
|
@@ -562,7 +562,7 @@ class MainAgent(BaseAgent):
|
|
|
562
562
|
auto_kb_dir.mkdir(parents=True, exist_ok=True)
|
|
563
563
|
|
|
564
564
|
# 使用 session_id 作为文件名(取前8位避免过长)
|
|
565
|
-
# 注意: session_id 可能包含 '/' (
|
|
565
|
+
# 注意: session_id 可能包含 '/' (来自旧版 agent_path 格式),
|
|
566
566
|
# 必须替换为安全字符,避免创建意外的子目录
|
|
567
567
|
safe_session = session_id.replace("-", "").replace("/", "_")[:12] if session_id else "default"
|
|
568
568
|
kb_file = auto_kb_dir / f"{safe_session}.md"
|
|
@@ -667,7 +667,7 @@ class MainAgent(BaseAgent):
|
|
|
667
667
|
stream_callback: 可选的 SSE 事件回调 (callable 或 async callable)
|
|
668
668
|
stream_response: 可选的流式响应对象(用于 LLM 流式输出)
|
|
669
669
|
text_delta_callback: 可选的文本增量回调
|
|
670
|
-
agent_path: Agent
|
|
670
|
+
agent_path: Agent 的数字 aid(用于独立工作目录)
|
|
671
671
|
"""
|
|
672
672
|
task_id = context.task_id or generate_id("task")
|
|
673
673
|
context.task_id = task_id
|
|
@@ -1264,7 +1264,7 @@ class MainAgent(BaseAgent):
|
|
|
1264
1264
|
logger.info(f"[{task_id}] 会话自动命名: {subject}")
|
|
1265
1265
|
await self._emit_v2_event(
|
|
1266
1266
|
"v2_session_rename",
|
|
1267
|
-
{"
|
|
1267
|
+
{"sid": context.session_id, "name": subject},
|
|
1268
1268
|
stream_callback,
|
|
1269
1269
|
)
|
|
1270
1270
|
except Exception as e:
|
package/communication/channel.py
CHANGED
|
@@ -38,8 +38,8 @@ class Message:
|
|
|
38
38
|
"""A communication message between agents."""
|
|
39
39
|
|
|
40
40
|
id: str = ""
|
|
41
|
-
from_agent: str = "" # Sender
|
|
42
|
-
to_agent: str = "" # Recipient
|
|
41
|
+
from_agent: str = "" # Sender 的数字 aid
|
|
42
|
+
to_agent: str = "" # Recipient 的数字 aid
|
|
43
43
|
content: str = "" # Plaintext content
|
|
44
44
|
timestamp: float = 0.0
|
|
45
45
|
encrypted: bool = False
|
package/communication/peer.py
CHANGED
|
@@ -16,7 +16,7 @@ from typing import Optional, List, Dict
|
|
|
16
16
|
class Peer:
|
|
17
17
|
"""Represents a known remote/local agent peer."""
|
|
18
18
|
|
|
19
|
-
agent_id: str #
|
|
19
|
+
agent_id: str # Agent 的数字 aid(如 "1", "2")或对端标识
|
|
20
20
|
public_key: str # Ed25519 public key (hex, 64 chars)
|
|
21
21
|
display_name: str = "" # Human-readable name
|
|
22
22
|
added_at: float = 0.0 # Unix timestamp
|
package/config.py
CHANGED
|
@@ -27,9 +27,9 @@ class LLMConfig:
|
|
|
27
27
|
api_key: str = ""
|
|
28
28
|
base_url: str = "https://api.openai.com/v1"
|
|
29
29
|
model: str = "gpt-4"
|
|
30
|
-
temperature: float = 0.
|
|
31
|
-
max_tokens: int =
|
|
32
|
-
context_window: int =
|
|
30
|
+
temperature: float = 0.8
|
|
31
|
+
max_tokens: int = 10240
|
|
32
|
+
context_window: int = 200000 # 上下文窗口大小
|
|
33
33
|
input_modes: List[str] = field(default_factory=lambda: ["text"]) # 支持的输入模式
|
|
34
34
|
reasoning: bool = False # 是否支持推理
|
|
35
35
|
timeout: int = 120 # 请求超时(秒)
|
|
@@ -94,9 +94,9 @@ class ModelEntry:
|
|
|
94
94
|
model: str = "" # API 调用使用的实际模型字符串
|
|
95
95
|
base_url: str = "" # 自定义 Base URL(空=使用 provider 默认值)
|
|
96
96
|
api_key: str = "" # 专用 API Key(空=使用全局默认值)
|
|
97
|
-
max_tokens: int =
|
|
98
|
-
temperature: float = 0.
|
|
99
|
-
context_window: int =
|
|
97
|
+
max_tokens: int = 10240
|
|
98
|
+
temperature: float = 0.8
|
|
99
|
+
context_window: int = 200000 # 上下文窗口大小(token)
|
|
100
100
|
input_modes: List[str] = field(default_factory=lambda: ["text"]) # 支持的输入模式: text, image, video, audio
|
|
101
101
|
reasoning: bool = True # 是否支持推理(如 o1 系列)
|
|
102
102
|
enabled: bool = True
|
|
@@ -133,8 +133,8 @@ class CommunicationConfig:
|
|
|
133
133
|
"""Agent 间通信配置"""
|
|
134
134
|
enabled: bool = False # 默认不启用
|
|
135
135
|
server_url: str = "wss://aicq.online/ws" # AICQ 中继服务器
|
|
136
|
-
agent_id: str = "" #
|
|
137
|
-
private_key: str = "" #
|
|
136
|
+
agent_id: str = "" # Ed25519 公钥(持久化用,空=自动生成)
|
|
137
|
+
private_key: str = "" # Ed25519 私钥(持久化用,空=自动生成)
|
|
138
138
|
max_friends: int = 200
|
|
139
139
|
auto_accept: bool = False # 自动接受好友请求
|
|
140
140
|
|
package/core/agent_storage.py
CHANGED
|
@@ -35,8 +35,8 @@ logger = get_logger("myagent.agent_storage")
|
|
|
35
35
|
@dataclass
|
|
36
36
|
class AgentConfig:
|
|
37
37
|
"""Agent 配置(对应数据库一行)"""
|
|
38
|
-
path: str = "" # Agent
|
|
39
|
-
id: str = "" #
|
|
38
|
+
path: str = "" # Agent 路径 = 数字 aid,如 "1", "2", "3"
|
|
39
|
+
id: str = "" # 数字 Agent ID,自增整数
|
|
40
40
|
name: str = "" # 显示名称
|
|
41
41
|
description: str = "" # 描述
|
|
42
42
|
avatar_color: str = "" # 头像颜色
|
|
@@ -47,7 +47,7 @@ class AgentConfig:
|
|
|
47
47
|
system: bool = False # 是否系统内置 Agent
|
|
48
48
|
system_prompt: str = "" # 系统提示词
|
|
49
49
|
model: str = "" # 模型覆盖
|
|
50
|
-
parent: str = "" # 父 Agent
|
|
50
|
+
parent: str = "" # 父 Agent 的数字 aid
|
|
51
51
|
# 平台绑定
|
|
52
52
|
platform: str = "" # 平台标识
|
|
53
53
|
platform_token: str = "" # 平台 Token
|
package/core/context_builder.py
CHANGED
|
@@ -99,7 +99,7 @@ class ContextBuilder:
|
|
|
99
99
|
skill_registry: Optional["SkillRegistry"] = None,
|
|
100
100
|
knowledge_base_dir: Optional[str] = None,
|
|
101
101
|
max_dialog_chars: int = 20000,
|
|
102
|
-
context_window: int =
|
|
102
|
+
context_window: int = 200000,
|
|
103
103
|
) -> None:
|
|
104
104
|
self.memory_manager = memory_manager
|
|
105
105
|
self.skill_registry = skill_registry
|
|
@@ -144,7 +144,7 @@ class ContextBuilder:
|
|
|
144
144
|
用于 RAG 搜索知识库。为空时使用用户消息作为查询。
|
|
145
145
|
recall: 上一轮 LLM 输出的 <recall> 内容,
|
|
146
146
|
用于定向检索长期记忆。为空时仅用用户消息搜索。
|
|
147
|
-
agent_path: Agent
|
|
147
|
+
agent_path: Agent 的数字 aid(如 "1", "2"),用于定位独立工作目录。
|
|
148
148
|
|
|
149
149
|
Returns:
|
|
150
150
|
完整的 <context>...</context> XML 字符串
|
|
@@ -230,7 +230,7 @@ class ContextBuilder:
|
|
|
230
230
|
agent_name: Agent 名称
|
|
231
231
|
agent_description: Agent 描述
|
|
232
232
|
agent_override_prompt: 可选的覆盖提示词
|
|
233
|
-
agent_path: Agent
|
|
233
|
+
agent_path: Agent 的数字 aid(用于定位独立工作目录)
|
|
234
234
|
|
|
235
235
|
Returns:
|
|
236
236
|
<whomi> XML 段落字符串
|
|
@@ -259,9 +259,9 @@ class ContextBuilder:
|
|
|
259
259
|
def _get_workspace_dir(self, agent_path: Optional[str] = None) -> Optional[str]:
|
|
260
260
|
"""[v1.20.8] [v1.23.52] 获取工作目录路径
|
|
261
261
|
|
|
262
|
-
|
|
263
|
-
~/.myagent/data/agents/{
|
|
264
|
-
|
|
262
|
+
所有 Agent 均使用基于数字 aid 的独立工作目录:
|
|
263
|
+
~/.myagent/data/agents/{aid}/workspace/
|
|
264
|
+
无 agent_path 时返回全局工作目录:
|
|
265
265
|
~/.myagent/data/workspace/
|
|
266
266
|
独立目录下自动创建 userfiles 子目录。
|
|
267
267
|
"""
|
|
@@ -269,15 +269,15 @@ class ContextBuilder:
|
|
|
269
269
|
from config import ConfigManager
|
|
270
270
|
import os
|
|
271
271
|
cm = ConfigManager()
|
|
272
|
-
if agent_path
|
|
273
|
-
# 使用 Agent
|
|
272
|
+
if agent_path:
|
|
273
|
+
# 使用 Agent 独立工作目录(基于数字 aid)
|
|
274
274
|
wd = cm.data_dir / "agents" / agent_path / "workspace"
|
|
275
275
|
wd.mkdir(parents=True, exist_ok=True)
|
|
276
276
|
userfiles = wd / "userfiles"
|
|
277
277
|
userfiles.mkdir(parents=True, exist_ok=True)
|
|
278
278
|
return str(wd)
|
|
279
279
|
else:
|
|
280
|
-
#
|
|
280
|
+
# 无 agent_path 时使用全局工作目录
|
|
281
281
|
wd = cm.data_dir / "workspace"
|
|
282
282
|
wd.mkdir(parents=True, exist_ok=True)
|
|
283
283
|
return str(wd)
|
package/core/context_manager.py
CHANGED
|
@@ -47,8 +47,8 @@ class ContextBudget:
|
|
|
47
47
|
@dataclass
|
|
48
48
|
class ContextConfig:
|
|
49
49
|
"""上下文管理配置"""
|
|
50
|
-
# 模型上下文窗口大小 (token数), 默认
|
|
51
|
-
model_context_window: int =
|
|
50
|
+
# 模型上下文窗口大小 (token数), 默认200K
|
|
51
|
+
model_context_window: int = 200000
|
|
52
52
|
# 预算分配
|
|
53
53
|
budget: ContextBudget = field(default_factory=ContextBudget)
|
|
54
54
|
# 近期消息保留条数 (原始消息, 不压缩)
|
package/core/llm.py
CHANGED
|
@@ -132,13 +132,13 @@ class LLMClient:
|
|
|
132
132
|
api_key: str = "",
|
|
133
133
|
base_url: str = "",
|
|
134
134
|
model: str = "gpt-4",
|
|
135
|
-
temperature: float = 0.
|
|
136
|
-
max_tokens: int =
|
|
135
|
+
temperature: float = 0.8,
|
|
136
|
+
max_tokens: int = 10240,
|
|
137
137
|
timeout: int = 120,
|
|
138
138
|
max_retries: int = 3,
|
|
139
139
|
reasoning: bool = False,
|
|
140
140
|
reasoning_effort: str = "medium",
|
|
141
|
-
context_window: int =
|
|
141
|
+
context_window: int = 200000,
|
|
142
142
|
**kwargs,
|
|
143
143
|
):
|
|
144
144
|
self.provider = provider
|
package/core/task_persistence.py
CHANGED
package/core/tool_dispatcher.py
CHANGED
|
@@ -559,21 +559,21 @@ class ToolDispatcher:
|
|
|
559
559
|
if stream_callback:
|
|
560
560
|
await self._emit_sse("v2_web_control", {
|
|
561
561
|
"action": "open",
|
|
562
|
-
"
|
|
562
|
+
"sid": session_id,
|
|
563
563
|
"url": url,
|
|
564
564
|
"panel_url": f"/api/web_control/panel?sid={session_id}",
|
|
565
565
|
}, stream_callback)
|
|
566
566
|
return {
|
|
567
567
|
"success": True,
|
|
568
568
|
"output": f"已打开网页控制面板 (session: {session_id})" + (f",URL: {url}" if url else ""),
|
|
569
|
-
"
|
|
569
|
+
"sid": session_id,
|
|
570
570
|
}
|
|
571
571
|
|
|
572
572
|
elif action == "close":
|
|
573
573
|
wc_mgr.close_session(session_id)
|
|
574
574
|
if stream_callback:
|
|
575
575
|
await self._emit_sse("v2_web_control", {
|
|
576
|
-
"action": "close", "
|
|
576
|
+
"action": "close", "sid": session_id
|
|
577
577
|
}, stream_callback)
|
|
578
578
|
return {"success": True, "output": f"已关闭网页控制面板 (session: {session_id})"}
|
|
579
579
|
|
|
@@ -584,7 +584,7 @@ class ToolDispatcher:
|
|
|
584
584
|
session.current_url = url
|
|
585
585
|
if stream_callback:
|
|
586
586
|
await self._emit_sse("v2_web_control", {
|
|
587
|
-
"action": "navigate", "
|
|
587
|
+
"action": "navigate", "sid": session_id, "url": url
|
|
588
588
|
}, stream_callback)
|
|
589
589
|
return {"success": True, "output": f"正在导航到: {url}"}
|
|
590
590
|
|
|
@@ -631,7 +631,7 @@ class ToolDispatcher:
|
|
|
631
631
|
if stream_callback:
|
|
632
632
|
await self._emit_sse("v2_web_control", {
|
|
633
633
|
"action": "human_interact",
|
|
634
|
-
"
|
|
634
|
+
"sid": session_id,
|
|
635
635
|
"prompt": prompt,
|
|
636
636
|
"platform": platform,
|
|
637
637
|
"timeout": timeout,
|
|
@@ -654,7 +654,7 @@ class ToolDispatcher:
|
|
|
654
654
|
if stream_callback:
|
|
655
655
|
await self._emit_sse("v2_web_control", {
|
|
656
656
|
"action": "human_done",
|
|
657
|
-
"
|
|
657
|
+
"sid": session_id,
|
|
658
658
|
"timed_out": True,
|
|
659
659
|
}, stream_callback)
|
|
660
660
|
return {"success": False, "error": f"人机交互超时 ({timeout}s)"}
|
|
@@ -687,7 +687,7 @@ class ToolDispatcher:
|
|
|
687
687
|
if stream_callback:
|
|
688
688
|
await self._emit_sse("v2_web_control", {
|
|
689
689
|
"action": "human_done",
|
|
690
|
-
"
|
|
690
|
+
"sid": session_id,
|
|
691
691
|
}, stream_callback)
|
|
692
692
|
|
|
693
693
|
output_parts = [f"用户已完成人机交互操作"]
|
|
@@ -701,7 +701,7 @@ class ToolDispatcher:
|
|
|
701
701
|
return {
|
|
702
702
|
"success": True,
|
|
703
703
|
"output": "\n".join(output_parts),
|
|
704
|
-
"
|
|
704
|
+
"sid": session_id,
|
|
705
705
|
"cookies_saved": bool(cookie_file) and not cookie_file.startswith("("),
|
|
706
706
|
"cookie_file": cookie_file,
|
|
707
707
|
"data": result_data,
|
|
@@ -747,7 +747,7 @@ class ToolDispatcher:
|
|
|
747
747
|
if stream_callback:
|
|
748
748
|
await self._emit_sse("v2_web_control", {
|
|
749
749
|
"action": "login",
|
|
750
|
-
"
|
|
750
|
+
"sid": session_id,
|
|
751
751
|
"url": login_url,
|
|
752
752
|
"panel_url": f"/api/web_control/panel?sid={session_id}",
|
|
753
753
|
"platform": platform,
|
|
@@ -792,7 +792,7 @@ class ToolDispatcher:
|
|
|
792
792
|
pass
|
|
793
793
|
if stream_callback:
|
|
794
794
|
await self._emit_sse("v2_web_control", {
|
|
795
|
-
"action": "human_done", "
|
|
795
|
+
"action": "human_done", "sid": session_id, "timed_out": True,
|
|
796
796
|
}, stream_callback)
|
|
797
797
|
return {"success": False, "error": f"登录超时 ({timeout}s),请重试"}
|
|
798
798
|
|
|
@@ -839,7 +839,7 @@ class ToolDispatcher:
|
|
|
839
839
|
if stream_callback:
|
|
840
840
|
await self._emit_sse("v2_web_control", {
|
|
841
841
|
"action": "login_done",
|
|
842
|
-
"
|
|
842
|
+
"sid": session_id,
|
|
843
843
|
"platform": platform,
|
|
844
844
|
"login_success": login_success,
|
|
845
845
|
}, stream_callback)
|
|
@@ -861,7 +861,7 @@ class ToolDispatcher:
|
|
|
861
861
|
return {
|
|
862
862
|
"success": True,
|
|
863
863
|
"output": "\n".join(output_parts),
|
|
864
|
-
"
|
|
864
|
+
"sid": session_id,
|
|
865
865
|
"login_success": login_success,
|
|
866
866
|
"platform": platform,
|
|
867
867
|
"cookie_file": cookie_file,
|
package/core/web_control.py
CHANGED
|
@@ -94,7 +94,7 @@ CONTROL_SCRIPT = """
|
|
|
94
94
|
notifyParent('ready', {
|
|
95
95
|
url: window.location.href,
|
|
96
96
|
title: document.title,
|
|
97
|
-
|
|
97
|
+
sid: window.__webControlSessionId
|
|
98
98
|
});
|
|
99
99
|
}
|
|
100
100
|
|
|
@@ -672,7 +672,7 @@ class WebControlManager:
|
|
|
672
672
|
"""客户端轮询 — 返回待执行命令"""
|
|
673
673
|
session = self.get_session(session_id)
|
|
674
674
|
if not session:
|
|
675
|
-
return {"commands": [], "
|
|
675
|
+
return {"commands": [], "sid": session_id, "error": "Session not found"}
|
|
676
676
|
|
|
677
677
|
session.is_panel_open = True
|
|
678
678
|
session.touch()
|
|
@@ -684,7 +684,7 @@ class WebControlManager:
|
|
|
684
684
|
except asyncio.QueueEmpty:
|
|
685
685
|
break
|
|
686
686
|
|
|
687
|
-
return {"commands": commands, "
|
|
687
|
+
return {"commands": commands, "sid": session_id}
|
|
688
688
|
|
|
689
689
|
async def submit_result(self, session_id: str, cmd_id: str, result: Dict) -> bool:
|
|
690
690
|
"""客户端提交命令执行结果"""
|
package/groups/manager.py
CHANGED
|
@@ -30,7 +30,7 @@ logger = logging.getLogger("myagent.groups")
|
|
|
30
30
|
@dataclass
|
|
31
31
|
class GroupMember:
|
|
32
32
|
"""群成员"""
|
|
33
|
-
agent_path: str # Agent
|
|
33
|
+
agent_path: str # Agent 的数字 aid,如 "1", "2", "3"
|
|
34
34
|
role: str = "member" # owner | admin | member
|
|
35
35
|
joined_at: float = 0.0
|
|
36
36
|
nickname: str = "" # 群内昵称(空=使用agent默认名)
|
|
@@ -61,13 +61,13 @@ class GroupMessage:
|
|
|
61
61
|
"""群消息"""
|
|
62
62
|
id: str = ""
|
|
63
63
|
group_id: str = ""
|
|
64
|
-
sender: str = "" # "user" 或
|
|
64
|
+
sender: str = "" # "user" 或 agent 的数字 aid
|
|
65
65
|
sender_name: str = "" # 发送者显示名
|
|
66
66
|
sender_avatar: str = "" # 发送者头像emoji
|
|
67
67
|
content: str = ""
|
|
68
68
|
msg_type: str = "text" # text | system
|
|
69
69
|
timestamp: float = 0.0
|
|
70
|
-
agent_path: str = "" # 消息关联的 agent
|
|
70
|
+
agent_path: str = "" # 消息关联的 agent 的数字 aid
|
|
71
71
|
|
|
72
72
|
def to_dict(self) -> dict:
|
|
73
73
|
return {
|
|
@@ -466,7 +466,7 @@ class GroupManager:
|
|
|
466
466
|
|
|
467
467
|
Args:
|
|
468
468
|
group_id: 群ID
|
|
469
|
-
agent_path: 要添加的 agent
|
|
469
|
+
agent_path: 要添加的 agent 的数字 aid
|
|
470
470
|
role: 成员角色 (member | admin)
|
|
471
471
|
nickname: 群内昵称
|
|
472
472
|
operator: 操作者 agent_path
|
|
@@ -519,7 +519,7 @@ class GroupManager:
|
|
|
519
519
|
|
|
520
520
|
Args:
|
|
521
521
|
group_id: 群ID
|
|
522
|
-
agent_path: 要移除的 agent
|
|
522
|
+
agent_path: 要移除的 agent 的数字 aid
|
|
523
523
|
operator: 操作者 agent_path
|
|
524
524
|
|
|
525
525
|
Returns:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "myagent-ai",
|
|
3
|
-
"version": "1.27.
|
|
3
|
+
"version": "1.27.7",
|
|
4
4
|
"description": "本地桌面端执行型AI助手 - Open Interpreter 风格 | Local Desktop Execution-Oriented AI Assistant",
|
|
5
5
|
"main": "main.py",
|
|
6
6
|
"bin": {
|
|
@@ -43,4 +43,4 @@
|
|
|
43
43
|
"python": ">=3.10",
|
|
44
44
|
"node": ">=18"
|
|
45
45
|
}
|
|
46
|
-
}
|
|
46
|
+
}
|
package/web/api_server.py
CHANGED
|
@@ -1322,7 +1322,7 @@ function tryDirectConnect() {{
|
|
|
1322
1322
|
sessions = []
|
|
1323
1323
|
for sid, session in mgr.sessions.items():
|
|
1324
1324
|
sessions.append({
|
|
1325
|
-
"
|
|
1325
|
+
"sid": sid,
|
|
1326
1326
|
"current_url": session.current_url,
|
|
1327
1327
|
"is_panel_open": session.is_panel_open,
|
|
1328
1328
|
"created_at": session.created_at,
|
|
@@ -1336,16 +1336,16 @@ function tryDirectConnect() {{
|
|
|
1336
1336
|
session = mgr.create_session()
|
|
1337
1337
|
return web.json_response({
|
|
1338
1338
|
"success": True,
|
|
1339
|
-
"
|
|
1339
|
+
"sid": session.session_id,
|
|
1340
1340
|
"panel_url": f"/api/web_control/panel?sid={session.session_id}",
|
|
1341
1341
|
})
|
|
1342
1342
|
|
|
1343
1343
|
async def handle_wc_close_session(self, request):
|
|
1344
1344
|
"""POST /api/web_control/close - 关闭 Web Control 会话"""
|
|
1345
1345
|
data = await request.json() if request.content_type == 'application/json' else {}
|
|
1346
|
-
sid = data.get('session_id') or request.query.get('sid', '')
|
|
1346
|
+
sid = data.get('sid') or data.get('session_id') or request.query.get('sid', '')
|
|
1347
1347
|
if not sid:
|
|
1348
|
-
return web.json_response({"success": False, "error": "Missing
|
|
1348
|
+
return web.json_response({"success": False, "error": "Missing sid"}, status=400)
|
|
1349
1349
|
self._get_wc_manager().close_session(sid)
|
|
1350
1350
|
return web.json_response({"success": True})
|
|
1351
1351
|
|
|
@@ -1363,11 +1363,11 @@ function tryDirectConnect() {{
|
|
|
1363
1363
|
data = await request.json()
|
|
1364
1364
|
except:
|
|
1365
1365
|
return web.json_response({"success": False, "error": "Invalid JSON"}, status=400)
|
|
1366
|
-
sid = data.get('session_id', '')
|
|
1366
|
+
sid = data.get('sid') or data.get('session_id', '')
|
|
1367
1367
|
cmd_id = data.get('cmd_id', '')
|
|
1368
1368
|
result = data.get('result', {})
|
|
1369
1369
|
if not sid or not cmd_id:
|
|
1370
|
-
return web.json_response({"success": False, "error": "Missing
|
|
1370
|
+
return web.json_response({"success": False, "error": "Missing sid or cmd_id"}, status=400)
|
|
1371
1371
|
ok = await self._get_wc_manager().submit_result(sid, cmd_id, result)
|
|
1372
1372
|
return web.json_response({"success": ok})
|
|
1373
1373
|
|
|
@@ -1692,7 +1692,7 @@ function wcExecuteCommand(cmd) {{
|
|
|
1692
1692
|
return;
|
|
1693
1693
|
}}
|
|
1694
1694
|
if (cmd.action === 'close') {{
|
|
1695
|
-
window.parent.postMessage({{ __webControlPanel: true, action: 'close',
|
|
1695
|
+
window.parent.postMessage({{ __webControlPanel: true, action: 'close', sid: WC_SESSION_ID }}, '*');
|
|
1696
1696
|
wcSubmitResult({{ cmdId: cmd.id, success: true, closed: true }});
|
|
1697
1697
|
return;
|
|
1698
1698
|
}}
|
|
@@ -1718,7 +1718,7 @@ async function wcSubmitResult(resultData) {{
|
|
|
1718
1718
|
method: 'POST',
|
|
1719
1719
|
headers: {{ 'Content-Type': 'application/json' }},
|
|
1720
1720
|
body: JSON.stringify({{
|
|
1721
|
-
|
|
1721
|
+
sid: WC_SESSION_ID,
|
|
1722
1722
|
cmd_id: resultData.cmdId,
|
|
1723
1723
|
result: resultData
|
|
1724
1724
|
}})
|
|
@@ -1783,11 +1783,11 @@ if ('{initial_url}') {{
|
|
|
1783
1783
|
}}
|
|
1784
1784
|
|
|
1785
1785
|
// ── 通知父窗口面板已打开 ──
|
|
1786
|
-
window.parent.postMessage({{ __webControlPanel: true, action: 'opened',
|
|
1786
|
+
window.parent.postMessage({{ __webControlPanel: true, action: 'opened', sid: WC_SESSION_ID }}, '*');
|
|
1787
1787
|
|
|
1788
1788
|
// ── 页面卸载时清理 ──
|
|
1789
1789
|
window.addEventListener('beforeunload', function() {{
|
|
1790
|
-
window.parent.postMessage({{ __webControlPanel: true, action: 'closed',
|
|
1790
|
+
window.parent.postMessage({{ __webControlPanel: true, action: 'closed', sid: WC_SESSION_ID }}, '*');
|
|
1791
1791
|
}});
|
|
1792
1792
|
</script>
|
|
1793
1793
|
</body>
|
|
@@ -1824,9 +1824,8 @@ window.addEventListener('beforeunload', function() {{
|
|
|
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)
|
|
1827
|
-
#
|
|
1828
|
-
|
|
1829
|
-
session_id = data.get("session_id", "") or "web_default"
|
|
1827
|
+
# 统一使用 sid 作为会话标识(兼容旧字段 session_id)
|
|
1828
|
+
session_id = data.get("sid", "") or data.get("session_id", "") or "web_default"
|
|
1830
1829
|
chat_mode = data.get("mode", "") # "exec" = 执行模式
|
|
1831
1830
|
escalated = data.get("escalated", False) # 临时提权到 local
|
|
1832
1831
|
|
|
@@ -1898,7 +1897,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
1898
1897
|
except Exception as tp_err:
|
|
1899
1898
|
logger.warning(f"任务列表更新失败: {tp_err}")
|
|
1900
1899
|
|
|
1901
|
-
resp_data = {"response": response, "
|
|
1900
|
+
resp_data = {"response": response, "sid": session_id, "agent_name": agent_path, "agent_path": agent_path}
|
|
1902
1901
|
if exec_events:
|
|
1903
1902
|
resp_data["exec_events"] = exec_events
|
|
1904
1903
|
return web.json_response(resp_data)
|
|
@@ -1985,8 +1984,8 @@ window.addEventListener('beforeunload', function() {{
|
|
|
1985
1984
|
return web.Response(text="data: " + json.dumps({"error": "message is required"}) + "\n\n", content_type="text/event-stream")
|
|
1986
1985
|
|
|
1987
1986
|
agent_path = data.get("agent_path", data.get("agent_name", "1")) or "1"
|
|
1988
|
-
#
|
|
1989
|
-
session_id = data.get("session_id", "") or "web_default"
|
|
1987
|
+
# 统一使用 sid 作为会话标识(兼容旧字段 session_id)
|
|
1988
|
+
session_id = data.get("sid", "") or data.get("session_id", "") or "web_default"
|
|
1990
1989
|
chat_mode = data.get("mode", "")
|
|
1991
1990
|
escalated = data.get("escalated", False)
|
|
1992
1991
|
voice_text = data.get("voice_text", "").strip() # 语音转文字原始文本(用于 usersays_correct)
|
|
@@ -2015,16 +2014,16 @@ window.addEventListener('beforeunload', function() {{
|
|
|
2015
2014
|
# 先发送已生成的内容
|
|
2016
2015
|
existing_result = running_info.get("result", "")
|
|
2017
2016
|
if existing_result:
|
|
2018
|
-
await response.write(("data: " + json.dumps({"type": "resume", "
|
|
2017
|
+
await response.write(("data: " + json.dumps({"type": "resume", "sid": session_id, "running": True, "started_at": running_info.get("started_at"), "result": existing_result}, ensure_ascii=False) + "\n\n").encode())
|
|
2019
2018
|
else:
|
|
2020
|
-
await response.write(("data: " + json.dumps({"type": "resume", "
|
|
2019
|
+
await response.write(("data: " + json.dumps({"type": "resume", "sid": session_id, "running": True, "started_at": running_info.get("started_at")}, ensure_ascii=False) + "\n\n").encode())
|
|
2021
2020
|
|
|
2022
2021
|
# 持续检查任务是否完成,完成后发送完成事件
|
|
2023
2022
|
while not running_info.get("done"):
|
|
2024
2023
|
await asyncio.sleep(0.5) # 每 500ms 检查一次
|
|
2025
2024
|
running_info = self._running_sessions.get(session_id)
|
|
2026
2025
|
if running_info and running_info.get("done"):
|
|
2027
|
-
await response.write(("data: " + json.dumps({"type": "resume_complete", "
|
|
2026
|
+
await response.write(("data: " + json.dumps({"type": "resume_complete", "sid": session_id, "result": running_info.get("result", "")}, ensure_ascii=False) + "\n\n").encode())
|
|
2028
2027
|
break
|
|
2029
2028
|
|
|
2030
2029
|
return response
|
|
@@ -2112,7 +2111,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
2112
2111
|
|
|
2113
2112
|
# 发送 session 信息
|
|
2114
2113
|
logger.info(f"[{session_id}] 准备发送 session 事件")
|
|
2115
|
-
await safe_write({"type": "session", "
|
|
2114
|
+
await safe_write({"type": "session", "sid": session_id, "agent_path": agent_path})
|
|
2116
2115
|
logger.info(f"[{session_id}] session 事件已发送")
|
|
2117
2116
|
|
|
2118
2117
|
# ── 定义后台流式处理任务(独立于 SSE 连接) ──
|
|
@@ -2196,7 +2195,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
2196
2195
|
self._running_sessions[session_id]["completed_at"] = time.time()
|
|
2197
2196
|
|
|
2198
2197
|
# 发送完成事件
|
|
2199
|
-
await safe_write({"type": "done", "exec_events": exec_events, "
|
|
2198
|
+
await safe_write({"type": "done", "exec_events": exec_events, "sid": session_id})
|
|
2200
2199
|
|
|
2201
2200
|
# ── 处理消息队列 ──
|
|
2202
2201
|
while session_id in self._msg_queues and self._msg_queues[session_id]:
|
|
@@ -2205,7 +2204,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
2205
2204
|
if not next_message:
|
|
2206
2205
|
continue
|
|
2207
2206
|
logger.info(f"[{session_id}] 处理队列消息: {next_message[:50]}...")
|
|
2208
|
-
await safe_write({"type": "queue_start", "message": next_message, "
|
|
2207
|
+
await safe_write({"type": "queue_start", "message": next_message, "sid": session_id})
|
|
2209
2208
|
clean_message_q, agent_system_prompt_q = self._build_agent_chat_context(agent_path, agent_cfg, next_message)
|
|
2210
2209
|
if model_chain and self.core.llm:
|
|
2211
2210
|
full_response = await self._try_model_chain_stream(
|
|
@@ -2227,7 +2226,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
2227
2226
|
result_store["full_response"] = full_response or ""
|
|
2228
2227
|
result_store["exec_events"] = exec_events_q
|
|
2229
2228
|
result_store["done"] = True
|
|
2230
|
-
await safe_write({"type": "done", "exec_events": exec_events_q, "
|
|
2229
|
+
await safe_write({"type": "done", "exec_events": exec_events_q, "sid": session_id})
|
|
2231
2230
|
|
|
2232
2231
|
except asyncio.CancelledError:
|
|
2233
2232
|
# [v1.23.38] 任务被取消(用户点击停止),清理资源
|
|
@@ -2235,7 +2234,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
2235
2234
|
result_store["done"] = True
|
|
2236
2235
|
result_store["cancelled"] = True
|
|
2237
2236
|
try:
|
|
2238
|
-
await safe_write({"type": "stopped", "
|
|
2237
|
+
await safe_write({"type": "stopped", "sid": session_id})
|
|
2239
2238
|
except Exception:
|
|
2240
2239
|
pass
|
|
2241
2240
|
except Exception as e:
|
|
@@ -2327,9 +2326,9 @@ window.addEventListener('beforeunload', function() {{
|
|
|
2327
2326
|
except Exception:
|
|
2328
2327
|
return web.json_response({"error": "invalid JSON"}, status=400)
|
|
2329
2328
|
|
|
2330
|
-
session_id = data.get("session_id", "")
|
|
2329
|
+
session_id = data.get("sid", "") or data.get("session_id", "")
|
|
2331
2330
|
if not session_id:
|
|
2332
|
-
return web.json_response({"ok": False, "error": "missing
|
|
2331
|
+
return web.json_response({"ok": False, "error": "missing sid"})
|
|
2333
2332
|
|
|
2334
2333
|
logger.info(f"[{session_id}] 收到停止执行请求")
|
|
2335
2334
|
|
|
@@ -2376,8 +2375,8 @@ window.addEventListener('beforeunload', function() {{
|
|
|
2376
2375
|
return web.json_response({"error": "message is required"}, status=400)
|
|
2377
2376
|
|
|
2378
2377
|
agent_path = data.get("agent_path", "1") or "1"
|
|
2379
|
-
#
|
|
2380
|
-
session_id = data.get("session_id", "web_default")
|
|
2378
|
+
# 统一使用 sid 作为会话标识(兼容旧字段 session_id)
|
|
2379
|
+
session_id = data.get("sid", "") or data.get("session_id", "web_default")
|
|
2381
2380
|
choice = data.get("choice", "queue") # "continue" (插入后继续) 或 "queue" (排队)
|
|
2382
2381
|
|
|
2383
2382
|
# 检查会话是否正在运行
|
|
@@ -2424,7 +2423,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
2424
2423
|
return web.json_response({"error": "text is required"}, status=400)
|
|
2425
2424
|
|
|
2426
2425
|
agent_path = data.get("agent_path", "1") or "1"
|
|
2427
|
-
session_id = data.get("session_id", "")
|
|
2426
|
+
session_id = data.get("sid", "") or data.get("session_id", "")
|
|
2428
2427
|
chat_mode = data.get("mode", "")
|
|
2429
2428
|
|
|
2430
2429
|
# Build full session ID
|
|
@@ -2856,7 +2855,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
2856
2855
|
for sid, info in self._running_sessions.items():
|
|
2857
2856
|
if info.get("running") and not info.get("done"):
|
|
2858
2857
|
running_agents.append({
|
|
2859
|
-
"
|
|
2858
|
+
"sid": sid,
|
|
2860
2859
|
"agent_path": info.get("agent_path", ""),
|
|
2861
2860
|
"message": info.get("message", ""),
|
|
2862
2861
|
"started_at": info.get("started_at"),
|
|
@@ -4190,7 +4189,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
4190
4189
|
for session_id, info in self._running_sessions.items():
|
|
4191
4190
|
if info.get("running") and not info.get("done"):
|
|
4192
4191
|
running.append({
|
|
4193
|
-
"
|
|
4192
|
+
"sid": session_id,
|
|
4194
4193
|
"running": True,
|
|
4195
4194
|
"started_at": info.get("started_at"),
|
|
4196
4195
|
"agent_path": info.get("agent_path"),
|
|
@@ -4561,7 +4560,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
4561
4560
|
return web.json_response([{
|
|
4562
4561
|
"id": e.id, "key": e.key, "content": e.content[:500],
|
|
4563
4562
|
"category": e.category, "importance": e.importance,
|
|
4564
|
-
"role": e.role, "
|
|
4563
|
+
"role": e.role, "sid": e.session_id, "created_at": e.created_at,
|
|
4565
4564
|
} for e in results])
|
|
4566
4565
|
|
|
4567
4566
|
async def handle_memory_list(self, request):
|
|
@@ -4574,7 +4573,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
4574
4573
|
"id": e.id, "key": e.key, "content": e.content[:500],
|
|
4575
4574
|
"summary": e.summary, "importance": e.importance,
|
|
4576
4575
|
"category": e.category, "role": e.role,
|
|
4577
|
-
"
|
|
4576
|
+
"sid": e.session_id, "created_at": e.created_at,
|
|
4578
4577
|
} for e in entries])
|
|
4579
4578
|
|
|
4580
4579
|
async def handle_delete_memory(self, request):
|
|
@@ -4698,7 +4697,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
4698
4697
|
base_url = data.get("base_url", "")
|
|
4699
4698
|
model = data.get("model", "")
|
|
4700
4699
|
api_type = data.get("api_type", "")
|
|
4701
|
-
temperature = data.get("temperature", 0.
|
|
4700
|
+
temperature = data.get("temperature", 0.8)
|
|
4702
4701
|
provider = data.get("provider", "")
|
|
4703
4702
|
input_modes = data.get("input_modes", ["text"])
|
|
4704
4703
|
|
|
@@ -4863,9 +4862,9 @@ window.addEventListener('beforeunload', function() {{
|
|
|
4863
4862
|
model=data.get("model", model_id),
|
|
4864
4863
|
base_url=data.get("base_url", ""),
|
|
4865
4864
|
api_key=data.get("api_key", ""),
|
|
4866
|
-
max_tokens=data.get("max_tokens",
|
|
4867
|
-
temperature=data.get("temperature", 0.
|
|
4868
|
-
context_window=data.get("context_window",
|
|
4865
|
+
max_tokens=data.get("max_tokens", 10240),
|
|
4866
|
+
temperature=data.get("temperature", 0.8),
|
|
4867
|
+
context_window=data.get("context_window", 200000),
|
|
4869
4868
|
input_modes=data.get("input_modes", ["text"]),
|
|
4870
4869
|
reasoning=data.get("reasoning", False),
|
|
4871
4870
|
enabled=data.get("enabled", True),
|
|
@@ -5544,7 +5543,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
5544
5543
|
"temperature": llm.temperature,
|
|
5545
5544
|
"max_tokens": llm.max_tokens,
|
|
5546
5545
|
"api_type": getattr(llm, 'api_type', ''),
|
|
5547
|
-
"context_window": getattr(llm, 'context_window',
|
|
5546
|
+
"context_window": getattr(llm, 'context_window', 200000),
|
|
5548
5547
|
}
|
|
5549
5548
|
|
|
5550
5549
|
try:
|
|
@@ -5577,9 +5576,9 @@ window.addEventListener('beforeunload', function() {{
|
|
|
5577
5576
|
if agent_system_prompt and self.core.main_agent:
|
|
5578
5577
|
self.core.main_agent._agent_override_prompt = agent_system_prompt
|
|
5579
5578
|
self.core.main_agent._agent_override_path = agent_path
|
|
5580
|
-
# [v1.23.52]
|
|
5579
|
+
# [v1.23.52] 为所有 Agent 设置独立工作目录(基于数字 aid,executor 层面)
|
|
5581
5580
|
_original_exec_work_dir = None
|
|
5582
|
-
if agent_path and
|
|
5581
|
+
if agent_path and self.core.main_agent and self.core.main_agent.executor:
|
|
5583
5582
|
from config import ConfigManager
|
|
5584
5583
|
_cm = ConfigManager()
|
|
5585
5584
|
_agent_wd = _cm.data_dir / "agents" / agent_path / "workspace"
|
|
@@ -5698,7 +5697,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
5698
5697
|
"provider": llm.provider, "model": llm.model, "base_url": llm.base_url,
|
|
5699
5698
|
"api_key": llm.api_key, "temperature": llm.temperature, "max_tokens": llm.max_tokens,
|
|
5700
5699
|
"api_type": getattr(llm, 'api_type', ''),
|
|
5701
|
-
"context_window": getattr(llm, 'context_window',
|
|
5700
|
+
"context_window": getattr(llm, 'context_window', 200000),
|
|
5702
5701
|
}
|
|
5703
5702
|
try:
|
|
5704
5703
|
if "provider" in mc: llm.provider = mc["provider"]
|
|
@@ -5907,8 +5906,8 @@ window.addEventListener('beforeunload', function() {{
|
|
|
5907
5906
|
if _exec_mode:
|
|
5908
5907
|
_original_exec_mode = agent.executor.execution_mode
|
|
5909
5908
|
agent.executor.set_execution_mode(_exec_mode)
|
|
5910
|
-
# [v1.23.52]
|
|
5911
|
-
if agent_path and
|
|
5909
|
+
# [v1.23.52] 为所有 Agent 设置独立工作目录(基于数字 aid)
|
|
5910
|
+
if agent_path and agent.executor:
|
|
5912
5911
|
from config import ConfigManager
|
|
5913
5912
|
cm = ConfigManager()
|
|
5914
5913
|
agent_work_dir = cm.data_dir / "agents" / agent_path / "workspace"
|
|
@@ -7924,10 +7923,10 @@ window.addEventListener('beforeunload', function() {{
|
|
|
7924
7923
|
- @某个Agent: 只有被@的Agent需要回复
|
|
7925
7924
|
- @所有人 / @all: 所有成员都需要回复
|
|
7926
7925
|
- 不@任何人(广播): 你自行判断是否需要回复
|
|
7927
|
-
2. **跨Agent私下沟通**: 你可以使用 `myagent-ai chat --agent
|
|
7928
|
-
- **⚠️ 必须使用 Agent
|
|
7929
|
-
- 从上方「群成员列表」中找到目标Agent的 `[方括号]`
|
|
7930
|
-
- 正确示例: `myagent-ai chat --agent
|
|
7926
|
+
2. **跨Agent私下沟通**: 你可以使用 `myagent-ai chat --agent <数字ID> --message "消息"` 命令向群内其他Agent发送私下消息。对方会在自己下次处理消息时收到。
|
|
7927
|
+
- **⚠️ 必须使用 Agent 的数字 ID,不能用名字!** 例如群成员列表中显示 `薇纸 [3] (成员)`,则 ID 是 `3`,不是 `薇纸`
|
|
7928
|
+
- 从上方「群成员列表」中找到目标Agent的 `[方括号]` 内容就是它的数字 ID
|
|
7929
|
+
- 正确示例: `myagent-ai chat --agent 3 --message "你好"`
|
|
7931
7930
|
- 错误示例: `myagent-ai chat --agent 薇纸 --message "你好"`(名字可能重复或找不到)
|
|
7932
7931
|
- 私下沟通的内容不会直接显示给用户,适合讨论细节、交换数据、协调方案
|
|
7933
7932
|
- 当任务需要多个Agent协作时,应该先在群里讨论分工,然后私下沟通具体细节
|
|
@@ -12,7 +12,7 @@ async function renderMemory(){
|
|
|
12
12
|
try{lt=await api('/api/memory/list?category='+encodeURIComponent(_memCategory))}catch(e){lt=[]}
|
|
13
13
|
if(stats.error){$('content').innerHTML='<div class="empty" style="color:var(--danger)">记忆系统异常: '+escHtml(stats.error)+'</div>';return}
|
|
14
14
|
// [v1.18.9] 按 agent 筛选
|
|
15
|
-
if(_memAgentFilter){lt=lt.filter(e=>(e.agent_id||e.
|
|
15
|
+
if(_memAgentFilter){lt=lt.filter(e=>(e.agent_id||e.sid||'').includes(_memAgentFilter));}
|
|
16
16
|
const cats=[{k:'global',l:'全局记忆'},{k:'session',l:'会话记忆'}];
|
|
17
17
|
let tabHtml='<div class="flex gap-8 mb-8" style="flex-wrap:wrap">';
|
|
18
18
|
for(const c of cats){
|
|
@@ -40,7 +40,7 @@ async function renderMemory(){
|
|
|
40
40
|
<div class="mem-meta">
|
|
41
41
|
<span class="tag">${escHtml(e.role||'')}</span>
|
|
42
42
|
${!isSession&&e.importance!=null?'<span class="tag tag-imp">'+e.importance.toFixed(2)+'</span>':''}
|
|
43
|
-
${e.
|
|
43
|
+
${e.sid?'<span class="mem-session" title="'+escHtml(e.sid)+'">'+escHtml((e.sid||'').split('_web_')[0])+'</span>':''}
|
|
44
44
|
</div>
|
|
45
45
|
</div>
|
|
46
46
|
<div class="mem-content">${contentPreview}</div>
|
|
@@ -67,7 +67,7 @@ async function searchMemory(){
|
|
|
67
67
|
<div class="mem-meta">
|
|
68
68
|
<span class="tag">${e.category||''}</span>
|
|
69
69
|
<span class="tag">${escHtml(e.role||'')}</span>
|
|
70
|
-
<span class="mem-session">${escHtml((e.
|
|
70
|
+
<span class="mem-session">${escHtml((e.sid||'').split('_web_')[0])}</span>
|
|
71
71
|
</div>
|
|
72
72
|
</div>
|
|
73
73
|
<div class="mem-content">${escHtml(content)}</div>
|
package/web/ui/chat/chat_main.js
CHANGED
|
@@ -1792,7 +1792,7 @@ window.addEventListener('message', function(event) {
|
|
|
1792
1792
|
if (event.data && event.data.__webControlPanel) {
|
|
1793
1793
|
var action = event.data.action;
|
|
1794
1794
|
if (action === 'opened') {
|
|
1795
|
-
wcCurrentSessionId = event.data.
|
|
1795
|
+
wcCurrentSessionId = event.data.sid || wcCurrentSessionId;
|
|
1796
1796
|
// 通知服务端面板已打开
|
|
1797
1797
|
api('/api/web_control/poll?sid=' + wcCurrentSessionId).catch(function(){});
|
|
1798
1798
|
} else if (action === 'close' || action === 'closed') {
|
|
@@ -3659,7 +3659,7 @@ window.buildMessageHtml = function(msg, idx, agent) {
|
|
|
3659
3659
|
if (!wcEvents || wcEvents.length === 0) return '';
|
|
3660
3660
|
let lastEvent = wcEvents[wcEvents.length - 1];
|
|
3661
3661
|
let wcAction = lastEvent.action || 'open';
|
|
3662
|
-
let wcSessionId = lastEvent.
|
|
3662
|
+
let wcSessionId = lastEvent.sid || '';
|
|
3663
3663
|
let wcUrl = lastEvent.url || '';
|
|
3664
3664
|
let wcTitle = 'Web Control';
|
|
3665
3665
|
let wcIcon = '🌐';
|
|
@@ -226,7 +226,7 @@ async function sendChunkSequentially(chunks, idx) {
|
|
|
226
226
|
method: 'POST',
|
|
227
227
|
body: JSON.stringify({
|
|
228
228
|
message: text,
|
|
229
|
-
|
|
229
|
+
sid: state.activeSessionId || ('split_' + Date.now()),
|
|
230
230
|
agent_name: state.activeAgent,
|
|
231
231
|
agent_path: state.activeAgent,
|
|
232
232
|
mode: state.chatMode,
|
|
@@ -1718,7 +1718,7 @@ async function sendMessage(opts) {
|
|
|
1718
1718
|
headers: { 'Content-Type': 'application/json' },
|
|
1719
1719
|
body: JSON.stringify({
|
|
1720
1720
|
message: text,
|
|
1721
|
-
|
|
1721
|
+
sid: sessionId,
|
|
1722
1722
|
agent_name: state.activeAgent,
|
|
1723
1723
|
agent_path: state.activeAgent,
|
|
1724
1724
|
mode: state.chatMode,
|
|
@@ -1788,14 +1788,14 @@ async function sendMessage(opts) {
|
|
|
1788
1788
|
const evt = JSON.parse(line.substring(6));
|
|
1789
1789
|
|
|
1790
1790
|
if (evt.type === 'session') {
|
|
1791
|
-
sessionIdReceived = evt.
|
|
1791
|
+
sessionIdReceived = evt.sid;
|
|
1792
1792
|
// Sync the actual session ID (backend may prefix with agent_path)
|
|
1793
|
-
state.activeSessionId = evt.
|
|
1793
|
+
state.activeSessionId = evt.sid;
|
|
1794
1794
|
// [v1.23.24] 同步本地 sessions 列表中的 ID(前端生成的临时 ID → 后端 canonical ID)
|
|
1795
|
-
if (sessionIdOriginal && sessionIdOriginal !== evt.
|
|
1795
|
+
if (sessionIdOriginal && sessionIdOriginal !== evt.sid) {
|
|
1796
1796
|
var _sesIdx = state.sessions.findIndex(function(s) { return s.id === sessionIdOriginal; });
|
|
1797
1797
|
if (_sesIdx >= 0) {
|
|
1798
|
-
state.sessions[_sesIdx].id = evt.
|
|
1798
|
+
state.sessions[_sesIdx].id = evt.sid;
|
|
1799
1799
|
state.agentSessions[state.activeAgent] = [...state.sessions];
|
|
1800
1800
|
renderSessions();
|
|
1801
1801
|
}
|
|
@@ -1803,7 +1803,7 @@ async function sendMessage(opts) {
|
|
|
1803
1803
|
// ── 更新 URL 参数(后端返回的 session ID 可能与前端不同) ──
|
|
1804
1804
|
try {
|
|
1805
1805
|
const _url = new URL(window.location.href);
|
|
1806
|
-
_url.searchParams.set('s', UrlCodec.encode(evt.
|
|
1806
|
+
_url.searchParams.set('s', UrlCodec.encode(evt.sid));
|
|
1807
1807
|
window.history.replaceState({}, '', _url.toString());
|
|
1808
1808
|
} catch (_) {}
|
|
1809
1809
|
} else if (evt.type === 'user_files') {
|
|
@@ -2189,7 +2189,7 @@ async function sendMessage(opts) {
|
|
|
2189
2189
|
// [v1.21.0] Agent is opening/controlling web control panel
|
|
2190
2190
|
if (evt.data) {
|
|
2191
2191
|
var wcAction = evt.data.action;
|
|
2192
|
-
var wcSessionId = evt.data.
|
|
2192
|
+
var wcSessionId = evt.data.sid || '';
|
|
2193
2193
|
var wcUrl = evt.data.url || '';
|
|
2194
2194
|
if (wcAction === 'open' || wcAction === 'navigate') {
|
|
2195
2195
|
// 打开或导航 Web Control 面板
|
|
@@ -2210,7 +2210,7 @@ async function sendMessage(opts) {
|
|
|
2210
2210
|
// [v1.15.8] 会话自动命名 — 后端通过 mainsubject 生成
|
|
2211
2211
|
if (evt.data && evt.data.name) {
|
|
2212
2212
|
var newName = evt.data.name;
|
|
2213
|
-
var targetId = evt.data.
|
|
2213
|
+
var targetId = evt.data.sid || sessionId;
|
|
2214
2214
|
var _ses = state.sessions.find(function(s) { return s.id === targetId; });
|
|
2215
2215
|
if (_ses) {
|
|
2216
2216
|
_ses.name = newName;
|
|
@@ -2458,7 +2458,7 @@ function stopGenerating() {
|
|
|
2458
2458
|
fetch('/api/chat/stop', {
|
|
2459
2459
|
method: 'POST',
|
|
2460
2460
|
headers: { 'Content-Type': 'application/json' },
|
|
2461
|
-
body: JSON.stringify({
|
|
2461
|
+
body: JSON.stringify({ sid: sid }),
|
|
2462
2462
|
}).catch(function() {});
|
|
2463
2463
|
}
|
|
2464
2464
|
// 中断前端 SSE 连接
|
|
@@ -2508,7 +2508,7 @@ async function handleInjectChoice(choice) {
|
|
|
2508
2508
|
headers: { 'Content-Type': 'application/json' },
|
|
2509
2509
|
body: JSON.stringify({
|
|
2510
2510
|
message: text,
|
|
2511
|
-
|
|
2511
|
+
sid: rawSid,
|
|
2512
2512
|
agent_path: state.activeAgent,
|
|
2513
2513
|
choice: choice
|
|
2514
2514
|
})
|
package/web/ui/chat/groupchat.js
CHANGED
|
@@ -251,8 +251,8 @@ async function selectGroup(gid) {
|
|
|
251
251
|
// [v1.23.81] 获取群聊 session ID 并写入 URL(纯数字,用于导航恢复)
|
|
252
252
|
try {
|
|
253
253
|
var sessionData = await api('/api/groups/' + encodeURIComponent(gid) + '/session');
|
|
254
|
-
if (sessionData && sessionData.
|
|
255
|
-
var sessionId = sessionData.
|
|
254
|
+
if (sessionData && sessionData.sid) {
|
|
255
|
+
var sessionId = sessionData.sid;
|
|
256
256
|
// 用群聊专用 ?g= 参数更新 URL(不刷新页面),纯数字 session ID
|
|
257
257
|
var newUrl = '/ui/chat/chat_container.html?g=' + sessionId;
|
|
258
258
|
if (typeof state !== 'undefined' && state.activeAgent) {
|