forked from SelectXn00b/AndroidForClaw
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFeishuMention.kt
More file actions
190 lines (171 loc) · 5.21 KB
/
FeishuMention.kt
File metadata and controls
190 lines (171 loc) · 5.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
package com.xiaomo.feishu.messaging
/**
* OpenClaw Source Reference:
* - ../openclaw/src/channels/feishu/(all)
*
* AndroidForClaw adaptation: Feishu messaging transport.
*/
/**
* Feishu @mention handling
* Aligned with OpenClaw mention.ts
*
* Feature:
* - Extract @mention targets from messages
* - Detect if it's a forward request
* - Format @mention tags
*/
object FeishuMention {
/**
* Mention target info
*/
data class MentionTarget(
val openId: String,
val name: String,
val key: String // placeholder, e.g. @_user_1
)
/**
* Escape regex metacharacters
*/
private fun escapeRegex(input: String): String {
return Regex.escape(input)
}
/**
* Extract mention targets from MessageEvent (excluding the bot itself)
*
* @param mentions List of mentions
* @param botOpenId Bot's open_id
* @return List of mention targets
*/
fun extractMentionTargets(
mentions: List<Map<String, Any?>>,
botOpenId: String? = null
): List<MentionTarget> {
return mentions.mapNotNull { mention ->
val id = mention["id"] as? Map<*, *>
val openId = id?.get("open_id") as? String
val name = mention["name"] as? String ?: ""
val key = mention["key"] as? String ?: ""
// Exclude bot itself && must have open_id
if (openId != null && openId != botOpenId) {
MentionTarget(openId, name, key)
} else {
null
}
}
}
/**
* Check if it's a mention forward request
*
* Rule:
* - Group chat: Message mentions bot + at least one other user
* - Direct message: Message mentions any user (no need to mention bot)
*
* @param mentions List of mentions
* @param chatType Chat type (p2p/group)
* @param botOpenId Bot's open_id
* @return Whether it's a forward request
*/
fun isMentionForwardRequest(
mentions: List<Map<String, Any?>>,
chatType: String,
botOpenId: String?
): Boolean {
if (mentions.isEmpty()) {
return false
}
val isDirectMessage = chatType != "group"
val hasOtherMention = mentions.any { mention ->
val id = mention["id"] as? Map<*, *>
val openId = id?.get("open_id") as? String
openId != botOpenId
}
return if (isDirectMessage) {
// DM: mention any non-bot user triggers
hasOtherMention
} else {
// Group: need to mention both bot and other users
val hasBotMention = mentions.any { mention ->
val id = mention["id"] as? Map<*, *>
val openId = id?.get("open_id") as? String
openId == botOpenId
}
hasBotMention && hasOtherMention
}
}
/**
* Extract message body (removing @ placeholders)
*
* @param text Original text
* @param allMentionKeys List of all @ placeholders
* @return Cleaned text
*/
fun extractMessageBody(text: String, allMentionKeys: List<String>): String {
var result = text
// Remove all @ placeholders
for (key in allMentionKeys) {
result = result.replace(Regex(escapeRegex(key)), "")
}
// Compress whitespace
return result.replace(Regex("\\s+"), " ").trim()
}
/**
* Format @mention tag (text message)
*
* @param target Mention target
* @return Formatted tag
*/
fun formatMentionForText(target: MentionTarget): String {
return """<at user_id="${target.openId}">${target.name}</at>"""
}
/**
* Format @all tag (text message)
*/
fun formatMentionAllForText(): String {
return """<at user_id="all">Everyone</at>"""
}
/**
* Format @mention tag (card message lark_md)
*
* @param target Mention target
* @return Formatted tag
*/
fun formatMentionForCard(target: MentionTarget): String {
return """<at id=${target.openId}></at>"""
}
/**
* Format @all tag (card message lark_md)
*/
fun formatMentionAllForCard(): String {
return """<at id=all></at>"""
}
/**
* Build text message with mentions
*
* @param targets List of mention targets
* @param messageBody Message body
* @return Complete message text
*/
fun buildMentionedMessage(targets: List<MentionTarget>, messageBody: String): String {
val mentions = targets.joinToString(" ") { formatMentionForText(it) }
return if (mentions.isNotEmpty()) {
"$mentions $messageBody"
} else {
messageBody
}
}
/**
* Build card content with mentions (lark_md)
*
* @param targets List of mention targets
* @param cardContent Card content
* @return Card content with mentions
*/
fun buildMentionedCardContent(targets: List<MentionTarget>, cardContent: String): String {
val mentions = targets.joinToString(" ") { formatMentionForCard(it) }
return if (mentions.isNotEmpty()) {
"$mentions\n\n$cardContent"
} else {
cardContent
}
}
}