metheus-governance-mcp-cli 0.2.250 → 0.2.252
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 +24 -26
- package/lib/bot-commands.mjs +1 -1
- package/lib/local-ai-adapters.mjs +30 -2
- package/lib/runner-helpers.mjs +22 -0
- package/lib/runner-orchestration.mjs +29 -19
- package/lib/runner-trigger.mjs +7 -14
- package/lib/selftest-runner-scenarios.mjs +211 -8
- package/package.json +1 -1
package/cli.mjs
CHANGED
|
@@ -141,6 +141,7 @@ import {
|
|
|
141
141
|
buildProcessableArchiveLogicalKey,
|
|
142
142
|
findEarlierProcessableArchiveDuplicate,
|
|
143
143
|
findRecentTelegramMessageEnvelope,
|
|
144
|
+
isTelegramLocalInboundEnvelopeForRoute,
|
|
144
145
|
isInboundArchiveKind,
|
|
145
146
|
normalizeTelegramMessageEnvelope as normalizeRunnerTelegramMessageEnvelope,
|
|
146
147
|
normalizeArchiveCommentRecord,
|
|
@@ -2665,14 +2666,17 @@ function buildRunnerSourceMessageEnvelope({
|
|
|
2665
2666
|
parsedArchive = null,
|
|
2666
2667
|
}) {
|
|
2667
2668
|
const localEnvelope = findRunnerRouteLocalInboundEnvelope(routeState, parsedArchive);
|
|
2668
|
-
if (String(localEnvelope.source_origin || "").trim().toLowerCase() === "local_telegram_inbound") {
|
|
2669
|
-
return localEnvelope;
|
|
2670
|
-
}
|
|
2671
2669
|
const fallbackBotSelector = normalizeTelegramMentionUsername(
|
|
2672
2670
|
normalizedRoute?.botName
|
|
2673
2671
|
|| normalizedRoute?.serverBotName
|
|
2674
2672
|
|| "",
|
|
2675
2673
|
);
|
|
2674
|
+
if (isTelegramLocalInboundEnvelopeForRoute(localEnvelope, {
|
|
2675
|
+
routeKey,
|
|
2676
|
+
botUsername: fallbackBotSelector,
|
|
2677
|
+
})) {
|
|
2678
|
+
return localEnvelope;
|
|
2679
|
+
}
|
|
2676
2680
|
return buildRunnerTelegramMessageEnvelopeFromParsedArchive(parsedArchive, {
|
|
2677
2681
|
source_origin: "archive_reconstructed",
|
|
2678
2682
|
source_route_key: String(routeKey || "").trim(),
|
|
@@ -7865,30 +7869,23 @@ function extractTelegramEntityText(text, entity) {
|
|
|
7865
7869
|
return body.slice(offset, offset + length);
|
|
7866
7870
|
}
|
|
7867
7871
|
|
|
7868
|
-
function extractTelegramMentionUsernames(text, entities) {
|
|
7869
|
-
const set = new Set();
|
|
7870
|
-
for (const entityRaw of ensureArray(entities)) {
|
|
7871
|
-
const entity = safeObject(entityRaw);
|
|
7872
|
+
function extractTelegramMentionUsernames(text, entities) {
|
|
7873
|
+
const set = new Set();
|
|
7874
|
+
for (const entityRaw of ensureArray(entities)) {
|
|
7875
|
+
const entity = safeObject(entityRaw);
|
|
7872
7876
|
const type = String(entity.type || "").trim().toLowerCase();
|
|
7873
7877
|
if (type === "mention") {
|
|
7874
7878
|
const username = normalizeTelegramMentionUsername(extractTelegramEntityText(text, entity));
|
|
7875
7879
|
if (username) set.add(username);
|
|
7876
7880
|
continue;
|
|
7877
7881
|
}
|
|
7878
|
-
if (type === "text_mention") {
|
|
7879
|
-
const username = normalizeTelegramMentionUsername(entity.user?.username);
|
|
7880
|
-
if (username) set.add(username);
|
|
7881
|
-
}
|
|
7882
|
-
}
|
|
7883
|
-
|
|
7884
|
-
|
|
7885
|
-
while (match) {
|
|
7886
|
-
const username = normalizeTelegramMentionUsername(match[2]);
|
|
7887
|
-
if (username) set.add(username);
|
|
7888
|
-
match = regex.exec(String(text || ""));
|
|
7889
|
-
}
|
|
7890
|
-
return Array.from(set);
|
|
7891
|
-
}
|
|
7882
|
+
if (type === "text_mention") {
|
|
7883
|
+
const username = normalizeTelegramMentionUsername(entity.user?.username);
|
|
7884
|
+
if (username) set.add(username);
|
|
7885
|
+
}
|
|
7886
|
+
}
|
|
7887
|
+
return Array.from(set);
|
|
7888
|
+
}
|
|
7892
7889
|
|
|
7893
7890
|
function normalizeLocalTelegramUpdate(rawUpdate) {
|
|
7894
7891
|
const update = safeObject(rawUpdate);
|
|
@@ -17539,11 +17536,12 @@ TELEGRAM_BOT_REVIEW_TOKEN=review-token
|
|
|
17539
17536
|
mergeServerRunnerRequestLedgerIntoLocalState,
|
|
17540
17537
|
buildRunnerStatusQueryLookup,
|
|
17541
17538
|
tryJsonParse,
|
|
17542
|
-
safeObject,
|
|
17543
|
-
normalizeRunnerTriggerPolicy,
|
|
17544
|
-
evaluateTelegramRunnerTrigger,
|
|
17545
|
-
|
|
17546
|
-
|
|
17539
|
+
safeObject,
|
|
17540
|
+
normalizeRunnerTriggerPolicy,
|
|
17541
|
+
evaluateTelegramRunnerTrigger,
|
|
17542
|
+
resolveHumanIntentContext,
|
|
17543
|
+
resolveRunnerResponderAdjudication,
|
|
17544
|
+
selectPendingArchiveComments,
|
|
17547
17545
|
selectRunnerPendingWork,
|
|
17548
17546
|
processRunnerSelectedRecord,
|
|
17549
17547
|
resolveRunnerStartupLoopAdjudication,
|
package/lib/bot-commands.mjs
CHANGED
|
@@ -2669,7 +2669,7 @@ function suggestedAIModelsForClient(clientName) {
|
|
|
2669
2669
|
{ value: "Opus 4.6", label: "Opus 4.6", description: "display label; runs as opus" },
|
|
2670
2670
|
];
|
|
2671
2671
|
}
|
|
2672
|
-
|
|
2672
|
+
if (normalizedClient === "gemini") {
|
|
2673
2673
|
return [
|
|
2674
2674
|
{ value: "gemini-3.1-pro", label: "gemini-3.1-pro", description: "display label; runs as auto-gemini-3" },
|
|
2675
2675
|
];
|
|
@@ -18,6 +18,7 @@ const GEMINI_HOME_SYNC_FILES = [
|
|
|
18
18
|
"settings.json",
|
|
19
19
|
];
|
|
20
20
|
const GEMINI_STDIN_BRIDGE_PROMPT = "Use the full task provided on standard input as the authoritative prompt. Follow it exactly and output only the final answer.";
|
|
21
|
+
const GEMINI_CLI_TIMEOUT_MS = 90 * 1000;
|
|
21
22
|
const LOCAL_AI_MODEL_MAPPINGS = {
|
|
22
23
|
gpt: [
|
|
23
24
|
{
|
|
@@ -769,13 +770,36 @@ function runGeminiRawText({ promptText, workspaceDir, model, permissionMode, rea
|
|
|
769
770
|
env: runtime.env,
|
|
770
771
|
input: String(promptText || ""),
|
|
771
772
|
maxBuffer: 8 * 1024 * 1024,
|
|
773
|
+
timeout: GEMINI_CLI_TIMEOUT_MS,
|
|
772
774
|
},
|
|
773
775
|
);
|
|
774
776
|
if (result.error) {
|
|
777
|
+
const errorCode = String(result.error?.code || "").trim().toUpperCase();
|
|
778
|
+
if (errorCode === "ETIMEDOUT") {
|
|
779
|
+
const stderrText = String(result.stderr || "").trim();
|
|
780
|
+
const stdoutText = String(result.stdout || "").trim();
|
|
781
|
+
const details = [stderrText, stdoutText]
|
|
782
|
+
.filter(Boolean)
|
|
783
|
+
.map((value) => value.replace(/\s+/g, " ").trim())
|
|
784
|
+
.filter(Boolean)
|
|
785
|
+
.slice(0, 2)
|
|
786
|
+
.join(" | ");
|
|
787
|
+
throw new Error(
|
|
788
|
+
details
|
|
789
|
+
? `Gemini CLI timed out after ${Math.round(GEMINI_CLI_TIMEOUT_MS / 1000)}s while waiting for a model response (${details})`
|
|
790
|
+
: `Gemini CLI timed out after ${Math.round(GEMINI_CLI_TIMEOUT_MS / 1000)}s while waiting for a model response`,
|
|
791
|
+
);
|
|
792
|
+
}
|
|
775
793
|
throw new Error(String(result.error?.message || result.error));
|
|
776
794
|
}
|
|
777
795
|
if (result.status !== 0) {
|
|
778
|
-
|
|
796
|
+
const stderrText = String(result.stderr || "");
|
|
797
|
+
const stdoutText = String(result.stdout || "");
|
|
798
|
+
const combinedText = `${stderrText}\n${stdoutText}`.trim();
|
|
799
|
+
if (/MODEL_CAPACITY_EXHAUSTED|No capacity available for model/i.test(combinedText)) {
|
|
800
|
+
throw new Error(`Gemini model capacity is currently unavailable for ${String(model || "").trim() || "the configured model"}`);
|
|
801
|
+
}
|
|
802
|
+
throw new Error(combinedText || `gemini exited with status ${result.status}`);
|
|
779
803
|
}
|
|
780
804
|
return String(result.stdout || "");
|
|
781
805
|
} finally {
|
|
@@ -1377,7 +1401,8 @@ function buildGeminiArgs({ model, permissionMode }) {
|
|
|
1377
1401
|
"--allowed-mcp-server-names",
|
|
1378
1402
|
"none",
|
|
1379
1403
|
];
|
|
1380
|
-
|
|
1404
|
+
const normalizedModel = normalizeModelAliasText(model);
|
|
1405
|
+
if (model && normalizedModel !== "auto-gemini-3") {
|
|
1381
1406
|
args.push("--model", model);
|
|
1382
1407
|
}
|
|
1383
1408
|
return args;
|
|
@@ -1433,6 +1458,9 @@ function buildGeminiThinkingConfig(model, reasoningEffort) {
|
|
|
1433
1458
|
|
|
1434
1459
|
export function resolveGeminiReasoningConfig(rawModelValue = "", reasoningEffort = "medium") {
|
|
1435
1460
|
const executionModel = resolveLocalAIExecutionModel("gemini", rawModelValue);
|
|
1461
|
+
if (!executionModel || executionModel === "auto-gemini-3") {
|
|
1462
|
+
return null;
|
|
1463
|
+
}
|
|
1436
1464
|
const thinkingConfig = buildGeminiThinkingConfig(executionModel, reasoningEffort);
|
|
1437
1465
|
if (!thinkingConfig) {
|
|
1438
1466
|
return null;
|
package/lib/runner-helpers.mjs
CHANGED
|
@@ -284,6 +284,28 @@ function normalizeMentionSelector(rawValue) {
|
|
|
284
284
|
return String(rawValue || "").trim().replace(/^@+/, "").toLowerCase();
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
+
export function isTelegramLocalInboundEnvelopeForRoute(rawEnvelope, {
|
|
288
|
+
routeKey = "",
|
|
289
|
+
botUsername = "",
|
|
290
|
+
} = {}) {
|
|
291
|
+
const envelope = normalizeTelegramMessageEnvelope(rawEnvelope);
|
|
292
|
+
const sourceOrigin = String(envelope.source_origin || "").trim().toLowerCase();
|
|
293
|
+
if (sourceOrigin !== "local_telegram_inbound") {
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
const expectedRouteKey = String(routeKey || "").trim();
|
|
297
|
+
const actualRouteKey = String(envelope.source_route_key || "").trim();
|
|
298
|
+
if (expectedRouteKey && expectedRouteKey !== actualRouteKey) {
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
const expectedBotUsername = normalizeMentionSelector(botUsername);
|
|
302
|
+
const actualBotUsername = normalizeMentionSelector(envelope.source_bot_username || "");
|
|
303
|
+
if (expectedBotUsername && expectedBotUsername !== actualBotUsername) {
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
return true;
|
|
307
|
+
}
|
|
308
|
+
|
|
287
309
|
function uniqueNormalizedSelectors(values) {
|
|
288
310
|
return Array.from(new Set(
|
|
289
311
|
ensureArray(values)
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
compareArchiveCommentRecords,
|
|
9
9
|
dedupeProcessableArchiveComments,
|
|
10
10
|
findRecentTelegramMessageEnvelope,
|
|
11
|
+
isTelegramLocalInboundEnvelopeForRoute,
|
|
11
12
|
isInboundArchiveKind,
|
|
12
13
|
normalizeTelegramMessageEnvelope,
|
|
13
14
|
selectPendingArchiveComments,
|
|
@@ -402,18 +403,23 @@ function resolveRunnerDeliverySourceMessageEnvelope({
|
|
|
402
403
|
messageID: archiveMessageID,
|
|
403
404
|
},
|
|
404
405
|
);
|
|
405
|
-
if (
|
|
406
|
+
if (isTelegramLocalInboundEnvelopeForRoute(routeLocalEnvelope, {
|
|
407
|
+
routeKey,
|
|
408
|
+
botUsername: currentBotSelector,
|
|
409
|
+
})) {
|
|
406
410
|
return routeLocalEnvelope;
|
|
407
411
|
}
|
|
408
412
|
const persistedSourceEnvelope = normalizeTelegramMessageEnvelope(
|
|
409
413
|
safeObject(persistedRequest).source_message_envelope
|
|
410
414
|
|| safeObject(persistedRequest).sourceMessageEnvelope,
|
|
411
415
|
);
|
|
412
|
-
const persistedOrigin = String(persistedSourceEnvelope.source_origin || "").trim().toLowerCase();
|
|
413
416
|
const persistedChatID = String(persistedSourceEnvelope.chat_id || "").trim();
|
|
414
417
|
const persistedMessageID = intFromRawAllowZero(persistedSourceEnvelope.message_id, 0);
|
|
415
418
|
if (
|
|
416
|
-
|
|
419
|
+
isTelegramLocalInboundEnvelopeForRoute(persistedSourceEnvelope, {
|
|
420
|
+
routeKey,
|
|
421
|
+
botUsername: currentBotSelector,
|
|
422
|
+
})
|
|
417
423
|
&& archiveChatID
|
|
418
424
|
&& archiveChatID === persistedChatID
|
|
419
425
|
&& archiveMessageID > 0
|
|
@@ -3382,21 +3388,22 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
3382
3388
|
};
|
|
3383
3389
|
}
|
|
3384
3390
|
|
|
3385
|
-
function buildConversationPeerMap(bot, normalizedRoute, deps) {
|
|
3386
|
-
const peers = typeof deps?.resolveConversationPeerBots === "function"
|
|
3387
|
-
? ensureArray(deps.resolveConversationPeerBots(normalizedRoute))
|
|
3388
|
-
: [];
|
|
3389
|
-
const output = new Map();
|
|
3390
|
-
const register = (peerRaw) => {
|
|
3391
|
-
const peer = safeObject(peerRaw);
|
|
3392
|
-
const displayName = String(peer.name || peer.username || peer.id || "").trim();
|
|
3393
|
-
const
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3391
|
+
function buildConversationPeerMap(bot, normalizedRoute, deps) {
|
|
3392
|
+
const peers = typeof deps?.resolveConversationPeerBots === "function"
|
|
3393
|
+
? ensureArray(deps.resolveConversationPeerBots(normalizedRoute))
|
|
3394
|
+
: [];
|
|
3395
|
+
const output = new Map();
|
|
3396
|
+
const register = (peerRaw) => {
|
|
3397
|
+
const peer = safeObject(peerRaw);
|
|
3398
|
+
const displayName = String(peer.name || peer.username || peer.id || "").trim();
|
|
3399
|
+
const explicitUsername = normalizeMentionSelector(peer.username);
|
|
3400
|
+
const selectors = uniqueOrdered([
|
|
3401
|
+
explicitUsername,
|
|
3402
|
+
explicitUsername ? "" : normalizeMentionSelector(peer.name),
|
|
3403
|
+
]);
|
|
3404
|
+
for (const selector of selectors) {
|
|
3405
|
+
output.set(selector, {
|
|
3406
|
+
selector,
|
|
3400
3407
|
displayName: displayName || selector,
|
|
3401
3408
|
id: String(peer.id || "").trim(),
|
|
3402
3409
|
});
|
|
@@ -4935,7 +4942,10 @@ export async function processRunnerSelectedRecord({
|
|
|
4935
4942
|
&& !precomputedConversationResponderSelection;
|
|
4936
4943
|
if (!currentBotSelected && !shouldDeferBotReplyConversationAuthorization) {
|
|
4937
4944
|
const adjudicationDecision = String(responderAdjudication.decision || "").trim() || "no_responder";
|
|
4938
|
-
const
|
|
4945
|
+
const rawAdjudicationReason = String(responderAdjudication.reason_code || "").trim() || "not_selected_by_adjudicator";
|
|
4946
|
+
const adjudicationReason = rawAdjudicationReason === "precomputed_human_intent_contract" && selectedResponderSelectors.length > 0
|
|
4947
|
+
? "precomputed_human_intent_contract_selected_other_responder"
|
|
4948
|
+
: rawAdjudicationReason;
|
|
4939
4949
|
saveRunnerRouteState(
|
|
4940
4950
|
routeKey,
|
|
4941
4951
|
buildRunnerRouteStateFromComment(selectedRecord, {
|
package/lib/runner-trigger.mjs
CHANGED
|
@@ -35,19 +35,11 @@ function normalizeTelegramMentionUsername(rawValue) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
function listTelegramMentionUsernames(parsedArchive) {
|
|
38
|
-
|
|
38
|
+
return uniqueOrdered(
|
|
39
39
|
ensureArray(parsedArchive?.mentionUsernames)
|
|
40
40
|
.map((value) => normalizeTelegramMentionUsername(value))
|
|
41
41
|
.filter(Boolean),
|
|
42
42
|
);
|
|
43
|
-
const text = String(parsedArchive?.body || "").trim().toLowerCase();
|
|
44
|
-
for (const match of text.matchAll(/@([a-z0-9_]{3,})/gi)) {
|
|
45
|
-
const normalized = normalizeTelegramMentionUsername(match?.[1]);
|
|
46
|
-
if (normalized) {
|
|
47
|
-
usernames.add(normalized);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
return Array.from(usernames);
|
|
51
43
|
}
|
|
52
44
|
|
|
53
45
|
function inferTelegramArchiveChatType(parsedArchive) {
|
|
@@ -60,10 +52,13 @@ function inferTelegramArchiveChatType(parsedArchive) {
|
|
|
60
52
|
|
|
61
53
|
function buildTelegramBotUsernameCandidates(bot, route) {
|
|
62
54
|
const set = new Set();
|
|
55
|
+
const explicitUsername = normalizeTelegramMentionUsername(bot?.username);
|
|
56
|
+
const fallbackDisplayCandidates = explicitUsername
|
|
57
|
+
? []
|
|
58
|
+
: [bot?.name, route?.botName];
|
|
63
59
|
for (const candidate of [
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
route?.botName,
|
|
60
|
+
explicitUsername,
|
|
61
|
+
...fallbackDisplayCandidates,
|
|
67
62
|
]) {
|
|
68
63
|
const normalized = normalizeTelegramMentionUsername(candidate);
|
|
69
64
|
if (normalized) {
|
|
@@ -74,13 +69,11 @@ function buildTelegramBotUsernameCandidates(bot, route) {
|
|
|
74
69
|
}
|
|
75
70
|
|
|
76
71
|
function doesTelegramArchiveMentionBot(parsedArchive, bot, route) {
|
|
77
|
-
const text = String(parsedArchive?.body || "").trim().toLowerCase();
|
|
78
72
|
const mentions = new Set(listTelegramMentionUsernames(parsedArchive));
|
|
79
73
|
const candidates = buildTelegramBotUsernameCandidates(bot, route);
|
|
80
74
|
for (const username of candidates) {
|
|
81
75
|
if (!username) continue;
|
|
82
76
|
if (mentions.has(username)) return true;
|
|
83
|
-
if (text.includes(`@${username}`)) return true;
|
|
84
77
|
}
|
|
85
78
|
return false;
|
|
86
79
|
}
|
|
@@ -117,7 +117,8 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
117
117
|
const tryJsonParse = requireDependency(deps, "tryJsonParse");
|
|
118
118
|
const safeObject = requireDependency(deps, "safeObject");
|
|
119
119
|
const normalizeRunnerTriggerPolicy = requireDependency(deps, "normalizeRunnerTriggerPolicy");
|
|
120
|
-
const evaluateTelegramRunnerTrigger = requireDependency(deps, "evaluateTelegramRunnerTrigger");
|
|
120
|
+
const evaluateTelegramRunnerTrigger = requireDependency(deps, "evaluateTelegramRunnerTrigger");
|
|
121
|
+
const resolveHumanIntentContext = requireDependency(deps, "resolveHumanIntentContext");
|
|
121
122
|
const resolveRunnerResponderAdjudication = requireDependency(deps, "resolveRunnerResponderAdjudication");
|
|
122
123
|
const selectPendingArchiveComments = requireDependency(deps, "selectPendingArchiveComments");
|
|
123
124
|
const selectRunnerPendingWork = requireDependency(deps, "selectRunnerPendingWork");
|
|
@@ -2464,13 +2465,80 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
2464
2465
|
mentionOnlyRoute,
|
|
2465
2466
|
{ name: "ServerProtocolMonitorBot", role: "monitor" },
|
|
2466
2467
|
);
|
|
2467
|
-
push(
|
|
2468
|
-
"telegram_trigger_mentions_only_accepts_bot_mention",
|
|
2469
|
-
mentionOnlyMatched.shouldRespond === true && mentionOnlyMatched.trigger === "mention",
|
|
2470
|
-
`shouldRespond=${mentionOnlyMatched.shouldRespond} trigger=${mentionOnlyMatched.trigger}`,
|
|
2471
|
-
);
|
|
2472
|
-
|
|
2473
|
-
const
|
|
2468
|
+
push(
|
|
2469
|
+
"telegram_trigger_mentions_only_accepts_bot_mention",
|
|
2470
|
+
mentionOnlyMatched.shouldRespond === true && mentionOnlyMatched.trigger === "mention",
|
|
2471
|
+
`shouldRespond=${mentionOnlyMatched.shouldRespond} trigger=${mentionOnlyMatched.trigger}`,
|
|
2472
|
+
);
|
|
2473
|
+
|
|
2474
|
+
const mentionOnlyAliasCandidate = evaluateTelegramRunnerTrigger(
|
|
2475
|
+
{
|
|
2476
|
+
id: "comment-2a",
|
|
2477
|
+
parsedArchive: {
|
|
2478
|
+
kind: "telegram_message",
|
|
2479
|
+
chatID: "-100123",
|
|
2480
|
+
chatType: "supergroup",
|
|
2481
|
+
body: "hello @RyoAI_bot2",
|
|
2482
|
+
mentionUsernames: [],
|
|
2483
|
+
replyToSenderIsBot: false,
|
|
2484
|
+
},
|
|
2485
|
+
},
|
|
2486
|
+
mentionOnlyRoute,
|
|
2487
|
+
{ username: "ryoai2_bot", name: "RyoAI_bot2", role: "monitor" },
|
|
2488
|
+
);
|
|
2489
|
+
push(
|
|
2490
|
+
"telegram_trigger_does_not_treat_raw_alias_text_as_authoritative_mention",
|
|
2491
|
+
mentionOnlyAliasCandidate.shouldRespond === true
|
|
2492
|
+
&& mentionOnlyAliasCandidate.trigger === "mentions_only_unaddressed_candidate",
|
|
2493
|
+
`shouldRespond=${mentionOnlyAliasCandidate.shouldRespond} trigger=${mentionOnlyAliasCandidate.trigger}`,
|
|
2494
|
+
);
|
|
2495
|
+
|
|
2496
|
+
try {
|
|
2497
|
+
const aliasHumanIntentContext = await resolveHumanIntentContext({
|
|
2498
|
+
selectedRecord: {
|
|
2499
|
+
id: "comment-alias-managed-mention",
|
|
2500
|
+
parsedArchive: {
|
|
2501
|
+
kind: "telegram_message",
|
|
2502
|
+
body: "@RyoAI_bot2 hi",
|
|
2503
|
+
senderIsBot: false,
|
|
2504
|
+
},
|
|
2505
|
+
},
|
|
2506
|
+
normalizedRoute: {
|
|
2507
|
+
name: "telegram-monitor-ryoai2-bot-2",
|
|
2508
|
+
},
|
|
2509
|
+
bot: {
|
|
2510
|
+
username: "ryoai2_bot",
|
|
2511
|
+
name: "RyoAI_bot2",
|
|
2512
|
+
},
|
|
2513
|
+
executionPlan: {},
|
|
2514
|
+
deps: {
|
|
2515
|
+
resolveConversationPeerBots: () => [],
|
|
2516
|
+
},
|
|
2517
|
+
persistedRequest: {
|
|
2518
|
+
conversation_intent_mode: "single_bot",
|
|
2519
|
+
conversation_reply_expectation: "informational",
|
|
2520
|
+
conversation_initial_responders: ["ryoai2_bot"],
|
|
2521
|
+
conversation_allowed_responders: ["ryoai2_bot"],
|
|
2522
|
+
conversation_participants: ["ryoai2_bot"],
|
|
2523
|
+
conversation_lead_bot: "ryoai2_bot",
|
|
2524
|
+
conversation_summary_bot: "ryoai2_bot",
|
|
2525
|
+
},
|
|
2526
|
+
});
|
|
2527
|
+
push(
|
|
2528
|
+
"runner_human_intent_context_ignores_raw_alias_selector_for_managed_mentions",
|
|
2529
|
+
ensureArray(aliasHumanIntentContext?.managedMentions).length === 0
|
|
2530
|
+
&& aliasHumanIntentContext?.reusedPersistedContract === true,
|
|
2531
|
+
`managedMentions=${JSON.stringify(ensureArray(aliasHumanIntentContext?.managedMentions))} reused=${String(aliasHumanIntentContext?.reusedPersistedContract)}`,
|
|
2532
|
+
);
|
|
2533
|
+
} catch (err) {
|
|
2534
|
+
push(
|
|
2535
|
+
"runner_human_intent_context_ignores_raw_alias_selector_for_managed_mentions",
|
|
2536
|
+
false,
|
|
2537
|
+
String(err?.message || err),
|
|
2538
|
+
);
|
|
2539
|
+
}
|
|
2540
|
+
|
|
2541
|
+
const mentionOverridesReplyForUnmentionedBot = evaluateTelegramRunnerTrigger(
|
|
2474
2542
|
{
|
|
2475
2543
|
id: "comment-2b",
|
|
2476
2544
|
parsedArchive: {
|
|
@@ -12986,6 +13054,141 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
12986
13054
|
push("runner_delivery_prefers_route_local_inbound_provenance_envelope", false, String(err?.message || err));
|
|
12987
13055
|
}
|
|
12988
13056
|
|
|
13057
|
+
try {
|
|
13058
|
+
let capturedSourceMessageEnvelope = {};
|
|
13059
|
+
const processed = await processRunnerSelectedRecord({
|
|
13060
|
+
routeKey: "telegram-monitor-ryoai2-bot-2::project::telegram::monitor::dest::actor",
|
|
13061
|
+
normalizedRoute: {
|
|
13062
|
+
name: "telegram-monitor-ryoai2-bot-2",
|
|
13063
|
+
provider: "telegram",
|
|
13064
|
+
role: "monitor",
|
|
13065
|
+
roleProfile: "monitor",
|
|
13066
|
+
botName: "RyoAI2_bot",
|
|
13067
|
+
archivePolicy: { mirrorReplies: true, dedupeOutbound: true },
|
|
13068
|
+
triggerPolicy: {
|
|
13069
|
+
directMessages: true,
|
|
13070
|
+
mentionsOnly: false,
|
|
13071
|
+
replyToBotMessages: true,
|
|
13072
|
+
ignoreEditedMessages: true,
|
|
13073
|
+
},
|
|
13074
|
+
},
|
|
13075
|
+
routeState: {
|
|
13076
|
+
recent_local_inbound_envelopes: {},
|
|
13077
|
+
},
|
|
13078
|
+
selectedRecord: {
|
|
13079
|
+
id: "comment-foreign-provenance",
|
|
13080
|
+
threadID: "thread-1",
|
|
13081
|
+
parsedArchive: {
|
|
13082
|
+
kind: "telegram_message",
|
|
13083
|
+
chatID: "-100123",
|
|
13084
|
+
chatType: "supergroup",
|
|
13085
|
+
body: "@RyoAI2_bot hi",
|
|
13086
|
+
messageID: 228,
|
|
13087
|
+
sender: "human",
|
|
13088
|
+
senderIsBot: false,
|
|
13089
|
+
mentionUsernames: ["ryoai2_bot"],
|
|
13090
|
+
},
|
|
13091
|
+
},
|
|
13092
|
+
persistedHumanIntentRequest: {
|
|
13093
|
+
source_message_envelope: {
|
|
13094
|
+
chat_id: "-100123",
|
|
13095
|
+
message_id: 228,
|
|
13096
|
+
source_origin: "local_telegram_inbound",
|
|
13097
|
+
source_route_key: "telegram-monitor-ryoai-bot-2::project::telegram::monitor::dest::actor",
|
|
13098
|
+
source_bot_username: "ryoai_bot",
|
|
13099
|
+
},
|
|
13100
|
+
},
|
|
13101
|
+
pendingOrdered: [],
|
|
13102
|
+
bot: {
|
|
13103
|
+
id: "bot-2",
|
|
13104
|
+
name: "RyoAI2_bot",
|
|
13105
|
+
username: "RyoAI2_bot",
|
|
13106
|
+
role: "monitor",
|
|
13107
|
+
provider: "telegram",
|
|
13108
|
+
},
|
|
13109
|
+
destination: {
|
|
13110
|
+
id: "dest-1",
|
|
13111
|
+
label: "Main Room",
|
|
13112
|
+
provider: "telegram",
|
|
13113
|
+
chatID: "-100123",
|
|
13114
|
+
},
|
|
13115
|
+
archiveThread: {
|
|
13116
|
+
threadID: "thread-1",
|
|
13117
|
+
workItemID: "work-item-1",
|
|
13118
|
+
},
|
|
13119
|
+
executionPlan: {
|
|
13120
|
+
mode: "role_profile",
|
|
13121
|
+
roleProfileName: "monitor",
|
|
13122
|
+
roleProfile: {
|
|
13123
|
+
client: "sample",
|
|
13124
|
+
model: "",
|
|
13125
|
+
permissionMode: "read_only",
|
|
13126
|
+
reasoningEffort: "low",
|
|
13127
|
+
},
|
|
13128
|
+
workspaceDir: "",
|
|
13129
|
+
workspaceSource: "selftest",
|
|
13130
|
+
usedCommandFallback: false,
|
|
13131
|
+
},
|
|
13132
|
+
runtime: {
|
|
13133
|
+
baseURL: "https://example.test",
|
|
13134
|
+
token: "selftest-token",
|
|
13135
|
+
timeoutSeconds: 30,
|
|
13136
|
+
actor: { user_id: "user-1" },
|
|
13137
|
+
},
|
|
13138
|
+
deps: {
|
|
13139
|
+
saveRunnerRouteState: () => {},
|
|
13140
|
+
startRunnerTypingHeartbeat: () => ({ async stop() {} }),
|
|
13141
|
+
runRunnerAIExecution: async () => ({
|
|
13142
|
+
skip: false,
|
|
13143
|
+
reply: "Hello from RyoAI2_bot.",
|
|
13144
|
+
}),
|
|
13145
|
+
performLocalBotDelivery: async ({ sourceMessageEnvelope }) => {
|
|
13146
|
+
capturedSourceMessageEnvelope = safeObject(sourceMessageEnvelope);
|
|
13147
|
+
return {
|
|
13148
|
+
delivery: {
|
|
13149
|
+
dryRun: false,
|
|
13150
|
+
body: {
|
|
13151
|
+
result: {
|
|
13152
|
+
message_id: 9002,
|
|
13153
|
+
},
|
|
13154
|
+
},
|
|
13155
|
+
},
|
|
13156
|
+
archive: {},
|
|
13157
|
+
};
|
|
13158
|
+
},
|
|
13159
|
+
serializeRunnerTriggerPolicy: (value) => value,
|
|
13160
|
+
serializeRunnerArchivePolicy: (value) => value,
|
|
13161
|
+
buildRunnerExecutionDeps: () => ({
|
|
13162
|
+
validateWorkspaceArtifacts,
|
|
13163
|
+
analyzeHumanConversationIntentWithAI: async () => ({
|
|
13164
|
+
mode: "single_bot",
|
|
13165
|
+
lead_bot: "ryoai2_bot",
|
|
13166
|
+
participants: ["ryoai2_bot"],
|
|
13167
|
+
initial_responders: ["ryoai2_bot"],
|
|
13168
|
+
allowed_responders: ["ryoai2_bot"],
|
|
13169
|
+
summary_bot: "",
|
|
13170
|
+
allow_bot_to_bot: false,
|
|
13171
|
+
reply_expectation: "informational",
|
|
13172
|
+
intent_type: "small_talk",
|
|
13173
|
+
}),
|
|
13174
|
+
}),
|
|
13175
|
+
buildRunnerDeliveryDeps: () => ({}),
|
|
13176
|
+
buildRunnerRuntimeDeps: () => ({}),
|
|
13177
|
+
resolveConversationPeerBots: () => [],
|
|
13178
|
+
},
|
|
13179
|
+
});
|
|
13180
|
+
push(
|
|
13181
|
+
"runner_delivery_rejects_foreign_route_local_provenance",
|
|
13182
|
+
processed.kind === "replied"
|
|
13183
|
+
&& String(capturedSourceMessageEnvelope.source_origin || "") === "archive_reconstructed"
|
|
13184
|
+
&& String(capturedSourceMessageEnvelope.source_route_key || "").includes("telegram-monitor-ryoai2-bot-2")
|
|
13185
|
+
&& String(capturedSourceMessageEnvelope.source_bot_username || "") === "ryoai2_bot",
|
|
13186
|
+
`kind=${String(processed.kind || "(none)")} origin=${String(capturedSourceMessageEnvelope.source_origin || "(none)")} route=${String(capturedSourceMessageEnvelope.source_route_key || "(none)")} bot=${String(capturedSourceMessageEnvelope.source_bot_username || "(none)")}`,
|
|
13187
|
+
);
|
|
13188
|
+
} catch (err) {
|
|
13189
|
+
push("runner_delivery_rejects_foreign_route_local_provenance", false, String(err?.message || err));
|
|
13190
|
+
}
|
|
13191
|
+
|
|
12989
13192
|
try {
|
|
12990
13193
|
const workspaceDir = fs.mkdtempSync(path.join(os.tmpdir(), "metheus-runner-selftest-observed-artifacts-"));
|
|
12991
13194
|
const scriptDir = path.join(workspaceDir, ".metheus", "runner-runtime", "local-ai-scratch");
|