metheus-governance-mcp-cli 0.2.295 → 0.2.296

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.
@@ -383,6 +383,19 @@ function buildRunnerRequestFollowupSyntheticRecord(requestRaw, currentBotSelecto
383
383
  .map((value) => normalizeMentionSelector(value))
384
384
  .filter(Boolean),
385
385
  ));
386
+ const normalizedExecutionContractType = String(
387
+ request.execution_contract_type || request.normalized_execution_contract_type || "",
388
+ ).trim().toLowerCase() || "direct_result";
389
+ const normalizedSummaryBotSelector = normalizeMentionSelector(request.conversation_summary_bot);
390
+ const executionContract = {
391
+ type: normalizedExecutionContractType,
392
+ actionable: request.execution_contract_actionable === true,
393
+ assignments: executionTargets.map((targetBot) => ({
394
+ target_bot: targetBot,
395
+ })),
396
+ ...(normalizedSummaryBotSelector ? { summary_bot: normalizedSummaryBotSelector } : {}),
397
+ ...(nextResponders.length > 0 ? { next_responders: nextResponders } : {}),
398
+ };
386
399
  const replyOccurredAtMs = Date.parse(occurredAt);
387
400
  const maxPendingAgeMs = intFromRawAllowZero(safeObject(pendingSelectionOptions).maxPendingAgeMs, 0);
388
401
  const staleAfterAt = maxPendingAgeMs > 0 && Number.isFinite(replyOccurredAtMs)
