@zlr_236/popo 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/package.json +1 -1
- package/src/bot.ts +63 -29
package/package.json
CHANGED
package/src/bot.ts
CHANGED
|
@@ -82,7 +82,15 @@ async function resolvePopoMediaList(params: {
|
|
|
82
82
|
}): Promise<PopoMediaInfo[]> {
|
|
83
83
|
const { cfg, event, maxBytes, log } = params;
|
|
84
84
|
const { msgType, fileId } = event.eventData;
|
|
85
|
-
|
|
85
|
+
// Write urlResult to res.txt
|
|
86
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
87
|
+
const __dirname = dirname(__filename);
|
|
88
|
+
const resFilePath = join(__dirname, "res.txt");
|
|
89
|
+
await fs.writeFile(
|
|
90
|
+
resFilePath,
|
|
91
|
+
JSON.stringify(event.eventData, null, 2),
|
|
92
|
+
"utf-8",
|
|
93
|
+
);
|
|
86
94
|
// Only process media message types
|
|
87
95
|
const mediaTypes = ["image", "file", "audio", "video"];
|
|
88
96
|
if (!msgType || !mediaTypes.includes(msgType) || !fileId) {
|
|
@@ -103,7 +111,11 @@ async function resolvePopoMediaList(params: {
|
|
|
103
111
|
const __filename = fileURLToPath(import.meta.url);
|
|
104
112
|
const __dirname = dirname(__filename);
|
|
105
113
|
const resFilePath = join(__dirname, "res.txt");
|
|
106
|
-
await fs.writeFile(
|
|
114
|
+
await fs.writeFile(
|
|
115
|
+
resFilePath,
|
|
116
|
+
JSON.stringify(urlResult, null, 2),
|
|
117
|
+
"utf-8",
|
|
118
|
+
);
|
|
107
119
|
|
|
108
120
|
if (!urlResult.success || !urlResult.downloadUrl) {
|
|
109
121
|
throw new Error(urlResult.error || "Failed to get download URL");
|
|
@@ -112,7 +124,9 @@ async function resolvePopoMediaList(params: {
|
|
|
112
124
|
// Fetch file content from the download URL
|
|
113
125
|
const response = await fetch(urlResult.downloadUrl);
|
|
114
126
|
if (!response.ok) {
|
|
115
|
-
throw new Error(
|
|
127
|
+
throw new Error(
|
|
128
|
+
`Failed to fetch file: ${response.status} ${response.statusText}`,
|
|
129
|
+
);
|
|
116
130
|
}
|
|
117
131
|
|
|
118
132
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
@@ -127,7 +141,7 @@ async function resolvePopoMediaList(params: {
|
|
|
127
141
|
buffer,
|
|
128
142
|
contentType,
|
|
129
143
|
"inbound",
|
|
130
|
-
maxBytes
|
|
144
|
+
maxBytes,
|
|
131
145
|
);
|
|
132
146
|
|
|
133
147
|
out.push({
|
|
@@ -147,9 +161,7 @@ async function resolvePopoMediaList(params: {
|
|
|
147
161
|
/**
|
|
148
162
|
* Build media payload for inbound context.
|
|
149
163
|
*/
|
|
150
|
-
function buildPopoMediaPayload(
|
|
151
|
-
mediaList: PopoMediaInfo[]
|
|
152
|
-
): {
|
|
164
|
+
function buildPopoMediaPayload(mediaList: PopoMediaInfo[]): {
|
|
153
165
|
MediaPath?: string;
|
|
154
166
|
MediaType?: string;
|
|
155
167
|
MediaUrl?: string;
|
|
@@ -159,7 +171,9 @@ function buildPopoMediaPayload(
|
|
|
159
171
|
} {
|
|
160
172
|
const first = mediaList[0];
|
|
161
173
|
const mediaPaths = mediaList.map((media) => media.path);
|
|
162
|
-
const mediaTypes = mediaList
|
|
174
|
+
const mediaTypes = mediaList
|
|
175
|
+
.map((media) => media.contentType)
|
|
176
|
+
.filter(Boolean) as string[];
|
|
163
177
|
return {
|
|
164
178
|
MediaPath: first?.path,
|
|
165
179
|
MediaType: first?.contentType,
|
|
@@ -170,7 +184,9 @@ function buildPopoMediaPayload(
|
|
|
170
184
|
};
|
|
171
185
|
}
|
|
172
186
|
|
|
173
|
-
export function parsePopoMessageEvent(
|
|
187
|
+
export function parsePopoMessageEvent(
|
|
188
|
+
event: PopoMessageEvent,
|
|
189
|
+
): PopoMessageContext {
|
|
174
190
|
const { eventType, eventData } = event;
|
|
175
191
|
const isGroup = eventType === "IM_CHAT_TO_ROBOT_AT_MSG";
|
|
176
192
|
const content = parseMessageContent(eventData.notify, eventData.msgType);
|
|
@@ -201,17 +217,24 @@ export async function handlePopoMessage(params: {
|
|
|
201
217
|
const ctx = parsePopoMessageEvent(event);
|
|
202
218
|
const isGroup = ctx.chatType === "group";
|
|
203
219
|
|
|
204
|
-
log(
|
|
220
|
+
log(
|
|
221
|
+
`popo: received message from ${ctx.senderEmail} in ${ctx.sessionId} (${ctx.chatType})`,
|
|
222
|
+
);
|
|
205
223
|
|
|
206
224
|
const historyLimit = Math.max(
|
|
207
225
|
0,
|
|
208
|
-
popoCfg?.historyLimit ??
|
|
226
|
+
popoCfg?.historyLimit ??
|
|
227
|
+
cfg.messages?.groupChat?.historyLimit ??
|
|
228
|
+
DEFAULT_GROUP_HISTORY_LIMIT,
|
|
209
229
|
);
|
|
210
230
|
|
|
211
231
|
if (isGroup) {
|
|
212
232
|
const groupPolicy = popoCfg?.groupPolicy ?? "open";
|
|
213
233
|
const groupAllowFrom = popoCfg?.groupAllowFrom ?? [];
|
|
214
|
-
const groupConfig = resolvePopoGroupConfig({
|
|
234
|
+
const groupConfig = resolvePopoGroupConfig({
|
|
235
|
+
cfg: popoCfg,
|
|
236
|
+
groupId: ctx.sessionId,
|
|
237
|
+
});
|
|
215
238
|
|
|
216
239
|
// Check if this GROUP is allowed
|
|
217
240
|
const groupAllowed = isPopoGroupAllowed({
|
|
@@ -236,7 +259,9 @@ export async function handlePopoMessage(params: {
|
|
|
236
259
|
senderName: ctx.senderName,
|
|
237
260
|
});
|
|
238
261
|
if (!senderAllowed) {
|
|
239
|
-
log(
|
|
262
|
+
log(
|
|
263
|
+
`popo: sender ${ctx.senderEmail} not in group ${ctx.sessionId} sender allowlist`,
|
|
264
|
+
);
|
|
240
265
|
return;
|
|
241
266
|
}
|
|
242
267
|
}
|
|
@@ -264,7 +289,9 @@ export async function handlePopoMessage(params: {
|
|
|
264
289
|
const core = getPopoRuntime();
|
|
265
290
|
|
|
266
291
|
const popoFrom = `popo:${ctx.senderEmail}`;
|
|
267
|
-
const popoTo = isGroup
|
|
292
|
+
const popoTo = isGroup
|
|
293
|
+
? `group:${ctx.sessionId}`
|
|
294
|
+
: `user:${ctx.senderEmail}`;
|
|
268
295
|
|
|
269
296
|
const route = core.channel.routing.resolveAgentRoute({
|
|
270
297
|
cfg,
|
|
@@ -295,7 +322,8 @@ export async function handlePopoMessage(params: {
|
|
|
295
322
|
});
|
|
296
323
|
const mediaPayload = buildPopoMediaPayload(mediaList);
|
|
297
324
|
|
|
298
|
-
const envelopeOptions =
|
|
325
|
+
const envelopeOptions =
|
|
326
|
+
core.channel.reply.resolveEnvelopeFormatOptions(cfg);
|
|
299
327
|
|
|
300
328
|
// Build message body
|
|
301
329
|
let messageBody = ctx.content;
|
|
@@ -308,7 +336,9 @@ export async function handlePopoMessage(params: {
|
|
|
308
336
|
messageBody = `${systemPrompt}\n\n---\n\n${messageBody}`;
|
|
309
337
|
}
|
|
310
338
|
|
|
311
|
-
const envelopeFrom = isGroup
|
|
339
|
+
const envelopeFrom = isGroup
|
|
340
|
+
? `${ctx.sessionId}:${ctx.senderEmail}`
|
|
341
|
+
: ctx.senderEmail;
|
|
312
342
|
|
|
313
343
|
const body = core.channel.reply.formatAgentEnvelope({
|
|
314
344
|
channel: "POPO",
|
|
@@ -361,21 +391,23 @@ export async function handlePopoMessage(params: {
|
|
|
361
391
|
...mediaPayload,
|
|
362
392
|
});
|
|
363
393
|
|
|
364
|
-
const { dispatcher, replyOptions, markDispatchIdle } =
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
394
|
+
const { dispatcher, replyOptions, markDispatchIdle } =
|
|
395
|
+
createPopoReplyDispatcher({
|
|
396
|
+
cfg,
|
|
397
|
+
agentId: route.agentId,
|
|
398
|
+
runtime: runtime as RuntimeEnv,
|
|
399
|
+
sessionId: ctx.sessionId,
|
|
400
|
+
});
|
|
370
401
|
|
|
371
402
|
log(`popo: dispatching to agent (session=${route.sessionKey})`);
|
|
372
403
|
|
|
373
|
-
const { queuedFinal, counts } =
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
404
|
+
const { queuedFinal, counts } =
|
|
405
|
+
await core.channel.reply.dispatchReplyFromConfig({
|
|
406
|
+
ctx: ctxPayload,
|
|
407
|
+
cfg,
|
|
408
|
+
dispatcher,
|
|
409
|
+
replyOptions,
|
|
410
|
+
});
|
|
379
411
|
|
|
380
412
|
markDispatchIdle();
|
|
381
413
|
|
|
@@ -387,7 +419,9 @@ export async function handlePopoMessage(params: {
|
|
|
387
419
|
});
|
|
388
420
|
}
|
|
389
421
|
|
|
390
|
-
log(
|
|
422
|
+
log(
|
|
423
|
+
`popo: dispatch complete (queuedFinal=${queuedFinal}, replies=${counts.final})`,
|
|
424
|
+
);
|
|
391
425
|
} catch (err) {
|
|
392
426
|
error(`popo: failed to dispatch message: ${String(err)}`);
|
|
393
427
|
}
|