@ycodium-ai/plugin-im 0.2.2972 → 0.2.2974
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/README.md +56 -4
- package/dist/index.js +949 -504
- package/locales/en.json +7 -2
- package/locales/zh-CN.json +7 -2
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -126225,6 +126225,26 @@ var readAttached = (data) => {
|
|
|
126225
126225
|
return chatKey === null || threadId === null || projectId === null || attachedAt === null ? null : { chatKey, threadId, projectId, attachedAt };
|
|
126226
126226
|
};
|
|
126227
126227
|
|
|
126228
|
+
// src/chatAliases.ts
|
|
126229
|
+
var aliasKey = (rowId, alias) => `${rowId}:${alias}`;
|
|
126230
|
+
var chatAliasOf = (state, rowId, alias) => state.aliases?.[aliasKey(rowId, alias)];
|
|
126231
|
+
var nonEmpty2 = (value2) => typeof value2 === "string" && value2 !== "" ? value2 : null;
|
|
126232
|
+
var foldAliased = (state, data) => {
|
|
126233
|
+
const rowId = nonEmpty2(data["rowId"]);
|
|
126234
|
+
const alias = nonEmpty2(data["alias"]);
|
|
126235
|
+
const chatId = nonEmpty2(data["chatId"]);
|
|
126236
|
+
if (rowId === null || alias === null || chatId === null) return state;
|
|
126237
|
+
const key = aliasKey(rowId, alias);
|
|
126238
|
+
if (state.aliases?.[key] !== void 0) return state;
|
|
126239
|
+
return { ...state, aliases: { ...state.aliases, [key]: chatId } };
|
|
126240
|
+
};
|
|
126241
|
+
|
|
126242
|
+
// src/keepNewest.ts
|
|
126243
|
+
var keepNewest = (record2, limit) => {
|
|
126244
|
+
const entries = Object.entries(record2);
|
|
126245
|
+
return entries.length <= limit ? record2 : Object.fromEntries(entries.slice(entries.length - limit));
|
|
126246
|
+
};
|
|
126247
|
+
|
|
126228
126248
|
// src/chatState.ts
|
|
126229
126249
|
var IM_STATE_KEY = "chats";
|
|
126230
126250
|
var IM_STATE_VERSION = 1;
|
|
@@ -126236,7 +126256,8 @@ var emptyState = () => ({
|
|
|
126236
126256
|
approvals: {},
|
|
126237
126257
|
turnCards: {},
|
|
126238
126258
|
questions: {},
|
|
126239
|
-
queue: {}
|
|
126259
|
+
queue: {},
|
|
126260
|
+
aliases: {}
|
|
126240
126261
|
});
|
|
126241
126262
|
var questionsOf = (state) => state.questions ?? {};
|
|
126242
126263
|
var queueOf = (state) => state.queue ?? {};
|
|
@@ -126294,11 +126315,11 @@ var openQueueOfThread = (state, threadId) => Object.values(queueOf(state)).filte
|
|
|
126294
126315
|
(record2) => record2.threadId === threadId && record2.settled === void 0
|
|
126295
126316
|
);
|
|
126296
126317
|
var isRecord = (value2) => typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
126297
|
-
var
|
|
126318
|
+
var nonEmpty3 = (value2) => typeof value2 === "string" && value2 !== "" ? value2 : null;
|
|
126298
126319
|
var readTarget = (value2) => {
|
|
126299
126320
|
if (!isRecord(value2)) return null;
|
|
126300
126321
|
if (value2["kind"] === "thread") return { kind: "thread" };
|
|
126301
|
-
const teamId =
|
|
126322
|
+
const teamId = nonEmpty3(value2["teamId"]);
|
|
126302
126323
|
return value2["kind"] === "team" && teamId !== null ? { kind: "team", teamId } : null;
|
|
126303
126324
|
};
|
|
126304
126325
|
var readButtons = (value2) => {
|
|
@@ -126306,8 +126327,8 @@ var readButtons = (value2) => {
|
|
|
126306
126327
|
const buttons = [];
|
|
126307
126328
|
for (const entry of value2) {
|
|
126308
126329
|
if (!isRecord(entry)) return null;
|
|
126309
|
-
const token =
|
|
126310
|
-
const decision =
|
|
126330
|
+
const token = nonEmpty3(entry["token"]);
|
|
126331
|
+
const decision = nonEmpty3(entry["decision"]);
|
|
126311
126332
|
const label = typeof entry["label"] === "string" ? entry["label"] : null;
|
|
126312
126333
|
if (token === null || decision === null || label === null) return null;
|
|
126313
126334
|
buttons.push({ token, label, decision });
|
|
@@ -126319,8 +126340,8 @@ var readQuestionOptions = (value2) => {
|
|
|
126319
126340
|
const options = [];
|
|
126320
126341
|
for (const entry of value2) {
|
|
126321
126342
|
if (!isRecord(entry)) return null;
|
|
126322
|
-
const token =
|
|
126323
|
-
const optionValue =
|
|
126343
|
+
const token = nonEmpty3(entry["token"]);
|
|
126344
|
+
const optionValue = nonEmpty3(entry["value"]);
|
|
126324
126345
|
if (token === null || optionValue === null || typeof entry["label"] !== "string") return null;
|
|
126325
126346
|
const planAction = entry["planAction"];
|
|
126326
126347
|
options.push({
|
|
@@ -126338,10 +126359,10 @@ var readQuestionItems = (value2) => {
|
|
|
126338
126359
|
const items = [];
|
|
126339
126360
|
for (const entry of value2) {
|
|
126340
126361
|
if (!isRecord(entry)) return null;
|
|
126341
|
-
const id =
|
|
126362
|
+
const id = nonEmpty3(entry["id"]);
|
|
126342
126363
|
const options = readQuestionOptions(entry["options"]);
|
|
126343
126364
|
if (id === null || options === null || typeof entry["question"] !== "string") return null;
|
|
126344
|
-
const submitToken =
|
|
126365
|
+
const submitToken = nonEmpty3(entry["submitToken"]);
|
|
126345
126366
|
items.push({
|
|
126346
126367
|
id,
|
|
126347
126368
|
header: typeof entry["header"] === "string" ? entry["header"] : "",
|
|
@@ -126384,10 +126405,6 @@ var withQueueRecord = (state, intentId, patch) => {
|
|
|
126384
126405
|
if (intentId === null || record2 === void 0) return state;
|
|
126385
126406
|
return { ...state, queue: { ...queueOf(state), [intentId]: patch(record2) } };
|
|
126386
126407
|
};
|
|
126387
|
-
var keepNewest = (record2, limit) => {
|
|
126388
|
-
const entries = Object.entries(record2);
|
|
126389
|
-
return entries.length <= limit ? record2 : Object.fromEntries(entries.slice(entries.length - limit));
|
|
126390
|
-
};
|
|
126391
126408
|
var withChat = (state, chatKey, patch) => ({
|
|
126392
126409
|
...state,
|
|
126393
126410
|
chats: { ...state.chats, [chatKey]: { ...chatOf(state, chatKey), ...patch } }
|
|
@@ -126396,19 +126413,19 @@ var foldImEvent = (state, name, data) => {
|
|
|
126396
126413
|
if (!isRecord(data)) return state;
|
|
126397
126414
|
switch (name) {
|
|
126398
126415
|
case "chat-updated": {
|
|
126399
|
-
const chatKey =
|
|
126416
|
+
const chatKey = nonEmpty3(data["chatKey"]);
|
|
126400
126417
|
if (chatKey === null) return state;
|
|
126401
126418
|
const patch = {};
|
|
126402
126419
|
if (data["projectId"] === null) patch.projectId = null;
|
|
126403
|
-
else if (
|
|
126420
|
+
else if (nonEmpty3(data["projectId"]) !== null) patch.projectId = nonEmpty3(data["projectId"]);
|
|
126404
126421
|
if (data["threadId"] === null) patch.threadId = null;
|
|
126405
|
-
else if (
|
|
126422
|
+
else if (nonEmpty3(data["threadId"]) !== null) patch.threadId = nonEmpty3(data["threadId"]);
|
|
126406
126423
|
const target2 = readTarget(data["target"]);
|
|
126407
126424
|
if (target2 !== null) patch.target = target2;
|
|
126408
126425
|
if (data["model"] === null) patch.model = null;
|
|
126409
126426
|
else if (isRecord(data["model"])) {
|
|
126410
|
-
const instanceId =
|
|
126411
|
-
const model =
|
|
126427
|
+
const instanceId = nonEmpty3(data["model"]["instanceId"]);
|
|
126428
|
+
const model = nonEmpty3(data["model"]["model"]);
|
|
126412
126429
|
if (instanceId !== null && model !== null) patch.model = { instanceId, model };
|
|
126413
126430
|
}
|
|
126414
126431
|
if (typeof data["plan"] === "boolean") patch.plan = data["plan"];
|
|
@@ -126419,10 +126436,10 @@ var foldImEvent = (state, name, data) => {
|
|
|
126419
126436
|
return withChat(state, chatKey, patch);
|
|
126420
126437
|
}
|
|
126421
126438
|
case "thread-opened": {
|
|
126422
|
-
const chatKey =
|
|
126423
|
-
const threadId =
|
|
126424
|
-
const projectId =
|
|
126425
|
-
const openedAt =
|
|
126439
|
+
const chatKey = nonEmpty3(data["chatKey"]);
|
|
126440
|
+
const threadId = nonEmpty3(data["threadId"]);
|
|
126441
|
+
const projectId = nonEmpty3(data["projectId"]);
|
|
126442
|
+
const openedAt = nonEmpty3(data["openedAt"]);
|
|
126426
126443
|
if (chatKey === null || threadId === null || projectId === null || openedAt === null) {
|
|
126427
126444
|
return state;
|
|
126428
126445
|
}
|
|
@@ -126443,9 +126460,9 @@ var foldImEvent = (state, name, data) => {
|
|
|
126443
126460
|
return { ...state, attached: keepNewest(attached, ATTACHED_THREAD_LIMIT) };
|
|
126444
126461
|
}
|
|
126445
126462
|
case "approval-offered": {
|
|
126446
|
-
const chatKey =
|
|
126447
|
-
const threadId =
|
|
126448
|
-
const requestId =
|
|
126463
|
+
const chatKey = nonEmpty3(data["chatKey"]);
|
|
126464
|
+
const threadId = nonEmpty3(data["threadId"]);
|
|
126465
|
+
const requestId = nonEmpty3(data["requestId"]);
|
|
126449
126466
|
const options = readButtons(data["options"]);
|
|
126450
126467
|
if (chatKey === null || threadId === null || requestId === null || options === null) {
|
|
126451
126468
|
return state;
|
|
@@ -126462,7 +126479,7 @@ var foldImEvent = (state, name, data) => {
|
|
|
126462
126479
|
};
|
|
126463
126480
|
}
|
|
126464
126481
|
case "approval-resolved": {
|
|
126465
|
-
const requestId =
|
|
126482
|
+
const requestId = nonEmpty3(data["requestId"]);
|
|
126466
126483
|
const existing = requestId === null ? void 0 : state.approvals[requestId];
|
|
126467
126484
|
if (requestId === null || existing === void 0) return state;
|
|
126468
126485
|
return {
|
|
@@ -126471,8 +126488,8 @@ var foldImEvent = (state, name, data) => {
|
|
|
126471
126488
|
};
|
|
126472
126489
|
}
|
|
126473
126490
|
case "approval-carded": {
|
|
126474
|
-
const requestId =
|
|
126475
|
-
const cardId =
|
|
126491
|
+
const requestId = nonEmpty3(data["requestId"]);
|
|
126492
|
+
const cardId = nonEmpty3(data["cardId"]);
|
|
126476
126493
|
const existing = requestId === null ? void 0 : state.approvals[requestId];
|
|
126477
126494
|
if (requestId === null || cardId === null || existing === void 0) return state;
|
|
126478
126495
|
return {
|
|
@@ -126481,9 +126498,9 @@ var foldImEvent = (state, name, data) => {
|
|
|
126481
126498
|
};
|
|
126482
126499
|
}
|
|
126483
126500
|
case "question-offered": {
|
|
126484
|
-
const chatKey =
|
|
126485
|
-
const threadId =
|
|
126486
|
-
const requestId =
|
|
126501
|
+
const chatKey = nonEmpty3(data["chatKey"]);
|
|
126502
|
+
const threadId = nonEmpty3(data["threadId"]);
|
|
126503
|
+
const requestId = nonEmpty3(data["requestId"]);
|
|
126487
126504
|
const items = readQuestionItems(data["items"]);
|
|
126488
126505
|
if (chatKey === null || threadId === null || requestId === null || items === null) {
|
|
126489
126506
|
return state;
|
|
@@ -126500,12 +126517,12 @@ var foldImEvent = (state, name, data) => {
|
|
|
126500
126517
|
};
|
|
126501
126518
|
}
|
|
126502
126519
|
case "question-carded": {
|
|
126503
|
-
const cardId =
|
|
126520
|
+
const cardId = nonEmpty3(data["cardId"]);
|
|
126504
126521
|
if (cardId === null) return state;
|
|
126505
126522
|
return withQuestionItem(
|
|
126506
126523
|
state,
|
|
126507
|
-
|
|
126508
|
-
|
|
126524
|
+
nonEmpty3(data["requestId"]),
|
|
126525
|
+
nonEmpty3(data["questionId"]),
|
|
126509
126526
|
(item) => ({ ...item, cardId })
|
|
126510
126527
|
);
|
|
126511
126528
|
}
|
|
@@ -126514,8 +126531,8 @@ var foldImEvent = (state, name, data) => {
|
|
|
126514
126531
|
if (!Array.isArray(selected)) return state;
|
|
126515
126532
|
return withQuestionItem(
|
|
126516
126533
|
state,
|
|
126517
|
-
|
|
126518
|
-
|
|
126534
|
+
nonEmpty3(data["requestId"]),
|
|
126535
|
+
nonEmpty3(data["questionId"]),
|
|
126519
126536
|
(item) => ({ ...item, selected })
|
|
126520
126537
|
);
|
|
126521
126538
|
}
|
|
@@ -126525,13 +126542,13 @@ var foldImEvent = (state, name, data) => {
|
|
|
126525
126542
|
const label = typeof data["label"] === "string" ? data["label"] : "";
|
|
126526
126543
|
return withQuestionItem(
|
|
126527
126544
|
state,
|
|
126528
|
-
|
|
126529
|
-
|
|
126545
|
+
nonEmpty3(data["requestId"]),
|
|
126546
|
+
nonEmpty3(data["questionId"]),
|
|
126530
126547
|
(item) => ({ ...item, answer, answerLabel: label })
|
|
126531
126548
|
);
|
|
126532
126549
|
}
|
|
126533
126550
|
case "question-resolved": {
|
|
126534
|
-
const requestId =
|
|
126551
|
+
const requestId = nonEmpty3(data["requestId"]);
|
|
126535
126552
|
const existing = requestId === null ? void 0 : questionsOf(state)[requestId];
|
|
126536
126553
|
if (requestId === null || existing === void 0) return state;
|
|
126537
126554
|
const ending = data["ending"];
|
|
@@ -126548,12 +126565,12 @@ var foldImEvent = (state, name, data) => {
|
|
|
126548
126565
|
};
|
|
126549
126566
|
}
|
|
126550
126567
|
case "queue-offered": {
|
|
126551
|
-
const chatKey =
|
|
126552
|
-
const threadId =
|
|
126553
|
-
const intentId =
|
|
126554
|
-
const steerToken =
|
|
126555
|
-
const withdrawToken =
|
|
126556
|
-
const resumeToken =
|
|
126568
|
+
const chatKey = nonEmpty3(data["chatKey"]);
|
|
126569
|
+
const threadId = nonEmpty3(data["threadId"]);
|
|
126570
|
+
const intentId = nonEmpty3(data["intentId"]);
|
|
126571
|
+
const steerToken = nonEmpty3(data["steerToken"]);
|
|
126572
|
+
const withdrawToken = nonEmpty3(data["withdrawToken"]);
|
|
126573
|
+
const resumeToken = nonEmpty3(data["resumeToken"]);
|
|
126557
126574
|
if (chatKey === null || threadId === null || intentId === null || steerToken === null || withdrawToken === null || resumeToken === null) {
|
|
126558
126575
|
return state;
|
|
126559
126576
|
}
|
|
@@ -126578,30 +126595,30 @@ var foldImEvent = (state, name, data) => {
|
|
|
126578
126595
|
};
|
|
126579
126596
|
}
|
|
126580
126597
|
case "queue-carded": {
|
|
126581
|
-
const cardId =
|
|
126598
|
+
const cardId = nonEmpty3(data["cardId"]);
|
|
126582
126599
|
if (cardId === null) return state;
|
|
126583
|
-
return withQueueRecord(state,
|
|
126600
|
+
return withQueueRecord(state, nonEmpty3(data["intentId"]), (record2) => ({
|
|
126584
126601
|
...record2,
|
|
126585
126602
|
cardId
|
|
126586
126603
|
}));
|
|
126587
126604
|
}
|
|
126588
126605
|
case "queue-steering":
|
|
126589
|
-
return withQueueRecord(state,
|
|
126606
|
+
return withQueueRecord(state, nonEmpty3(data["intentId"]), (record2) => ({
|
|
126590
126607
|
...record2,
|
|
126591
126608
|
steering: data["steering"] === true
|
|
126592
126609
|
}));
|
|
126593
126610
|
case "queue-settled": {
|
|
126594
126611
|
const outcome = data["outcome"];
|
|
126595
126612
|
if (outcome !== "steered" && outcome !== "sent" && outcome !== "removed") return state;
|
|
126596
|
-
return withQueueRecord(state,
|
|
126613
|
+
return withQueueRecord(state, nonEmpty3(data["intentId"]), (record2) => ({
|
|
126597
126614
|
...record2,
|
|
126598
126615
|
settled: outcome
|
|
126599
126616
|
}));
|
|
126600
126617
|
}
|
|
126601
126618
|
case "turn-card-opened": {
|
|
126602
|
-
const cardId =
|
|
126603
|
-
const chatKey =
|
|
126604
|
-
const threadId =
|
|
126619
|
+
const cardId = nonEmpty3(data["cardId"]);
|
|
126620
|
+
const chatKey = nonEmpty3(data["chatKey"]);
|
|
126621
|
+
const threadId = nonEmpty3(data["threadId"]);
|
|
126605
126622
|
if (cardId === null || chatKey === null || threadId === null) return state;
|
|
126606
126623
|
const title = typeof data["title"] === "string" ? data["title"] : "";
|
|
126607
126624
|
return {
|
|
@@ -126613,11 +126630,13 @@ var foldImEvent = (state, name, data) => {
|
|
|
126613
126630
|
};
|
|
126614
126631
|
}
|
|
126615
126632
|
case "turn-card-closed": {
|
|
126616
|
-
const cardId =
|
|
126633
|
+
const cardId = nonEmpty3(data["cardId"]);
|
|
126617
126634
|
if (cardId === null) return state;
|
|
126618
126635
|
const { [cardId]: _closed, ...rest } = openTurnCardsOf(state);
|
|
126619
126636
|
return { ...state, turnCards: rest };
|
|
126620
126637
|
}
|
|
126638
|
+
case "chat-aliased":
|
|
126639
|
+
return foldAliased(state, data);
|
|
126621
126640
|
default:
|
|
126622
126641
|
return state;
|
|
126623
126642
|
}
|
|
@@ -126990,6 +127009,7 @@ var readBots = (config2, adapterFor) => {
|
|
|
126990
127009
|
};
|
|
126991
127010
|
var bindingOf = (bot, chatId, state) => ({
|
|
126992
127011
|
...bot,
|
|
127012
|
+
reply: void 0,
|
|
126993
127013
|
chatId,
|
|
126994
127014
|
projectId: chatOf(state, chatKeyOf({ rowId: bot.rowId, chatId })).projectId ?? ""
|
|
126995
127015
|
});
|
|
@@ -127044,7 +127064,7 @@ var numberedApprovalText = (request) => [
|
|
|
127044
127064
|
].join("\n");
|
|
127045
127065
|
|
|
127046
127066
|
// src/approvals.ts
|
|
127047
|
-
var makeApprovals = (core) => {
|
|
127067
|
+
var makeApprovals = (core, anchors) => {
|
|
127048
127068
|
const { host, t, adapterFor, commit, outbound, bindingForChatKey, bindingOfThread, ready } = core;
|
|
127049
127069
|
const settleApprovalCard = async (approval, settlement) => {
|
|
127050
127070
|
if (approval.cardId === void 0) return;
|
|
@@ -127080,7 +127100,7 @@ var makeApprovals = (core) => {
|
|
|
127080
127100
|
};
|
|
127081
127101
|
const sendApprovalCard = async (binding, adapter, threadId, offer) => {
|
|
127082
127102
|
try {
|
|
127083
|
-
const cardId = await adapter.askApproval(binding, {
|
|
127103
|
+
const cardId = await adapter.askApproval(await anchors.anchored(binding, threadId, null), {
|
|
127084
127104
|
title: offer.title,
|
|
127085
127105
|
body: offer.body,
|
|
127086
127106
|
options: offer.buttons,
|
|
@@ -127224,7 +127244,7 @@ var makeChatSetup = (core, deps) => {
|
|
|
127224
127244
|
listedProjectsByChat.set(chatKey, listedProjectIds(rows));
|
|
127225
127245
|
if (rows.length > 0 && hasPanel(binding)) {
|
|
127226
127246
|
try {
|
|
127227
|
-
await deps.openPicker(chatKey, rows);
|
|
127247
|
+
await deps.openPicker(chatKey, rows, binding.reply);
|
|
127228
127248
|
return;
|
|
127229
127249
|
} catch (error) {
|
|
127230
127250
|
host.log.warn("chat could not open the project picker card", {
|
|
@@ -127574,7 +127594,7 @@ var makeCommands = (core, deps) => {
|
|
|
127574
127594
|
case "panel":
|
|
127575
127595
|
if (hasPanel(binding)) {
|
|
127576
127596
|
try {
|
|
127577
|
-
await openPanel(chatKey);
|
|
127597
|
+
await openPanel(chatKey, binding.reply);
|
|
127578
127598
|
return true;
|
|
127579
127599
|
} catch (error) {
|
|
127580
127600
|
host.log.warn("chat could not open the command panel", {
|
|
@@ -127694,51 +127714,339 @@ var makeCommands = (core, deps) => {
|
|
|
127694
127714
|
return { handleCommand, targetOf };
|
|
127695
127715
|
};
|
|
127696
127716
|
|
|
127717
|
+
// src/keyedQueue.ts
|
|
127718
|
+
var makeKeyedQueue = (onError) => {
|
|
127719
|
+
const tails = /* @__PURE__ */ new Map();
|
|
127720
|
+
return (key, work) => {
|
|
127721
|
+
const run = (tails.get(key) ?? Promise.resolve()).then(work).catch(onError).then(() => {
|
|
127722
|
+
if (tails.get(key) === run) tails.delete(key);
|
|
127723
|
+
});
|
|
127724
|
+
tails.set(key, run);
|
|
127725
|
+
};
|
|
127726
|
+
};
|
|
127727
|
+
|
|
127697
127728
|
// src/connections.ts
|
|
127729
|
+
var connectionKey = (adapter, bot) => JSON.stringify([
|
|
127730
|
+
adapter.platform,
|
|
127731
|
+
bot.displayName,
|
|
127732
|
+
// 「跟机器默认」与「不加代理」是两种选择,分开记。
|
|
127733
|
+
bot.proxy === void 0 ? [] : [bot.proxy],
|
|
127734
|
+
bot.groupMention,
|
|
127735
|
+
[...adapter.columns.map((column) => column.key), ...adapter.unlistedValues ?? []].map(
|
|
127736
|
+
(key) => bot.values[key] ?? ""
|
|
127737
|
+
)
|
|
127738
|
+
]);
|
|
127698
127739
|
var startConnections = (core, inboundHandlersFor) => {
|
|
127699
127740
|
const { host, adapterFor, ready } = core;
|
|
127700
|
-
const
|
|
127701
|
-
const
|
|
127702
|
-
|
|
127741
|
+
const live = /* @__PURE__ */ new Map();
|
|
127742
|
+
const enqueueForRow = makeKeyedQueue((error) => {
|
|
127743
|
+
host.log.warn("chat could not start an inbound connection", { error: describeError(error) });
|
|
127744
|
+
});
|
|
127703
127745
|
let disposed = false;
|
|
127704
|
-
|
|
127746
|
+
const open = (bot, key) => {
|
|
127705
127747
|
const adapter = adapterFor(bot.platform);
|
|
127706
|
-
|
|
127707
|
-
|
|
127708
|
-
|
|
127709
|
-
|
|
127710
|
-
|
|
127711
|
-
|
|
127712
|
-
|
|
127713
|
-
|
|
127714
|
-
|
|
127715
|
-
|
|
127716
|
-
|
|
127717
|
-
|
|
127718
|
-
|
|
127719
|
-
|
|
127720
|
-
|
|
127721
|
-
|
|
127722
|
-
platform: bot.platform,
|
|
127723
|
-
error: describeError(error)
|
|
127724
|
-
});
|
|
127748
|
+
let closed = false;
|
|
127749
|
+
let closeConnection;
|
|
127750
|
+
enqueueForRow(bot.rowId, async () => {
|
|
127751
|
+
try {
|
|
127752
|
+
await ready;
|
|
127753
|
+
if (closed || adapter === void 0) return;
|
|
127754
|
+
const connection = await adapter.connect(bot, inboundHandlersFor(bot));
|
|
127755
|
+
if (closed) connection.close();
|
|
127756
|
+
else closeConnection = () => connection.close();
|
|
127757
|
+
} catch (error) {
|
|
127758
|
+
host.log.warn("chat could not start an inbound connection", {
|
|
127759
|
+
bot: bot.displayName,
|
|
127760
|
+
platform: bot.platform,
|
|
127761
|
+
error: describeError(error)
|
|
127762
|
+
});
|
|
127763
|
+
}
|
|
127725
127764
|
});
|
|
127726
|
-
|
|
127765
|
+
return {
|
|
127766
|
+
key,
|
|
127767
|
+
close: () => {
|
|
127768
|
+
closed = true;
|
|
127769
|
+
closeConnection?.();
|
|
127770
|
+
}
|
|
127771
|
+
};
|
|
127772
|
+
};
|
|
127773
|
+
const reconcile = () => {
|
|
127774
|
+
const bots = disposed ? [] : core.bots();
|
|
127775
|
+
const wanted = /* @__PURE__ */ new Map();
|
|
127776
|
+
const credentials3 = /* @__PURE__ */ new Set();
|
|
127777
|
+
for (const bot of bots) {
|
|
127778
|
+
const adapter = adapterFor(bot.platform);
|
|
127779
|
+
if (adapter === void 0) continue;
|
|
127780
|
+
const fingerprint = `${bot.platform}:${adapter.columns.map((column) => bot.values[column.key] ?? "").join(" ")}`;
|
|
127781
|
+
if (credentials3.has(fingerprint)) {
|
|
127782
|
+
host.log.warn("chat did not connect a bot that repeats another bot's credentials", {
|
|
127783
|
+
bot: bot.displayName,
|
|
127784
|
+
platform: bot.platform
|
|
127785
|
+
});
|
|
127786
|
+
continue;
|
|
127787
|
+
}
|
|
127788
|
+
credentials3.add(fingerprint);
|
|
127789
|
+
wanted.set(bot.rowId, { bot, key: connectionKey(adapter, bot) });
|
|
127790
|
+
}
|
|
127791
|
+
for (const [rowId, connection] of live) {
|
|
127792
|
+
if (wanted.get(rowId)?.key === connection.key) continue;
|
|
127793
|
+
connection.close();
|
|
127794
|
+
live.delete(rowId);
|
|
127795
|
+
}
|
|
127796
|
+
for (const [rowId, { bot, key }] of wanted) {
|
|
127797
|
+
if (!live.has(rowId)) live.set(rowId, open(bot, key));
|
|
127798
|
+
}
|
|
127799
|
+
return { bots: bots.length, connecting: wanted.size };
|
|
127800
|
+
};
|
|
127727
127801
|
host.onDispose(() => {
|
|
127728
127802
|
disposed = true;
|
|
127729
|
-
|
|
127803
|
+
reconcile();
|
|
127730
127804
|
});
|
|
127731
|
-
return {
|
|
127805
|
+
return { reconcile };
|
|
127732
127806
|
};
|
|
127733
127807
|
|
|
127734
|
-
// src/
|
|
127735
|
-
|
|
127736
|
-
|
|
127737
|
-
|
|
127738
|
-
|
|
127739
|
-
|
|
127808
|
+
// src/deliveryHttp.ts
|
|
127809
|
+
import * as NodeCrypto from "node:crypto";
|
|
127810
|
+
import * as NodeHttp from "node:http";
|
|
127811
|
+
|
|
127812
|
+
// src/boundedBody.ts
|
|
127813
|
+
var readBoundedBody = (req, limit) => new Promise((resolve) => {
|
|
127814
|
+
const chunks = [];
|
|
127815
|
+
let size = 0;
|
|
127816
|
+
let settled = false;
|
|
127817
|
+
const finish = (result) => {
|
|
127818
|
+
if (settled) return;
|
|
127819
|
+
settled = true;
|
|
127820
|
+
resolve(result);
|
|
127821
|
+
};
|
|
127822
|
+
req.on("data", (chunk) => {
|
|
127823
|
+
if (settled) return;
|
|
127824
|
+
size += chunk.length;
|
|
127825
|
+
if (size > limit) {
|
|
127826
|
+
finish({ kind: "too-large" });
|
|
127827
|
+
req.destroy();
|
|
127828
|
+
return;
|
|
127829
|
+
}
|
|
127830
|
+
chunks.push(chunk);
|
|
127831
|
+
});
|
|
127832
|
+
req.on("end", () => finish({ kind: "ok", bytes: Buffer.concat(chunks) }));
|
|
127833
|
+
req.on("error", () => finish({ kind: "read-failed" }));
|
|
127834
|
+
req.on("close", () => finish({ kind: "read-failed" }));
|
|
127835
|
+
});
|
|
127836
|
+
|
|
127837
|
+
// src/deliveryContract.ts
|
|
127838
|
+
var DELIVERY_SEND_ERROR_CODES = [
|
|
127839
|
+
"bad-request",
|
|
127840
|
+
"unknown-bot",
|
|
127841
|
+
"unknown-target",
|
|
127842
|
+
"bot-not-connected",
|
|
127843
|
+
"delivery-failed"
|
|
127844
|
+
];
|
|
127845
|
+
var isDeliverySendErrorCode = (value2) => typeof value2 === "string" && DELIVERY_SEND_ERROR_CODES.includes(value2);
|
|
127846
|
+
var DeliverySendError = class extends Error {
|
|
127847
|
+
code;
|
|
127848
|
+
constructor(code2, message) {
|
|
127849
|
+
super(message);
|
|
127850
|
+
this.name = "DeliverySendError";
|
|
127851
|
+
this.code = code2;
|
|
127852
|
+
}
|
|
127853
|
+
};
|
|
127854
|
+
|
|
127855
|
+
// src/deliveryHttp.ts
|
|
127856
|
+
var LOOPBACK = "127.0.0.1";
|
|
127857
|
+
var MAX_BODY_BYTES = 1 * 1024 * 1024;
|
|
127858
|
+
var PATH = "/v1/delivery/messages";
|
|
127859
|
+
var statusFor = (code2) => {
|
|
127860
|
+
switch (code2) {
|
|
127861
|
+
case "bad-request":
|
|
127862
|
+
return 400;
|
|
127863
|
+
case "unauthorized":
|
|
127864
|
+
return 401;
|
|
127865
|
+
case "unknown-bot":
|
|
127866
|
+
case "unknown-target":
|
|
127867
|
+
return 404;
|
|
127868
|
+
case "bot-not-connected":
|
|
127869
|
+
return 503;
|
|
127870
|
+
case "delivery-failed":
|
|
127871
|
+
return 502;
|
|
127872
|
+
case "method-not-allowed":
|
|
127873
|
+
return 405;
|
|
127874
|
+
case "unsupported-media-type":
|
|
127875
|
+
return 415;
|
|
127876
|
+
case "payload-too-large":
|
|
127877
|
+
return 413;
|
|
127878
|
+
}
|
|
127879
|
+
};
|
|
127880
|
+
var writeJson = (res, status, body) => {
|
|
127881
|
+
const payload = JSON.stringify(body);
|
|
127882
|
+
res.writeHead(status, {
|
|
127883
|
+
"content-type": "application/json; charset=utf-8",
|
|
127884
|
+
"content-length": Buffer.byteLength(payload),
|
|
127885
|
+
"cache-control": "no-store"
|
|
127886
|
+
});
|
|
127887
|
+
res.end(payload);
|
|
127888
|
+
};
|
|
127889
|
+
var writeError = (res, code2, message) => {
|
|
127890
|
+
writeJson(res, statusFor(code2), { error: { code: code2, message } });
|
|
127891
|
+
};
|
|
127892
|
+
var isLoopbackRemote = (remote) => {
|
|
127893
|
+
if (remote === void 0 || remote === "") return false;
|
|
127894
|
+
return remote === "127.0.0.1" || remote === "::1" || remote === "::ffff:127.0.0.1";
|
|
127895
|
+
};
|
|
127896
|
+
var timingSafeEqualString = (a, b) => {
|
|
127897
|
+
const left = Buffer.from(a);
|
|
127898
|
+
const right = Buffer.from(b);
|
|
127899
|
+
if (left.length !== right.length) return false;
|
|
127900
|
+
return NodeCrypto.timingSafeEqual(left, right);
|
|
127901
|
+
};
|
|
127902
|
+
var parseSendBody = (raw) => {
|
|
127903
|
+
let parsed;
|
|
127904
|
+
try {
|
|
127905
|
+
parsed = JSON.parse(raw.toString("utf8"));
|
|
127906
|
+
} catch {
|
|
127907
|
+
return "bad-request";
|
|
127908
|
+
}
|
|
127909
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return "bad-request";
|
|
127910
|
+
const record2 = parsed;
|
|
127911
|
+
const botId = record2["botId"];
|
|
127912
|
+
const targetId = record2["targetId"];
|
|
127913
|
+
const text3 = record2["text"];
|
|
127914
|
+
const format2 = record2["format"];
|
|
127915
|
+
if (typeof botId !== "string" || botId.trim() === "") return "bad-request";
|
|
127916
|
+
if (typeof targetId !== "string" || targetId.trim() === "") return "bad-request";
|
|
127917
|
+
if (typeof text3 !== "string" || text3.trim() === "") return "bad-request";
|
|
127918
|
+
if (format2 !== void 0 && format2 !== "plain" && format2 !== "markdown") return "bad-request";
|
|
127919
|
+
for (const key of Object.keys(record2)) {
|
|
127920
|
+
if (key !== "botId" && key !== "targetId" && key !== "text" && key !== "format") {
|
|
127921
|
+
return "bad-request";
|
|
127922
|
+
}
|
|
127923
|
+
}
|
|
127924
|
+
return {
|
|
127925
|
+
botId: botId.trim(),
|
|
127926
|
+
targetId: targetId.trim(),
|
|
127927
|
+
text: text3,
|
|
127928
|
+
format: format2 === "markdown" ? "markdown" : format2 === "plain" ? "plain" : void 0
|
|
127929
|
+
};
|
|
127930
|
+
};
|
|
127931
|
+
var startDeliveryHttpServer = async (options) => {
|
|
127932
|
+
const server = NodeHttp.createServer((req, res) => {
|
|
127933
|
+
void (async () => {
|
|
127934
|
+
if (!isLoopbackRemote(req.socket.remoteAddress)) {
|
|
127935
|
+
writeError(res, "unauthorized", "Only loopback clients are accepted.");
|
|
127936
|
+
return;
|
|
127937
|
+
}
|
|
127938
|
+
const url = new URL(req.url ?? "/", `http://${LOOPBACK}`);
|
|
127939
|
+
if (url.pathname !== PATH) {
|
|
127940
|
+
writeError(res, "bad-request", `Unknown path '${url.pathname}'.`);
|
|
127941
|
+
return;
|
|
127942
|
+
}
|
|
127943
|
+
if (req.method !== "POST") {
|
|
127944
|
+
res.setHeader("allow", "POST");
|
|
127945
|
+
writeError(res, "method-not-allowed", "Only POST is accepted.");
|
|
127946
|
+
return;
|
|
127947
|
+
}
|
|
127948
|
+
const contentType = (req.headers["content-type"] ?? "").split(";")[0]?.trim().toLowerCase();
|
|
127949
|
+
if (contentType !== "application/json") {
|
|
127950
|
+
writeError(res, "unsupported-media-type", "Content-Type must be application/json.");
|
|
127951
|
+
return;
|
|
127952
|
+
}
|
|
127953
|
+
if (options.token !== "") {
|
|
127954
|
+
const header = req.headers.authorization ?? "";
|
|
127955
|
+
const prefix = "Bearer ";
|
|
127956
|
+
if (!header.startsWith(prefix) || !timingSafeEqualString(header.slice(prefix.length), options.token)) {
|
|
127957
|
+
writeError(res, "unauthorized", "Bearer token required.");
|
|
127958
|
+
return;
|
|
127959
|
+
}
|
|
127960
|
+
}
|
|
127961
|
+
const read = await readBoundedBody(req, MAX_BODY_BYTES);
|
|
127962
|
+
if (read.kind !== "ok") {
|
|
127963
|
+
if (read.kind === "too-large") {
|
|
127964
|
+
writeError(res, "payload-too-large", "JSON body exceeds 1 MiB.");
|
|
127965
|
+
} else {
|
|
127966
|
+
writeError(res, "bad-request", "Failed to read body.");
|
|
127967
|
+
}
|
|
127968
|
+
return;
|
|
127969
|
+
}
|
|
127970
|
+
const parsed = parseSendBody(read.bytes);
|
|
127971
|
+
if (typeof parsed === "string") {
|
|
127972
|
+
writeError(res, parsed, "Invalid JSON body.");
|
|
127973
|
+
return;
|
|
127974
|
+
}
|
|
127975
|
+
try {
|
|
127976
|
+
const result = await options.send(parsed);
|
|
127977
|
+
writeJson(res, 200, { sent: result.sent });
|
|
127978
|
+
} catch (error) {
|
|
127979
|
+
const rawCode = error instanceof Error ? error.code : void 0;
|
|
127980
|
+
const code2 = isDeliverySendErrorCode(rawCode) ? rawCode : "delivery-failed";
|
|
127981
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
127982
|
+
options.log?.warn("delivery http send failed", { code: code2, message });
|
|
127983
|
+
writeError(res, code2, message);
|
|
127984
|
+
}
|
|
127985
|
+
})().catch((error) => {
|
|
127986
|
+
options.log?.warn("delivery http handler crashed", {
|
|
127987
|
+
error: error instanceof Error ? error.message : String(error)
|
|
127988
|
+
});
|
|
127989
|
+
if (!res.headersSent) writeError(res, "delivery-failed", "Internal error.");
|
|
127740
127990
|
});
|
|
127741
|
-
|
|
127991
|
+
});
|
|
127992
|
+
await new Promise((resolve, reject) => {
|
|
127993
|
+
server.once("error", reject);
|
|
127994
|
+
server.listen(options.port, LOOPBACK, () => resolve());
|
|
127995
|
+
});
|
|
127996
|
+
const address = server.address();
|
|
127997
|
+
const port = address.port;
|
|
127998
|
+
options.log?.info("delivery http listening", { host: LOOPBACK, port, path: PATH });
|
|
127999
|
+
return {
|
|
128000
|
+
port,
|
|
128001
|
+
origin: `http://${LOOPBACK}:${String(port)}`,
|
|
128002
|
+
close: () => new Promise((resolve, reject) => {
|
|
128003
|
+
server.close((error) => error ? reject(error) : resolve());
|
|
128004
|
+
})
|
|
128005
|
+
};
|
|
128006
|
+
};
|
|
128007
|
+
|
|
128008
|
+
// src/deliveryHttpLifecycle.ts
|
|
128009
|
+
var makeDeliveryHttp = (input) => {
|
|
128010
|
+
const start = input.start ?? startDeliveryHttpServer;
|
|
128011
|
+
let running;
|
|
128012
|
+
let disposed = false;
|
|
128013
|
+
const stop = async () => {
|
|
128014
|
+
const current = running;
|
|
128015
|
+
running = void 0;
|
|
128016
|
+
if (current === void 0) return;
|
|
128017
|
+
await current.server.close().catch((error) => {
|
|
128018
|
+
input.log.warn("delivery http could not close", { error: describeError(error) });
|
|
128019
|
+
});
|
|
128020
|
+
};
|
|
128021
|
+
input.onDispose(() => {
|
|
128022
|
+
disposed = true;
|
|
128023
|
+
void stop();
|
|
128024
|
+
});
|
|
128025
|
+
return {
|
|
128026
|
+
apply: async (config2) => {
|
|
128027
|
+
const port = readDeliveryHttpPort(config2);
|
|
128028
|
+
const token = readDeliveryHttpToken(config2);
|
|
128029
|
+
const wanted = readDeliveryHttpEnabled(config2) ? `${String(port)}
|
|
128030
|
+
${token}` : void 0;
|
|
128031
|
+
if (wanted === running?.listening) return;
|
|
128032
|
+
await stop();
|
|
128033
|
+
if (wanted === void 0 || disposed) return;
|
|
128034
|
+
try {
|
|
128035
|
+
const server = await start({
|
|
128036
|
+
port,
|
|
128037
|
+
token,
|
|
128038
|
+
send: input.send,
|
|
128039
|
+
log: {
|
|
128040
|
+
info: (message, fields) => input.log.info(message, fields),
|
|
128041
|
+
warn: (message, fields) => input.log.warn(message, fields)
|
|
128042
|
+
}
|
|
128043
|
+
});
|
|
128044
|
+
running = { listening: wanted, server };
|
|
128045
|
+
if (disposed) await stop();
|
|
128046
|
+
} catch (error) {
|
|
128047
|
+
input.log.warn("delivery http failed to listen", { port, error: describeError(error) });
|
|
128048
|
+
}
|
|
128049
|
+
}
|
|
127742
128050
|
};
|
|
127743
128051
|
};
|
|
127744
128052
|
|
|
@@ -127809,7 +128117,7 @@ var makeImCore = (input) => {
|
|
|
127809
128117
|
host.log.warn("chat could not deliver", { error: describeError(error) });
|
|
127810
128118
|
}
|
|
127811
128119
|
};
|
|
127812
|
-
const bots = () => readBots(input.config, adapterFor);
|
|
128120
|
+
const bots = () => readBots(input.config(), adapterFor);
|
|
127813
128121
|
const bindingForChatKey = (chatKey) => findBindingByChatKey(bots(), state, chatKey);
|
|
127814
128122
|
return {
|
|
127815
128123
|
host,
|
|
@@ -128123,6 +128431,64 @@ var makeCooldown = (windowMs, now, maxKeys = Number.POSITIVE_INFINITY) => {
|
|
|
128123
128431
|
};
|
|
128124
128432
|
};
|
|
128125
128433
|
|
|
128434
|
+
// src/boundedMap.ts
|
|
128435
|
+
var makeBoundedMap = (limit) => {
|
|
128436
|
+
const entries = /* @__PURE__ */ new Map();
|
|
128437
|
+
return {
|
|
128438
|
+
get: (key) => entries.get(key),
|
|
128439
|
+
set: (key, value2) => {
|
|
128440
|
+
entries.delete(key);
|
|
128441
|
+
entries.set(key, value2);
|
|
128442
|
+
if (entries.size > limit) {
|
|
128443
|
+
const oldest = entries.keys().next().value;
|
|
128444
|
+
if (oldest !== void 0) entries.delete(oldest);
|
|
128445
|
+
}
|
|
128446
|
+
}
|
|
128447
|
+
};
|
|
128448
|
+
};
|
|
128449
|
+
|
|
128450
|
+
// src/replyAnchors.ts
|
|
128451
|
+
var THREAD_LIMIT = 256;
|
|
128452
|
+
var TURNS_PER_THREAD = 16;
|
|
128453
|
+
var anchorOfMessage = (adapter, message) => adapter?.quotesReplies === true ? { messageId: message.messageId, inThread: message.replyInThread === true } : void 0;
|
|
128454
|
+
var makeReplyAnchors = (host) => {
|
|
128455
|
+
const byThread = makeBoundedMap(THREAD_LIMIT);
|
|
128456
|
+
const userMessageOfTurn = async (threadId, turnId) => {
|
|
128457
|
+
const execution = await host.projections.getThreadExecution(threadId).catch(() => null);
|
|
128458
|
+
if (execution === null) return void 0;
|
|
128459
|
+
const latest = execution.latestTurn;
|
|
128460
|
+
const wanted = turnId ?? execution.session?.activeTurnId ?? latest?.turnId;
|
|
128461
|
+
if (wanted == null) return void 0;
|
|
128462
|
+
const intent = execution.turnIntents.find((candidate) => candidate.turn?.turnId === wanted);
|
|
128463
|
+
return intent?.messageId ?? (latest?.turnId === wanted ? latest.userMessageId : void 0);
|
|
128464
|
+
};
|
|
128465
|
+
return {
|
|
128466
|
+
/**
|
|
128467
|
+
* 开轮时记一笔:`userMessageId` 是派给宿主的那条用户消息,`binding` 是收到聊天消息的那个
|
|
128468
|
+
* 聊天(带着它的锚点)。没有锚点(平台不引用)就不记。
|
|
128469
|
+
*/
|
|
128470
|
+
note: (threadId, userMessageId, binding) => {
|
|
128471
|
+
if (binding.reply === void 0) return;
|
|
128472
|
+
const turns = byThread.get(threadId) ?? makeBoundedMap(TURNS_PER_THREAD);
|
|
128473
|
+
byThread.set(threadId, turns);
|
|
128474
|
+
turns.set(userMessageId, { chatKey: chatKeyOf(binding), anchor: binding.reply });
|
|
128475
|
+
},
|
|
128476
|
+
/**
|
|
128477
|
+
* 给发往这条会话的聊天挂上 `turnId` 那一轮的锚点(null 的含义见上);取不到就原样返回。
|
|
128478
|
+
*
|
|
128479
|
+
* 锚点只配给它那条消息所在的聊天:会话可以被另一个聊天接走(`/resume`),而回复接口只按被
|
|
128480
|
+
* 回复的消息寻址,挂错了答复就发回原来的聊天。
|
|
128481
|
+
*/
|
|
128482
|
+
anchored: async (binding, threadId, turnId) => {
|
|
128483
|
+
const turns = byThread.get(threadId);
|
|
128484
|
+
if (turns === void 0) return binding;
|
|
128485
|
+
const asked = await userMessageOfTurn(threadId, turnId);
|
|
128486
|
+
const noted = asked === void 0 ? void 0 : turns.get(asked);
|
|
128487
|
+
return noted?.chatKey === chatKeyOf(binding) ? { ...binding, reply: noted.anchor } : binding;
|
|
128488
|
+
}
|
|
128489
|
+
};
|
|
128490
|
+
};
|
|
128491
|
+
|
|
128126
128492
|
// src/inbound.ts
|
|
128127
128493
|
var SEEN_MESSAGE_LIMIT = 256;
|
|
128128
128494
|
var ARCHIVED_REPLY_COOLDOWN_MS = 10 * 6e4;
|
|
@@ -128139,7 +128505,7 @@ var makeInbound = (core, deps) => {
|
|
|
128139
128505
|
const { questionFlow, handleButtonClick } = deps.interactions;
|
|
128140
128506
|
const { answerByToken } = deps.approvals;
|
|
128141
128507
|
const { handlePanelClick } = deps.panelWiring;
|
|
128142
|
-
const { startTurn, receiveAttachmentsOnly } = deps.turns;
|
|
128508
|
+
const { startTurn, receiveAttachmentsOnly, hasWaitingAttachments } = deps.turns;
|
|
128143
128509
|
const { fetchTeams, startTeamRun } = deps.teams;
|
|
128144
128510
|
const { markWorking } = deps.acknowledgements;
|
|
128145
128511
|
const archivedReplyCooldown = makeCooldown(ARCHIVED_REPLY_COOLDOWN_MS, () => Date.now());
|
|
@@ -128166,6 +128532,34 @@ var makeInbound = (core, deps) => {
|
|
|
128166
128532
|
() => deliver(target2, t("reply.notAllowedYet", { id: sender }))
|
|
128167
128533
|
);
|
|
128168
128534
|
};
|
|
128535
|
+
const currentBot = (rowId) => bots().find((candidate) => candidate.rowId === rowId);
|
|
128536
|
+
const inheritFromParent = (bot, chatId, parentChatId) => {
|
|
128537
|
+
if (parentChatId === void 0) return;
|
|
128538
|
+
const chatKey = chatKeyOf({ rowId: bot.rowId, chatId });
|
|
128539
|
+
if (chatOf(core.state, chatKey).projectId) return;
|
|
128540
|
+
const parent = chatOf(core.state, chatKeyOf({ rowId: bot.rowId, chatId: parentChatId }));
|
|
128541
|
+
if (!parent.projectId) return;
|
|
128542
|
+
commit("chat-updated", {
|
|
128543
|
+
chatKey,
|
|
128544
|
+
projectId: parent.projectId,
|
|
128545
|
+
model: parent.model,
|
|
128546
|
+
plan: parent.plan
|
|
128547
|
+
});
|
|
128548
|
+
};
|
|
128549
|
+
const noteChatAlias = (bot, alias, chatId) => {
|
|
128550
|
+
if (chatAliasOf(core.state, bot.rowId, alias) !== void 0) return;
|
|
128551
|
+
commit("chat-aliased", { rowId: bot.rowId, alias, chatId });
|
|
128552
|
+
};
|
|
128553
|
+
const settleChat = (bot, message) => {
|
|
128554
|
+
if (message.chatAlias === void 0) return message;
|
|
128555
|
+
const known = chatAliasOf(core.state, bot.rowId, message.chatAlias);
|
|
128556
|
+
if (known === void 0) noteChatAlias(bot, message.chatAlias, message.chatId);
|
|
128557
|
+
return known === void 0 || known === message.chatId ? message : { ...message, chatId: known };
|
|
128558
|
+
};
|
|
128559
|
+
const openTurn = async (speaker, message) => {
|
|
128560
|
+
const threadId = await startTurn(speaker, message);
|
|
128561
|
+
if (threadId !== null) await markWorking(speaker, threadId, message.messageId);
|
|
128562
|
+
};
|
|
128169
128563
|
const inboundHandlersFor = (bot) => ({
|
|
128170
128564
|
onError: (message) => host.log.warn("chat inbound connection failed", {
|
|
128171
128565
|
platform: bot.platform,
|
|
@@ -128173,10 +128567,16 @@ var makeInbound = (core, deps) => {
|
|
|
128173
128567
|
message
|
|
128174
128568
|
}),
|
|
128175
128569
|
onButton: handleButtonClick,
|
|
128176
|
-
onPanelClick: (click) =>
|
|
128177
|
-
|
|
128178
|
-
|
|
128570
|
+
onPanelClick: (click) => {
|
|
128571
|
+
const current = currentBot(bot.rowId);
|
|
128572
|
+
return current === void 0 ? null : handlePanelClick(current, click);
|
|
128573
|
+
},
|
|
128574
|
+
noteChatAlias: (alias, chatId) => noteChatAlias(bot, alias, chatId),
|
|
128575
|
+
knowsChatAlias: (alias) => chatAliasOf(core.state, bot.rowId, alias) !== void 0,
|
|
128576
|
+
onMessage: (received) => {
|
|
128577
|
+
const current = currentBot(bot.rowId);
|
|
128179
128578
|
if (current === void 0) return;
|
|
128579
|
+
const message = settleChat(current, received);
|
|
128180
128580
|
const arrived = bindingOf2(current, message.chatId);
|
|
128181
128581
|
if (alreadyHandled(arrived, message.messageId)) return;
|
|
128182
128582
|
if (message.chatKind !== void 0 && chatOf(core.state, chatKeyOf(arrived)).chatKind !== message.chatKind) {
|
|
@@ -128206,7 +128606,11 @@ var makeInbound = (core, deps) => {
|
|
|
128206
128606
|
return;
|
|
128207
128607
|
}
|
|
128208
128608
|
enqueueForChat(chatKeyOf(arrived), async () => {
|
|
128209
|
-
|
|
128609
|
+
inheritFromParent(current, message.chatId, message.parentChatId);
|
|
128610
|
+
const target2 = {
|
|
128611
|
+
...bindingOf2(current, message.chatId),
|
|
128612
|
+
reply: anchorOfMessage(adapterFor(current.platform), message)
|
|
128613
|
+
};
|
|
128210
128614
|
const chatKey = chatKeyOf(target2);
|
|
128211
128615
|
const teams = await fetchTeams(target2);
|
|
128212
128616
|
if (await handleCommand(target2, message.text, teams ?? [], message.senderId)) return;
|
|
@@ -128261,8 +128665,15 @@ var makeInbound = (core, deps) => {
|
|
|
128261
128665
|
await receiveAttachmentsOnly(target2, message);
|
|
128262
128666
|
return;
|
|
128263
128667
|
}
|
|
128264
|
-
const
|
|
128265
|
-
if (
|
|
128668
|
+
const branchChatId = hasWaitingAttachments(chatKey) ? void 0 : message.branchChatId;
|
|
128669
|
+
if (branchChatId === void 0) {
|
|
128670
|
+
await openTurn(target2, message);
|
|
128671
|
+
return;
|
|
128672
|
+
}
|
|
128673
|
+
enqueueForChat(chatKeyOf({ rowId: current.rowId, chatId: branchChatId }), async () => {
|
|
128674
|
+
inheritFromParent(current, branchChatId, message.chatId);
|
|
128675
|
+
await openTurn({ ...bindingOf2(current, branchChatId), reply: target2.reply }, message);
|
|
128676
|
+
});
|
|
128266
128677
|
});
|
|
128267
128678
|
}
|
|
128268
128679
|
});
|
|
@@ -128440,7 +128851,7 @@ var makeQuestionFlow = (host) => {
|
|
|
128440
128851
|
if (record2 === void 0 || record2.resolved || item === void 0) return;
|
|
128441
128852
|
try {
|
|
128442
128853
|
const cardId = await cards.open(
|
|
128443
|
-
target2.binding,
|
|
128854
|
+
await host.anchored(target2.binding, record2.threadId),
|
|
128444
128855
|
questionCardOf(item, record2.items.indexOf(item), record2.items.length, t)
|
|
128445
128856
|
);
|
|
128446
128857
|
if (cardId === null) continue;
|
|
@@ -128678,7 +129089,7 @@ var makeQueueFlow = (host, deps) => {
|
|
|
128678
129089
|
queuePaused: execution.queuePaused,
|
|
128679
129090
|
intent: execution.intents.find((intent) => intent.intentId === intentId)
|
|
128680
129091
|
});
|
|
128681
|
-
const noteQueued = async (chatKey, threadId, messageId, text3) => {
|
|
129092
|
+
const noteQueued = async (chatKey, threadId, messageId, text3, reply) => {
|
|
128682
129093
|
const target2 = host.target(chatKey);
|
|
128683
129094
|
if (target2 === void 0) return;
|
|
128684
129095
|
let execution;
|
|
@@ -128723,7 +129134,10 @@ var makeQueueFlow = (host, deps) => {
|
|
|
128723
129134
|
host.commit("queue-settled", { intentId, outcome: view.outcome });
|
|
128724
129135
|
return;
|
|
128725
129136
|
}
|
|
128726
|
-
const cardId = await cards.open(
|
|
129137
|
+
const cardId = await cards.open(
|
|
129138
|
+
{ ...target2.binding, reply },
|
|
129139
|
+
queueCardOf(record2, view, null, t)
|
|
129140
|
+
);
|
|
128727
129141
|
if (cardId === null) return;
|
|
128728
129142
|
host.commit("queue-carded", { intentId, cardId });
|
|
128729
129143
|
shown.set(intentId, queueViewKey(view, null));
|
|
@@ -128883,6 +129297,8 @@ var makeInteractions = (core, deps) => {
|
|
|
128883
129297
|
const adapter = binding === void 0 ? void 0 : adapterFor(binding.platform);
|
|
128884
129298
|
return binding === void 0 || adapter === void 0 ? void 0 : { binding, adapter };
|
|
128885
129299
|
},
|
|
129300
|
+
// 提问是在跑的那一轮问的。
|
|
129301
|
+
anchored: (binding, threadId) => deps.anchors.anchored(binding, threadId, null),
|
|
128886
129302
|
allowed: (chatKey, operatorId) => {
|
|
128887
129303
|
const binding = bindingForChatKey(chatKey);
|
|
128888
129304
|
if (binding !== void 0 && isAllowedSender(binding, operatorId)) return true;
|
|
@@ -128961,6 +129377,9 @@ var makeInteractions = (core, deps) => {
|
|
|
128961
129377
|
const resolved = readRequestResolved(event);
|
|
128962
129378
|
if (resolved === null) return;
|
|
128963
129379
|
await ready;
|
|
129380
|
+
if (resolved.outcome !== "cancelled" && event.threadId !== null) {
|
|
129381
|
+
deps.rotateTurnCard(event.threadId);
|
|
129382
|
+
}
|
|
128964
129383
|
if (resolved.requestKind === "user-input") {
|
|
128965
129384
|
questionFlow.resolved(
|
|
128966
129385
|
resolved.requestId,
|
|
@@ -130779,24 +131198,50 @@ var fetchTenantToken = async (input) => {
|
|
|
130779
131198
|
}
|
|
130780
131199
|
return { token: body.tenant_access_token, expiresInSeconds: body.expire ?? 0 };
|
|
130781
131200
|
};
|
|
130782
|
-
var
|
|
131201
|
+
var postMessage = async (input) => {
|
|
131202
|
+
const headers = {
|
|
131203
|
+
authorization: `Bearer ${input.token}`,
|
|
131204
|
+
"content-type": "application/json; charset=utf-8"
|
|
131205
|
+
};
|
|
131206
|
+
const message = { msg_type: input.msgType, content: JSON.stringify(input.content) };
|
|
131207
|
+
const sentOf = async (response2) => (await readEnvelope(input.operation, response2)).data;
|
|
131208
|
+
if (input.reply !== void 0) {
|
|
131209
|
+
try {
|
|
131210
|
+
const response2 = await input.http(
|
|
131211
|
+
`${LARK_BASE}/im/v1/messages/${encodeURIComponent(input.reply.messageId)}/reply`,
|
|
131212
|
+
{
|
|
131213
|
+
method: "POST",
|
|
131214
|
+
headers,
|
|
131215
|
+
body: JSON.stringify({
|
|
131216
|
+
...message,
|
|
131217
|
+
...input.reply.inThread ? { reply_in_thread: true } : {}
|
|
131218
|
+
})
|
|
131219
|
+
}
|
|
131220
|
+
);
|
|
131221
|
+
const sent = await sentOf(response2);
|
|
131222
|
+
if (input.reply.inThread) input.onThreadReply?.(sent?.thread_id || void 0);
|
|
131223
|
+
return sent?.message_id ?? null;
|
|
131224
|
+
} catch (error) {
|
|
131225
|
+
if (!(error instanceof LarkApiError)) throw error;
|
|
131226
|
+
}
|
|
131227
|
+
}
|
|
130783
131228
|
const idType = input.receiveIdType ?? "chat_id";
|
|
130784
131229
|
const response = await input.http(`${LARK_BASE}/im/v1/messages?receive_id_type=${idType}`, {
|
|
130785
131230
|
method: "POST",
|
|
130786
|
-
headers
|
|
130787
|
-
|
|
130788
|
-
"content-type": "application/json; charset=utf-8"
|
|
130789
|
-
},
|
|
130790
|
-
body: JSON.stringify({
|
|
130791
|
-
receive_id: input.chatId,
|
|
130792
|
-
msg_type: "text",
|
|
130793
|
-
// content 是一个 JSON **字符串**,不是对象——飞书这条接口就是这么定的。
|
|
130794
|
-
content: JSON.stringify({ text: input.text })
|
|
130795
|
-
})
|
|
131231
|
+
headers,
|
|
131232
|
+
body: JSON.stringify({ receive_id: input.chatId, ...message })
|
|
130796
131233
|
});
|
|
130797
|
-
|
|
130798
|
-
|
|
131234
|
+
return (await sentOf(response))?.message_id ?? null;
|
|
131235
|
+
};
|
|
131236
|
+
var fetchMessageThreadId = async (input) => {
|
|
131237
|
+
const response = await input.http(
|
|
131238
|
+
`${LARK_BASE}/im/v1/messages/${encodeURIComponent(input.messageId)}`,
|
|
131239
|
+
{ headers: { authorization: `Bearer ${input.token}` } }
|
|
131240
|
+
);
|
|
131241
|
+
const body = await readEnvelope("message.get", response);
|
|
131242
|
+
return body.data?.items?.[0]?.thread_id || void 0;
|
|
130799
131243
|
};
|
|
131244
|
+
var sendChatText = async (input) => postMessage({ ...input, operation: "send", msgType: "text", content: { text: input.text } });
|
|
130800
131245
|
var LARK_WORKING_REACTION = "OnIt";
|
|
130801
131246
|
var addReaction = async (input) => {
|
|
130802
131247
|
const response = await input.http(
|
|
@@ -130856,54 +131301,19 @@ var uploadFile = async (input) => {
|
|
|
130856
131301
|
}
|
|
130857
131302
|
return body.data.file_key;
|
|
130858
131303
|
};
|
|
130859
|
-
var sendChatFile = async (input) => {
|
|
130860
|
-
|
|
130861
|
-
|
|
130862
|
-
|
|
130863
|
-
|
|
130864
|
-
|
|
130865
|
-
|
|
130866
|
-
|
|
130867
|
-
|
|
130868
|
-
|
|
130869
|
-
|
|
130870
|
-
|
|
130871
|
-
|
|
130872
|
-
const body = await readEnvelope("send.file", response);
|
|
130873
|
-
return body.data?.message_id ?? null;
|
|
130874
|
-
};
|
|
130875
|
-
var sendChatImage = async (input) => {
|
|
130876
|
-
const response = await input.http(`${LARK_BASE}/im/v1/messages?receive_id_type=chat_id`, {
|
|
130877
|
-
method: "POST",
|
|
130878
|
-
headers: {
|
|
130879
|
-
authorization: `Bearer ${input.token}`,
|
|
130880
|
-
"content-type": "application/json; charset=utf-8"
|
|
130881
|
-
},
|
|
130882
|
-
body: JSON.stringify({
|
|
130883
|
-
receive_id: input.chatId,
|
|
130884
|
-
msg_type: "image",
|
|
130885
|
-
content: JSON.stringify({ image_key: input.imageKey })
|
|
130886
|
-
})
|
|
130887
|
-
});
|
|
130888
|
-
const body = await readEnvelope("send.image", response);
|
|
130889
|
-
return body.data?.message_id ?? null;
|
|
130890
|
-
};
|
|
130891
|
-
var sendCard = async (input) => {
|
|
130892
|
-
const response = await input.http(`${LARK_BASE}/im/v1/messages?receive_id_type=chat_id`, {
|
|
130893
|
-
method: "POST",
|
|
130894
|
-
headers: {
|
|
130895
|
-
authorization: `Bearer ${input.token}`,
|
|
130896
|
-
"content-type": "application/json; charset=utf-8"
|
|
130897
|
-
},
|
|
130898
|
-
body: JSON.stringify({
|
|
130899
|
-
receive_id: input.chatId,
|
|
130900
|
-
msg_type: "interactive",
|
|
130901
|
-
content: JSON.stringify(input.card)
|
|
130902
|
-
})
|
|
130903
|
-
});
|
|
130904
|
-
const body = await readEnvelope("send.card", response);
|
|
130905
|
-
return body.data?.message_id ?? null;
|
|
130906
|
-
};
|
|
131304
|
+
var sendChatFile = async (input) => postMessage({
|
|
131305
|
+
...input,
|
|
131306
|
+
operation: "send.file",
|
|
131307
|
+
msgType: "file",
|
|
131308
|
+
content: { file_key: input.fileKey }
|
|
131309
|
+
});
|
|
131310
|
+
var sendChatImage = async (input) => postMessage({
|
|
131311
|
+
...input,
|
|
131312
|
+
operation: "send.image",
|
|
131313
|
+
msgType: "image",
|
|
131314
|
+
content: { image_key: input.imageKey }
|
|
131315
|
+
});
|
|
131316
|
+
var sendCard = async (input) => postMessage({ ...input, operation: "send.card", msgType: "interactive", content: input.card });
|
|
130907
131317
|
var patchCard = async (input) => {
|
|
130908
131318
|
const response = await input.http(
|
|
130909
131319
|
`${LARK_BASE}/im/v1/messages/${encodeURIComponent(input.messageId)}`,
|
|
@@ -136204,7 +136614,8 @@ var STATUS_TEMPLATE = {
|
|
|
136204
136614
|
working: "wathet",
|
|
136205
136615
|
done: "green",
|
|
136206
136616
|
error: "red",
|
|
136207
|
-
interrupted: "orange"
|
|
136617
|
+
interrupted: "orange",
|
|
136618
|
+
continued: "grey"
|
|
136208
136619
|
};
|
|
136209
136620
|
var encoder = new TextEncoder();
|
|
136210
136621
|
var stripAngleBrackets = (text3) => text3.replaceAll("<", "").replaceAll(">", "");
|
|
@@ -136388,9 +136799,9 @@ var styledText = (text3, style) => {
|
|
|
136388
136799
|
if (style?.includes("underline")) out = `<u>${out}</u>`;
|
|
136389
136800
|
return out;
|
|
136390
136801
|
};
|
|
136391
|
-
var
|
|
136802
|
+
var nonEmpty4 = (value2) => typeof value2 === "string" && value2 !== "";
|
|
136392
136803
|
var resourceOf = (element, index) => {
|
|
136393
|
-
if (element.tag === "img" &&
|
|
136804
|
+
if (element.tag === "img" && nonEmpty4(element.image_key)) {
|
|
136394
136805
|
return {
|
|
136395
136806
|
fileKey: element.image_key,
|
|
136396
136807
|
kind: "image",
|
|
@@ -136398,14 +136809,14 @@ var resourceOf = (element, index) => {
|
|
|
136398
136809
|
mimeType: "image/png"
|
|
136399
136810
|
};
|
|
136400
136811
|
}
|
|
136401
|
-
if ((element.tag === "media" || element.tag === "file") &&
|
|
136812
|
+
if ((element.tag === "media" || element.tag === "file") && nonEmpty4(element.file_key)) {
|
|
136402
136813
|
const video = element.tag === "media";
|
|
136403
|
-
const name =
|
|
136814
|
+
const name = nonEmpty4(element.file_name) ? element.file_name : video ? `video-${String(index)}.mp4` : `file-${String(index)}`;
|
|
136404
136815
|
return {
|
|
136405
136816
|
fileKey: element.file_key,
|
|
136406
136817
|
kind: "file",
|
|
136407
136818
|
name,
|
|
136408
|
-
mimeType: video && !
|
|
136819
|
+
mimeType: video && !nonEmpty4(element.file_name) ? "video/mp4" : mimeFromName(name)
|
|
136409
136820
|
};
|
|
136410
136821
|
}
|
|
136411
136822
|
return null;
|
|
@@ -136417,11 +136828,11 @@ var serializeElement = (element, index, botIds) => {
|
|
|
136417
136828
|
return styledText(element.text ?? "", element.style);
|
|
136418
136829
|
case "a": {
|
|
136419
136830
|
const label = element.text ?? element.href ?? "";
|
|
136420
|
-
return
|
|
136831
|
+
return nonEmpty4(element.href) ? `[${label}](${element.href})` : label;
|
|
136421
136832
|
}
|
|
136422
136833
|
case "at": {
|
|
136423
136834
|
if (element.user_id !== void 0 && botIds.has(element.user_id)) return "";
|
|
136424
|
-
return
|
|
136835
|
+
return nonEmpty4(element.user_name) ? `@${element.user_name}` : "";
|
|
136425
136836
|
}
|
|
136426
136837
|
case "code_block":
|
|
136427
136838
|
return `\`\`\`${element.language ?? ""}
|
|
@@ -136461,7 +136872,7 @@ var serializePost = (content, botIds = /* @__PURE__ */ new Set()) => {
|
|
|
136461
136872
|
for (const element of elements) {
|
|
136462
136873
|
const index = indexOf.get(element);
|
|
136463
136874
|
const key = element.tag === "img" ? element.image_key : element.file_key;
|
|
136464
|
-
if (index !== void 0 &&
|
|
136875
|
+
if (index !== void 0 && nonEmpty4(key)) {
|
|
136465
136876
|
placeholderByKey.set(key, placeholderOf(element, index));
|
|
136466
136877
|
}
|
|
136467
136878
|
}
|
|
@@ -136552,7 +136963,7 @@ var readText = (content) => {
|
|
|
136552
136963
|
const text3 = readJson(content)?.["text"];
|
|
136553
136964
|
return typeof text3 === "string" ? text3 : null;
|
|
136554
136965
|
};
|
|
136555
|
-
var parseInboundMessage = (event, appId, groupMention = "always") => {
|
|
136966
|
+
var parseInboundMessage = (event, appId, groupMention = "always", topicOnMention = true) => {
|
|
136556
136967
|
if (event.sender?.sender_type === "app") return null;
|
|
136557
136968
|
const message = event.message;
|
|
136558
136969
|
if (message === void 0) return null;
|
|
@@ -136562,6 +136973,11 @@ var parseInboundMessage = (event, appId, groupMention = "always") => {
|
|
|
136562
136973
|
const messageType = message.message_type ?? "";
|
|
136563
136974
|
if (!passesGroupGate(event, appId, groupMention, messageType)) return null;
|
|
136564
136975
|
const senderOpenId = event.sender?.sender_id?.open_id ?? null;
|
|
136976
|
+
const threadId = typeof message.thread_id === "string" && message.thread_id !== "" ? message.thread_id : void 0;
|
|
136977
|
+
const inThread = threadId !== void 0 || topicOnMention && mentionsApp(event, appId);
|
|
136978
|
+
const rootGiven = typeof message.root_id === "string" && message.root_id !== "";
|
|
136979
|
+
const rootId = rootGiven && message.root_id !== void 0 ? message.root_id : messageId;
|
|
136980
|
+
const topic = chatType === "p2p" || !inThread ? {} : threadId === void 0 ? { topic: { rootMessageId: messageId } } : { topic: { rootMessageId: rootId, threadId, rootGiven } };
|
|
136565
136981
|
if (UNSUPPORTED_MESSAGE_TYPES.has(messageType)) {
|
|
136566
136982
|
return {
|
|
136567
136983
|
messageId,
|
|
@@ -136570,6 +136986,8 @@ var parseInboundMessage = (event, appId, groupMention = "always") => {
|
|
|
136570
136986
|
senderOpenId,
|
|
136571
136987
|
text: "",
|
|
136572
136988
|
resources: [],
|
|
136989
|
+
inThread,
|
|
136990
|
+
...topic,
|
|
136573
136991
|
unsupportedType: messageType
|
|
136574
136992
|
};
|
|
136575
136993
|
}
|
|
@@ -136580,7 +136998,7 @@ var parseInboundMessage = (event, appId, groupMention = "always") => {
|
|
|
136580
136998
|
const raw = post !== void 0 ? post.text : messageType === "text" ? readText(message.content) : null;
|
|
136581
136999
|
const text3 = mentions.reduce((value2, mention) => value2.replaceAll(mention.key, ""), raw ?? "").trim();
|
|
136582
137000
|
if (text3.length === 0 && resources.length === 0) return null;
|
|
136583
|
-
return { messageId, chatId, chatType, senderOpenId, text: text3, resources };
|
|
137001
|
+
return { messageId, chatId, chatType, senderOpenId, text: text3, resources, inThread, ...topic };
|
|
136584
137002
|
};
|
|
136585
137003
|
var fetchMessageResource = async (input) => {
|
|
136586
137004
|
const url = `${LARK_BASE}/im/v1/messages/${encodeURIComponent(
|
|
@@ -136656,7 +137074,13 @@ var startLarkInbound = (input) => {
|
|
|
136656
137074
|
const dispatcher = new import_node_sdk.EventDispatcher({}).register({
|
|
136657
137075
|
"im.message.receive_v1": (event) => {
|
|
136658
137076
|
const mode = input.groupMention ?? "always";
|
|
136659
|
-
const
|
|
137077
|
+
const parse = (groupMention) => parseInboundMessage(
|
|
137078
|
+
event,
|
|
137079
|
+
input.appId,
|
|
137080
|
+
groupMention,
|
|
137081
|
+
input.topicOnMention
|
|
137082
|
+
);
|
|
137083
|
+
const parsed = parse(mode);
|
|
136660
137084
|
if (parsed !== null) {
|
|
136661
137085
|
input.onMessage(parsed);
|
|
136662
137086
|
return {};
|
|
@@ -136666,7 +137090,7 @@ var startLarkInbound = (input) => {
|
|
|
136666
137090
|
const chatId = chat?.chat_id;
|
|
136667
137091
|
if (typeof chatId === "string") {
|
|
136668
137092
|
void input.isSoloGroup(chatId).then((solo) => {
|
|
136669
|
-
const relaxed = solo ?
|
|
137093
|
+
const relaxed = solo ? parse("never") : null;
|
|
136670
137094
|
if (relaxed !== null) input.onMessage(relaxed);
|
|
136671
137095
|
});
|
|
136672
137096
|
}
|
|
@@ -136733,8 +137157,27 @@ var COLUMNS = [
|
|
|
136733
137157
|
labelKey: "column.larkAppId.label",
|
|
136734
137158
|
placeholderKey: "column.larkAppId.placeholder"
|
|
136735
137159
|
},
|
|
136736
|
-
{ key: "larkAppSecret", kind: "password", labelKey: "column.larkAppSecret.label" }
|
|
137160
|
+
{ key: "larkAppSecret", kind: "password", labelKey: "column.larkAppSecret.label" },
|
|
137161
|
+
// 被 @ 时答复要不要开话题。只有这个适配器读它,没填过就是开(见 `topicOnMentionOf`)。
|
|
137162
|
+
{
|
|
137163
|
+
key: "larkTopicOnMention",
|
|
137164
|
+
kind: "select",
|
|
137165
|
+
labelKey: "column.larkTopicOnMention.label",
|
|
137166
|
+
descriptionKey: "column.larkTopicOnMention.description",
|
|
137167
|
+
options: [
|
|
137168
|
+
{ value: "on", labelKey: "settings.onOff.on" },
|
|
137169
|
+
{ value: "off", labelKey: "settings.onOff.off" }
|
|
137170
|
+
]
|
|
137171
|
+
}
|
|
136737
137172
|
];
|
|
137173
|
+
var topicOnMentionOf = (binding) => binding.values["larkTopicOnMention"] !== "off";
|
|
137174
|
+
var TOPIC_THREAD_CACHE_LIMIT = 2e3;
|
|
137175
|
+
var topicChatIdOf = (chatId, rootMessageId) => `${chatId}:${rootMessageId}`;
|
|
137176
|
+
var splitTopicChatId = (chatId) => {
|
|
137177
|
+
const at = chatId.indexOf(":");
|
|
137178
|
+
return at < 0 ? { chatId } : { chatId: chatId.slice(0, at), rootMessageId: chatId.slice(at + 1) };
|
|
137179
|
+
};
|
|
137180
|
+
var topicAliasOf = (chatId, threadId) => `${chatId}:${threadId}`;
|
|
136738
137181
|
var credentials = (binding) => ({
|
|
136739
137182
|
appId: binding.values["larkAppId"] ?? "",
|
|
136740
137183
|
appSecret: binding.values["larkAppSecret"] ?? ""
|
|
@@ -136749,6 +137192,60 @@ var makeLarkAdapter = (deps) => {
|
|
|
136749
137192
|
await deps.cacheSet(key, { token: minted.token });
|
|
136750
137193
|
return minted.token;
|
|
136751
137194
|
};
|
|
137195
|
+
const aliasPorts = /* @__PURE__ */ new Map();
|
|
137196
|
+
const topicThreadIds = makeBoundedMap(TOPIC_THREAD_CACHE_LIMIT);
|
|
137197
|
+
const learning = /* @__PURE__ */ new Map();
|
|
137198
|
+
const learnTopic = (binding, target2, threadId) => {
|
|
137199
|
+
const key = chatKeyOf(binding);
|
|
137200
|
+
const report = (id) => {
|
|
137201
|
+
topicThreadIds.set(key, id);
|
|
137202
|
+
target2.port?.noteChatAlias?.(topicAliasOf(target2.chatId, id), binding.chatId);
|
|
137203
|
+
};
|
|
137204
|
+
const known = threadId ?? topicThreadIds.get(key);
|
|
137205
|
+
if (known !== void 0) {
|
|
137206
|
+
report(known);
|
|
137207
|
+
return;
|
|
137208
|
+
}
|
|
137209
|
+
const group = chatKeyOf({ rowId: binding.rowId, chatId: target2.chatId });
|
|
137210
|
+
const inflight = learning.get(group) ?? /* @__PURE__ */ new Map();
|
|
137211
|
+
if (inflight.has(key)) return;
|
|
137212
|
+
learning.set(group, inflight);
|
|
137213
|
+
const reading = fetchMessageThreadId({
|
|
137214
|
+
http: deps.http,
|
|
137215
|
+
token: target2.token,
|
|
137216
|
+
messageId: target2.rootMessageId
|
|
137217
|
+
}).then((id) => {
|
|
137218
|
+
if (id !== void 0) report(id);
|
|
137219
|
+
}).catch((error) => {
|
|
137220
|
+
deps.log.warn("lark could not learn the topic of a chat", { error: describeError(error) });
|
|
137221
|
+
}).finally(() => {
|
|
137222
|
+
inflight.delete(key);
|
|
137223
|
+
if (inflight.size === 0) learning.delete(group);
|
|
137224
|
+
});
|
|
137225
|
+
inflight.set(key, reading);
|
|
137226
|
+
};
|
|
137227
|
+
const topicUnsettled = (rowId, groupId, topic) => {
|
|
137228
|
+
if (topic.rootGiven === true) return null;
|
|
137229
|
+
const inflight = learning.get(chatKeyOf({ rowId, chatId: groupId }));
|
|
137230
|
+
if (inflight === void 0) return null;
|
|
137231
|
+
const known = aliasPorts.get(rowId)?.knowsChatAlias?.(topicAliasOf(groupId, topic.threadId));
|
|
137232
|
+
return known === true ? null : Promise.all(inflight.values());
|
|
137233
|
+
};
|
|
137234
|
+
const sendTarget = async (binding) => {
|
|
137235
|
+
const port = aliasPorts.get(binding.rowId);
|
|
137236
|
+
const token = await tenantToken(binding);
|
|
137237
|
+
const { chatId, rootMessageId } = splitTopicChatId(binding.chatId);
|
|
137238
|
+
if (rootMessageId === void 0) {
|
|
137239
|
+
return { http: deps.http, token, chatId, reply: binding.reply };
|
|
137240
|
+
}
|
|
137241
|
+
return {
|
|
137242
|
+
http: deps.http,
|
|
137243
|
+
token,
|
|
137244
|
+
chatId,
|
|
137245
|
+
reply: binding.reply ?? { messageId: rootMessageId, inThread: true },
|
|
137246
|
+
onThreadReply: (threadId) => learnTopic(binding, { token, chatId, rootMessageId, port }, threadId)
|
|
137247
|
+
};
|
|
137248
|
+
};
|
|
136752
137249
|
const soloGroupFor = (bot) => makeSoloGroupCheck(async (chatId) => {
|
|
136753
137250
|
const stats = await fetchChatStats({
|
|
136754
137251
|
http: deps.http,
|
|
@@ -136762,16 +137259,28 @@ var makeLarkAdapter = (deps) => {
|
|
|
136762
137259
|
icon: "lark",
|
|
136763
137260
|
label: "Lark",
|
|
136764
137261
|
columns: COLUMNS,
|
|
137262
|
+
quotesReplies: true,
|
|
137263
|
+
parentChatIdOf: (chatId) => {
|
|
137264
|
+
const { chatId: groupId, rootMessageId } = splitTopicChatId(chatId);
|
|
137265
|
+
return rootMessageId === void 0 ? void 0 : groupId;
|
|
137266
|
+
},
|
|
136765
137267
|
isConfigured: (binding) => {
|
|
136766
137268
|
const { appId, appSecret } = credentials(binding);
|
|
136767
137269
|
return appId !== "" && appSecret !== "";
|
|
136768
137270
|
},
|
|
136769
137271
|
connect: (binding, handlers) => {
|
|
136770
137272
|
const { appId, appSecret } = credentials(binding);
|
|
136771
|
-
|
|
137273
|
+
const port = {
|
|
137274
|
+
noteChatAlias: handlers.noteChatAlias,
|
|
137275
|
+
knowsChatAlias: handlers.knowsChatAlias
|
|
137276
|
+
};
|
|
137277
|
+
aliasPorts.set(binding.rowId, port);
|
|
137278
|
+
let open = true;
|
|
137279
|
+
const inbound = startLarkInbound({
|
|
136772
137280
|
appId,
|
|
136773
137281
|
appSecret,
|
|
136774
137282
|
groupMention: binding.groupMention,
|
|
137283
|
+
topicOnMention: topicOnMentionOf(binding),
|
|
136775
137284
|
isSoloGroup: soloGroupFor(binding),
|
|
136776
137285
|
onError: handlers.onError,
|
|
136777
137286
|
onCardAction: handlers.onButton,
|
|
@@ -136783,12 +137292,23 @@ var makeLarkAdapter = (deps) => {
|
|
|
136783
137292
|
arg: click.arg
|
|
136784
137293
|
}) ?? null,
|
|
136785
137294
|
onMessage: (message) => {
|
|
136786
|
-
|
|
137295
|
+
const { topic } = message;
|
|
137296
|
+
const deliver = () => handlers.onMessage({
|
|
136787
137297
|
messageId: message.messageId,
|
|
136788
|
-
|
|
137298
|
+
// 已经开出来的话题就是它自己那个聊天;将要开出来的(主窗口里 @ 机器人)先算群的,
|
|
137299
|
+
// 由核心决定要不要分出去。
|
|
137300
|
+
...topic === void 0 ? { chatId: message.chatId } : topic.threadId === void 0 ? {
|
|
137301
|
+
chatId: message.chatId,
|
|
137302
|
+
branchChatId: topicChatIdOf(message.chatId, topic.rootMessageId)
|
|
137303
|
+
} : {
|
|
137304
|
+
chatId: topicChatIdOf(message.chatId, topic.rootMessageId),
|
|
137305
|
+
parentChatId: message.chatId,
|
|
137306
|
+
chatAlias: topicAliasOf(message.chatId, topic.threadId)
|
|
137307
|
+
},
|
|
136789
137308
|
senderId: message.senderOpenId,
|
|
136790
137309
|
text: message.text,
|
|
136791
137310
|
chatKind: message.chatType === "p2p" ? "private" : "group",
|
|
137311
|
+
replyInThread: message.inThread,
|
|
136792
137312
|
resources: message.resources.map((resource) => ({
|
|
136793
137313
|
key: resource.fileKey,
|
|
136794
137314
|
name: resource.name,
|
|
@@ -136797,8 +137317,21 @@ var makeLarkAdapter = (deps) => {
|
|
|
136797
137317
|
})),
|
|
136798
137318
|
...message.unsupportedType === void 0 ? {} : { unsupportedType: message.unsupportedType }
|
|
136799
137319
|
});
|
|
137320
|
+
const pending = topic?.threadId === void 0 ? null : topicUnsettled(binding.rowId, message.chatId, {
|
|
137321
|
+
threadId: topic.threadId,
|
|
137322
|
+
rootGiven: topic.rootGiven
|
|
137323
|
+
});
|
|
137324
|
+
if (pending === null) deliver();
|
|
137325
|
+
else void pending.then(() => open ? deliver() : void 0);
|
|
136800
137326
|
}
|
|
136801
137327
|
});
|
|
137328
|
+
return {
|
|
137329
|
+
close: () => {
|
|
137330
|
+
open = false;
|
|
137331
|
+
if (aliasPorts.get(binding.rowId) === port) aliasPorts.delete(binding.rowId);
|
|
137332
|
+
inbound.close();
|
|
137333
|
+
}
|
|
137334
|
+
};
|
|
136802
137335
|
},
|
|
136803
137336
|
createGroup: async (binding, input) => createChat({
|
|
136804
137337
|
http: deps.http,
|
|
@@ -136807,13 +137340,11 @@ var makeLarkAdapter = (deps) => {
|
|
|
136807
137340
|
memberOpenIds: input.memberIds
|
|
136808
137341
|
}),
|
|
136809
137342
|
sendText: async (binding, text3, options) => {
|
|
136810
|
-
const
|
|
137343
|
+
const target2 = await sendTarget(binding);
|
|
136811
137344
|
const receiveIdType = options?.targetKind === "user" ? "open_id" : "chat_id";
|
|
136812
137345
|
for (const chunk of splitForLark(text3)) {
|
|
136813
137346
|
const messageId = await sendChatText({
|
|
136814
|
-
|
|
136815
|
-
token,
|
|
136816
|
-
chatId: binding.chatId,
|
|
137347
|
+
...target2,
|
|
136817
137348
|
receiveIdType,
|
|
136818
137349
|
text: chunk
|
|
136819
137350
|
});
|
|
@@ -136841,35 +137372,39 @@ var makeLarkAdapter = (deps) => {
|
|
|
136841
137372
|
}
|
|
136842
137373
|
},
|
|
136843
137374
|
sendImage: async (binding, image2) => {
|
|
136844
|
-
const
|
|
137375
|
+
const target2 = await sendTarget(binding);
|
|
136845
137376
|
const imageKey = await uploadImage({
|
|
136846
137377
|
http: deps.http,
|
|
136847
|
-
token,
|
|
137378
|
+
token: target2.token,
|
|
136848
137379
|
bytes: image2.bytes,
|
|
136849
137380
|
name: image2.name,
|
|
136850
137381
|
mimeType: image2.mimeType
|
|
136851
137382
|
});
|
|
136852
|
-
await sendChatImage({
|
|
137383
|
+
await sendChatImage({
|
|
137384
|
+
...target2,
|
|
137385
|
+
imageKey
|
|
137386
|
+
});
|
|
136853
137387
|
deps.log.info("lark delivered an image", { name: image2.name });
|
|
136854
137388
|
},
|
|
136855
137389
|
sendFile: async (binding, file) => {
|
|
136856
|
-
const
|
|
137390
|
+
const target2 = await sendTarget(binding);
|
|
136857
137391
|
const fileKey = await uploadFile({
|
|
136858
137392
|
http: deps.http,
|
|
136859
|
-
token,
|
|
137393
|
+
token: target2.token,
|
|
136860
137394
|
bytes: file.bytes,
|
|
136861
137395
|
name: file.name,
|
|
136862
137396
|
mimeType: file.mimeType
|
|
136863
137397
|
});
|
|
136864
|
-
await sendChatFile({
|
|
137398
|
+
await sendChatFile({
|
|
137399
|
+
...target2,
|
|
137400
|
+
fileKey
|
|
137401
|
+
});
|
|
136865
137402
|
deps.log.info("lark delivered a file", { name: file.name });
|
|
136866
137403
|
},
|
|
136867
137404
|
// 图 10 MB、文件 30 MB(飞书开放平台文档:上传图片接口、上传文件接口;空文件会被拒)。
|
|
136868
137405
|
outboundLimits: { imageBytes: 10 * 1024 * 1024, fileBytes: 30 * 1024 * 1024 },
|
|
136869
137406
|
askApproval: async (binding, request) => sendCard({
|
|
136870
|
-
|
|
136871
|
-
token: await tenantToken(binding),
|
|
136872
|
-
chatId: binding.chatId,
|
|
137407
|
+
...await sendTarget(binding),
|
|
136873
137408
|
card: buildApprovalCard({
|
|
136874
137409
|
title: request.title,
|
|
136875
137410
|
body: request.body,
|
|
@@ -136889,10 +137424,9 @@ var makeLarkAdapter = (deps) => {
|
|
|
136889
137424
|
},
|
|
136890
137425
|
turnCards: {
|
|
136891
137426
|
throttleMs: LARK_CARD_THROTTLE_MS,
|
|
137427
|
+
rotatesOnInteraction: true,
|
|
136892
137428
|
open: async (binding, view) => sendCard({
|
|
136893
|
-
|
|
136894
|
-
token: await tenantToken(binding),
|
|
136895
|
-
chatId: binding.chatId,
|
|
137429
|
+
...await sendTarget(binding),
|
|
136896
137430
|
card: buildTurnCard(view, deps.translate)
|
|
136897
137431
|
}),
|
|
136898
137432
|
update: async (binding, cardId, view) => {
|
|
@@ -136906,9 +137440,7 @@ var makeLarkAdapter = (deps) => {
|
|
|
136906
137440
|
},
|
|
136907
137441
|
panel: {
|
|
136908
137442
|
open: async (binding, card) => sendCard({
|
|
136909
|
-
|
|
136910
|
-
token: await tenantToken(binding),
|
|
136911
|
-
chatId: binding.chatId,
|
|
137443
|
+
...await sendTarget(binding),
|
|
136912
137444
|
card: buildPanelCard(card)
|
|
136913
137445
|
}),
|
|
136914
137446
|
update: async (binding, cardId, card) => {
|
|
@@ -136922,9 +137454,7 @@ var makeLarkAdapter = (deps) => {
|
|
|
136922
137454
|
},
|
|
136923
137455
|
choiceCards: {
|
|
136924
137456
|
open: async (binding, card) => sendCard({
|
|
136925
|
-
|
|
136926
|
-
token: await tenantToken(binding),
|
|
136927
|
-
chatId: binding.chatId,
|
|
137457
|
+
...await sendTarget(binding),
|
|
136928
137458
|
card: buildChoiceCard(card)
|
|
136929
137459
|
}),
|
|
136930
137460
|
update: async (binding, cardId, card) => {
|
|
@@ -136976,7 +137506,7 @@ var en_default = {
|
|
|
136976
137506
|
bots: "Bots",
|
|
136977
137507
|
language: {
|
|
136978
137508
|
label: "Reply language",
|
|
136979
|
-
description: "The language of the bot's own sentences in the chat: help, status, confirmations and notices. Chinese shortcut commands only work when this is Chinese.
|
|
137509
|
+
description: "The language of the bot's own sentences in the chat: help, status, confirmations and notices. Chinese shortcut commands only work when this is Chinese. A change applies from the bot's next sentence.",
|
|
136980
137510
|
zhCN: "\u4E2D\u6587",
|
|
136981
137511
|
en: "English"
|
|
136982
137512
|
},
|
|
@@ -137108,6 +137638,10 @@ var en_default = {
|
|
|
137108
137638
|
label: "Command panel",
|
|
137109
137639
|
description: "Which commands /panel (or typing /) lists. Minimal hides low-frequency system items; typing the same command still works."
|
|
137110
137640
|
},
|
|
137641
|
+
larkTopicOnMention: {
|
|
137642
|
+
label: "Open a topic when mentioned",
|
|
137643
|
+
description: "When someone @-mentions the bot, its answer opens a Lark topic under that message, so the question and the answer stay together. Messages already inside a topic are answered in that topic either way."
|
|
137644
|
+
},
|
|
137111
137645
|
wecomNumberedHints: {
|
|
137112
137646
|
label: "Numbered-reply hints",
|
|
137113
137647
|
description: "WeCom has no buttons; approvals and questions use reply numbers. When on, include fuller usage hints."
|
|
@@ -137337,7 +137871,8 @@ var en_default = {
|
|
|
137337
137871
|
working: "Working on it\u2026",
|
|
137338
137872
|
done: "Done",
|
|
137339
137873
|
error: "Something went wrong",
|
|
137340
|
-
interrupted: "Interrupted"
|
|
137874
|
+
interrupted: "Interrupted",
|
|
137875
|
+
continued: "Continues in the card below"
|
|
137341
137876
|
},
|
|
137342
137877
|
step: {
|
|
137343
137878
|
think: "think",
|
|
@@ -137582,7 +138117,7 @@ var zh_CN_default = {
|
|
|
137582
138117
|
bots: "\u673A\u5668\u4EBA",
|
|
137583
138118
|
language: {
|
|
137584
138119
|
label: "\u56DE\u8BDD\u8BED\u8A00",
|
|
137585
|
-
description: "\u673A\u5668\u4EBA\u5728\u804A\u5929\u91CC\u81EA\u5DF1\u8BF4\u7684\u8BDD\u7528\u4EC0\u4E48\u8BED\u8A00\uFF1A\u5E2E\u52A9\u3001\u72B6\u6001\u3001\u786E\u8BA4\u548C\u5404\u79CD\u63D0\u793A\u3002\u4E2D\u6587\u5FEB\u6377\u547D\u4EE4\u53EA\u5728\u9009\u4E2D\u6587\u65F6\u8BA4\u3002\
|
|
138120
|
+
description: "\u673A\u5668\u4EBA\u5728\u804A\u5929\u91CC\u81EA\u5DF1\u8BF4\u7684\u8BDD\u7528\u4EC0\u4E48\u8BED\u8A00\uFF1A\u5E2E\u52A9\u3001\u72B6\u6001\u3001\u786E\u8BA4\u548C\u5404\u79CD\u63D0\u793A\u3002\u4E2D\u6587\u5FEB\u6377\u547D\u4EE4\u53EA\u5728\u9009\u4E2D\u6587\u65F6\u8BA4\u3002\u6539\u4E86\u4E4B\u540E\u4ECE\u673A\u5668\u4EBA\u7684\u4E0B\u4E00\u53E5\u8BDD\u8D77\u751F\u6548\u3002",
|
|
137586
138121
|
zhCN: "\u4E2D\u6587",
|
|
137587
138122
|
en: "English"
|
|
137588
138123
|
},
|
|
@@ -137714,6 +138249,10 @@ var zh_CN_default = {
|
|
|
137714
138249
|
label: "\u6307\u4EE4\u9762\u677F",
|
|
137715
138250
|
description: "\u804A\u5929\u91CC /panel \u6216\u6253 / \u65F6\u5217\u51FA\u7684\u547D\u4EE4\u8303\u56F4\u3002\u7CBE\u7B80\u9690\u85CF\u4F4E\u9891\u7CFB\u7EDF\u9879\uFF1B\u624B\u52A8\u8F93\u5165\u540C\u4E00\u547D\u4EE4\u4ECD\u53EF\u7528\u3002"
|
|
137716
138251
|
},
|
|
138252
|
+
larkTopicOnMention: {
|
|
138253
|
+
label: "\u88AB @ \u65F6\u5F00\u8BDD\u9898",
|
|
138254
|
+
description: "\u6709\u4EBA @ \u673A\u5668\u4EBA\u63D0\u95EE\u65F6\uFF0C\u7B54\u590D\u5728\u90A3\u6761\u6D88\u606F\u4E0B\u5F00\u4E00\u4E2A\u98DE\u4E66\u8BDD\u9898\uFF0C\u4E00\u95EE\u4E00\u7B54\u6536\u5728\u8BDD\u9898\u91CC\u3002\u5DF2\u7ECF\u5728\u8BDD\u9898\u91CC\u7684\u6D88\u606F\uFF0C\u4E0D\u7BA1\u5F00\u4E0D\u5F00\uFF0C\u7B54\u590D\u90FD\u7559\u5728\u8BE5\u8BDD\u9898\u91CC\u3002"
|
|
138255
|
+
},
|
|
137717
138256
|
wecomNumberedHints: {
|
|
137718
138257
|
label: "\u7F16\u53F7\u5E94\u7B54\u63D0\u793A",
|
|
137719
138258
|
description: "\u4F01\u5FAE\u6CA1\u6709\u6309\u94AE\uFF0C\u5BA1\u6279\u4E0E\u63D0\u95EE\u9760\u56DE\u7F16\u53F7\u3002\u5F00\u542F\u65F6\u9644\u5E26\u66F4\u5B8C\u6574\u7684\u7528\u6CD5\u8BF4\u660E\u3002"
|
|
@@ -137943,7 +138482,8 @@ var zh_CN_default = {
|
|
|
137943
138482
|
working: "\u5904\u7406\u4E2D\u2026",
|
|
137944
138483
|
done: "\u5DF2\u5B8C\u6210",
|
|
137945
138484
|
error: "\u51FA\u9519\u4E86",
|
|
137946
|
-
interrupted: "\u5DF2\u4E2D\u65AD"
|
|
138485
|
+
interrupted: "\u5DF2\u4E2D\u65AD",
|
|
138486
|
+
continued: "\u540E\u7EED\u89C1\u4E0B\u65B9\u5361\u7247"
|
|
137947
138487
|
},
|
|
137948
138488
|
step: {
|
|
137949
138489
|
think: "\u601D\u8003",
|
|
@@ -138207,6 +138747,24 @@ var makeTranslate = (language) => {
|
|
|
138207
138747
|
{ optional, language }
|
|
138208
138748
|
);
|
|
138209
138749
|
};
|
|
138750
|
+
var makeLiveTranslate = (initial) => {
|
|
138751
|
+
let current = makeTranslate(initial);
|
|
138752
|
+
const t = Object.defineProperties(
|
|
138753
|
+
(key, params) => current(key, params),
|
|
138754
|
+
{
|
|
138755
|
+
optional: {
|
|
138756
|
+
value: (key, params) => current.optional(key, params)
|
|
138757
|
+
},
|
|
138758
|
+
language: { get: () => current.language }
|
|
138759
|
+
}
|
|
138760
|
+
);
|
|
138761
|
+
return {
|
|
138762
|
+
t,
|
|
138763
|
+
setLanguage: (language) => {
|
|
138764
|
+
if (language !== current.language) current = makeTranslate(language);
|
|
138765
|
+
}
|
|
138766
|
+
};
|
|
138767
|
+
};
|
|
138210
138768
|
|
|
138211
138769
|
// src/modelPlan.ts
|
|
138212
138770
|
var makeModelPlan = (core, deps) => {
|
|
@@ -138284,6 +138842,13 @@ var makeModelPlan = (core, deps) => {
|
|
|
138284
138842
|
return { currentModelOf, handleModel, handlePlan };
|
|
138285
138843
|
};
|
|
138286
138844
|
|
|
138845
|
+
// src/notificationTargets.ts
|
|
138846
|
+
var notificationChatKeys = (state, threadId, projectId) => {
|
|
138847
|
+
const owner = chatOfThread(state, threadId);
|
|
138848
|
+
if (owner !== void 0) return [owner];
|
|
138849
|
+
return projectId === null ? [] : chatsOnProject(state, projectId);
|
|
138850
|
+
};
|
|
138851
|
+
|
|
138287
138852
|
// src/turnOutcome.ts
|
|
138288
138853
|
var outcomeOfSession = (status) => {
|
|
138289
138854
|
if (status === "error") return "failed";
|
|
@@ -138298,7 +138863,7 @@ var makeNotifications = (core, deps) => {
|
|
|
138298
138863
|
const { host, adapterFor, deliver, bindingForChatKey, ready } = core;
|
|
138299
138864
|
const { clearWorking } = deps;
|
|
138300
138865
|
const { turnCards } = deps.replyCards;
|
|
138301
|
-
const { failures } = deps;
|
|
138866
|
+
const { failures, anchors } = deps;
|
|
138302
138867
|
const projectByThread = /* @__PURE__ */ new Map();
|
|
138303
138868
|
const projectOfThread = async (threadId) => {
|
|
138304
138869
|
const known = projectByThread.get(threadId);
|
|
@@ -138312,7 +138877,7 @@ var makeNotifications = (core, deps) => {
|
|
|
138312
138877
|
projectByThread.set(threadId, thread.projectId);
|
|
138313
138878
|
return thread.projectId;
|
|
138314
138879
|
};
|
|
138315
|
-
const targetsForProject = (projectId) =>
|
|
138880
|
+
const targetsForProject = (threadId, projectId) => notificationChatKeys(core.state, threadId, projectId).flatMap((chatKey) => {
|
|
138316
138881
|
const binding = bindingForChatKey(chatKey);
|
|
138317
138882
|
return binding === void 0 ? [] : [binding];
|
|
138318
138883
|
});
|
|
@@ -138338,7 +138903,7 @@ var makeNotifications = (core, deps) => {
|
|
|
138338
138903
|
if (payload.session?.activeTurnId != null) return;
|
|
138339
138904
|
const said = threadsWithSomethingToReport.delete(threadId);
|
|
138340
138905
|
await ready;
|
|
138341
|
-
const targets = targetsForProject(await projectOfThread(threadId));
|
|
138906
|
+
const targets = targetsForProject(threadId, await projectOfThread(threadId));
|
|
138342
138907
|
const reporters = said ? targets : [];
|
|
138343
138908
|
if (reporters.length > 0) {
|
|
138344
138909
|
const thread = await host.projections.getThread(threadId);
|
|
@@ -138348,7 +138913,12 @@ var makeNotifications = (core, deps) => {
|
|
|
138348
138913
|
const text3 = streamsTo(binding, threadId) ? "" : `${thread.title}
|
|
138349
138914
|
|
|
138350
138915
|
${final.text}`;
|
|
138351
|
-
|
|
138916
|
+
const owns = chatOf(core.state, chatKeyOf(binding)).threadId === threadId;
|
|
138917
|
+
await deliver(
|
|
138918
|
+
owns ? await anchors.anchored(binding, threadId, final.turnId) : binding,
|
|
138919
|
+
text3,
|
|
138920
|
+
final.attachments
|
|
138921
|
+
);
|
|
138352
138922
|
}
|
|
138353
138923
|
}
|
|
138354
138924
|
}
|
|
@@ -138361,7 +138931,7 @@ ${final.text}`;
|
|
|
138361
138931
|
if (threadId === null) return;
|
|
138362
138932
|
threadsWithSomethingToReport.delete(threadId);
|
|
138363
138933
|
await ready;
|
|
138364
|
-
const targets = targetsForProject(await projectOfThread(threadId));
|
|
138934
|
+
const targets = targetsForProject(threadId, await projectOfThread(threadId));
|
|
138365
138935
|
const textTargets = targets.filter(
|
|
138366
138936
|
(binding) => !(streamsTo(binding, threadId) && turnCards.covers(threadId))
|
|
138367
138937
|
);
|
|
@@ -138809,8 +139379,8 @@ ${t("panel.projects.hint")}`;
|
|
|
138809
139379
|
};
|
|
138810
139380
|
return {
|
|
138811
139381
|
/** 开一张新面板卡(`/help`)。发不出就抛,调用方退回文字版。 */
|
|
138812
|
-
open: async (chatKey) => {
|
|
138813
|
-
const surface = deps.surface(chatKey);
|
|
139382
|
+
open: async (chatKey, reply) => {
|
|
139383
|
+
const surface = deps.surface(chatKey, reply);
|
|
138814
139384
|
if (surface === null) throw new Error("this chat has no panel");
|
|
138815
139385
|
const entry = { cardId: "", chatKey, stack: [{ kind: "menu" }], busy: false };
|
|
138816
139386
|
const cardId = await surface.open(menuCard(chatKey));
|
|
@@ -138822,8 +139392,8 @@ ${t("panel.projects.hint")}`;
|
|
|
138822
139392
|
* 单独发一张选项目卡(聊天还没选项目时的第一句话、`/repo`)。发不出就抛,调用方退回文字
|
|
138823
139393
|
* 列表。选完不回面板菜单。
|
|
138824
139394
|
*/
|
|
138825
|
-
openProjects: async (chatKey, rows) => {
|
|
138826
|
-
const surface = deps.surface(chatKey);
|
|
139395
|
+
openProjects: async (chatKey, rows, reply) => {
|
|
139396
|
+
const surface = deps.surface(chatKey, reply);
|
|
138827
139397
|
if (surface === null) throw new Error("this chat has no panel");
|
|
138828
139398
|
const entry = {
|
|
138829
139399
|
cardId: "",
|
|
@@ -138837,6 +139407,11 @@ ${t("panel.projects.hint")}`;
|
|
|
138837
139407
|
entry.cardId = cardId;
|
|
138838
139408
|
remember(entry);
|
|
138839
139409
|
},
|
|
139410
|
+
/**
|
|
139411
|
+
* 这张卡开在哪个聊天上。没记过,或已经被淘汰,就是 undefined。
|
|
139412
|
+
* 只读:不改 `cards`,也不改淘汰顺序。
|
|
139413
|
+
*/
|
|
139414
|
+
chatKeyOfCard: (cardId) => cards.get(cardId)?.chatKey,
|
|
138840
139415
|
/**
|
|
138841
139416
|
* 处理一次点击,同步回给点击者的一句提示(null 就是没话说)。取数据、跑命令、改卡都
|
|
138842
139417
|
* 在回调应答之后做。
|
|
@@ -138908,12 +139483,12 @@ var makePanelWiring = (core, deps) => {
|
|
|
138908
139483
|
const { projectRowsFor, listedProjectsByChat } = deps.rows;
|
|
138909
139484
|
const panel = makePanelController({
|
|
138910
139485
|
t,
|
|
138911
|
-
surface: (chatKey) => {
|
|
139486
|
+
surface: (chatKey, reply) => {
|
|
138912
139487
|
const binding = bindingForChatKey(chatKey);
|
|
138913
139488
|
const surface = binding === void 0 ? void 0 : adapterFor(binding.platform)?.panel;
|
|
138914
139489
|
if (binding === void 0 || surface === void 0) return null;
|
|
138915
139490
|
return {
|
|
138916
|
-
open: (card) => surface.open(binding, card),
|
|
139491
|
+
open: (card) => surface.open({ ...binding, reply }, card),
|
|
138917
139492
|
update: (cardId, card) => surface.update(binding, cardId, card)
|
|
138918
139493
|
};
|
|
138919
139494
|
},
|
|
@@ -138965,7 +139540,10 @@ var makePanelWiring = (core, deps) => {
|
|
|
138965
139540
|
}
|
|
138966
139541
|
});
|
|
138967
139542
|
const handlePanelClick = (bot, click) => {
|
|
138968
|
-
const
|
|
139543
|
+
const remembered = panel.chatKeyOfCard(click.cardId);
|
|
139544
|
+
const opener = remembered === void 0 ? void 0 : bindingForChatKey(remembered);
|
|
139545
|
+
const chatId = opener !== void 0 && opener.rowId === bot.rowId && adapterFor(opener.platform)?.parentChatIdOf?.(opener.chatId) === click.chatId ? opener.chatId : click.chatId;
|
|
139546
|
+
const target2 = bindingOf2(bot, chatId);
|
|
138969
139547
|
if (!isAllowedSender(target2, click.operatorId)) {
|
|
138970
139548
|
host.log.warn("chat ignored a panel click from someone not on the allow list", {
|
|
138971
139549
|
bot: target2.displayName,
|
|
@@ -139111,6 +139689,8 @@ var trailingReply = (messages) => {
|
|
|
139111
139689
|
};
|
|
139112
139690
|
|
|
139113
139691
|
// src/turnCards.ts
|
|
139692
|
+
var ROTATE = "rotate";
|
|
139693
|
+
var isDrawing = (live) => live.card !== null || live.reopen;
|
|
139114
139694
|
var RECENT_ENDED_LIMIT = 256;
|
|
139115
139695
|
var makeTurnCards = (deps) => {
|
|
139116
139696
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -139147,12 +139727,37 @@ var makeTurnCards = (deps) => {
|
|
|
139147
139727
|
status: end.status,
|
|
139148
139728
|
errorText: end.errorText
|
|
139149
139729
|
});
|
|
139730
|
+
const openCard = (target2, view) => makeCardStream({
|
|
139731
|
+
open: target2.open,
|
|
139732
|
+
update: target2.update,
|
|
139733
|
+
schedule: deps.schedule,
|
|
139734
|
+
throttleMs: target2.throttleMs,
|
|
139735
|
+
warn: deps.warn
|
|
139736
|
+
}).open(view);
|
|
139737
|
+
const seal = async (slot) => {
|
|
139738
|
+
await deps.ready;
|
|
139739
|
+
const live = slot.live;
|
|
139740
|
+
if (disposed || live === null || live.card === null || !live.target.rotates) return;
|
|
139741
|
+
const card = live.card;
|
|
139742
|
+
await card.finish(
|
|
139743
|
+
buildTurnView({
|
|
139744
|
+
title: live.title,
|
|
139745
|
+
progress: live.lastProgress,
|
|
139746
|
+
texts: await readTexts(live, live.lastProgress),
|
|
139747
|
+
status: "continued"
|
|
139748
|
+
})
|
|
139749
|
+
);
|
|
139750
|
+
deps.onClosed(card.cardId);
|
|
139751
|
+
live.card = null;
|
|
139752
|
+
live.reopen = true;
|
|
139753
|
+
};
|
|
139150
139754
|
const finalize = async (slot, threadId, progress, end) => {
|
|
139151
139755
|
const live = slot.live;
|
|
139152
139756
|
slot.live = null;
|
|
139153
|
-
const
|
|
139757
|
+
const turnId = progress.turnId ?? live?.turnId ?? null;
|
|
139758
|
+
const target2 = live?.target ?? deps.resolveTarget(threadId, turnId);
|
|
139154
139759
|
if (target2 === null) return;
|
|
139155
|
-
rememberEnded(threadId,
|
|
139760
|
+
rememberEnded(threadId, turnId);
|
|
139156
139761
|
if (end.status === "error") erroredThreads.add(threadId);
|
|
139157
139762
|
const title = live?.title ?? await deps.titleOf(threadId);
|
|
139158
139763
|
const view = await finalView(title, progress, live, end);
|
|
@@ -139161,15 +139766,9 @@ var makeTurnCards = (deps) => {
|
|
|
139161
139766
|
deps.onClosed(live.card.cardId);
|
|
139162
139767
|
return;
|
|
139163
139768
|
}
|
|
139164
|
-
const card = await
|
|
139165
|
-
open: target2.open,
|
|
139166
|
-
update: target2.update,
|
|
139167
|
-
schedule: deps.schedule,
|
|
139168
|
-
throttleMs: target2.throttleMs,
|
|
139169
|
-
warn: deps.warn
|
|
139170
|
-
}).open(view);
|
|
139769
|
+
const card = await openCard(target2, view);
|
|
139171
139770
|
if (card === null) {
|
|
139172
|
-
await deps.fallback(threadId, target2.chatKey, view);
|
|
139771
|
+
await deps.fallback(threadId, turnId, target2.chatKey, view);
|
|
139173
139772
|
return;
|
|
139174
139773
|
}
|
|
139175
139774
|
};
|
|
@@ -139188,38 +139787,33 @@ var makeTurnCards = (deps) => {
|
|
|
139188
139787
|
}
|
|
139189
139788
|
}
|
|
139190
139789
|
if (item.phase === "ended") {
|
|
139191
|
-
if (live === null && deps.resolveTarget(threadId) === null) return;
|
|
139790
|
+
if (live === null && deps.resolveTarget(threadId, item.turnId) === null) return;
|
|
139192
139791
|
await finalize(slot, threadId, item, await deps.endOf(threadId, item.turnId));
|
|
139193
139792
|
return;
|
|
139194
139793
|
}
|
|
139195
139794
|
erroredThreads.delete(threadId);
|
|
139196
139795
|
if (live === null) {
|
|
139197
|
-
const target2 = deps.resolveTarget(threadId);
|
|
139796
|
+
const target2 = deps.resolveTarget(threadId, item.turnId);
|
|
139198
139797
|
if (target2 === null) return;
|
|
139199
139798
|
const title = await deps.titleOf(threadId);
|
|
139200
139799
|
const fresh = {
|
|
139201
139800
|
chatKey: target2.chatKey,
|
|
139202
139801
|
title,
|
|
139203
139802
|
card: null,
|
|
139803
|
+
reopen: false,
|
|
139204
139804
|
target: target2,
|
|
139205
139805
|
turnId: item.turnId,
|
|
139206
139806
|
lastSeq: item.seq,
|
|
139207
139807
|
lastProgress: item,
|
|
139208
139808
|
settledTexts: /* @__PURE__ */ new Map()
|
|
139209
139809
|
};
|
|
139210
|
-
const
|
|
139810
|
+
const view2 = buildTurnView({
|
|
139211
139811
|
title,
|
|
139212
139812
|
progress: item,
|
|
139213
139813
|
texts: await readTexts(fresh, item),
|
|
139214
139814
|
status: "working"
|
|
139215
139815
|
});
|
|
139216
|
-
const card = await
|
|
139217
|
-
open: target2.open,
|
|
139218
|
-
update: target2.update,
|
|
139219
|
-
schedule: deps.schedule,
|
|
139220
|
-
throttleMs: target2.throttleMs,
|
|
139221
|
-
warn: deps.warn
|
|
139222
|
-
}).open(view);
|
|
139816
|
+
const card = await openCard(target2, view2);
|
|
139223
139817
|
slot.live = { ...fresh, card };
|
|
139224
139818
|
if (card !== null) {
|
|
139225
139819
|
deps.onOpened({ cardId: card.cardId, chatKey: target2.chatKey, threadId, title });
|
|
@@ -139229,15 +139823,27 @@ var makeTurnCards = (deps) => {
|
|
|
139229
139823
|
live.turnId ??= item.turnId;
|
|
139230
139824
|
live.lastSeq = item.seq;
|
|
139231
139825
|
live.lastProgress = item;
|
|
139232
|
-
if (live.card === null) return;
|
|
139233
|
-
|
|
139234
|
-
|
|
139235
|
-
|
|
139236
|
-
|
|
139237
|
-
|
|
139238
|
-
|
|
139239
|
-
|
|
139240
|
-
|
|
139826
|
+
if (live.card === null && !live.reopen) return;
|
|
139827
|
+
const view = buildTurnView({
|
|
139828
|
+
title: live.title,
|
|
139829
|
+
progress: item,
|
|
139830
|
+
texts: await readTexts(live, item),
|
|
139831
|
+
status: "working"
|
|
139832
|
+
});
|
|
139833
|
+
if (live.card !== null) {
|
|
139834
|
+
live.card.push(view);
|
|
139835
|
+
return;
|
|
139836
|
+
}
|
|
139837
|
+
live.reopen = false;
|
|
139838
|
+
live.card = await openCard(live.target, view);
|
|
139839
|
+
if (live.card !== null) {
|
|
139840
|
+
deps.onOpened({
|
|
139841
|
+
cardId: live.card.cardId,
|
|
139842
|
+
chatKey: live.chatKey,
|
|
139843
|
+
threadId,
|
|
139844
|
+
title: live.title
|
|
139845
|
+
});
|
|
139846
|
+
}
|
|
139241
139847
|
};
|
|
139242
139848
|
const pump = async (threadId, slot) => {
|
|
139243
139849
|
try {
|
|
@@ -139245,7 +139851,8 @@ var makeTurnCards = (deps) => {
|
|
|
139245
139851
|
const item = slot.queue.shift();
|
|
139246
139852
|
if (item === void 0) break;
|
|
139247
139853
|
try {
|
|
139248
|
-
|
|
139854
|
+
if (item === ROTATE) await seal(slot);
|
|
139855
|
+
else await handle(slot, threadId, item);
|
|
139249
139856
|
} catch (error) {
|
|
139250
139857
|
deps.warn("could not draw a turn card", error);
|
|
139251
139858
|
}
|
|
@@ -139265,7 +139872,7 @@ var makeTurnCards = (deps) => {
|
|
|
139265
139872
|
slots.set(threadId, slot);
|
|
139266
139873
|
}
|
|
139267
139874
|
const last = slot.queue.at(-1);
|
|
139268
|
-
if (last !== void 0 && last.phase === "running" && last.turnId === progress.turnId) {
|
|
139875
|
+
if (last !== void 0 && last !== ROTATE && last.phase === "running" && last.turnId === progress.turnId) {
|
|
139269
139876
|
slot.queue[slot.queue.length - 1] = progress;
|
|
139270
139877
|
} else {
|
|
139271
139878
|
slot.queue.push(progress);
|
|
@@ -139275,13 +139882,29 @@ var makeTurnCards = (deps) => {
|
|
|
139275
139882
|
void pump(threadId, slot);
|
|
139276
139883
|
}
|
|
139277
139884
|
},
|
|
139278
|
-
/**
|
|
139885
|
+
/**
|
|
139886
|
+
* 审批或提问答完了:封存这条会话开着的卡,下一拍另开一张。立刻返回;没有在画的卡、或
|
|
139887
|
+
* 平台不换卡,就什么都不做。
|
|
139888
|
+
*/
|
|
139889
|
+
rotate: (threadId) => {
|
|
139890
|
+
const slot = slots.get(threadId);
|
|
139891
|
+
if (disposed || slot === void 0) return;
|
|
139892
|
+
slot.queue.push(ROTATE);
|
|
139893
|
+
if (!slot.running) {
|
|
139894
|
+
slot.running = true;
|
|
139895
|
+
void pump(threadId, slot);
|
|
139896
|
+
}
|
|
139897
|
+
},
|
|
139898
|
+
/** 这条会话正在画卡的那一轮(封存后等着另开的也算);没有在画的卡是 null。 */
|
|
139279
139899
|
drawingTurn: (threadId) => {
|
|
139280
139900
|
const live = slots.get(threadId)?.live;
|
|
139281
|
-
return live
|
|
139901
|
+
return live != null && isDrawing(live) ? live.turnId : null;
|
|
139282
139902
|
},
|
|
139283
139903
|
/** 这条会话现在有一张在画的卡,或者上一轮刚以失败收了卡:失败原因已经在卡上了。 */
|
|
139284
|
-
covers: (threadId) =>
|
|
139904
|
+
covers: (threadId) => {
|
|
139905
|
+
const live = slots.get(threadId)?.live;
|
|
139906
|
+
return live != null && isDrawing(live) || erroredThreads.has(threadId);
|
|
139907
|
+
},
|
|
139285
139908
|
/** 插件停用:放下所有在画的卡,不再发任何更新。卡会停在最后一拍,重启时被标「已中断」。 */
|
|
139286
139909
|
dispose: () => {
|
|
139287
139910
|
disposed = true;
|
|
@@ -139292,19 +139915,21 @@ var makeTurnCards = (deps) => {
|
|
|
139292
139915
|
};
|
|
139293
139916
|
|
|
139294
139917
|
// src/replyCards.ts
|
|
139295
|
-
var makeReplyCards = (core, failures) => {
|
|
139918
|
+
var makeReplyCards = (core, failures, anchors) => {
|
|
139296
139919
|
const { host, adapterFor, commit, deliver, bindingForChatKey, bindingOfThread, ready } = core;
|
|
139297
139920
|
const stopRequested = /* @__PURE__ */ new Set();
|
|
139298
139921
|
const turnCards = makeTurnCards({
|
|
139299
139922
|
ready,
|
|
139300
|
-
resolveTarget: (threadId) => {
|
|
139923
|
+
resolveTarget: (threadId, turnId) => {
|
|
139301
139924
|
const binding = bindingOfThread(threadId);
|
|
139302
139925
|
const cards = binding === void 0 ? void 0 : adapterFor(binding.platform)?.turnCards;
|
|
139303
139926
|
if (binding === void 0 || cards === void 0) return null;
|
|
139927
|
+
let anchored;
|
|
139304
139928
|
return {
|
|
139305
139929
|
chatKey: chatKeyOf(binding),
|
|
139306
139930
|
throttleMs: cards.throttleMs,
|
|
139307
|
-
|
|
139931
|
+
rotates: cards.rotatesOnInteraction === true,
|
|
139932
|
+
open: async (view) => cards.open(await (anchored ??= anchors.anchored(binding, threadId, turnId)), view),
|
|
139308
139933
|
update: (cardId, view) => cards.update(binding, cardId, view)
|
|
139309
139934
|
};
|
|
139310
139935
|
},
|
|
@@ -139335,11 +139960,11 @@ var makeReplyCards = (core, failures) => {
|
|
|
139335
139960
|
},
|
|
139336
139961
|
onOpened: (card) => commit("turn-card-opened", card),
|
|
139337
139962
|
onClosed: (cardId) => commit("turn-card-closed", { cardId }),
|
|
139338
|
-
fallback: async (
|
|
139963
|
+
fallback: async (threadId, turnId, chatKey, view) => {
|
|
139339
139964
|
const binding = bindingForChatKey(chatKey);
|
|
139340
139965
|
if (binding === void 0) return;
|
|
139341
139966
|
const text3 = [view.body, view.errorText ?? ""].filter((part) => part !== "").join("\n\n");
|
|
139342
|
-
await deliver(binding, text3);
|
|
139967
|
+
await deliver(await anchors.anchored(binding, threadId, turnId), text3);
|
|
139343
139968
|
},
|
|
139344
139969
|
schedule: (run, delayMs) => {
|
|
139345
139970
|
const timer = setTimeout(run, delayMs);
|
|
@@ -139390,24 +140015,6 @@ var ImNotConnectedError = class extends Error {
|
|
|
139390
140015
|
}
|
|
139391
140016
|
};
|
|
139392
140017
|
|
|
139393
|
-
// src/deliveryContract.ts
|
|
139394
|
-
var DELIVERY_SEND_ERROR_CODES = [
|
|
139395
|
-
"bad-request",
|
|
139396
|
-
"unknown-bot",
|
|
139397
|
-
"unknown-target",
|
|
139398
|
-
"bot-not-connected",
|
|
139399
|
-
"delivery-failed"
|
|
139400
|
-
];
|
|
139401
|
-
var isDeliverySendErrorCode = (value2) => typeof value2 === "string" && DELIVERY_SEND_ERROR_CODES.includes(value2);
|
|
139402
|
-
var DeliverySendError = class extends Error {
|
|
139403
|
-
code;
|
|
139404
|
-
constructor(code2, message) {
|
|
139405
|
-
super(message);
|
|
139406
|
-
this.name = "DeliverySendError";
|
|
139407
|
-
this.code = code2;
|
|
139408
|
-
}
|
|
139409
|
-
};
|
|
139410
|
-
|
|
139411
140018
|
// src/delivery.ts
|
|
139412
140019
|
var makeDeliverySender = (core, config2) => {
|
|
139413
140020
|
return async (input) => {
|
|
@@ -139436,188 +140043,6 @@ var makeDeliverySender = (core, config2) => {
|
|
|
139436
140043
|
};
|
|
139437
140044
|
};
|
|
139438
140045
|
|
|
139439
|
-
// src/deliveryHttp.ts
|
|
139440
|
-
import * as NodeCrypto from "node:crypto";
|
|
139441
|
-
import * as NodeHttp from "node:http";
|
|
139442
|
-
|
|
139443
|
-
// src/boundedBody.ts
|
|
139444
|
-
var readBoundedBody = (req, limit) => new Promise((resolve) => {
|
|
139445
|
-
const chunks = [];
|
|
139446
|
-
let size = 0;
|
|
139447
|
-
let settled = false;
|
|
139448
|
-
const finish = (result) => {
|
|
139449
|
-
if (settled) return;
|
|
139450
|
-
settled = true;
|
|
139451
|
-
resolve(result);
|
|
139452
|
-
};
|
|
139453
|
-
req.on("data", (chunk) => {
|
|
139454
|
-
if (settled) return;
|
|
139455
|
-
size += chunk.length;
|
|
139456
|
-
if (size > limit) {
|
|
139457
|
-
finish({ kind: "too-large" });
|
|
139458
|
-
req.destroy();
|
|
139459
|
-
return;
|
|
139460
|
-
}
|
|
139461
|
-
chunks.push(chunk);
|
|
139462
|
-
});
|
|
139463
|
-
req.on("end", () => finish({ kind: "ok", bytes: Buffer.concat(chunks) }));
|
|
139464
|
-
req.on("error", () => finish({ kind: "read-failed" }));
|
|
139465
|
-
req.on("close", () => finish({ kind: "read-failed" }));
|
|
139466
|
-
});
|
|
139467
|
-
|
|
139468
|
-
// src/deliveryHttp.ts
|
|
139469
|
-
var LOOPBACK = "127.0.0.1";
|
|
139470
|
-
var MAX_BODY_BYTES = 1 * 1024 * 1024;
|
|
139471
|
-
var PATH = "/v1/delivery/messages";
|
|
139472
|
-
var statusFor = (code2) => {
|
|
139473
|
-
switch (code2) {
|
|
139474
|
-
case "bad-request":
|
|
139475
|
-
return 400;
|
|
139476
|
-
case "unauthorized":
|
|
139477
|
-
return 401;
|
|
139478
|
-
case "unknown-bot":
|
|
139479
|
-
case "unknown-target":
|
|
139480
|
-
return 404;
|
|
139481
|
-
case "bot-not-connected":
|
|
139482
|
-
return 503;
|
|
139483
|
-
case "delivery-failed":
|
|
139484
|
-
return 502;
|
|
139485
|
-
case "method-not-allowed":
|
|
139486
|
-
return 405;
|
|
139487
|
-
case "unsupported-media-type":
|
|
139488
|
-
return 415;
|
|
139489
|
-
case "payload-too-large":
|
|
139490
|
-
return 413;
|
|
139491
|
-
}
|
|
139492
|
-
};
|
|
139493
|
-
var writeJson = (res, status, body) => {
|
|
139494
|
-
const payload = JSON.stringify(body);
|
|
139495
|
-
res.writeHead(status, {
|
|
139496
|
-
"content-type": "application/json; charset=utf-8",
|
|
139497
|
-
"content-length": Buffer.byteLength(payload),
|
|
139498
|
-
"cache-control": "no-store"
|
|
139499
|
-
});
|
|
139500
|
-
res.end(payload);
|
|
139501
|
-
};
|
|
139502
|
-
var writeError = (res, code2, message) => {
|
|
139503
|
-
writeJson(res, statusFor(code2), { error: { code: code2, message } });
|
|
139504
|
-
};
|
|
139505
|
-
var isLoopbackRemote = (remote) => {
|
|
139506
|
-
if (remote === void 0 || remote === "") return false;
|
|
139507
|
-
return remote === "127.0.0.1" || remote === "::1" || remote === "::ffff:127.0.0.1";
|
|
139508
|
-
};
|
|
139509
|
-
var timingSafeEqualString = (a, b) => {
|
|
139510
|
-
const left = Buffer.from(a);
|
|
139511
|
-
const right = Buffer.from(b);
|
|
139512
|
-
if (left.length !== right.length) return false;
|
|
139513
|
-
return NodeCrypto.timingSafeEqual(left, right);
|
|
139514
|
-
};
|
|
139515
|
-
var parseSendBody = (raw) => {
|
|
139516
|
-
let parsed;
|
|
139517
|
-
try {
|
|
139518
|
-
parsed = JSON.parse(raw.toString("utf8"));
|
|
139519
|
-
} catch {
|
|
139520
|
-
return "bad-request";
|
|
139521
|
-
}
|
|
139522
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return "bad-request";
|
|
139523
|
-
const record2 = parsed;
|
|
139524
|
-
const botId = record2["botId"];
|
|
139525
|
-
const targetId = record2["targetId"];
|
|
139526
|
-
const text3 = record2["text"];
|
|
139527
|
-
const format2 = record2["format"];
|
|
139528
|
-
if (typeof botId !== "string" || botId.trim() === "") return "bad-request";
|
|
139529
|
-
if (typeof targetId !== "string" || targetId.trim() === "") return "bad-request";
|
|
139530
|
-
if (typeof text3 !== "string" || text3.trim() === "") return "bad-request";
|
|
139531
|
-
if (format2 !== void 0 && format2 !== "plain" && format2 !== "markdown") return "bad-request";
|
|
139532
|
-
for (const key of Object.keys(record2)) {
|
|
139533
|
-
if (key !== "botId" && key !== "targetId" && key !== "text" && key !== "format") {
|
|
139534
|
-
return "bad-request";
|
|
139535
|
-
}
|
|
139536
|
-
}
|
|
139537
|
-
return {
|
|
139538
|
-
botId: botId.trim(),
|
|
139539
|
-
targetId: targetId.trim(),
|
|
139540
|
-
text: text3,
|
|
139541
|
-
format: format2 === "markdown" ? "markdown" : format2 === "plain" ? "plain" : void 0
|
|
139542
|
-
};
|
|
139543
|
-
};
|
|
139544
|
-
var startDeliveryHttpServer = async (options) => {
|
|
139545
|
-
const server = NodeHttp.createServer((req, res) => {
|
|
139546
|
-
void (async () => {
|
|
139547
|
-
if (!isLoopbackRemote(req.socket.remoteAddress)) {
|
|
139548
|
-
writeError(res, "unauthorized", "Only loopback clients are accepted.");
|
|
139549
|
-
return;
|
|
139550
|
-
}
|
|
139551
|
-
const url = new URL(req.url ?? "/", `http://${LOOPBACK}`);
|
|
139552
|
-
if (url.pathname !== PATH) {
|
|
139553
|
-
writeError(res, "bad-request", `Unknown path '${url.pathname}'.`);
|
|
139554
|
-
return;
|
|
139555
|
-
}
|
|
139556
|
-
if (req.method !== "POST") {
|
|
139557
|
-
res.setHeader("allow", "POST");
|
|
139558
|
-
writeError(res, "method-not-allowed", "Only POST is accepted.");
|
|
139559
|
-
return;
|
|
139560
|
-
}
|
|
139561
|
-
const contentType = (req.headers["content-type"] ?? "").split(";")[0]?.trim().toLowerCase();
|
|
139562
|
-
if (contentType !== "application/json") {
|
|
139563
|
-
writeError(res, "unsupported-media-type", "Content-Type must be application/json.");
|
|
139564
|
-
return;
|
|
139565
|
-
}
|
|
139566
|
-
if (options.token !== "") {
|
|
139567
|
-
const header = req.headers.authorization ?? "";
|
|
139568
|
-
const prefix = "Bearer ";
|
|
139569
|
-
if (!header.startsWith(prefix) || !timingSafeEqualString(header.slice(prefix.length), options.token)) {
|
|
139570
|
-
writeError(res, "unauthorized", "Bearer token required.");
|
|
139571
|
-
return;
|
|
139572
|
-
}
|
|
139573
|
-
}
|
|
139574
|
-
const read = await readBoundedBody(req, MAX_BODY_BYTES);
|
|
139575
|
-
if (read.kind !== "ok") {
|
|
139576
|
-
if (read.kind === "too-large") {
|
|
139577
|
-
writeError(res, "payload-too-large", "JSON body exceeds 1 MiB.");
|
|
139578
|
-
} else {
|
|
139579
|
-
writeError(res, "bad-request", "Failed to read body.");
|
|
139580
|
-
}
|
|
139581
|
-
return;
|
|
139582
|
-
}
|
|
139583
|
-
const parsed = parseSendBody(read.bytes);
|
|
139584
|
-
if (typeof parsed === "string") {
|
|
139585
|
-
writeError(res, parsed, "Invalid JSON body.");
|
|
139586
|
-
return;
|
|
139587
|
-
}
|
|
139588
|
-
try {
|
|
139589
|
-
const result = await options.send(parsed);
|
|
139590
|
-
writeJson(res, 200, { sent: result.sent });
|
|
139591
|
-
} catch (error) {
|
|
139592
|
-
const rawCode = error instanceof Error ? error.code : void 0;
|
|
139593
|
-
const code2 = isDeliverySendErrorCode(rawCode) ? rawCode : "delivery-failed";
|
|
139594
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
139595
|
-
options.log?.warn("delivery http send failed", { code: code2, message });
|
|
139596
|
-
writeError(res, code2, message);
|
|
139597
|
-
}
|
|
139598
|
-
})().catch((error) => {
|
|
139599
|
-
options.log?.warn("delivery http handler crashed", {
|
|
139600
|
-
error: error instanceof Error ? error.message : String(error)
|
|
139601
|
-
});
|
|
139602
|
-
if (!res.headersSent) writeError(res, "delivery-failed", "Internal error.");
|
|
139603
|
-
});
|
|
139604
|
-
});
|
|
139605
|
-
await new Promise((resolve, reject) => {
|
|
139606
|
-
server.once("error", reject);
|
|
139607
|
-
server.listen(options.port, LOOPBACK, () => resolve());
|
|
139608
|
-
});
|
|
139609
|
-
const address = server.address();
|
|
139610
|
-
const port = address.port;
|
|
139611
|
-
options.log?.info("delivery http listening", { host: LOOPBACK, port, path: PATH });
|
|
139612
|
-
return {
|
|
139613
|
-
port,
|
|
139614
|
-
origin: `http://${LOOPBACK}:${String(port)}`,
|
|
139615
|
-
close: () => new Promise((resolve, reject) => {
|
|
139616
|
-
server.close((error) => error ? reject(error) : resolve());
|
|
139617
|
-
})
|
|
139618
|
-
};
|
|
139619
|
-
};
|
|
139620
|
-
|
|
139621
140046
|
// src/sendFile.ts
|
|
139622
140047
|
var failure = (code2, text3) => ({
|
|
139623
140048
|
text: text3,
|
|
@@ -139673,7 +140098,7 @@ var makeSendFileTool = (deps) => ({
|
|
|
139673
140098
|
handle: async (input, invocation) => {
|
|
139674
140099
|
const path = typeof input["path"] === "string" ? input["path"].trim() : "";
|
|
139675
140100
|
if (path === "") return failure("unreadable", "`path` is required.");
|
|
139676
|
-
const binding = invocation.threadId === null ? void 0 : deps.boundChat(invocation.threadId);
|
|
140101
|
+
const binding = invocation.threadId === null ? void 0 : await deps.boundChat(invocation.threadId);
|
|
139677
140102
|
if (binding === void 0) {
|
|
139678
140103
|
return failure(
|
|
139679
140104
|
"not-in-chat",
|
|
@@ -139992,6 +140417,7 @@ var chatIdOf = (message) => {
|
|
|
139992
140417
|
const thread = message.message_thread_id;
|
|
139993
140418
|
return message.is_topic_message === true && thread !== void 0 && thread > 0 ? `${String(message.chat.id)}:${String(thread)}` : String(message.chat.id);
|
|
139994
140419
|
};
|
|
140420
|
+
var parentChatIdOf = (message) => chatIdOf(message) === String(message.chat.id) ? void 0 : String(message.chat.id);
|
|
139995
140421
|
var splitChatId = (chatId) => {
|
|
139996
140422
|
const match = /^(.+):([1-9]\d*)$/u.exec(chatId);
|
|
139997
140423
|
return match === null ? { chat: chatId, thread: null } : { chat: match[1] ?? chatId, thread: Number(match[2]) };
|
|
@@ -140515,12 +140941,17 @@ var makeTelegramAdapter = (deps) => {
|
|
|
140515
140941
|
arg: action.arg ?? null
|
|
140516
140942
|
}) ?? null;
|
|
140517
140943
|
};
|
|
140518
|
-
const apiFor =
|
|
140944
|
+
const apiFor = (binding) => {
|
|
140945
|
+
const token = tokenOf(binding);
|
|
140946
|
+
const builtFor = JSON.stringify([token, binding.proxy === void 0 ? [] : [binding.proxy]]);
|
|
140519
140947
|
const existing = apis.get(binding.rowId);
|
|
140520
|
-
if (existing
|
|
140521
|
-
const
|
|
140522
|
-
const
|
|
140523
|
-
apis.set(binding.rowId,
|
|
140948
|
+
if (existing?.builtFor === builtFor) return existing.api;
|
|
140949
|
+
const api = deps.fetchVia(binding.proxy).then((http) => makeTelegramApi({ http, token }));
|
|
140950
|
+
const entry = { builtFor, api };
|
|
140951
|
+
apis.set(binding.rowId, entry);
|
|
140952
|
+
api.catch(() => {
|
|
140953
|
+
if (apis.get(binding.rowId) === entry) apis.delete(binding.rowId);
|
|
140954
|
+
});
|
|
140524
140955
|
return api;
|
|
140525
140956
|
};
|
|
140526
140957
|
const makeWriter = (api, chatId, resume) => makeTurnWriter({
|
|
@@ -140618,9 +141049,11 @@ var makeTelegramAdapter = (deps) => {
|
|
|
140618
141049
|
});
|
|
140619
141050
|
continue;
|
|
140620
141051
|
}
|
|
141052
|
+
const parentChatId = parentChatIdOf(message);
|
|
140621
141053
|
handlers.onMessage({
|
|
140622
141054
|
messageId: String(message.message_id),
|
|
140623
141055
|
chatId: chatIdOf(message),
|
|
141056
|
+
...parentChatId === void 0 ? {} : { parentChatId },
|
|
140624
141057
|
senderId: message.from === void 0 ? null : String(message.from.id),
|
|
140625
141058
|
text: text3,
|
|
140626
141059
|
chatKind: message.chat.type === "private" ? "private" : "group",
|
|
@@ -140846,6 +141279,10 @@ var makeTurns = (core, deps) => {
|
|
|
140846
141279
|
return true;
|
|
140847
141280
|
}
|
|
140848
141281
|
};
|
|
141282
|
+
const waitingFor = (chatKey, threadId) => {
|
|
141283
|
+
const waiting = pendingByChat.get(chatKey);
|
|
141284
|
+
return waiting !== void 0 && waiting.threadId === threadId ? waiting : void 0;
|
|
141285
|
+
};
|
|
140849
141286
|
const interactionModeOf = (chatKey) => chatOf(core.state, chatKey).plan ? "plan" : "default";
|
|
140850
141287
|
const ensureThread = async (binding, titleSeed) => {
|
|
140851
141288
|
const chatKey = chatKeyOf(binding);
|
|
@@ -140905,9 +141342,8 @@ var makeTurns = (core, deps) => {
|
|
|
140905
141342
|
const text3 = message.text;
|
|
140906
141343
|
const threadId = await ensureThread(binding, text3 || message.resources[0]?.name || "Chat");
|
|
140907
141344
|
if (threadId === null) return null;
|
|
140908
|
-
const
|
|
141345
|
+
const carried = waitingFor(chatKey, threadId);
|
|
140909
141346
|
pendingByChat.delete(chatKey);
|
|
140910
|
-
const carried = waiting?.threadId === threadId ? waiting : void 0;
|
|
140911
141347
|
const own = await collectResources(
|
|
140912
141348
|
binding,
|
|
140913
141349
|
threadId,
|
|
@@ -140918,6 +141354,7 @@ var makeTurns = (core, deps) => {
|
|
|
140918
141354
|
const attachments = [...carried?.attachments ?? [], ...own.attachments];
|
|
140919
141355
|
const notes = [...carried?.notes ?? [], ...own.notes];
|
|
140920
141356
|
const userMessageId = crypto.randomUUID();
|
|
141357
|
+
deps.anchors.note(threadId, userMessageId, binding);
|
|
140921
141358
|
let intentAction;
|
|
140922
141359
|
if (binding.queueMode === "steer") {
|
|
140923
141360
|
try {
|
|
@@ -140965,7 +141402,8 @@ var makeTurns = (core, deps) => {
|
|
|
140965
141402
|
chatKey,
|
|
140966
141403
|
threadId,
|
|
140967
141404
|
userMessageId,
|
|
140968
|
-
text3.trim() || attachments[0]?.name || message.resources[0]?.name || ""
|
|
141405
|
+
text3.trim() || attachments[0]?.name || message.resources[0]?.name || "",
|
|
141406
|
+
binding.reply
|
|
140969
141407
|
);
|
|
140970
141408
|
return threadId;
|
|
140971
141409
|
};
|
|
@@ -140991,7 +141429,14 @@ var makeTurns = (core, deps) => {
|
|
|
140991
141429
|
})
|
|
140992
141430
|
);
|
|
140993
141431
|
};
|
|
140994
|
-
|
|
141432
|
+
const hasWaitingAttachments = (chatKey) => (waitingFor(chatKey, chatOf(core.state, chatKey).threadId)?.attachments.length ?? 0) > 0;
|
|
141433
|
+
return {
|
|
141434
|
+
threadStillUsable,
|
|
141435
|
+
ensureThread,
|
|
141436
|
+
startTurn,
|
|
141437
|
+
receiveAttachmentsOnly,
|
|
141438
|
+
hasWaitingAttachments
|
|
141439
|
+
};
|
|
140995
141440
|
};
|
|
140996
141441
|
|
|
140997
141442
|
// src/webSync.ts
|
|
@@ -141814,6 +142259,7 @@ ${kept}`;
|
|
|
141814
142259
|
icon: "wecom",
|
|
141815
142260
|
label: "WeCom",
|
|
141816
142261
|
columns: COLUMNS4,
|
|
142262
|
+
unlistedValues: ["wecomEndpoint"],
|
|
141817
142263
|
isConfigured: (binding) => {
|
|
141818
142264
|
const { botId, botSecret } = credentials2(binding);
|
|
141819
142265
|
return botId !== "" && botSecret !== "";
|
|
@@ -142920,7 +143366,9 @@ var imPlugin = definePlugin({
|
|
|
142920
143366
|
id: "im",
|
|
142921
143367
|
apiVersion: 3,
|
|
142922
143368
|
activate: async (ctx) => {
|
|
142923
|
-
const t =
|
|
143369
|
+
const { t, setLanguage } = makeLiveTranslate(
|
|
143370
|
+
parseReplyLanguage(ctx.config[REPLY_LANGUAGE_FIELD])
|
|
143371
|
+
);
|
|
142924
143372
|
const adapters = [
|
|
142925
143373
|
makeLarkAdapter({
|
|
142926
143374
|
http: ctx.http,
|
|
@@ -142989,29 +143437,36 @@ var imPlugin = definePlugin({
|
|
|
142989
143437
|
onDispose: ctx.onDispose
|
|
142990
143438
|
},
|
|
142991
143439
|
pluginId: ctx.id,
|
|
142992
|
-
config: ctx.config,
|
|
143440
|
+
config: () => ctx.config,
|
|
142993
143441
|
derivedState: ctx.derivedState,
|
|
142994
143442
|
t,
|
|
142995
143443
|
adapters
|
|
142996
143444
|
});
|
|
142997
143445
|
const acknowledgements = makeAcknowledgements(core);
|
|
142998
143446
|
const failures = makeFailureNotices(core);
|
|
142999
|
-
const
|
|
143447
|
+
const replyAnchors = makeReplyAnchors(core.host);
|
|
143448
|
+
const replyCards = makeReplyCards(core, failures, replyAnchors);
|
|
143000
143449
|
const teams = makeTeamRuns(core, { clearWorking: acknowledgements.clearWorking });
|
|
143001
143450
|
const notifications = makeNotifications(core, {
|
|
143002
143451
|
clearWorking: acknowledgements.clearWorking,
|
|
143003
143452
|
replyCards,
|
|
143004
|
-
failures
|
|
143453
|
+
failures,
|
|
143454
|
+
anchors: replyAnchors
|
|
143005
143455
|
});
|
|
143006
143456
|
const webSync = makeWebSync(core);
|
|
143007
|
-
const approvals = makeApprovals(core);
|
|
143008
|
-
const interactions = makeInteractions(core,
|
|
143457
|
+
const approvals = makeApprovals(core, replyAnchors);
|
|
143458
|
+
const interactions = makeInteractions(core, {
|
|
143459
|
+
...approvals,
|
|
143460
|
+
anchors: replyAnchors,
|
|
143461
|
+
rotateTurnCard: replyCards.turnCards.rotate
|
|
143462
|
+
});
|
|
143009
143463
|
const inboundAttachments = makeInboundAttachments(core);
|
|
143010
143464
|
const turns = makeTurns(core, {
|
|
143011
143465
|
attachments: inboundAttachments,
|
|
143012
143466
|
queueFlow: interactions.queueFlow,
|
|
143013
143467
|
rememberThreadProject: notifications.rememberThreadProject,
|
|
143014
|
-
noteInboundUserMessage: webSync.noteInboundUserMessage
|
|
143468
|
+
noteInboundUserMessage: webSync.noteInboundUserMessage,
|
|
143469
|
+
anchors: replyAnchors
|
|
143015
143470
|
});
|
|
143016
143471
|
const sessions = makeSessions(core);
|
|
143017
143472
|
const modelPlan = makeModelPlan(core, turns);
|
|
@@ -143027,7 +143482,7 @@ var imPlugin = definePlugin({
|
|
|
143027
143482
|
});
|
|
143028
143483
|
const chatSetup = makeChatSetup(core, {
|
|
143029
143484
|
rows: projectRows,
|
|
143030
|
-
openPicker: (chatKey, rows) => panelWiring.panel.openProjects(chatKey, rows)
|
|
143485
|
+
openPicker: (chatKey, rows, reply) => panelWiring.panel.openProjects(chatKey, rows, reply)
|
|
143031
143486
|
});
|
|
143032
143487
|
const commands = makeCommands(core, {
|
|
143033
143488
|
clearWorking: acknowledgements.clearWorking,
|
|
@@ -143035,7 +143490,7 @@ var imPlugin = definePlugin({
|
|
|
143035
143490
|
sessions,
|
|
143036
143491
|
modelPlan,
|
|
143037
143492
|
chatSetup,
|
|
143038
|
-
openPanel: (chatKey) => panelWiring.panel.open(chatKey)
|
|
143493
|
+
openPanel: (chatKey, reply) => panelWiring.panel.open(chatKey, reply)
|
|
143039
143494
|
});
|
|
143040
143495
|
const inbound = makeInbound(core, {
|
|
143041
143496
|
enqueueForChat: chatQueue.enqueueForChat,
|
|
@@ -143053,7 +143508,10 @@ var imPlugin = definePlugin({
|
|
|
143053
143508
|
name: "im",
|
|
143054
143509
|
tools: [
|
|
143055
143510
|
makeSendFileTool({
|
|
143056
|
-
boundChat: (threadId) =>
|
|
143511
|
+
boundChat: async (threadId) => {
|
|
143512
|
+
const binding = core.bindingOfThread(threadId);
|
|
143513
|
+
return binding === void 0 ? void 0 : replyAnchors.anchored(binding, threadId, null);
|
|
143514
|
+
},
|
|
143057
143515
|
adapterFor: (binding) => core.adapterFor(binding.platform),
|
|
143058
143516
|
translate: t,
|
|
143059
143517
|
log: {
|
|
@@ -143063,34 +143521,21 @@ var imPlugin = definePlugin({
|
|
|
143063
143521
|
})
|
|
143064
143522
|
]
|
|
143065
143523
|
});
|
|
143066
|
-
const
|
|
143067
|
-
|
|
143068
|
-
|
|
143069
|
-
|
|
143070
|
-
|
|
143071
|
-
|
|
143072
|
-
|
|
143073
|
-
|
|
143074
|
-
|
|
143075
|
-
|
|
143076
|
-
|
|
143077
|
-
|
|
143078
|
-
|
|
143079
|
-
|
|
143080
|
-
|
|
143081
|
-
ctx.onDispose(() => {
|
|
143082
|
-
void server.close().catch((error) => {
|
|
143083
|
-
ctx.log.warn("delivery http could not close", {
|
|
143084
|
-
error: error instanceof Error ? error.message : String(error)
|
|
143085
|
-
});
|
|
143086
|
-
});
|
|
143087
|
-
});
|
|
143088
|
-
} catch (error) {
|
|
143089
|
-
ctx.log.warn("delivery http failed to listen", {
|
|
143090
|
-
port,
|
|
143091
|
-
error: error instanceof Error ? error.message : String(error)
|
|
143092
|
-
});
|
|
143093
|
-
}
|
|
143524
|
+
const connections = startConnections(core, inbound.inboundHandlersFor);
|
|
143525
|
+
const { bots, connecting } = connections.reconcile();
|
|
143526
|
+
const deliveryHttp = makeDeliveryHttp({
|
|
143527
|
+
// 每次请求按此刻的设置找目标:投递目标表改了不用重开监听。
|
|
143528
|
+
send: (input) => makeDeliverySender(core, ctx.config)(input),
|
|
143529
|
+
log: ctx.log,
|
|
143530
|
+
onDispose: ctx.onDispose
|
|
143531
|
+
});
|
|
143532
|
+
await deliveryHttp.apply(ctx.config);
|
|
143533
|
+
if (typeof ctx.settings.onChange === "function") {
|
|
143534
|
+
ctx.settings.onChange(async (config2) => {
|
|
143535
|
+
setLanguage(parseReplyLanguage(config2[REPLY_LANGUAGE_FIELD]));
|
|
143536
|
+
connections.reconcile();
|
|
143537
|
+
await deliveryHttp.apply(config2);
|
|
143538
|
+
});
|
|
143094
143539
|
}
|
|
143095
143540
|
ctx.log.info("chat plugin active", { bots, connecting });
|
|
143096
143541
|
}
|