metheus-governance-mcp-cli 0.2.270 → 0.2.271
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/lib/runner-helpers.mjs
CHANGED
|
@@ -254,12 +254,24 @@ function normalizePendingSelectionOptions(rawOptions) {
|
|
|
254
254
|
};
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
+
function resolveArchiveRecordEventTime(record) {
|
|
258
|
+
const normalizedRecord = safeObject(record);
|
|
259
|
+
const parsedArchive = safeObject(normalizedRecord.parsedArchive);
|
|
260
|
+
return firstNonEmptyString([
|
|
261
|
+
normalizedRecord.sourceOccurredAt,
|
|
262
|
+
parsedArchive.occurredAt,
|
|
263
|
+
parsedArchive.occurred_at,
|
|
264
|
+
normalizedRecord.createdAt,
|
|
265
|
+
normalizedRecord.updatedAt,
|
|
266
|
+
]);
|
|
267
|
+
}
|
|
268
|
+
|
|
257
269
|
function isArchiveRecordWithinPendingAgeLimit(record, rawOptions) {
|
|
258
270
|
const options = normalizePendingSelectionOptions(rawOptions);
|
|
259
271
|
if (!(options.maxPendingAgeMs > 0)) {
|
|
260
272
|
return true;
|
|
261
273
|
}
|
|
262
|
-
const recordTime = Date.parse(
|
|
274
|
+
const recordTime = Date.parse(resolveArchiveRecordEventTime(record));
|
|
263
275
|
if (!Number.isFinite(recordTime)) {
|
|
264
276
|
return true;
|
|
265
277
|
}
|
|
@@ -411,8 +423,8 @@ function contextRelatednessScore(record, selectedRecord, rawOptions) {
|
|
|
411
423
|
}
|
|
412
424
|
|
|
413
425
|
export function compareArchiveCommentRecords(left, right) {
|
|
414
|
-
const leftTime =
|
|
415
|
-
const rightTime =
|
|
426
|
+
const leftTime = resolveArchiveRecordEventTime(left);
|
|
427
|
+
const rightTime = resolveArchiveRecordEventTime(right);
|
|
416
428
|
if (leftTime && rightTime && leftTime !== rightTime) {
|
|
417
429
|
return leftTime < rightTime ? -1 : 1;
|
|
418
430
|
}
|
|
@@ -521,13 +533,18 @@ export function buildRunnerRouteStateFromComment(record, patch = {}) {
|
|
|
521
533
|
export function normalizeArchiveCommentRecord(rawComment, parseArchivedChatComment) {
|
|
522
534
|
const comment = safeObject(rawComment);
|
|
523
535
|
const body = String(comment.body || "").trim();
|
|
536
|
+
const parsedArchive = typeof parseArchivedChatComment === "function" ? parseArchivedChatComment(body) : null;
|
|
524
537
|
return {
|
|
525
538
|
id: String(comment.id || "").trim(),
|
|
526
539
|
body,
|
|
527
540
|
createdAt: firstNonEmptyString([comment.created_at, comment.createdAt, comment.updated_at, comment.updatedAt]),
|
|
528
541
|
updatedAt: firstNonEmptyString([comment.updated_at, comment.updatedAt]),
|
|
529
542
|
authorUserID: firstNonEmptyString([comment.author_user_id, comment.authorUserId, comment.created_by]),
|
|
530
|
-
|
|
543
|
+
sourceOccurredAt: firstNonEmptyString([
|
|
544
|
+
safeObject(parsedArchive).occurredAt,
|
|
545
|
+
safeObject(parsedArchive).occurred_at,
|
|
546
|
+
]),
|
|
547
|
+
parsedArchive,
|
|
531
548
|
};
|
|
532
549
|
}
|
|
533
550
|
|
|
@@ -51,6 +51,48 @@ function detectDirectedManagedReplyTarget({
|
|
|
51
51
|
return "";
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
const DIRECTED_MANAGED_REPLY_ENGLISH_ACTION_PATTERN = "\\b(?:say|tell|greet|reply|answer|introduce|mention)\\b";
|
|
55
|
+
const DIRECTED_MANAGED_REPLY_KOREAN_ACTION_PATTERN = "(?:\\uC778\\uC0AC|\\uB9D0|\\uC804\\uB2EC|\\uB2F5|\\uC18C\\uAC1C|\\uC5B8\\uAE09)";
|
|
56
|
+
const DIRECTED_MANAGED_REPLY_ACTION_PATTERN = `(?:${DIRECTED_MANAGED_REPLY_ENGLISH_ACTION_PATTERN}|${DIRECTED_MANAGED_REPLY_KOREAN_ACTION_PATTERN})`;
|
|
57
|
+
const DIRECTED_MANAGED_REPLY_POSTPOSITION_PATTERN = "(?:\\uC5D0\\uAC8C|\\uD55C\\uD14C|\\uAED8|\\uBCF4\\uACE0)";
|
|
58
|
+
|
|
59
|
+
function detectDirectedManagedReplyTargetV2({
|
|
60
|
+
text,
|
|
61
|
+
currentBotSelector = "",
|
|
62
|
+
managedMentions = [],
|
|
63
|
+
}) {
|
|
64
|
+
const normalizedText = String(text || "").trim();
|
|
65
|
+
const currentSelector = String(currentBotSelector || "").trim().toLowerCase();
|
|
66
|
+
if (!normalizedText || !currentSelector) {
|
|
67
|
+
return "";
|
|
68
|
+
}
|
|
69
|
+
const instructionPattern = new RegExp(DIRECTED_MANAGED_REPLY_ACTION_PATTERN, "iu");
|
|
70
|
+
if (!instructionPattern.test(normalizedText)) {
|
|
71
|
+
return "";
|
|
72
|
+
}
|
|
73
|
+
const candidates = ensureArray(managedMentions)
|
|
74
|
+
.map((item) => String(item || "").trim().toLowerCase())
|
|
75
|
+
.filter((item) => item && item !== currentSelector);
|
|
76
|
+
for (const selector of candidates) {
|
|
77
|
+
const escapedSelector = escapeRegexText(String(selector || "").replace(/^@+/, ""));
|
|
78
|
+
const explicitTargetPattern = new RegExp(
|
|
79
|
+
`(?:@${escapedSelector}\\s*(?:${DIRECTED_MANAGED_REPLY_POSTPOSITION_PATTERN})?|(?:to|for)\\s+@${escapedSelector}\\b)`,
|
|
80
|
+
"iu",
|
|
81
|
+
);
|
|
82
|
+
if (explicitTargetPattern.test(normalizedText)) {
|
|
83
|
+
return selector;
|
|
84
|
+
}
|
|
85
|
+
const instructionWindowPattern = new RegExp(
|
|
86
|
+
`@${escapedSelector}(?:\\s*(?:${DIRECTED_MANAGED_REPLY_POSTPOSITION_PATTERN}))?(?:[^@\\n]{0,32}?)${DIRECTED_MANAGED_REPLY_ACTION_PATTERN}`,
|
|
87
|
+
"iu",
|
|
88
|
+
);
|
|
89
|
+
if (instructionWindowPattern.test(normalizedText)) {
|
|
90
|
+
return selector;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return "";
|
|
94
|
+
}
|
|
95
|
+
|
|
54
96
|
export async function resolveHumanIntentContext({
|
|
55
97
|
selectedRecord,
|
|
56
98
|
normalizedRoute,
|
|
@@ -118,7 +160,7 @@ export async function resolveHumanIntentContext({
|
|
|
118
160
|
runnerHumanIntentPromises.set(cacheKey, promise);
|
|
119
161
|
}
|
|
120
162
|
let humanIntent = await runnerHumanIntentPromises.get(cacheKey);
|
|
121
|
-
const directedReplyTargetSelector =
|
|
163
|
+
const directedReplyTargetSelector = detectDirectedManagedReplyTargetV2({
|
|
122
164
|
text: parsed.body,
|
|
123
165
|
currentBotSelector,
|
|
124
166
|
managedMentions,
|
|
@@ -740,11 +740,11 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
740
740
|
);
|
|
741
741
|
}
|
|
742
742
|
|
|
743
|
-
try {
|
|
744
|
-
const pendingSelection = selectPendingArchiveComments(
|
|
745
|
-
[
|
|
746
|
-
{
|
|
747
|
-
id: "dup-comment-1",
|
|
743
|
+
try {
|
|
744
|
+
const pendingSelection = selectPendingArchiveComments(
|
|
745
|
+
[
|
|
746
|
+
{
|
|
747
|
+
id: "dup-comment-1",
|
|
748
748
|
createdAt: "2026-03-18T00:00:01.000Z",
|
|
749
749
|
updatedAt: "2026-03-18T00:00:01.000Z",
|
|
750
750
|
parsedArchive: { kind: "telegram_message", chatID: "-1001", messageID: 353, body: "@RyoAI_bot first copy" },
|
|
@@ -770,14 +770,83 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
770
770
|
} catch (err) {
|
|
771
771
|
push(
|
|
772
772
|
"runner_pending_selection_ignores_duplicate_archived_inbound_message_ids",
|
|
773
|
-
false,
|
|
774
|
-
String(err?.message || err),
|
|
775
|
-
);
|
|
776
|
-
}
|
|
777
|
-
|
|
773
|
+
false,
|
|
774
|
+
String(err?.message || err),
|
|
775
|
+
);
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
try {
|
|
779
|
+
const nowMs = Date.parse("2026-03-31T12:00:00.000Z");
|
|
780
|
+
const pendingSelection = selectPendingArchiveComments(
|
|
781
|
+
[
|
|
782
|
+
{
|
|
783
|
+
id: "cursor-comment",
|
|
784
|
+
createdAt: "2026-03-31T11:55:00.000Z",
|
|
785
|
+
updatedAt: "2026-03-31T11:55:00.000Z",
|
|
786
|
+
sourceOccurredAt: "2026-03-31T09:55:00.000Z",
|
|
787
|
+
parsedArchive: {
|
|
788
|
+
kind: "telegram_message",
|
|
789
|
+
chatID: "-1001",
|
|
790
|
+
messageID: 1145,
|
|
791
|
+
occurredAt: "2026-03-31T09:55:00.000Z",
|
|
792
|
+
body: "@RyoAI_bot 기준 댓글",
|
|
793
|
+
},
|
|
794
|
+
},
|
|
795
|
+
{
|
|
796
|
+
id: "stale-source-comment",
|
|
797
|
+
createdAt: "2026-03-31T11:59:58.000Z",
|
|
798
|
+
updatedAt: "2026-03-31T11:59:58.000Z",
|
|
799
|
+
sourceOccurredAt: "2026-03-31T10:00:00.000Z",
|
|
800
|
+
parsedArchive: {
|
|
801
|
+
kind: "telegram_message",
|
|
802
|
+
chatID: "-1001",
|
|
803
|
+
messageID: 325,
|
|
804
|
+
occurredAt: "2026-03-31T10:00:00.000Z",
|
|
805
|
+
body: "@RyoAI_bot 오래된 하이",
|
|
806
|
+
},
|
|
807
|
+
},
|
|
808
|
+
{
|
|
809
|
+
id: "fresh-source-comment",
|
|
810
|
+
createdAt: "2026-03-31T11:59:59.000Z",
|
|
811
|
+
updatedAt: "2026-03-31T11:59:59.000Z",
|
|
812
|
+
sourceOccurredAt: "2026-03-31T11:57:00.000Z",
|
|
813
|
+
parsedArchive: {
|
|
814
|
+
kind: "telegram_message",
|
|
815
|
+
chatID: "-1001",
|
|
816
|
+
messageID: 1146,
|
|
817
|
+
occurredAt: "2026-03-31T11:57:00.000Z",
|
|
818
|
+
body: "@RyoAI_bot 최신 하이",
|
|
819
|
+
},
|
|
820
|
+
},
|
|
821
|
+
],
|
|
822
|
+
{
|
|
823
|
+
last_processed_comment_id: "cursor-comment",
|
|
824
|
+
},
|
|
825
|
+
"start",
|
|
826
|
+
(record) => record,
|
|
827
|
+
{
|
|
828
|
+
maxPendingAgeMs: 15 * 60 * 1000,
|
|
829
|
+
nowMs,
|
|
830
|
+
},
|
|
831
|
+
);
|
|
832
|
+
push(
|
|
833
|
+
"runner_pending_selection_uses_source_occurrence_time_for_stale_filtering",
|
|
834
|
+
pendingSelection.pending.length === 1
|
|
835
|
+
&& String(pendingSelection.pending[0]?.id || "") === "fresh-source-comment"
|
|
836
|
+
&& ensureArray(pendingSelection.staleSkipped).some((record) => String(record?.id || "") === "stale-source-comment"),
|
|
837
|
+
`pending=${pendingSelection.pending.map((item) => item.id).join(",") || "(none)"} stale=${ensureArray(pendingSelection.staleSkipped).map((item) => item.id).join(",") || "(none)"}`,
|
|
838
|
+
);
|
|
839
|
+
} catch (err) {
|
|
840
|
+
push(
|
|
841
|
+
"runner_pending_selection_uses_source_occurrence_time_for_stale_filtering",
|
|
842
|
+
false,
|
|
843
|
+
String(err?.message || err),
|
|
844
|
+
);
|
|
845
|
+
}
|
|
846
|
+
|
|
778
847
|
try {
|
|
779
848
|
const duplicateComments = [
|
|
780
|
-
{
|
|
849
|
+
{
|
|
781
850
|
id: "dup-comment-earliest",
|
|
782
851
|
createdAt: "2026-03-18T00:00:01.000Z",
|
|
783
852
|
updatedAt: "2026-03-18T00:00:01.000Z",
|
|
@@ -3225,15 +3294,76 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
3225
3294
|
&& aliasHumanIntentContext?.reusedPersistedContract === true,
|
|
3226
3295
|
`managedMentions=${JSON.stringify(ensureArray(aliasHumanIntentContext?.managedMentions))} reused=${String(aliasHumanIntentContext?.reusedPersistedContract)}`,
|
|
3227
3296
|
);
|
|
3228
|
-
} catch (err) {
|
|
3229
|
-
push(
|
|
3230
|
-
"runner_human_intent_context_ignores_raw_alias_selector_for_managed_mentions",
|
|
3231
|
-
false,
|
|
3232
|
-
String(err?.message || err),
|
|
3233
|
-
);
|
|
3234
|
-
}
|
|
3235
|
-
|
|
3236
|
-
|
|
3297
|
+
} catch (err) {
|
|
3298
|
+
push(
|
|
3299
|
+
"runner_human_intent_context_ignores_raw_alias_selector_for_managed_mentions",
|
|
3300
|
+
false,
|
|
3301
|
+
String(err?.message || err),
|
|
3302
|
+
);
|
|
3303
|
+
}
|
|
3304
|
+
|
|
3305
|
+
try {
|
|
3306
|
+
const replyTargetIntentContext = await resolveHumanIntentContext({
|
|
3307
|
+
selectedRecord: {
|
|
3308
|
+
id: "comment-directed-reply-target-korean",
|
|
3309
|
+
parsedArchive: {
|
|
3310
|
+
kind: "telegram_message",
|
|
3311
|
+
body: "@RyoAI_bot 너가 @SangHoon01_bot 인사 시켜봐",
|
|
3312
|
+
senderIsBot: false,
|
|
3313
|
+
},
|
|
3314
|
+
},
|
|
3315
|
+
normalizedRoute: {
|
|
3316
|
+
name: "telegram-monitor-ryoai-bot-2",
|
|
3317
|
+
},
|
|
3318
|
+
bot: {
|
|
3319
|
+
username: "ryoai_bot",
|
|
3320
|
+
name: "RyoAI_bot",
|
|
3321
|
+
},
|
|
3322
|
+
executionPlan: {},
|
|
3323
|
+
deps: {
|
|
3324
|
+
resolveConversationPeerBots: () => [
|
|
3325
|
+
{ id: "bot-self-1", name: "RyoAI_bot" },
|
|
3326
|
+
{ id: "bot-peer-1", name: "SangHoon01_bot" },
|
|
3327
|
+
],
|
|
3328
|
+
},
|
|
3329
|
+
intentDeps: {
|
|
3330
|
+
normalizeMentionSelector: normalizeSelftestMentionSelector,
|
|
3331
|
+
buildConversationPeerMap: (_bot, _route, runtimeDeps) => new Map(
|
|
3332
|
+
ensureArray(runtimeDeps?.resolveConversationPeerBots?.() || []).map((item) => {
|
|
3333
|
+
const selector = normalizeSelftestMentionSelector(item?.name || item?.username);
|
|
3334
|
+
return [selector, item];
|
|
3335
|
+
}).filter(([selector]) => selector),
|
|
3336
|
+
),
|
|
3337
|
+
extractOrderedMentionSelectors: (text) => Array.from(String(text || "").matchAll(/@([A-Za-z0-9_]+)/g)).map((match) => normalizeSelftestMentionSelector(match[1] || "")),
|
|
3338
|
+
uniqueOrdered: normalizeSelftestConversationSelectorList,
|
|
3339
|
+
buildHumanIntentFromPersistedRunnerRequest: () => null,
|
|
3340
|
+
buildRunnerHumanIntentCacheKey: () => "directed-reply-target-korean",
|
|
3341
|
+
runnerHumanIntentPromises: new Map(),
|
|
3342
|
+
analyzeHumanConversationIntentWithContractResolver: async () => ({
|
|
3343
|
+
intentMode: "single_bot",
|
|
3344
|
+
replyExpectation: "actionable",
|
|
3345
|
+
intentType: "actionable_request",
|
|
3346
|
+
}),
|
|
3347
|
+
scheduleRunnerHumanIntentCacheCleanup: () => {},
|
|
3348
|
+
isCompleteHumanIntentContract: () => true,
|
|
3349
|
+
normalizeHumanIntentType: (value, fallback = "") => String(value || "").trim() || fallback,
|
|
3350
|
+
},
|
|
3351
|
+
});
|
|
3352
|
+
push(
|
|
3353
|
+
"runner_human_intent_context_detects_korean_directed_reply_target",
|
|
3354
|
+
String(replyTargetIntentContext?.humanIntent?.replyTargetBotSelector || "") === "sanghoon01_bot"
|
|
3355
|
+
&& JSON.stringify(ensureArray(replyTargetIntentContext?.managedMentions || [])) === JSON.stringify(["ryoai_bot", "sanghoon01_bot"]),
|
|
3356
|
+
`reply_target=${String(replyTargetIntentContext?.humanIntent?.replyTargetBotSelector || "(none)")} managed=${JSON.stringify(ensureArray(replyTargetIntentContext?.managedMentions || []))}`,
|
|
3357
|
+
);
|
|
3358
|
+
} catch (err) {
|
|
3359
|
+
push(
|
|
3360
|
+
"runner_human_intent_context_detects_korean_directed_reply_target",
|
|
3361
|
+
false,
|
|
3362
|
+
String(err?.message || err),
|
|
3363
|
+
);
|
|
3364
|
+
}
|
|
3365
|
+
|
|
3366
|
+
const mentionOverridesReplyForUnmentionedBot = evaluateTelegramRunnerTrigger(
|
|
3237
3367
|
{
|
|
3238
3368
|
id: "comment-2b",
|
|
3239
3369
|
parsedArchive: {
|