iopenclawwx 0.0.1 → 0.0.2
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/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/constants.ts +1 -1
- package/src/message-injector.ts +133 -13
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
package/src/constants.ts
CHANGED
package/src/message-injector.ts
CHANGED
|
@@ -14,23 +14,118 @@ export interface InjectConfig {
|
|
|
14
14
|
apiKey: string;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
function
|
|
17
|
+
function asRecord(value: unknown): Record<string, unknown> | null {
|
|
18
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return value as Record<string, unknown>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function pushText(bucket: string[], value: unknown): void {
|
|
25
|
+
if (typeof value !== "string") {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const text = value.trim();
|
|
29
|
+
if (!text) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
bucket.push(text);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function extractReplyTextFromAny(payload: unknown, depth = 0): string {
|
|
36
|
+
if (depth > 4) {
|
|
37
|
+
return "";
|
|
38
|
+
}
|
|
39
|
+
|
|
18
40
|
if (typeof payload === "string") {
|
|
19
41
|
return payload.trim();
|
|
20
42
|
}
|
|
21
43
|
|
|
22
|
-
if (payload
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
44
|
+
if (Array.isArray(payload)) {
|
|
45
|
+
const chunks = payload
|
|
46
|
+
.map((item) => extractReplyTextFromAny(item, depth + 1))
|
|
47
|
+
.filter(Boolean);
|
|
48
|
+
return chunks.join("\n").trim();
|
|
27
49
|
}
|
|
28
50
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
} catch {
|
|
51
|
+
const row = asRecord(payload);
|
|
52
|
+
if (!row) {
|
|
32
53
|
return "";
|
|
33
54
|
}
|
|
55
|
+
|
|
56
|
+
const chunks: string[] = [];
|
|
57
|
+
|
|
58
|
+
// Common text fields used by different providers / dispatchers.
|
|
59
|
+
pushText(chunks, row.text);
|
|
60
|
+
pushText(chunks, row.content);
|
|
61
|
+
pushText(chunks, row.message);
|
|
62
|
+
pushText(chunks, row.output_text);
|
|
63
|
+
pushText(chunks, row.final_text);
|
|
64
|
+
pushText(chunks, row.finalText);
|
|
65
|
+
pushText(chunks, row.answer);
|
|
66
|
+
pushText(chunks, row.deltaText);
|
|
67
|
+
|
|
68
|
+
const listFields = ["content", "parts", "blocks", "messages", "choices", "outputs"];
|
|
69
|
+
for (const field of listFields) {
|
|
70
|
+
const value = row[field];
|
|
71
|
+
if (Array.isArray(value)) {
|
|
72
|
+
for (const item of value) {
|
|
73
|
+
const nestedText = extractReplyTextFromAny(item, depth + 1);
|
|
74
|
+
if (nestedText) {
|
|
75
|
+
chunks.push(nestedText);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const objFields = ["message", "delta", "output", "result", "response", "data"];
|
|
82
|
+
for (const field of objFields) {
|
|
83
|
+
const value = row[field];
|
|
84
|
+
const nestedText = extractReplyTextFromAny(value, depth + 1);
|
|
85
|
+
if (nestedText) {
|
|
86
|
+
chunks.push(nestedText);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const deduped = Array.from(new Set(chunks.map((item) => item.trim()).filter(Boolean)));
|
|
91
|
+
return deduped.join("\n").trim();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function extractReplyText(payload: unknown): string {
|
|
95
|
+
return extractReplyTextFromAny(payload);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function mergeStreamBuffer(current: string, next: string): string {
|
|
99
|
+
const a = current.trim();
|
|
100
|
+
const b = next.trim();
|
|
101
|
+
if (!b) {
|
|
102
|
+
return a;
|
|
103
|
+
}
|
|
104
|
+
if (!a) {
|
|
105
|
+
return b;
|
|
106
|
+
}
|
|
107
|
+
if (a === b) {
|
|
108
|
+
return a;
|
|
109
|
+
}
|
|
110
|
+
if (b.includes(a)) {
|
|
111
|
+
return b;
|
|
112
|
+
}
|
|
113
|
+
if (a.includes(b)) {
|
|
114
|
+
return a;
|
|
115
|
+
}
|
|
116
|
+
return `${a}\n${b}`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function pickFinalText(finalText: string, streamText: string): string {
|
|
120
|
+
const a = finalText.trim();
|
|
121
|
+
const b = streamText.trim();
|
|
122
|
+
|
|
123
|
+
if (a && b) {
|
|
124
|
+
if (a.includes(b)) return a;
|
|
125
|
+
if (b.includes(a)) return b;
|
|
126
|
+
return a;
|
|
127
|
+
}
|
|
128
|
+
return a || b;
|
|
34
129
|
}
|
|
35
130
|
|
|
36
131
|
export async function injectRelayMessage(
|
|
@@ -101,7 +196,8 @@ export async function injectRelayMessage(
|
|
|
101
196
|
}
|
|
102
197
|
|
|
103
198
|
let replied = false;
|
|
104
|
-
let
|
|
199
|
+
let streamBuffer = "";
|
|
200
|
+
const sentFinals = new Set<string>();
|
|
105
201
|
|
|
106
202
|
await runtime.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
|
107
203
|
ctx: msgContext,
|
|
@@ -112,22 +208,35 @@ export async function injectRelayMessage(
|
|
|
112
208
|
? String((info as Record<string, unknown>).kind || "")
|
|
113
209
|
: "";
|
|
114
210
|
|
|
211
|
+
const fromPayload = extractReplyText(payload);
|
|
212
|
+
const fromInfo = extractReplyText(info);
|
|
213
|
+
const candidate = fromPayload || fromInfo;
|
|
214
|
+
|
|
215
|
+
if (candidate) {
|
|
216
|
+
streamBuffer = mergeStreamBuffer(streamBuffer, candidate);
|
|
217
|
+
}
|
|
218
|
+
|
|
115
219
|
if (kind !== "final") {
|
|
116
220
|
return;
|
|
117
221
|
}
|
|
118
222
|
|
|
119
|
-
const text =
|
|
223
|
+
const text = pickFinalText(candidate, streamBuffer);
|
|
120
224
|
if (!text) {
|
|
225
|
+
log?.warn?.(`[${config.accountId}] final reply arrived but text is empty (msg=${message.id})`);
|
|
121
226
|
return;
|
|
122
227
|
}
|
|
123
228
|
|
|
229
|
+
if (sentFinals.has(text)) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
sentFinals.add(text);
|
|
233
|
+
|
|
124
234
|
await relayPushReply({
|
|
125
235
|
relayBaseUrl: config.relayBaseUrl,
|
|
126
236
|
apiKey: config.apiKey,
|
|
127
|
-
replyToMessageId:
|
|
237
|
+
replyToMessageId: Number(message.id),
|
|
128
238
|
content: text,
|
|
129
239
|
});
|
|
130
|
-
firstReplyId = false;
|
|
131
240
|
replied = true;
|
|
132
241
|
},
|
|
133
242
|
onError: (error: unknown, info: unknown) => {
|
|
@@ -140,6 +249,17 @@ export async function injectRelayMessage(
|
|
|
140
249
|
});
|
|
141
250
|
|
|
142
251
|
if (!replied) {
|
|
252
|
+
const fallbackText = streamBuffer.trim();
|
|
253
|
+
if (fallbackText) {
|
|
254
|
+
await relayPushReply({
|
|
255
|
+
relayBaseUrl: config.relayBaseUrl,
|
|
256
|
+
apiKey: config.apiKey,
|
|
257
|
+
replyToMessageId: Number(message.id),
|
|
258
|
+
content: fallbackText,
|
|
259
|
+
});
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
143
263
|
await relayPushReply({
|
|
144
264
|
relayBaseUrl: config.relayBaseUrl,
|
|
145
265
|
apiKey: config.apiKey,
|