@meet-im/meet 1.1.1 → 1.1.3
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 +1 -1
- package/skills/meet-at/SKILL.md +11 -8
- package/src/channel.ts +3 -12
- package/src/reply-dispatcher.ts +6 -2
- package/src/send.ts +62 -2
package/package.json
CHANGED
package/skills/meet-at/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: meet-at
|
|
3
|
-
description: "Meet IM messaging.
|
|
3
|
+
description: "Meet IM messaging. CRITICAL: Use EXACT format <@USER_ID> with BOTH angle brackets. <@553> is CORRECT. <@553 or @553> is WRONG - missing bracket. Always include opening < and closing > around the user ID."
|
|
4
4
|
metadata: { "openclaw": { "emoji": "💬", "requires": { "config": ["channels.meet"] } } }
|
|
5
5
|
allowed-tools: ["message"]
|
|
6
6
|
---
|
|
@@ -9,16 +9,19 @@ allowed-tools: ["message"]
|
|
|
9
9
|
|
|
10
10
|
Use the `message` tool for all Meet messaging operations.
|
|
11
11
|
|
|
12
|
-
## CRITICAL: Mention Format
|
|
12
|
+
## CRITICAL: Mention Format - MUST HAVE BOTH BRACKETS
|
|
13
13
|
|
|
14
|
-
**
|
|
14
|
+
**Correct format: `<@USER_ID>` with opening `<` and closing `>`**
|
|
15
15
|
|
|
16
|
-
| Format |
|
|
17
|
-
|
|
18
|
-
| <@USER_ID> |
|
|
19
|
-
| <@-1> |
|
|
16
|
+
| Format | Status | Example |
|
|
17
|
+
|--------|--------|---------|
|
|
18
|
+
| <@USER_ID> | ✅ CORRECT | <@553> |
|
|
19
|
+
| <@-1> | ✅ CORRECT | <@-1> |
|
|
20
|
+
| <@553 | ❌ WRONG - missing `>` | Will not trigger mention |
|
|
21
|
+
| @553> | ❌ WRONG - missing `<` | Will not trigger mention |
|
|
22
|
+
| @553 | ❌ WRONG - no brackets | Will not trigger mention |
|
|
20
23
|
|
|
21
|
-
**
|
|
24
|
+
**The format MUST be complete: `<@` + number + `>`**
|
|
22
25
|
|
|
23
26
|
## Examples
|
|
24
27
|
|
package/src/channel.ts
CHANGED
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
} from "./accounts.js";
|
|
19
19
|
import { meetOutbound } from "./outbound.js";
|
|
20
20
|
import { probeMeet } from "./probe.js";
|
|
21
|
-
import { resolveMeetGroupPolicy } from "./policy.js";
|
|
22
21
|
import {
|
|
23
22
|
parseMeetTarget,
|
|
24
23
|
looksLikeMeetId,
|
|
@@ -74,17 +73,9 @@ export const meetPlugin: ChannelPlugin<ResolvedMeetAccount> = {
|
|
|
74
73
|
accountId,
|
|
75
74
|
groupId,
|
|
76
75
|
}): GroupToolPolicyConfig | undefined => {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
groupAllowFrom: account.config.groupAllowFrom ?? [],
|
|
81
|
-
chatId: groupId ?? "",
|
|
82
|
-
groups: account.config.groups,
|
|
83
|
-
});
|
|
84
|
-
if (!groupPolicy.allowed) {
|
|
85
|
-
return { deny: ["*"] };
|
|
86
|
-
}
|
|
87
|
-
return undefined;
|
|
76
|
+
// 群组访问控制在 bot.ts 中处理,这里只返回工具策略配置
|
|
77
|
+
// 不使用 { deny: ["*"] } 拒绝所有工具,否则会导致 tools: []
|
|
78
|
+
return undefined
|
|
88
79
|
},
|
|
89
80
|
},
|
|
90
81
|
reload: { configPrefixes: ["channels.meet"] },
|
package/src/reply-dispatcher.ts
CHANGED
|
@@ -50,8 +50,12 @@ export function protectMentionsInChunks(chunks: string[]): string[] {
|
|
|
50
50
|
if (endMatch) {
|
|
51
51
|
// 将不完整的部分移到下一个 chunk 前面
|
|
52
52
|
const splitIndex = chunk.lastIndexOf("<@")
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
// splitIndex >= 0 时处理(包括 chunk 只有 "<@" 的情况)
|
|
54
|
+
if (splitIndex >= 0) {
|
|
55
|
+
// 如果 splitIndex 之前有内容,保留到 result
|
|
56
|
+
if (splitIndex > 0) {
|
|
57
|
+
result.push(chunk.slice(0, splitIndex))
|
|
58
|
+
}
|
|
55
59
|
pendingSuffix = chunk.slice(splitIndex)
|
|
56
60
|
continue
|
|
57
61
|
}
|
package/src/send.ts
CHANGED
|
@@ -52,6 +52,57 @@ export function inferContentTypeFromFileName(fileName: string): string | undefin
|
|
|
52
52
|
return mimeMap[ext];
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
/**
|
|
56
|
+
* 根据 MIME 类型获取文件扩展名
|
|
57
|
+
*/
|
|
58
|
+
function getExtensionFromContentType(contentType: string): string | undefined {
|
|
59
|
+
const mimeToExt: Record<string, string> = {
|
|
60
|
+
"image/jpeg": ".jpg",
|
|
61
|
+
"image/png": ".png",
|
|
62
|
+
"image/gif": ".gif",
|
|
63
|
+
"image/webp": ".webp",
|
|
64
|
+
"image/avif": ".avif",
|
|
65
|
+
"image/heic": ".heic",
|
|
66
|
+
"image/heif": ".heif",
|
|
67
|
+
"image/bmp": ".bmp",
|
|
68
|
+
"image/x-icon": ".ico",
|
|
69
|
+
"image/svg+xml": ".svg",
|
|
70
|
+
"image/tiff": ".tiff",
|
|
71
|
+
"video/mp4": ".mp4",
|
|
72
|
+
"video/webm": ".webm",
|
|
73
|
+
"video/quicktime": ".mov",
|
|
74
|
+
"video/x-msvideo": ".avi",
|
|
75
|
+
"video/x-matroska": ".mkv",
|
|
76
|
+
"audio/mpeg": ".mp3",
|
|
77
|
+
"audio/wav": ".wav",
|
|
78
|
+
"audio/ogg": ".ogg",
|
|
79
|
+
"audio/flac": ".flac",
|
|
80
|
+
"audio/mp4": ".m4a",
|
|
81
|
+
"application/pdf": ".pdf",
|
|
82
|
+
"application/json": ".json",
|
|
83
|
+
"application/xml": ".xml",
|
|
84
|
+
};
|
|
85
|
+
return mimeToExt[contentType];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* 确保文件名有正确的扩展名
|
|
90
|
+
* 如果文件名没有扩展名,根据 contentType 添加
|
|
91
|
+
*/
|
|
92
|
+
function ensureFileNameExtension(fileName: string, contentType: string): string {
|
|
93
|
+
// 检查是否已有扩展名
|
|
94
|
+
const hasExtension = /\.[a-zA-Z0-9]+$/.test(fileName);
|
|
95
|
+
if (hasExtension) {
|
|
96
|
+
return fileName;
|
|
97
|
+
}
|
|
98
|
+
// 根据 contentType 添加扩展名
|
|
99
|
+
const ext = getExtensionFromContentType(contentType);
|
|
100
|
+
if (ext) {
|
|
101
|
+
return fileName + ext;
|
|
102
|
+
}
|
|
103
|
+
return fileName;
|
|
104
|
+
}
|
|
105
|
+
|
|
55
106
|
/**
|
|
56
107
|
* 获取最终的 contentType
|
|
57
108
|
* 如果原始 contentType 缺失或为通用二进制流,则根据文件名推断
|
|
@@ -78,7 +129,9 @@ export function setSendMessageLogger(logger: RuntimeEnv): void {
|
|
|
78
129
|
function log(message: string): void {
|
|
79
130
|
if (_logger) {
|
|
80
131
|
_logger.log(message);
|
|
132
|
+
return;
|
|
81
133
|
}
|
|
134
|
+
console.log(message);
|
|
82
135
|
}
|
|
83
136
|
|
|
84
137
|
function logError(message: string): void {
|
|
@@ -118,6 +171,11 @@ export async function sendMessageMeet(
|
|
|
118
171
|
if (!account.configured) {
|
|
119
172
|
throw new Error(`Meet account not configured: ${accountId ?? "default"}`);
|
|
120
173
|
}
|
|
174
|
+
// logLevel: info 时记录 AI 输出的原始内容,方便调试 mention 格式问题
|
|
175
|
+
// 默认为 silent,只有显式设置为 info 时才输出
|
|
176
|
+
if (account.config.logLevel === "info") {
|
|
177
|
+
console.log(`[${account.accountId}] AI output raw text: ${JSON.stringify(text)}`);
|
|
178
|
+
}
|
|
121
179
|
const token = account.apiToken;
|
|
122
180
|
if (!token) {
|
|
123
181
|
throw new Error("Meet API token not configured");
|
|
@@ -200,8 +258,10 @@ export async function sendMediaMeet(
|
|
|
200
258
|
}
|
|
201
259
|
|
|
202
260
|
const sessionInfo = parseTargetToSessionInfo(to, Number(botUserId));
|
|
203
|
-
const
|
|
204
|
-
const contentType = resolveContentType(
|
|
261
|
+
const rawFileName = media.fileName || "file";
|
|
262
|
+
const contentType = resolveContentType(rawFileName, media.contentType);
|
|
263
|
+
// 确保文件名有正确的扩展名
|
|
264
|
+
const fileName = ensureFileNameExtension(rawFileName, contentType);
|
|
205
265
|
|
|
206
266
|
log(
|
|
207
267
|
`sending media to=${to} fileName=${fileName} size=${media.buffer.length} contentType=${contentType}`,
|