@@ -412,27 +425,33 @@ function buildRunnerRequestFollowupSyntheticRecord(requestRaw, currentBotSelecto
412
425
  senderIsBot: true,
413
426
  username: senderSelector,
414
427
  botUsername: senderSelector,
415
- mentionUsernames: ensureArray(replyEnvelope.mention_usernames),
428
+ mentionUsernames: uniqueOrdered([
429
+ ...ensureArray(replyEnvelope.mention_usernames)
430
+ .map((value) => normalizeMentionSelector(value))
431
+ .filter(Boolean),
432
+ ...nextResponders,
433
+ ]),
416
434
  occurredAt,
417
435
  body: String(replyEnvelope.body || "").trim(),
418
436
  conversationID: String(request.conversation_id || "").trim(),
419
- conversationMode: String(request.conversation_intent_mode || "").trim(),
437
+ conversationMode: "public_multi_bot",
420
438
  conversationStage: "bot_reply",
439
+ conversationIntentMode: String(request.conversation_intent_mode || "").trim(),
421
440
  conversationAllowBotToBot: request.conversation_allow_bot_to_bot === true,
422
441
  conversationLeadBotUsername: normalizeMentionSelector(request.conversation_lead_bot),
423
- conversationSummaryBotUsername: normalizeMentionSelector(request.conversation_summary_bot),
442
+ conversationSummaryBotUsername: normalizedSummaryBotSelector,
424
443
  conversationTargetBotUsername: nextResponders.length === 1 ? nextResponders[0] : "",
425
444
  conversationParticipants: participants,
426
445
  conversationInitialResponders: initialResponders,
427
446
  conversationAllowedResponders: allowedResponders,
428
447
  conversationReplyExpectation: String(request.conversation_reply_expectation || "").trim().toLowerCase(),
429
- executionContractType: String(
430
- request.execution_contract_type || request.normalized_execution_contract_type || "",
431
- ).trim().toLowerCase(),
448
+ executionContract,
449
+ executionContractType: normalizedExecutionContractType,
432
450
  executionContractActionable: request.execution_contract_actionable === true,
433
451
  executionContractAssignments: executionTargets.map((targetBot) => ({
434
452
  targetBot,
435
453
  })),
454
+ executionContractSummaryBot: normalizedSummaryBotSelector,
436
455
  executionContractNextResponders: nextResponders,
437
456
  sourceOrigin: "request_followup_replay",
438
457
  sourceRouteKey: String(request.claimed_by_route || "").trim(),
@@ -22236,7 +22236,10 @@ export async function runSelftestRunnerScenarios(push, deps) {
22236
22236
  && ensureArray(safeObject(pendingWork.pending).pending).length === 1
22237
22237
  && String(safeObject(ensureArray(pendingWork.requestFollowupPending)[0]).id || "").startsWith("request-followup:request-followup-1:498:ryoai_bot")
22238
22238
  && safeObject(safeObject(ensureArray(pendingWork.requestFollowupPending)[0]).parsedArchive).kind === "bot_reply"
22239
- && ensureArray(safeObject(safeObject(ensureArray(pendingWork.requestFollowupPending)[0]).parsedArchive).executionContractNextResponders).includes("ryoai_bot"),
22239
+ && String(safeObject(safeObject(ensureArray(pendingWork.requestFollowupPending)[0]).parsedArchive).conversationMode || "") === "public_multi_bot"
22240
+ && String(safeObject(safeObject(ensureArray(pendingWork.requestFollowupPending)[0]).parsedArchive).conversationIntentMode || "") === "multi_bot_direct"
22241
+ && ensureArray(safeObject(safeObject(ensureArray(pendingWork.requestFollowupPending)[0]).parsedArchive).executionContractNextResponders).includes("ryoai_bot")
22242
+ && ensureArray(safeObject(safeObject(safeObject(ensureArray(pendingWork.requestFollowupPending)[0]).parsedArchive).executionContract).next_responders).includes("ryoai_bot"),
22240
22243
  `replay=${ensureArray(pendingWork.requestFollowupPending).map((item) => String(safeObject(item).id || "")).join(",") || "(none)"} pending=${ensureArray(safeObject(pendingWork.pending).pending).map((item) => String(safeObject(item).id || "")).join(",") || "(none)"}`,
22241
22244
  );
22242
22245
  } catch (err) {
@@ -22310,6 +22313,174 @@ export async function runSelftestRunnerScenarios(push, deps) {
22310
22313
  push("runner_entrypoint_does_not_replay_request_followup_after_route_cursor", false, String(err?.message || err));
22311
22314
  }
22312
22315
 
22316
+ try {
22317
+ const pendingWork = selectRunnerPendingWorkEntrypoint({
22318
+ comments: [],
22319
+ importOutcome: {
22320
+ importedCommentIDs: [],
22321
+ importedComments: [],
22322
+ currentPollLocalInboundReceipts: [],
22323
+ },
22324
+ refreshedState: {
22325
+ last_processed_comment_id: "comment-before-followup-3",
22326
+ last_processed_created_at: "2026-04-06T00:12:00.000Z",
22327
+ },
22328
+ mode: "continue",
22329
+ parseArchivedChatComment,
22330
+ deps: {
22331
+ normalizeArchiveCommentRecord: (record) => ({
22332
+ id: String(record?.id || "").trim(),
22333
+ body: String(record?.body || "").trim(),
22334
+ createdAt: String(record?.created_at || record?.createdAt || record?.updated_at || record?.updatedAt || "").trim(),
22335
+ updatedAt: String(record?.updated_at || record?.updatedAt || "").trim(),
22336
+ parsedArchive: safeObject(record?.parsedArchive),
22337
+ }),
22338
+ applyPendingAgeSelection: (selection) => selection,
22339
+ },
22340
+ pendingSelectionOptions: {},
22341
+ followupRequests: [
22342
+ {
22343
+ request_key: "request-followup-3",
22344
+ status: "running",
22345
+ project_id: selftestProjectID,
22346
+ provider: "telegram",
22347
+ chat_id: "-100126",
22348
+ conversation_id: "conversation-followup-3",
22349
+ conversation_intent_mode: "multi_bot_direct",
22350
+ conversation_allow_bot_to_bot: true,
22351
+ conversation_participants: ["ryoai2_bot", "ryoai3_bot"],
22352
+ conversation_initial_responders: ["ryoai2_bot", "ryoai3_bot"],
22353
+ conversation_allowed_responders: ["ryoai2_bot", "ryoai3_bot"],
22354
+ execution_contract_type: "direct_result",
22355
+ execution_contract_actionable: true,
22356
+ execution_contract_targets: ["ryoai2_bot", "ryoai3_bot"],
22357
+ next_expected_responders: ["ryoai3_bot"],
22358
+ updated_at: "2026-04-06T00:12:00.000Z",
22359
+ last_reply_message_envelope: {
22360
+ chat_id: "-100126",
22361
+ message_id: 515,
22362
+ reply_to_message_id: 514,
22363
+ body: "안녕하세요, RyoAI2_bot입니다.",
22364
+ sender: "@RyoAI2_bot",
22365
+ sender_username: "ryoai2_bot",
22366
+ sender_is_bot: true,
22367
+ occurred_at: "2026-04-06T00:12:00.000Z",
22368
+ canonical_human_message_key: "shared-human-key-515",
22369
+ },
22370
+ },
22371
+ ],
22372
+ currentBotSelector: "ryoai3_bot",
22373
+ });
22374
+ let aiCalls = 0;
22375
+ const deliveredConversation = [];
22376
+ const processed = await processRunnerSelectedRecord({
22377
+ routeKey: "runner-followup-public-multi-bot-peer-key",
22378
+ normalizedRoute: normalizeRunnerRoute({
22379
+ name: "telegram-monitor-runner-followup-public-multi-bot-peer",
22380
+ project_id: selftestProjectID,
22381
+ provider: "telegram",
22382
+ role: "monitor",
22383
+ role_profile: "monitor",
22384
+ destination_id: "dest-1",
22385
+ destination_label: "Main Room",
22386
+ server_bot_name: "RyoAI3_bot",
22387
+ server_bot_id: "bot-peer-2",
22388
+ trigger_policy: {
22389
+ mentions_only: true,
22390
+ direct_messages: true,
22391
+ reply_to_bot_messages: true,
22392
+ },
22393
+ archive_policy: {
22394
+ mirror_replies: true,
22395
+ dedupe_inbound: true,
22396
+ dedupe_outbound: true,
22397
+ skip_bot_messages: true,
22398
+ },
22399
+ dry_run_delivery: true,
22400
+ }),
22401
+ selectedRecord: ensureArray(pendingWork.requestFollowupPending)[0],
22402
+ pendingOrdered: ensureArray(pendingWork.pending?.pending),
22403
+ bot: {
22404
+ id: "bot-peer-2",
22405
+ name: "RyoAI3_bot",
22406
+ username: "RyoAI3_bot",
22407
+ role: "monitor",
22408
+ provider: "telegram",
22409
+ },
22410
+ destination: {
22411
+ id: "dest-1",
22412
+ label: "Main Room",
22413
+ provider: "telegram",
22414
+ chatID: "-100126",
22415
+ },
22416
+ archiveThread: {
22417
+ threadID: "thread-1",
22418
+ workItemID: "work-item-1",
22419
+ },
22420
+ executionPlan: {
22421
+ mode: "role_profile",
22422
+ roleProfileName: "monitor",
22423
+ roleProfile: {
22424
+ client: "sample",
22425
+ model: "",
22426
+ permissionMode: "read_only",
22427
+ reasoningEffort: "low",
22428
+ },
22429
+ workspaceDir: path.join(os.tmpdir(), "metheus-runner-selftest-followup-public-multi-bot-peer"),
22430
+ workspaceSource: "selftest",
22431
+ usedCommandFallback: false,
22432
+ },
22433
+ runtime: {
22434
+ baseURL: "https://example.test",
22435
+ token: "selftest-token",
22436
+ timeoutSeconds: 30,
22437
+ actor: { user_id: "user-1" },
22438
+ },
22439
+ deps: {
22440
+ saveRunnerRouteState: () => {},
22441
+ startRunnerTypingHeartbeat: () => ({ async stop() {} }),
22442
+ runRunnerAIExecution: async () => {
22443
+ aiCalls += 1;
22444
+ return {
22445
+ skip: false,
22446
+ reply: "안녕하세요, RyoAI3_bot입니다.",
22447
+ };
22448
+ },
22449
+ performLocalBotDelivery: async ({ archiveConversation, archiveConversationContext, archiveExecutionContract }) => {
22450
+ deliveredConversation.push(buildSelftestArchiveConversation({
22451
+ archiveConversation,
22452
+ archiveConversationContext,
22453
+ archiveExecutionContract,
22454
+ }));
22455
+ return {
22456
+ delivery: { dryRun: true, body: {} },
22457
+ archive: {},
22458
+ };
22459
+ },
22460
+ serializeRunnerTriggerPolicy: (value) => value,
22461
+ serializeRunnerArchivePolicy: (value) => value,
22462
+ buildRunnerExecutionDeps: () => ({}),
22463
+ buildRunnerDeliveryDeps: () => ({}),
22464
+ buildRunnerRuntimeDeps: () => ({}),
22465
+ resolveConversationPeerBots: () => [
22466
+ { id: "bot-peer-1", name: "RyoAI2_bot" },
22467
+ { id: "bot-peer-2", name: "RyoAI3_bot" },
22468
+ ],
22469
+ },
22470
+ });
22471
+ push(
22472
+ "runner_request_followup_public_multi_bot_continuation_is_authorized",
22473
+ processed.kind === "replied"
22474
+ && aiCalls === 1
22475
+ && String(deliveredConversation[0]?.mode || "") === "public_multi_bot"
22476
+ && String(deliveredConversation[0]?.intentMode || "") === "multi_bot_direct"
22477
+ && ensureArray(deliveredConversation[0]?.allowedResponderSelectors).includes("ryoai3_bot"),
22478
+ `kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} mode=${String(deliveredConversation[0]?.mode || "(none)")} intent=${String(deliveredConversation[0]?.intentMode || "(none)")} reason=${String(processed.skippedRecord?.reason || "(none)")}`,
22479
+ );
22480
+ } catch (err) {
22481
+ push("runner_request_followup_public_multi_bot_continuation_is_authorized", false, String(err?.message || err));
22482
+ }
22483
+
22313
22484
  try {
22314
22485
  const deliveryContext = await prepareLocalBotDeliveryContext({
22315
22486
  siteBaseURL: "https://example.test",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metheus-governance-mcp-cli",
3
- "version": "0.2.295",
3
+ "version": "0.2.296",
4
4
  "description": "Metheus Governance MCP CLI (setup + stdio proxy)",
5
5
  "type": "module",
6
6
  "files": [