adp-openclaw 0.0.49 → 0.0.51

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adp-openclaw",
3
- "version": "0.0.49",
3
+ "version": "0.0.51",
4
4
  "description": "ADP-OpenClaw demo channel plugin (Go WebSocket backend)",
5
5
  "type": "module",
6
6
  "dependencies": {
@@ -518,7 +518,7 @@ export const ADP_UPLOAD_TOOL_NAME = "adp_upload_file";
518
518
 
519
519
  const ADP_UPLOAD_TOOL_SCHEMA_TITLE = "ADP file upload";
520
520
  const ADP_UPLOAD_TOOL_SCHEMA_DESCRIPTION =
521
- "Upload local files from this machine to ADP storage. If the call succeeds, the files are uploaded and signed download URLs are returned. The user can access the files via these URLs.";
521
+ "Upload local files from this machine to ADP storage. If the call succeeds, the files are uploaded and signed download URLs are returned. The user can access the files via these URLs. IMPORTANT: When presenting download links to users, format them as clickable Markdown links like [filename](url), do NOT wrap URLs in code blocks or backticks.";
522
522
  const ADP_UPLOAD_TOOL_PATHS_DESCRIPTION =
523
523
  "Local filesystem paths only (1-10 total). Any file type is accepted, including text, images, documents, PDFs, archives, and binary files. Use absolute or workspace-relative local paths that are readable files.";
524
524
 
@@ -659,6 +659,8 @@ export interface UploadedFileInfo {
659
659
  export interface AdpUploadToolResult {
660
660
  ok: boolean;
661
661
  files?: UploadedFileInfo[];
662
+ /** 预格式化的消息,AI 可以直接展示给用户(不要用代码块包装) */
663
+ message?: string;
662
664
  error?: {
663
665
  code: number;
664
666
  message: string;
@@ -769,9 +771,16 @@ export const uploadFilesToAdpEndpoint = async (
769
771
  }
770
772
  );
771
773
 
774
+ // 构建预格式化的消息,告诉 AI 如何展示给用户
775
+ const formattedLinks = uploadResults.map(f =>
776
+ `- [${f.name}](${f.downloadUrl})`
777
+ ).join("\n");
778
+ const message = `Files uploaded successfully. Present these download links to the user as clickable Markdown links (do NOT use code blocks):\n${formattedLinks}`;
779
+
772
780
  return {
773
781
  ok: true,
774
782
  files: uploadResults,
783
+ message,
775
784
  };
776
785
  } catch (error) {
777
786
  return {
package/src/channel.ts CHANGED
@@ -219,42 +219,78 @@ export const adpOpenclawPlugin: ChannelPlugin<ResolvedAdpOpenclawAccount> = {
219
219
  });
220
220
  },
221
221
  },
222
- // Outbound message support for the "message" tool
222
+ // Outbound message support for the "message" tool and cron tasks
223
223
  outbound: {
224
- send: async ({ text, to, log }) => {
224
+ deliveryMode: "direct",
225
+
226
+ // Send text message
227
+ sendText: async (ctx) => {
228
+ const { to, text } = ctx;
225
229
  const ws = getActiveWebSocket();
230
+
226
231
  if (!ws) {
227
- log?.error?.("[adp-openclaw] No active WebSocket connection for outbound message");
228
- return { ok: false, error: "No active WebSocket connection" };
232
+ console.error("[adp-openclaw] No active WebSocket connection for outbound message");
233
+ throw new Error("No active WebSocket connection");
229
234
  }
230
235
 
231
- // Parse target: expected format is "adp-openclaw:{userId}" or "adp-openclaw:bot"
232
- // The "to" parameter comes from the message tool with format like "adp-openclaw:user123"
236
+ // Parse target: expected format is "adp-openclaw:{userId}" or just "{userId}"
233
237
  const targetParts = to.split(":");
234
238
  const targetUserId = targetParts.length > 1 ? targetParts.slice(1).join(":") : to;
235
239
 
236
- log?.info?.(`[adp-openclaw] Sending outbound message to ${targetUserId}: ${text.slice(0, 50)}...`);
240
+ console.log(`[adp-openclaw] Sending outbound text to ${targetUserId}: ${text.slice(0, 50)}...`);
241
+
242
+ // Generate unique request ID
243
+ const requestId = `outbound-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
244
+
245
+ const outMsg = {
246
+ type: "outbound",
247
+ requestId,
248
+ payload: {
249
+ to: targetUserId,
250
+ text: text,
251
+ },
252
+ timestamp: Date.now(),
253
+ };
254
+
255
+ ws.send(JSON.stringify(outMsg));
256
+ return { channel: "adp-openclaw", messageId: requestId };
257
+ },
258
+
259
+ // Send media message (text with optional media URL)
260
+ sendMedia: async (ctx) => {
261
+ const { to, text, mediaUrl } = ctx;
262
+ const ws = getActiveWebSocket();
237
263
 
238
- try {
239
- // Generate unique request ID
240
- const requestId = `outbound-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
241
-
242
- const outMsg = {
243
- type: "outbound",
244
- requestId,
245
- payload: {
246
- to: targetUserId,
247
- text: text,
248
- },
249
- timestamp: Date.now(),
250
- };
251
-
252
- ws.send(JSON.stringify(outMsg));
253
- return { ok: true };
254
- } catch (err) {
255
- log?.error?.(`[adp-openclaw] Failed to send outbound message: ${err}`);
256
- return { ok: false, error: String(err) };
264
+ if (!ws) {
265
+ console.error("[adp-openclaw] No active WebSocket connection for outbound media");
266
+ throw new Error("No active WebSocket connection");
257
267
  }
268
+
269
+ // Parse target
270
+ const targetParts = to.split(":");
271
+ const targetUserId = targetParts.length > 1 ? targetParts.slice(1).join(":") : to;
272
+
273
+ console.log(`[adp-openclaw] Sending outbound media to ${targetUserId}: ${text.slice(0, 50)}... (media: ${mediaUrl || "none"})`);
274
+
275
+ // Generate unique request ID
276
+ const requestId = `outbound-media-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
277
+
278
+ // Combine text and media URL if present
279
+ const finalText = mediaUrl ? `${text}\n\n📎 ${mediaUrl}` : text;
280
+
281
+ const outMsg = {
282
+ type: "outbound",
283
+ requestId,
284
+ payload: {
285
+ to: targetUserId,
286
+ text: finalText,
287
+ mediaUrl: mediaUrl,
288
+ },
289
+ timestamp: Date.now(),
290
+ };
291
+
292
+ ws.send(JSON.stringify(outMsg));
293
+ return { channel: "adp-openclaw", messageId: requestId };
258
294
  },
259
295
  },
260
296
  };
package/src/monitor.ts CHANGED
@@ -177,6 +177,13 @@ async function connectAndHandle(params: ConnectParams): Promise<void> {
177
177
  ws.on("open", () => {
178
178
  log?.info(`[adp-openclaw] WebSocket connected, authenticating...`);
179
179
 
180
+ // 设置 TCP keepalive(作为额外保障)
181
+ const socket = (ws as any)._socket;
182
+ if (socket && typeof socket.setKeepAlive === 'function') {
183
+ socket.setKeepAlive(true, 30000); // 30秒
184
+ log?.info(`[adp-openclaw] TCP keepalive enabled`);
185
+ }
186
+
180
187
  // Save active WebSocket for outbound messaging
181
188
  setActiveWebSocket(ws);
182
189