metheus-governance-mcp-cli 0.2.281 → 0.2.283
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 +200 -128
- package/lib/local-ai-adapters.mjs +34 -3
- package/lib/runner-orchestration-failure.mjs +14 -2
- package/lib/runner-orchestration-visibility.mjs +152 -18
- package/lib/runner-recorder-lifecycle-handoff.mjs +5 -0
- package/lib/runner-runtime.mjs +21 -0
- package/lib/selftest-bot-commands.mjs +14 -1
- package/lib/selftest-runner-scenarios.mjs +174 -5
- package/package.json +1 -1
package/cli.mjs
CHANGED
|
@@ -25,9 +25,10 @@ import {
|
|
|
25
25
|
resolveRolePlannerAuditorModelDisplayName,
|
|
26
26
|
resolveRolePlannerModelDisplayName,
|
|
27
27
|
resolveRolePlannerRepairModelDisplayName,
|
|
28
|
-
resolveResponderAdjudicatorModelDisplayName,
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
resolveResponderAdjudicatorModelDisplayName,
|
|
29
|
+
resolveGeminiHeadlessExecutionModel,
|
|
30
|
+
resolveGeminiReasoningConfig,
|
|
31
|
+
suggestLocalAIModelDisplayName,
|
|
31
32
|
SUPPORTED_LOCAL_AI_CLIENTS,
|
|
32
33
|
normalizeLocalAIClientName,
|
|
33
34
|
normalizeLocalAIPermissionMode,
|
|
@@ -3111,20 +3112,25 @@ function normalizeBotRunnerRequests(rawRequests, nowMs = Date.now()) {
|
|
|
3111
3112
|
entry.sourceMessageBotUsername,
|
|
3112
3113
|
]),
|
|
3113
3114
|
});
|
|
3114
|
-
normalized[requestKey] = {
|
|
3115
|
-
request_key: requestKey,
|
|
3116
|
-
project_id: String(entry.project_id || entry.projectID || "").trim(),
|
|
3117
|
-
provider: String(entry.provider || "").trim(),
|
|
3118
|
-
chat_id: firstNonEmptyString([
|
|
3119
|
-
entry.chat_id,
|
|
3120
|
-
entry.chatID,
|
|
3121
|
-
normalizedSourceMessageEnvelope.chat_id,
|
|
3122
|
-
]),
|
|
3123
|
-
|
|
3124
|
-
entry.
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3115
|
+
normalized[requestKey] = {
|
|
3116
|
+
request_key: requestKey,
|
|
3117
|
+
project_id: String(entry.project_id || entry.projectID || "").trim(),
|
|
3118
|
+
provider: String(entry.provider || "").trim(),
|
|
3119
|
+
chat_id: firstNonEmptyString([
|
|
3120
|
+
entry.chat_id,
|
|
3121
|
+
entry.chatID,
|
|
3122
|
+
normalizedSourceMessageEnvelope.chat_id,
|
|
3123
|
+
]),
|
|
3124
|
+
canonical_human_message_key: firstNonEmptyString([
|
|
3125
|
+
entry.canonical_human_message_key,
|
|
3126
|
+
entry.canonicalHumanMessageKey,
|
|
3127
|
+
normalizedSourceMessageEnvelope.canonical_human_message_key,
|
|
3128
|
+
]),
|
|
3129
|
+
source_message_id: intFromRawAllowZero(
|
|
3130
|
+
entry.source_message_id
|
|
3131
|
+
|| entry.sourceMessageID
|
|
3132
|
+
|| normalizedSourceMessageEnvelope.message_id,
|
|
3133
|
+
0,
|
|
3128
3134
|
) || undefined,
|
|
3129
3135
|
source_message_thread_id: intFromRawAllowZero(
|
|
3130
3136
|
entry.source_message_thread_id
|
|
@@ -3813,18 +3819,35 @@ function shouldBypassRunnerStartupLoopForContractFollowup({
|
|
|
3813
3819
|
return true;
|
|
3814
3820
|
}
|
|
3815
3821
|
|
|
3816
|
-
function findRunnerRequestsForMessageID(state, normalizedRoute, selectors = {}) {
|
|
3817
|
-
const chatID = String(selectors.chatID || "").trim();
|
|
3818
|
-
const messageID = intFromRawAllowZero(selectors.messageID, 0);
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3822
|
+
function findRunnerRequestsForMessageID(state, normalizedRoute, selectors = {}) {
|
|
3823
|
+
const chatID = String(selectors.chatID || "").trim();
|
|
3824
|
+
const messageID = intFromRawAllowZero(selectors.messageID, 0);
|
|
3825
|
+
const canonicalHumanMessageKey = String(selectors.canonicalHumanMessageKey || "").trim();
|
|
3826
|
+
if (!chatID || (messageID <= 0 && !canonicalHumanMessageKey)) {
|
|
3827
|
+
return [];
|
|
3828
|
+
}
|
|
3829
|
+
return findRunnerRequestsForScope(state, normalizedRoute, { chatID })
|
|
3830
|
+
.filter((entryRaw) => {
|
|
3831
|
+
const entry = safeObject(entryRaw);
|
|
3832
|
+
if (canonicalHumanMessageKey) {
|
|
3833
|
+
const requestCanonicalHumanMessageKey = firstNonEmptyString([
|
|
3834
|
+
entry.canonical_human_message_key,
|
|
3835
|
+
safeObject(entry.source_message_envelope).canonical_human_message_key,
|
|
3836
|
+
buildRunnerCanonicalHumanInboundKey(safeObject(entry.source_message_envelope)),
|
|
3837
|
+
]);
|
|
3838
|
+
if (requestCanonicalHumanMessageKey === canonicalHumanMessageKey) {
|
|
3839
|
+
return true;
|
|
3840
|
+
}
|
|
3841
|
+
}
|
|
3842
|
+
return (
|
|
3843
|
+
messageID > 0
|
|
3844
|
+
&& (
|
|
3845
|
+
intFromRawAllowZero(entry.source_message_id, 0) === messageID
|
|
3846
|
+
|| intFromRawAllowZero(entry.last_source_message_id, 0) === messageID
|
|
3847
|
+
)
|
|
3848
|
+
);
|
|
3849
|
+
});
|
|
3850
|
+
}
|
|
3828
3851
|
|
|
3829
3852
|
function sortRunnerRequestEntriesNewestFirst(entries = []) {
|
|
3830
3853
|
return ensureArray(entries).slice().sort((leftRaw, rightRaw) => {
|
|
@@ -3839,24 +3862,26 @@ function sortRunnerRequestEntriesNewestFirst(entries = []) {
|
|
|
3839
3862
|
});
|
|
3840
3863
|
}
|
|
3841
3864
|
|
|
3842
|
-
async function findServerRunnerRequestForMessageID({
|
|
3843
|
-
normalizedRoute,
|
|
3844
|
-
runtime,
|
|
3845
|
-
chatID,
|
|
3846
|
-
messageID,
|
|
3847
|
-
|
|
3865
|
+
async function findServerRunnerRequestForMessageID({
|
|
3866
|
+
normalizedRoute,
|
|
3867
|
+
runtime,
|
|
3868
|
+
chatID,
|
|
3869
|
+
messageID,
|
|
3870
|
+
canonicalHumanMessageKey = "",
|
|
3871
|
+
}) {
|
|
3848
3872
|
const projectID = String(normalizedRoute?.projectID || "").trim();
|
|
3849
3873
|
const provider = String(normalizedRoute?.provider || "").trim();
|
|
3850
|
-
const normalizedChatID = String(chatID || "").trim();
|
|
3851
|
-
const normalizedMessageID = intFromRawAllowZero(messageID, 0);
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|| !
|
|
3856
|
-
||
|
|
3857
|
-
|| !
|
|
3858
|
-
|| !runtime?.
|
|
3859
|
-
|
|
3874
|
+
const normalizedChatID = String(chatID || "").trim();
|
|
3875
|
+
const normalizedMessageID = intFromRawAllowZero(messageID, 0);
|
|
3876
|
+
const normalizedCanonicalHumanMessageKey = String(canonicalHumanMessageKey || "").trim();
|
|
3877
|
+
if (
|
|
3878
|
+
!projectID
|
|
3879
|
+
|| !provider
|
|
3880
|
+
|| !normalizedChatID
|
|
3881
|
+
|| (normalizedMessageID <= 0 && !normalizedCanonicalHumanMessageKey)
|
|
3882
|
+
|| !runtime?.baseURL
|
|
3883
|
+
|| !runtime?.token
|
|
3884
|
+
) {
|
|
3860
3885
|
return null;
|
|
3861
3886
|
}
|
|
3862
3887
|
try {
|
|
@@ -3869,18 +3894,29 @@ async function findServerRunnerRequestForMessageID({
|
|
|
3869
3894
|
limit: 500,
|
|
3870
3895
|
offset: 0,
|
|
3871
3896
|
});
|
|
3872
|
-
const matched = sortRunnerRequestEntriesNewestFirst(serverRequests.filter((entryRaw) => {
|
|
3873
|
-
const entry = safeObject(entryRaw);
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
)
|
|
3882
|
-
|
|
3883
|
-
|
|
3897
|
+
const matched = sortRunnerRequestEntriesNewestFirst(serverRequests.filter((entryRaw) => {
|
|
3898
|
+
const entry = safeObject(entryRaw);
|
|
3899
|
+
const requestCanonicalHumanMessageKey = firstNonEmptyString([
|
|
3900
|
+
entry.canonical_human_message_key,
|
|
3901
|
+
safeObject(entry.source_message_envelope).canonical_human_message_key,
|
|
3902
|
+
buildRunnerCanonicalHumanInboundKey(safeObject(entry.source_message_envelope)),
|
|
3903
|
+
]);
|
|
3904
|
+
return (
|
|
3905
|
+
String(entry.project_id || "").trim() === projectID
|
|
3906
|
+
&& String(entry.provider || "").trim() === provider
|
|
3907
|
+
&& String(entry.chat_id || "").trim() === normalizedChatID
|
|
3908
|
+
&& (
|
|
3909
|
+
(normalizedCanonicalHumanMessageKey && requestCanonicalHumanMessageKey === normalizedCanonicalHumanMessageKey)
|
|
3910
|
+
|| (
|
|
3911
|
+
normalizedMessageID > 0
|
|
3912
|
+
&& (
|
|
3913
|
+
intFromRawAllowZero(entry.source_message_id, 0) === normalizedMessageID
|
|
3914
|
+
|| intFromRawAllowZero(entry.last_source_message_id, 0) === normalizedMessageID
|
|
3915
|
+
)
|
|
3916
|
+
)
|
|
3917
|
+
)
|
|
3918
|
+
);
|
|
3919
|
+
}));
|
|
3884
3920
|
return safeObject(matched[0]);
|
|
3885
3921
|
} catch {
|
|
3886
3922
|
return null;
|
|
@@ -4109,12 +4145,14 @@ function buildRunnerValidationAndDeliverySummary({
|
|
|
4109
4145
|
responseContractValidationStatus = "",
|
|
4110
4146
|
responseContractValidationReason = "",
|
|
4111
4147
|
responseContractValidationTargets = [],
|
|
4112
|
-
assignmentValidationStatus = "",
|
|
4113
|
-
assignmentValidationReason = "",
|
|
4114
|
-
assignmentValidationModes = [],
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4148
|
+
assignmentValidationStatus = "",
|
|
4149
|
+
assignmentValidationReason = "",
|
|
4150
|
+
assignmentValidationModes = [],
|
|
4151
|
+
failureReplyClassification = "",
|
|
4152
|
+
failureFacts = {},
|
|
4153
|
+
deliveryStatus = "",
|
|
4154
|
+
archiveStatus = "",
|
|
4155
|
+
transportError = "",
|
|
4118
4156
|
archiveError = "",
|
|
4119
4157
|
sourceMessageEnvelope = {},
|
|
4120
4158
|
lastReplyMessageEnvelope = {},
|
|
@@ -4321,25 +4359,27 @@ function pickRunnerSharedConversationSourceRequest(entries = [], excludeRequestK
|
|
|
4321
4359
|
return safeObject(matched[0]);
|
|
4322
4360
|
}
|
|
4323
4361
|
|
|
4324
|
-
async function findServerRunnerConversationSourceRequestForMessageID({
|
|
4325
|
-
normalizedRoute,
|
|
4326
|
-
runtime,
|
|
4327
|
-
chatID,
|
|
4328
|
-
messageID,
|
|
4329
|
-
|
|
4330
|
-
|
|
4362
|
+
async function findServerRunnerConversationSourceRequestForMessageID({
|
|
4363
|
+
normalizedRoute,
|
|
4364
|
+
runtime,
|
|
4365
|
+
chatID,
|
|
4366
|
+
messageID,
|
|
4367
|
+
canonicalHumanMessageKey = "",
|
|
4368
|
+
excludeRequestKey = "",
|
|
4369
|
+
}) {
|
|
4331
4370
|
const projectID = String(normalizedRoute?.projectID || "").trim();
|
|
4332
4371
|
const provider = String(normalizedRoute?.provider || "").trim();
|
|
4333
|
-
const normalizedChatID = String(chatID || "").trim();
|
|
4334
|
-
const normalizedMessageID = intFromRawAllowZero(messageID, 0);
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|| !
|
|
4339
|
-
||
|
|
4340
|
-
|| !
|
|
4341
|
-
|| !runtime?.
|
|
4342
|
-
|
|
4372
|
+
const normalizedChatID = String(chatID || "").trim();
|
|
4373
|
+
const normalizedMessageID = intFromRawAllowZero(messageID, 0);
|
|
4374
|
+
const normalizedCanonicalHumanMessageKey = String(canonicalHumanMessageKey || "").trim();
|
|
4375
|
+
if (
|
|
4376
|
+
!projectID
|
|
4377
|
+
|| !provider
|
|
4378
|
+
|| !normalizedChatID
|
|
4379
|
+
|| (normalizedMessageID <= 0 && !normalizedCanonicalHumanMessageKey)
|
|
4380
|
+
|| !runtime?.baseURL
|
|
4381
|
+
|| !runtime?.token
|
|
4382
|
+
) {
|
|
4343
4383
|
return null;
|
|
4344
4384
|
}
|
|
4345
4385
|
try {
|
|
@@ -4352,18 +4392,29 @@ async function findServerRunnerConversationSourceRequestForMessageID({
|
|
|
4352
4392
|
limit: 500,
|
|
4353
4393
|
offset: 0,
|
|
4354
4394
|
});
|
|
4355
|
-
const matched = serverRequests.filter((entryRaw) => {
|
|
4356
|
-
const entry = safeObject(entryRaw);
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
)
|
|
4365
|
-
|
|
4366
|
-
|
|
4395
|
+
const matched = serverRequests.filter((entryRaw) => {
|
|
4396
|
+
const entry = safeObject(entryRaw);
|
|
4397
|
+
const requestCanonicalHumanMessageKey = firstNonEmptyString([
|
|
4398
|
+
entry.canonical_human_message_key,
|
|
4399
|
+
safeObject(entry.source_message_envelope).canonical_human_message_key,
|
|
4400
|
+
buildRunnerCanonicalHumanInboundKey(safeObject(entry.source_message_envelope)),
|
|
4401
|
+
]);
|
|
4402
|
+
return (
|
|
4403
|
+
String(entry.project_id || "").trim() === projectID
|
|
4404
|
+
&& String(entry.provider || "").trim() === provider
|
|
4405
|
+
&& String(entry.chat_id || "").trim() === normalizedChatID
|
|
4406
|
+
&& (
|
|
4407
|
+
(normalizedCanonicalHumanMessageKey && requestCanonicalHumanMessageKey === normalizedCanonicalHumanMessageKey)
|
|
4408
|
+
|| (
|
|
4409
|
+
normalizedMessageID > 0
|
|
4410
|
+
&& (
|
|
4411
|
+
intFromRawAllowZero(entry.source_message_id, 0) === normalizedMessageID
|
|
4412
|
+
|| intFromRawAllowZero(entry.last_source_message_id, 0) === normalizedMessageID
|
|
4413
|
+
)
|
|
4414
|
+
)
|
|
4415
|
+
)
|
|
4416
|
+
);
|
|
4417
|
+
});
|
|
4367
4418
|
return pickRunnerSharedConversationSourceRequest(matched, excludeRequestKey);
|
|
4368
4419
|
} catch {
|
|
4369
4420
|
return null;
|
|
@@ -5026,13 +5077,14 @@ async function claimRunnerRequestForHumanComment({
|
|
|
5026
5077
|
runtime,
|
|
5027
5078
|
archiveThreadID,
|
|
5028
5079
|
});
|
|
5029
|
-
const replyChainContext = safeObject(replyChainResolution.replyChainContext);
|
|
5080
|
+
const replyChainContext = safeObject(replyChainResolution.replyChainContext);
|
|
5030
5081
|
const referencedRequest = safeObject(replyChainContext.referencedRequest);
|
|
5031
5082
|
const resolvedNormalizedIntent = resolveRunnerRequestClaimIntent({
|
|
5032
5083
|
normalizedIntent,
|
|
5033
5084
|
});
|
|
5034
|
-
|
|
5035
|
-
|
|
5085
|
+
const canonicalHumanMessageKey = buildRunnerCanonicalHumanInboundKey(parsed);
|
|
5086
|
+
let stateForClaim = safeObject(replyChainResolution.state);
|
|
5087
|
+
const normalizedSharedHumanIntent = safeObject(sharedHumanIntent);
|
|
5036
5088
|
const provisionalConversationID = String(
|
|
5037
5089
|
parsed.conversationID
|
|
5038
5090
|
|| replyChainContext.conversationID
|
|
@@ -5067,29 +5119,31 @@ async function claimRunnerRequestForHumanComment({
|
|
|
5067
5119
|
};
|
|
5068
5120
|
}
|
|
5069
5121
|
const currentMessageID = intFromRawAllowZero(parsed.messageID, 0);
|
|
5070
|
-
let sharedConversationSource = currentMessageID > 0
|
|
5071
|
-
? pickRunnerSharedConversationSourceRequest(
|
|
5072
|
-
findRunnerRequestsForMessageID(stateForClaim, normalizedRoute, {
|
|
5073
|
-
chatID: String(parsed.chatID || parsed.chatId || "").trim(),
|
|
5074
|
-
messageID: currentMessageID,
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5122
|
+
let sharedConversationSource = currentMessageID > 0
|
|
5123
|
+
? pickRunnerSharedConversationSourceRequest(
|
|
5124
|
+
findRunnerRequestsForMessageID(stateForClaim, normalizedRoute, {
|
|
5125
|
+
chatID: String(parsed.chatID || parsed.chatId || "").trim(),
|
|
5126
|
+
messageID: currentMessageID,
|
|
5127
|
+
canonicalHumanMessageKey,
|
|
5128
|
+
}),
|
|
5129
|
+
provisionalRequestKey,
|
|
5130
|
+
)
|
|
5131
|
+
: {};
|
|
5079
5132
|
if (
|
|
5080
5133
|
!Object.keys(sharedConversationSource).length
|
|
5081
5134
|
&& currentMessageID > 0
|
|
5082
5135
|
&& runtime?.baseURL
|
|
5083
5136
|
&& runtime?.token
|
|
5084
5137
|
) {
|
|
5085
|
-
sharedConversationSource = safeObject(await findServerRunnerConversationSourceRequestForMessageID({
|
|
5086
|
-
normalizedRoute,
|
|
5087
|
-
runtime,
|
|
5088
|
-
chatID: String(parsed.chatID || parsed.chatId || "").trim(),
|
|
5089
|
-
messageID: currentMessageID,
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5138
|
+
sharedConversationSource = safeObject(await findServerRunnerConversationSourceRequestForMessageID({
|
|
5139
|
+
normalizedRoute,
|
|
5140
|
+
runtime,
|
|
5141
|
+
chatID: String(parsed.chatID || parsed.chatId || "").trim(),
|
|
5142
|
+
messageID: currentMessageID,
|
|
5143
|
+
canonicalHumanMessageKey,
|
|
5144
|
+
excludeRequestKey: provisionalRequestKey,
|
|
5145
|
+
}));
|
|
5146
|
+
}
|
|
5093
5147
|
const authorityContext = resolveRunnerHumanCommentAuthorityContext({
|
|
5094
5148
|
normalizedRoute,
|
|
5095
5149
|
selectedRecord,
|
|
@@ -5183,9 +5237,10 @@ async function claimRunnerRequestForHumanComment({
|
|
|
5183
5237
|
provider: String(normalizedRoute?.provider || "").trim(),
|
|
5184
5238
|
chat_id: String(parsed.chatID || parsed.chatId || "").trim(),
|
|
5185
5239
|
source_message_id: intFromRawAllowZero(parsed.messageID, 0) || undefined,
|
|
5186
|
-
source_message_thread_id: intFromRawAllowZero(parsed.messageThreadID, 0) || undefined,
|
|
5187
|
-
source_message_body: String(parsed.body || "").trim(),
|
|
5188
|
-
|
|
5240
|
+
source_message_thread_id: intFromRawAllowZero(parsed.messageThreadID, 0) || undefined,
|
|
5241
|
+
source_message_body: String(parsed.body || "").trim(),
|
|
5242
|
+
canonical_human_message_key: canonicalHumanMessageKey,
|
|
5243
|
+
source_message_origin: String(sourceMessageEnvelope.source_origin || "").trim().toLowerCase(),
|
|
5189
5244
|
source_message_route_key: String(sourceMessageEnvelope.source_route_key || "").trim(),
|
|
5190
5245
|
source_message_bot_username: normalizeTelegramMentionUsername(sourceMessageEnvelope.source_bot_username),
|
|
5191
5246
|
source_message_envelope: sourceMessageEnvelope,
|
|
@@ -6329,12 +6384,14 @@ function markRunnerRequestLifecycle({
|
|
|
6329
6384
|
responseContractValidationStatus = "",
|
|
6330
6385
|
responseContractValidationReason = "",
|
|
6331
6386
|
responseContractValidationTargets = [],
|
|
6332
|
-
assignmentValidationStatus = "",
|
|
6333
|
-
assignmentValidationReason = "",
|
|
6334
|
-
assignmentValidationModes = [],
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6387
|
+
assignmentValidationStatus = "",
|
|
6388
|
+
assignmentValidationReason = "",
|
|
6389
|
+
assignmentValidationModes = [],
|
|
6390
|
+
failureReplyClassification = "",
|
|
6391
|
+
failureFacts = {},
|
|
6392
|
+
deliveryStatus = "",
|
|
6393
|
+
archiveStatus = "",
|
|
6394
|
+
transportError = "",
|
|
6338
6395
|
archiveError = "",
|
|
6339
6396
|
lastReplyMessageID = 0,
|
|
6340
6397
|
lastReplyMessageThreadID = 0,
|
|
@@ -6445,6 +6502,8 @@ function markRunnerRequestLifecycle({
|
|
|
6445
6502
|
|| "",
|
|
6446
6503
|
).trim().toLowerCase();
|
|
6447
6504
|
const normalizedOutcome = String(outcome || "").trim().toLowerCase();
|
|
6505
|
+
const normalizedFailureReplyClassification = String(failureReplyClassification || "").trim().toLowerCase();
|
|
6506
|
+
const normalizedFailureFacts = safeObject(failureFacts);
|
|
6448
6507
|
const shouldRemainRunningAfterReply = authoritativeDecisionBundle.should_close_after_reply === true
|
|
6449
6508
|
? false
|
|
6450
6509
|
: authoritativeDecisionBundle.should_close_after_reply === false
|
|
@@ -6459,6 +6518,18 @@ function markRunnerRequestLifecycle({
|
|
|
6459
6518
|
|| rootEffectiveNextExpectedResponders.length > 0
|
|
6460
6519
|
|| continuationSelectors.length > 0
|
|
6461
6520
|
);
|
|
6521
|
+
const shouldRemainRunningAfterError = ["error", "execution_failed"].includes(normalizedOutcome)
|
|
6522
|
+
&& (
|
|
6523
|
+
normalizedFailureFacts.retryable === true
|
|
6524
|
+
|| normalizedFailureReplyClassification === "retryable_failure"
|
|
6525
|
+
)
|
|
6526
|
+
&& authoritativeDecisionBundle.should_close_after_reply !== true
|
|
6527
|
+
&& (
|
|
6528
|
+
nextExecutionContractType === "delegation"
|
|
6529
|
+
|| rootEffectiveExecutionContractTargets.length > 0
|
|
6530
|
+
|| rootEffectiveNextExpectedResponders.length > 0
|
|
6531
|
+
|| continuationSelectors.length > 0
|
|
6532
|
+
);
|
|
6462
6533
|
const nextConversationIntentMode = String(
|
|
6463
6534
|
authoritativeDecisionBundle.conversation_intent_mode
|
|
6464
6535
|
|| conversationIntentMode
|
|
@@ -6495,7 +6566,7 @@ function markRunnerRequestLifecycle({
|
|
|
6495
6566
|
|| normalizedOutcome === "execution_failed"
|
|
6496
6567
|
|| normalizedOutcome === "policy_violation"
|
|
6497
6568
|
) {
|
|
6498
|
-
return "closed";
|
|
6569
|
+
return shouldRemainRunningAfterError ? "running" : "closed";
|
|
6499
6570
|
}
|
|
6500
6571
|
return normalizeRunnerRequestStatus(existing.status);
|
|
6501
6572
|
})();
|
|
@@ -19502,12 +19573,13 @@ TELEGRAM_BOT_REVIEW_TOKEN=review-token
|
|
|
19502
19573
|
push("runner_tui_frame_renders_route_statuses", false, String(err?.message || err));
|
|
19503
19574
|
}
|
|
19504
19575
|
|
|
19505
|
-
await runSelftestBotCommands(push, {
|
|
19506
|
-
cliPath: fileURLToPath(import.meta.url),
|
|
19507
|
-
parseSimpleEnvText,
|
|
19508
|
-
resolveLocalAIExecutionModel,
|
|
19509
|
-
|
|
19510
|
-
|
|
19576
|
+
await runSelftestBotCommands(push, {
|
|
19577
|
+
cliPath: fileURLToPath(import.meta.url),
|
|
19578
|
+
parseSimpleEnvText,
|
|
19579
|
+
resolveLocalAIExecutionModel,
|
|
19580
|
+
resolveGeminiHeadlessExecutionModel,
|
|
19581
|
+
suggestLocalAIModelDisplayName,
|
|
19582
|
+
resolveGeminiReasoningConfig,
|
|
19511
19583
|
stripLocalOnlyToolArgs: (requestObj, toolName) =>
|
|
19512
19584
|
stripLocalOnlyToolArgs(requestObj, toolName),
|
|
19513
19585
|
applyProxyResponsePatches: (params, deps = buildProxyResponsePipelineDeps()) =>
|
|
@@ -19,6 +19,7 @@ const GEMINI_HOME_SYNC_FILES = [
|
|
|
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
21
|
const GEMINI_CLI_TIMEOUT_MS = 90 * 1000;
|
|
22
|
+
const GEMINI_RUNNER_STABLE_EXECUTION_MODEL = "gemini-3-flash-preview";
|
|
22
23
|
const LOCAL_AI_MODEL_MAPPINGS = {
|
|
23
24
|
gpt: [
|
|
24
25
|
{
|
|
@@ -880,7 +881,12 @@ function runLocalAIPromptRawText({
|
|
|
880
881
|
const normalizedClient = normalizeLocalAIClientName(client);
|
|
881
882
|
const normalizedPermissionMode = normalizeLocalAIPermissionMode(permissionMode);
|
|
882
883
|
const normalizedReasoningEffort = normalizeLocalAIReasoningEffort(reasoningEffort, "low");
|
|
883
|
-
const resolvedExecutionModel =
|
|
884
|
+
const resolvedExecutionModel = normalizedClient === "gemini"
|
|
885
|
+
? resolveGeminiHeadlessExecutionModel(model, {
|
|
886
|
+
permissionMode: normalizedPermissionMode,
|
|
887
|
+
reasoningEffort: normalizedReasoningEffort,
|
|
888
|
+
})
|
|
889
|
+
: resolveLocalAIExecutionModel(normalizedClient, model);
|
|
884
890
|
const resolvedWorkspaceDir = ensureWorkspaceDir(workspaceDir);
|
|
885
891
|
const nextEnv = {
|
|
886
892
|
...process.env,
|
|
@@ -1386,6 +1392,23 @@ export function resolveLocalAIExecutionModel(clientName, rawModelValue = "") {
|
|
|
1386
1392
|
return match ? String(match.execution || "").trim() : modelValue;
|
|
1387
1393
|
}
|
|
1388
1394
|
|
|
1395
|
+
export function resolveGeminiHeadlessExecutionModel(
|
|
1396
|
+
rawModelValue = "",
|
|
1397
|
+
{ permissionMode = "read_only", reasoningEffort = "low" } = {},
|
|
1398
|
+
) {
|
|
1399
|
+
const resolvedExecutionModel = resolveLocalAIExecutionModel("gemini", rawModelValue);
|
|
1400
|
+
const normalizedExecutionModel = normalizeModelAliasText(resolvedExecutionModel);
|
|
1401
|
+
void normalizeLocalAIPermissionMode(permissionMode);
|
|
1402
|
+
void normalizeLocalAIReasoningEffort(reasoningEffort, "low");
|
|
1403
|
+
if (normalizedExecutionModel !== "auto-gemini-3") {
|
|
1404
|
+
return resolvedExecutionModel;
|
|
1405
|
+
}
|
|
1406
|
+
// Headless runner turns should not depend on Gemini CLI's internal auto-router.
|
|
1407
|
+
// Under heavier prompts it can escalate to capacity-constrained preview models,
|
|
1408
|
+
// which makes one bot path look flaky even though the routing logic is correct.
|
|
1409
|
+
return GEMINI_RUNNER_STABLE_EXECUTION_MODEL;
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1389
1412
|
function buildCodexArgs({ workspaceDir, model, permissionMode, reasoningEffort, outputPath }) {
|
|
1390
1413
|
const args = ["exec"];
|
|
1391
1414
|
if (model) {
|
|
@@ -1513,7 +1536,10 @@ function buildGeminiThinkingConfig(model, reasoningEffort) {
|
|
|
1513
1536
|
}
|
|
1514
1537
|
|
|
1515
1538
|
export function resolveGeminiReasoningConfig(rawModelValue = "", reasoningEffort = "medium") {
|
|
1516
|
-
const executionModel =
|
|
1539
|
+
const executionModel = resolveGeminiHeadlessExecutionModel(rawModelValue, {
|
|
1540
|
+
permissionMode: "read_only",
|
|
1541
|
+
reasoningEffort,
|
|
1542
|
+
});
|
|
1517
1543
|
if (!executionModel) {
|
|
1518
1544
|
return null;
|
|
1519
1545
|
}
|
|
@@ -3256,7 +3282,12 @@ export function runLocalAIClient({
|
|
|
3256
3282
|
const normalizedClient = normalizeLocalAIClientName(client);
|
|
3257
3283
|
const normalizedPermissionMode = normalizeLocalAIPermissionMode(permissionMode);
|
|
3258
3284
|
const normalizedReasoningEffort = normalizeLocalAIReasoningEffort(reasoningEffort);
|
|
3259
|
-
const resolvedExecutionModel =
|
|
3285
|
+
const resolvedExecutionModel = normalizedClient === "gemini"
|
|
3286
|
+
? resolveGeminiHeadlessExecutionModel(model, {
|
|
3287
|
+
permissionMode: normalizedPermissionMode,
|
|
3288
|
+
reasoningEffort: normalizedReasoningEffort,
|
|
3289
|
+
})
|
|
3290
|
+
: resolveLocalAIExecutionModel(normalizedClient, model);
|
|
3260
3291
|
const resolvedWorkspaceDir = ensureWorkspaceDir(workspaceDir);
|
|
3261
3292
|
const promptText = buildLocalBotPrompt(inputPayload);
|
|
3262
3293
|
if (normalizedClient === "sample") {
|
|
@@ -26,11 +26,14 @@ export function classifyExecutionFailureFacts(detail) {
|
|
|
26
26
|
const normalizedDetail = String(detail || "").trim();
|
|
27
27
|
const networkReset = /ECONNRESET|socket hang up|read ECONNRESET/i.test(normalizedDetail);
|
|
28
28
|
const networkTimeout = /ETIMEDOUT|http timeout|ECONNABORTED|aborted/i.test(normalizedDetail);
|
|
29
|
-
const
|
|
29
|
+
const providerCapacityExhausted = /MODEL_CAPACITY_EXHAUSTED|RESOURCE_EXHAUSTED|No capacity available for model|rateLimitExceeded/i.test(normalizedDetail);
|
|
30
|
+
const retryable = networkReset || networkTimeout || providerCapacityExhausted;
|
|
30
31
|
const base = {
|
|
31
32
|
stage: "execution",
|
|
32
33
|
operation: "runner_execution",
|
|
33
|
-
errorType:
|
|
34
|
+
errorType: providerCapacityExhausted
|
|
35
|
+
? "provider_capacity_exhausted"
|
|
36
|
+
: retryable
|
|
34
37
|
? (networkTimeout ? "network_timeout" : "network_reset")
|
|
35
38
|
: "execution_failed",
|
|
36
39
|
retryable,
|
|
@@ -42,6 +45,15 @@ export function classifyExecutionFailureFacts(detail) {
|
|
|
42
45
|
if (!normalizedDetail) {
|
|
43
46
|
return base;
|
|
44
47
|
}
|
|
48
|
+
if (providerCapacityExhausted) {
|
|
49
|
+
return {
|
|
50
|
+
...base,
|
|
51
|
+
stage: "provider_call",
|
|
52
|
+
operation: "local_ai_model_request",
|
|
53
|
+
errorType: "provider_capacity_exhausted",
|
|
54
|
+
retryable: true,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
45
57
|
if (/permission_mode=read_only|read[_ -]?only/i.test(normalizedDetail)) {
|
|
46
58
|
return {
|
|
47
59
|
...base,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
buildCanonicalHumanInboundKey,
|
|
2
3
|
buildTelegramMessageEnvelopeFromParsedArchive,
|
|
3
4
|
findRecentTelegramMessageEnvelope,
|
|
4
5
|
isTelegramLocalInboundEnvelopeForRoute,
|
|
@@ -27,6 +28,20 @@ function normalizeMentionSelector(value) {
|
|
|
27
28
|
return String(value || "").trim().replace(/^@+/, "").toLowerCase();
|
|
28
29
|
}
|
|
29
30
|
|
|
31
|
+
function firstNonEmptyString(values) {
|
|
32
|
+
for (const value of ensureArray(values)) {
|
|
33
|
+
const normalized = String(value ?? "").trim();
|
|
34
|
+
if (normalized) {
|
|
35
|
+
return normalized;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return "";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function normalizeCanonicalHumanMessageKey(rawValue) {
|
|
42
|
+
return String(rawValue || "").trim();
|
|
43
|
+
}
|
|
44
|
+
|
|
30
45
|
function uniqueOrdered(values) {
|
|
31
46
|
const ordered = [];
|
|
32
47
|
const seen = new Set();
|
|
@@ -82,6 +97,15 @@ function doesTelegramEnvelopeMatchMessage(rawEnvelope, {
|
|
|
82
97
|
&& intFromRawAllowZero(envelope.message_id, 0) === normalizedMessageID;
|
|
83
98
|
}
|
|
84
99
|
|
|
100
|
+
function doesTelegramEnvelopeMatchCanonicalHumanMessage(rawEnvelope, canonicalHumanMessageKey = "") {
|
|
101
|
+
const normalizedCanonicalHumanMessageKey = normalizeCanonicalHumanMessageKey(canonicalHumanMessageKey);
|
|
102
|
+
if (!normalizedCanonicalHumanMessageKey) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
const envelope = normalizeTelegramMessageEnvelope(rawEnvelope);
|
|
106
|
+
return String(envelope.canonical_human_message_key || "").trim() === normalizedCanonicalHumanMessageKey;
|
|
107
|
+
}
|
|
108
|
+
|
|
85
109
|
function normalizeRunnerRecentLocalInboundReceipt(rawReceipt) {
|
|
86
110
|
const receipt = safeObject(rawReceipt);
|
|
87
111
|
const chatID = String(receipt.chat_id || receipt.chatID || "").trim();
|
|
@@ -89,7 +113,7 @@ function normalizeRunnerRecentLocalInboundReceipt(rawReceipt) {
|
|
|
89
113
|
if (!chatID || !(messageID > 0)) {
|
|
90
114
|
return {};
|
|
91
115
|
}
|
|
92
|
-
|
|
116
|
+
const normalized = {
|
|
93
117
|
chat_id: chatID,
|
|
94
118
|
message_id: messageID,
|
|
95
119
|
...(intFromRawAllowZero(receipt.message_thread_id ?? receipt.messageThreadID, 0) > 0
|
|
@@ -107,10 +131,16 @@ function normalizeRunnerRecentLocalInboundReceipt(rawReceipt) {
|
|
|
107
131
|
...(normalizeMentionSelector(receipt.sender_username || receipt.senderUsername || "")
|
|
108
132
|
? { sender_username: normalizeMentionSelector(receipt.sender_username || receipt.senderUsername || "") }
|
|
109
133
|
: {}),
|
|
134
|
+
...(String(receipt.sender_id || receipt.senderID || "").trim()
|
|
135
|
+
? { sender_id: String(receipt.sender_id || receipt.senderID || "").trim() }
|
|
136
|
+
: {}),
|
|
110
137
|
sender_is_bot: receipt.sender_is_bot === true || receipt.senderIsBot === true,
|
|
111
138
|
...(String(receipt.body || "").trim()
|
|
112
139
|
? { body: String(receipt.body || "").trim() }
|
|
113
140
|
: {}),
|
|
141
|
+
...(String(receipt.occurred_at || receipt.occurredAt || "").trim()
|
|
142
|
+
? { occurred_at: String(receipt.occurred_at || receipt.occurredAt || "").trim() }
|
|
143
|
+
: {}),
|
|
114
144
|
...(String(receipt.receipt_origin || receipt.receiptOrigin || "").trim()
|
|
115
145
|
? { receipt_origin: String(receipt.receipt_origin || receipt.receiptOrigin || "").trim().toLowerCase() }
|
|
116
146
|
: {}),
|
|
@@ -121,16 +151,59 @@ function normalizeRunnerRecentLocalInboundReceipt(rawReceipt) {
|
|
|
121
151
|
? { receipt_bot_username: normalizeMentionSelector(receipt.receipt_bot_username || receipt.receiptBotUsername || "") }
|
|
122
152
|
: {}),
|
|
123
153
|
};
|
|
154
|
+
const canonicalHumanMessageKey = buildCanonicalHumanInboundKey({
|
|
155
|
+
chat_id: normalized.chat_id,
|
|
156
|
+
message_id: normalized.message_id,
|
|
157
|
+
message_thread_id: normalized.message_thread_id,
|
|
158
|
+
reply_to_message_id: normalized.reply_to_message_id,
|
|
159
|
+
kind: normalized.kind,
|
|
160
|
+
sender_id: normalized.sender_id,
|
|
161
|
+
sender_username: normalized.sender_username,
|
|
162
|
+
sender_is_bot: normalized.sender_is_bot === true,
|
|
163
|
+
body: normalized.body,
|
|
164
|
+
occurred_at: normalized.occurred_at,
|
|
165
|
+
canonical_human_message_key: firstNonEmptyString([
|
|
166
|
+
receipt.canonical_human_message_key,
|
|
167
|
+
receipt.canonicalHumanMessageKey,
|
|
168
|
+
]),
|
|
169
|
+
});
|
|
170
|
+
if (canonicalHumanMessageKey) {
|
|
171
|
+
normalized.canonical_human_message_key = canonicalHumanMessageKey;
|
|
172
|
+
}
|
|
173
|
+
return normalized;
|
|
124
174
|
}
|
|
125
175
|
|
|
126
|
-
function findRecentTelegramInboundReceipt(rawMap, {
|
|
176
|
+
function findRecentTelegramInboundReceipt(rawMap, {
|
|
177
|
+
chatID = "",
|
|
178
|
+
messageID = 0,
|
|
179
|
+
canonicalHumanMessageKey = "",
|
|
180
|
+
} = {}) {
|
|
127
181
|
const normalizedChatID = String(chatID || "").trim();
|
|
128
182
|
const normalizedMessageID = intFromRawAllowZero(messageID, 0);
|
|
129
|
-
|
|
183
|
+
const normalizedCanonicalHumanMessageKey = normalizeCanonicalHumanMessageKey(canonicalHumanMessageKey);
|
|
184
|
+
if (!normalizedChatID || (!(normalizedMessageID > 0) && !normalizedCanonicalHumanMessageKey)) {
|
|
185
|
+
return {};
|
|
186
|
+
}
|
|
187
|
+
if (normalizedMessageID > 0) {
|
|
188
|
+
const key = `${normalizedChatID}:${normalizedMessageID}`;
|
|
189
|
+
const exactReceipt = normalizeRunnerRecentLocalInboundReceipt(safeObject(safeObject(rawMap)[key]));
|
|
190
|
+
if (Object.keys(exactReceipt).length > 0) {
|
|
191
|
+
return exactReceipt;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (!normalizedCanonicalHumanMessageKey) {
|
|
130
195
|
return {};
|
|
131
196
|
}
|
|
132
|
-
const
|
|
133
|
-
|
|
197
|
+
for (const value of Object.values(safeObject(rawMap))) {
|
|
198
|
+
const normalizedReceipt = normalizeRunnerRecentLocalInboundReceipt(value);
|
|
199
|
+
if (
|
|
200
|
+
String(normalizedReceipt.chat_id || "").trim() === normalizedChatID
|
|
201
|
+
&& String(normalizedReceipt.canonical_human_message_key || "").trim() === normalizedCanonicalHumanMessageKey
|
|
202
|
+
) {
|
|
203
|
+
return normalizedReceipt;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return {};
|
|
134
207
|
}
|
|
135
208
|
|
|
136
209
|
function buildTelegramMessageEnvelopeFromRecentReceipt(rawReceipt) {
|
|
@@ -154,6 +227,35 @@ function buildTelegramMessageEnvelopeFromRecentReceipt(rawReceipt) {
|
|
|
154
227
|
});
|
|
155
228
|
}
|
|
156
229
|
|
|
230
|
+
function findRecentTelegramMessageEnvelopeWithCanonicalFallback(rawMap, {
|
|
231
|
+
chatID = "",
|
|
232
|
+
messageID = 0,
|
|
233
|
+
canonicalHumanMessageKey = "",
|
|
234
|
+
} = {}) {
|
|
235
|
+
const exactEnvelope = findRecentTelegramMessageEnvelope(rawMap, {
|
|
236
|
+
chatID,
|
|
237
|
+
messageID,
|
|
238
|
+
});
|
|
239
|
+
if (Object.keys(safeObject(exactEnvelope)).length > 0) {
|
|
240
|
+
return exactEnvelope;
|
|
241
|
+
}
|
|
242
|
+
const normalizedChatID = String(chatID || "").trim();
|
|
243
|
+
const normalizedCanonicalHumanMessageKey = normalizeCanonicalHumanMessageKey(canonicalHumanMessageKey);
|
|
244
|
+
if (!normalizedChatID || !normalizedCanonicalHumanMessageKey) {
|
|
245
|
+
return {};
|
|
246
|
+
}
|
|
247
|
+
for (const rawEnvelope of Object.values(safeObject(rawMap))) {
|
|
248
|
+
const normalizedEnvelope = normalizeTelegramMessageEnvelope(rawEnvelope);
|
|
249
|
+
if (
|
|
250
|
+
String(normalizedEnvelope.chat_id || "").trim() === normalizedChatID
|
|
251
|
+
&& String(normalizedEnvelope.canonical_human_message_key || "").trim() === normalizedCanonicalHumanMessageKey
|
|
252
|
+
) {
|
|
253
|
+
return normalizedEnvelope;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return {};
|
|
257
|
+
}
|
|
258
|
+
|
|
157
259
|
function resolveRunnerTelegramSourceEnvelopeCandidates({
|
|
158
260
|
routeState,
|
|
159
261
|
persistedRequest,
|
|
@@ -173,19 +275,26 @@ function resolveRunnerTelegramSourceEnvelopeCandidates({
|
|
|
173
275
|
archivedSourceEnvelope.message_id || archiveEnvelope.message_id,
|
|
174
276
|
0,
|
|
175
277
|
);
|
|
278
|
+
const archiveCanonicalHumanMessageKey = firstNonEmptyString([
|
|
279
|
+
archivedSourceEnvelope.canonical_human_message_key,
|
|
280
|
+
archiveEnvelope.canonical_human_message_key,
|
|
281
|
+
buildCanonicalHumanInboundKey(selectedRecord?.parsedArchive),
|
|
282
|
+
]);
|
|
176
283
|
const routeLocalReceipt = findRecentTelegramInboundReceipt(
|
|
177
284
|
safeObject(routeState).recent_local_inbound_receipts,
|
|
178
285
|
{
|
|
179
286
|
chatID: archiveChatID,
|
|
180
287
|
messageID: archiveMessageID,
|
|
288
|
+
canonicalHumanMessageKey: archiveCanonicalHumanMessageKey,
|
|
181
289
|
},
|
|
182
290
|
);
|
|
183
291
|
const routeLocalReceiptEnvelope = buildTelegramMessageEnvelopeFromRecentReceipt(routeLocalReceipt);
|
|
184
|
-
const routeLocalEnvelope =
|
|
292
|
+
const routeLocalEnvelope = findRecentTelegramMessageEnvelopeWithCanonicalFallback(
|
|
185
293
|
safeObject(routeState).recent_local_inbound_envelopes,
|
|
186
294
|
{
|
|
187
295
|
chatID: archiveChatID,
|
|
188
296
|
messageID: archiveMessageID,
|
|
297
|
+
canonicalHumanMessageKey: archiveCanonicalHumanMessageKey,
|
|
189
298
|
},
|
|
190
299
|
);
|
|
191
300
|
const persistedSourceEnvelope = normalizeTelegramMessageEnvelope(
|
|
@@ -197,6 +306,7 @@ function resolveRunnerTelegramSourceEnvelopeCandidates({
|
|
|
197
306
|
archiveEnvelope,
|
|
198
307
|
archiveChatID,
|
|
199
308
|
archiveMessageID,
|
|
309
|
+
archiveCanonicalHumanMessageKey,
|
|
200
310
|
routeLocalReceipt,
|
|
201
311
|
routeLocalReceiptEnvelope,
|
|
202
312
|
routeLocalEnvelope,
|
|
@@ -222,6 +332,7 @@ function resolveRunnerLocalSourceEnvelopeForRoute({
|
|
|
222
332
|
archivedSourceEnvelope,
|
|
223
333
|
archiveChatID,
|
|
224
334
|
archiveMessageID,
|
|
335
|
+
archiveCanonicalHumanMessageKey,
|
|
225
336
|
routeLocalReceiptEnvelope,
|
|
226
337
|
routeLocalEnvelope,
|
|
227
338
|
persistedSourceEnvelope,
|
|
@@ -251,10 +362,16 @@ function resolveRunnerLocalSourceEnvelopeForRoute({
|
|
|
251
362
|
routeKey,
|
|
252
363
|
botUsername: currentBotSelector,
|
|
253
364
|
})
|
|
254
|
-
&&
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
365
|
+
&& (
|
|
366
|
+
doesTelegramEnvelopeMatchMessage(persistedSourceEnvelope, {
|
|
367
|
+
chatID: archiveChatID,
|
|
368
|
+
messageID: archiveMessageID,
|
|
369
|
+
})
|
|
370
|
+
|| doesTelegramEnvelopeMatchCanonicalHumanMessage(
|
|
371
|
+
persistedSourceEnvelope,
|
|
372
|
+
archiveCanonicalHumanMessageKey,
|
|
373
|
+
)
|
|
374
|
+
)
|
|
258
375
|
) {
|
|
259
376
|
return {
|
|
260
377
|
envelope: persistedSourceEnvelope,
|
|
@@ -267,10 +384,16 @@ function resolveRunnerLocalSourceEnvelopeForRoute({
|
|
|
267
384
|
routeKey,
|
|
268
385
|
botUsername: currentBotSelector,
|
|
269
386
|
})
|
|
270
|
-
&&
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
387
|
+
&& (
|
|
388
|
+
doesTelegramEnvelopeMatchMessage(archivedSourceEnvelope, {
|
|
389
|
+
chatID: archiveChatID,
|
|
390
|
+
messageID: archiveMessageID,
|
|
391
|
+
})
|
|
392
|
+
|| doesTelegramEnvelopeMatchCanonicalHumanMessage(
|
|
393
|
+
archivedSourceEnvelope,
|
|
394
|
+
archiveCanonicalHumanMessageKey,
|
|
395
|
+
)
|
|
396
|
+
)
|
|
274
397
|
) {
|
|
275
398
|
return {
|
|
276
399
|
envelope: archivedSourceEnvelope,
|
|
@@ -289,14 +412,21 @@ function hasForeignRouteLocalEnvelopeForMessage({
|
|
|
289
412
|
envelopes,
|
|
290
413
|
archiveChatID,
|
|
291
414
|
archiveMessageID,
|
|
415
|
+
archiveCanonicalHumanMessageKey,
|
|
292
416
|
routeKey,
|
|
293
417
|
currentBotSelector,
|
|
294
418
|
}) {
|
|
295
419
|
return ensureArray(envelopes).some((rawEnvelope) => (
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
420
|
+
(
|
|
421
|
+
doesTelegramEnvelopeMatchMessage(rawEnvelope, {
|
|
422
|
+
chatID: archiveChatID,
|
|
423
|
+
messageID: archiveMessageID,
|
|
424
|
+
})
|
|
425
|
+
|| doesTelegramEnvelopeMatchCanonicalHumanMessage(
|
|
426
|
+
rawEnvelope,
|
|
427
|
+
archiveCanonicalHumanMessageKey,
|
|
428
|
+
)
|
|
429
|
+
)
|
|
300
430
|
&& String(safeObject(normalizeTelegramMessageEnvelope(rawEnvelope)).source_origin || "").trim().toLowerCase() === "local_telegram_inbound"
|
|
301
431
|
&& !isTelegramLocalInboundEnvelopeForRoute(rawEnvelope, {
|
|
302
432
|
routeKey,
|
|
@@ -352,6 +482,7 @@ function resolveRunnerReceiptBackedHumanInboundVisibility({
|
|
|
352
482
|
archivedSourceEnvelope,
|
|
353
483
|
archiveChatID,
|
|
354
484
|
archiveMessageID,
|
|
485
|
+
archiveCanonicalHumanMessageKey,
|
|
355
486
|
routeLocalReceipt,
|
|
356
487
|
persistedSourceEnvelope,
|
|
357
488
|
} = safeObject(localMatch.candidates);
|
|
@@ -367,6 +498,7 @@ function resolveRunnerReceiptBackedHumanInboundVisibility({
|
|
|
367
498
|
envelopes: [persistedSourceEnvelope, archivedSourceEnvelope],
|
|
368
499
|
archiveChatID,
|
|
369
500
|
archiveMessageID,
|
|
501
|
+
archiveCanonicalHumanMessageKey,
|
|
370
502
|
routeKey,
|
|
371
503
|
currentBotSelector,
|
|
372
504
|
});
|
|
@@ -413,6 +545,7 @@ function buildRunnerDiagnosticTraceSummary({
|
|
|
413
545
|
archivedSourceEnvelope,
|
|
414
546
|
archiveChatID,
|
|
415
547
|
archiveMessageID,
|
|
548
|
+
archiveCanonicalHumanMessageKey,
|
|
416
549
|
persistedSourceEnvelope,
|
|
417
550
|
routeLocalEnvelope,
|
|
418
551
|
routeLocalReceipt,
|
|
@@ -436,6 +569,7 @@ function buildRunnerDiagnosticTraceSummary({
|
|
|
436
569
|
envelopes: [persistedSourceEnvelope, archivedSourceEnvelope],
|
|
437
570
|
archiveChatID,
|
|
438
571
|
archiveMessageID,
|
|
572
|
+
archiveCanonicalHumanMessageKey,
|
|
439
573
|
routeKey,
|
|
440
574
|
currentBotSelector,
|
|
441
575
|
});
|
|
@@ -88,6 +88,7 @@ export function buildRunnerProcessedLifecycleInput({
|
|
|
88
88
|
const processed = safeObject(processedRaw);
|
|
89
89
|
const result = safeObject(processed.result);
|
|
90
90
|
const normalizedOutcome = normalizeRunnerProcessedLifecycleOutcome(processed);
|
|
91
|
+
const normalizedFailureFacts = safeObject(result.failure_facts);
|
|
91
92
|
return {
|
|
92
93
|
requestKey,
|
|
93
94
|
selectedRecord,
|
|
@@ -95,6 +96,8 @@ export function buildRunnerProcessedLifecycleInput({
|
|
|
95
96
|
outcome: normalizedOutcome,
|
|
96
97
|
closedReason: normalizedOutcome === "skipped"
|
|
97
98
|
? String(processed.skippedRecord?.reason || result.detail || "skipped").trim() || "skipped"
|
|
99
|
+
: ["error", "execution_failed", "policy_violation"].includes(normalizedOutcome)
|
|
100
|
+
? String(result.detail || "execution_error").trim() || "execution_error"
|
|
98
101
|
: "",
|
|
99
102
|
conversationIDRaw: String(result.conversation_id || "").trim(),
|
|
100
103
|
conversationParticipants: ensureArray(result.conversation_participants),
|
|
@@ -126,6 +129,8 @@ export function buildRunnerProcessedLifecycleInput({
|
|
|
126
129
|
assignmentValidationStatus: String(result.assignment_validation_status || "").trim(),
|
|
127
130
|
assignmentValidationReason: String(result.assignment_validation_reason || "").trim(),
|
|
128
131
|
assignmentValidationModes: ensureArray(result.assignment_validation_modes),
|
|
132
|
+
failureReplyClassification: String(result.failure_reply_classification || "").trim(),
|
|
133
|
+
failureFacts: normalizedFailureFacts,
|
|
129
134
|
deliveryStatus: String(result.delivery_status || "").trim(),
|
|
130
135
|
archiveStatus: String(result.archive_status || "").trim(),
|
|
131
136
|
transportError: String(result.transport_error || "").trim(),
|
package/lib/runner-runtime.mjs
CHANGED
|
@@ -528,6 +528,27 @@ function normalizeRunnerRecentLocalInboundReceipt(rawReceipt, fallbackKey = "")
|
|
|
528
528
|
if (chatTitle) {
|
|
529
529
|
normalized.chat_title = chatTitle;
|
|
530
530
|
}
|
|
531
|
+
const canonicalHumanMessageKey = String(
|
|
532
|
+
safeObject(normalizeTelegramMessageEnvelope({
|
|
533
|
+
chat_id: normalized.chat_id,
|
|
534
|
+
message_id: normalized.message_id,
|
|
535
|
+
message_thread_id: normalized.message_thread_id,
|
|
536
|
+
reply_to_message_id: normalized.reply_to_message_id,
|
|
537
|
+
kind: normalized.kind,
|
|
538
|
+
sender_id: normalized.sender_id,
|
|
539
|
+
sender_username: normalized.sender_username,
|
|
540
|
+
sender_is_bot: normalized.sender_is_bot === true,
|
|
541
|
+
body: normalized.body,
|
|
542
|
+
occurred_at: normalized.occurred_at,
|
|
543
|
+
canonical_human_message_key: firstNonEmptyString([
|
|
544
|
+
receipt.canonical_human_message_key,
|
|
545
|
+
receipt.canonicalHumanMessageKey,
|
|
546
|
+
]),
|
|
547
|
+
})).canonical_human_message_key || "",
|
|
548
|
+
).trim();
|
|
549
|
+
if (canonicalHumanMessageKey) {
|
|
550
|
+
normalized.canonical_human_message_key = canonicalHumanMessageKey;
|
|
551
|
+
}
|
|
531
552
|
return [receiptKey, normalized];
|
|
532
553
|
}
|
|
533
554
|
|
|
@@ -361,6 +361,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
361
361
|
const cliPath = String(requireDependency(deps, "cliPath") || "").trim();
|
|
362
362
|
const parseSimpleEnvText = requireDependency(deps, "parseSimpleEnvText");
|
|
363
363
|
const resolveLocalAIExecutionModel = requireDependency(deps, "resolveLocalAIExecutionModel");
|
|
364
|
+
const resolveGeminiHeadlessExecutionModel = requireDependency(deps, "resolveGeminiHeadlessExecutionModel");
|
|
364
365
|
const suggestLocalAIModelDisplayName = requireDependency(deps, "suggestLocalAIModelDisplayName");
|
|
365
366
|
const resolveGeminiReasoningConfig = requireDependency(deps, "resolveGeminiReasoningConfig");
|
|
366
367
|
const stripLocalOnlyToolArgs = requireDependency(deps, "stripLocalOnlyToolArgs");
|
|
@@ -392,6 +393,18 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
392
393
|
].join(" "),
|
|
393
394
|
);
|
|
394
395
|
|
|
396
|
+
push(
|
|
397
|
+
"gemini_headless_runner_uses_explicit_stable_execution_model",
|
|
398
|
+
resolveGeminiHeadlessExecutionModel("gemini-3.1-pro", {
|
|
399
|
+
permissionMode: "read_only",
|
|
400
|
+
reasoningEffort: "low",
|
|
401
|
+
}) === "gemini-3-flash-preview",
|
|
402
|
+
`gemini_headless=${resolveGeminiHeadlessExecutionModel("gemini-3.1-pro", {
|
|
403
|
+
permissionMode: "read_only",
|
|
404
|
+
reasoningEffort: "low",
|
|
405
|
+
})}`,
|
|
406
|
+
);
|
|
407
|
+
|
|
395
408
|
push(
|
|
396
409
|
"blank_model_defaults_to_first_display_model_for_each_client",
|
|
397
410
|
suggestLocalAIModelDisplayName("gpt", "") === "gpt-5.4"
|
|
@@ -409,7 +422,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
409
422
|
const geminiHighReasoning = resolveGeminiReasoningConfig("gemini-3.1-pro", "high");
|
|
410
423
|
push(
|
|
411
424
|
"gemini_reasoning_effort_maps_to_runtime_settings_override",
|
|
412
|
-
String(geminiLowReasoning?.model || "") === "
|
|
425
|
+
String(geminiLowReasoning?.model || "") === "gemini-3-flash-preview"
|
|
413
426
|
&& String(safeObject(geminiLowReasoning?.thinkingConfig).thinkingLevel || "") === "LOW"
|
|
414
427
|
&& String(safeObject(geminiMediumReasoning?.thinkingConfig).thinkingLevel || "") === "THINKING_LEVEL_UNSPECIFIED"
|
|
415
428
|
&& String(safeObject(geminiHighReasoning?.thinkingConfig).thinkingLevel || "") === "HIGH",
|
|
@@ -2303,20 +2303,31 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
2303
2303
|
},
|
|
2304
2304
|
});
|
|
2305
2305
|
const sharedHumanState = loadBotRunnerState();
|
|
2306
|
-
const
|
|
2306
|
+
const sharedHumanRequests = Object.values(safeObject(sharedHumanState.requests))
|
|
2307
2307
|
.filter((entryRaw) => {
|
|
2308
2308
|
const entry = safeObject(entryRaw);
|
|
2309
2309
|
return String(entry.chat_id || "") === "-100123"
|
|
2310
2310
|
&& String(entry.source_message_body || "") === sharedHumanBody;
|
|
2311
|
-
})
|
|
2312
|
-
|
|
2311
|
+
});
|
|
2312
|
+
const sharedHumanRequestCount = sharedHumanRequests.length;
|
|
2313
|
+
const sharedHumanCanonicalKey = buildArchivedInboundMessageKey({
|
|
2314
|
+
chatID: "-100123",
|
|
2315
|
+
messageID: 1189,
|
|
2316
|
+
messageThreadID: 0,
|
|
2317
|
+
kind: "telegram_message",
|
|
2318
|
+
senderID: "7001",
|
|
2319
|
+
senderIsBot: false,
|
|
2320
|
+
occurredAt: "2026-04-01T06:00:00.000Z",
|
|
2321
|
+
body: sharedHumanBody,
|
|
2322
|
+
}).replace(/^human:/, "");
|
|
2313
2323
|
push(
|
|
2314
2324
|
"runner_human_opening_request_identity_is_canonical_across_routes",
|
|
2315
2325
|
sharedHumanClaimPrimary.ok === true
|
|
2316
2326
|
&& (sharedHumanClaimPeer.ok === true || String(sharedHumanClaimPeer.reason || "") === "request_already_claimed")
|
|
2317
2327
|
&& String(sharedHumanClaimPrimary.requestKey || "") === String(sharedHumanClaimPeer.requestKey || "")
|
|
2318
|
-
&& sharedHumanRequestCount === 1
|
|
2319
|
-
|
|
2328
|
+
&& sharedHumanRequestCount === 1
|
|
2329
|
+
&& String(safeObject(sharedHumanRequests[0]).canonical_human_message_key || "") === sharedHumanCanonicalKey,
|
|
2330
|
+
`primary=${String(sharedHumanClaimPrimary.requestKey || "(none)")} peer=${String(sharedHumanClaimPeer.requestKey || "(none)")} peer_reason=${String(sharedHumanClaimPeer.reason || "(none)")} count=${sharedHumanRequestCount} canonical=${String(safeObject(sharedHumanRequests[0]).canonical_human_message_key || "(none)")}`,
|
|
2320
2331
|
);
|
|
2321
2332
|
|
|
2322
2333
|
const rootTaskRecord = {
|
|
@@ -3234,6 +3245,73 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
3234
3245
|
`status=${String(failedRequest?.status || "(none)")} reason=${String(failedRequest?.closed_reason || "(none)")} closed_at=${String(failedRequest?.closed_at || "(none)")}`,
|
|
3235
3246
|
);
|
|
3236
3247
|
|
|
3248
|
+
saveBotRunnerState({
|
|
3249
|
+
routes: {
|
|
3250
|
+
[requestRouteKey]: {},
|
|
3251
|
+
},
|
|
3252
|
+
sharedInboxes: {},
|
|
3253
|
+
excludedComments: {},
|
|
3254
|
+
requests: {
|
|
3255
|
+
"request-key-2f": {
|
|
3256
|
+
request_key: "request-key-2f",
|
|
3257
|
+
project_id: selftestProjectID,
|
|
3258
|
+
provider: "telegram",
|
|
3259
|
+
chat_id: "-100123",
|
|
3260
|
+
source_message_id: 751,
|
|
3261
|
+
conversation_id: "conv-request-2f",
|
|
3262
|
+
execution_contract_type: "delegation",
|
|
3263
|
+
execution_contract_targets: ["ryoai3_bot"],
|
|
3264
|
+
next_expected_responders: ["ryoai3_bot"],
|
|
3265
|
+
authoritative_decision_bundle: {
|
|
3266
|
+
schema_version: "runner_conversation_decision.v1",
|
|
3267
|
+
decision_type: "reply_outcome",
|
|
3268
|
+
conversation_intent_mode: "delegated_single_lead",
|
|
3269
|
+
allowed_responders: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
3270
|
+
initial_responders: ["ryoai_bot"],
|
|
3271
|
+
selected_bot_usernames: ["ryoai2_bot"],
|
|
3272
|
+
allow_bot_to_bot: true,
|
|
3273
|
+
execution_contract_type: "delegation",
|
|
3274
|
+
execution_contract_targets: ["ryoai3_bot"],
|
|
3275
|
+
next_expected_responders: ["ryoai3_bot"],
|
|
3276
|
+
should_close_after_reply: false,
|
|
3277
|
+
},
|
|
3278
|
+
decision_bundle_validation_status: "valid",
|
|
3279
|
+
status: "running",
|
|
3280
|
+
claimed_by_route: requestRouteKey,
|
|
3281
|
+
},
|
|
3282
|
+
},
|
|
3283
|
+
consumedComments: {},
|
|
3284
|
+
});
|
|
3285
|
+
const retryableFailedDelegation = markRunnerRequestLifecycle({
|
|
3286
|
+
normalizedRoute: requestRoute,
|
|
3287
|
+
requestKey: "request-key-2f",
|
|
3288
|
+
selectedRecord: {
|
|
3289
|
+
id: "comment-request-finish-2f",
|
|
3290
|
+
parsedArchive: {
|
|
3291
|
+
kind: "bot_reply",
|
|
3292
|
+
chatID: "-100123",
|
|
3293
|
+
messageID: 752,
|
|
3294
|
+
conversationID: "conv-request-2f",
|
|
3295
|
+
},
|
|
3296
|
+
},
|
|
3297
|
+
routeKey: requestRouteKey,
|
|
3298
|
+
outcome: "error",
|
|
3299
|
+
closedReason: "Gemini CLI timed out after 90s while waiting for a model response (No capacity available for model gemini-3.1-pro-preview on the server)",
|
|
3300
|
+
currentBotSelector: "@RyoAI2_bot",
|
|
3301
|
+
failureReplyClassification: "retryable_failure",
|
|
3302
|
+
failureFacts: {
|
|
3303
|
+
retryable: true,
|
|
3304
|
+
error_type: "provider_capacity_exhausted",
|
|
3305
|
+
},
|
|
3306
|
+
});
|
|
3307
|
+
push(
|
|
3308
|
+
"runner_request_lifecycle_retryable_delegated_error_stays_running",
|
|
3309
|
+
String(retryableFailedDelegation?.status || "") === "running"
|
|
3310
|
+
&& ensureArray(retryableFailedDelegation?.next_expected_responders).includes("ryoai3_bot")
|
|
3311
|
+
&& String(retryableFailedDelegation?.closed_reason || "").trim() === "",
|
|
3312
|
+
`status=${String(retryableFailedDelegation?.status || "(none)")} next=${ensureArray(retryableFailedDelegation?.next_expected_responders).join(",")} closed_reason=${String(retryableFailedDelegation?.closed_reason || "(none)")}`,
|
|
3313
|
+
);
|
|
3314
|
+
|
|
3237
3315
|
saveBotRunnerState({
|
|
3238
3316
|
routes: {
|
|
3239
3317
|
[requestRouteKey]: {},
|
|
@@ -16534,6 +16612,97 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
16534
16612
|
}
|
|
16535
16613
|
}
|
|
16536
16614
|
|
|
16615
|
+
try {
|
|
16616
|
+
const canonicalVisibility = resolveRunnerHumanInboundVisibility({
|
|
16617
|
+
routeState: {
|
|
16618
|
+
recent_local_inbound_envelopes: {},
|
|
16619
|
+
recent_local_inbound_receipts: {
|
|
16620
|
+
"-100123:5201": {
|
|
16621
|
+
chat_id: "-100123",
|
|
16622
|
+
message_id: 5201,
|
|
16623
|
+
sender_id: "7001",
|
|
16624
|
+
body: "@ryoai_bot canonical hello",
|
|
16625
|
+
occurred_at: "2026-04-02T00:00:00.000Z",
|
|
16626
|
+
receipt_origin: "local_telegram_inbound",
|
|
16627
|
+
receipt_route_key: "telegram-monitor-canonical-owner::project::telegram::monitor::dest::actor",
|
|
16628
|
+
receipt_bot_username: "ryoai_bot",
|
|
16629
|
+
received_at: "2026-04-02T00:00:01.000Z",
|
|
16630
|
+
},
|
|
16631
|
+
},
|
|
16632
|
+
},
|
|
16633
|
+
persistedRequest: null,
|
|
16634
|
+
selectedRecord: {
|
|
16635
|
+
id: "comment-canonical-visibility-1",
|
|
16636
|
+
parsedArchive: {
|
|
16637
|
+
kind: "telegram_message",
|
|
16638
|
+
chatID: "-100123",
|
|
16639
|
+
chatType: "supergroup",
|
|
16640
|
+
body: "@ryoai_bot canonical hello",
|
|
16641
|
+
messageID: 6301,
|
|
16642
|
+
senderID: "7001",
|
|
16643
|
+
senderIsBot: false,
|
|
16644
|
+
occurredAt: "2026-04-02T00:00:00.000Z",
|
|
16645
|
+
mentionUsernames: ["ryoai_bot"],
|
|
16646
|
+
},
|
|
16647
|
+
},
|
|
16648
|
+
routeKey: "telegram-monitor-canonical-owner::project::telegram::monitor::dest::actor",
|
|
16649
|
+
currentBotSelector: "ryoai_bot",
|
|
16650
|
+
triggerDecision: {
|
|
16651
|
+
shouldRespond: true,
|
|
16652
|
+
triggerEligible: true,
|
|
16653
|
+
candidateHintOnly: true,
|
|
16654
|
+
trigger: "mention",
|
|
16655
|
+
reason: "canonical receipt-backed mention trigger",
|
|
16656
|
+
candidateBotUsernames: ["ryoai_bot"],
|
|
16657
|
+
},
|
|
16658
|
+
});
|
|
16659
|
+
const canonicalSourceEnvelope = resolveRunnerDeliverySourceMessageEnvelope({
|
|
16660
|
+
routeState: {
|
|
16661
|
+
recent_local_inbound_envelopes: {},
|
|
16662
|
+
recent_local_inbound_receipts: {
|
|
16663
|
+
"-100123:5201": {
|
|
16664
|
+
chat_id: "-100123",
|
|
16665
|
+
message_id: 5201,
|
|
16666
|
+
sender_id: "7001",
|
|
16667
|
+
body: "@ryoai_bot canonical hello",
|
|
16668
|
+
occurred_at: "2026-04-02T00:00:00.000Z",
|
|
16669
|
+
receipt_origin: "local_telegram_inbound",
|
|
16670
|
+
receipt_route_key: "telegram-monitor-canonical-owner::project::telegram::monitor::dest::actor",
|
|
16671
|
+
receipt_bot_username: "ryoai_bot",
|
|
16672
|
+
received_at: "2026-04-02T00:00:01.000Z",
|
|
16673
|
+
},
|
|
16674
|
+
},
|
|
16675
|
+
},
|
|
16676
|
+
persistedRequest: null,
|
|
16677
|
+
selectedRecord: {
|
|
16678
|
+
id: "comment-canonical-visibility-1",
|
|
16679
|
+
parsedArchive: {
|
|
16680
|
+
kind: "telegram_message",
|
|
16681
|
+
chatID: "-100123",
|
|
16682
|
+
chatType: "supergroup",
|
|
16683
|
+
body: "@ryoai_bot canonical hello",
|
|
16684
|
+
messageID: 6301,
|
|
16685
|
+
senderID: "7001",
|
|
16686
|
+
senderIsBot: false,
|
|
16687
|
+
occurredAt: "2026-04-02T00:00:00.000Z",
|
|
16688
|
+
mentionUsernames: ["ryoai_bot"],
|
|
16689
|
+
},
|
|
16690
|
+
},
|
|
16691
|
+
routeKey: "telegram-monitor-canonical-owner::project::telegram::monitor::dest::actor",
|
|
16692
|
+
currentBotSelector: "ryoai_bot",
|
|
16693
|
+
});
|
|
16694
|
+
push(
|
|
16695
|
+
"runner_visibility_receipt_backed_human_opening_matches_canonical_key_across_route_local_copies",
|
|
16696
|
+
canonicalVisibility.applies === true
|
|
16697
|
+
&& canonicalVisibility.executable === true
|
|
16698
|
+
&& String(canonicalVisibility.visibilitySource || "") === "route_local_inbound_receipt"
|
|
16699
|
+
&& Number(safeObject(canonicalSourceEnvelope).message_id || 0) === 5201,
|
|
16700
|
+
`mode=${String(canonicalVisibility.visibilityMode || "(none)")} status=${String(canonicalVisibility.visibilityStatus || "(none)")} source=${String(canonicalVisibility.visibilitySource || "(none)")} reply_message_id=${String(safeObject(canonicalSourceEnvelope).message_id || "(none)")}`,
|
|
16701
|
+
);
|
|
16702
|
+
} catch (err) {
|
|
16703
|
+
push("runner_visibility_receipt_backed_human_opening_matches_canonical_key_across_route_local_copies", false, String(err?.message || err));
|
|
16704
|
+
}
|
|
16705
|
+
|
|
16537
16706
|
for (const [testName, triggerKind, messageID] of [
|
|
16538
16707
|
[
|
|
16539
16708
|
"runner_visibility_receipt_first_mention_without_exact_receipt_is_blocked",
|