openclaw-elys 1.4.8 → 1.5.0

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.
@@ -65,7 +65,7 @@ export async function monitorElysProvider(opts) {
65
65
  fullText += payload.text;
66
66
  seq++;
67
67
  const done = info.kind === "final";
68
- mqttClient.publishStreamChunk(cmd.id, payload.text, seq, done);
68
+ mqttClient.publishStreamChunk(cmd.id, payload.text, seq, done, cmd.reply_to);
69
69
  if (info.kind === "block") {
70
70
  log(`[elys] stream chunk #${seq}: ${payload.text.slice(0, 80)}...`);
71
71
  }
@@ -75,7 +75,7 @@ export async function monitorElysProvider(opts) {
75
75
  }
76
76
  else if (info.kind === "final") {
77
77
  seq++;
78
- mqttClient.publishStreamChunk(cmd.id, "", seq, true);
78
+ mqttClient.publishStreamChunk(cmd.id, "", seq, true, cmd.reply_to);
79
79
  log(`[elys] final reply delivered (empty)`);
80
80
  }
81
81
  },
@@ -17,9 +17,8 @@ export declare class ElysDeviceMQTTClient {
17
17
  connect(abortSignal?: AbortSignal): Promise<void>;
18
18
  disconnect(): void;
19
19
  /** Send a stream chunk (for streaming AI responses) */
20
- publishStreamChunk(commandId: string, chunk: string, seq: number, done: boolean): void;
20
+ publishStreamChunk(commandId: string, chunk: string, seq: number, done: boolean, replyTo?: string): void;
21
21
  private handleMessage;
22
22
  private publishAck;
23
- private publishResult;
24
23
  private publish;
25
24
  }
@@ -104,7 +104,7 @@ export class ElysDeviceMQTTClient {
104
104
  }
105
105
  }
106
106
  /** Send a stream chunk (for streaming AI responses) */
107
- publishStreamChunk(commandId, chunk, seq, done) {
107
+ publishStreamChunk(commandId, chunk, seq, done, replyTo) {
108
108
  const msg = {
109
109
  id: commandId,
110
110
  type: "stream",
@@ -113,7 +113,7 @@ export class ElysDeviceMQTTClient {
113
113
  seq,
114
114
  done,
115
115
  };
116
- this.publish(msg);
116
+ this.publish(msg, replyTo);
117
117
  }
118
118
  async handleMessage(payload) {
119
119
  const raw = JSON.parse(payload.toString());
@@ -122,23 +122,25 @@ export class ElysDeviceMQTTClient {
122
122
  return;
123
123
  }
124
124
  this.log(`[elys] received command: ${raw.command} (id: ${raw.id})`);
125
- // Send ACK immediately
125
+ // ACK always goes to shared upstream topic (any gateway instance can process it)
126
126
  this.publishAck(raw.id);
127
+ // Result/stream goes to reply_to if present (routes to the specific gateway instance)
128
+ const replyTo = raw.reply_to;
127
129
  // Execute command
128
130
  if (this.commandHandler) {
129
131
  try {
130
132
  const result = await this.commandHandler(raw);
131
- this.publishResult(result);
133
+ this.publish(result, replyTo);
132
134
  }
133
135
  catch (err) {
134
136
  const errMsg = err instanceof Error ? err.message : String(err);
135
- this.publishResult({
137
+ this.publish({
136
138
  id: raw.id,
137
139
  type: "result",
138
140
  timestamp: Date.now() / 1000,
139
141
  status: "error",
140
142
  error: errMsg,
141
- });
143
+ }, replyTo);
142
144
  }
143
145
  }
144
146
  }
@@ -148,15 +150,13 @@ export class ElysDeviceMQTTClient {
148
150
  type: "ack",
149
151
  timestamp: Math.floor(Date.now() / 1000),
150
152
  };
153
+ // ACK always to default upstream topic (shared subscription)
151
154
  this.publish(msg);
152
155
  }
153
- publishResult(msg) {
154
- this.publish(msg);
155
- }
156
- publish(msg) {
156
+ publish(msg, replyTo) {
157
157
  if (!this.client)
158
158
  return;
159
- const topic = `elys/up/${this.credentials.deviceId}`;
159
+ const topic = replyTo || `elys/up/${this.credentials.deviceId}`;
160
160
  this.client.publish(topic, JSON.stringify(msg), { qos: 1 }, (err) => {
161
161
  if (err) {
162
162
  this.log(`[elys] failed to publish to ${topic}:`, err);
@@ -24,6 +24,8 @@ export interface CommandMessage extends MQTTBaseMessage {
24
24
  type: "command";
25
25
  command: string;
26
26
  args?: Record<string, unknown>;
27
+ /** If set, device should publish result/stream to this topic instead of elys/up/{device_id} */
28
+ reply_to?: string;
27
29
  }
28
30
  export interface AckMessage extends MQTTBaseMessage {
29
31
  type: "ack";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-elys",
3
- "version": "1.4.8",
3
+ "version": "1.5.0",
4
4
  "description": "OpenClaw Elys channel plugin — connects to Elys App",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",