metheus-governance-mcp-cli 0.2.276 → 0.2.278
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/cli.mjs +123 -56
- package/lib/runner-helpers.mjs +160 -0
- package/lib/runner-orchestration-adjudication.mjs +60 -0
- package/lib/runner-orchestration-entrypoints.mjs +20 -0
- package/lib/runner-recovery.mjs +19 -0
- package/lib/runner-runtime.mjs +24 -14
- package/lib/selftest-runner-scenarios.mjs +278 -16
- package/lib/selftest-telegram-e2e.mjs +117 -0
- package/package.json +1 -1
package/cli.mjs
CHANGED
|
@@ -135,6 +135,7 @@ import {
|
|
|
135
135
|
} from "./lib/client-registration.mjs";
|
|
136
136
|
import {
|
|
137
137
|
applyPendingAgeSelection,
|
|
138
|
+
buildCanonicalHumanInboundKey as buildRunnerCanonicalHumanInboundKey,
|
|
138
139
|
buildTelegramBotReplyEnvelope,
|
|
139
140
|
buildTelegramMessageEnvelopeFromParsedArchive as buildRunnerTelegramMessageEnvelopeFromParsedArchive,
|
|
140
141
|
buildRunnerRouteDuplicateStateFromComment,
|
|
@@ -3522,30 +3523,35 @@ function uniqueOrderedStrings(values, normalizer = (value) => String(value || ""
|
|
|
3522
3523
|
return output;
|
|
3523
3524
|
}
|
|
3524
3525
|
|
|
3525
|
-
function buildRunnerRequestKey({
|
|
3526
|
-
normalizedRoute,
|
|
3527
|
-
selectedRecord,
|
|
3528
|
-
selectedBotUsernames = [],
|
|
3529
|
-
normalizedIntent = "",
|
|
3530
|
-
conversationID = "",
|
|
3531
|
-
}) {
|
|
3532
|
-
const parsed = safeObject(selectedRecord?.parsedArchive);
|
|
3533
|
-
const chatID = String(parsed.chatID || parsed.chatId || "").trim() || "-";
|
|
3534
|
-
const messageID = intFromRawAllowZero(parsed.messageID, 0);
|
|
3535
|
-
const kind = String(parsed.kind || "").trim().toLowerCase() || "-";
|
|
3536
|
-
const
|
|
3537
|
-
const
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3526
|
+
function buildRunnerRequestKey({
|
|
3527
|
+
normalizedRoute,
|
|
3528
|
+
selectedRecord,
|
|
3529
|
+
selectedBotUsernames = [],
|
|
3530
|
+
normalizedIntent = "",
|
|
3531
|
+
conversationID = "",
|
|
3532
|
+
}) {
|
|
3533
|
+
const parsed = safeObject(selectedRecord?.parsedArchive);
|
|
3534
|
+
const chatID = String(parsed.chatID || parsed.chatId || "").trim() || "-";
|
|
3535
|
+
const messageID = intFromRawAllowZero(parsed.messageID, 0);
|
|
3536
|
+
const kind = String(parsed.kind || "").trim().toLowerCase() || "-";
|
|
3537
|
+
const canonicalHumanKey = buildRunnerCanonicalHumanInboundKey(parsed);
|
|
3538
|
+
const responders = canonicalHumanKey
|
|
3539
|
+
? "-"
|
|
3540
|
+
: uniqueOrderedStrings(selectedBotUsernames, normalizeTelegramMentionUsername).join(",") || "-";
|
|
3541
|
+
const intent = canonicalHumanKey
|
|
3542
|
+
? "-"
|
|
3543
|
+
: String(normalizedIntent || "").trim().toLowerCase() || "-";
|
|
3544
|
+
const resolvedConversationID = String(conversationID || parsed.conversationID || "").trim() || "-";
|
|
3545
|
+
return [
|
|
3546
|
+
String(normalizedRoute?.projectID || "").trim() || "-",
|
|
3547
|
+
String(normalizedRoute?.provider || "").trim() || "-",
|
|
3548
|
+
chatID,
|
|
3549
|
+
canonicalHumanKey ? `human:${canonicalHumanKey}` : String(messageID || "-"),
|
|
3550
|
+
kind,
|
|
3551
|
+
responders,
|
|
3552
|
+
intent,
|
|
3553
|
+
resolvedConversationID,
|
|
3554
|
+
].join("::");
|
|
3549
3555
|
}
|
|
3550
3556
|
|
|
3551
3557
|
function resolveRunnerRequestClaimIntent({
|
|
@@ -3614,15 +3620,19 @@ function buildSyntheticReplyChainConversationID(normalizedRoute, chatID, anchorM
|
|
|
3614
3620
|
return `reply_chain:${provider}:${normalizedChatID}:${normalizedAnchorMessageID}`;
|
|
3615
3621
|
}
|
|
3616
3622
|
|
|
3617
|
-
function buildSyntheticHumanOpeningConversationID(normalizedRoute, chatID, messageID) {
|
|
3618
|
-
const provider = String(normalizedRoute?.provider || "").trim() || "unknown";
|
|
3619
|
-
const
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3623
|
+
function buildSyntheticHumanOpeningConversationID(normalizedRoute, chatID, messageID, canonicalHumanMessageKey = "") {
|
|
3624
|
+
const provider = String(normalizedRoute?.provider || "").trim() || "unknown";
|
|
3625
|
+
const canonicalKey = String(canonicalHumanMessageKey || "").trim();
|
|
3626
|
+
if (canonicalKey) {
|
|
3627
|
+
return `human_opening:${provider}:${canonicalKey}`;
|
|
3628
|
+
}
|
|
3629
|
+
const normalizedChatID = String(chatID || "").trim() || "-";
|
|
3630
|
+
const normalizedMessageID = intFromRawAllowZero(messageID, 0);
|
|
3631
|
+
if (normalizedMessageID <= 0) {
|
|
3632
|
+
return "";
|
|
3633
|
+
}
|
|
3634
|
+
return `human_opening:${provider}:${normalizedChatID}:${normalizedMessageID}`;
|
|
3635
|
+
}
|
|
3626
3636
|
|
|
3627
3637
|
function findRunnerRequestsForScope(state, normalizedRoute, selectors = {}) {
|
|
3628
3638
|
const requests = normalizeBotRunnerRequests(state?.requests);
|
|
@@ -4910,24 +4920,26 @@ function resolveRunnerHumanCommentAuthorityContext({
|
|
|
4910
4920
|
const referenced = safeObject(referencedRequest);
|
|
4911
4921
|
const sharedSource = safeObject(sharedConversationSource);
|
|
4912
4922
|
const sharedIntent = safeObject(normalizedSharedHumanIntent);
|
|
4913
|
-
const authoritySource = Object.keys(referenced).length
|
|
4914
|
-
? referenced
|
|
4915
|
-
: Object.keys(sharedSource).length
|
|
4916
|
-
? sharedSource
|
|
4917
|
-
: {};
|
|
4918
|
-
const currentMessageID = intFromRawAllowZero(parsed.messageID, 0);
|
|
4919
|
-
const
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4923
|
+
const authoritySource = Object.keys(referenced).length
|
|
4924
|
+
? referenced
|
|
4925
|
+
: Object.keys(sharedSource).length
|
|
4926
|
+
? sharedSource
|
|
4927
|
+
: {};
|
|
4928
|
+
const currentMessageID = intFromRawAllowZero(parsed.messageID, 0);
|
|
4929
|
+
const canonicalHumanMessageKey = buildRunnerCanonicalHumanInboundKey(parsed);
|
|
4930
|
+
const resolvedConversationID = firstNonEmptyString([
|
|
4931
|
+
parsed.conversationID,
|
|
4932
|
+
replyChain.conversationID,
|
|
4933
|
+
authoritySource.conversation_id,
|
|
4934
|
+
Object.keys(sharedIntent).length > 0
|
|
4935
|
+
? buildSyntheticHumanOpeningConversationID(
|
|
4936
|
+
normalizedRoute,
|
|
4937
|
+
String(parsed.chatID || parsed.chatId || "").trim(),
|
|
4938
|
+
currentMessageID,
|
|
4939
|
+
canonicalHumanMessageKey,
|
|
4940
|
+
)
|
|
4941
|
+
: "",
|
|
4942
|
+
]);
|
|
4931
4943
|
const explicitSelectedBotUsernames = uniqueOrderedStrings(
|
|
4932
4944
|
selectedBotUsernames,
|
|
4933
4945
|
normalizeTelegramMentionUsername,
|
|
@@ -5770,7 +5782,21 @@ async function finalizePreparedRunnerSelectedRecordExecutionContext({
|
|
|
5770
5782
|
};
|
|
5771
5783
|
}
|
|
5772
5784
|
if (mode === "continuation_finalize") {
|
|
5773
|
-
const requestClaim = normalizePreparedRunnerRequestClaim(
|
|
5785
|
+
const requestClaim = normalizePreparedRunnerRequestClaim(resolveRunnerContinuationRequestForBotReplyImpl({
|
|
5786
|
+
normalizedRoute,
|
|
5787
|
+
routeKey,
|
|
5788
|
+
selectedRecord,
|
|
5789
|
+
persist: true,
|
|
5790
|
+
deps: buildRunnerRecoveryDeps(),
|
|
5791
|
+
}));
|
|
5792
|
+
if (!requestClaim.ok) {
|
|
5793
|
+
return finalizeRunnerRequestClaimFailureRecorderState({
|
|
5794
|
+
normalizedRoute,
|
|
5795
|
+
runtime,
|
|
5796
|
+
requestClaim,
|
|
5797
|
+
syncRunnerRequestLedgerForProjectToServer,
|
|
5798
|
+
});
|
|
5799
|
+
}
|
|
5774
5800
|
const finalizedRequest = await finalizePreparedRunnerRequestForExecution({
|
|
5775
5801
|
normalizedRoute,
|
|
5776
5802
|
routeKey,
|
|
@@ -8125,6 +8151,16 @@ function buildTelegramArchiveStructuredPayload(normalized) {
|
|
|
8125
8151
|
.map((value) => normalizeTelegramMentionUsername(value))
|
|
8126
8152
|
.filter(Boolean),
|
|
8127
8153
|
occurredAt: String(normalized?.occurredAt || "").trim(),
|
|
8154
|
+
canonicalHumanMessageKey: buildRunnerCanonicalHumanInboundKey({
|
|
8155
|
+
chatID: normalized?.chatID,
|
|
8156
|
+
kind,
|
|
8157
|
+
senderID: normalized?.fromID,
|
|
8158
|
+
senderIsBot: normalized?.fromIsBot === true,
|
|
8159
|
+
occurredAt: normalized?.occurredAt,
|
|
8160
|
+
messageThreadID: normalized?.messageThreadID,
|
|
8161
|
+
replyToMessageID: normalized?.replyToMessageID,
|
|
8162
|
+
body: normalized?.text,
|
|
8163
|
+
}),
|
|
8128
8164
|
sourceOrigin: String(normalized?.archiveSourceOrigin || normalized?.sourceOrigin || "").trim().toLowerCase(),
|
|
8129
8165
|
sourceRouteKey: String(normalized?.archiveSourceRouteKey || normalized?.sourceRouteKey || "").trim(),
|
|
8130
8166
|
sourceBotUsername: normalizeTelegramMentionUsername(normalized?.archiveSourceBotUsername || normalized?.sourceBotUsername || ""),
|
|
@@ -8261,6 +8297,10 @@ function parseArchivedChatComment(rawBody) {
|
|
|
8261
8297
|
.map((value) => normalizeTelegramMentionUsername(value))
|
|
8262
8298
|
.filter(Boolean),
|
|
8263
8299
|
occurredAt: firstNonEmptyString([safeObject(structuredPayload).occurredAt, metadata.occurred_at]),
|
|
8300
|
+
canonicalHumanMessageKey: firstNonEmptyString([
|
|
8301
|
+
safeObject(structuredPayload).canonicalHumanMessageKey,
|
|
8302
|
+
metadata.canonical_human_message_key,
|
|
8303
|
+
]),
|
|
8264
8304
|
sourceOrigin: firstNonEmptyString([safeObject(structuredPayload).sourceOrigin, metadata.archive_source_origin, metadata.source_origin]).toLowerCase(),
|
|
8265
8305
|
sourceRouteKey: firstNonEmptyString([safeObject(structuredPayload).sourceRouteKey, metadata.archive_source_route_key, metadata.source_route_key]),
|
|
8266
8306
|
sourceBotUsername: normalizeTelegramMentionUsername(
|
|
@@ -8595,9 +8635,35 @@ function normalizeLocalTelegramUpdate(rawUpdate) {
|
|
|
8595
8635
|
};
|
|
8596
8636
|
}
|
|
8597
8637
|
|
|
8598
|
-
function buildArchivedInboundMessageKey(
|
|
8599
|
-
const
|
|
8600
|
-
|
|
8638
|
+
function buildArchivedInboundMessageKey(chatIDOrEnvelope, messageID = undefined, sourceBotUsername = "") {
|
|
8639
|
+
const rawEnvelope = messageID === undefined && typeof chatIDOrEnvelope === "object" && chatIDOrEnvelope !== null
|
|
8640
|
+
? safeObject(chatIDOrEnvelope)
|
|
8641
|
+
: {
|
|
8642
|
+
chatID: chatIDOrEnvelope,
|
|
8643
|
+
messageID,
|
|
8644
|
+
sourceBotUsername,
|
|
8645
|
+
};
|
|
8646
|
+
const canonicalHumanKey = buildRunnerCanonicalHumanInboundKey(rawEnvelope);
|
|
8647
|
+
if (canonicalHumanKey) {
|
|
8648
|
+
return `human:${canonicalHumanKey}`;
|
|
8649
|
+
}
|
|
8650
|
+
const chatID = String(
|
|
8651
|
+
rawEnvelope.chatID
|
|
8652
|
+
|| rawEnvelope.chatId
|
|
8653
|
+
|| rawEnvelope.chat_id
|
|
8654
|
+
|| "",
|
|
8655
|
+
).trim();
|
|
8656
|
+
const normalizedMessageID = intFromRawAllowZero(
|
|
8657
|
+
rawEnvelope.messageID
|
|
8658
|
+
|| rawEnvelope.message_id,
|
|
8659
|
+
0,
|
|
8660
|
+
);
|
|
8661
|
+
const baseKey = `${chatID}:${normalizedMessageID}`;
|
|
8662
|
+
const normalizedBotUsername = normalizeTelegramMentionUsername(
|
|
8663
|
+
rawEnvelope.sourceBotUsername
|
|
8664
|
+
|| rawEnvelope.source_bot_username
|
|
8665
|
+
|| sourceBotUsername,
|
|
8666
|
+
);
|
|
8601
8667
|
return normalizedBotUsername ? `${baseKey}::${normalizedBotUsername}` : baseKey;
|
|
8602
8668
|
}
|
|
8603
8669
|
|
|
@@ -17917,7 +17983,8 @@ TELEGRAM_BOT_REVIEW_TOKEN=review-token
|
|
|
17917
17983
|
saveRunnerRouteState,
|
|
17918
17984
|
mergeServerRunnerRequestLedgerIntoLocalState,
|
|
17919
17985
|
buildRunnerStatusQueryLookup,
|
|
17920
|
-
|
|
17986
|
+
buildArchivedInboundMessageKey,
|
|
17987
|
+
tryJsonParse,
|
|
17921
17988
|
safeObject,
|
|
17922
17989
|
normalizeRunnerTriggerPolicy,
|
|
17923
17990
|
evaluateTelegramRunnerTrigger,
|
package/lib/runner-helpers.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import process from "node:process";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
2
3
|
|
|
3
4
|
function safeObject(value) {
|
|
4
5
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -11,6 +12,24 @@ function ensureArray(value) {
|
|
|
11
12
|
return Array.isArray(value) ? value : [];
|
|
12
13
|
}
|
|
13
14
|
|
|
15
|
+
function normalizeBodyForCanonicalKey(value) {
|
|
16
|
+
return String(value || "")
|
|
17
|
+
.replace(/\s+/g, " ")
|
|
18
|
+
.trim();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function normalizeOccurredAtForCanonicalKey(value) {
|
|
22
|
+
const text = String(value || "").trim();
|
|
23
|
+
if (!text) {
|
|
24
|
+
return "";
|
|
25
|
+
}
|
|
26
|
+
const parsed = Date.parse(text);
|
|
27
|
+
if (!Number.isFinite(parsed)) {
|
|
28
|
+
return text;
|
|
29
|
+
}
|
|
30
|
+
return new Date(Math.floor(parsed / 1000) * 1000).toISOString();
|
|
31
|
+
}
|
|
32
|
+
|
|
14
33
|
function firstNonEmptyString(values) {
|
|
15
34
|
for (const value of ensureArray(values)) {
|
|
16
35
|
const text = String(value ?? "").trim();
|
|
@@ -31,6 +50,93 @@ function intFromRaw(raw, fallback) {
|
|
|
31
50
|
return parsed > 0 ? parsed : fallback;
|
|
32
51
|
}
|
|
33
52
|
|
|
53
|
+
function buildCanonicalHumanInboundSource(rawValue) {
|
|
54
|
+
const value = safeObject(rawValue);
|
|
55
|
+
const kind = String(value.kind || "").trim().toLowerCase();
|
|
56
|
+
const senderIsBotRaw = value.sender_is_bot
|
|
57
|
+
?? value.senderIsBot
|
|
58
|
+
?? value.fromIsBot
|
|
59
|
+
?? value.from_is_bot;
|
|
60
|
+
const senderIsBot = senderIsBotRaw === true
|
|
61
|
+
|| senderIsBotRaw === "true"
|
|
62
|
+
|| senderIsBotRaw === 1
|
|
63
|
+
|| senderIsBotRaw === "1"
|
|
64
|
+
|| kind === "bot_reply";
|
|
65
|
+
if (senderIsBot) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
const chatID = String(
|
|
69
|
+
value.chat_id
|
|
70
|
+
|| value.chatID
|
|
71
|
+
|| value.chatId
|
|
72
|
+
|| "",
|
|
73
|
+
).trim();
|
|
74
|
+
const senderID = String(
|
|
75
|
+
value.sender_id
|
|
76
|
+
|| value.senderID
|
|
77
|
+
|| value.fromID
|
|
78
|
+
|| value.from_id
|
|
79
|
+
|| value.user_id
|
|
80
|
+
|| value.userID
|
|
81
|
+
|| value.sender_username
|
|
82
|
+
|| value.senderUsername
|
|
83
|
+
|| value.fromUsername
|
|
84
|
+
|| value.from_username
|
|
85
|
+
|| value.username
|
|
86
|
+
|| "",
|
|
87
|
+
).trim().toLowerCase();
|
|
88
|
+
const occurredAt = String(
|
|
89
|
+
value.occurred_at
|
|
90
|
+
|| value.occurredAt
|
|
91
|
+
|| "",
|
|
92
|
+
).trim();
|
|
93
|
+
const body = normalizeBodyForCanonicalKey(
|
|
94
|
+
value.body
|
|
95
|
+
|| value.text
|
|
96
|
+
|| "",
|
|
97
|
+
);
|
|
98
|
+
if (!chatID || !senderID || !occurredAt || !body) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
const messageThreadID = intFromRawAllowZero(
|
|
102
|
+
value.message_thread_id
|
|
103
|
+
|| value.messageThreadID,
|
|
104
|
+
0,
|
|
105
|
+
);
|
|
106
|
+
const replyToMessageID = intFromRawAllowZero(
|
|
107
|
+
value.reply_to_message_id
|
|
108
|
+
|| value.replyToMessageID,
|
|
109
|
+
0,
|
|
110
|
+
);
|
|
111
|
+
return {
|
|
112
|
+
chatID,
|
|
113
|
+
senderID,
|
|
114
|
+
occurredAt: normalizeOccurredAtForCanonicalKey(occurredAt),
|
|
115
|
+
body,
|
|
116
|
+
messageThreadID: messageThreadID > 0 ? messageThreadID : 0,
|
|
117
|
+
replyToMessageID: replyToMessageID > 0 ? replyToMessageID : 0,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function buildCanonicalHumanInboundKey(rawValue) {
|
|
122
|
+
const value = safeObject(rawValue);
|
|
123
|
+
const explicitKey = String(
|
|
124
|
+
value.canonical_human_message_key
|
|
125
|
+
|| value.canonicalHumanMessageKey
|
|
126
|
+
|| "",
|
|
127
|
+
).trim();
|
|
128
|
+
if (explicitKey) {
|
|
129
|
+
return explicitKey;
|
|
130
|
+
}
|
|
131
|
+
const source = buildCanonicalHumanInboundSource(value);
|
|
132
|
+
if (!source) {
|
|
133
|
+
return "";
|
|
134
|
+
}
|
|
135
|
+
return createHash("sha1")
|
|
136
|
+
.update(JSON.stringify(source))
|
|
137
|
+
.digest("hex");
|
|
138
|
+
}
|
|
139
|
+
|
|
34
140
|
export function normalizeTelegramMessageEnvelope(rawEnvelope) {
|
|
35
141
|
const envelope = safeObject(rawEnvelope);
|
|
36
142
|
const chatID = String(
|
|
@@ -61,6 +167,13 @@ export function normalizeTelegramMessageEnvelope(rawEnvelope) {
|
|
|
61
167
|
envelope.sender,
|
|
62
168
|
senderUsername ? `@${senderUsername}` : "",
|
|
63
169
|
]);
|
|
170
|
+
const senderID = String(
|
|
171
|
+
envelope.sender_id
|
|
172
|
+
|| envelope.senderID
|
|
173
|
+
|| envelope.fromID
|
|
174
|
+
|| envelope.from_id
|
|
175
|
+
|| "",
|
|
176
|
+
).trim();
|
|
64
177
|
const rawSenderIsBot = envelope.sender_is_bot ?? envelope.senderIsBot;
|
|
65
178
|
const senderIsBot = rawSenderIsBot === true
|
|
66
179
|
|| rawSenderIsBot === "true"
|
|
@@ -68,6 +181,15 @@ export function normalizeTelegramMessageEnvelope(rawEnvelope) {
|
|
|
68
181
|
|| rawSenderIsBot === "1"
|
|
69
182
|
|| kind === "bot_reply";
|
|
70
183
|
const body = String(envelope.body || envelope.text || "").trim();
|
|
184
|
+
const occurredAt = String(
|
|
185
|
+
envelope.occurred_at
|
|
186
|
+
|| envelope.occurredAt
|
|
187
|
+
|| "",
|
|
188
|
+
).trim();
|
|
189
|
+
const mentionUsernames = uniqueNormalizedSelectors(
|
|
190
|
+
envelope.mention_usernames
|
|
191
|
+
|| envelope.mentionUsernames,
|
|
192
|
+
);
|
|
71
193
|
const sourceOrigin = String(
|
|
72
194
|
envelope.source_origin
|
|
73
195
|
|| envelope.sourceOrigin
|
|
@@ -90,14 +212,29 @@ export function normalizeTelegramMessageEnvelope(rawEnvelope) {
|
|
|
90
212
|
&& !(replyToMessageID > 0)
|
|
91
213
|
&& !kind
|
|
92
214
|
&& !sender
|
|
215
|
+
&& !senderID
|
|
93
216
|
&& !senderUsername
|
|
94
217
|
&& !body
|
|
218
|
+
&& !occurredAt
|
|
219
|
+
&& mentionUsernames.length === 0
|
|
95
220
|
&& !sourceOrigin
|
|
96
221
|
&& !sourceRouteKey
|
|
97
222
|
&& !sourceBotUsername
|
|
98
223
|
) {
|
|
99
224
|
return {};
|
|
100
225
|
}
|
|
226
|
+
const canonicalHumanMessageKey = buildCanonicalHumanInboundKey({
|
|
227
|
+
chat_id: chatID,
|
|
228
|
+
message_id: messageID,
|
|
229
|
+
message_thread_id: messageThreadID,
|
|
230
|
+
reply_to_message_id: replyToMessageID,
|
|
231
|
+
kind,
|
|
232
|
+
sender_id: senderID,
|
|
233
|
+
sender_username: senderUsername,
|
|
234
|
+
sender_is_bot: senderIsBot === true,
|
|
235
|
+
body,
|
|
236
|
+
occurred_at: occurredAt,
|
|
237
|
+
});
|
|
101
238
|
return {
|
|
102
239
|
...(chatID ? { chat_id: chatID } : {}),
|
|
103
240
|
...(messageID > 0 ? { message_id: messageID } : {}),
|
|
@@ -105,9 +242,13 @@ export function normalizeTelegramMessageEnvelope(rawEnvelope) {
|
|
|
105
242
|
...(replyToMessageID > 0 ? { reply_to_message_id: replyToMessageID } : {}),
|
|
106
243
|
...(kind ? { kind } : {}),
|
|
107
244
|
...(sender ? { sender } : {}),
|
|
245
|
+
...(senderID ? { sender_id: senderID } : {}),
|
|
108
246
|
...(senderUsername ? { sender_username: senderUsername } : {}),
|
|
109
247
|
sender_is_bot: senderIsBot === true,
|
|
110
248
|
...(body ? { body } : {}),
|
|
249
|
+
...(occurredAt ? { occurred_at: occurredAt } : {}),
|
|
250
|
+
...(mentionUsernames.length > 0 ? { mention_usernames: mentionUsernames } : {}),
|
|
251
|
+
...(canonicalHumanMessageKey ? { canonical_human_message_key: canonicalHumanMessageKey } : {}),
|
|
111
252
|
...(sourceOrigin ? { source_origin: sourceOrigin } : {}),
|
|
112
253
|
...(sourceRouteKey ? { source_route_key: sourceRouteKey } : {}),
|
|
113
254
|
...(sourceBotUsername ? { source_bot_username: sourceBotUsername } : {}),
|
|
@@ -126,6 +267,10 @@ export function buildTelegramMessageEnvelopeFromParsedArchive(parsedArchiveRaw,
|
|
|
126
267
|
message_thread_id: overrides.message_thread_id ?? parsedArchive.messageThreadID,
|
|
127
268
|
reply_to_message_id: overrides.reply_to_message_id ?? parsedArchive.replyToMessageID,
|
|
128
269
|
kind: firstNonEmptyString([overrides.kind, parsedArchive.kind]),
|
|
270
|
+
sender_id: firstNonEmptyString([
|
|
271
|
+
overrides.sender_id,
|
|
272
|
+
parsedArchive.senderID,
|
|
273
|
+
]),
|
|
129
274
|
sender: firstNonEmptyString([
|
|
130
275
|
overrides.sender,
|
|
131
276
|
parsedArchive.sender,
|
|
@@ -140,6 +285,17 @@ export function buildTelegramMessageEnvelopeFromParsedArchive(parsedArchiveRaw,
|
|
|
140
285
|
]),
|
|
141
286
|
sender_is_bot: overrides.sender_is_bot ?? parsedArchive.senderIsBot,
|
|
142
287
|
body: firstNonEmptyString([overrides.body, parsedArchive.body]),
|
|
288
|
+
occurred_at: firstNonEmptyString([overrides.occurred_at, parsedArchive.occurredAt]),
|
|
289
|
+
mention_usernames: ensureArray(
|
|
290
|
+
overrides.mention_usernames
|
|
291
|
+
|| overrides.mentionUsernames
|
|
292
|
+
|| parsedArchive.mentionUsernames,
|
|
293
|
+
),
|
|
294
|
+
canonical_human_message_key: firstNonEmptyString([
|
|
295
|
+
overrides.canonical_human_message_key,
|
|
296
|
+
overrides.canonicalHumanMessageKey,
|
|
297
|
+
parsedArchive.canonicalHumanMessageKey,
|
|
298
|
+
]),
|
|
143
299
|
source_origin: firstNonEmptyString([
|
|
144
300
|
overrides.source_origin,
|
|
145
301
|
parsedArchive.sourceOrigin,
|
|
@@ -451,6 +607,10 @@ export function buildProcessableArchiveLogicalKey(recordRaw) {
|
|
|
451
607
|
if (!isRunnerProcessableArchiveKind(kind)) {
|
|
452
608
|
return "";
|
|
453
609
|
}
|
|
610
|
+
const canonicalHumanKey = buildCanonicalHumanInboundKey(parsed);
|
|
611
|
+
if (canonicalHumanKey) {
|
|
612
|
+
return `human:${canonicalHumanKey}`;
|
|
613
|
+
}
|
|
454
614
|
const chatID = firstNonEmptyString([parsed.chatID, parsed.chatId]);
|
|
455
615
|
const messageID = intFromRawAllowZero(parsed.messageID, 0);
|
|
456
616
|
if (!chatID || !(messageID > 0)) {
|
|
@@ -16,6 +16,10 @@ function ensureArray(value) {
|
|
|
16
16
|
return Array.isArray(value) ? value : [];
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
function normalizeMentionSelector(rawValue) {
|
|
20
|
+
return String(rawValue || "").trim().replace(/^@+/, "").toLowerCase();
|
|
21
|
+
}
|
|
22
|
+
|
|
19
23
|
function intFromRawAllowZero(raw, fallback = 0) {
|
|
20
24
|
if (raw === null || raw === undefined || raw === "") {
|
|
21
25
|
return fallback;
|
|
@@ -48,6 +52,45 @@ function buildRunnerContinuationContractTriggerDecision(triggerDecision) {
|
|
|
48
52
|
};
|
|
49
53
|
}
|
|
50
54
|
|
|
55
|
+
function isRunnerBotReplyContinuationAuthorizedForCurrentBot({
|
|
56
|
+
selectedRecord,
|
|
57
|
+
persistedRequest = null,
|
|
58
|
+
currentBotSelector = "",
|
|
59
|
+
}) {
|
|
60
|
+
const normalizedCurrentBotSelector = normalizeMentionSelector(currentBotSelector);
|
|
61
|
+
if (!normalizedCurrentBotSelector) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
const parsed = safeObject(selectedRecord?.parsedArchive);
|
|
65
|
+
const normalizedSenderSelectors = ensureArray([
|
|
66
|
+
parsed.botUsername,
|
|
67
|
+
parsed.senderUsername,
|
|
68
|
+
parsed.sender,
|
|
69
|
+
])
|
|
70
|
+
.map((value) => normalizeMentionSelector(value))
|
|
71
|
+
.filter(Boolean);
|
|
72
|
+
if (normalizedSenderSelectors.includes(normalizedCurrentBotSelector)) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
const explicitReplyTargets = ensureArray([
|
|
76
|
+
...(Array.isArray(parsed.mentionUsernames) ? parsed.mentionUsernames : []),
|
|
77
|
+
parsed.replyToBotUsername,
|
|
78
|
+
parsed.targetBotUsername,
|
|
79
|
+
parsed.assignBotUsername,
|
|
80
|
+
parsed.nextResponderBotUsername,
|
|
81
|
+
])
|
|
82
|
+
.map((value) => normalizeMentionSelector(value))
|
|
83
|
+
.filter(Boolean);
|
|
84
|
+
if (explicitReplyTargets.includes(normalizedCurrentBotSelector)) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
const request = safeObject(persistedRequest);
|
|
88
|
+
const nextExpectedResponders = ensureArray(request.next_expected_responders)
|
|
89
|
+
.map((value) => normalizeMentionSelector(value))
|
|
90
|
+
.filter(Boolean);
|
|
91
|
+
return nextExpectedResponders.includes(normalizedCurrentBotSelector);
|
|
92
|
+
}
|
|
93
|
+
|
|
51
94
|
export async function resolveRunnerPrecomputedResponderAdjudication({
|
|
52
95
|
selectedRecord,
|
|
53
96
|
pendingOrdered,
|
|
@@ -189,6 +232,11 @@ export async function resolveRunnerPrecomputedBotReplyAuthorityContext({
|
|
|
189
232
|
persistedRequest: resolveRunnerContinuationLinkedRequest(normalizedRequestClaim),
|
|
190
233
|
triggerDecision,
|
|
191
234
|
});
|
|
235
|
+
const continuationAuthorizedForCurrentBot = isRunnerBotReplyContinuationAuthorizedForCurrentBot({
|
|
236
|
+
selectedRecord,
|
|
237
|
+
persistedRequest: resolveRunnerContinuationLinkedRequest(normalizedRequestClaim),
|
|
238
|
+
currentBotSelector,
|
|
239
|
+
});
|
|
192
240
|
const currentBotSelected = ensureArray(continuationAdjudication?.selected_bot_usernames)
|
|
193
241
|
.map((value) => String(value || "").trim().replace(/^@+/, "").toLowerCase())
|
|
194
242
|
.includes(currentBotSelector);
|
|
@@ -204,6 +252,18 @@ export async function resolveRunnerPrecomputedBotReplyAuthorityContext({
|
|
|
204
252
|
sharedHumanIntentContext: null,
|
|
205
253
|
};
|
|
206
254
|
}
|
|
255
|
+
if (!continuationAuthorizedForCurrentBot) {
|
|
256
|
+
return {
|
|
257
|
+
shouldSkip: true,
|
|
258
|
+
requestless: false,
|
|
259
|
+
skipAction: "adjudication_skipped",
|
|
260
|
+
skipReason: "bot_reply_not_explicitly_handed_off",
|
|
261
|
+
skipTrigger: "request_contract",
|
|
262
|
+
skipRecordPatch: {},
|
|
263
|
+
adjudication: continuationAdjudication,
|
|
264
|
+
sharedHumanIntentContext: null,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
207
267
|
return {
|
|
208
268
|
shouldSkip: false,
|
|
209
269
|
requestless: false,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
buildCanonicalHumanInboundKey,
|
|
2
3
|
buildRunnerContextWindow,
|
|
3
4
|
compareArchiveCommentRecords,
|
|
4
5
|
dedupeProcessableArchiveComments,
|
|
@@ -103,6 +104,10 @@ function resolveRunnerLocalInboundReceiptTargetSelector(receiptRaw) {
|
|
|
103
104
|
|
|
104
105
|
function buildRunnerArchiveSourceMessageKey(recordRaw) {
|
|
105
106
|
const parsed = safeObject(safeObject(recordRaw).parsedArchive);
|
|
107
|
+
const canonicalHumanKey = buildCanonicalHumanInboundKey(parsed);
|
|
108
|
+
if (canonicalHumanKey) {
|
|
109
|
+
return `human:${canonicalHumanKey}`;
|
|
110
|
+
}
|
|
106
111
|
const chatID = String(parsed.chatID || parsed.chatId || "").trim();
|
|
107
112
|
const messageID = intFromRawAllowZero(parsed.messageID || parsed.messageId, 0);
|
|
108
113
|
if (!chatID || !(messageID > 0)) {
|
|
@@ -113,6 +118,21 @@ function buildRunnerArchiveSourceMessageKey(recordRaw) {
|
|
|
113
118
|
|
|
114
119
|
function buildRunnerLocalInboundReceiptKey(receiptRaw) {
|
|
115
120
|
const receipt = safeObject(receiptRaw);
|
|
121
|
+
const canonicalHumanKey = buildCanonicalHumanInboundKey({
|
|
122
|
+
chat_id: receipt.chat_id,
|
|
123
|
+
message_id: receipt.message_id,
|
|
124
|
+
message_thread_id: receipt.message_thread_id,
|
|
125
|
+
reply_to_message_id: receipt.reply_to_message_id,
|
|
126
|
+
kind: receipt.kind,
|
|
127
|
+
sender_id: receipt.sender_id,
|
|
128
|
+
sender_username: receipt.sender_username,
|
|
129
|
+
sender_is_bot: receipt.sender_is_bot === true,
|
|
130
|
+
body: receipt.body,
|
|
131
|
+
occurred_at: receipt.occurred_at,
|
|
132
|
+
});
|
|
133
|
+
if (canonicalHumanKey) {
|
|
134
|
+
return `human:${canonicalHumanKey}`;
|
|
135
|
+
}
|
|
116
136
|
const chatID = String(receipt.chat_id || receipt.chatID || "").trim();
|
|
117
137
|
const messageID = intFromRawAllowZero(receipt.message_id || receipt.messageID, 0);
|
|
118
138
|
if (!chatID || !(messageID > 0)) {
|
package/lib/runner-recovery.mjs
CHANGED
|
@@ -431,6 +431,7 @@ export function peekRunnerContinuationRequestForBotReply({
|
|
|
431
431
|
export function recoverRunnerContinuationRequestForBotReply({
|
|
432
432
|
normalizedRoute,
|
|
433
433
|
continuationPreview,
|
|
434
|
+
persist = true,
|
|
434
435
|
deps = {},
|
|
435
436
|
}) {
|
|
436
437
|
const upsertRunnerRequest = requireDependency(deps, "upsertRunnerRequest");
|
|
@@ -506,6 +507,18 @@ export function recoverRunnerContinuationRequestForBotReply({
|
|
|
506
507
|
|| "",
|
|
507
508
|
).trim().toLowerCase(),
|
|
508
509
|
};
|
|
510
|
+
if (persist !== true) {
|
|
511
|
+
return {
|
|
512
|
+
ok: true,
|
|
513
|
+
linkedRequestKey: fallbackRequestKey,
|
|
514
|
+
linkedRequest: seedRequest,
|
|
515
|
+
currentState,
|
|
516
|
+
conversationID: String(preview.conversationID || "").trim(),
|
|
517
|
+
commentKind: String(preview.commentKind || "").trim().toLowerCase(),
|
|
518
|
+
linkResolutionKind: "recovered_request_link",
|
|
519
|
+
linkRecovered: true,
|
|
520
|
+
};
|
|
521
|
+
}
|
|
509
522
|
const seededRequest = upsertRunnerRequest(currentState, fallbackRequestKey, seedRequest);
|
|
510
523
|
currentState.requests = seededRequest.requests;
|
|
511
524
|
saveBotRunnerState({
|
|
@@ -531,6 +544,7 @@ export function resolveRunnerContinuationRequestForBotReply({
|
|
|
531
544
|
normalizedRoute,
|
|
532
545
|
routeKey,
|
|
533
546
|
selectedRecord,
|
|
547
|
+
persist = true,
|
|
534
548
|
deps = {},
|
|
535
549
|
}) {
|
|
536
550
|
const upsertRunnerConsumedComment = requireDependency(deps, "upsertRunnerConsumedComment");
|
|
@@ -547,12 +561,16 @@ export function resolveRunnerContinuationRequestForBotReply({
|
|
|
547
561
|
continuation = recoverRunnerContinuationRequestForBotReply({
|
|
548
562
|
normalizedRoute,
|
|
549
563
|
continuationPreview: continuation,
|
|
564
|
+
persist,
|
|
550
565
|
deps,
|
|
551
566
|
});
|
|
552
567
|
}
|
|
553
568
|
if (!continuation.ok) {
|
|
554
569
|
return continuation;
|
|
555
570
|
}
|
|
571
|
+
if (persist !== true) {
|
|
572
|
+
return continuation;
|
|
573
|
+
}
|
|
556
574
|
const {
|
|
557
575
|
currentState,
|
|
558
576
|
linkedRequest,
|
|
@@ -609,6 +627,7 @@ export function prepareRunnerBotReplyContinuationContext({
|
|
|
609
627
|
normalizedRoute,
|
|
610
628
|
routeKey,
|
|
611
629
|
selectedRecord,
|
|
630
|
+
persist: false,
|
|
612
631
|
deps,
|
|
613
632
|
})
|
|
614
633
|
: continuationPreview;
|
package/lib/runner-runtime.mjs
CHANGED
|
@@ -539,10 +539,12 @@ function buildRunnerLocalInboundEnvelopeFromReceipt(rawReceipt) {
|
|
|
539
539
|
message_thread_id: receipt.message_thread_id,
|
|
540
540
|
reply_to_message_id: receipt.reply_to_message_id,
|
|
541
541
|
kind: receipt.kind,
|
|
542
|
+
sender_id: receipt.sender_id,
|
|
542
543
|
sender: receipt.sender,
|
|
543
544
|
sender_username: receipt.sender_username,
|
|
544
545
|
sender_is_bot: receipt.sender_is_bot === true,
|
|
545
546
|
body: receipt.body,
|
|
547
|
+
occurred_at: receipt.occurred_at,
|
|
546
548
|
source_origin: receipt.receipt_origin,
|
|
547
549
|
source_route_key: receipt.receipt_route_key,
|
|
548
550
|
source_bot_username: receipt.receipt_bot_username,
|
|
@@ -670,16 +672,13 @@ function buildRunnerRecentLocalInboundReceipts(routeStateRaw, localInboundArtifa
|
|
|
670
672
|
const RUNNER_INBOUND_ARCHIVE_RESERVATION_TTL_MS = 10 * 60 * 1000;
|
|
671
673
|
const runnerInboundArchiveReservations = new Map();
|
|
672
674
|
|
|
673
|
-
function buildRunnerInboundArchiveReservationKey(threadID,
|
|
675
|
+
function buildRunnerInboundArchiveReservationKey(threadID, archiveMessageKey = "") {
|
|
674
676
|
const normalizedThreadID = String(threadID || "").trim();
|
|
675
|
-
const
|
|
676
|
-
|
|
677
|
-
const normalizedSourceBotUsername = normalizeMentionSelector(sourceBotUsername);
|
|
678
|
-
if (!normalizedThreadID || !normalizedChatID || !(normalizedMessageID > 0)) {
|
|
677
|
+
const normalizedArchiveMessageKey = String(archiveMessageKey || "").trim();
|
|
678
|
+
if (!normalizedThreadID || !normalizedArchiveMessageKey) {
|
|
679
679
|
return "";
|
|
680
680
|
}
|
|
681
|
-
|
|
682
|
-
return normalizedSourceBotUsername ? `${baseKey}::${normalizedSourceBotUsername}` : baseKey;
|
|
681
|
+
return `${normalizedThreadID}::${normalizedArchiveMessageKey}`;
|
|
683
682
|
}
|
|
684
683
|
|
|
685
684
|
function cleanupRunnerInboundArchiveReservations(nowMs = Date.now()) {
|
|
@@ -690,8 +689,8 @@ function cleanupRunnerInboundArchiveReservations(nowMs = Date.now()) {
|
|
|
690
689
|
}
|
|
691
690
|
}
|
|
692
691
|
|
|
693
|
-
function reserveRunnerInboundArchiveMessage(threadID,
|
|
694
|
-
const reservationKey = buildRunnerInboundArchiveReservationKey(threadID,
|
|
692
|
+
function reserveRunnerInboundArchiveMessage(threadID, archiveMessageKey = "") {
|
|
693
|
+
const reservationKey = buildRunnerInboundArchiveReservationKey(threadID, archiveMessageKey);
|
|
695
694
|
if (!reservationKey) {
|
|
696
695
|
return {
|
|
697
696
|
ok: false,
|
|
@@ -821,7 +820,7 @@ async function loadRunnerExistingInboundArchiveKeys({
|
|
|
821
820
|
.map((record) => normalizeArchiveCommentRecord(record, parseArchivedChatComment))
|
|
822
821
|
.map((record) => record.parsedArchive)
|
|
823
822
|
.filter((parsed) => parsed && isInboundArchiveKind(parsed.kind) && parsed.chatID)
|
|
824
|
-
.map((parsed) => buildArchivedInboundMessageKey(parsed
|
|
823
|
+
.map((parsed) => buildArchivedInboundMessageKey(parsed)),
|
|
825
824
|
);
|
|
826
825
|
}
|
|
827
826
|
|
|
@@ -884,16 +883,27 @@ async function archiveRunnerTelegramInboundUpdates({
|
|
|
884
883
|
route,
|
|
885
884
|
bot,
|
|
886
885
|
});
|
|
887
|
-
const dedupeKey = buildArchivedInboundMessageKey(
|
|
886
|
+
const dedupeKey = buildArchivedInboundMessageKey({
|
|
887
|
+
chatID: update.chatID,
|
|
888
|
+
messageID: update.messageID,
|
|
889
|
+
messageThreadID: update.messageThreadID,
|
|
890
|
+
kind: update.fromIsBot ? "bot_reply" : "telegram_message",
|
|
891
|
+
senderID: update.fromID,
|
|
892
|
+
sender: update.fromName,
|
|
893
|
+
senderUsername: update.fromUsername,
|
|
894
|
+
senderIsBot: update.fromIsBot === true,
|
|
895
|
+
body: update.text,
|
|
896
|
+
occurredAt: update.occurredAt,
|
|
897
|
+
replyToMessageID: update.replyToMessageID,
|
|
898
|
+
sourceBotUsername: archiveSourceBotUsername,
|
|
899
|
+
});
|
|
888
900
|
if (boolFromRaw(archivePolicy.dedupeInbound, true) && existingKeys.has(dedupeKey)) {
|
|
889
901
|
continue;
|
|
890
902
|
}
|
|
891
903
|
const reservation = boolFromRaw(archivePolicy.dedupeInbound, true)
|
|
892
904
|
? reserveRunnerInboundArchiveMessage(
|
|
893
905
|
archiveThread?.threadID,
|
|
894
|
-
|
|
895
|
-
update.messageID,
|
|
896
|
-
archiveSourceBotUsername,
|
|
906
|
+
dedupeKey,
|
|
897
907
|
)
|
|
898
908
|
: { ok: true, reservationKey: "" };
|
|
899
909
|
if (!reservation.ok) {
|
|
@@ -299,6 +299,7 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
299
299
|
const mergeServerRunnerRequestLedgerIntoLocalState = requireDependency(deps, "mergeServerRunnerRequestLedgerIntoLocalState");
|
|
300
300
|
const buildRunnerStatusQueryLookup = requireDependency(deps, "buildRunnerStatusQueryLookup");
|
|
301
301
|
const claimRunnerRequestForHumanComment = requireDependency(deps, "claimRunnerRequestForHumanComment");
|
|
302
|
+
const buildArchivedInboundMessageKey = requireDependency(deps, "buildArchivedInboundMessageKey");
|
|
302
303
|
const markRunnerRequestLifecycle = requireDependency(deps, "markRunnerRequestLifecycle");
|
|
303
304
|
const resolveRunnerContinuationRequestForBotReply = requireDependency(deps, "resolveRunnerContinuationRequestForBotReply");
|
|
304
305
|
const prepareRunnerSelectedRecordRecoveryContext = requireDependency(deps, "prepareRunnerSelectedRecordRecoveryContext");
|
|
@@ -2180,17 +2181,142 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
2180
2181
|
const authoritativeSourceRequest = safeObject(
|
|
2181
2182
|
safeObject(loadBotRunnerState().requests)[authoritativeSourceClaim.requestKey],
|
|
2182
2183
|
);
|
|
2183
|
-
push(
|
|
2184
|
-
"runner_request_claim_preserves_authoritative_source_message_envelope",
|
|
2185
|
-
authoritativeSourceClaim.ok === true
|
|
2186
|
-
&& String(authoritativeSourceRequest.source_message_origin || "") === "local_telegram_inbound"
|
|
2187
|
-
&& String(authoritativeSourceRequest.source_message_route_key || "") === requestRouteKey
|
|
2188
|
-
&& String(authoritativeSourceRequest.source_message_bot_username || "") === "ryoai_bot"
|
|
2189
|
-
&& Number(safeObject(authoritativeSourceRequest.source_message_envelope).message_id || 0) === 503,
|
|
2190
|
-
`origin=${String(authoritativeSourceRequest.source_message_origin || "(none)")} route=${String(authoritativeSourceRequest.source_message_route_key || "(none)")} bot=${String(authoritativeSourceRequest.source_message_bot_username || "(none)")} message=${String(safeObject(authoritativeSourceRequest.source_message_envelope).message_id || "(none)")}`,
|
|
2191
|
-
);
|
|
2192
|
-
|
|
2193
|
-
const
|
|
2184
|
+
push(
|
|
2185
|
+
"runner_request_claim_preserves_authoritative_source_message_envelope",
|
|
2186
|
+
authoritativeSourceClaim.ok === true
|
|
2187
|
+
&& String(authoritativeSourceRequest.source_message_origin || "") === "local_telegram_inbound"
|
|
2188
|
+
&& String(authoritativeSourceRequest.source_message_route_key || "") === requestRouteKey
|
|
2189
|
+
&& String(authoritativeSourceRequest.source_message_bot_username || "") === "ryoai_bot"
|
|
2190
|
+
&& Number(safeObject(authoritativeSourceRequest.source_message_envelope).message_id || 0) === 503,
|
|
2191
|
+
`origin=${String(authoritativeSourceRequest.source_message_origin || "(none)")} route=${String(authoritativeSourceRequest.source_message_route_key || "(none)")} bot=${String(authoritativeSourceRequest.source_message_bot_username || "(none)")} message=${String(safeObject(authoritativeSourceRequest.source_message_envelope).message_id || "(none)")}`,
|
|
2192
|
+
);
|
|
2193
|
+
|
|
2194
|
+
const canonicalHumanArchiveKeyPrimary = buildArchivedInboundMessageKey({
|
|
2195
|
+
chatID: "-100123",
|
|
2196
|
+
messageID: 1189,
|
|
2197
|
+
messageThreadID: 0,
|
|
2198
|
+
kind: "telegram_message",
|
|
2199
|
+
senderID: "7001",
|
|
2200
|
+
senderIsBot: false,
|
|
2201
|
+
occurredAt: "2026-04-01T06:00:00.000Z",
|
|
2202
|
+
body: "@RyoAI_bot @RyoAI2_bot @RyoAI3_bot 같이 논의 해죠",
|
|
2203
|
+
sourceBotUsername: "ryoai_bot",
|
|
2204
|
+
});
|
|
2205
|
+
const canonicalHumanArchiveKeyPeer = buildArchivedInboundMessageKey({
|
|
2206
|
+
chatID: "-100123",
|
|
2207
|
+
messageID: 294,
|
|
2208
|
+
messageThreadID: 0,
|
|
2209
|
+
kind: "telegram_message",
|
|
2210
|
+
senderID: "7001",
|
|
2211
|
+
senderIsBot: false,
|
|
2212
|
+
occurredAt: "2026-04-01T06:00:00.000Z",
|
|
2213
|
+
body: "@RyoAI_bot @RyoAI2_bot @RyoAI3_bot 같이 논의 해죠",
|
|
2214
|
+
sourceBotUsername: "ryoai3_bot",
|
|
2215
|
+
});
|
|
2216
|
+
push(
|
|
2217
|
+
"runner_human_inbound_archive_identity_is_canonical_across_routes",
|
|
2218
|
+
canonicalHumanArchiveKeyPrimary === canonicalHumanArchiveKeyPeer
|
|
2219
|
+
&& canonicalHumanArchiveKeyPrimary.startsWith("human:"),
|
|
2220
|
+
`primary=${canonicalHumanArchiveKeyPrimary} peer=${canonicalHumanArchiveKeyPeer}`,
|
|
2221
|
+
);
|
|
2222
|
+
|
|
2223
|
+
const sharedHumanRouteRyoai1 = normalizeRunnerRoute({
|
|
2224
|
+
...requestRoute,
|
|
2225
|
+
name: "telegram-monitor-request-ledger-shared-human-ryoai1",
|
|
2226
|
+
});
|
|
2227
|
+
const sharedHumanRouteRyoai3 = normalizeRunnerRoute({
|
|
2228
|
+
...requestRoute,
|
|
2229
|
+
name: "telegram-monitor-request-ledger-shared-human-ryoai3",
|
|
2230
|
+
});
|
|
2231
|
+
const sharedHumanRouteRyoai1Key = runnerRouteKey(sharedHumanRouteRyoai1);
|
|
2232
|
+
const sharedHumanRouteRyoai3Key = runnerRouteKey(sharedHumanRouteRyoai3);
|
|
2233
|
+
const sharedHumanBody = "@RyoAI_bot @RyoAI2_bot @RyoAI3_bot 같이 논의 해죠";
|
|
2234
|
+
const sharedHumanRecordPrimary = {
|
|
2235
|
+
id: "comment-request-shared-human-1",
|
|
2236
|
+
createdAt: "2026-04-01T06:00:00.000Z",
|
|
2237
|
+
updatedAt: "2026-04-01T06:00:00.000Z",
|
|
2238
|
+
parsedArchive: {
|
|
2239
|
+
kind: "telegram_message",
|
|
2240
|
+
chatID: "-100123",
|
|
2241
|
+
chatType: "supergroup",
|
|
2242
|
+
body: sharedHumanBody,
|
|
2243
|
+
messageID: 1189,
|
|
2244
|
+
senderID: "7001",
|
|
2245
|
+
senderIsBot: false,
|
|
2246
|
+
occurredAt: "2026-04-01T06:00:00.000Z",
|
|
2247
|
+
mentionUsernames: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
2248
|
+
},
|
|
2249
|
+
};
|
|
2250
|
+
const sharedHumanRecordPeer = {
|
|
2251
|
+
id: "comment-request-shared-human-2",
|
|
2252
|
+
createdAt: "2026-04-01T06:00:00.000Z",
|
|
2253
|
+
updatedAt: "2026-04-01T06:00:00.000Z",
|
|
2254
|
+
parsedArchive: {
|
|
2255
|
+
kind: "telegram_message",
|
|
2256
|
+
chatID: "-100123",
|
|
2257
|
+
chatType: "supergroup",
|
|
2258
|
+
body: sharedHumanBody,
|
|
2259
|
+
messageID: 294,
|
|
2260
|
+
senderID: "7001",
|
|
2261
|
+
senderIsBot: false,
|
|
2262
|
+
occurredAt: "2026-04-01T06:00:00.000Z",
|
|
2263
|
+
mentionUsernames: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
2264
|
+
},
|
|
2265
|
+
};
|
|
2266
|
+
const sharedHumanClaimPrimary = await claimRunnerRequestForHumanComment({
|
|
2267
|
+
normalizedRoute: sharedHumanRouteRyoai1,
|
|
2268
|
+
routeKey: sharedHumanRouteRyoai1Key,
|
|
2269
|
+
selectedRecord: sharedHumanRecordPrimary,
|
|
2270
|
+
selectedBotUsernames: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
2271
|
+
normalizedIntent: "discussion_request",
|
|
2272
|
+
authoritativeSourceMessageEnvelope: {
|
|
2273
|
+
chat_id: "-100123",
|
|
2274
|
+
message_id: 1189,
|
|
2275
|
+
sender_id: "7001",
|
|
2276
|
+
sender_is_bot: false,
|
|
2277
|
+
occurred_at: "2026-04-01T06:00:00.000Z",
|
|
2278
|
+
body: sharedHumanBody,
|
|
2279
|
+
source_origin: "local_telegram_inbound",
|
|
2280
|
+
source_route_key: sharedHumanRouteRyoai1Key,
|
|
2281
|
+
source_bot_username: "ryoai_bot",
|
|
2282
|
+
},
|
|
2283
|
+
});
|
|
2284
|
+
const sharedHumanClaimPeer = await claimRunnerRequestForHumanComment({
|
|
2285
|
+
normalizedRoute: sharedHumanRouteRyoai3,
|
|
2286
|
+
routeKey: sharedHumanRouteRyoai3Key,
|
|
2287
|
+
selectedRecord: sharedHumanRecordPeer,
|
|
2288
|
+
selectedBotUsernames: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
2289
|
+
normalizedIntent: "discussion_request",
|
|
2290
|
+
authoritativeSourceMessageEnvelope: {
|
|
2291
|
+
chat_id: "-100123",
|
|
2292
|
+
message_id: 294,
|
|
2293
|
+
sender_id: "7001",
|
|
2294
|
+
sender_is_bot: false,
|
|
2295
|
+
occurred_at: "2026-04-01T06:00:00.000Z",
|
|
2296
|
+
body: sharedHumanBody,
|
|
2297
|
+
source_origin: "local_telegram_inbound",
|
|
2298
|
+
source_route_key: sharedHumanRouteRyoai3Key,
|
|
2299
|
+
source_bot_username: "ryoai3_bot",
|
|
2300
|
+
},
|
|
2301
|
+
});
|
|
2302
|
+
const sharedHumanState = loadBotRunnerState();
|
|
2303
|
+
const sharedHumanRequestCount = Object.values(safeObject(sharedHumanState.requests))
|
|
2304
|
+
.filter((entryRaw) => {
|
|
2305
|
+
const entry = safeObject(entryRaw);
|
|
2306
|
+
return String(entry.chat_id || "") === "-100123"
|
|
2307
|
+
&& String(entry.source_message_body || "") === sharedHumanBody;
|
|
2308
|
+
})
|
|
2309
|
+
.length;
|
|
2310
|
+
push(
|
|
2311
|
+
"runner_human_opening_request_identity_is_canonical_across_routes",
|
|
2312
|
+
sharedHumanClaimPrimary.ok === true
|
|
2313
|
+
&& (sharedHumanClaimPeer.ok === true || String(sharedHumanClaimPeer.reason || "") === "request_already_claimed")
|
|
2314
|
+
&& String(sharedHumanClaimPrimary.requestKey || "") === String(sharedHumanClaimPeer.requestKey || "")
|
|
2315
|
+
&& sharedHumanRequestCount === 1,
|
|
2316
|
+
`primary=${String(sharedHumanClaimPrimary.requestKey || "(none)")} peer=${String(sharedHumanClaimPeer.requestKey || "(none)")} peer_reason=${String(sharedHumanClaimPeer.reason || "(none)")} count=${sharedHumanRequestCount}`,
|
|
2317
|
+
);
|
|
2318
|
+
|
|
2319
|
+
const rootTaskRecord = {
|
|
2194
2320
|
id: "comment-request-root-task-1",
|
|
2195
2321
|
createdAt: "2026-03-22T00:05:00.000Z",
|
|
2196
2322
|
updatedAt: "2026-03-22T00:05:00.000Z",
|
|
@@ -16340,11 +16466,82 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
16340
16466
|
&& !Object.prototype.hasOwnProperty.call(continuation, "request"),
|
|
16341
16467
|
`linked_key=${String(continuation.linkedRequestKey || "(none)")} has_request=${String(Object.prototype.hasOwnProperty.call(continuation, "request"))}`,
|
|
16342
16468
|
);
|
|
16343
|
-
|
|
16344
|
-
|
|
16345
|
-
|
|
16346
|
-
|
|
16347
|
-
|
|
16469
|
+
saveBotRunnerState({
|
|
16470
|
+
routes: {
|
|
16471
|
+
[provenanceRouteKey]: {
|
|
16472
|
+
conversation_sessions: {
|
|
16473
|
+
"conversation-provenance-seed": {
|
|
16474
|
+
status: "open",
|
|
16475
|
+
started_at: "2026-03-27T00:00:00.000Z",
|
|
16476
|
+
participants: ["ryoai_bot"],
|
|
16477
|
+
initial_responders: ["ryoai_bot"],
|
|
16478
|
+
allowed_responders: ["ryoai_bot"],
|
|
16479
|
+
intent_mode: "single_bot",
|
|
16480
|
+
allow_bot_to_bot: false,
|
|
16481
|
+
},
|
|
16482
|
+
},
|
|
16483
|
+
recent_local_inbound_receipts: {
|
|
16484
|
+
"-100123:779": {
|
|
16485
|
+
chat_id: "-100123",
|
|
16486
|
+
message_id: 779,
|
|
16487
|
+
receipt_origin: "local_telegram_inbound",
|
|
16488
|
+
receipt_route_key: provenanceRouteKey,
|
|
16489
|
+
receipt_bot_username: "ryoai_bot",
|
|
16490
|
+
source_origin: "local_telegram_inbound",
|
|
16491
|
+
source_route_key: provenanceRouteKey,
|
|
16492
|
+
source_bot_username: "ryoai_bot",
|
|
16493
|
+
body: "hello provenance",
|
|
16494
|
+
message_thread_id: 43,
|
|
16495
|
+
},
|
|
16496
|
+
},
|
|
16497
|
+
last_followup_source_message_envelope: {
|
|
16498
|
+
message_id: 779,
|
|
16499
|
+
message_thread_id: 43,
|
|
16500
|
+
body: "hello provenance",
|
|
16501
|
+
source_origin: "local_telegram_inbound",
|
|
16502
|
+
source_route_key: provenanceRouteKey,
|
|
16503
|
+
source_bot_username: "ryoai_bot",
|
|
16504
|
+
},
|
|
16505
|
+
},
|
|
16506
|
+
},
|
|
16507
|
+
sharedInboxes: {},
|
|
16508
|
+
excludedComments: {},
|
|
16509
|
+
requests: {},
|
|
16510
|
+
consumedComments: {},
|
|
16511
|
+
});
|
|
16512
|
+
const stateBeforePreviewOnlyContinuation = loadBotRunnerState();
|
|
16513
|
+
const previewOnlyRecoveryContext = prepareRunnerSelectedRecordRecoveryContext({
|
|
16514
|
+
normalizedRoute: provenanceRoute,
|
|
16515
|
+
routeKey: provenanceRouteKey,
|
|
16516
|
+
selectedRecord: {
|
|
16517
|
+
id: "bot-reply-preview-only-seed",
|
|
16518
|
+
parsedArchive: {
|
|
16519
|
+
kind: "bot_reply",
|
|
16520
|
+
chatID: "-100123",
|
|
16521
|
+
messageID: 881,
|
|
16522
|
+
senderIsBot: true,
|
|
16523
|
+
conversationID: "conversation-provenance-seed",
|
|
16524
|
+
botUsername: "@ryoai_bot",
|
|
16525
|
+
},
|
|
16526
|
+
},
|
|
16527
|
+
});
|
|
16528
|
+
const stateAfterPreviewOnlyContinuation = loadBotRunnerState();
|
|
16529
|
+
const previewRequestsBefore = Object.keys(normalizeBotRunnerRequests(stateBeforePreviewOnlyContinuation.requests)).length;
|
|
16530
|
+
const previewRequestsAfter = Object.keys(normalizeBotRunnerRequests(stateAfterPreviewOnlyContinuation.requests)).length;
|
|
16531
|
+
const previewConsumedBefore = Object.keys(safeObject(stateBeforePreviewOnlyContinuation.consumedComments || stateBeforePreviewOnlyContinuation.consumed_comments)).length;
|
|
16532
|
+
const previewConsumedAfter = Object.keys(safeObject(stateAfterPreviewOnlyContinuation.consumedComments || stateAfterPreviewOnlyContinuation.consumed_comments)).length;
|
|
16533
|
+
push(
|
|
16534
|
+
"runner_continuation_preview_does_not_write_request_or_consumed_state",
|
|
16535
|
+
safeObject(previewOnlyRecoveryContext.botReplyContinuationContext).continuationLinkRecoverable === true
|
|
16536
|
+
&& previewRequestsBefore === previewRequestsAfter
|
|
16537
|
+
&& previewConsumedBefore === previewConsumedAfter,
|
|
16538
|
+
`recoverable=${String(safeObject(previewOnlyRecoveryContext.botReplyContinuationContext).continuationLinkRecoverable)} requests=${String(previewRequestsBefore)}->${String(previewRequestsAfter)} consumed=${String(previewConsumedBefore)}->${String(previewConsumedAfter)}`,
|
|
16539
|
+
);
|
|
16540
|
+
} finally {
|
|
16541
|
+
process.env.HOME = previousHome;
|
|
16542
|
+
process.env.USERPROFILE = previousUserProfile;
|
|
16543
|
+
try {
|
|
16544
|
+
fs.rmSync(provenanceTempRoot, { recursive: true, force: true });
|
|
16348
16545
|
} catch {}
|
|
16349
16546
|
}
|
|
16350
16547
|
} catch (err) {
|
|
@@ -17447,6 +17644,7 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
17447
17644
|
linkedRequest: {
|
|
17448
17645
|
request_key: "req-1",
|
|
17449
17646
|
selected_bot_usernames: ["alpha_bot"],
|
|
17647
|
+
next_expected_responders: ["alpha_bot"],
|
|
17450
17648
|
},
|
|
17451
17649
|
},
|
|
17452
17650
|
},
|
|
@@ -17493,6 +17691,7 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
17493
17691
|
linkedRequest: {
|
|
17494
17692
|
request_key: "req-1",
|
|
17495
17693
|
selected_bot_usernames: ["alpha_bot"],
|
|
17694
|
+
next_expected_responders: ["alpha_bot"],
|
|
17496
17695
|
},
|
|
17497
17696
|
},
|
|
17498
17697
|
},
|
|
@@ -17529,6 +17728,69 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
17529
17728
|
push("runner_selected_record_execution_context_promotes_continuation_only_after_recovery", false, String(err?.message || err));
|
|
17530
17729
|
}
|
|
17531
17730
|
|
|
17731
|
+
try {
|
|
17732
|
+
const preparation = await resolveRunnerPrecomputedSelectedRecordExecutionContext({
|
|
17733
|
+
selectedRecord: {
|
|
17734
|
+
id: "comment-continuation-no-explicit-handoff",
|
|
17735
|
+
parsedArchive: {
|
|
17736
|
+
kind: "bot_reply",
|
|
17737
|
+
chatID: "-100123",
|
|
17738
|
+
chatType: "supergroup",
|
|
17739
|
+
messageID: 3504,
|
|
17740
|
+
body: "foreign bot follow up",
|
|
17741
|
+
sender: "other bot",
|
|
17742
|
+
senderIsBot: true,
|
|
17743
|
+
botUsername: "@other_bot",
|
|
17744
|
+
mentionUsernames: [],
|
|
17745
|
+
},
|
|
17746
|
+
},
|
|
17747
|
+
recoveryContext: {
|
|
17748
|
+
selectedRecordKind: "bot_reply",
|
|
17749
|
+
botReplyContinuationContext: {
|
|
17750
|
+
continuationLinkRecoverable: true,
|
|
17751
|
+
continuationLinkResolution: {
|
|
17752
|
+
ok: true,
|
|
17753
|
+
linkedRequestKey: "req-no-explicit-handoff",
|
|
17754
|
+
linkedRequest: {
|
|
17755
|
+
request_key: "req-no-explicit-handoff",
|
|
17756
|
+
selected_bot_usernames: ["alpha_bot"],
|
|
17757
|
+
next_expected_responders: [],
|
|
17758
|
+
},
|
|
17759
|
+
},
|
|
17760
|
+
},
|
|
17761
|
+
},
|
|
17762
|
+
normalizedRoute: {
|
|
17763
|
+
provider: "telegram",
|
|
17764
|
+
triggerPolicy: {
|
|
17765
|
+
replyToBotMessages: true,
|
|
17766
|
+
},
|
|
17767
|
+
},
|
|
17768
|
+
routeKey: "telegram-monitor-alpha::project::telegram::monitor::dest::actor",
|
|
17769
|
+
routeState: {},
|
|
17770
|
+
fallbackRouteState: {},
|
|
17771
|
+
bot: {
|
|
17772
|
+
username: "alpha_bot",
|
|
17773
|
+
name: "alpha_bot",
|
|
17774
|
+
},
|
|
17775
|
+
executionPlan: {},
|
|
17776
|
+
pendingOrdered: [],
|
|
17777
|
+
currentBotSelector: "alpha_bot",
|
|
17778
|
+
routingExecutionDeps: {
|
|
17779
|
+
managedConversationBots: [],
|
|
17780
|
+
},
|
|
17781
|
+
});
|
|
17782
|
+
push(
|
|
17783
|
+
"runner_selected_record_execution_context_requires_explicit_handoff_for_bot_reply_continuation",
|
|
17784
|
+
preparation.kind === "skip"
|
|
17785
|
+
&& String(preparation?.skipAction || "") === "adjudication_skipped"
|
|
17786
|
+
&& String(preparation?.skipReason || "") === "bot_reply_not_explicitly_handed_off"
|
|
17787
|
+
&& String(preparation?.skipTrigger || "") === "request_contract",
|
|
17788
|
+
`kind=${String(preparation?.kind || "(none)")} action=${String(preparation?.skipAction || "(none)")} reason=${String(preparation?.skipReason || "(none)")} trigger=${String(preparation?.skipTrigger || "(none)")}`,
|
|
17789
|
+
);
|
|
17790
|
+
} catch (err) {
|
|
17791
|
+
push("runner_selected_record_execution_context_requires_explicit_handoff_for_bot_reply_continuation", false, String(err?.message || err));
|
|
17792
|
+
}
|
|
17793
|
+
|
|
17532
17794
|
try {
|
|
17533
17795
|
const preparation = await resolveRunnerPrecomputedSelectedRecordExecutionContext({
|
|
17534
17796
|
selectedRecord: {
|
|
@@ -1599,6 +1599,123 @@ export async function runSelftestTelegramE2E(push, deps) {
|
|
|
1599
1599
|
});
|
|
1600
1600
|
const routeRyoai2Key = runnerRouteKey(routeRyoai2);
|
|
1601
1601
|
const routeRyoai3Key = runnerRouteKey(routeRyoai3);
|
|
1602
|
+
|
|
1603
|
+
telegramE2EServer.state.comments = [];
|
|
1604
|
+
telegramE2EServer.state.updates = [
|
|
1605
|
+
{
|
|
1606
|
+
update_id: 402,
|
|
1607
|
+
message: {
|
|
1608
|
+
message_id: 84,
|
|
1609
|
+
date: Math.floor(Date.now() / 1000),
|
|
1610
|
+
chat: {
|
|
1611
|
+
id: Number(e2eDestination.chat_id),
|
|
1612
|
+
type: "supergroup",
|
|
1613
|
+
title: e2eDestination.label,
|
|
1614
|
+
},
|
|
1615
|
+
from: {
|
|
1616
|
+
id: 7001,
|
|
1617
|
+
is_bot: false,
|
|
1618
|
+
first_name: "Operator",
|
|
1619
|
+
username: "operator_user",
|
|
1620
|
+
},
|
|
1621
|
+
text: "@RyoAI_bot @RyoAI2_bot @RyoAI3_bot 같이 논의 해죠",
|
|
1622
|
+
entities: buildTelegramMentionEntities("@RyoAI_bot @RyoAI2_bot @RyoAI3_bot 같이 논의 해죠"),
|
|
1623
|
+
},
|
|
1624
|
+
},
|
|
1625
|
+
];
|
|
1626
|
+
const sharedHumanRouteRuntime = {
|
|
1627
|
+
baseURL: telegramE2EServer.baseURL,
|
|
1628
|
+
timeoutSeconds: 10,
|
|
1629
|
+
token: e2eToken,
|
|
1630
|
+
actor: {
|
|
1631
|
+
user_id: e2eActorUserID,
|
|
1632
|
+
},
|
|
1633
|
+
};
|
|
1634
|
+
const sharedHumanManagedBots = [
|
|
1635
|
+
{
|
|
1636
|
+
username: "RyoAI_bot",
|
|
1637
|
+
route: routeRyoai1,
|
|
1638
|
+
bot: { username: "RyoAI_bot", name: "RyoAI_bot" },
|
|
1639
|
+
},
|
|
1640
|
+
{
|
|
1641
|
+
username: "RyoAI2_bot",
|
|
1642
|
+
route: routeRyoai2,
|
|
1643
|
+
bot: { username: "RyoAI2_bot", name: "RyoAI2_bot" },
|
|
1644
|
+
},
|
|
1645
|
+
{
|
|
1646
|
+
username: "RyoAI3_bot",
|
|
1647
|
+
route: routeRyoai3,
|
|
1648
|
+
bot: { username: "RyoAI3_bot", name: "RyoAI3_bot" },
|
|
1649
|
+
},
|
|
1650
|
+
];
|
|
1651
|
+
await archiveLocalTelegramMessagesForRoute({
|
|
1652
|
+
routeKey: runnerRouteKey(routeRyoai1),
|
|
1653
|
+
route: routeRyoai1,
|
|
1654
|
+
routeState: {},
|
|
1655
|
+
runtime: sharedHumanRouteRuntime,
|
|
1656
|
+
bot: {
|
|
1657
|
+
id: "88888888-8888-4888-8888-888888888881",
|
|
1658
|
+
name: "RyoAI_bot",
|
|
1659
|
+
username: "RyoAI_bot",
|
|
1660
|
+
role: "monitor",
|
|
1661
|
+
},
|
|
1662
|
+
destination: {
|
|
1663
|
+
chatID: e2eDestination.chat_id,
|
|
1664
|
+
},
|
|
1665
|
+
archiveThread: {
|
|
1666
|
+
threadID: e2eThreadID,
|
|
1667
|
+
},
|
|
1668
|
+
managedConversationBots: sharedHumanManagedBots,
|
|
1669
|
+
deps: buildRunnerRuntimeDeps(),
|
|
1670
|
+
});
|
|
1671
|
+
await archiveLocalTelegramMessagesForRoute({
|
|
1672
|
+
routeKey: routeRyoai2Key,
|
|
1673
|
+
route: routeRyoai2,
|
|
1674
|
+
routeState: {},
|
|
1675
|
+
runtime: sharedHumanRouteRuntime,
|
|
1676
|
+
bot: {
|
|
1677
|
+
id: "88888888-8888-4888-8888-888888888882",
|
|
1678
|
+
name: "RyoAI2_bot",
|
|
1679
|
+
username: "RyoAI2_bot",
|
|
1680
|
+
role: "monitor",
|
|
1681
|
+
},
|
|
1682
|
+
destination: {
|
|
1683
|
+
chatID: e2eDestination.chat_id,
|
|
1684
|
+
},
|
|
1685
|
+
archiveThread: {
|
|
1686
|
+
threadID: e2eThreadID,
|
|
1687
|
+
},
|
|
1688
|
+
managedConversationBots: sharedHumanManagedBots,
|
|
1689
|
+
deps: buildRunnerRuntimeDeps(),
|
|
1690
|
+
});
|
|
1691
|
+
await archiveLocalTelegramMessagesForRoute({
|
|
1692
|
+
routeKey: routeRyoai3Key,
|
|
1693
|
+
route: routeRyoai3,
|
|
1694
|
+
routeState: {},
|
|
1695
|
+
runtime: sharedHumanRouteRuntime,
|
|
1696
|
+
bot: {
|
|
1697
|
+
id: "88888888-8888-4888-8888-888888888883",
|
|
1698
|
+
name: "RyoAI3_bot",
|
|
1699
|
+
username: "RyoAI3_bot",
|
|
1700
|
+
role: "monitor",
|
|
1701
|
+
},
|
|
1702
|
+
destination: {
|
|
1703
|
+
chatID: e2eDestination.chat_id,
|
|
1704
|
+
},
|
|
1705
|
+
archiveThread: {
|
|
1706
|
+
threadID: e2eThreadID,
|
|
1707
|
+
},
|
|
1708
|
+
managedConversationBots: sharedHumanManagedBots,
|
|
1709
|
+
deps: buildRunnerRuntimeDeps(),
|
|
1710
|
+
});
|
|
1711
|
+
const sharedHumanBodies = telegramE2EServer.state.comments.map((item) => String(item.body || ""));
|
|
1712
|
+
push(
|
|
1713
|
+
"telegram_multi_bot_human_opening_archives_once_across_routes",
|
|
1714
|
+
sharedHumanBodies.filter((item) => item.includes("message_id: 84")).length === 1,
|
|
1715
|
+
`count=${sharedHumanBodies.filter((item) => item.includes("message_id: 84")).length} bodies=${sharedHumanBodies.join(" || ")}`,
|
|
1716
|
+
);
|
|
1717
|
+
|
|
1718
|
+
telegramE2EServer.state.comments = [];
|
|
1602
1719
|
await archiveLocalTelegramMessagesForRoute({
|
|
1603
1720
|
routeKey: routeRyoai3Key,
|
|
1604
1721
|
route: routeRyoai3,
|