metheus-governance-mcp-cli 0.2.225 → 0.2.226
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 +26 -0
- package/lib/local-ai-adapters.mjs +15 -4
- package/lib/runner-orchestration.mjs +251 -71
- package/lib/selftest-runner-scenarios.mjs +161 -10
- package/package.json +1 -1
package/cli.mjs
CHANGED
|
@@ -2397,6 +2397,11 @@ function normalizeBotRunnerRequests(rawRequests, nowMs = Date.now()) {
|
|
|
2397
2397
|
response_contract_validation_targets: ensureArray(entry.response_contract_validation_targets || entry.responseContractValidationTargets)
|
|
2398
2398
|
.map((value) => normalizeTelegramMentionUsername(value))
|
|
2399
2399
|
.filter(Boolean),
|
|
2400
|
+
assignment_validation_status: String(entry.assignment_validation_status || entry.assignmentValidationStatus || "").trim().toLowerCase(),
|
|
2401
|
+
assignment_validation_reason: String(entry.assignment_validation_reason || entry.assignmentValidationReason || "").trim(),
|
|
2402
|
+
assignment_validation_modes: ensureArray(entry.assignment_validation_modes || entry.assignmentValidationModes)
|
|
2403
|
+
.map((value) => String(value || "").trim().toLowerCase())
|
|
2404
|
+
.filter(Boolean),
|
|
2400
2405
|
delivery_status: String(entry.delivery_status || entry.deliveryStatus || "").trim().toLowerCase(),
|
|
2401
2406
|
archive_status: String(entry.archive_status || entry.archiveStatus || "").trim().toLowerCase(),
|
|
2402
2407
|
transport_error: String(entry.transport_error || entry.transportError || "").trim(),
|
|
@@ -4516,6 +4521,9 @@ function markRunnerRequestLifecycle({
|
|
|
4516
4521
|
responseContractValidationStatus = "",
|
|
4517
4522
|
responseContractValidationReason = "",
|
|
4518
4523
|
responseContractValidationTargets = [],
|
|
4524
|
+
assignmentValidationStatus = "",
|
|
4525
|
+
assignmentValidationReason = "",
|
|
4526
|
+
assignmentValidationModes = [],
|
|
4519
4527
|
deliveryStatus = "",
|
|
4520
4528
|
archiveStatus = "",
|
|
4521
4529
|
transportError = "",
|
|
@@ -4643,6 +4651,18 @@ function markRunnerRequestLifecycle({
|
|
|
4643
4651
|
: existing.response_contract_validation_targets,
|
|
4644
4652
|
normalizeTelegramMentionUsername,
|
|
4645
4653
|
),
|
|
4654
|
+
assignment_validation_status: String(
|
|
4655
|
+
assignmentValidationStatus || existing.assignment_validation_status || "",
|
|
4656
|
+
).trim().toLowerCase(),
|
|
4657
|
+
assignment_validation_reason: String(
|
|
4658
|
+
assignmentValidationReason || existing.assignment_validation_reason || "",
|
|
4659
|
+
).trim(),
|
|
4660
|
+
assignment_validation_modes: uniqueOrderedStrings(
|
|
4661
|
+
ensureArray(assignmentValidationModes).length
|
|
4662
|
+
? assignmentValidationModes
|
|
4663
|
+
: existing.assignment_validation_modes,
|
|
4664
|
+
(value) => String(value || "").trim().toLowerCase(),
|
|
4665
|
+
),
|
|
4646
4666
|
delivery_status: String(deliveryStatus || existing.delivery_status || "").trim().toLowerCase(),
|
|
4647
4667
|
archive_status: String(archiveStatus || existing.archive_status || "").trim().toLowerCase(),
|
|
4648
4668
|
transport_error: String(transportError || existing.transport_error || "").trim(),
|
|
@@ -8873,6 +8893,9 @@ async function processRunnerRouteOnce(route, runtime, mode, options = {}) {
|
|
|
8873
8893
|
responseContractValidationStatus: String(processed.result?.response_contract_validation_status || "").trim(),
|
|
8874
8894
|
responseContractValidationReason: String(processed.result?.response_contract_validation_reason || "").trim(),
|
|
8875
8895
|
responseContractValidationTargets: ensureArray(processed.result?.response_contract_validation_targets),
|
|
8896
|
+
assignmentValidationStatus: String(processed.result?.assignment_validation_status || "").trim(),
|
|
8897
|
+
assignmentValidationReason: String(processed.result?.assignment_validation_reason || "").trim(),
|
|
8898
|
+
assignmentValidationModes: ensureArray(processed.result?.assignment_validation_modes),
|
|
8876
8899
|
deliveryStatus: String(processed.result?.delivery_status || "").trim(),
|
|
8877
8900
|
archiveStatus: String(processed.result?.archive_status || "").trim(),
|
|
8878
8901
|
transportError: String(processed.result?.transport_error || "").trim(),
|
|
@@ -11293,6 +11316,9 @@ async function runRunnerStartResolvedRoutes(routes, flags, options = {}) {
|
|
|
11293
11316
|
responseContractValidationStatus: String(processed.result?.response_contract_validation_status || "").trim(),
|
|
11294
11317
|
responseContractValidationReason: String(processed.result?.response_contract_validation_reason || "").trim(),
|
|
11295
11318
|
responseContractValidationTargets: ensureArray(processed.result?.response_contract_validation_targets),
|
|
11319
|
+
assignmentValidationStatus: String(processed.result?.assignment_validation_status || "").trim(),
|
|
11320
|
+
assignmentValidationReason: String(processed.result?.assignment_validation_reason || "").trim(),
|
|
11321
|
+
assignmentValidationModes: ensureArray(processed.result?.assignment_validation_modes),
|
|
11296
11322
|
deliveryStatus: String(processed.result?.delivery_status || "").trim(),
|
|
11297
11323
|
archiveStatus: String(processed.result?.archive_status || "").trim(),
|
|
11298
11324
|
transportError: String(processed.result?.transport_error || "").trim(),
|
|
@@ -1918,7 +1918,10 @@ export function buildLocalBotPrompt(payload, { terse = true } = {}) {
|
|
|
1918
1918
|
"Do not mention another managed bot unless the contract explicitly names that bot in assignments or next_responders.",
|
|
1919
1919
|
"Without a matching contract, newly mentioned bots will not act.",
|
|
1920
1920
|
"When delegating to another managed bot, use contract.type=\"delegation\" with actionable=true, assignments, and next_responders.",
|
|
1921
|
-
"
|
|
1921
|
+
"Each assignment must declare whether it is a conversational contribution or a real execution task.",
|
|
1922
|
+
"Use assignment.mode=\"conversation_contribution\" for opinions, discussion, review, comparison, synthesis, greetings, or other room-visible contributions that do not require workspace artifacts.",
|
|
1923
|
+
"Use assignment.mode=\"execution_task\" only when the delegated bot must change workspace files, create artifacts, update ctxpack, or produce other concrete project outputs. If it is an execution task, also set artifacts_required=true.",
|
|
1924
|
+
"Delegation contract example: {\"type\":\"delegation\",\"actionable\":true,\"assignments\":[{\"target_bot\":\"ryoai2_bot\",\"task\":\"briefly greet in one line\",\"mode\":\"conversation_contribution\",\"artifacts_required\":false}],\"next_responders\":[\"ryoai2_bot\"]}.",
|
|
1922
1925
|
ensureArray(responseContract.required_delegation_targets).length > 0
|
|
1923
1926
|
? `This reply must delegate to these exact managed bots now: ${ensureArray(responseContract.required_delegation_targets).map((item) => `@${String(item || "").trim().replace(/^@+/, "")}`).join(", ")}.`
|
|
1924
1927
|
: "",
|
|
@@ -1970,7 +1973,10 @@ export function buildLocalBotPrompt(payload, { terse = true } = {}) {
|
|
|
1970
1973
|
"Do not mention another managed bot unless the contract explicitly names that bot in assignments or next_responders.",
|
|
1971
1974
|
"Without a matching contract, mentioned bots will not act.",
|
|
1972
1975
|
"When delegating to another managed bot, use contract.type=\"delegation\" with actionable=true, assignments, and next_responders.",
|
|
1973
|
-
"
|
|
1976
|
+
"Each assignment must declare whether it is a conversational contribution or a real execution task.",
|
|
1977
|
+
"Use assignment.mode=\"conversation_contribution\" for opinions, discussion, review, comparison, synthesis, greetings, or other room-visible contributions that do not require workspace artifacts.",
|
|
1978
|
+
"Use assignment.mode=\"execution_task\" only when the delegated bot must change workspace files, create artifacts, update ctxpack, or produce other concrete project outputs. If it is an execution task, also set artifacts_required=true.",
|
|
1979
|
+
"Delegation contract example: {\"type\":\"delegation\",\"actionable\":true,\"assignments\":[{\"target_bot\":\"ryoai2_bot\",\"task\":\"briefly greet in one line\",\"mode\":\"conversation_contribution\",\"artifacts_required\":false}],\"next_responders\":[\"ryoai2_bot\"]}.",
|
|
1974
1980
|
ensureArray(responseContract.required_delegation_targets).length > 0
|
|
1975
1981
|
? `This reply must delegate to these exact managed bots now: ${ensureArray(responseContract.required_delegation_targets).map((item) => `@${String(item || "").trim().replace(/^@+/, "")}`).join(", ")}.`
|
|
1976
1982
|
: "",
|
|
@@ -2006,7 +2012,7 @@ export function buildLocalBotPrompt(payload, { terse = true } = {}) {
|
|
|
2006
2012
|
isInternalExecutionStep
|
|
2007
2013
|
? "Return JSON only in one line: {\"reply\":\"what was completed in this step\",\"artifacts\":[{\"path\":\"relative/or/absolute/path\",\"kind\":\"plan|code|doc|spec|test\",\"operation\":\"create|update|delete\"}],\"ctxpack_files\":[{\"path\":\"relative/path.md\",\"content\":\"full document text\",\"doc_type\":\"guide|readme|agenda|rule|architecture|manifest\",\"operation\":\"create|update|delete\"}],\"work_items\":[{\"title\":\"short atomic task\",\"description\":\"useful implementation detail\"}],\"contract\":{\"type\":\"direct_result|summary_request|final_summary\",\"actionable\":true,\"summary_bot\":\"username\",\"next_responders\":[\"username\"]}}. Use ctxpack_files when ctxpack-backed guidance/instruction files must be authored. If execution_step.ctxpack_update_required is true, ctxpack_files must not be empty. Use artifacts: [] only if this step truly changes no project files, and use work_items: [] only if this step truly creates no governance tasks."
|
|
2008
2014
|
: responseContract.is_current_bot_candidate === true
|
|
2009
|
-
? "Return JSON only in one line: {\"reply\":\"...\",\"artifacts\":[],\"ctxpack_files\":[],\"work_items\":[]} or {\"clarify\":\"...\"} or {\"skip\":true,\"reason\":\"...\"} or {\"reply\":\"...\",\"artifacts\":[],\"ctxpack_files\":[],\"work_items\":[],\"contract\":{\"type\":\"direct_result|delegation|summary_request|final_summary\",\"actionable\":true,\"assignments\":[{\"target_bot\":\"username\",\"task\":\"...\"}],\"summary_bot\":\"username\",\"next_responders\":[\"username\"]},\"context_suggestion\":{\"should_store\":true,\"title\":\"...\",\"body\":\"...\",\"category\":\"bot_role|operating_rule|project_fact|current_focus|risk|general\",\"importance\":\"low|normal|high|critical\"}}."
|
|
2015
|
+
? "Return JSON only in one line: {\"reply\":\"...\",\"artifacts\":[],\"ctxpack_files\":[],\"work_items\":[]} or {\"clarify\":\"...\"} or {\"skip\":true,\"reason\":\"...\"} or {\"reply\":\"...\",\"artifacts\":[],\"ctxpack_files\":[],\"work_items\":[],\"contract\":{\"type\":\"direct_result|delegation|summary_request|final_summary\",\"actionable\":true,\"assignments\":[{\"target_bot\":\"username\",\"task\":\"...\",\"mode\":\"conversation_contribution|execution_task\",\"artifacts_required\":true|false}],\"summary_bot\":\"username\",\"next_responders\":[\"username\"]},\"context_suggestion\":{\"should_store\":true,\"title\":\"...\",\"body\":\"...\",\"category\":\"bot_role|operating_rule|project_fact|current_focus|risk|general\",\"importance\":\"low|normal|high|critical\"}}."
|
|
2010
2016
|
: terse
|
|
2011
2017
|
? "Return JSON only in one line: {\"reply\":\"...\",\"artifacts\":[],\"ctxpack_files\":[],\"work_items\":[],\"context_suggestion\":{\"should_store\":true,\"title\":\"...\",\"body\":\"...\",\"category\":\"bot_role|operating_rule|project_fact|current_focus|risk|general\",\"importance\":\"low|normal|high|critical\"}} or {\"clarify\":\"...\"} or {\"skip\":true,\"reason\":\"...\"}."
|
|
2012
2018
|
: "Return JSON only: {\"reply\":\"...\",\"artifacts\":[],\"ctxpack_files\":[],\"work_items\":[],\"context_suggestion\":{\"should_store\":true,\"title\":\"...\",\"body\":\"...\",\"category\":\"bot_role|operating_rule|project_fact|current_focus|risk|general\",\"importance\":\"low|normal|high|critical\"}} or {\"clarify\":\"...\"} or {\"skip\":true,\"reason\":\"...\"}. Keep the reply concise and directly useful in a group chat.",
|
|
@@ -2061,7 +2067,12 @@ export function buildLocalBotPrompt(payload, { terse = true } = {}) {
|
|
|
2061
2067
|
}
|
|
2062
2068
|
if (assignmentsForThisBot.length > 0) {
|
|
2063
2069
|
lines.push(
|
|
2064
|
-
`Current Assignment For This Bot: ${assignmentsForThisBot.map((item) =>
|
|
2070
|
+
`Current Assignment For This Bot: ${assignmentsForThisBot.map((item) => {
|
|
2071
|
+
const task = String(item.task || "").trim();
|
|
2072
|
+
const mode = String(item.mode || "").trim();
|
|
2073
|
+
const artifactsRequired = item.artifactsRequired === true || item.artifacts_required === true;
|
|
2074
|
+
return `${task}${mode ? ` [mode=${mode}]` : ""}${artifactsRequired ? " [artifacts_required=yes]" : ""}`;
|
|
2075
|
+
}).join(" | ")}`,
|
|
2065
2076
|
);
|
|
2066
2077
|
}
|
|
2067
2078
|
if (String(currentExecutionContract.summary_bot || currentExecutionContract.summaryBot || "").trim()) {
|
|
@@ -710,6 +710,112 @@ function normalizeReplyExpectation(value, fallback = "informational") {
|
|
|
710
710
|
return fallback;
|
|
711
711
|
}
|
|
712
712
|
|
|
713
|
+
function boolFromRunnerRaw(raw, fallback = false) {
|
|
714
|
+
if (raw === true || raw === false) {
|
|
715
|
+
return raw;
|
|
716
|
+
}
|
|
717
|
+
const normalized = String(raw ?? "").trim().toLowerCase();
|
|
718
|
+
if (!normalized) return fallback;
|
|
719
|
+
if (["1", "true", "yes", "y", "on"].includes(normalized)) {
|
|
720
|
+
return true;
|
|
721
|
+
}
|
|
722
|
+
if (["0", "false", "no", "n", "off"].includes(normalized)) {
|
|
723
|
+
return false;
|
|
724
|
+
}
|
|
725
|
+
return fallback;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
function normalizeExecutionAssignmentMode(rawValue, fallback = "conversation_contribution") {
|
|
729
|
+
const normalized = String(rawValue || "").trim().toLowerCase();
|
|
730
|
+
if (!normalized) {
|
|
731
|
+
return fallback;
|
|
732
|
+
}
|
|
733
|
+
if ([
|
|
734
|
+
"execution_task",
|
|
735
|
+
"workspace_action",
|
|
736
|
+
"artifact_work",
|
|
737
|
+
"artifact_task",
|
|
738
|
+
"file_work",
|
|
739
|
+
"ctxpack_update",
|
|
740
|
+
"workitem_task",
|
|
741
|
+
].includes(normalized)) {
|
|
742
|
+
return "execution_task";
|
|
743
|
+
}
|
|
744
|
+
if ([
|
|
745
|
+
"conversation_contribution",
|
|
746
|
+
"discussion_contribution",
|
|
747
|
+
"opinion",
|
|
748
|
+
"analysis",
|
|
749
|
+
"review",
|
|
750
|
+
"comparison",
|
|
751
|
+
"summary_contribution",
|
|
752
|
+
"greeting",
|
|
753
|
+
"reply",
|
|
754
|
+
].includes(normalized)) {
|
|
755
|
+
return "conversation_contribution";
|
|
756
|
+
}
|
|
757
|
+
return fallback;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
function normalizeExecutionAssignment(rawAssignment, {
|
|
761
|
+
allowedResponderSet = null,
|
|
762
|
+
currentBotSelector = "",
|
|
763
|
+
excludeCurrentTargetAssignments = false,
|
|
764
|
+
} = {}) {
|
|
765
|
+
const assignment = safeObject(rawAssignment);
|
|
766
|
+
const targetBot = normalizeMentionSelector(
|
|
767
|
+
assignment.targetBot
|
|
768
|
+
|| assignment.target_bot
|
|
769
|
+
|| assignment.bot
|
|
770
|
+
|| assignment.username,
|
|
771
|
+
);
|
|
772
|
+
const task = String(
|
|
773
|
+
assignment.task
|
|
774
|
+
|| assignment.instruction
|
|
775
|
+
|| assignment.assignment
|
|
776
|
+
|| assignment.work
|
|
777
|
+
|| assignment.description
|
|
778
|
+
|| "",
|
|
779
|
+
).trim();
|
|
780
|
+
if (!targetBot || !task) {
|
|
781
|
+
return null;
|
|
782
|
+
}
|
|
783
|
+
if (allowedResponderSet?.size && !allowedResponderSet.has(targetBot)) {
|
|
784
|
+
return null;
|
|
785
|
+
}
|
|
786
|
+
if (
|
|
787
|
+
excludeCurrentTargetAssignments === true
|
|
788
|
+
&& currentBotSelector
|
|
789
|
+
&& targetBot === normalizeMentionSelector(currentBotSelector)
|
|
790
|
+
) {
|
|
791
|
+
return null;
|
|
792
|
+
}
|
|
793
|
+
const artifactsRequired = boolFromRunnerRaw(
|
|
794
|
+
assignment.artifactsRequired ?? assignment.artifacts_required,
|
|
795
|
+
false,
|
|
796
|
+
);
|
|
797
|
+
const workspaceAction = boolFromRunnerRaw(
|
|
798
|
+
assignment.workspaceAction ?? assignment.workspace_action,
|
|
799
|
+
false,
|
|
800
|
+
);
|
|
801
|
+
const mode = normalizeExecutionAssignmentMode(
|
|
802
|
+
assignment.mode
|
|
803
|
+
|| assignment.assignment_mode
|
|
804
|
+
|| assignment.kind
|
|
805
|
+
|| assignment.type,
|
|
806
|
+
(artifactsRequired || workspaceAction) ? "execution_task" : "conversation_contribution",
|
|
807
|
+
);
|
|
808
|
+
const requiresExecution = mode === "execution_task" || artifactsRequired || workspaceAction;
|
|
809
|
+
return {
|
|
810
|
+
targetBot,
|
|
811
|
+
task,
|
|
812
|
+
mode,
|
|
813
|
+
artifactsRequired,
|
|
814
|
+
workspaceAction,
|
|
815
|
+
requiresExecution,
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
|
|
713
819
|
function normalizeHumanIntentType(value, fallback = "") {
|
|
714
820
|
const normalized = String(value || "").trim().toLowerCase();
|
|
715
821
|
if ([
|
|
@@ -1811,14 +1917,84 @@ function buildFallbackArchivedBotReplyConversationContext({
|
|
|
1811
1917
|
};
|
|
1812
1918
|
}
|
|
1813
1919
|
|
|
1814
|
-
function
|
|
1920
|
+
function extractCurrentAssignmentsForBot(conversationContext, currentBotSelector) {
|
|
1815
1921
|
const currentSelector = normalizeMentionSelector(currentBotSelector);
|
|
1816
1922
|
if (!currentSelector) return [];
|
|
1817
1923
|
return ensureArray(safeObject(conversationContext?.executionContract).assignments)
|
|
1818
1924
|
.map((item) => safeObject(item))
|
|
1819
1925
|
.filter((item) => normalizeMentionSelector(item.targetBot || item.target_bot) === currentSelector)
|
|
1820
|
-
.map((item) =>
|
|
1821
|
-
|
|
1926
|
+
.map((item) => ({
|
|
1927
|
+
targetBot: normalizeMentionSelector(item.targetBot || item.target_bot),
|
|
1928
|
+
task: String(item.task || item.instruction || "").trim(),
|
|
1929
|
+
mode: normalizeExecutionAssignmentMode(
|
|
1930
|
+
item.mode || item.assignment_mode || item.kind || item.type,
|
|
1931
|
+
item.requiresExecution === true
|
|
1932
|
+
|| item.artifactsRequired === true
|
|
1933
|
+
|| item.workspaceAction === true
|
|
1934
|
+
|| item.artifacts_required === true
|
|
1935
|
+
|| item.workspace_action === true
|
|
1936
|
+
? "execution_task"
|
|
1937
|
+
: "conversation_contribution",
|
|
1938
|
+
),
|
|
1939
|
+
artifactsRequired: item.artifactsRequired === true || item.artifacts_required === true,
|
|
1940
|
+
workspaceAction: item.workspaceAction === true || item.workspace_action === true,
|
|
1941
|
+
requiresExecution: item.requiresExecution === true
|
|
1942
|
+
|| item.artifactsRequired === true
|
|
1943
|
+
|| item.workspaceAction === true
|
|
1944
|
+
|| item.artifacts_required === true
|
|
1945
|
+
|| item.workspace_action === true
|
|
1946
|
+
|| normalizeExecutionAssignmentMode(
|
|
1947
|
+
item.mode || item.assignment_mode || item.kind || item.type,
|
|
1948
|
+
"conversation_contribution",
|
|
1949
|
+
) === "execution_task",
|
|
1950
|
+
}))
|
|
1951
|
+
.filter((item) => item.task);
|
|
1952
|
+
}
|
|
1953
|
+
|
|
1954
|
+
function summarizeCurrentAssignmentExecutionValidation(conversationContext, currentBotSelector) {
|
|
1955
|
+
const assignments = extractCurrentAssignmentsForBot(conversationContext, currentBotSelector);
|
|
1956
|
+
const assignmentModes = uniqueOrdered(
|
|
1957
|
+
assignments.map((item) => String(item.mode || "").trim()).filter(Boolean),
|
|
1958
|
+
);
|
|
1959
|
+
const executionAssignments = assignments.filter((item) => item.requiresExecution === true);
|
|
1960
|
+
const conversationAssignments = assignments.filter((item) => item.requiresExecution !== true);
|
|
1961
|
+
if (!assignments.length) {
|
|
1962
|
+
return {
|
|
1963
|
+
status: "no_assignment",
|
|
1964
|
+
reason: "no assignment for current bot in the active execution contract",
|
|
1965
|
+
assignmentModes: [],
|
|
1966
|
+
assignments: [],
|
|
1967
|
+
executionAssignments: [],
|
|
1968
|
+
conversationAssignments: [],
|
|
1969
|
+
executionTasks: [],
|
|
1970
|
+
allTasks: [],
|
|
1971
|
+
requiresPlanner: false,
|
|
1972
|
+
};
|
|
1973
|
+
}
|
|
1974
|
+
if (executionAssignments.length > 0) {
|
|
1975
|
+
return {
|
|
1976
|
+
status: "execution_assignment",
|
|
1977
|
+
reason: "active assignment explicitly requires workspace/artifact execution",
|
|
1978
|
+
assignmentModes,
|
|
1979
|
+
assignments,
|
|
1980
|
+
executionAssignments,
|
|
1981
|
+
conversationAssignments,
|
|
1982
|
+
executionTasks: executionAssignments.map((item) => String(item.task || "").trim()).filter(Boolean),
|
|
1983
|
+
allTasks: assignments.map((item) => String(item.task || "").trim()).filter(Boolean),
|
|
1984
|
+
requiresPlanner: true,
|
|
1985
|
+
};
|
|
1986
|
+
}
|
|
1987
|
+
return {
|
|
1988
|
+
status: "conversation_assignment",
|
|
1989
|
+
reason: "active assignment is a conversational contribution and does not require planner/worker execution",
|
|
1990
|
+
assignmentModes,
|
|
1991
|
+
assignments,
|
|
1992
|
+
executionAssignments: [],
|
|
1993
|
+
conversationAssignments,
|
|
1994
|
+
executionTasks: [],
|
|
1995
|
+
allTasks: assignments.map((item) => String(item.task || "").trim()).filter(Boolean),
|
|
1996
|
+
requiresPlanner: false,
|
|
1997
|
+
};
|
|
1822
1998
|
}
|
|
1823
1999
|
|
|
1824
2000
|
function requiresArtifactsForExecutionStep(step) {
|
|
@@ -2557,6 +2733,7 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
2557
2733
|
saveRunnerRouteState,
|
|
2558
2734
|
runRunnerAIExecution,
|
|
2559
2735
|
validateWorkspaceArtifacts,
|
|
2736
|
+
assignmentExecutionValidation = null,
|
|
2560
2737
|
}) {
|
|
2561
2738
|
const planner = typeof executionDeps.planRoleExecutionWithAI === "function"
|
|
2562
2739
|
? executionDeps.planRoleExecutionWithAI
|
|
@@ -2576,8 +2753,12 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
2576
2753
|
if (!planner || !resolveRunnerExecutionPlanForRole) {
|
|
2577
2754
|
return null;
|
|
2578
2755
|
}
|
|
2579
|
-
const
|
|
2580
|
-
const
|
|
2756
|
+
const assignmentValidation = safeObject(assignmentExecutionValidation);
|
|
2757
|
+
const assignmentValidationStatus = String(assignmentValidation.status || "").trim();
|
|
2758
|
+
const assignmentValidationReason = String(assignmentValidation.reason || "").trim();
|
|
2759
|
+
const assignmentTasks = ensureArray(assignmentValidation.executionTasks)
|
|
2760
|
+
.map((item) => String(item || "").trim())
|
|
2761
|
+
.filter(Boolean);
|
|
2581
2762
|
const humanIntentType = normalizeHumanIntentType(
|
|
2582
2763
|
safeObject(directHumanResponseContract).intentType
|
|
2583
2764
|
|| safeObject(safeObject(humanIntentContext).humanIntent).intentType,
|
|
@@ -2610,7 +2791,7 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
2610
2791
|
) {
|
|
2611
2792
|
return null;
|
|
2612
2793
|
}
|
|
2613
|
-
const shouldPlanExecution =
|
|
2794
|
+
const shouldPlanExecution = assignmentValidation.requiresPlanner === true || (
|
|
2614
2795
|
triggerDecision.requiresDirectReply === true
|
|
2615
2796
|
&& humanIntentMode === "single_bot"
|
|
2616
2797
|
&& actionableReplyExpectation
|
|
@@ -2756,6 +2937,8 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
2756
2937
|
last_conversation_id: String(conversationContext?.id || "").trim(),
|
|
2757
2938
|
last_conversation_stage: String(conversationContext?.stage || "").trim(),
|
|
2758
2939
|
last_workspace_dir: String(executionPlan.workspaceDir || "").trim(),
|
|
2940
|
+
last_assignment_validation_status: assignmentValidationStatus,
|
|
2941
|
+
last_assignment_validation_reason: assignmentValidationReason,
|
|
2759
2942
|
...safeObject(intentStatePatch),
|
|
2760
2943
|
}),
|
|
2761
2944
|
);
|
|
@@ -2769,6 +2952,9 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
2769
2952
|
thread_id: archiveThread.threadID,
|
|
2770
2953
|
comment_id: selectedRecord.id,
|
|
2771
2954
|
trigger_kind: String(triggerDecision.trigger || "").trim(),
|
|
2955
|
+
assignment_validation_status: assignmentValidationStatus,
|
|
2956
|
+
assignment_validation_reason: assignmentValidationReason,
|
|
2957
|
+
assignment_validation_modes: ensureArray(assignmentValidation.assignmentModes),
|
|
2772
2958
|
},
|
|
2773
2959
|
};
|
|
2774
2960
|
}
|
|
@@ -2786,6 +2972,8 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
2786
2972
|
last_conversation_id: String(conversationContext?.id || "").trim(),
|
|
2787
2973
|
last_conversation_stage: String(conversationContext?.stage || "").trim(),
|
|
2788
2974
|
last_workspace_dir: String(executionPlan.workspaceDir || "").trim(),
|
|
2975
|
+
last_assignment_validation_status: assignmentValidationStatus,
|
|
2976
|
+
last_assignment_validation_reason: assignmentValidationReason,
|
|
2789
2977
|
...safeObject(intentStatePatch),
|
|
2790
2978
|
}),
|
|
2791
2979
|
);
|
|
@@ -2799,6 +2987,9 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
2799
2987
|
thread_id: archiveThread.threadID,
|
|
2800
2988
|
comment_id: selectedRecord.id,
|
|
2801
2989
|
trigger_kind: String(triggerDecision.trigger || "").trim(),
|
|
2990
|
+
assignment_validation_status: assignmentValidationStatus,
|
|
2991
|
+
assignment_validation_reason: assignmentValidationReason,
|
|
2992
|
+
assignment_validation_modes: ensureArray(assignmentValidation.assignmentModes),
|
|
2802
2993
|
},
|
|
2803
2994
|
};
|
|
2804
2995
|
}
|
|
@@ -2833,6 +3024,8 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
2833
3024
|
last_conversation_id: String(conversationContext?.id || "").trim(),
|
|
2834
3025
|
last_conversation_stage: String(conversationContext?.stage || "").trim(),
|
|
2835
3026
|
last_workspace_dir: String(executionPlan.workspaceDir || "").trim(),
|
|
3027
|
+
last_assignment_validation_status: assignmentValidationStatus,
|
|
3028
|
+
last_assignment_validation_reason: assignmentValidationReason,
|
|
2836
3029
|
...safeObject(intentStatePatch),
|
|
2837
3030
|
}),
|
|
2838
3031
|
);
|
|
@@ -2846,6 +3039,9 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
2846
3039
|
thread_id: archiveThread.threadID,
|
|
2847
3040
|
comment_id: selectedRecord.id,
|
|
2848
3041
|
trigger_kind: String(triggerDecision.trigger || "").trim(),
|
|
3042
|
+
assignment_validation_status: assignmentValidationStatus,
|
|
3043
|
+
assignment_validation_reason: assignmentValidationReason,
|
|
3044
|
+
assignment_validation_modes: ensureArray(assignmentValidation.assignmentModes),
|
|
2849
3045
|
},
|
|
2850
3046
|
};
|
|
2851
3047
|
}
|
|
@@ -2862,6 +3058,8 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
2862
3058
|
last_conversation_id: String(conversationContext?.id || "").trim(),
|
|
2863
3059
|
last_conversation_stage: String(conversationContext?.stage || "").trim(),
|
|
2864
3060
|
last_workspace_dir: String(stepExecutionPlan.workspaceDir || executionPlan.workspaceDir || "").trim(),
|
|
3061
|
+
last_assignment_validation_status: assignmentValidationStatus,
|
|
3062
|
+
last_assignment_validation_reason: assignmentValidationReason,
|
|
2865
3063
|
...safeObject(intentStatePatch),
|
|
2866
3064
|
}),
|
|
2867
3065
|
);
|
|
@@ -2875,6 +3073,9 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
2875
3073
|
thread_id: archiveThread.threadID,
|
|
2876
3074
|
comment_id: selectedRecord.id,
|
|
2877
3075
|
trigger_kind: String(triggerDecision.trigger || "").trim(),
|
|
3076
|
+
assignment_validation_status: assignmentValidationStatus,
|
|
3077
|
+
assignment_validation_reason: assignmentValidationReason,
|
|
3078
|
+
assignment_validation_modes: ensureArray(assignmentValidation.assignmentModes),
|
|
2878
3079
|
},
|
|
2879
3080
|
};
|
|
2880
3081
|
}
|
|
@@ -2918,6 +3119,8 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
2918
3119
|
last_conversation_id: String(conversationContext?.id || "").trim(),
|
|
2919
3120
|
last_conversation_stage: String(conversationContext?.stage || "").trim(),
|
|
2920
3121
|
last_workspace_dir: String(stepExecutionPlan.workspaceDir || executionPlan.workspaceDir || "").trim(),
|
|
3122
|
+
last_assignment_validation_status: assignmentValidationStatus,
|
|
3123
|
+
last_assignment_validation_reason: assignmentValidationReason,
|
|
2921
3124
|
...safeObject(intentStatePatch),
|
|
2922
3125
|
}),
|
|
2923
3126
|
);
|
|
@@ -2931,6 +3134,9 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
2931
3134
|
thread_id: archiveThread.threadID,
|
|
2932
3135
|
comment_id: selectedRecord.id,
|
|
2933
3136
|
trigger_kind: String(triggerDecision.trigger || "").trim(),
|
|
3137
|
+
assignment_validation_status: assignmentValidationStatus,
|
|
3138
|
+
assignment_validation_reason: assignmentValidationReason,
|
|
3139
|
+
assignment_validation_modes: ensureArray(assignmentValidation.assignmentModes),
|
|
2934
3140
|
},
|
|
2935
3141
|
};
|
|
2936
3142
|
}
|
|
@@ -3057,6 +3263,8 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
3057
3263
|
last_artifact_errors: stepErrors,
|
|
3058
3264
|
last_boundary_violations: stepBoundaryViolations,
|
|
3059
3265
|
last_workspace_dir: String(stepExecutionPlan.workspaceDir || executionPlan.workspaceDir || "").trim(),
|
|
3266
|
+
last_assignment_validation_status: assignmentValidationStatus,
|
|
3267
|
+
last_assignment_validation_reason: assignmentValidationReason,
|
|
3060
3268
|
...safeObject(intentStatePatch),
|
|
3061
3269
|
}),
|
|
3062
3270
|
);
|
|
@@ -3073,6 +3281,9 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
3073
3281
|
artifact_validation: String(stepValidation.status || "").trim() || "execution_failed",
|
|
3074
3282
|
artifact_paths: summarizeValidatedArtifactPaths(stepValidation),
|
|
3075
3283
|
artifact_errors: stepErrors,
|
|
3284
|
+
assignment_validation_status: assignmentValidationStatus,
|
|
3285
|
+
assignment_validation_reason: assignmentValidationReason,
|
|
3286
|
+
assignment_validation_modes: ensureArray(assignmentValidation.assignmentModes),
|
|
3076
3287
|
},
|
|
3077
3288
|
};
|
|
3078
3289
|
}
|
|
@@ -3380,47 +3591,21 @@ function normalizeConversationExecutionContract(
|
|
|
3380
3591
|
|| contract.contractType
|
|
3381
3592
|
|| "",
|
|
3382
3593
|
).trim().toLowerCase();
|
|
3383
|
-
const normalizedType = [
|
|
3384
|
-
"direct_result",
|
|
3385
|
-
"delegation",
|
|
3386
|
-
"summary_request",
|
|
3387
|
-
"final_summary",
|
|
3388
|
-
].includes(type)
|
|
3389
|
-
? type
|
|
3390
|
-
: "";
|
|
3391
|
-
const assignments = ensureArray(contract.assignments)
|
|
3392
|
-
.map((item) => {
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|| assignment.username,
|
|
3399
|
-
);
|
|
3400
|
-
const task = String(
|
|
3401
|
-
assignment.task
|
|
3402
|
-
|| assignment.instruction
|
|
3403
|
-
|| assignment.assignment
|
|
3404
|
-
|| assignment.work
|
|
3405
|
-
|| assignment.description
|
|
3406
|
-
|| "",
|
|
3407
|
-
).trim();
|
|
3408
|
-
if (!targetBot || !task) {
|
|
3409
|
-
return null;
|
|
3410
|
-
}
|
|
3411
|
-
if (allowedResponderSet.size && !allowedResponderSet.has(targetBot)) {
|
|
3412
|
-
return null;
|
|
3413
|
-
}
|
|
3414
|
-
if (
|
|
3415
|
-
excludeCurrentTargetAssignments === true
|
|
3416
|
-
&& currentBotSelector
|
|
3417
|
-
&& targetBot === normalizeMentionSelector(currentBotSelector)
|
|
3418
|
-
) {
|
|
3419
|
-
return null;
|
|
3420
|
-
}
|
|
3421
|
-
return { targetBot, task };
|
|
3422
|
-
})
|
|
3423
|
-
.filter(Boolean);
|
|
3594
|
+
const normalizedType = [
|
|
3595
|
+
"direct_result",
|
|
3596
|
+
"delegation",
|
|
3597
|
+
"summary_request",
|
|
3598
|
+
"final_summary",
|
|
3599
|
+
].includes(type)
|
|
3600
|
+
? type
|
|
3601
|
+
: "";
|
|
3602
|
+
const assignments = ensureArray(contract.assignments)
|
|
3603
|
+
.map((item) => normalizeExecutionAssignment(item, {
|
|
3604
|
+
allowedResponderSet,
|
|
3605
|
+
currentBotSelector,
|
|
3606
|
+
excludeCurrentTargetAssignments,
|
|
3607
|
+
}))
|
|
3608
|
+
.filter(Boolean);
|
|
3424
3609
|
const summaryBot = normalizeMentionSelector(
|
|
3425
3610
|
contract.summaryBot
|
|
3426
3611
|
|| contract.summary_bot
|
|
@@ -3483,30 +3668,10 @@ function normalizeResponseExecutionContract(rawContract, responseContract, { cur
|
|
|
3483
3668
|
return null;
|
|
3484
3669
|
}
|
|
3485
3670
|
const assignments = ensureArray(contract.assignments)
|
|
3486
|
-
.map((item) => {
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|| assignment.target_bot
|
|
3491
|
-
|| assignment.bot
|
|
3492
|
-
|| assignment.username,
|
|
3493
|
-
);
|
|
3494
|
-
const task = String(
|
|
3495
|
-
assignment.task
|
|
3496
|
-
|| assignment.instruction
|
|
3497
|
-
|| assignment.assignment
|
|
3498
|
-
|| assignment.work
|
|
3499
|
-
|| assignment.description
|
|
3500
|
-
|| "",
|
|
3501
|
-
).trim();
|
|
3502
|
-
if (!targetBot || !task) {
|
|
3503
|
-
return null;
|
|
3504
|
-
}
|
|
3505
|
-
if (currentBotSelector && targetBot === currentBotSelector) {
|
|
3506
|
-
return null;
|
|
3507
|
-
}
|
|
3508
|
-
return { targetBot, task };
|
|
3509
|
-
})
|
|
3671
|
+
.map((item) => normalizeExecutionAssignment(item, {
|
|
3672
|
+
currentBotSelector,
|
|
3673
|
+
excludeCurrentTargetAssignments: true,
|
|
3674
|
+
}))
|
|
3510
3675
|
.filter(Boolean);
|
|
3511
3676
|
const summaryBot = normalizeMentionSelector(
|
|
3512
3677
|
contract.summaryBot
|
|
@@ -4826,6 +4991,10 @@ export async function processRunnerSelectedRecord({
|
|
|
4826
4991
|
directQueryReply: directInformationalReply,
|
|
4827
4992
|
responderAdjudication,
|
|
4828
4993
|
});
|
|
4994
|
+
const assignmentExecutionValidation = summarizeCurrentAssignmentExecutionValidation(
|
|
4995
|
+
conversationContext,
|
|
4996
|
+
currentBotSelector,
|
|
4997
|
+
);
|
|
4829
4998
|
const emitRunnerStage = (phase, detail) => {
|
|
4830
4999
|
if (!reportRunnerStage) return;
|
|
4831
5000
|
try {
|
|
@@ -4981,6 +5150,7 @@ export async function processRunnerSelectedRecord({
|
|
|
4981
5150
|
saveRunnerRouteState,
|
|
4982
5151
|
runRunnerAIExecution,
|
|
4983
5152
|
validateWorkspaceArtifacts,
|
|
5153
|
+
assignmentExecutionValidation,
|
|
4984
5154
|
});
|
|
4985
5155
|
if (dynamicRoleExecution?.kind === "error") {
|
|
4986
5156
|
dynamicExecutionError = dynamicRoleExecution.result;
|
|
@@ -5433,6 +5603,8 @@ export async function processRunnerSelectedRecord({
|
|
|
5433
5603
|
last_contract_validation_status: String(responseContractValidation.status || "").trim(),
|
|
5434
5604
|
last_contract_validation_reason: String(responseContractValidation.reason || "").trim(),
|
|
5435
5605
|
last_contract_validation_targets: ensureArray(responseContractValidation.targets),
|
|
5606
|
+
last_assignment_validation_status: String(assignmentExecutionValidation.status || "").trim(),
|
|
5607
|
+
last_assignment_validation_reason: String(assignmentExecutionValidation.reason || "").trim(),
|
|
5436
5608
|
last_speaker_bot_username: normalizeMentionSelector(bot?.username || bot?.name),
|
|
5437
5609
|
last_workspace_dir: String(effectiveExecutionPlan.workspaceDir || "").trim(),
|
|
5438
5610
|
...intentStatePatch,
|
|
@@ -5474,6 +5646,9 @@ export async function processRunnerSelectedRecord({
|
|
|
5474
5646
|
response_contract_validation_status: String(responseContractValidation.status || "").trim(),
|
|
5475
5647
|
response_contract_validation_reason: String(responseContractValidation.reason || "").trim(),
|
|
5476
5648
|
response_contract_validation_targets: ensureArray(responseContractValidation.targets),
|
|
5649
|
+
assignment_validation_status: String(assignmentExecutionValidation.status || "").trim(),
|
|
5650
|
+
assignment_validation_reason: String(assignmentExecutionValidation.reason || "").trim(),
|
|
5651
|
+
assignment_validation_modes: ensureArray(assignmentExecutionValidation.assignmentModes),
|
|
5477
5652
|
reply_chars: String(sanitizedReplyText || "").length,
|
|
5478
5653
|
execution_mode: effectiveExecutionPlan.mode,
|
|
5479
5654
|
role_profile: effectiveExecutionPlan.roleProfileName,
|
|
@@ -5564,6 +5739,8 @@ export async function processRunnerSelectedRecord({
|
|
|
5564
5739
|
last_contract_validation_status: String(responseContractValidation.status || "").trim(),
|
|
5565
5740
|
last_contract_validation_reason: String(responseContractValidation.reason || "").trim(),
|
|
5566
5741
|
last_contract_validation_targets: ensureArray(responseContractValidation.targets),
|
|
5742
|
+
last_assignment_validation_status: String(assignmentExecutionValidation.status || "").trim(),
|
|
5743
|
+
last_assignment_validation_reason: String(assignmentExecutionValidation.reason || "").trim(),
|
|
5567
5744
|
last_trigger: String(effectiveTriggerDecision.trigger || "").trim(),
|
|
5568
5745
|
last_reason: effectiveConversationContext?.mode === "public_multi_bot"
|
|
5569
5746
|
? [
|
|
@@ -5664,6 +5841,9 @@ export async function processRunnerSelectedRecord({
|
|
|
5664
5841
|
response_contract_validation_status: String(responseContractValidation.status || "").trim(),
|
|
5665
5842
|
response_contract_validation_reason: String(responseContractValidation.reason || "").trim(),
|
|
5666
5843
|
response_contract_validation_targets: ensureArray(responseContractValidation.targets),
|
|
5844
|
+
assignment_validation_status: String(assignmentExecutionValidation.status || "").trim(),
|
|
5845
|
+
assignment_validation_reason: String(assignmentExecutionValidation.reason || "").trim(),
|
|
5846
|
+
assignment_validation_modes: ensureArray(assignmentExecutionValidation.assignmentModes),
|
|
5667
5847
|
delivery_status: deliveryResult.delivery.dryRun ? "dry_run" : "delivered",
|
|
5668
5848
|
execution_mode: effectiveExecutionPlan.mode,
|
|
5669
5849
|
role_profile: effectiveExecutionPlan.roleProfileName,
|
|
@@ -5483,9 +5483,9 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
5483
5483
|
push("single_bot_execution_failure_uses_ai_failure_explainer_when_available", false, String(err?.message || err));
|
|
5484
5484
|
}
|
|
5485
5485
|
|
|
5486
|
-
try {
|
|
5487
|
-
let aiCalls = 0;
|
|
5488
|
-
const processed = await processRunnerSelectedRecord({
|
|
5486
|
+
try {
|
|
5487
|
+
let aiCalls = 0;
|
|
5488
|
+
const processed = await processRunnerSelectedRecord({
|
|
5489
5489
|
routeKey: "single-bot-informational-human-request-key",
|
|
5490
5490
|
normalizedRoute: normalizeRunnerRoute({
|
|
5491
5491
|
name: "telegram-monitor-single-bot-informational",
|
|
@@ -9087,13 +9087,164 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
9087
9087
|
&& String(processed.result?.execution_contract_type || "") === "summary_request",
|
|
9088
9088
|
`kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} contract=${String(processed.result?.execution_contract_type || "(none)")} reason=${String(processed.skippedRecord?.reason || "(none)")}`,
|
|
9089
9089
|
);
|
|
9090
|
-
} catch (err) {
|
|
9091
|
-
push("delegated_single_lead_lead_reply_can_wake_named_peer", false, String(err?.message || err));
|
|
9092
|
-
}
|
|
9093
|
-
|
|
9094
|
-
try {
|
|
9095
|
-
let aiCalls = 0;
|
|
9096
|
-
|
|
9090
|
+
} catch (err) {
|
|
9091
|
+
push("delegated_single_lead_lead_reply_can_wake_named_peer", false, String(err?.message || err));
|
|
9092
|
+
}
|
|
9093
|
+
|
|
9094
|
+
try {
|
|
9095
|
+
let aiCalls = 0;
|
|
9096
|
+
let plannerCalls = 0;
|
|
9097
|
+
const processed = await processRunnerSelectedRecord({
|
|
9098
|
+
routeKey: "delegated-single-lead-conversation-assignment-skips-planner-key",
|
|
9099
|
+
normalizedRoute: normalizeRunnerRoute({
|
|
9100
|
+
name: "telegram-monitor-delegated-single-lead-conversation-assignment-skips-planner",
|
|
9101
|
+
project_id: selftestProjectID,
|
|
9102
|
+
provider: "telegram",
|
|
9103
|
+
role: "monitor",
|
|
9104
|
+
role_profile: "monitor",
|
|
9105
|
+
destination_id: "dest-1",
|
|
9106
|
+
destination_label: "Main Room",
|
|
9107
|
+
server_bot_name: "RyoAI2_bot",
|
|
9108
|
+
server_bot_id: "bot-peer-1",
|
|
9109
|
+
trigger_policy: {
|
|
9110
|
+
mentions_only: true,
|
|
9111
|
+
direct_messages: true,
|
|
9112
|
+
reply_to_bot_messages: true,
|
|
9113
|
+
},
|
|
9114
|
+
archive_policy: {
|
|
9115
|
+
mirror_replies: true,
|
|
9116
|
+
dedupe_inbound: true,
|
|
9117
|
+
dedupe_outbound: true,
|
|
9118
|
+
skip_bot_messages: true,
|
|
9119
|
+
},
|
|
9120
|
+
dry_run_delivery: true,
|
|
9121
|
+
}),
|
|
9122
|
+
selectedRecord: {
|
|
9123
|
+
id: "comment-delegated-single-lead-conversation-assignment-skips-planner",
|
|
9124
|
+
createdAt: "2026-03-16T00:02:12.000Z",
|
|
9125
|
+
parsedArchive: {
|
|
9126
|
+
kind: "bot_reply",
|
|
9127
|
+
conversationID: "comment-delegated-single-lead-conversation-open",
|
|
9128
|
+
conversationMode: "public_multi_bot",
|
|
9129
|
+
conversationStage: "bot_reply",
|
|
9130
|
+
conversationIntentMode: "delegated_single_lead",
|
|
9131
|
+
conversationAllowBotToBot: true,
|
|
9132
|
+
conversationLeadBotUsername: "ryoai_bot",
|
|
9133
|
+
conversationParticipants: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
9134
|
+
conversationInitialResponders: ["ryoai_bot"],
|
|
9135
|
+
conversationAllowedResponders: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
9136
|
+
conversationSummaryBotUsername: "ryoai_bot",
|
|
9137
|
+
botUsername: "RyoAI_bot",
|
|
9138
|
+
botName: "RyoAI_bot",
|
|
9139
|
+
sender: "RyoAI_bot",
|
|
9140
|
+
body: "@RyoAI2_bot 관점 하나만 짧게 말해줘.",
|
|
9141
|
+
mentionUsernames: ["ryoai2_bot"],
|
|
9142
|
+
executionContract: {
|
|
9143
|
+
type: "delegation",
|
|
9144
|
+
actionable: true,
|
|
9145
|
+
assignments: [
|
|
9146
|
+
{ target_bot: "ryoai2_bot", task: "관점 하나만 짧게 말해줘.", mode: "conversation_contribution", artifacts_required: false },
|
|
9147
|
+
],
|
|
9148
|
+
summary_bot: "ryoai_bot",
|
|
9149
|
+
next_responders: ["ryoai2_bot"],
|
|
9150
|
+
},
|
|
9151
|
+
},
|
|
9152
|
+
},
|
|
9153
|
+
pendingOrdered: [],
|
|
9154
|
+
bot: {
|
|
9155
|
+
id: "bot-peer-1",
|
|
9156
|
+
name: "RyoAI2_bot",
|
|
9157
|
+
username: "RyoAI2_bot",
|
|
9158
|
+
role: "monitor",
|
|
9159
|
+
provider: "telegram",
|
|
9160
|
+
},
|
|
9161
|
+
destination: {
|
|
9162
|
+
id: "dest-1",
|
|
9163
|
+
label: "Main Room",
|
|
9164
|
+
provider: "telegram",
|
|
9165
|
+
chatID: "-100123",
|
|
9166
|
+
},
|
|
9167
|
+
archiveThread: {
|
|
9168
|
+
threadID: "thread-1",
|
|
9169
|
+
workItemID: "work-item-1",
|
|
9170
|
+
},
|
|
9171
|
+
executionPlan: {
|
|
9172
|
+
mode: "role_profile",
|
|
9173
|
+
roleProfileName: "monitor",
|
|
9174
|
+
roleProfile: {
|
|
9175
|
+
client: "sample",
|
|
9176
|
+
model: "",
|
|
9177
|
+
permissionMode: "read_only",
|
|
9178
|
+
reasoningEffort: "low",
|
|
9179
|
+
},
|
|
9180
|
+
workspaceDir: path.join(os.tmpdir(), "metheus-runner-selftest-conversation-assignment-skips-planner"),
|
|
9181
|
+
workspaceSource: "selftest",
|
|
9182
|
+
usedCommandFallback: false,
|
|
9183
|
+
},
|
|
9184
|
+
runtime: {
|
|
9185
|
+
baseURL: "https://example.test",
|
|
9186
|
+
token: "selftest-token",
|
|
9187
|
+
timeoutSeconds: 30,
|
|
9188
|
+
actor: { user_id: "user-1" },
|
|
9189
|
+
},
|
|
9190
|
+
deps: {
|
|
9191
|
+
saveRunnerRouteState: () => {},
|
|
9192
|
+
startRunnerTypingHeartbeat: () => ({ async stop() {} }),
|
|
9193
|
+
runRunnerAIExecution: async () => {
|
|
9194
|
+
aiCalls += 1;
|
|
9195
|
+
return {
|
|
9196
|
+
skip: false,
|
|
9197
|
+
reply: "제 관점에서는 범위와 우선순위를 먼저 고정하는 게 맞습니다.",
|
|
9198
|
+
contract: {
|
|
9199
|
+
type: "summary_request",
|
|
9200
|
+
actionable: true,
|
|
9201
|
+
assignments: [],
|
|
9202
|
+
summary_bot: "ryoai_bot",
|
|
9203
|
+
next_responders: ["ryoai_bot"],
|
|
9204
|
+
},
|
|
9205
|
+
};
|
|
9206
|
+
},
|
|
9207
|
+
performLocalBotDelivery: async () => ({
|
|
9208
|
+
delivery: { dryRun: true, body: {} },
|
|
9209
|
+
archive: {},
|
|
9210
|
+
}),
|
|
9211
|
+
serializeRunnerTriggerPolicy: (value) => value,
|
|
9212
|
+
serializeRunnerArchivePolicy: (value) => value,
|
|
9213
|
+
buildRunnerExecutionDeps: () => ({
|
|
9214
|
+
planRoleExecutionWithAI: async () => {
|
|
9215
|
+
plannerCalls += 1;
|
|
9216
|
+
return {
|
|
9217
|
+
requiresExecution: true,
|
|
9218
|
+
summaryRole: "worker",
|
|
9219
|
+
steps: [{ role: "worker", goal: "unexpected", artifactsRequired: true }],
|
|
9220
|
+
};
|
|
9221
|
+
},
|
|
9222
|
+
}),
|
|
9223
|
+
buildRunnerDeliveryDeps: () => ({}),
|
|
9224
|
+
buildRunnerRuntimeDeps: () => ({}),
|
|
9225
|
+
resolveConversationPeerBots: () => [
|
|
9226
|
+
{ id: "bot-lead-1", name: "RyoAI_bot" },
|
|
9227
|
+
{ id: "bot-peer-1", name: "RyoAI2_bot" },
|
|
9228
|
+
{ id: "bot-peer-2", name: "RyoAI3_bot" },
|
|
9229
|
+
],
|
|
9230
|
+
},
|
|
9231
|
+
});
|
|
9232
|
+
push(
|
|
9233
|
+
"delegated_single_lead_conversation_assignment_skips_planner",
|
|
9234
|
+
processed.kind === "replied"
|
|
9235
|
+
&& aiCalls === 1
|
|
9236
|
+
&& plannerCalls === 0
|
|
9237
|
+
&& String(processed.result?.assignment_validation_status || "") === "conversation_assignment"
|
|
9238
|
+
&& ensureArray(processed.result?.assignment_validation_modes).includes("conversation_contribution"),
|
|
9239
|
+
`kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} planner_calls=${plannerCalls} assignment_status=${String(processed.result?.assignment_validation_status || "(none)")} modes=${JSON.stringify(processed.result?.assignment_validation_modes || [])}`,
|
|
9240
|
+
);
|
|
9241
|
+
} catch (err) {
|
|
9242
|
+
push("delegated_single_lead_conversation_assignment_skips_planner", false, String(err?.message || err));
|
|
9243
|
+
}
|
|
9244
|
+
|
|
9245
|
+
try {
|
|
9246
|
+
let aiCalls = 0;
|
|
9247
|
+
const deliveredConversation = [];
|
|
9097
9248
|
const processed = await processRunnerSelectedRecord({
|
|
9098
9249
|
routeKey: "delegated-single-lead-restored-bot-reply-key",
|
|
9099
9250
|
normalizedRoute: normalizeRunnerRoute({
|