@next-open-ai/openclawx 0.8.28 → 0.8.36

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.
Files changed (32) hide show
  1. package/README.md +78 -45
  2. package/apps/desktop/renderer/dist/assets/{index-D9748VrD.js → index-BGHtXhm3.js} +30 -30
  3. package/apps/desktop/renderer/dist/assets/index-CB2-m4ae.css +10 -0
  4. package/apps/desktop/renderer/dist/index.html +2 -2
  5. package/dist/core/agent/agent-manager.js +5 -2
  6. package/dist/core/agent/proxy/adapters/opencode-adapter.js +48 -14
  7. package/dist/core/inbound-message-preprocess.d.ts +27 -0
  8. package/dist/core/inbound-message-preprocess.js +96 -0
  9. package/dist/core/mcp/client.d.ts +4 -0
  10. package/dist/core/mcp/client.js +2 -0
  11. package/dist/core/mcp/index.d.ts +3 -1
  12. package/dist/core/mcp/index.js +4 -1
  13. package/dist/core/mcp/operator.d.ts +17 -2
  14. package/dist/core/mcp/operator.js +97 -30
  15. package/dist/core/mcp/transport/index.d.ts +4 -0
  16. package/dist/core/mcp/transport/index.js +6 -1
  17. package/dist/core/mcp/transport/stdio.d.ts +6 -0
  18. package/dist/core/mcp/transport/stdio.js +22 -1
  19. package/dist/core/session-outlet/index.d.ts +19 -0
  20. package/dist/core/session-outlet/index.js +33 -0
  21. package/dist/core/session-outlet/outlet.d.ts +15 -0
  22. package/dist/core/session-outlet/outlet.js +49 -0
  23. package/dist/core/session-outlet/types.d.ts +35 -0
  24. package/dist/core/session-outlet/types.js +5 -0
  25. package/dist/gateway/channel/channel-core.d.ts +1 -0
  26. package/dist/gateway/channel/channel-core.js +101 -59
  27. package/dist/gateway/methods/agent-cancel.js +3 -0
  28. package/dist/gateway/methods/agent-chat.d.ts +4 -0
  29. package/dist/gateway/methods/agent-chat.js +293 -229
  30. package/dist/gateway/server.js +2 -0
  31. package/package.json +1 -1
  32. package/apps/desktop/renderer/dist/assets/index-DVbrfeA6.css +0 -10
@@ -1,5 +1,11 @@
1
1
  import { runAgentAndCollectReply, runAgentAndStreamReply } from "./run-agent.js";
2
2
  import { getChannelSessionPersistence, persistChannelUserMessage, persistChannelAssistantMessage } from "./session-persistence.js";
3
+ import { preprocessInboundMessage } from "../../core/inbound-message-preprocess.js";
4
+ import { getSessionCurrentAgentUpdater } from "../../core/session-current-agent.js";
5
+ import { getSessionOutlet, sendSessionMessage } from "../../core/session-outlet/index.js";
6
+ /** 系统消息前缀,与正常回复同路下发,仅用此前缀区分,各端无需额外逻辑;结尾换行便于与正文分行 */
7
+ const SYSTEM_MSG_PREFIX = "[System Message] ";
8
+ const SYSTEM_MSG_SUFFIX = "\n";
3
9
  const STREAM_THROTTLE_MS = 280;
