metheus-governance-mcp-cli 0.2.295 → 0.2.298
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 +101 -70
- package/lib/runner-orchestration-adjudication.mjs +35 -5
- package/lib/runner-orchestration-decision-bundle.mjs +106 -0
- package/lib/runner-orchestration-entrypoints.mjs +171 -26
- package/lib/runner-orchestration-intent-contracts.mjs +145 -20
- package/lib/runner-orchestration-selected-record-context.mjs +14 -13
- package/lib/runner-orchestration-selected-record-preparation.mjs +34 -9
- package/lib/runner-recovery.mjs +30 -23
- package/lib/selftest-runner-scenarios.mjs +529 -18
- package/package.json +1 -1
package/cli.mjs
CHANGED
|
@@ -3874,68 +3874,83 @@ function runnerRequestAuthoritativeDecisionBundle(entryRaw) {
|
|
|
3874
3874
|
function runnerRequestPreferredExecutionContractType(entryRaw) {
|
|
3875
3875
|
const entry = safeObject(entryRaw);
|
|
3876
3876
|
const decisionBundle = runnerRequestAuthoritativeDecisionBundle(entry);
|
|
3877
|
+
const hasAuthoritativeDecisionBundle = Object.keys(decisionBundle).length > 0;
|
|
3877
3878
|
return String(
|
|
3878
|
-
|
|
3879
|
+
(hasAuthoritativeDecisionBundle
|
|
3880
|
+
? decisionBundle.execution_contract_type
|
|
3881
|
+
: "")
|
|
3879
3882
|
|| entry.execution_contract_type
|
|
3880
3883
|
|| entry.root_execution_contract_type
|
|
3881
3884
|
|| "",
|
|
3882
3885
|
).trim().toLowerCase();
|
|
3883
3886
|
}
|
|
3884
|
-
|
|
3887
|
+
|
|
3885
3888
|
function runnerRequestPreferredExecutionContractActionable(entryRaw) {
|
|
3886
3889
|
const entry = safeObject(entryRaw);
|
|
3887
3890
|
const decisionBundle = runnerRequestAuthoritativeDecisionBundle(entry);
|
|
3888
|
-
|
|
3891
|
+
const hasAuthoritativeDecisionBundle = Object.keys(decisionBundle).length > 0;
|
|
3892
|
+
if (hasAuthoritativeDecisionBundle) {
|
|
3893
|
+
return decisionBundle.execution_contract_actionable === true;
|
|
3894
|
+
}
|
|
3895
|
+
return entry.execution_contract_actionable === true;
|
|
3889
3896
|
}
|
|
3890
3897
|
|
|
3891
3898
|
function runnerRequestPreferredExecutionContractTargets(entryRaw) {
|
|
3892
3899
|
const entry = safeObject(entryRaw);
|
|
3893
3900
|
const decisionBundle = runnerRequestAuthoritativeDecisionBundle(entry);
|
|
3901
|
+
const hasAuthoritativeDecisionBundle = Object.keys(decisionBundle).length > 0;
|
|
3894
3902
|
return uniqueOrderedStrings(
|
|
3895
|
-
|
|
3903
|
+
hasAuthoritativeDecisionBundle
|
|
3896
3904
|
? decisionBundle.execution_contract_targets
|
|
3897
3905
|
: ensureArray(entry.execution_contract_targets).length
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3906
|
+
? entry.execution_contract_targets
|
|
3907
|
+
: ensureArray(entry.root_execution_contract_targets).length
|
|
3908
|
+
? entry.root_execution_contract_targets
|
|
3909
|
+
: [],
|
|
3902
3910
|
normalizeTelegramMentionUsername,
|
|
3903
3911
|
);
|
|
3904
3912
|
}
|
|
3905
|
-
|
|
3913
|
+
|
|
3906
3914
|
function runnerRequestPreferredNextExpectedResponders(entryRaw) {
|
|
3907
3915
|
const entry = safeObject(entryRaw);
|
|
3908
3916
|
const decisionBundle = runnerRequestAuthoritativeDecisionBundle(entry);
|
|
3917
|
+
const hasAuthoritativeDecisionBundle = Object.keys(decisionBundle).length > 0;
|
|
3909
3918
|
return uniqueOrderedStrings(
|
|
3910
|
-
|
|
3919
|
+
hasAuthoritativeDecisionBundle
|
|
3911
3920
|
? decisionBundle.next_expected_responders
|
|
3912
3921
|
: ensureArray(entry.next_expected_responders).length
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3922
|
+
? entry.next_expected_responders
|
|
3923
|
+
: ensureArray(entry.root_next_expected_responders).length
|
|
3924
|
+
? entry.root_next_expected_responders
|
|
3925
|
+
: [],
|
|
3917
3926
|
normalizeTelegramMentionUsername,
|
|
3918
3927
|
);
|
|
3919
3928
|
}
|
|
3920
|
-
|
|
3929
|
+
|
|
3921
3930
|
function runnerRequestPreferredAuthoritySelectedBotUsernames(entryRaw) {
|
|
3922
3931
|
const entry = safeObject(entryRaw);
|
|
3932
|
+
const decisionBundle = runnerRequestAuthoritativeDecisionBundle(entry);
|
|
3933
|
+
const hasAuthoritativeDecisionBundle = Object.keys(decisionBundle).length > 0;
|
|
3923
3934
|
const normalizedSummaryBot = normalizeTelegramMentionUsername(entry.conversation_summary_bot);
|
|
3924
3935
|
return uniqueOrderedStrings(
|
|
3925
|
-
runnerRequestPreferredNextExpectedResponders(entry).length
|
|
3926
|
-
? runnerRequestPreferredNextExpectedResponders(entry)
|
|
3927
|
-
: runnerRequestPreferredExecutionContractTargets(entry).length
|
|
3928
|
-
? runnerRequestPreferredExecutionContractTargets(entry)
|
|
3929
|
-
: ensureArray(
|
|
3930
|
-
?
|
|
3931
|
-
: ensureArray(
|
|
3932
|
-
?
|
|
3933
|
-
:
|
|
3934
|
-
?
|
|
3935
|
-
:
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3936
|
+
runnerRequestPreferredNextExpectedResponders(entry).length
|
|
3937
|
+
? runnerRequestPreferredNextExpectedResponders(entry)
|
|
3938
|
+
: runnerRequestPreferredExecutionContractTargets(entry).length
|
|
3939
|
+
? runnerRequestPreferredExecutionContractTargets(entry)
|
|
3940
|
+
: hasAuthoritativeDecisionBundle && ensureArray(decisionBundle.selected_bot_usernames).length
|
|
3941
|
+
? decisionBundle.selected_bot_usernames
|
|
3942
|
+
: hasAuthoritativeDecisionBundle && ensureArray(decisionBundle.initial_responders).length
|
|
3943
|
+
? decisionBundle.initial_responders
|
|
3944
|
+
: ensureArray(entry.selected_bot_usernames).length
|
|
3945
|
+
? entry.selected_bot_usernames
|
|
3946
|
+
: ensureArray(entry.conversation_initial_responders).length
|
|
3947
|
+
? entry.conversation_initial_responders
|
|
3948
|
+
: normalizedSummaryBot
|
|
3949
|
+
? [normalizedSummaryBot]
|
|
3950
|
+
: [],
|
|
3951
|
+
normalizeTelegramMentionUsername,
|
|
3952
|
+
);
|
|
3953
|
+
}
|
|
3939
3954
|
|
|
3940
3955
|
function extractRunnerExplicitSelectedBotUsernamesFromParsed(parsedArchiveRaw) {
|
|
3941
3956
|
const parsedArchive = safeObject(parsedArchiveRaw);
|
|
@@ -3956,6 +3971,8 @@ function runnerRequestAllowsSharedHumanClaimTakeover({
|
|
|
3956
3971
|
canonicalHumanMessageKey = "",
|
|
3957
3972
|
}) {
|
|
3958
3973
|
const entry = safeObject(entryRaw);
|
|
3974
|
+
const decisionBundle = runnerRequestAuthoritativeDecisionBundle(entry);
|
|
3975
|
+
const hasAuthoritativeDecisionBundle = Object.keys(decisionBundle).length > 0;
|
|
3959
3976
|
const normalizedCurrentBotUsername = normalizeTelegramMentionUsername(currentBotUsername);
|
|
3960
3977
|
const normalizedCanonicalHumanMessageKey = String(canonicalHumanMessageKey || "").trim();
|
|
3961
3978
|
if (!normalizedCurrentBotUsername || !normalizedCanonicalHumanMessageKey) {
|
|
@@ -3969,11 +3986,17 @@ function runnerRequestAllowsSharedHumanClaimTakeover({
|
|
|
3969
3986
|
return pendingResponders.includes(normalizedCurrentBotUsername);
|
|
3970
3987
|
}
|
|
3971
3988
|
const directHumanResponders = uniqueOrderedStrings(
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3989
|
+
hasAuthoritativeDecisionBundle
|
|
3990
|
+
? [
|
|
3991
|
+
...ensureArray(decisionBundle.selected_bot_usernames),
|
|
3992
|
+
...ensureArray(decisionBundle.initial_responders),
|
|
3993
|
+
...ensureArray(decisionBundle.allowed_responders),
|
|
3994
|
+
]
|
|
3995
|
+
: [
|
|
3996
|
+
...ensureArray(entry.selected_bot_usernames),
|
|
3997
|
+
...ensureArray(entry.conversation_initial_responders),
|
|
3998
|
+
...ensureArray(entry.conversation_allowed_responders),
|
|
3999
|
+
],
|
|
3977
4000
|
normalizeTelegramMentionUsername,
|
|
3978
4001
|
);
|
|
3979
4002
|
return directHumanResponders.includes(normalizedCurrentBotUsername);
|
|
@@ -7096,18 +7119,30 @@ function mergeRunnerRequestForServerHydration(localEntryRaw, serverEntryRaw) {
|
|
|
7096
7119
|
merged[fieldName] = localValue;
|
|
7097
7120
|
}
|
|
7098
7121
|
};
|
|
7099
|
-
const preserveLocalArrayWhenServerEmpty = (fieldName) => {
|
|
7100
|
-
const serverValues = ensureArray(serverEntry[fieldName]).filter(Boolean);
|
|
7101
|
-
const localValues = ensureArray(localEntry[fieldName]).filter(Boolean);
|
|
7102
|
-
if (serverValues.length === 0 && localValues.length > 0) {
|
|
7103
|
-
merged[fieldName] = localValues;
|
|
7104
|
-
}
|
|
7105
|
-
};
|
|
7106
|
-
const
|
|
7107
|
-
const serverValue =
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
7122
|
+
const preserveLocalArrayWhenServerEmpty = (fieldName) => {
|
|
7123
|
+
const serverValues = ensureArray(serverEntry[fieldName]).filter(Boolean);
|
|
7124
|
+
const localValues = ensureArray(localEntry[fieldName]).filter(Boolean);
|
|
7125
|
+
if (serverValues.length === 0 && localValues.length > 0) {
|
|
7126
|
+
merged[fieldName] = localValues;
|
|
7127
|
+
}
|
|
7128
|
+
};
|
|
7129
|
+
const clearMergedStringWhenServerBlank = (fieldName) => {
|
|
7130
|
+
const serverValue = String(serverEntry[fieldName] || "").trim();
|
|
7131
|
+
if (!serverValue) {
|
|
7132
|
+
delete merged[fieldName];
|
|
7133
|
+
}
|
|
7134
|
+
};
|
|
7135
|
+
const clearMergedArrayWhenServerEmpty = (fieldName) => {
|
|
7136
|
+
const serverValues = ensureArray(serverEntry[fieldName]).filter(Boolean);
|
|
7137
|
+
if (serverValues.length === 0) {
|
|
7138
|
+
delete merged[fieldName];
|
|
7139
|
+
}
|
|
7140
|
+
};
|
|
7141
|
+
const preserveLocalObjectWhenServerBlank = (fieldName) => {
|
|
7142
|
+
const serverValue = safeObject(serverEntry[fieldName]);
|
|
7143
|
+
const localValue = safeObject(localEntry[fieldName]);
|
|
7144
|
+
if (!Object.keys(serverValue).length && Object.keys(localValue).length) {
|
|
7145
|
+
merged[fieldName] = localValue;
|
|
7111
7146
|
}
|
|
7112
7147
|
};
|
|
7113
7148
|
preserveLocalNumberWhenServerMissing("source_message_id");
|
|
@@ -7136,16 +7171,13 @@ function mergeRunnerRequestForServerHydration(localEntryRaw, serverEntryRaw) {
|
|
|
7136
7171
|
preserveLocalStringWhenServerBlank("root_thread_id");
|
|
7137
7172
|
preserveLocalStringWhenServerBlank("root_work_item_created_at");
|
|
7138
7173
|
preserveLocalStringWhenServerBlank("root_work_item_last_error");
|
|
7139
|
-
preserveLocalStringWhenServerBlank("
|
|
7140
|
-
preserveLocalStringWhenServerBlank("
|
|
7141
|
-
preserveLocalStringWhenServerBlank("
|
|
7142
|
-
preserveLocalStringWhenServerBlank("
|
|
7143
|
-
preserveLocalStringWhenServerBlank("
|
|
7144
|
-
preserveLocalStringWhenServerBlank("
|
|
7145
|
-
preserveLocalStringWhenServerBlank("
|
|
7146
|
-
preserveLocalStringWhenServerBlank("followup_response_contract_validation_status");
|
|
7147
|
-
preserveLocalStringWhenServerBlank("followup_response_contract_validation_reason");
|
|
7148
|
-
preserveLocalStringWhenServerBlank("followup_assignment_validation_status");
|
|
7174
|
+
preserveLocalStringWhenServerBlank("root_ai_reply_preview");
|
|
7175
|
+
preserveLocalStringWhenServerBlank("root_response_contract_validation_status");
|
|
7176
|
+
preserveLocalStringWhenServerBlank("root_response_contract_validation_reason");
|
|
7177
|
+
preserveLocalStringWhenServerBlank("followup_ai_reply_preview");
|
|
7178
|
+
preserveLocalStringWhenServerBlank("followup_response_contract_validation_status");
|
|
7179
|
+
preserveLocalStringWhenServerBlank("followup_response_contract_validation_reason");
|
|
7180
|
+
preserveLocalStringWhenServerBlank("followup_assignment_validation_status");
|
|
7149
7181
|
preserveLocalStringWhenServerBlank("followup_assignment_validation_reason");
|
|
7150
7182
|
preserveLocalStringWhenServerBlank("followup_delivery_status");
|
|
7151
7183
|
preserveLocalStringWhenServerBlank("followup_archive_status");
|
|
@@ -7154,24 +7186,23 @@ function mergeRunnerRequestForServerHydration(localEntryRaw, serverEntryRaw) {
|
|
|
7154
7186
|
preserveLocalArrayWhenServerEmpty("conversation_participants");
|
|
7155
7187
|
preserveLocalArrayWhenServerEmpty("conversation_initial_responders");
|
|
7156
7188
|
preserveLocalArrayWhenServerEmpty("conversation_allowed_responders");
|
|
7157
|
-
preserveLocalArrayWhenServerEmpty("
|
|
7158
|
-
preserveLocalArrayWhenServerEmpty("next_expected_responders");
|
|
7159
|
-
preserveLocalArrayWhenServerEmpty("normalized_execution_contract_targets");
|
|
7160
|
-
preserveLocalArrayWhenServerEmpty("normalized_execution_next_responders");
|
|
7161
|
-
preserveLocalArrayWhenServerEmpty("root_execution_contract_targets");
|
|
7162
|
-
preserveLocalArrayWhenServerEmpty("root_next_expected_responders");
|
|
7163
|
-
preserveLocalArrayWhenServerEmpty("root_response_contract_validation_targets");
|
|
7164
|
-
preserveLocalArrayWhenServerEmpty("followup_execution_contract_targets");
|
|
7165
|
-
preserveLocalArrayWhenServerEmpty("followup_next_expected_responders");
|
|
7166
|
-
preserveLocalArrayWhenServerEmpty("followup_normalized_execution_contract_targets");
|
|
7167
|
-
preserveLocalArrayWhenServerEmpty("followup_normalized_execution_next_responders");
|
|
7189
|
+
preserveLocalArrayWhenServerEmpty("root_response_contract_validation_targets");
|
|
7168
7190
|
preserveLocalArrayWhenServerEmpty("followup_response_contract_validation_targets");
|
|
7169
7191
|
preserveLocalArrayWhenServerEmpty("followup_assignment_validation_modes");
|
|
7170
7192
|
preserveLocalObjectWhenServerBlank("authoritative_decision_bundle");
|
|
7171
7193
|
preserveLocalObjectWhenServerBlank("reply_chain_context");
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7194
|
+
clearMergedStringWhenServerBlank("root_execution_contract_type");
|
|
7195
|
+
clearMergedArrayWhenServerEmpty("root_execution_contract_targets");
|
|
7196
|
+
clearMergedArrayWhenServerEmpty("root_next_expected_responders");
|
|
7197
|
+
clearMergedStringWhenServerBlank("followup_execution_contract_type");
|
|
7198
|
+
clearMergedStringWhenServerBlank("followup_normalized_execution_contract_type");
|
|
7199
|
+
clearMergedArrayWhenServerEmpty("followup_execution_contract_targets");
|
|
7200
|
+
clearMergedArrayWhenServerEmpty("followup_next_expected_responders");
|
|
7201
|
+
clearMergedArrayWhenServerEmpty("followup_normalized_execution_contract_targets");
|
|
7202
|
+
clearMergedArrayWhenServerEmpty("followup_normalized_execution_next_responders");
|
|
7203
|
+
if (serverEntry.conversation_allow_bot_to_bot !== true && localEntry.conversation_allow_bot_to_bot === true) {
|
|
7204
|
+
merged.conversation_allow_bot_to_bot = true;
|
|
7205
|
+
}
|
|
7175
7206
|
if (serverEntry.execution_contract_actionable !== true && localEntry.execution_contract_actionable === true) {
|
|
7176
7207
|
merged.execution_contract_actionable = true;
|
|
7177
7208
|
}
|
|
@@ -6,6 +6,10 @@ import {
|
|
|
6
6
|
} from "./runner-orchestration-visibility.mjs";
|
|
7
7
|
import {
|
|
8
8
|
resolveRunnerConversationDecisionBundle,
|
|
9
|
+
deriveRunnerConversationContinuationKind,
|
|
10
|
+
normalizeRunnerConversationDecisionBundle,
|
|
11
|
+
resolveRunnerConversationDecisionBundleCurrentTurnResponders,
|
|
12
|
+
validateRunnerConversationDecisionBundle,
|
|
9
13
|
} from "./runner-orchestration-decision-bundle.mjs";
|
|
10
14
|
|
|
11
15
|
function safeObject(value) {
|
|
@@ -75,6 +79,36 @@ function isRunnerBotReplyContinuationAuthorizedForCurrentBot({
|
|
|
75
79
|
if (normalizedSenderSelectors.includes(normalizedCurrentBotSelector)) {
|
|
76
80
|
return false;
|
|
77
81
|
}
|
|
82
|
+
const parsedAuthoritativeDecisionBundle = safeObject(parsed.authoritativeDecisionBundle);
|
|
83
|
+
const requestAuthoritativeDecisionBundle = safeObject(safeObject(persistedRequest).authoritative_decision_bundle);
|
|
84
|
+
const parsedAuthoritativeDecisionBundleValidation = Object.keys(parsedAuthoritativeDecisionBundle).length > 0
|
|
85
|
+
? validateRunnerConversationDecisionBundle(parsedAuthoritativeDecisionBundle)
|
|
86
|
+
: null;
|
|
87
|
+
const requestAuthoritativeDecisionBundleValidation = Object.keys(requestAuthoritativeDecisionBundle).length > 0
|
|
88
|
+
? validateRunnerConversationDecisionBundle(requestAuthoritativeDecisionBundle)
|
|
89
|
+
: null;
|
|
90
|
+
const authoritativeDecisionBundle = parsedAuthoritativeDecisionBundleValidation?.ok
|
|
91
|
+
? parsedAuthoritativeDecisionBundleValidation.bundle
|
|
92
|
+
: requestAuthoritativeDecisionBundleValidation?.ok
|
|
93
|
+
? requestAuthoritativeDecisionBundleValidation.bundle
|
|
94
|
+
: {};
|
|
95
|
+
if (Object.keys(authoritativeDecisionBundle).length > 0) {
|
|
96
|
+
const continuationKind = deriveRunnerConversationContinuationKind(authoritativeDecisionBundle);
|
|
97
|
+
const currentTurnResponders = resolveRunnerConversationDecisionBundleCurrentTurnResponders(
|
|
98
|
+
authoritativeDecisionBundle,
|
|
99
|
+
normalizedCurrentBotSelector,
|
|
100
|
+
);
|
|
101
|
+
if (currentTurnResponders.includes(normalizedCurrentBotSelector)) {
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
if (continuationKind === "public_multi_bot_followup") {
|
|
105
|
+
return ensureArray(authoritativeDecisionBundle.next_expected_responders).includes(normalizedCurrentBotSelector);
|
|
106
|
+
}
|
|
107
|
+
if (continuationKind === "delegation_followup") {
|
|
108
|
+
return ensureArray(authoritativeDecisionBundle.execution_contract_targets).includes(normalizedCurrentBotSelector)
|
|
109
|
+
|| ensureArray(authoritativeDecisionBundle.next_expected_responders).includes(normalizedCurrentBotSelector);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
78
112
|
const explicitReplyTargets = ensureArray([
|
|
79
113
|
...(Array.isArray(parsed.mentionUsernames) ? parsed.mentionUsernames : []),
|
|
80
114
|
parsed.replyToBotUsername,
|
|
@@ -87,11 +121,7 @@ function isRunnerBotReplyContinuationAuthorizedForCurrentBot({
|
|
|
87
121
|
if (explicitReplyTargets.includes(normalizedCurrentBotSelector)) {
|
|
88
122
|
return true;
|
|
89
123
|
}
|
|
90
|
-
|
|
91
|
-
const nextExpectedResponders = ensureArray(request.next_expected_responders)
|
|
92
|
-
.map((value) => normalizeMentionSelector(value))
|
|
93
|
-
.filter(Boolean);
|
|
94
|
-
return nextExpectedResponders.includes(normalizedCurrentBotSelector);
|
|
124
|
+
return false;
|
|
95
125
|
}
|
|
96
126
|
|
|
97
127
|
export async function resolveRunnerPrecomputedResponderAdjudication({
|
|
@@ -44,6 +44,23 @@ function normalizeBoolean(value, fallback = false) {
|
|
|
44
44
|
return fallback;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
function intFromRawAllowZero(raw, fallback = 0) {
|
|
48
|
+
const text = String(raw ?? "").trim();
|
|
49
|
+
if (!text) {
|
|
50
|
+
return fallback;
|
|
51
|
+
}
|
|
52
|
+
const parsed = Number.parseInt(text, 10);
|
|
53
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function normalizeContinuationKind(value) {
|
|
57
|
+
return String(value || "").trim().toLowerCase();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function normalizeReplyAnchorKind(value) {
|
|
61
|
+
return String(value || "").trim().toLowerCase();
|
|
62
|
+
}
|
|
63
|
+
|
|
47
64
|
function normalizeContractAssignments(assignmentsRaw) {
|
|
48
65
|
return uniqueOrderedSelectors(
|
|
49
66
|
ensureArray(assignmentsRaw).map((item) => {
|
|
@@ -70,6 +87,24 @@ export function normalizeRunnerConversationDecisionBundle(bundleRaw) {
|
|
|
70
87
|
? bundle.selected_bot_usernames
|
|
71
88
|
: initialResponders,
|
|
72
89
|
);
|
|
90
|
+
const replyToMessageID = intFromRawAllowZero(
|
|
91
|
+
bundle.reply_to_message_id
|
|
92
|
+
|| bundle.replyToMessageID,
|
|
93
|
+
0,
|
|
94
|
+
);
|
|
95
|
+
const replyAnchorSource = String(
|
|
96
|
+
bundle.reply_anchor_source
|
|
97
|
+
|| bundle.replyAnchorSource
|
|
98
|
+
|| "",
|
|
99
|
+
).trim().toLowerCase();
|
|
100
|
+
const replyAnchorKind = normalizeReplyAnchorKind(
|
|
101
|
+
bundle.reply_anchor_kind
|
|
102
|
+
|| bundle.replyAnchorKind,
|
|
103
|
+
);
|
|
104
|
+
const continuationKind = normalizeContinuationKind(
|
|
105
|
+
bundle.continuation_kind
|
|
106
|
+
|| bundle.continuationKind,
|
|
107
|
+
);
|
|
73
108
|
return {
|
|
74
109
|
schema_version: String(bundle.schema_version || "runner_conversation_decision.v1").trim(),
|
|
75
110
|
decision_type: String(bundle.decision_type || "unspecified").trim().toLowerCase(),
|
|
@@ -87,6 +122,10 @@ export function normalizeRunnerConversationDecisionBundle(bundleRaw) {
|
|
|
87
122
|
execution_contract_actionable: normalizeBoolean(bundle.execution_contract_actionable, false),
|
|
88
123
|
execution_contract_targets: executionContractTargets,
|
|
89
124
|
next_expected_responders: nextExpectedResponders,
|
|
125
|
+
reply_to_message_id: replyToMessageID > 0 ? replyToMessageID : 0,
|
|
126
|
+
reply_anchor_source: replyAnchorSource,
|
|
127
|
+
reply_anchor_kind: replyAnchorKind,
|
|
128
|
+
continuation_kind: continuationKind,
|
|
90
129
|
should_close_after_reply: typeof bundle.should_close_after_reply === "boolean"
|
|
91
130
|
? bundle.should_close_after_reply
|
|
92
131
|
: false,
|
|
@@ -98,6 +137,59 @@ export function normalizeRunnerConversationDecisionBundle(bundleRaw) {
|
|
|
98
137
|
};
|
|
99
138
|
}
|
|
100
139
|
|
|
140
|
+
export function deriveRunnerConversationContinuationKind(bundleRaw) {
|
|
141
|
+
const bundle = normalizeRunnerConversationDecisionBundle(bundleRaw);
|
|
142
|
+
if (bundle.continuation_kind) {
|
|
143
|
+
return bundle.continuation_kind;
|
|
144
|
+
}
|
|
145
|
+
if (bundle.execution_contract_type === "delegation" && (
|
|
146
|
+
bundle.execution_contract_targets.length > 0
|
|
147
|
+
|| bundle.next_expected_responders.length > 0
|
|
148
|
+
)) {
|
|
149
|
+
return "delegation_followup";
|
|
150
|
+
}
|
|
151
|
+
if (bundle.conversation_intent_mode === "multi_bot_direct" && bundle.next_expected_responders.length > 0) {
|
|
152
|
+
return "public_multi_bot_followup";
|
|
153
|
+
}
|
|
154
|
+
if (bundle.allow_bot_to_bot === true && bundle.next_expected_responders.length > 0) {
|
|
155
|
+
return "relay_followup";
|
|
156
|
+
}
|
|
157
|
+
return "";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function resolveRunnerConversationDecisionBundleReplyAnchor(bundleRaw) {
|
|
161
|
+
const bundle = normalizeRunnerConversationDecisionBundle(bundleRaw);
|
|
162
|
+
return {
|
|
163
|
+
replyToMessageID: intFromRawAllowZero(bundle.reply_to_message_id, 0),
|
|
164
|
+
replyAnchorSource: String(bundle.reply_anchor_source || "").trim().toLowerCase(),
|
|
165
|
+
replyAnchorKind: normalizeReplyAnchorKind(bundle.reply_anchor_kind),
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function resolveRunnerConversationDecisionBundleCurrentTurnResponders(bundleRaw, currentBotSelector = "") {
|
|
170
|
+
const bundle = normalizeRunnerConversationDecisionBundle(bundleRaw);
|
|
171
|
+
const normalizedCurrentBotSelector = normalizeMentionSelector(currentBotSelector);
|
|
172
|
+
const continuationKind = deriveRunnerConversationContinuationKind(bundle);
|
|
173
|
+
const candidateResponders = uniqueOrderedSelectors(
|
|
174
|
+
ensureArray(bundle.next_expected_responders).length
|
|
175
|
+
? bundle.next_expected_responders
|
|
176
|
+
: ensureArray(bundle.execution_contract_targets).length
|
|
177
|
+
? bundle.execution_contract_targets
|
|
178
|
+
: bundle.selected_bot_usernames,
|
|
179
|
+
);
|
|
180
|
+
if (!normalizedCurrentBotSelector) {
|
|
181
|
+
return continuationKind ? candidateResponders : bundle.selected_bot_usernames;
|
|
182
|
+
}
|
|
183
|
+
if (continuationKind) {
|
|
184
|
+
return candidateResponders.includes(normalizedCurrentBotSelector)
|
|
185
|
+
? [normalizedCurrentBotSelector]
|
|
186
|
+
: [];
|
|
187
|
+
}
|
|
188
|
+
return bundle.selected_bot_usernames.includes(normalizedCurrentBotSelector)
|
|
189
|
+
? [normalizedCurrentBotSelector]
|
|
190
|
+
: [];
|
|
191
|
+
}
|
|
192
|
+
|
|
101
193
|
export function validateRunnerConversationDecisionBundle(bundleRaw) {
|
|
102
194
|
const bundle = normalizeRunnerConversationDecisionBundle(bundleRaw);
|
|
103
195
|
if (!Object.keys(safeObject(bundleRaw)).length) {
|
|
@@ -184,6 +276,14 @@ export function validateRunnerConversationDecisionBundle(bundleRaw) {
|
|
|
184
276
|
bundle,
|
|
185
277
|
};
|
|
186
278
|
}
|
|
279
|
+
if (!(bundle.reply_to_message_id > 0) && (bundle.reply_anchor_source || bundle.reply_anchor_kind)) {
|
|
280
|
+
return {
|
|
281
|
+
ok: false,
|
|
282
|
+
status: "invalid_reply_anchor_without_message_id",
|
|
283
|
+
reason: "reply anchor metadata requires reply_to_message_id",
|
|
284
|
+
bundle,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
187
287
|
if (bundle.visible_handoff_required === true && bundle.visible_handoff_targets.length === 0) {
|
|
188
288
|
return {
|
|
189
289
|
ok: false,
|
|
@@ -212,6 +312,9 @@ export function buildRunnerConversationDecisionBundle({
|
|
|
212
312
|
normalizedExecutionContractType = "",
|
|
213
313
|
normalizedExecutionTargets = [],
|
|
214
314
|
normalizedExecutionNextResponders = [],
|
|
315
|
+
replyToMessageID = 0,
|
|
316
|
+
replyAnchorSource = "",
|
|
317
|
+
replyAnchorKind = "",
|
|
215
318
|
shouldCloseAfterReply,
|
|
216
319
|
reasoningSummary = "",
|
|
217
320
|
}) {
|
|
@@ -270,6 +373,9 @@ export function buildRunnerConversationDecisionBundle({
|
|
|
270
373
|
execution_contract_actionable: contract.actionable === true,
|
|
271
374
|
execution_contract_targets: ensureArray(normalizedExecutionTargets),
|
|
272
375
|
next_expected_responders: ensureArray(normalizedExecutionNextResponders),
|
|
376
|
+
reply_to_message_id: intFromRawAllowZero(replyToMessageID, 0) || undefined,
|
|
377
|
+
reply_anchor_source: String(replyAnchorSource || "").trim().toLowerCase(),
|
|
378
|
+
reply_anchor_kind: normalizeReplyAnchorKind(replyAnchorKind),
|
|
273
379
|
should_close_after_reply: typeof shouldCloseAfterReply === "boolean"
|
|
274
380
|
? shouldCloseAfterReply
|
|
275
381
|
: undefined,
|