@ai-setting/roy-agent-core 1.5.89 → 1.5.90
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/dist/env/agent/index.js +3 -3
- package/dist/env/event-source/index.js +8 -4
- package/dist/env/index.js +9 -9
- package/dist/env/llm/index.js +4 -2
- package/dist/env/session/index.js +3 -3
- package/dist/env/session/storage/index.js +2 -2
- package/dist/env/task/plugins/index.js +1 -1
- package/dist/env/workflow/engine/index.js +2 -2
- package/dist/env/workflow/index.js +3 -3
- package/dist/env/workflow/nodes/index.js +1 -1
- package/dist/index.js +119 -14
- package/dist/shared/@ai-setting/{roy-agent-core-r0m0at3x.js → roy-agent-core-0r4ndyn9.js} +119 -7
- package/dist/shared/@ai-setting/{roy-agent-core-fvfc7f6v.js → roy-agent-core-2c8eraxq.js} +62 -8
- package/dist/shared/@ai-setting/{roy-agent-core-h2d1s8yd.js → roy-agent-core-5ykms33a.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-fgpnv7dt.js → roy-agent-core-8zjntsbb.js} +71 -28
- package/dist/shared/@ai-setting/{roy-agent-core-vneyghpg.js → roy-agent-core-ddq5hcp5.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-qhhxx2x2.js → roy-agent-core-ds5f75pg.js} +2 -1
- package/dist/shared/@ai-setting/{roy-agent-core-3f6k060j.js → roy-agent-core-j0107ww1.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-2q7cshpm.js → roy-agent-core-m683wd1n.js} +283 -15
- package/dist/shared/@ai-setting/{roy-agent-core-qbq3jgrn.js → roy-agent-core-rkz8r2sx.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-c1j7ev4e.js → roy-agent-core-txwf64pd.js} +70 -0
- package/dist/shared/@ai-setting/{roy-agent-core-m3dkyprg.js → roy-agent-core-w0kb72ve.js} +7 -2
- package/dist/shared/@ai-setting/{roy-agent-core-hc20420t.js → roy-agent-core-z240ts1r.js} +27 -3
- package/dist/shared/@ai-setting/{roy-agent-core-q7sqeax6.js → roy-agent-core-zky9jse4.js} +163 -3
- package/package.json +1 -1
- /package/dist/shared/@ai-setting/{roy-agent-core-4f3976cd.js → roy-agent-core-k5hxvaf0.js} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TaskTagPlugin,
|
|
3
3
|
createLarkCliTaskNotifyHook
|
|
4
|
-
} from "./roy-agent-core-
|
|
4
|
+
} from "./roy-agent-core-w0kb72ve.js";
|
|
5
5
|
import {
|
|
6
6
|
envKeyToConfigKey
|
|
7
7
|
} from "./roy-agent-core-qxhq8ven.js";
|
|
@@ -192,6 +192,249 @@ var timerHandler = {
|
|
|
192
192
|
}
|
|
193
193
|
};
|
|
194
194
|
|
|
195
|
+
// src/env/event-source/bounty-im-handler.ts
|
|
196
|
+
function readBountyIMConfig(config) {
|
|
197
|
+
const topLevelAddress = config.address;
|
|
198
|
+
const topLevelUrl = config.imServerUrl;
|
|
199
|
+
const optionsAddress = config.options?.address;
|
|
200
|
+
const optionsUrl = config.options?.imServerUrl;
|
|
201
|
+
return {
|
|
202
|
+
address: topLevelAddress || optionsAddress,
|
|
203
|
+
imServerUrl: topLevelUrl || optionsUrl
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function readBountyIMTlsSkipVerify(config) {
|
|
207
|
+
const topLevel = config.tlsSkipVerify;
|
|
208
|
+
const fromOptions = config.options?.tlsSkipVerify;
|
|
209
|
+
const raw = topLevel !== undefined ? topLevel : fromOptions;
|
|
210
|
+
return raw === true;
|
|
211
|
+
}
|
|
212
|
+
function shouldWriteBunTlsSkipEnv(tlsSkipVerify, isBunRuntimeOverride) {
|
|
213
|
+
const isBun = isBunRuntimeOverride ?? typeof Bun !== "undefined";
|
|
214
|
+
return tlsSkipVerify === true && isBun;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
class BountyIMInstance {
|
|
218
|
+
config;
|
|
219
|
+
status = "created";
|
|
220
|
+
ws = null;
|
|
221
|
+
buffer = "";
|
|
222
|
+
eventHandler;
|
|
223
|
+
constructor(config) {
|
|
224
|
+
this.config = config;
|
|
225
|
+
}
|
|
226
|
+
getCurrentAddress() {
|
|
227
|
+
const { address } = readBountyIMConfig(this.config);
|
|
228
|
+
return address || "unknown";
|
|
229
|
+
}
|
|
230
|
+
getStatus() {
|
|
231
|
+
return this.status;
|
|
232
|
+
}
|
|
233
|
+
async start() {
|
|
234
|
+
if (this.status === "running")
|
|
235
|
+
return;
|
|
236
|
+
this.setStatus("starting");
|
|
237
|
+
const { address, imServerUrl } = readBountyIMConfig(this.config);
|
|
238
|
+
if (!imServerUrl) {
|
|
239
|
+
throw new Error("imServerUrl is required for bounty-im event source");
|
|
240
|
+
}
|
|
241
|
+
const wsUrl = new URL(imServerUrl);
|
|
242
|
+
if (address) {
|
|
243
|
+
wsUrl.searchParams.set("address", address);
|
|
244
|
+
}
|
|
245
|
+
console.log(`[BountyIM] Connecting to ${wsUrl.toString()}...`);
|
|
246
|
+
try {
|
|
247
|
+
const { WebSocket } = await import("ws");
|
|
248
|
+
const tlsSkipVerify = readBountyIMTlsSkipVerify(this.config);
|
|
249
|
+
const isWss = imServerUrl.startsWith("wss://");
|
|
250
|
+
if (isWss && shouldWriteBunTlsSkipEnv(tlsSkipVerify)) {
|
|
251
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
252
|
+
}
|
|
253
|
+
this.ws = new WebSocket(wsUrl.toString(), {
|
|
254
|
+
headers: this.config.headers,
|
|
255
|
+
rejectUnauthorized: !tlsSkipVerify
|
|
256
|
+
});
|
|
257
|
+
this.ws.on("open", () => {
|
|
258
|
+
console.log(`[BountyIM] Connected${address ? ` as ${address}` : ""}`);
|
|
259
|
+
this.setStatus("running");
|
|
260
|
+
});
|
|
261
|
+
this.ws.on("message", (data) => {
|
|
262
|
+
this.handleMessage(data.toString());
|
|
263
|
+
});
|
|
264
|
+
this.ws.on("error", (error) => {
|
|
265
|
+
console.error(`[BountyIM] Error:`, error.message);
|
|
266
|
+
this.setStatus("error");
|
|
267
|
+
});
|
|
268
|
+
this.ws.on("close", () => {
|
|
269
|
+
console.log(`[BountyIM] Connection closed`);
|
|
270
|
+
this.setStatus("stopped");
|
|
271
|
+
});
|
|
272
|
+
} catch (error) {
|
|
273
|
+
this.setStatus("error");
|
|
274
|
+
throw new Error(`Failed to connect to Bounty IM server: ${error}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
async stop() {
|
|
278
|
+
if (this.status === "stopped" || this.status === "created")
|
|
279
|
+
return;
|
|
280
|
+
this.setStatus("stopping");
|
|
281
|
+
if (this.ws) {
|
|
282
|
+
this.ws.close();
|
|
283
|
+
this.ws = null;
|
|
284
|
+
}
|
|
285
|
+
this.setStatus("stopped");
|
|
286
|
+
}
|
|
287
|
+
onEvent(handler) {
|
|
288
|
+
this.eventHandler = handler;
|
|
289
|
+
}
|
|
290
|
+
offEvent() {
|
|
291
|
+
this.eventHandler = undefined;
|
|
292
|
+
}
|
|
293
|
+
setStatus(status) {
|
|
294
|
+
this.status = status;
|
|
295
|
+
}
|
|
296
|
+
handleMessage(data) {
|
|
297
|
+
this.buffer += data;
|
|
298
|
+
try {
|
|
299
|
+
JSON.parse(this.buffer);
|
|
300
|
+
this.processLine(this.buffer);
|
|
301
|
+
this.buffer = "";
|
|
302
|
+
} catch {}
|
|
303
|
+
}
|
|
304
|
+
processLine(rawData) {
|
|
305
|
+
try {
|
|
306
|
+
let rawEvent;
|
|
307
|
+
try {
|
|
308
|
+
rawEvent = JSON.parse(rawData);
|
|
309
|
+
} catch {
|
|
310
|
+
rawEvent = {
|
|
311
|
+
event: "message",
|
|
312
|
+
data: { content: { type: "text", body: rawData } }
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
const evt = rawEvent;
|
|
316
|
+
const msg = evt.data || {};
|
|
317
|
+
if (evt.event !== "message") {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const eventType = `bounty-im.${evt.event || "message"}`;
|
|
321
|
+
const fromAddress = msg.from || "unknown";
|
|
322
|
+
const currentAddress = this.getCurrentAddress();
|
|
323
|
+
const toAddress = msg.to || currentAddress;
|
|
324
|
+
if (msg.to && msg.to !== currentAddress) {
|
|
325
|
+
console.warn(`[BountyIM] Warning: message.to (${msg.to}) !== current address (${currentAddress})`);
|
|
326
|
+
}
|
|
327
|
+
const msgContent = msg.content;
|
|
328
|
+
const content = msgContent?.type === "text" ? String(msgContent.body || "") : "";
|
|
329
|
+
const { imServerUrl } = readBountyIMConfig(this.config);
|
|
330
|
+
const agent = this.config.handleRule?.agent;
|
|
331
|
+
const metadata = {
|
|
332
|
+
eventType,
|
|
333
|
+
senderId: fromAddress,
|
|
334
|
+
chatId: toAddress,
|
|
335
|
+
agent
|
|
336
|
+
};
|
|
337
|
+
let recommendedAction;
|
|
338
|
+
if (evt.event === "message") {
|
|
339
|
+
recommendedAction = {
|
|
340
|
+
action: `处理消息并通过 bounty com send 回复发件人。使用格式:bounty com send -f ${toAddress} -t ${fromAddress} -b "回复内容"`,
|
|
341
|
+
replyTo: {
|
|
342
|
+
chatId: fromAddress
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
const replyChannel = {
|
|
347
|
+
type: "bounty-im",
|
|
348
|
+
chatId: fromAddress,
|
|
349
|
+
params: {
|
|
350
|
+
from: toAddress,
|
|
351
|
+
to: fromAddress,
|
|
352
|
+
imServerUrl
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
const displayMessage = content ? `[From ${fromAddress}] ${content}
|
|
356
|
+
|
|
357
|
+
\uD83D\uDCA1 回复: bounty com send -f ${toAddress} -t ${fromAddress} -b "回复内容"` : this.formatMessage(rawEvent);
|
|
358
|
+
const event = {
|
|
359
|
+
id: `es-${this.config.id}-${Date.now()}`,
|
|
360
|
+
type: eventType,
|
|
361
|
+
timestamp: Date.now(),
|
|
362
|
+
metadata: {
|
|
363
|
+
source: "event-source",
|
|
364
|
+
sourceId: this.config.id,
|
|
365
|
+
agent
|
|
366
|
+
},
|
|
367
|
+
payload: {
|
|
368
|
+
sourceId: this.config.id,
|
|
369
|
+
sourceType: "bounty-im",
|
|
370
|
+
rawEvent,
|
|
371
|
+
message: displayMessage,
|
|
372
|
+
metadata,
|
|
373
|
+
recommendedAction,
|
|
374
|
+
replyChannel,
|
|
375
|
+
timestamp: Date.now()
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
this.eventHandler?.(event);
|
|
379
|
+
if (msg.id && this.ws) {
|
|
380
|
+
try {
|
|
381
|
+
const ackPayload = JSON.stringify({
|
|
382
|
+
event: "ack",
|
|
383
|
+
data: { messageIds: [msg.id] }
|
|
384
|
+
});
|
|
385
|
+
this.ws.send(ackPayload);
|
|
386
|
+
console.log(`[BountyIM] 已发送 ACK for message: ${msg.id}`);
|
|
387
|
+
} catch (ackErr) {
|
|
388
|
+
console.error(`[BountyIM] 发送 ACK 失败:`, ackErr);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
} catch (err) {
|
|
392
|
+
console.error(`[BountyIM] Error processing message:`, err);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
formatMessage(rawEvent) {
|
|
396
|
+
const evt = rawEvent;
|
|
397
|
+
if (evt.event === "connected") {
|
|
398
|
+
return `✅ 已连接到 bounty IM 服务器`;
|
|
399
|
+
}
|
|
400
|
+
if (evt.event === "message") {
|
|
401
|
+
const msg = evt.data || {};
|
|
402
|
+
const from = msg.from || "unknown";
|
|
403
|
+
let content = "未知内容";
|
|
404
|
+
if (msg.content?.type === "text") {
|
|
405
|
+
content = String(msg.content?.body || "");
|
|
406
|
+
}
|
|
407
|
+
return `[${from}] ${content}`;
|
|
408
|
+
}
|
|
409
|
+
return `事件: ${evt.event || "unknown"}`;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
var bountyIMHandler = {
|
|
413
|
+
type: "bounty-im",
|
|
414
|
+
validateConfig(config) {
|
|
415
|
+
const errors = [];
|
|
416
|
+
if (!config.id)
|
|
417
|
+
errors.push("EventSource ID is required");
|
|
418
|
+
if (!config.name)
|
|
419
|
+
errors.push("EventSource name is required");
|
|
420
|
+
const { address, imServerUrl } = readBountyIMConfig(config);
|
|
421
|
+
if (!address) {
|
|
422
|
+
errors.push("Bounty IM address is required (top-level address or options.address)");
|
|
423
|
+
} else if (!/^[\w-]+@[\w.-]+$/.test(address)) {
|
|
424
|
+
errors.push("Bounty IM address format invalid (expected: agent-id@host)");
|
|
425
|
+
}
|
|
426
|
+
if (!imServerUrl) {
|
|
427
|
+
errors.push("Bounty IM imServerUrl is required (top-level imServerUrl or options.imServerUrl)");
|
|
428
|
+
} else if (!imServerUrl.startsWith("ws://") && !imServerUrl.startsWith("wss://")) {
|
|
429
|
+
errors.push("Bounty IM imServerUrl must start with ws:// or wss://");
|
|
430
|
+
}
|
|
431
|
+
return errors;
|
|
432
|
+
},
|
|
433
|
+
createInstance(config) {
|
|
434
|
+
return new BountyIMInstance(config);
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
|
|
195
438
|
// src/env/event-source/event-source-handlers.ts
|
|
196
439
|
init_global_hook_manager();
|
|
197
440
|
import { spawn } from "child_process";
|
|
@@ -259,18 +502,24 @@ function extractMetadata(rawEvent, eventType) {
|
|
|
259
502
|
}
|
|
260
503
|
let recommendedAction;
|
|
261
504
|
if (eventType === "im.message.receive_v1" || event.type === "im.message.receive_v1") {
|
|
505
|
+
const profile2 = event.profile;
|
|
506
|
+
const profileFlag = profile2 ? `--profile ${profile2} ` : "";
|
|
507
|
+
const profileHint = profile2 ? `(⚠️ 必须使用 profile="${profile2}" 调用 lark-cli,否则会因 openId 跨 app 失败)` : "";
|
|
262
508
|
recommendedAction = {
|
|
263
|
-
action:
|
|
509
|
+
action: `处理飞书消息并以机器人身份回复${profileHint},例如:lark-cli ${profileFlag}im +messages-reply --message-id "xxxxid" --as bot --text "回复内容"`,
|
|
264
510
|
replyTo: {
|
|
265
511
|
appId: metadata.appId,
|
|
512
|
+
profile: profile2,
|
|
266
513
|
chatId: metadata.chatId,
|
|
267
514
|
messageId: metadata.messageId
|
|
268
515
|
}
|
|
269
516
|
};
|
|
270
517
|
}
|
|
518
|
+
const profile = event.profile;
|
|
271
519
|
const replyChannel = {
|
|
272
520
|
type: "lark-cli",
|
|
273
521
|
appId: metadata.appId,
|
|
522
|
+
profile,
|
|
274
523
|
chatId: messageData?.chat_id,
|
|
275
524
|
messageId: messageData?.message_id
|
|
276
525
|
};
|
|
@@ -291,7 +540,14 @@ class LarkCliInstance {
|
|
|
291
540
|
if (this.status === "running")
|
|
292
541
|
return;
|
|
293
542
|
await this.loadPlugins();
|
|
294
|
-
const
|
|
543
|
+
const profile = this.config.profile;
|
|
544
|
+
const profileFlag = profile ? `--profile ${profile} ` : "";
|
|
545
|
+
let command;
|
|
546
|
+
if (this.config.command) {
|
|
547
|
+
command = this.config.command.replace(/^(lark-cli)(\s+|$)/, (_, head, tail) => `${head} ${profileFlag.trim()}${tail}`);
|
|
548
|
+
} else {
|
|
549
|
+
command = `lark-cli ${profileFlag}event consume im.message.receive_v1 --as bot`;
|
|
550
|
+
}
|
|
295
551
|
this.child = spawn("exec " + command, [], {
|
|
296
552
|
shell: true,
|
|
297
553
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -530,7 +786,12 @@ class LarkCliInstance {
|
|
|
530
786
|
if (this.config.eventTypes?.length && !matchEventType(eventType, this.config.eventTypes)) {
|
|
531
787
|
return;
|
|
532
788
|
}
|
|
533
|
-
const
|
|
789
|
+
const enrichedEvent = {
|
|
790
|
+
...rawEvent,
|
|
791
|
+
profile: this.config.profile,
|
|
792
|
+
eventSourceId: this.config.id
|
|
793
|
+
};
|
|
794
|
+
const { metadata, replyChannel, recommendedAction } = extractMetadata(enrichedEvent, eventType);
|
|
534
795
|
const message = JSON.stringify({
|
|
535
796
|
rawData,
|
|
536
797
|
recommendedAction
|
|
@@ -598,18 +859,21 @@ class LarkCliInstance {
|
|
|
598
859
|
if (!replyChannel || !replyChannel.chatId && !replyChannel.messageId) {
|
|
599
860
|
return;
|
|
600
861
|
}
|
|
862
|
+
const profile = replyChannel.profile;
|
|
601
863
|
return {
|
|
602
864
|
type: replyChannel.type,
|
|
603
865
|
messageId: replyChannel.messageId,
|
|
604
866
|
chatId: replyChannel.chatId,
|
|
605
867
|
userId: replyChannel.params?.userId,
|
|
868
|
+
profile,
|
|
606
869
|
identity: "bot",
|
|
607
870
|
sendText: async (text) => {
|
|
608
871
|
await this.sendLarkMessage({
|
|
609
872
|
chatId: replyChannel.chatId,
|
|
610
873
|
userId: replyChannel.params?.userId,
|
|
611
874
|
content: text,
|
|
612
|
-
as: "bot"
|
|
875
|
+
as: "bot",
|
|
876
|
+
profile
|
|
613
877
|
});
|
|
614
878
|
},
|
|
615
879
|
sendMarkdown: async (markdown) => {
|
|
@@ -618,7 +882,8 @@ class LarkCliInstance {
|
|
|
618
882
|
userId: replyChannel.params?.userId,
|
|
619
883
|
content: markdown,
|
|
620
884
|
as: "bot",
|
|
621
|
-
format: "markdown"
|
|
885
|
+
format: "markdown",
|
|
886
|
+
profile
|
|
622
887
|
});
|
|
623
888
|
},
|
|
624
889
|
sendMessage: async (content) => {
|
|
@@ -626,7 +891,8 @@ class LarkCliInstance {
|
|
|
626
891
|
chatId: replyChannel.chatId,
|
|
627
892
|
userId: replyChannel.params?.userId,
|
|
628
893
|
content: JSON.stringify(content),
|
|
629
|
-
as: "bot"
|
|
894
|
+
as: "bot",
|
|
895
|
+
profile
|
|
630
896
|
});
|
|
631
897
|
},
|
|
632
898
|
reply: async (content) => {
|
|
@@ -634,7 +900,8 @@ class LarkCliInstance {
|
|
|
634
900
|
await this.sendLarkMessage({
|
|
635
901
|
messageId: replyChannel.messageId,
|
|
636
902
|
content: JSON.stringify(content),
|
|
637
|
-
as: "bot"
|
|
903
|
+
as: "bot",
|
|
904
|
+
profile
|
|
638
905
|
});
|
|
639
906
|
}
|
|
640
907
|
}
|
|
@@ -642,7 +909,7 @@ class LarkCliInstance {
|
|
|
642
909
|
}
|
|
643
910
|
async sendLarkMessage(options) {
|
|
644
911
|
return new Promise((resolve, reject) => {
|
|
645
|
-
const { chatId, userId, messageId, content, as: identity, format = "text" } = options;
|
|
912
|
+
const { chatId, userId, messageId, content, as: identity, format = "text", profile } = options;
|
|
646
913
|
const contentFlag = format === "markdown" ? "--markdown" : "--text";
|
|
647
914
|
const args = ["im", "+messages-send", "--as", identity];
|
|
648
915
|
if (messageId) {
|
|
@@ -655,6 +922,9 @@ class LarkCliInstance {
|
|
|
655
922
|
reject(new Error("No target specified for sending message"));
|
|
656
923
|
return;
|
|
657
924
|
}
|
|
925
|
+
if (profile) {
|
|
926
|
+
args.unshift("--profile", profile);
|
|
927
|
+
}
|
|
658
928
|
const proc = spawn("lark-cli", args, {
|
|
659
929
|
shell: false,
|
|
660
930
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -691,9 +961,6 @@ var larkCliHandler = {
|
|
|
691
961
|
type: "lark-cli",
|
|
692
962
|
validateConfig(config) {
|
|
693
963
|
const errors = [];
|
|
694
|
-
if (!config.command) {
|
|
695
|
-
errors.push("command is optional, will use default: lark-cli event consume im.message.receive_v1 --as bot");
|
|
696
|
-
}
|
|
697
964
|
return errors;
|
|
698
965
|
},
|
|
699
966
|
createInstance(config) {
|
|
@@ -702,7 +969,8 @@ var larkCliHandler = {
|
|
|
702
969
|
};
|
|
703
970
|
var builtInHandlers = [
|
|
704
971
|
larkCliHandler,
|
|
705
|
-
timerHandler
|
|
972
|
+
timerHandler,
|
|
973
|
+
bountyIMHandler
|
|
706
974
|
];
|
|
707
975
|
function getBuiltInHandler(type) {
|
|
708
976
|
return builtInHandlers.find((h) => h.type === type);
|
|
@@ -804,7 +1072,7 @@ class EventSourceComponent extends BaseComponent {
|
|
|
804
1072
|
}
|
|
805
1073
|
}
|
|
806
1074
|
async executeInitHooks() {
|
|
807
|
-
const { EventSourceInitHooks } = await import("./roy-agent-core-
|
|
1075
|
+
const { EventSourceInitHooks } = await import("./roy-agent-core-ddq5hcp5.js");
|
|
808
1076
|
await EventSourceInitHooks.execute(this);
|
|
809
1077
|
}
|
|
810
1078
|
registerHandler(handler) {
|
|
@@ -1146,4 +1414,4 @@ __legacyDecorateClassTS([
|
|
|
1146
1414
|
TracedAs("event-source.update", { recordParams: false, log: false })
|
|
1147
1415
|
], EventSourceComponent.prototype, "update", null);
|
|
1148
1416
|
|
|
1149
|
-
export { TimerInstance, timerHandler, larkCliHandler, builtInHandlers, getBuiltInHandler, EventSourceComponent };
|
|
1417
|
+
export { TimerInstance, timerHandler, BountyIMInstance, bountyIMHandler, larkCliHandler, builtInHandlers, getBuiltInHandler, EventSourceComponent };
|
|
@@ -5,6 +5,41 @@ import {
|
|
|
5
5
|
// src/env/session/session-message-converter.ts
|
|
6
6
|
import { randomUUID } from "crypto";
|
|
7
7
|
var DEFAULT_REASONING_BUDGET_TOKENS = 1e4;
|
|
8
|
+
function toModelImagePart(imagePart) {
|
|
9
|
+
return {
|
|
10
|
+
type: "image",
|
|
11
|
+
image: normalizeImagePayload(imagePart.image, imagePart.mimeType),
|
|
12
|
+
mimeType: imagePart.mimeType
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function isLegacyBufferShape(v) {
|
|
16
|
+
return typeof v === "object" && v !== null && !Array.isArray(v) && !(v instanceof Uint8Array) && !(v instanceof URL) && v.type === "Buffer" && Array.isArray(v.data);
|
|
17
|
+
}
|
|
18
|
+
function normalizeImagePayload(image, mimeType) {
|
|
19
|
+
if (typeof image === "string" || image instanceof URL) {
|
|
20
|
+
return image;
|
|
21
|
+
}
|
|
22
|
+
if (typeof Buffer !== "undefined" && Buffer.isBuffer(image)) {
|
|
23
|
+
const mime = mimeType ?? "image/jpeg";
|
|
24
|
+
return `data:${mime};base64,${image.toString("base64")}`;
|
|
25
|
+
}
|
|
26
|
+
if (image instanceof Uint8Array) {
|
|
27
|
+
if (typeof Buffer !== "undefined") {
|
|
28
|
+
const mime2 = mimeType ?? "image/jpeg";
|
|
29
|
+
return `data:${mime2};base64,${Buffer.from(image).toString("base64")}`;
|
|
30
|
+
}
|
|
31
|
+
let binary = "";
|
|
32
|
+
for (let i = 0;i < image.length; i++) {
|
|
33
|
+
binary += String.fromCharCode(image[i]);
|
|
34
|
+
}
|
|
35
|
+
const mime = mimeType ?? "image/jpeg";
|
|
36
|
+
return `data:${mime};base64,${globalThis.btoa?.(binary) ?? binary}`;
|
|
37
|
+
}
|
|
38
|
+
if (isLegacyBufferShape(image)) {
|
|
39
|
+
return new Uint8Array(image.data);
|
|
40
|
+
}
|
|
41
|
+
return image;
|
|
42
|
+
}
|
|
8
43
|
|
|
9
44
|
class SessionMessageConverter {
|
|
10
45
|
toModelMessage(msg) {
|
|
@@ -47,6 +82,8 @@ class SessionMessageConverter {
|
|
|
47
82
|
mimeType: filePart.mime,
|
|
48
83
|
filename: filePart.filename
|
|
49
84
|
});
|
|
85
|
+
} else if (part.type === "image") {
|
|
86
|
+
content.push(toModelImagePart(part));
|
|
50
87
|
} else if (part.type === "tool-result" || part.type === "checkpoint") {} else {
|
|
51
88
|
console.debug(`[session-message-converter] Skipping unsupported part type in assistant: ${part.type}`);
|
|
52
89
|
}
|
|
@@ -68,6 +105,32 @@ class SessionMessageConverter {
|
|
|
68
105
|
}]
|
|
69
106
|
};
|
|
70
107
|
}
|
|
108
|
+
if (msg.role === "user" || msg.role === "system") {
|
|
109
|
+
const parts = msg.parts || [];
|
|
110
|
+
const hasMultimodal = parts.some((p) => p.type === "image" || p.type === "file");
|
|
111
|
+
if (hasMultimodal) {
|
|
112
|
+
const content = [];
|
|
113
|
+
for (const part of parts) {
|
|
114
|
+
if (part.type === "text") {
|
|
115
|
+
content.push({ type: "text", text: part.content });
|
|
116
|
+
} else if (part.type === "image") {
|
|
117
|
+
content.push(toModelImagePart(part));
|
|
118
|
+
} else if (part.type === "file") {
|
|
119
|
+
const filePart = part;
|
|
120
|
+
content.push({
|
|
121
|
+
type: "file",
|
|
122
|
+
url: filePart.url,
|
|
123
|
+
mimeType: filePart.mime,
|
|
124
|
+
filename: filePart.filename
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
role: msg.role,
|
|
130
|
+
content
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
71
134
|
return {
|
|
72
135
|
role: msg.role,
|
|
73
136
|
content: msg.content || ""
|
|
@@ -121,6 +184,13 @@ class SessionMessageConverter {
|
|
|
121
184
|
url: p.url,
|
|
122
185
|
filename: p.filename
|
|
123
186
|
});
|
|
187
|
+
} else if (p.type === "image") {
|
|
188
|
+
const imageData = normalizeImagePayload(p.image, p.mimeType);
|
|
189
|
+
parts.push({
|
|
190
|
+
type: "image",
|
|
191
|
+
image: imageData,
|
|
192
|
+
mimeType: p.mimeType
|
|
193
|
+
});
|
|
124
194
|
} else {
|
|
125
195
|
console.debug(`[session-message-converter] Unknown part type: ${p.type}`);
|
|
126
196
|
}
|
|
@@ -461,10 +461,12 @@ ${content}`;
|
|
|
461
461
|
if (isTaskNotifyDebugEnabled()) {
|
|
462
462
|
logger2.debug(`Sending message - messageId: ${messageId}`);
|
|
463
463
|
}
|
|
464
|
+
const profile = replyChannel?.profile;
|
|
464
465
|
await this.sendLarkMessage({
|
|
465
466
|
chatId,
|
|
466
467
|
messageId,
|
|
467
|
-
content: message
|
|
468
|
+
content: message,
|
|
469
|
+
profile
|
|
468
470
|
});
|
|
469
471
|
logger2.info(`Notification sent: ${type}`);
|
|
470
472
|
} catch (error) {
|
|
@@ -473,7 +475,7 @@ ${content}`;
|
|
|
473
475
|
}
|
|
474
476
|
sendLarkMessage(options) {
|
|
475
477
|
return new Promise((resolve, reject) => {
|
|
476
|
-
const { chatId, messageId, content } = options;
|
|
478
|
+
const { chatId, messageId, content, profile } = options;
|
|
477
479
|
let args;
|
|
478
480
|
if (messageId) {
|
|
479
481
|
args = [
|
|
@@ -496,6 +498,9 @@ ${content}`;
|
|
|
496
498
|
content
|
|
497
499
|
];
|
|
498
500
|
}
|
|
501
|
+
if (profile) {
|
|
502
|
+
args.unshift("--profile", profile);
|
|
503
|
+
}
|
|
499
504
|
const proc = spawn("lark-cli", args, {
|
|
500
505
|
shell: false,
|
|
501
506
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -8,7 +8,22 @@ import {
|
|
|
8
8
|
} from "./roy-agent-core-fs0mn2jk.js";
|
|
9
9
|
|
|
10
10
|
// src/env/workflow/nodes/tool-node.ts
|
|
11
|
-
|
|
11
|
+
function isPositiveNumber(v) {
|
|
12
|
+
return typeof v === "number" && Number.isFinite(v) && v > 0;
|
|
13
|
+
}
|
|
14
|
+
function getToolTimeoutMs(input, config) {
|
|
15
|
+
if (input && typeof input === "object") {
|
|
16
|
+
const inputTimeout = input.timeout;
|
|
17
|
+
if (isPositiveNumber(inputTimeout)) {
|
|
18
|
+
return inputTimeout;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (config && isPositiveNumber(config.timeout)) {
|
|
22
|
+
return config.timeout;
|
|
23
|
+
}
|
|
24
|
+
return DEFAULT_TOOL_TIMEOUT_MS;
|
|
25
|
+
}
|
|
26
|
+
var DEFAULT_TOOL_TIMEOUT_MS = 60000, ToolNode;
|
|
12
27
|
var init_tool_node = __esm(() => {
|
|
13
28
|
init_decorator();
|
|
14
29
|
ToolNode = class ToolNode {
|
|
@@ -88,11 +103,20 @@ var init_tool_node = __esm(() => {
|
|
|
88
103
|
nodeId: context.nodeId
|
|
89
104
|
}
|
|
90
105
|
};
|
|
106
|
+
const toolTimeoutMs = getToolTimeoutMs(input, this.definition.config);
|
|
91
107
|
const executePromise = tool.execute(input, toolContext);
|
|
108
|
+
let timeoutHandle;
|
|
92
109
|
const timeoutPromise = new Promise((_, reject) => {
|
|
93
|
-
setTimeout(() => reject(new Error(`Tool '${toolName}' execution timeout after
|
|
110
|
+
timeoutHandle = setTimeout(() => reject(new Error(`Tool '${toolName}' execution timeout after ${Math.round(toolTimeoutMs / 1000)} seconds`)), toolTimeoutMs);
|
|
94
111
|
});
|
|
95
|
-
|
|
112
|
+
try {
|
|
113
|
+
output = await Promise.race([executePromise, timeoutPromise]);
|
|
114
|
+
} finally {
|
|
115
|
+
if (timeoutHandle !== undefined) {
|
|
116
|
+
clearTimeout(timeoutHandle);
|
|
117
|
+
timeoutHandle = undefined;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
96
120
|
} catch (toolError) {
|
|
97
121
|
if (toolError instanceof TypeError && toolError.message.includes("context") && toolError.message.includes("not a function")) {
|
|
98
122
|
output = await tool.execute(input);
|