4
10
  function toSessionId(channelId, threadId) {
5
11
  return `channel:${channelId}:${threadId}`;
@@ -61,75 +67,111 @@ export async function handleChannelMessage(channel, msg) {
61
67
  console.warn("[ChannelCore] invalid threadId, skip reply");
62
68
  return;
63
69
  }
64
- // Web/Desktop 统一:通道会话入库并追加用户消息(用 currentAgentId)
65
- await persistChannelUserMessage(sessionId, {
66
- agentId: currentAgentId,
67
- title: msg.messageText?.trim().slice(0, 50) || undefined,
68
- messageText: msg.messageText?.trim() || "",
70
+ const rawMessage = msg.messageText?.trim() ?? "";
71
+ const { message: messageText, agentId: effectiveAgentId, directResponse } = await preprocessInboundMessage({
72
+ sessionId,
73
+ message: rawMessage,
74
+ currentAgentId,
69
75
  });
70
- const useStream = typeof outbound.sendStream === "function";
71
- if (useStream) {
72
- let sink;
73
- try {
74
- sink = await outbound.sendStream(threadId);
76
+ getSessionCurrentAgentUpdater()?.(sessionId, effectiveAgentId);
77
+ const outlet = getSessionOutlet();
78
+ const channelConsumer = {
79
+ send(m) {
80
+ if (m.type !== "system")
81
+ return;
82
+ const raw = m.payload?.text ?? m.payload?.message ?? m.payload?.phase ?? "";
83
+ if (raw) {
84
+ const text = SYSTEM_MSG_PREFIX + raw + SYSTEM_MSG_SUFFIX;
85
+ outbound.send(threadId, { text }).catch((e) => console.warn("[ChannelCore] outlet send failed:", e));
86
+ }
87
+ },
88
+ };
89
+ const unregisterConsumer = outlet ? outlet.registerConsumer(sessionId, channelConsumer) : () => { };
90
+ try {
91
+ if (directResponse != null && directResponse !== "") {
92
+ await persistChannelUserMessage(sessionId, {
93
+ agentId: effectiveAgentId,
94
+ title: rawMessage.slice(0, 50) || undefined,
95
+ messageText: rawMessage,
96
+ });
97
+ persistChannelAssistantMessage(sessionId, directResponse);
98
+ sendSessionMessage(sessionId, { type: "system", code: "command.result", payload: { text: directResponse } });
99
+ await msg.ack?.({ text: directResponse });
100
+ return;
75
101
  }
76
- catch (err) {
77
- console.error("[ChannelCore] sendStream init failed:", err);
78
- const reply = { text: "发信失败,请稍后再试。" };
79
- await outbound.send(threadId, reply);
102
+ // Web/Desktop 统一:通道会话入库并追加用户消息(用预处理后的 agentId 与消息)
103
+ await persistChannelUserMessage(sessionId, {
104
+ agentId: effectiveAgentId,
105
+ title: messageText.slice(0, 50) || undefined,
106
+ messageText,
107
+ });
108
+ const useStream = typeof outbound.sendStream === "function";
109
+ if (useStream) {
110
+ let sink;
111
+ try {
112
+ sink = await outbound.sendStream(threadId);
113
+ }
114
+ catch (err) {
115
+ console.error("[ChannelCore] sendStream init failed:", err);
116
+ const reply = { text: "发信失败,请稍后再试。" };
117
+ await outbound.send(threadId, reply);
118
+ return;
119
+ }
120
+ let accumulated = "";
121
+ let donePromise = null;
122
+ const throttled = throttle(() => {
123
+ if (sink.onChunk)
124
+ void Promise.resolve(sink.onChunk(accumulated)).catch((e) => console.error("[ChannelCore] stream onChunk error:", e));
125
+ }, STREAM_THROTTLE_MS);
126
+ try {
127
+ await runAgentAndStreamReply({ sessionId, message: messageText, agentId: effectiveAgentId }, {
128
+ onChunk(delta) {
129
+ accumulated += delta;
130
+ throttled.run();
131
+ },
132
+ onTurnEnd() {
133
+ throttled.flush();
134
+ if (sink.onTurnEnd)
135
+ void Promise.resolve(sink.onTurnEnd(accumulated)).catch((e) => console.error("[ChannelCore] stream onTurnEnd error:", e));
136
+ },
137
+ onDone() {
138
+ throttled.cancel();
139
+ const final = accumulated.trim() || "(无文本回复)";
140
+ persistChannelAssistantMessage(sessionId, final);
141
+ donePromise = Promise.resolve(sink.onDone(final)).catch((e) => console.error("[ChannelCore] stream onDone error:", e));
142
+ },
143
+ });
144
+ if (donePromise)
145
+ await donePromise;
146
+ await msg.ack?.(undefined);
147
+ }
148
+ catch (err) {
149
+ console.error("[ChannelCore] runAgent failed:", err);
150
+ throttled.cancel();
151
+ const fallback = accumulated.trim() || "处理时出错,请稍后再试。";
152
+ await Promise.resolve(sink.onDone(fallback)).catch(() => { });
153
+ await msg.ack?.(undefined);
154
+ }
80
155
  return;
81
156
  }
82
- let accumulated = "";
83
- let donePromise = null;
84
- const throttled = throttle(() => {
85
- if (sink.onChunk)
86
- void Promise.resolve(sink.onChunk(accumulated)).catch((e) => console.error("[ChannelCore] stream onChunk error:", e));
87
- }, STREAM_THROTTLE_MS);
157
+ let replyText;
88
158
  try {
89
- await runAgentAndStreamReply({ sessionId, message: msg.messageText, agentId: currentAgentId }, {
90
- onChunk(delta) {
91
- accumulated += delta;
92
- throttled.run();
93
- },
94
- onTurnEnd() {
95
- throttled.flush();
96
- if (sink.onTurnEnd)
97
- void Promise.resolve(sink.onTurnEnd(accumulated)).catch((e) => console.error("[ChannelCore] stream onTurnEnd error:", e));
98
- },
99
- onDone() {
100
- throttled.cancel();
101
- const final = accumulated.trim() || "(无文本回复)";
102
- persistChannelAssistantMessage(sessionId, final);
103
- donePromise = Promise.resolve(sink.onDone(final)).catch((e) => console.error("[ChannelCore] stream onDone error:", e));
104
- },
159
+ replyText = await runAgentAndCollectReply({
160
+ sessionId,
161
+ message: messageText,
162
+ agentId: effectiveAgentId,
105
163
  });
106
- if (donePromise)
107
- await donePromise;
108
- await msg.ack?.(undefined);
109
164
  }
110
165
  catch (err) {
111
166
  console.error("[ChannelCore] runAgent failed:", err);
112
- throttled.cancel();
113
- const fallback = accumulated.trim() || "处理时出错,请稍后再试。";
114
- await Promise.resolve(sink.onDone(fallback)).catch(() => { });
115
- await msg.ack?.(undefined);
167
+ replyText = "处理时出错,请稍后再试。";
116
168
  }
117
- return;
118
- }
119
- let replyText;
120
- try {
121
- replyText = await runAgentAndCollectReply({
122
- sessionId,
123
- message: msg.messageText,
124
- agentId: currentAgentId,
125
- });
169
+ persistChannelAssistantMessage(sessionId, replyText);
170
+ const reply = { text: replyText };
171
+ const sendResult = await outbound.send(threadId, reply);
172
+ await msg.ack?.(sendResult);
126
173
  }
127
- catch (err) {
128
- console.error("[ChannelCore] runAgent failed:", err);
129
- replyText = "处理时出错,请稍后再试。";
174
+ finally {
175
+ unregisterConsumer();
130
176
  }
131
- persistChannelAssistantMessage(sessionId, replyText);
132
- const reply = { text: replyText };
133
- const sendResult = await outbound.send(threadId, reply);
134
- await msg.ack?.(sendResult);
135
177
  }
@@ -1,5 +1,6 @@
1
1
  import { agentManager } from "../../core/agent/agent-manager.js";
2
2
  import { abortProxyRun } from "../proxy-run-abort.js";
3
+ import { clearSessionStreamSubscription } from "./agent-chat.js";
3
4
  const COMPOSITE_KEY_SEP = "::";
4
5
  /**
5
6
  * Handle agent.cancel: abort the current turn for the given session.
@@ -13,8 +14,10 @@ export async function handleAgentCancel(client, params) {
13
14
  }
14
15
  const agentId = params?.agentId ?? client.agentId ?? "default";
15
16
  if (abortProxyRun(sessionId, agentId)) {
17
+ clearSessionStreamSubscription(sessionId);
16
18
  return { status: "aborted" };
17
19
  }
20
+ clearSessionStreamSubscription(sessionId);
18
21
  const compositeKey = sessionId + COMPOSITE_KEY_SEP + agentId;
19
22
  let session = agentManager.getSession(compositeKey);
20
23
  if (!session) {
@@ -1,4 +1,8 @@
1
1
  import type { GatewayClient, AgentChatParams } from "../types.js";
2
+ /**
3
+ * 移除某 session 的流式订阅(cancel 或新消息开始时调用,避免同一事件被多个回调处理导致界面重复)
4
+ */
5
+ export declare function clearSessionStreamSubscription(sessionId: string): void;
2
6
  /**
3
7
  * Handle agent chat request with streaming support
4
8
  */