metheus-governance-mcp-cli 0.2.230 → 0.2.231
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 +90 -0
- package/lib/runner-orchestration.mjs +72 -92
- package/lib/selftest-runner-scenarios.mjs +171 -19
- package/package.json +1 -1
package/cli.mjs
CHANGED
|
@@ -2430,12 +2430,32 @@ function normalizeBotRunnerRequests(rawRequests, nowMs = Date.now()) {
|
|
|
2430
2430
|
next_expected_responders: ensureArray(entry.next_expected_responders || entry.nextExpectedResponders)
|
|
2431
2431
|
.map((value) => normalizeTelegramMentionUsername(value))
|
|
2432
2432
|
.filter(Boolean),
|
|
2433
|
+
normalized_execution_contract_type: String(entry.normalized_execution_contract_type || entry.normalizedExecutionContractType || "").trim().toLowerCase(),
|
|
2434
|
+
normalized_execution_contract_targets: ensureArray(entry.normalized_execution_contract_targets || entry.normalizedExecutionContractTargets)
|
|
2435
|
+
.map((value) => normalizeTelegramMentionUsername(value))
|
|
2436
|
+
.filter(Boolean),
|
|
2437
|
+
normalized_execution_next_responders: ensureArray(entry.normalized_execution_next_responders || entry.normalizedExecutionNextResponders)
|
|
2438
|
+
.map((value) => normalizeTelegramMentionUsername(value))
|
|
2439
|
+
.filter(Boolean),
|
|
2433
2440
|
ai_reply_generated: boolFromRaw(
|
|
2434
2441
|
entry.ai_reply_generated ?? entry.aiReplyGenerated,
|
|
2435
2442
|
false,
|
|
2436
2443
|
),
|
|
2437
2444
|
ai_reply_generated_at: firstNonEmptyString([entry.ai_reply_generated_at, entry.aiReplyGeneratedAt]),
|
|
2438
2445
|
ai_reply_preview: String(entry.ai_reply_preview || entry.aiReplyPreview || "").trim(),
|
|
2446
|
+
root_execution_contract_type: String(entry.root_execution_contract_type || entry.rootExecutionContractType || "").trim().toLowerCase(),
|
|
2447
|
+
root_execution_contract_targets: ensureArray(entry.root_execution_contract_targets || entry.rootExecutionContractTargets)
|
|
2448
|
+
.map((value) => normalizeTelegramMentionUsername(value))
|
|
2449
|
+
.filter(Boolean),
|
|
2450
|
+
root_next_expected_responders: ensureArray(entry.root_next_expected_responders || entry.rootNextExpectedResponders)
|
|
2451
|
+
.map((value) => normalizeTelegramMentionUsername(value))
|
|
2452
|
+
.filter(Boolean),
|
|
2453
|
+
root_ai_reply_preview: String(entry.root_ai_reply_preview || entry.rootAiReplyPreview || "").trim(),
|
|
2454
|
+
root_response_contract_validation_status: String(entry.root_response_contract_validation_status || entry.rootResponseContractValidationStatus || "").trim().toLowerCase(),
|
|
2455
|
+
root_response_contract_validation_reason: String(entry.root_response_contract_validation_reason || entry.rootResponseContractValidationReason || "").trim(),
|
|
2456
|
+
root_response_contract_validation_targets: ensureArray(entry.root_response_contract_validation_targets || entry.rootResponseContractValidationTargets)
|
|
2457
|
+
.map((value) => normalizeTelegramMentionUsername(value))
|
|
2458
|
+
.filter(Boolean),
|
|
2439
2459
|
response_contract_validation_status: String(entry.response_contract_validation_status || entry.responseContractValidationStatus || "").trim().toLowerCase(),
|
|
2440
2460
|
response_contract_validation_reason: String(entry.response_contract_validation_reason || entry.responseContractValidationReason || "").trim(),
|
|
2441
2461
|
response_contract_validation_targets: ensureArray(entry.response_contract_validation_targets || entry.responseContractValidationTargets)
|
|
@@ -4597,6 +4617,9 @@ function markRunnerRequestLifecycle({
|
|
|
4597
4617
|
aiReplyGenerated = false,
|
|
4598
4618
|
aiReplyGeneratedAt = "",
|
|
4599
4619
|
aiReplyPreview = "",
|
|
4620
|
+
normalizedExecutionContractType = "",
|
|
4621
|
+
normalizedExecutionContractTargets = [],
|
|
4622
|
+
normalizedExecutionNextResponders = [],
|
|
4600
4623
|
responseContractValidationStatus = "",
|
|
4601
4624
|
responseContractValidationReason = "",
|
|
4602
4625
|
responseContractValidationTargets = [],
|
|
@@ -4668,6 +4691,8 @@ function markRunnerRequestLifecycle({
|
|
|
4668
4691
|
return normalizeRunnerRequestStatus(existing.status);
|
|
4669
4692
|
})();
|
|
4670
4693
|
const nowISO = new Date().toISOString();
|
|
4694
|
+
const commentKind = String(parsed.kind || "").trim().toLowerCase();
|
|
4695
|
+
const isRootHumanComment = ["telegram_message", "telegram_edited_message"].includes(commentKind);
|
|
4671
4696
|
const patch = {
|
|
4672
4697
|
conversation_id: conversationID,
|
|
4673
4698
|
conversation_participants: uniqueOrderedStrings(
|
|
@@ -4713,11 +4738,70 @@ function markRunnerRequestLifecycle({
|
|
|
4713
4738
|
ensureArray(nextExpectedResponders).length ? nextExpectedResponders : existing.next_expected_responders,
|
|
4714
4739
|
normalizeTelegramMentionUsername,
|
|
4715
4740
|
),
|
|
4741
|
+
normalized_execution_contract_type: String(
|
|
4742
|
+
normalizedExecutionContractType || existing.normalized_execution_contract_type || "",
|
|
4743
|
+
).trim().toLowerCase(),
|
|
4744
|
+
normalized_execution_contract_targets: uniqueOrderedStrings(
|
|
4745
|
+
ensureArray(normalizedExecutionContractTargets).length
|
|
4746
|
+
? normalizedExecutionContractTargets
|
|
4747
|
+
: existing.normalized_execution_contract_targets,
|
|
4748
|
+
normalizeTelegramMentionUsername,
|
|
4749
|
+
),
|
|
4750
|
+
normalized_execution_next_responders: uniqueOrderedStrings(
|
|
4751
|
+
ensureArray(normalizedExecutionNextResponders).length
|
|
4752
|
+
? normalizedExecutionNextResponders
|
|
4753
|
+
: existing.normalized_execution_next_responders,
|
|
4754
|
+
normalizeTelegramMentionUsername,
|
|
4755
|
+
),
|
|
4716
4756
|
ai_reply_generated: aiReplyGenerated === true || existing.ai_reply_generated === true,
|
|
4717
4757
|
ai_reply_generated_at: aiReplyGenerated === true
|
|
4718
4758
|
? firstNonEmptyString([aiReplyGeneratedAt, existing.ai_reply_generated_at, nowISO])
|
|
4719
4759
|
: String(existing.ai_reply_generated_at || "").trim(),
|
|
4720
4760
|
ai_reply_preview: String(aiReplyPreview || existing.ai_reply_preview || "").trim(),
|
|
4761
|
+
root_execution_contract_type: String(
|
|
4762
|
+
isRootHumanComment
|
|
4763
|
+
? nextExecutionContractType
|
|
4764
|
+
: existing.root_execution_contract_type || existing.execution_contract_type || "",
|
|
4765
|
+
).trim().toLowerCase(),
|
|
4766
|
+
root_execution_contract_targets: uniqueOrderedStrings(
|
|
4767
|
+
isRootHumanComment && ensureArray(executionContractTargets).length
|
|
4768
|
+
? executionContractTargets
|
|
4769
|
+
: ensureArray(existing.root_execution_contract_targets).length
|
|
4770
|
+
? existing.root_execution_contract_targets
|
|
4771
|
+
: existing.execution_contract_targets,
|
|
4772
|
+
normalizeTelegramMentionUsername,
|
|
4773
|
+
),
|
|
4774
|
+
root_next_expected_responders: uniqueOrderedStrings(
|
|
4775
|
+
isRootHumanComment && ensureArray(nextExpectedResponders).length
|
|
4776
|
+
? nextExpectedResponders
|
|
4777
|
+
: ensureArray(existing.root_next_expected_responders).length
|
|
4778
|
+
? existing.root_next_expected_responders
|
|
4779
|
+
: existing.next_expected_responders,
|
|
4780
|
+
normalizeTelegramMentionUsername,
|
|
4781
|
+
),
|
|
4782
|
+
root_ai_reply_preview: String(
|
|
4783
|
+
isRootHumanComment
|
|
4784
|
+
? aiReplyPreview || existing.root_ai_reply_preview || existing.ai_reply_preview || ""
|
|
4785
|
+
: existing.root_ai_reply_preview || existing.ai_reply_preview || "",
|
|
4786
|
+
).trim(),
|
|
4787
|
+
root_response_contract_validation_status: String(
|
|
4788
|
+
isRootHumanComment
|
|
4789
|
+
? responseContractValidationStatus || existing.root_response_contract_validation_status || existing.response_contract_validation_status || ""
|
|
4790
|
+
: existing.root_response_contract_validation_status || existing.response_contract_validation_status || "",
|
|
4791
|
+
).trim().toLowerCase(),
|
|
4792
|
+
root_response_contract_validation_reason: String(
|
|
4793
|
+
isRootHumanComment
|
|
4794
|
+
? responseContractValidationReason || existing.root_response_contract_validation_reason || existing.response_contract_validation_reason || ""
|
|
4795
|
+
: existing.root_response_contract_validation_reason || existing.response_contract_validation_reason || "",
|
|
4796
|
+
).trim(),
|
|
4797
|
+
root_response_contract_validation_targets: uniqueOrderedStrings(
|
|
4798
|
+
isRootHumanComment && ensureArray(responseContractValidationTargets).length
|
|
4799
|
+
? responseContractValidationTargets
|
|
4800
|
+
: ensureArray(existing.root_response_contract_validation_targets).length
|
|
4801
|
+
? existing.root_response_contract_validation_targets
|
|
4802
|
+
: existing.response_contract_validation_targets,
|
|
4803
|
+
normalizeTelegramMentionUsername,
|
|
4804
|
+
),
|
|
4721
4805
|
response_contract_validation_status: String(
|
|
4722
4806
|
responseContractValidationStatus || existing.response_contract_validation_status || "",
|
|
4723
4807
|
).trim().toLowerCase(),
|
|
@@ -8967,6 +9051,9 @@ async function processRunnerRouteOnce(route, runtime, mode, options = {}) {
|
|
|
8967
9051
|
executionContractActionable: processed.result?.execution_contract_actionable === true,
|
|
8968
9052
|
executionContractTargets: ensureArray(processed.result?.execution_contract_targets),
|
|
8969
9053
|
nextExpectedResponders: ensureArray(processed.result?.next_expected_responders),
|
|
9054
|
+
normalizedExecutionContractType: String(processed.result?.normalized_execution_contract_type || "").trim(),
|
|
9055
|
+
normalizedExecutionContractTargets: ensureArray(processed.result?.normalized_execution_contract_targets),
|
|
9056
|
+
normalizedExecutionNextResponders: ensureArray(processed.result?.normalized_execution_next_responders),
|
|
8970
9057
|
currentBotSelector,
|
|
8971
9058
|
conversationIntentMode: String(processed.result?.conversation_intent_mode || "").trim(),
|
|
8972
9059
|
normalizedIntent: resolvedIntentType,
|
|
@@ -11388,6 +11475,9 @@ async function runRunnerStartResolvedRoutes(routes, flags, options = {}) {
|
|
|
11388
11475
|
executionContractActionable: processed.result?.execution_contract_actionable === true,
|
|
11389
11476
|
executionContractTargets: ensureArray(processed.result?.execution_contract_targets),
|
|
11390
11477
|
nextExpectedResponders: ensureArray(processed.result?.next_expected_responders),
|
|
11478
|
+
normalizedExecutionContractType: String(processed.result?.normalized_execution_contract_type || "").trim(),
|
|
11479
|
+
normalizedExecutionContractTargets: ensureArray(processed.result?.normalized_execution_contract_targets),
|
|
11480
|
+
normalizedExecutionNextResponders: ensureArray(processed.result?.normalized_execution_next_responders),
|
|
11391
11481
|
currentBotSelector: normalizeTelegramMentionUsername(
|
|
11392
11482
|
deferredExecution.bot?.username || deferredExecution.bot?.name,
|
|
11393
11483
|
),
|
|
@@ -2502,8 +2502,8 @@ function buildWorkerFallbackExecutionPlan(plan, audit, options = {}) {
|
|
|
2502
2502
|
.map((item) => safeObject(item))
|
|
2503
2503
|
.filter((item) => String(item.role || "").trim());
|
|
2504
2504
|
const hasWorker = executionPlanIncludesWorkerStep(normalizedPlan);
|
|
2505
|
-
const requiresCtxpackUpdate =
|
|
2506
|
-
||
|
|
2505
|
+
const requiresCtxpackUpdate = safeObject(options).forceCtxpackUpdate === true
|
|
2506
|
+
|| normalizedAudit.requires_ctxpack_update_step === true;
|
|
2507
2507
|
const requiresWorkItems = normalizedAudit.requires_work_items_step === true;
|
|
2508
2508
|
if (hasWorker) {
|
|
2509
2509
|
const patchedSteps = existingSteps.map((item) => {
|
|
@@ -2581,16 +2581,17 @@ function describeExecutionPlanAdequacyFailure(plan, audit) {
|
|
|
2581
2581
|
function shouldForceWorkerFallbackExecutionPlan(plan, audit) {
|
|
2582
2582
|
const normalizedPlan = safeObject(plan);
|
|
2583
2583
|
const normalizedAudit = safeObject(audit);
|
|
2584
|
-
if (
|
|
2585
|
-
return
|
|
2584
|
+
if (normalizedAudit.requires_ctxpack_update_step === true && !executionPlanIncludesCtxpackUpdateStep(normalizedPlan)) {
|
|
2585
|
+
return true;
|
|
2586
2586
|
}
|
|
2587
|
-
if (normalizedAudit.
|
|
2587
|
+
if (normalizedAudit.requires_work_items_step === true && !executionPlanIncludesWorkItemsStep(normalizedPlan)) {
|
|
2588
2588
|
return true;
|
|
2589
2589
|
}
|
|
2590
|
-
if (normalizedAudit.
|
|
2590
|
+
if (normalizedAudit.requires_worker_step === true && !executionPlanIncludesWorkerStep(normalizedPlan)) {
|
|
2591
2591
|
return true;
|
|
2592
2592
|
}
|
|
2593
2593
|
return normalizedAudit.requires_execution === true
|
|
2594
|
+
&& !executionPlanIncludesWorkerStep(normalizedPlan)
|
|
2594
2595
|
&& normalizedAudit.plan_satisfies_request === false;
|
|
2595
2596
|
}
|
|
2596
2597
|
|
|
@@ -2840,6 +2841,9 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
2840
2841
|
};
|
|
2841
2842
|
let executedPlan;
|
|
2842
2843
|
let executedPlanAudit = null;
|
|
2844
|
+
const sourceMessageText = String(safeObject(selectedRecord?.parsedArchive).body || "").trim();
|
|
2845
|
+
const explicitCtxpackRequest = looksLikeCtxpackGuidanceMutationRequest(sourceMessageText)
|
|
2846
|
+
|| /\bctxpack\b/i.test(sourceMessageText);
|
|
2843
2847
|
try {
|
|
2844
2848
|
executedPlan = await invokePlanner();
|
|
2845
2849
|
} catch {
|
|
@@ -2890,8 +2894,9 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
2890
2894
|
let forcedWorkerFallback = false;
|
|
2891
2895
|
if (adequacyFailure && shouldForceWorkerFallbackExecutionPlan(executedPlan, executedPlanAudit)) {
|
|
2892
2896
|
executedPlan = buildWorkerFallbackExecutionPlan(executedPlan, executedPlanAudit, {
|
|
2893
|
-
messageText:
|
|
2897
|
+
messageText: sourceMessageText,
|
|
2894
2898
|
humanIntentType,
|
|
2899
|
+
forceCtxpackUpdate: explicitCtxpackRequest || safeObject(executedPlanAudit).requires_ctxpack_update_step === true,
|
|
2895
2900
|
});
|
|
2896
2901
|
executedPlanAudit = await auditPlannedExecution(executedPlan);
|
|
2897
2902
|
adequacyFailure = describeExecutionPlanAdequacyFailure(executedPlan, executedPlanAudit);
|
|
@@ -2905,10 +2910,9 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
2905
2910
|
) {
|
|
2906
2911
|
adequacyFailure = "";
|
|
2907
2912
|
}
|
|
2908
|
-
const sourceMessageText = String(safeObject(selectedRecord?.parsedArchive).body || "").trim();
|
|
2909
2913
|
if (
|
|
2910
2914
|
(
|
|
2911
|
-
|
|
2915
|
+
explicitCtxpackRequest
|
|
2912
2916
|
|| safeObject(executedPlanAudit).requires_ctxpack_update_step === true
|
|
2913
2917
|
)
|
|
2914
2918
|
&& (
|
|
@@ -2923,7 +2927,11 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
2923
2927
|
requiresExecution: true,
|
|
2924
2928
|
},
|
|
2925
2929
|
executedPlanAudit,
|
|
2926
|
-
{
|
|
2930
|
+
{
|
|
2931
|
+
messageText: sourceMessageText,
|
|
2932
|
+
humanIntentType,
|
|
2933
|
+
forceCtxpackUpdate: true,
|
|
2934
|
+
},
|
|
2927
2935
|
);
|
|
2928
2936
|
executedPlanAudit = await auditPlannedExecution(executedPlan);
|
|
2929
2937
|
adequacyFailure = describeExecutionPlanAdequacyFailure(executedPlan, executedPlanAudit);
|
|
@@ -5421,6 +5429,12 @@ export async function processRunnerSelectedRecord({
|
|
|
5421
5429
|
triggerDecision: effectiveTriggerDecision,
|
|
5422
5430
|
conversationContext: effectiveConversationContext,
|
|
5423
5431
|
});
|
|
5432
|
+
const normalizedExecutionTargets = ensureArray(executionContract?.assignments)
|
|
5433
|
+
.map((item) => normalizeMentionSelector(item?.targetBot))
|
|
5434
|
+
.filter(Boolean);
|
|
5435
|
+
const normalizedExecutionNextResponders = collectExecutionContractNextResponders(executionContract)
|
|
5436
|
+
.map((item) => normalizeMentionSelector(item))
|
|
5437
|
+
.filter(Boolean);
|
|
5424
5438
|
const visibleDelegationTargets = uniqueOrdered(
|
|
5425
5439
|
effectiveConversationContext?.mode === "public_multi_bot"
|
|
5426
5440
|
&& String(effectiveConversationContext?.stage || "").trim() === "human_opening"
|
|
@@ -5428,9 +5442,7 @@ export async function processRunnerSelectedRecord({
|
|
|
5428
5442
|
&& currentBotSelector
|
|
5429
5443
|
&& currentBotSelector === normalizeMentionSelector(effectiveConversationContext?.leadBotUsername)
|
|
5430
5444
|
&& normalizedExecutionContractType === "delegation"
|
|
5431
|
-
?
|
|
5432
|
-
.map((item) => normalizeMentionSelector(item?.targetBot))
|
|
5433
|
-
.filter(Boolean)
|
|
5445
|
+
? normalizedExecutionTargets
|
|
5434
5446
|
: [],
|
|
5435
5447
|
);
|
|
5436
5448
|
if (responseContractValidation.ok && visibleDelegationTargets.length > 0) {
|
|
@@ -5457,14 +5469,22 @@ export async function processRunnerSelectedRecord({
|
|
|
5457
5469
|
&& currentBotSelector !== normalizeMentionSelector(effectiveConversationContext.leadBotUsername)
|
|
5458
5470
|
&& normalizedExecutionContractType === "delegation"
|
|
5459
5471
|
) {
|
|
5460
|
-
const
|
|
5461
|
-
...
|
|
5462
|
-
.map((item) => normalizeMentionSelector(item?.targetBot))
|
|
5463
|
-
.filter(Boolean),
|
|
5464
|
-
...collectExecutionContractNextResponders(executionContract)
|
|
5472
|
+
const currentContractScopeTargets = uniqueOrdered([
|
|
5473
|
+
...collectExecutionContractNextResponders(safeObject(effectiveConversationContext.executionContract))
|
|
5465
5474
|
.map((item) => normalizeMentionSelector(item))
|
|
5466
5475
|
.filter(Boolean),
|
|
5467
|
-
|
|
5476
|
+
normalizeMentionSelector(
|
|
5477
|
+
safeObject(effectiveConversationContext.executionContract).summaryBot
|
|
5478
|
+
|| safeObject(effectiveConversationContext.executionContract).summary_bot
|
|
5479
|
+
|| effectiveConversationContext.summaryBotUsername,
|
|
5480
|
+
),
|
|
5481
|
+
normalizeMentionSelector(effectiveConversationContext.leadBotUsername),
|
|
5482
|
+
normalizeMentionSelector(effectiveConversationContext.summaryBotUsername),
|
|
5483
|
+
].filter(Boolean));
|
|
5484
|
+
const unauthorizedDelegationTargets = uniqueOrdered([
|
|
5485
|
+
...normalizedExecutionTargets,
|
|
5486
|
+
...normalizedExecutionNextResponders,
|
|
5487
|
+
]).filter((item) => item && item !== currentBotSelector && !currentContractScopeTargets.includes(item));
|
|
5468
5488
|
if (unauthorizedDelegationTargets.length > 0) {
|
|
5469
5489
|
responseContractValidation = {
|
|
5470
5490
|
ok: false,
|
|
@@ -5474,55 +5494,6 @@ export async function processRunnerSelectedRecord({
|
|
|
5474
5494
|
};
|
|
5475
5495
|
}
|
|
5476
5496
|
}
|
|
5477
|
-
if (!responseContractValidation.ok && String(responseContractValidation.status || "").trim() === "non_lead_public_assignment") {
|
|
5478
|
-
const reason = String(responseContractValidation.reason || "").trim()
|
|
5479
|
-
|| "response contract validation failed";
|
|
5480
|
-
saveRunnerRouteState(
|
|
5481
|
-
routeKey,
|
|
5482
|
-
buildRunnerRouteStateFromComment(selectedRecord, {
|
|
5483
|
-
last_action: "conversation_skipped",
|
|
5484
|
-
last_reason: reason,
|
|
5485
|
-
last_conversation_id: String(effectiveConversationContext?.id || "").trim(),
|
|
5486
|
-
last_conversation_stage: String(effectiveConversationContext?.stage || "").trim(),
|
|
5487
|
-
last_contract_validation_status: String(responseContractValidation.status || "").trim(),
|
|
5488
|
-
last_contract_validation_reason: reason,
|
|
5489
|
-
last_contract_validation_targets: ensureArray(responseContractValidation.targets),
|
|
5490
|
-
...intentStatePatch,
|
|
5491
|
-
}),
|
|
5492
|
-
);
|
|
5493
|
-
return {
|
|
5494
|
-
kind: "skipped",
|
|
5495
|
-
skippedRecord: {
|
|
5496
|
-
id: selectedRecord.id,
|
|
5497
|
-
reason,
|
|
5498
|
-
messageID: intFromRawAllowZero(selectedRecord?.parsedArchive?.messageID, 0),
|
|
5499
|
-
},
|
|
5500
|
-
result: {
|
|
5501
|
-
route_key: routeKey,
|
|
5502
|
-
route_name: normalizedRoute.name,
|
|
5503
|
-
outcome: "contract_validation_failed",
|
|
5504
|
-
detail: reason,
|
|
5505
|
-
thread_id: archiveThread.threadID,
|
|
5506
|
-
comment_id: selectedRecord.id,
|
|
5507
|
-
trigger_kind: String(effectiveTriggerDecision.trigger || "").trim(),
|
|
5508
|
-
conversation_id: String(effectiveConversationContext?.id || "").trim(),
|
|
5509
|
-
conversation_stage: String(effectiveConversationContext?.stage || "").trim(),
|
|
5510
|
-
conversation_intent_mode: String(effectiveConversationContext?.intentMode || "").trim(),
|
|
5511
|
-
conversation_lead_bot: String(effectiveConversationContext?.leadBotUsername || "").trim(),
|
|
5512
|
-
conversation_summary_bot: String(effectiveConversationContext?.summaryBotUsername || "").trim(),
|
|
5513
|
-
execution_contract_type: String(executionContract?.type || "").trim(),
|
|
5514
|
-
execution_contract_actionable: executionContract?.actionable === true,
|
|
5515
|
-
execution_contract_targets: ensureArray(executionContract?.assignments).map((item) => normalizeMentionSelector(item.targetBot)).filter(Boolean),
|
|
5516
|
-
next_expected_responders: collectExecutionContractNextResponders(executionContract),
|
|
5517
|
-
response_contract_validation_status: String(responseContractValidation.status || "").trim(),
|
|
5518
|
-
response_contract_validation_reason: reason,
|
|
5519
|
-
response_contract_validation_targets: ensureArray(responseContractValidation.targets),
|
|
5520
|
-
assignment_validation_status: String(assignmentExecutionValidation.status || "").trim(),
|
|
5521
|
-
assignment_validation_reason: String(assignmentExecutionValidation.reason || "").trim(),
|
|
5522
|
-
assignment_validation_modes: ensureArray(assignmentExecutionValidation.assignmentModes),
|
|
5523
|
-
},
|
|
5524
|
-
};
|
|
5525
|
-
}
|
|
5526
5497
|
if (effectiveConversationContext?.mode === "public_multi_bot") {
|
|
5527
5498
|
const currentBotSelector = normalizeMentionSelector(bot?.username || bot?.name);
|
|
5528
5499
|
const currentSession = safeObject(effectiveConversationContext.session);
|
|
@@ -5679,6 +5650,9 @@ export async function processRunnerSelectedRecord({
|
|
|
5679
5650
|
execution_contract_actionable: executionContract?.actionable === true,
|
|
5680
5651
|
execution_contract_targets: ensureArray(executionContract?.assignments).map((item) => normalizeMentionSelector(item.targetBot)).filter(Boolean),
|
|
5681
5652
|
next_expected_responders: collectExecutionContractNextResponders(executionContract),
|
|
5653
|
+
normalized_execution_contract_type: normalizedExecutionContractType,
|
|
5654
|
+
normalized_execution_contract_targets: normalizedExecutionTargets,
|
|
5655
|
+
normalized_execution_next_responders: normalizedExecutionNextResponders,
|
|
5682
5656
|
artifact_validation: String(artifactValidation.status || "").trim() || "none",
|
|
5683
5657
|
artifact_paths: summarizeValidatedArtifactPaths(artifactValidation),
|
|
5684
5658
|
ai_reply_generated: true,
|
|
@@ -5755,15 +5729,15 @@ export async function processRunnerSelectedRecord({
|
|
|
5755
5729
|
participants: ensureArray(effectiveConversationContext.participantSelectors),
|
|
5756
5730
|
initial_responders: ensureArray(effectiveConversationContext.initialResponderSelectors),
|
|
5757
5731
|
allowed_responders: ensureArray(effectiveConversationContext.allowedResponderSelectors),
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5732
|
+
last_execution_contract_type: String(executionContract?.type || "").trim(),
|
|
5733
|
+
last_execution_contract_actionable: executionContract?.actionable === true,
|
|
5734
|
+
last_execution_contract_targets: normalizedExecutionTargets,
|
|
5735
|
+
next_expected_responders: normalizedExecutionNextResponders,
|
|
5736
|
+
last_speaker_bot_username: currentBotSelector,
|
|
5737
|
+
speaker_counts: speakerCounts,
|
|
5738
|
+
last_sender_bot_username: String(effectiveConversationContext?.senderBotUsername || "").trim(),
|
|
5739
|
+
last_reply_fingerprint_by_bot: {
|
|
5740
|
+
...safeObject(currentSession.last_reply_fingerprint_by_bot),
|
|
5767
5741
|
[currentBotSelector]: normalizeConversationReplyFingerprint(sanitizedReplyText),
|
|
5768
5742
|
},
|
|
5769
5743
|
},
|
|
@@ -5781,14 +5755,17 @@ export async function processRunnerSelectedRecord({
|
|
|
5781
5755
|
safeObject(deliveryResult.delivery.body).result?.message_id ?? safeObject(deliveryResult.delivery.body).message_id,
|
|
5782
5756
|
0,
|
|
5783
5757
|
),
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5758
|
+
last_contract_validation_status: String(responseContractValidation.status || "").trim(),
|
|
5759
|
+
last_contract_validation_reason: String(responseContractValidation.reason || "").trim(),
|
|
5760
|
+
last_contract_validation_targets: ensureArray(responseContractValidation.targets),
|
|
5761
|
+
last_normalized_execution_contract_type: normalizedExecutionContractType,
|
|
5762
|
+
last_normalized_execution_contract_targets: normalizedExecutionTargets,
|
|
5763
|
+
last_normalized_execution_next_responders: normalizedExecutionNextResponders,
|
|
5764
|
+
last_assignment_validation_status: String(assignmentExecutionValidation.status || "").trim(),
|
|
5765
|
+
last_assignment_validation_reason: String(assignmentExecutionValidation.reason || "").trim(),
|
|
5766
|
+
last_trigger: String(effectiveTriggerDecision.trigger || "").trim(),
|
|
5767
|
+
last_reason: effectiveConversationContext?.mode === "public_multi_bot"
|
|
5768
|
+
? [
|
|
5792
5769
|
`conversation=${String(effectiveConversationContext.id || "").trim() || "-"}`,
|
|
5793
5770
|
`stage=${String(effectiveConversationContext.stage || "").trim() || "-"}`,
|
|
5794
5771
|
formatConversationContractSummary(effectiveConversationContext),
|
|
@@ -5855,13 +5832,16 @@ export async function processRunnerSelectedRecord({
|
|
|
5855
5832
|
conversation_initial_responders: ensureArray(effectiveConversationContext?.initialResponderSelectors),
|
|
5856
5833
|
conversation_allowed_responders: ensureArray(effectiveConversationContext?.allowedResponderSelectors),
|
|
5857
5834
|
conversation_allow_bot_to_bot: effectiveConversationContext?.allowBotToBot === true,
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5835
|
+
conversation_reply_expectation: String(effectiveConversationContext?.replyExpectation || "").trim(),
|
|
5836
|
+
execution_contract_type: String(executionContract?.type || "").trim(),
|
|
5837
|
+
execution_contract_actionable: executionContract?.actionable === true,
|
|
5838
|
+
execution_contract_targets: normalizedExecutionTargets,
|
|
5839
|
+
next_expected_responders: normalizedExecutionNextResponders,
|
|
5840
|
+
normalized_execution_contract_type: normalizedExecutionContractType,
|
|
5841
|
+
normalized_execution_contract_targets: normalizedExecutionTargets,
|
|
5842
|
+
normalized_execution_next_responders: normalizedExecutionNextResponders,
|
|
5843
|
+
artifact_validation: String(artifactValidation.status || "").trim() || "none",
|
|
5844
|
+
artifact_paths: summarizeValidatedArtifactPaths(artifactValidation),
|
|
5865
5845
|
ctxpack_version_id: String(safeObject(aiResult?.ctxpackUpdate).version_id || "").trim(),
|
|
5866
5846
|
ctxpack_changed_paths: ensureArray(safeObject(aiResult?.ctxpackUpdate).changed_paths).map((item) => String(item || "").trim()).filter(Boolean),
|
|
5867
5847
|
ctxpack_pushed_file_count: intFromRawAllowZero(safeObject(aiResult?.ctxpackUpdate).pushed_file_count, 0),
|
|
@@ -9644,16 +9644,168 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
9644
9644
|
&& String(processed.result?.execution_contract_type || "") === "summary_request",
|
|
9645
9645
|
`kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} contract=${String(processed.result?.execution_contract_type || "(none)")} reason=${String(processed.skippedRecord?.reason || "(none)")}`,
|
|
9646
9646
|
);
|
|
9647
|
-
|
|
9648
|
-
|
|
9649
|
-
|
|
9647
|
+
} catch (err) {
|
|
9648
|
+
push("delegated_single_lead_non_lead_summary_request_allowed", false, String(err?.message || err));
|
|
9649
|
+
}
|
|
9650
9650
|
|
|
9651
|
-
|
|
9652
|
-
|
|
9653
|
-
|
|
9654
|
-
|
|
9655
|
-
|
|
9656
|
-
|
|
9651
|
+
try {
|
|
9652
|
+
let aiCalls = 0;
|
|
9653
|
+
const processed = await processRunnerSelectedRecord({
|
|
9654
|
+
routeKey: "delegated-single-lead-non-lead-handoff-back-to-lead-key",
|
|
9655
|
+
normalizedRoute: normalizeRunnerRoute({
|
|
9656
|
+
name: "telegram-monitor-delegated-single-lead-non-lead-handoff-back-to-lead",
|
|
9657
|
+
project_id: selftestProjectID,
|
|
9658
|
+
provider: "telegram",
|
|
9659
|
+
role: "monitor",
|
|
9660
|
+
role_profile: "monitor",
|
|
9661
|
+
destination_id: "dest-1",
|
|
9662
|
+
destination_label: "Main Room",
|
|
9663
|
+
server_bot_name: "RyoAI2_bot",
|
|
9664
|
+
server_bot_id: "bot-peer-1",
|
|
9665
|
+
trigger_policy: {
|
|
9666
|
+
mentions_only: true,
|
|
9667
|
+
direct_messages: true,
|
|
9668
|
+
reply_to_bot_messages: true,
|
|
9669
|
+
},
|
|
9670
|
+
}),
|
|
9671
|
+
routeState: {
|
|
9672
|
+
conversation_sessions: {
|
|
9673
|
+
"delegated-single-lead-non-lead-handoff-back-to-lead": {
|
|
9674
|
+
id: "delegated-single-lead-non-lead-handoff-back-to-lead",
|
|
9675
|
+
mode: "public_multi_bot",
|
|
9676
|
+
stage: "bot_reply",
|
|
9677
|
+
status: "open",
|
|
9678
|
+
intent_mode: "delegated_single_lead",
|
|
9679
|
+
lead_bot_username: "ryoai_bot",
|
|
9680
|
+
participants: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
9681
|
+
initial_responders: ["ryoai_bot"],
|
|
9682
|
+
allowed_responders: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
9683
|
+
next_expected_responders: ["ryoai2_bot"],
|
|
9684
|
+
last_execution_contract_type: "delegation",
|
|
9685
|
+
last_execution_contract_targets: ["ryoai2_bot"],
|
|
9686
|
+
last_execution_contract_actionable: true,
|
|
9687
|
+
},
|
|
9688
|
+
},
|
|
9689
|
+
},
|
|
9690
|
+
selectedRecord: {
|
|
9691
|
+
id: "delegated-single-lead-non-lead-handoff-back-to-lead-comment",
|
|
9692
|
+
body: "@RyoAI2_bot 현재 관점으로 의견 주세요.",
|
|
9693
|
+
threadID: "thread-1",
|
|
9694
|
+
createdAt: "2026-03-24T00:00:00.000Z",
|
|
9695
|
+
updatedAt: "2026-03-24T00:00:00.000Z",
|
|
9696
|
+
parsedArchive: {
|
|
9697
|
+
kind: "bot_reply",
|
|
9698
|
+
body: "@RyoAI2_bot 현재 관점으로 의견 주세요.",
|
|
9699
|
+
senderIsBot: true,
|
|
9700
|
+
botUsername: "ryoai_bot",
|
|
9701
|
+
botName: "RyoAI_bot",
|
|
9702
|
+
sender: "RyoAI_bot",
|
|
9703
|
+
senderName: "RyoAI_bot",
|
|
9704
|
+
senderBotUsername: "ryoai_bot",
|
|
9705
|
+
messageID: 990212,
|
|
9706
|
+
chatID: "-1001",
|
|
9707
|
+
mentionUsernames: ["ryoai2_bot"],
|
|
9708
|
+
conversationID: "delegated-single-lead-non-lead-handoff-back-to-lead",
|
|
9709
|
+
executionContract: {
|
|
9710
|
+
type: "delegation",
|
|
9711
|
+
actionable: true,
|
|
9712
|
+
assignments: [{ targetBot: "ryoai2_bot", task: "현재 관점으로 의견을 말하고 리드에게 정리 요청" }],
|
|
9713
|
+
nextResponders: ["ryoai2_bot"],
|
|
9714
|
+
},
|
|
9715
|
+
},
|
|
9716
|
+
},
|
|
9717
|
+
pendingOrdered: [],
|
|
9718
|
+
bot: { id: "bot-peer-1", username: "ryoai2_bot", name: "RyoAI2_bot" },
|
|
9719
|
+
destination: { id: "dest-1", provider: "telegram", chatID: "-1001", label: "Main Room" },
|
|
9720
|
+
archiveThread: {
|
|
9721
|
+
threadID: "thread-1",
|
|
9722
|
+
source: "telegram",
|
|
9723
|
+
projectID: selftestProjectID,
|
|
9724
|
+
},
|
|
9725
|
+
executionPlan: {
|
|
9726
|
+
mode: "role_profile",
|
|
9727
|
+
roleProfileName: "monitor",
|
|
9728
|
+
roleProfile: {
|
|
9729
|
+
client: "sample",
|
|
9730
|
+
model: "",
|
|
9731
|
+
permissionMode: "read_only",
|
|
9732
|
+
reasoningEffort: "low",
|
|
9733
|
+
},
|
|
9734
|
+
workspaceDir: path.join(os.tmpdir(), "metheus-runner-selftest-non-lead-handoff-back-to-lead"),
|
|
9735
|
+
workspaceSource: "selftest",
|
|
9736
|
+
usedCommandFallback: false,
|
|
9737
|
+
},
|
|
9738
|
+
runtime: {
|
|
9739
|
+
baseURL: "https://example.test",
|
|
9740
|
+
token: "selftest-token",
|
|
9741
|
+
timeoutSeconds: 30,
|
|
9742
|
+
actor: { user_id: "user-1" },
|
|
9743
|
+
},
|
|
9744
|
+
triggerDecision: {
|
|
9745
|
+
trigger: "bot_reply_mention",
|
|
9746
|
+
requiresDirectReply: true,
|
|
9747
|
+
candidateResponder: true,
|
|
9748
|
+
},
|
|
9749
|
+
responderAdjudication: {
|
|
9750
|
+
decision: "reply",
|
|
9751
|
+
selected_bot_usernames: ["ryoai2_bot"],
|
|
9752
|
+
},
|
|
9753
|
+
deps: {
|
|
9754
|
+
saveRunnerRouteState: () => {},
|
|
9755
|
+
startRunnerTypingHeartbeat: () => ({ async stop() {} }),
|
|
9756
|
+
runRunnerAIExecution: async () => {
|
|
9757
|
+
aiCalls += 1;
|
|
9758
|
+
return {
|
|
9759
|
+
reply: "@RyoAI_bot 현재 공개된 맥락 기준으로 우선순위와 리스크를 먼저 정리했습니다. 다음 정리를 부탁드립니다.",
|
|
9760
|
+
artifacts: [],
|
|
9761
|
+
ctxpackFiles: [],
|
|
9762
|
+
workItems: [],
|
|
9763
|
+
contract: {
|
|
9764
|
+
type: "delegation",
|
|
9765
|
+
actionable: true,
|
|
9766
|
+
assignments: [{ target_bot: "ryoai_bot", task: "현재 contributor 의견을 정리해서 다음 단계 제안" }],
|
|
9767
|
+
next_responders: ["ryoai_bot"],
|
|
9768
|
+
},
|
|
9769
|
+
};
|
|
9770
|
+
},
|
|
9771
|
+
managedConversationBots: [
|
|
9772
|
+
{ id: "bot-lead", name: "RyoAI_bot" },
|
|
9773
|
+
{ id: "bot-peer-1", name: "RyoAI2_bot" },
|
|
9774
|
+
{ id: "bot-peer-2", name: "RyoAI3_bot" },
|
|
9775
|
+
],
|
|
9776
|
+
performLocalBotDelivery: async () => ({
|
|
9777
|
+
delivery: { dryRun: true, body: {} },
|
|
9778
|
+
archive: {},
|
|
9779
|
+
}),
|
|
9780
|
+
serializeRunnerTriggerPolicy: (value) => value,
|
|
9781
|
+
serializeRunnerArchivePolicy: (value) => value,
|
|
9782
|
+
buildRunnerExecutionDeps: () => ({}),
|
|
9783
|
+
buildRunnerDeliveryDeps: () => ({}),
|
|
9784
|
+
buildRunnerRuntimeDeps: () => ({}),
|
|
9785
|
+
resolveConversationPeerBots: () => [
|
|
9786
|
+
{ id: "bot-lead", name: "RyoAI_bot" },
|
|
9787
|
+
{ id: "bot-peer-1", name: "RyoAI2_bot" },
|
|
9788
|
+
{ id: "bot-peer-2", name: "RyoAI3_bot" },
|
|
9789
|
+
],
|
|
9790
|
+
},
|
|
9791
|
+
});
|
|
9792
|
+
push(
|
|
9793
|
+
"delegated_single_lead_non_lead_handoff_back_to_lead_not_blocked",
|
|
9794
|
+
processed.kind === "replied"
|
|
9795
|
+
&& aiCalls === 1
|
|
9796
|
+
&& String(processed.result?.response_contract_validation_status || "") !== "non_lead_public_assignment",
|
|
9797
|
+
`kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} validation=${String(processed.result?.response_contract_validation_status || "(none)")} contract=${String(processed.result?.execution_contract_type || "(none)")} reason=${String(processed.skippedRecord?.reason || "(none)")}`,
|
|
9798
|
+
);
|
|
9799
|
+
} catch (err) {
|
|
9800
|
+
push("delegated_single_lead_non_lead_handoff_back_to_lead_not_blocked", false, String(err?.message || err));
|
|
9801
|
+
}
|
|
9802
|
+
|
|
9803
|
+
try {
|
|
9804
|
+
let aiCalls = 0;
|
|
9805
|
+
const processed = await processRunnerSelectedRecord({
|
|
9806
|
+
routeKey: "delegated-single-lead-non-lead-new-assignment-recorded-key",
|
|
9807
|
+
normalizedRoute: normalizeRunnerRoute({
|
|
9808
|
+
name: "telegram-monitor-delegated-single-lead-non-lead-new-assignment-recorded",
|
|
9657
9809
|
project_id: selftestProjectID,
|
|
9658
9810
|
provider: "telegram",
|
|
9659
9811
|
role: "monitor",
|
|
@@ -9777,16 +9929,16 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
9777
9929
|
],
|
|
9778
9930
|
},
|
|
9779
9931
|
});
|
|
9780
|
-
|
|
9781
|
-
|
|
9782
|
-
|
|
9783
|
-
|
|
9784
|
-
|
|
9785
|
-
|
|
9786
|
-
|
|
9787
|
-
|
|
9788
|
-
|
|
9789
|
-
|
|
9932
|
+
push(
|
|
9933
|
+
"delegated_single_lead_non_lead_new_assignment_recorded",
|
|
9934
|
+
processed.kind === "replied"
|
|
9935
|
+
&& aiCalls === 1
|
|
9936
|
+
&& String(processed.result?.response_contract_validation_status || "") === "non_lead_public_assignment",
|
|
9937
|
+
`kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} validation=${String(processed.result?.response_contract_validation_status || "(none)")} reason=${String(processed.result?.response_contract_validation_reason || "(none)")}`,
|
|
9938
|
+
);
|
|
9939
|
+
} catch (err) {
|
|
9940
|
+
push("delegated_single_lead_non_lead_new_assignment_recorded", false, String(err?.message || err));
|
|
9941
|
+
}
|
|
9790
9942
|
|
|
9791
9943
|
try {
|
|
9792
9944
|
const workspaceDir = fs.mkdtempSync(path.join(os.tmpdir(), "metheus-runner-selftest-artifacts-ok-"));
|