metheus-governance-mcp-cli 0.2.212 → 0.2.214
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 +65 -16
- package/lib/local-ai-adapters.mjs +6 -0
- package/lib/runner-orchestration.mjs +111 -48
- package/lib/runner-trigger.mjs +36 -18
- package/lib/selftest-runner-scenarios.mjs +127 -6
- package/package.json +1 -1
package/cli.mjs
CHANGED
|
@@ -2358,6 +2358,16 @@ function normalizeBotRunnerRequests(rawRequests, nowMs = Date.now()) {
|
|
|
2358
2358
|
next_expected_responders: ensureArray(entry.next_expected_responders || entry.nextExpectedResponders)
|
|
2359
2359
|
.map((value) => normalizeTelegramMentionUsername(value))
|
|
2360
2360
|
.filter(Boolean),
|
|
2361
|
+
ai_reply_generated: boolFromRaw(
|
|
2362
|
+
entry.ai_reply_generated ?? entry.aiReplyGenerated,
|
|
2363
|
+
false,
|
|
2364
|
+
),
|
|
2365
|
+
ai_reply_generated_at: firstNonEmptyString([entry.ai_reply_generated_at, entry.aiReplyGeneratedAt]),
|
|
2366
|
+
ai_reply_preview: String(entry.ai_reply_preview || entry.aiReplyPreview || "").trim(),
|
|
2367
|
+
delivery_status: String(entry.delivery_status || entry.deliveryStatus || "").trim().toLowerCase(),
|
|
2368
|
+
archive_status: String(entry.archive_status || entry.archiveStatus || "").trim().toLowerCase(),
|
|
2369
|
+
transport_error: String(entry.transport_error || entry.transportError || "").trim(),
|
|
2370
|
+
archive_error: String(entry.archive_error || entry.archiveError || "").trim(),
|
|
2361
2371
|
normalized_intent: String(entry.normalized_intent || entry.normalizedIntent || "").trim().toLowerCase(),
|
|
2362
2372
|
status,
|
|
2363
2373
|
claimed_by_route: String(entry.claimed_by_route || entry.claimedByRoute || "").trim(),
|
|
@@ -4482,6 +4492,13 @@ function markRunnerRequestLifecycle({
|
|
|
4482
4492
|
conversationReplyExpectation = "",
|
|
4483
4493
|
normalizedIntent = "",
|
|
4484
4494
|
closedReason = "",
|
|
4495
|
+
aiReplyGenerated = false,
|
|
4496
|
+
aiReplyGeneratedAt = "",
|
|
4497
|
+
aiReplyPreview = "",
|
|
4498
|
+
deliveryStatus = "",
|
|
4499
|
+
archiveStatus = "",
|
|
4500
|
+
transportError = "",
|
|
4501
|
+
archiveError = "",
|
|
4485
4502
|
}) {
|
|
4486
4503
|
const key = String(requestKey || "").trim();
|
|
4487
4504
|
if (!key) return null;
|
|
@@ -4531,6 +4548,7 @@ function markRunnerRequestLifecycle({
|
|
|
4531
4548
|
const nextStatus = (() => {
|
|
4532
4549
|
if (normalizedOutcome === "claimed") return "claimed";
|
|
4533
4550
|
if (normalizedOutcome === "running") return "running";
|
|
4551
|
+
if (normalizedOutcome === "delivery_failed_after_generation") return "running";
|
|
4534
4552
|
if (normalizedOutcome === "replied") {
|
|
4535
4553
|
return shouldRemainRunningAfterReply ? "running" : "completed";
|
|
4536
4554
|
}
|
|
@@ -4587,6 +4605,15 @@ function markRunnerRequestLifecycle({
|
|
|
4587
4605
|
ensureArray(nextExpectedResponders).length ? nextExpectedResponders : existing.next_expected_responders,
|
|
4588
4606
|
normalizeTelegramMentionUsername,
|
|
4589
4607
|
),
|
|
4608
|
+
ai_reply_generated: aiReplyGenerated === true || existing.ai_reply_generated === true,
|
|
4609
|
+
ai_reply_generated_at: aiReplyGenerated === true
|
|
4610
|
+
? firstNonEmptyString([aiReplyGeneratedAt, existing.ai_reply_generated_at, nowISO])
|
|
4611
|
+
: String(existing.ai_reply_generated_at || "").trim(),
|
|
4612
|
+
ai_reply_preview: String(aiReplyPreview || existing.ai_reply_preview || "").trim(),
|
|
4613
|
+
delivery_status: String(deliveryStatus || existing.delivery_status || "").trim().toLowerCase(),
|
|
4614
|
+
archive_status: String(archiveStatus || existing.archive_status || "").trim().toLowerCase(),
|
|
4615
|
+
transport_error: String(transportError || existing.transport_error || "").trim(),
|
|
4616
|
+
archive_error: String(archiveError || existing.archive_error || "").trim(),
|
|
4590
4617
|
normalized_intent: nextNormalizedIntent,
|
|
4591
4618
|
status: nextStatus,
|
|
4592
4619
|
started_at: firstNonEmptyString([existing.started_at, nowISO]),
|
|
@@ -8741,7 +8768,9 @@ async function processRunnerRouteOnce(route, runtime, mode, options = {}) {
|
|
|
8741
8768
|
requestKey: requestClaim.requestKey,
|
|
8742
8769
|
selectedRecord,
|
|
8743
8770
|
routeKey,
|
|
8744
|
-
outcome:
|
|
8771
|
+
outcome: processed.kind === "delivery_failed"
|
|
8772
|
+
? "delivery_failed_after_generation"
|
|
8773
|
+
: String(processed.result?.outcome || "replied").trim().toLowerCase(),
|
|
8745
8774
|
conversationIDRaw: String(processed.result?.conversation_id || "").trim(),
|
|
8746
8775
|
conversationParticipants: ensureArray(processed.result?.conversation_participants),
|
|
8747
8776
|
conversationInitialResponders: ensureArray(processed.result?.conversation_initial_responders),
|
|
@@ -8757,14 +8786,23 @@ async function processRunnerRouteOnce(route, runtime, mode, options = {}) {
|
|
|
8757
8786
|
currentBotSelector,
|
|
8758
8787
|
conversationIntentMode: String(processed.result?.conversation_intent_mode || "").trim(),
|
|
8759
8788
|
normalizedIntent: resolvedIntentType,
|
|
8789
|
+
aiReplyGenerated: processed.result?.ai_reply_generated === true,
|
|
8790
|
+
aiReplyGeneratedAt: String(processed.result?.ai_reply_generated_at || "").trim(),
|
|
8791
|
+
aiReplyPreview: String(processed.result?.ai_reply_preview || "").trim(),
|
|
8792
|
+
deliveryStatus: String(processed.result?.delivery_status || "").trim(),
|
|
8793
|
+
archiveStatus: String(processed.result?.archive_status || "").trim(),
|
|
8794
|
+
transportError: String(processed.result?.transport_error || "").trim(),
|
|
8795
|
+
archiveError: String(processed.result?.archive_error || "").trim(),
|
|
8760
8796
|
});
|
|
8761
|
-
|
|
8762
|
-
|
|
8763
|
-
|
|
8764
|
-
|
|
8765
|
-
|
|
8766
|
-
|
|
8767
|
-
|
|
8797
|
+
if (processed.kind !== "delivery_failed") {
|
|
8798
|
+
await ensureRunnerRootWorkItemForRequest({
|
|
8799
|
+
normalizedRoute,
|
|
8800
|
+
routeKey,
|
|
8801
|
+
selectedRecord,
|
|
8802
|
+
runtime,
|
|
8803
|
+
requestKey: requestClaim.requestKey,
|
|
8804
|
+
});
|
|
8805
|
+
}
|
|
8768
8806
|
const rootWorkItemSync = await syncRunnerRequestRootWorkItemForOutcome({
|
|
8769
8807
|
normalizedRoute,
|
|
8770
8808
|
runtime,
|
|
@@ -11143,7 +11181,9 @@ async function runRunnerStartResolvedRoutes(routes, flags, options = {}) {
|
|
|
11143
11181
|
requestKey: deferredExecution.requestKey,
|
|
11144
11182
|
selectedRecord: deferredExecution.selectedRecord,
|
|
11145
11183
|
routeKey: deferredExecution.routeKey,
|
|
11146
|
-
outcome:
|
|
11184
|
+
outcome: processed.kind === "delivery_failed"
|
|
11185
|
+
? "delivery_failed_after_generation"
|
|
11186
|
+
: String(processed.result?.outcome || "replied").trim().toLowerCase(),
|
|
11147
11187
|
conversationIDRaw: String(processed.result?.conversation_id || "").trim(),
|
|
11148
11188
|
conversationParticipants: ensureArray(processed.result?.conversation_participants),
|
|
11149
11189
|
conversationInitialResponders: ensureArray(processed.result?.conversation_initial_responders),
|
|
@@ -11161,14 +11201,23 @@ async function runRunnerStartResolvedRoutes(routes, flags, options = {}) {
|
|
|
11161
11201
|
),
|
|
11162
11202
|
conversationIntentMode: String(processed.result?.conversation_intent_mode || "").trim(),
|
|
11163
11203
|
normalizedIntent: resolvedIntentType,
|
|
11204
|
+
aiReplyGenerated: processed.result?.ai_reply_generated === true,
|
|
11205
|
+
aiReplyGeneratedAt: String(processed.result?.ai_reply_generated_at || "").trim(),
|
|
11206
|
+
aiReplyPreview: String(processed.result?.ai_reply_preview || "").trim(),
|
|
11207
|
+
deliveryStatus: String(processed.result?.delivery_status || "").trim(),
|
|
11208
|
+
archiveStatus: String(processed.result?.archive_status || "").trim(),
|
|
11209
|
+
transportError: String(processed.result?.transport_error || "").trim(),
|
|
11210
|
+
archiveError: String(processed.result?.archive_error || "").trim(),
|
|
11164
11211
|
});
|
|
11165
|
-
|
|
11166
|
-
|
|
11167
|
-
|
|
11168
|
-
|
|
11169
|
-
|
|
11170
|
-
|
|
11171
|
-
|
|
11212
|
+
if (processed.kind !== "delivery_failed") {
|
|
11213
|
+
await ensureRunnerRootWorkItemForRequest({
|
|
11214
|
+
normalizedRoute: deferredExecution.normalizedRoute,
|
|
11215
|
+
routeKey: deferredExecution.routeKey,
|
|
11216
|
+
selectedRecord: deferredExecution.selectedRecord,
|
|
11217
|
+
runtime: deferredExecution.runtime,
|
|
11218
|
+
requestKey: deferredExecution.requestKey,
|
|
11219
|
+
});
|
|
11220
|
+
}
|
|
11172
11221
|
const rootWorkItemSync = await syncRunnerRequestRootWorkItemForOutcome({
|
|
11173
11222
|
normalizedRoute: deferredExecution.normalizedRoute,
|
|
11174
11223
|
runtime: deferredExecution.runtime,
|
|
@@ -1657,6 +1657,9 @@ function inferCurrentTurnPurpose({ trigger, conversation, selfBotUsername, other
|
|
|
1657
1657
|
export function buildLocalBotPrompt(payload, { terse = true } = {}) {
|
|
1658
1658
|
const safePayload = payload && typeof payload === "object" ? payload : {};
|
|
1659
1659
|
const taskName = String(safePayload.task || "").trim();
|
|
1660
|
+
const agentContext = safePayload.agent_context && typeof safePayload.agent_context === "object"
|
|
1661
|
+
? safePayload.agent_context
|
|
1662
|
+
: null;
|
|
1660
1663
|
const trigger = safePayload.trigger && typeof safePayload.trigger === "object" ? safePayload.trigger : {};
|
|
1661
1664
|
const responseContract = safePayload.response_contract && typeof safePayload.response_contract === "object"
|
|
1662
1665
|
? safePayload.response_contract
|
|
@@ -1786,6 +1789,9 @@ export function buildLocalBotPrompt(payload, { terse = true } = {}) {
|
|
|
1786
1789
|
"Current turn purpose:",
|
|
1787
1790
|
currentTurnPurpose,
|
|
1788
1791
|
"",
|
|
1792
|
+
"Agent contract/context blob (primary control and state input):",
|
|
1793
|
+
agentContext ? JSON.stringify(agentContext, null, 2) : "-",
|
|
1794
|
+
"",
|
|
1789
1795
|
"Current user request:",
|
|
1790
1796
|
String(trigger.body || "").trim() || "-",
|
|
1791
1797
|
"",
|
|
@@ -5406,55 +5406,114 @@ export async function processRunnerSelectedRecord({
|
|
|
5406
5406
|
messageID: intFromRawAllowZero(selectedRecord?.parsedArchive?.messageID, 0),
|
|
5407
5407
|
},
|
|
5408
5408
|
};
|
|
5409
|
-
}
|
|
5410
|
-
}
|
|
5409
|
+
}
|
|
5410
|
+
}
|
|
5411
|
+
const aiReplyGeneratedAt = new Date().toISOString();
|
|
5412
|
+
const aiReplyPreview = String(sanitizedReplyText || "").replace(/\s+/g, " ").trim().slice(0, 280);
|
|
5411
5413
|
emitRunnerStage("delivering", "sending reply and mirroring archive");
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5414
|
+
let deliveryResult;
|
|
5415
|
+
try {
|
|
5416
|
+
deliveryResult = await performLocalBotDelivery({
|
|
5417
|
+
siteBaseURL: runtime.baseURL,
|
|
5418
|
+
token: runtime.token,
|
|
5419
|
+
timeoutSeconds: runtime.timeoutSeconds,
|
|
5420
|
+
actorUserID: runtime.actor.user_id,
|
|
5421
|
+
bot: {
|
|
5422
|
+
id: bot.id,
|
|
5423
|
+
name: bot.name,
|
|
5424
|
+
username: bot.username,
|
|
5425
|
+
role: bot.role,
|
|
5426
|
+
provider: bot.provider,
|
|
5427
|
+
},
|
|
5428
|
+
projectID: normalizedRoute.projectID,
|
|
5429
|
+
provider: normalizedRoute.provider,
|
|
5430
|
+
destinationSelectors: {
|
|
5431
|
+
destinationID: destination.id,
|
|
5432
|
+
destinationLabel: destination.label,
|
|
5433
|
+
},
|
|
5434
|
+
text: sanitizedReplyText,
|
|
5435
|
+
disableWebPagePreview: true,
|
|
5436
|
+
replyToMessageID,
|
|
5437
|
+
archiveReplies: normalizedRoute.archivePolicy.mirrorReplies,
|
|
5438
|
+
archiveDedupeOutbound: normalizedRoute.archivePolicy.dedupeOutbound,
|
|
5439
|
+
archiveThreadID: archiveThread.threadID,
|
|
5440
|
+
archiveWorkItemID: archiveThread.workItemID,
|
|
5441
|
+
archiveConversation: effectiveConversationContext
|
|
5442
|
+
? {
|
|
5443
|
+
id: effectiveConversationContext.id,
|
|
5444
|
+
mode: effectiveConversationContext.mode,
|
|
5445
|
+
stage: effectiveConversationContext.stage,
|
|
5446
|
+
intentMode: effectiveConversationContext.intentMode,
|
|
5447
|
+
allowBotToBot: effectiveConversationContext.allowBotToBot === true,
|
|
5448
|
+
leadBotUsername: effectiveConversationContext.leadBotUsername,
|
|
5449
|
+
summaryBotUsername: effectiveConversationContext.summaryBotUsername,
|
|
5450
|
+
participants: effectiveConversationContext.participantSelectors,
|
|
5451
|
+
participantSelectors: effectiveConversationContext.participantSelectors,
|
|
5452
|
+
initialResponders: effectiveConversationContext.initialResponderSelectors,
|
|
5453
|
+
initialResponderSelectors: effectiveConversationContext.initialResponderSelectors,
|
|
5454
|
+
allowedResponders: effectiveConversationContext.allowedResponderSelectors,
|
|
5455
|
+
allowedResponderSelectors: effectiveConversationContext.allowedResponderSelectors,
|
|
5456
|
+
executionContract,
|
|
5457
|
+
}
|
|
5458
|
+
: null,
|
|
5459
|
+
dryRun: normalizedRoute.dryRunDelivery,
|
|
5460
|
+
deps: buildRunnerDeliveryDeps(),
|
|
5461
|
+
});
|
|
5462
|
+
} catch (err) {
|
|
5463
|
+
const transportError = String(err?.message || err).trim() || "delivery_failed";
|
|
5464
|
+
saveRunnerRouteState(
|
|
5465
|
+
routeKey,
|
|
5466
|
+
buildRunnerRouteStateFromComment(selectedRecord, {
|
|
5467
|
+
last_action: "delivery_failed_after_generation",
|
|
5468
|
+
last_reason: transportError,
|
|
5469
|
+
last_trigger: String(effectiveTriggerDecision.trigger || "").trim(),
|
|
5470
|
+
last_conversation_id: String(effectiveConversationContext?.id || "").trim(),
|
|
5471
|
+
last_conversation_stage: String(effectiveConversationContext?.stage || "").trim(),
|
|
5472
|
+
last_speaker_bot_username: normalizeMentionSelector(bot?.username || bot?.name),
|
|
5473
|
+
last_workspace_dir: String(effectiveExecutionPlan.workspaceDir || "").trim(),
|
|
5474
|
+
...intentStatePatch,
|
|
5475
|
+
}),
|
|
5476
|
+
);
|
|
5477
|
+
return {
|
|
5478
|
+
kind: "delivery_failed",
|
|
5479
|
+
result: {
|
|
5480
|
+
route_key: routeKey,
|
|
5481
|
+
route_name: normalizedRoute.name,
|
|
5482
|
+
outcome: "delivery_failed_after_generation",
|
|
5483
|
+
detail: `ai reply generated but delivery failed (${transportError})`,
|
|
5484
|
+
thread_id: archiveThread.threadID,
|
|
5485
|
+
comment_id: selectedRecord.id,
|
|
5486
|
+
trigger_kind: String(effectiveTriggerDecision.trigger || "").trim(),
|
|
5487
|
+
conversation_id: String(effectiveConversationContext?.id || "").trim(),
|
|
5488
|
+
conversation_stage: String(effectiveConversationContext?.stage || "").trim(),
|
|
5489
|
+
conversation_intent_mode: String(effectiveConversationContext?.intentMode || "").trim(),
|
|
5490
|
+
conversation_lead_bot: String(effectiveConversationContext?.leadBotUsername || "").trim(),
|
|
5491
|
+
conversation_summary_bot: String(effectiveConversationContext?.summaryBotUsername || "").trim(),
|
|
5492
|
+
conversation_participants: ensureArray(effectiveConversationContext?.participantSelectors),
|
|
5493
|
+
conversation_initial_responders: ensureArray(effectiveConversationContext?.initialResponderSelectors),
|
|
5494
|
+
conversation_allowed_responders: ensureArray(effectiveConversationContext?.allowedResponderSelectors),
|
|
5495
|
+
conversation_allow_bot_to_bot: effectiveConversationContext?.allowBotToBot === true,
|
|
5496
|
+
conversation_reply_expectation: String(effectiveConversationContext?.replyExpectation || "").trim(),
|
|
5497
|
+
execution_contract_type: String(executionContract?.type || "").trim(),
|
|
5498
|
+
execution_contract_actionable: executionContract?.actionable === true,
|
|
5499
|
+
execution_contract_targets: ensureArray(executionContract?.assignments).map((item) => normalizeMentionSelector(item.targetBot)).filter(Boolean),
|
|
5500
|
+
next_expected_responders: collectExecutionContractNextResponders(executionContract),
|
|
5501
|
+
artifact_validation: String(artifactValidation.status || "").trim() || "none",
|
|
5502
|
+
artifact_paths: summarizeValidatedArtifactPaths(artifactValidation),
|
|
5503
|
+
ai_reply_generated: true,
|
|
5504
|
+
ai_reply_generated_at: aiReplyGeneratedAt,
|
|
5505
|
+
ai_reply_preview: aiReplyPreview,
|
|
5506
|
+
delivery_status: "failed_transport",
|
|
5507
|
+
archive_status: "not_attempted",
|
|
5508
|
+
transport_error: transportError,
|
|
5509
|
+
archive_error: "",
|
|
5510
|
+
reply_chars: String(sanitizedReplyText || "").length,
|
|
5511
|
+
execution_mode: effectiveExecutionPlan.mode,
|
|
5512
|
+
role_profile: effectiveExecutionPlan.roleProfileName,
|
|
5513
|
+
executed_role_plan: executedRolePlan && Object.keys(executedRolePlan).length > 0 ? executedRolePlan : undefined,
|
|
5514
|
+
},
|
|
5515
|
+
};
|
|
5516
|
+
}
|
|
5458
5517
|
emitRunnerStage("context_suggesting", "evaluating shared project context suggestion");
|
|
5459
5518
|
const projectContextSuggestion = await maybeCreateSuggestedProjectContext({
|
|
5460
5519
|
aiResult,
|
|
@@ -5629,6 +5688,10 @@ export async function processRunnerSelectedRecord({
|
|
|
5629
5688
|
evidence_ids: ensureArray(aiResult?.evidenceItems).map((item) => String(safeObject(item).id || "").trim()).filter(Boolean),
|
|
5630
5689
|
evidence_paths: ensureArray(aiResult?.evidenceItems).map((item) => String(safeObject(item).path || "").trim()).filter(Boolean),
|
|
5631
5690
|
reply_chars: String(sanitizedReplyText || "").length,
|
|
5691
|
+
ai_reply_generated: true,
|
|
5692
|
+
ai_reply_generated_at: aiReplyGeneratedAt,
|
|
5693
|
+
ai_reply_preview: aiReplyPreview,
|
|
5694
|
+
delivery_status: deliveryResult.delivery.dryRun ? "dry_run" : "delivered",
|
|
5632
5695
|
execution_mode: effectiveExecutionPlan.mode,
|
|
5633
5696
|
role_profile: effectiveExecutionPlan.roleProfileName,
|
|
5634
5697
|
executed_role_plan: executedRolePlan && Object.keys(executedRolePlan).length > 0 ? executedRolePlan : undefined,
|
package/lib/runner-trigger.mjs
CHANGED
|
@@ -94,19 +94,7 @@ function buildTriggerCandidateBotUsernames(parsedArchive) {
|
|
|
94
94
|
function buildRunnerTaskName(humanIntentType, humanIntentContract = null) {
|
|
95
95
|
const normalizedIntentType = String(humanIntentType || "").trim().toLowerCase();
|
|
96
96
|
const contract = safeObject(humanIntentContract);
|
|
97
|
-
const replyExpectation = String(contract.replyExpectation || contract.reply_expectation || "").trim().toLowerCase();
|
|
98
97
|
const executionContractType = String(contract.executionContractType || contract.execution_contract_type || "").trim().toLowerCase();
|
|
99
|
-
const intentMode = String(contract.intentMode || contract.intent_mode || "").trim().toLowerCase();
|
|
100
|
-
const executionIntentRequested = [
|
|
101
|
-
"general_execution",
|
|
102
|
-
"ctxpack_mutation",
|
|
103
|
-
"workitem_mutation",
|
|
104
|
-
].includes(normalizedIntentType);
|
|
105
|
-
const collaborativeIntentMode = [
|
|
106
|
-
"delegated_single_lead",
|
|
107
|
-
"multi_bot_collab",
|
|
108
|
-
"multi_bot_direct",
|
|
109
|
-
].includes(intentMode);
|
|
110
98
|
if (normalizedIntentType === "status_query") return "answer_project_status_query";
|
|
111
99
|
if (normalizedIntentType === "workspace_query") return "answer_project_workspace_query";
|
|
112
100
|
if (normalizedIntentType === "bot_role_query") return "answer_project_bot_role_query";
|
|
@@ -115,12 +103,6 @@ function buildRunnerTaskName(humanIntentType, humanIntentContract = null) {
|
|
|
115
103
|
if (executionContractType) {
|
|
116
104
|
return "reply_to_project_actionable_message";
|
|
117
105
|
}
|
|
118
|
-
if (collaborativeIntentMode && replyExpectation === "actionable") {
|
|
119
|
-
return "reply_to_project_chat_message";
|
|
120
|
-
}
|
|
121
|
-
if (executionIntentRequested) {
|
|
122
|
-
return "reply_to_project_actionable_message";
|
|
123
|
-
}
|
|
124
106
|
return "reply_to_project_chat_message";
|
|
125
107
|
}
|
|
126
108
|
|
|
@@ -199,6 +181,9 @@ export function buildRunnerInputPayload({
|
|
|
199
181
|
const directHumanIntent = safeObject(humanIntentContract);
|
|
200
182
|
const safeDirectQueryReply = safeObject(directQueryReply);
|
|
201
183
|
const candidateBotUsernames = buildTriggerCandidateBotUsernames(parsed);
|
|
184
|
+
const executionContractType = String(
|
|
185
|
+
directHumanIntent.executionContractType || directHumanIntent.execution_contract_type || "",
|
|
186
|
+
).trim().toLowerCase();
|
|
202
187
|
return {
|
|
203
188
|
task: buildRunnerTaskName(directHumanIntent.intentType, directHumanIntent),
|
|
204
189
|
project_id: String(route?.projectID || "").trim(),
|
|
@@ -279,6 +264,39 @@ export function buildRunnerInputPayload({
|
|
|
279
264
|
require_actionable_contract: directHumanIntent.requiresActionableContract === true,
|
|
280
265
|
allowed_contract_types: ensureArray(directHumanIntent.allowedContractTypes),
|
|
281
266
|
},
|
|
267
|
+
agent_context: {
|
|
268
|
+
bot_identity: {
|
|
269
|
+
id: String(bot?.id || "").trim(),
|
|
270
|
+
name: String(bot?.name || "").trim(),
|
|
271
|
+
username: String(bot?.username || "").trim(),
|
|
272
|
+
role: String(bot?.role || route?.role || "").trim(),
|
|
273
|
+
},
|
|
274
|
+
request_facts: {
|
|
275
|
+
comment_id: selectedRecord?.id,
|
|
276
|
+
trigger_kind: String(triggerDecision?.trigger || "").trim(),
|
|
277
|
+
body: String(parsed.body || "").trim(),
|
|
278
|
+
message_id: Number.parseInt(String(parsed.messageID ?? 0), 10) || 0,
|
|
279
|
+
reply_to_message_id: Number.parseInt(String(parsed.replyToMessageID ?? 0), 10) || 0,
|
|
280
|
+
},
|
|
281
|
+
conversation_contract: {
|
|
282
|
+
conversation_id: String(directHumanIntent.conversationID || directHumanIntent.conversation_id || parsed.conversationID || "").trim(),
|
|
283
|
+
mode: String(directHumanIntent.intentMode || directHumanIntent.intent_mode || "").trim(),
|
|
284
|
+
intent_type: String(directHumanIntent.intentType || directHumanIntent.intent_type || "").trim(),
|
|
285
|
+
lead_bot: String(directHumanIntent.leadBotSelector || directHumanIntent.lead_bot || "").trim(),
|
|
286
|
+
summary_bot: String(directHumanIntent.summaryBotSelector || directHumanIntent.summary_bot || "").trim(),
|
|
287
|
+
participants: ensureArray(directHumanIntent.participantSelectors || directHumanIntent.participants),
|
|
288
|
+
initial_responders: ensureArray(directHumanIntent.initialResponderSelectors || directHumanIntent.initial_responders),
|
|
289
|
+
allowed_responders: ensureArray(directHumanIntent.allowedResponderSelectors || directHumanIntent.allowed_responders),
|
|
290
|
+
reply_expectation: String(directHumanIntent.replyExpectation || directHumanIntent.reply_expectation || "").trim(),
|
|
291
|
+
execution_contract_type: executionContractType,
|
|
292
|
+
},
|
|
293
|
+
validation_contract: {
|
|
294
|
+
current_bot_is_candidate: true,
|
|
295
|
+
require_actionable_contract: directHumanIntent.requiresActionableContract === true,
|
|
296
|
+
allowed_contract_types: ensureArray(directHumanIntent.allowedContractTypes),
|
|
297
|
+
candidate_bot_usernames: candidateBotUsernames,
|
|
298
|
+
},
|
|
299
|
+
},
|
|
282
300
|
conversation: conversationContext
|
|
283
301
|
? {
|
|
284
302
|
mode: String(conversationContext.mode || "").trim(),
|
|
@@ -11985,12 +11985,133 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
11985
11985
|
&& !/project-operating-guide\.md/i.test(deliveredText),
|
|
11986
11986
|
`kind=${String(processed.kind || "(none)")} outcome=${String(processed.result?.outcome || "(none)")} delivery_calls=${deliveryCalls} delivered=${deliveredText} detail=${String(processed.result?.detail || "(none)")}`,
|
|
11987
11987
|
);
|
|
11988
|
-
} catch (err) {
|
|
11989
|
-
push("runner_direct_failure_reply_uses_generic_message_for_unobserved_reported_artifacts", false, String(err?.message || err));
|
|
11990
|
-
}
|
|
11991
|
-
|
|
11992
|
-
try {
|
|
11993
|
-
const
|
|
11988
|
+
} catch (err) {
|
|
11989
|
+
push("runner_direct_failure_reply_uses_generic_message_for_unobserved_reported_artifacts", false, String(err?.message || err));
|
|
11990
|
+
}
|
|
11991
|
+
|
|
11992
|
+
try {
|
|
11993
|
+
const processed = await processRunnerSelectedRecord({
|
|
11994
|
+
routeKey: "delivery-failed-after-generation-key",
|
|
11995
|
+
normalizedRoute: normalizeRunnerRoute({
|
|
11996
|
+
name: "telegram-monitor-delivery-failed-after-generation",
|
|
11997
|
+
project_id: selftestProjectID,
|
|
11998
|
+
provider: "telegram",
|
|
11999
|
+
role: "monitor",
|
|
12000
|
+
role_profile: "monitor",
|
|
12001
|
+
destination_id: "dest-1",
|
|
12002
|
+
destination_label: "Main Room",
|
|
12003
|
+
server_bot_name: "RyoAI_bot",
|
|
12004
|
+
server_bot_id: "bot-1",
|
|
12005
|
+
trigger_policy: {
|
|
12006
|
+
mentions_only: true,
|
|
12007
|
+
direct_messages: true,
|
|
12008
|
+
reply_to_bot_messages: true,
|
|
12009
|
+
},
|
|
12010
|
+
archive_policy: {
|
|
12011
|
+
mirror_replies: true,
|
|
12012
|
+
dedupe_inbound: true,
|
|
12013
|
+
dedupe_outbound: true,
|
|
12014
|
+
skip_bot_messages: true,
|
|
12015
|
+
},
|
|
12016
|
+
dry_run_delivery: false,
|
|
12017
|
+
}),
|
|
12018
|
+
selectedRecord: {
|
|
12019
|
+
id: "comment-delivery-failed-after-generation",
|
|
12020
|
+
createdAt: "2026-03-17T00:00:21.000Z",
|
|
12021
|
+
parsedArchive: {
|
|
12022
|
+
kind: "telegram_message",
|
|
12023
|
+
chatID: "-100123",
|
|
12024
|
+
chatType: "supergroup",
|
|
12025
|
+
body: "@RyoAI_bot hi",
|
|
12026
|
+
messageID: 126,
|
|
12027
|
+
sender: "human",
|
|
12028
|
+
senderIsBot: false,
|
|
12029
|
+
mentionUsernames: ["ryoai_bot"],
|
|
12030
|
+
},
|
|
12031
|
+
},
|
|
12032
|
+
pendingOrdered: [],
|
|
12033
|
+
bot: {
|
|
12034
|
+
id: "bot-1",
|
|
12035
|
+
name: "RyoAI_bot",
|
|
12036
|
+
username: "RyoAI_bot",
|
|
12037
|
+
role: "monitor",
|
|
12038
|
+
provider: "telegram",
|
|
12039
|
+
},
|
|
12040
|
+
destination: {
|
|
12041
|
+
id: "dest-1",
|
|
12042
|
+
label: "Main Room",
|
|
12043
|
+
provider: "telegram",
|
|
12044
|
+
chatID: "-100123",
|
|
12045
|
+
},
|
|
12046
|
+
archiveThread: {
|
|
12047
|
+
threadID: "thread-1",
|
|
12048
|
+
workItemID: "work-item-1",
|
|
12049
|
+
},
|
|
12050
|
+
executionPlan: {
|
|
12051
|
+
mode: "role_profile",
|
|
12052
|
+
roleProfileName: "monitor",
|
|
12053
|
+
roleProfile: {
|
|
12054
|
+
client: "sample",
|
|
12055
|
+
model: "",
|
|
12056
|
+
permissionMode: "read_only",
|
|
12057
|
+
reasoningEffort: "low",
|
|
12058
|
+
},
|
|
12059
|
+
workspaceDir: "",
|
|
12060
|
+
workspaceSource: "selftest",
|
|
12061
|
+
usedCommandFallback: false,
|
|
12062
|
+
},
|
|
12063
|
+
runtime: {
|
|
12064
|
+
baseURL: "https://example.test",
|
|
12065
|
+
token: "selftest-token",
|
|
12066
|
+
timeoutSeconds: 30,
|
|
12067
|
+
actor: { user_id: "user-1" },
|
|
12068
|
+
},
|
|
12069
|
+
deps: {
|
|
12070
|
+
saveRunnerRouteState: () => {},
|
|
12071
|
+
startRunnerTypingHeartbeat: () => ({ async stop() {} }),
|
|
12072
|
+
runRunnerAIExecution: async () => ({
|
|
12073
|
+
skip: false,
|
|
12074
|
+
reply: "Hello from RyoAI_bot.",
|
|
12075
|
+
}),
|
|
12076
|
+
performLocalBotDelivery: async () => {
|
|
12077
|
+
throw new Error("read ECONNRESET");
|
|
12078
|
+
},
|
|
12079
|
+
serializeRunnerTriggerPolicy: (value) => value,
|
|
12080
|
+
serializeRunnerArchivePolicy: (value) => value,
|
|
12081
|
+
buildRunnerExecutionDeps: () => ({
|
|
12082
|
+
validateWorkspaceArtifacts,
|
|
12083
|
+
analyzeHumanConversationIntentWithAI: async () => ({
|
|
12084
|
+
mode: "single_bot",
|
|
12085
|
+
lead_bot: "ryoai_bot",
|
|
12086
|
+
participants: ["ryoai_bot"],
|
|
12087
|
+
initial_responders: ["ryoai_bot"],
|
|
12088
|
+
allowed_responders: ["ryoai_bot"],
|
|
12089
|
+
summary_bot: "",
|
|
12090
|
+
allow_bot_to_bot: false,
|
|
12091
|
+
reply_expectation: "informational",
|
|
12092
|
+
intent_type: "small_talk",
|
|
12093
|
+
}),
|
|
12094
|
+
}),
|
|
12095
|
+
buildRunnerDeliveryDeps: () => ({}),
|
|
12096
|
+
buildRunnerRuntimeDeps: () => ({}),
|
|
12097
|
+
resolveConversationPeerBots: () => [],
|
|
12098
|
+
},
|
|
12099
|
+
});
|
|
12100
|
+
push(
|
|
12101
|
+
"runner_delivery_failure_after_generation_records_ai_state_without_execution_error",
|
|
12102
|
+
processed.kind === "delivery_failed"
|
|
12103
|
+
&& String(processed.result?.outcome || "") === "delivery_failed_after_generation"
|
|
12104
|
+
&& processed.result?.ai_reply_generated === true
|
|
12105
|
+
&& String(processed.result?.delivery_status || "") === "failed_transport"
|
|
12106
|
+
&& /ECONNRESET/i.test(String(processed.result?.transport_error || "")),
|
|
12107
|
+
`kind=${String(processed.kind || "(none)")} outcome=${String(processed.result?.outcome || "(none)")} ai_generated=${String(processed.result?.ai_reply_generated || false)} delivery=${String(processed.result?.delivery_status || "(none)")} transport=${String(processed.result?.transport_error || "(none)")}`,
|
|
12108
|
+
);
|
|
12109
|
+
} catch (err) {
|
|
12110
|
+
push("runner_delivery_failure_after_generation_records_ai_state_without_execution_error", false, String(err?.message || err));
|
|
12111
|
+
}
|
|
12112
|
+
|
|
12113
|
+
try {
|
|
12114
|
+
const workspaceDir = fs.mkdtempSync(path.join(os.tmpdir(), "metheus-runner-selftest-observed-artifacts-"));
|
|
11994
12115
|
const scriptDir = path.join(workspaceDir, ".metheus", "runner-runtime", "local-ai-scratch");
|
|
11995
12116
|
fs.mkdirSync(scriptDir, { recursive: true });
|
|
11996
12117
|
const scriptPath = path.join(scriptDir, "emit-artifact.js");
|