@efengx/openclaw-channel-dragon 0.5.13 → 0.5.14

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.
@@ -11,6 +11,7 @@ export declare class ChannelComponent implements IComponent {
11
11
  private options;
12
12
  private telemetry;
13
13
  private processedMessageIds;
14
+ private sessionQueues;
14
15
  constructor(options: ChannelOptions, telemetry: TelemetryComponent);
15
16
  start(): Promise<void>;
16
17
  stop(): Promise<void>;
@@ -3,6 +3,7 @@ export class ChannelComponent {
3
3
  options;
4
4
  telemetry;
5
5
  processedMessageIds = new Set();
6
+ sessionQueues = new Map();
6
7
  constructor(options, telemetry) {
7
8
  this.options = options;
8
9
  this.telemetry = telemetry;
@@ -26,38 +27,50 @@ export class ChannelComponent {
26
27
  return;
27
28
  const { accountId, agentId, cfg, logger } = this.options;
28
29
  const sessionKey = `dragon:${agentId}:direct:${sessionId}`;
29
- logger?.info?.(`[Dragon Plugin] Sending to OpenClaw: "${content.substring(0, 50)}${content.length > 50 ? '...' : ''}" [Session: ${sessionId}]`);
30
- await replyDispatcher({
31
- ctx: {
32
- Body: content,
33
- From: sessionId === 'default' ? "workbench-user" : `workbench-user-${sessionId}`,
34
- To: agentId,
35
- ChatType: "direct",
36
- Provider: channelId,
37
- ChannelId: channelId,
38
- AccountId: accountId,
39
- SessionKey: sessionKey,
40
- Timestamp: Date.now(),
41
- Model: modelId,
42
- Attachments: attachments,
43
- },
44
- cfg,
45
- dispatcherOptions: {
46
- deliver: async (payload) => {
47
- const text = payload?.text || "";
48
- if (!text && !payload?.tool_calls?.length)
49
- return;
50
- await this.telemetry.reportReply({
51
- content: text,
52
- sessionId,
53
- tool_calls: payload?.tool_calls,
54
- reasoning_content: payload?.reasoning_content,
55
- source: "telemetry_deliver",
56
- msgId: replyMsgId,
57
- });
30
+ const previous = this.sessionQueues.get(sessionKey) || Promise.resolve();
31
+ const current = previous
32
+ .catch(() => { })
33
+ .then(async () => {
34
+ logger?.info?.(`[Dragon Plugin] Sending to OpenClaw: "${content.substring(0, 50)}${content.length > 50 ? '...' : ''}" [Session: ${sessionId}]`);
35
+ await replyDispatcher({
36
+ ctx: {
37
+ Body: content,
38
+ From: sessionId === 'default' ? "workbench-user" : `workbench-user-${sessionId}`,
39
+ To: agentId,
40
+ ChatType: "direct",
41
+ Provider: channelId,
42
+ ChannelId: channelId,
43
+ AccountId: accountId,
44
+ SessionKey: sessionKey,
45
+ Timestamp: Date.now(),
46
+ Model: modelId,
47
+ Attachments: attachments,
48
+ },
49
+ cfg,
50
+ dispatcherOptions: {
51
+ deliver: async (payload) => {
52
+ const text = payload?.text || "";
53
+ if (!text && !payload?.tool_calls?.length)
54
+ return;
55
+ await this.telemetry.reportReply({
56
+ content: text,
57
+ sessionId,
58
+ tool_calls: payload?.tool_calls,
59
+ reasoning_content: payload?.reasoning_content,
60
+ source: "telemetry_deliver",
61
+ msgId: replyMsgId,
62
+ });
63
+ }
58
64
  }
65
+ });
66
+ })
67
+ .finally(() => {
68
+ if (this.sessionQueues.get(sessionKey) === current) {
69
+ this.sessionQueues.delete(sessionKey);
59
70
  }
60
71
  });
72
+ this.sessionQueues.set(sessionKey, current);
73
+ await current;
61
74
  };
62
75
  handleOutboundText = async (ctx) => {
63
76
  const text = ctx?.text || "";
@@ -26,7 +26,7 @@ export class SseComponent {
26
26
  const url = `${this.http.options.baseURL}/api/agents/events`;
27
27
  logger?.info?.(`[Dragon Plugin] Connecting to Orchestrator SSE: ${url}`);
28
28
  try {
29
- // In Node 22, we might need a fetch-based SSE or a library,
29
+ // In Node 22, we might need a fetch-based SSE or a library,
30
30
  // but for simplicity we'll use the same pattern as Bridge if possible.
31
31
  // Actually, standard EventSource is not in Node globals yet.
32
32
  // We'll use a simple fetch-based stream reader.
@@ -65,7 +65,9 @@ export class SseComponent {
65
65
  if (line.startsWith("data: ")) {
66
66
  try {
67
67
  const data = JSON.parse(line.slice(6));
68
- this.handleEvent(data);
68
+ void this.handleEvent(data).catch((err) => {
69
+ this.options.logger?.error?.(`[Dragon Plugin] SSE event handling failed: ${err?.message || err}`);
70
+ });
69
71
  }
70
72
  catch (e) { }
71
73
  }
@@ -79,7 +81,7 @@ export class SseComponent {
79
81
  }
80
82
  }
81
83
  }
82
- handleEvent(data) {
84
+ async handleEvent(data) {
83
85
  const { agentId, logger } = this.options;
84
86
  // 1. Filter for events belonging to this agent
85
87
  if (data.agentId && data.agentId !== agentId)
@@ -88,7 +90,7 @@ export class SseComponent {
88
90
  if (data.type === 'WORKBENCH_MESSAGE') {
89
91
  const { content, sessionId, attachments, id, msgId } = data.payload || {};
90
92
  logger?.info?.(`[Dragon Plugin] [SSE] Received from Workbench: "${content?.substring(0, 50)}${content?.length > 50 ? '...' : ''}" [Session: ${sessionId}]`);
91
- this.channel.deliverToOpenClaw(content, sessionId, undefined, attachments, msgId || id);
93
+ await this.channel.deliverToOpenClaw(content, sessionId, undefined, attachments, msgId || id);
92
94
  }
93
95
  else if (data.type === 'FETCH_HISTORY') {
94
96
  const { sessionId } = data.payload || {};
@@ -2,7 +2,7 @@
2
2
  "id": "dragon",
3
3
  "name": "Dragon Workbench Channel",
4
4
  "description": "Connect OpenClaw to the Dragon agent-client workbench chat.",
5
- "version": "0.5.8",
5
+ "version": "0.5.14",
6
6
  "enabledByDefault": true,
7
7
  "activation": {
8
8
  "onCapabilities": ["hook"]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@efengx/openclaw-channel-dragon",
3
- "version": "0.5.13",
3
+ "version": "0.5.14",
4
4
  "description": "Dragon workbench channel for OpenClaw",
5
5
  "author": "feng xiang <ofengx@gmail.com>",
6
6
  "type": "module",