metheus-governance-mcp-cli 0.2.231 → 0.2.232
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 +2205 -1331
- package/lib/local-ai-adapters.mjs +2 -82
- package/lib/runner-orchestration.mjs +253 -215
- package/lib/runner-trigger.mjs +3 -5
- package/lib/selftest-runner-scenarios.mjs +20 -27
- package/package.json +1 -1
package/cli.mjs
CHANGED
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
adjudicateRunnerStartupLoopWithAI,
|
|
16
16
|
analyzeHumanConversationIntentWithAI,
|
|
17
17
|
auditRoleExecutionPlanWithAI,
|
|
18
|
-
auditDirectHumanReplyWithAI,
|
|
19
18
|
explainExecutionFailureWithAI,
|
|
20
19
|
normalizeExecutionArtifacts,
|
|
21
20
|
planRoleExecutionWithAI,
|
|
@@ -1915,6 +1914,15 @@ function mergeRunnerStateRecords(preferred, fallback) {
|
|
|
1915
1914
|
}
|
|
1916
1915
|
return allowUndefined ? undefined : 0;
|
|
1917
1916
|
};
|
|
1917
|
+
const pickArrayField = (key, normalizer = (value) => String(value || "").trim()) => {
|
|
1918
|
+
if (hasOwn(primary, key)) {
|
|
1919
|
+
const value = uniqueOrderedStrings(ensureArray(primary[key]), normalizer).filter(Boolean);
|
|
1920
|
+
if (value.length) {
|
|
1921
|
+
return value;
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
return uniqueOrderedStrings(ensureArray(secondary[key]), normalizer).filter(Boolean);
|
|
1925
|
+
};
|
|
1918
1926
|
return {
|
|
1919
1927
|
last_processed_comment_id: pickStringField("last_processed_comment_id"),
|
|
1920
1928
|
last_processed_created_at: pickStringField("last_processed_created_at"),
|
|
@@ -1949,6 +1957,31 @@ function mergeRunnerStateRecords(preferred, fallback) {
|
|
|
1949
1957
|
last_root_work_item_id: pickStringField("last_root_work_item_id"),
|
|
1950
1958
|
last_root_work_item_title: pickStringField("last_root_work_item_title"),
|
|
1951
1959
|
last_root_work_item_status: pickStringField("last_root_work_item_status"),
|
|
1960
|
+
last_contract_validation_status: pickStringField("last_contract_validation_status"),
|
|
1961
|
+
last_contract_validation_reason: pickStringField("last_contract_validation_reason"),
|
|
1962
|
+
last_normalized_execution_contract_type: pickStringField("last_normalized_execution_contract_type"),
|
|
1963
|
+
last_assignment_validation_status: pickStringField("last_assignment_validation_status"),
|
|
1964
|
+
last_assignment_validation_reason: pickStringField("last_assignment_validation_reason"),
|
|
1965
|
+
last_followup_ai_reply_preview: pickStringField("last_followup_ai_reply_preview"),
|
|
1966
|
+
last_followup_execution_contract_type: pickStringField("last_followup_execution_contract_type"),
|
|
1967
|
+
last_followup_normalized_execution_contract_type: pickStringField("last_followup_normalized_execution_contract_type"),
|
|
1968
|
+
last_followup_response_contract_validation_status: pickStringField("last_followup_response_contract_validation_status"),
|
|
1969
|
+
last_followup_response_contract_validation_reason: pickStringField("last_followup_response_contract_validation_reason"),
|
|
1970
|
+
last_followup_assignment_validation_status: pickStringField("last_followup_assignment_validation_status"),
|
|
1971
|
+
last_followup_assignment_validation_reason: pickStringField("last_followup_assignment_validation_reason"),
|
|
1972
|
+
last_followup_delivery_status: pickStringField("last_followup_delivery_status"),
|
|
1973
|
+
last_followup_archive_status: pickStringField("last_followup_archive_status"),
|
|
1974
|
+
last_followup_transport_error: pickStringField("last_followup_transport_error"),
|
|
1975
|
+
last_followup_archive_error: pickStringField("last_followup_archive_error"),
|
|
1976
|
+
last_contract_validation_targets: pickArrayField("last_contract_validation_targets", normalizeTelegramMentionUsername),
|
|
1977
|
+
last_normalized_execution_contract_targets: pickArrayField("last_normalized_execution_contract_targets", normalizeTelegramMentionUsername),
|
|
1978
|
+
last_normalized_execution_next_responders: pickArrayField("last_normalized_execution_next_responders", normalizeTelegramMentionUsername),
|
|
1979
|
+
last_followup_execution_contract_targets: pickArrayField("last_followup_execution_contract_targets", normalizeTelegramMentionUsername),
|
|
1980
|
+
last_followup_next_expected_responders: pickArrayField("last_followup_next_expected_responders", normalizeTelegramMentionUsername),
|
|
1981
|
+
last_followup_normalized_execution_contract_targets: pickArrayField("last_followup_normalized_execution_contract_targets", normalizeTelegramMentionUsername),
|
|
1982
|
+
last_followup_normalized_execution_next_responders: pickArrayField("last_followup_normalized_execution_next_responders", normalizeTelegramMentionUsername),
|
|
1983
|
+
last_followup_response_contract_validation_targets: pickArrayField("last_followup_response_contract_validation_targets", normalizeTelegramMentionUsername),
|
|
1984
|
+
last_followup_assignment_validation_modes: pickArrayField("last_followup_assignment_validation_modes", (value) => String(value || "").trim().toLowerCase()),
|
|
1952
1985
|
conversation_sessions: {
|
|
1953
1986
|
...safeObject(secondary.conversation_sessions),
|
|
1954
1987
|
...safeObject(primary.conversation_sessions),
|
|
@@ -2443,6 +2476,7 @@ function normalizeBotRunnerRequests(rawRequests, nowMs = Date.now()) {
|
|
|
2443
2476
|
),
|
|
2444
2477
|
ai_reply_generated_at: firstNonEmptyString([entry.ai_reply_generated_at, entry.aiReplyGeneratedAt]),
|
|
2445
2478
|
ai_reply_preview: String(entry.ai_reply_preview || entry.aiReplyPreview || "").trim(),
|
|
2479
|
+
followup_ai_reply_preview: String(entry.followup_ai_reply_preview || entry.followupAiReplyPreview || "").trim(),
|
|
2446
2480
|
root_execution_contract_type: String(entry.root_execution_contract_type || entry.rootExecutionContractType || "").trim().toLowerCase(),
|
|
2447
2481
|
root_execution_contract_targets: ensureArray(entry.root_execution_contract_targets || entry.rootExecutionContractTargets)
|
|
2448
2482
|
.map((value) => normalizeTelegramMentionUsername(value))
|
|
@@ -2461,15 +2495,43 @@ function normalizeBotRunnerRequests(rawRequests, nowMs = Date.now()) {
|
|
|
2461
2495
|
response_contract_validation_targets: ensureArray(entry.response_contract_validation_targets || entry.responseContractValidationTargets)
|
|
2462
2496
|
.map((value) => normalizeTelegramMentionUsername(value))
|
|
2463
2497
|
.filter(Boolean),
|
|
2498
|
+
followup_execution_contract_type: String(entry.followup_execution_contract_type || entry.followupExecutionContractType || "").trim().toLowerCase(),
|
|
2499
|
+
followup_execution_contract_targets: ensureArray(entry.followup_execution_contract_targets || entry.followupExecutionContractTargets)
|
|
2500
|
+
.map((value) => normalizeTelegramMentionUsername(value))
|
|
2501
|
+
.filter(Boolean),
|
|
2502
|
+
followup_next_expected_responders: ensureArray(entry.followup_next_expected_responders || entry.followupNextExpectedResponders)
|
|
2503
|
+
.map((value) => normalizeTelegramMentionUsername(value))
|
|
2504
|
+
.filter(Boolean),
|
|
2505
|
+
followup_normalized_execution_contract_type: String(entry.followup_normalized_execution_contract_type || entry.followupNormalizedExecutionContractType || "").trim().toLowerCase(),
|
|
2506
|
+
followup_normalized_execution_contract_targets: ensureArray(entry.followup_normalized_execution_contract_targets || entry.followupNormalizedExecutionContractTargets)
|
|
2507
|
+
.map((value) => normalizeTelegramMentionUsername(value))
|
|
2508
|
+
.filter(Boolean),
|
|
2509
|
+
followup_normalized_execution_next_responders: ensureArray(entry.followup_normalized_execution_next_responders || entry.followupNormalizedExecutionNextResponders)
|
|
2510
|
+
.map((value) => normalizeTelegramMentionUsername(value))
|
|
2511
|
+
.filter(Boolean),
|
|
2512
|
+
followup_response_contract_validation_status: String(entry.followup_response_contract_validation_status || entry.followupResponseContractValidationStatus || "").trim().toLowerCase(),
|
|
2513
|
+
followup_response_contract_validation_reason: String(entry.followup_response_contract_validation_reason || entry.followupResponseContractValidationReason || "").trim(),
|
|
2514
|
+
followup_response_contract_validation_targets: ensureArray(entry.followup_response_contract_validation_targets || entry.followupResponseContractValidationTargets)
|
|
2515
|
+
.map((value) => normalizeTelegramMentionUsername(value))
|
|
2516
|
+
.filter(Boolean),
|
|
2464
2517
|
assignment_validation_status: String(entry.assignment_validation_status || entry.assignmentValidationStatus || "").trim().toLowerCase(),
|
|
2465
2518
|
assignment_validation_reason: String(entry.assignment_validation_reason || entry.assignmentValidationReason || "").trim(),
|
|
2466
2519
|
assignment_validation_modes: ensureArray(entry.assignment_validation_modes || entry.assignmentValidationModes)
|
|
2467
2520
|
.map((value) => String(value || "").trim().toLowerCase())
|
|
2468
2521
|
.filter(Boolean),
|
|
2522
|
+
followup_assignment_validation_status: String(entry.followup_assignment_validation_status || entry.followupAssignmentValidationStatus || "").trim().toLowerCase(),
|
|
2523
|
+
followup_assignment_validation_reason: String(entry.followup_assignment_validation_reason || entry.followupAssignmentValidationReason || "").trim(),
|
|
2524
|
+
followup_assignment_validation_modes: ensureArray(entry.followup_assignment_validation_modes || entry.followupAssignmentValidationModes)
|
|
2525
|
+
.map((value) => String(value || "").trim().toLowerCase())
|
|
2526
|
+
.filter(Boolean),
|
|
2469
2527
|
delivery_status: String(entry.delivery_status || entry.deliveryStatus || "").trim().toLowerCase(),
|
|
2470
2528
|
archive_status: String(entry.archive_status || entry.archiveStatus || "").trim().toLowerCase(),
|
|
2471
2529
|
transport_error: String(entry.transport_error || entry.transportError || "").trim(),
|
|
2472
2530
|
archive_error: String(entry.archive_error || entry.archiveError || "").trim(),
|
|
2531
|
+
followup_delivery_status: String(entry.followup_delivery_status || entry.followupDeliveryStatus || "").trim().toLowerCase(),
|
|
2532
|
+
followup_archive_status: String(entry.followup_archive_status || entry.followupArchiveStatus || "").trim().toLowerCase(),
|
|
2533
|
+
followup_transport_error: String(entry.followup_transport_error || entry.followupTransportError || "").trim(),
|
|
2534
|
+
followup_archive_error: String(entry.followup_archive_error || entry.followupArchiveError || "").trim(),
|
|
2473
2535
|
normalized_intent: String(entry.normalized_intent || entry.normalizedIntent || "").trim().toLowerCase(),
|
|
2474
2536
|
status,
|
|
2475
2537
|
claimed_by_route: String(entry.claimed_by_route || entry.claimedByRoute || "").trim(),
|
|
@@ -3051,11 +3113,341 @@ function runnerRequestHasConversationContractData(entryRaw) {
|
|
|
3051
3113
|
|| ensureArray(entry.conversation_allowed_responders).length
|
|
3052
3114
|
|| entry.conversation_allow_bot_to_bot === true
|
|
3053
3115
|
|| String(entry.conversation_reply_expectation || "").trim()
|
|
3054
|
-
||
|
|
3055
|
-
|| entry
|
|
3056
|
-
||
|
|
3057
|
-
||
|
|
3116
|
+
|| runnerRequestPreferredExecutionContractType(entry)
|
|
3117
|
+
|| runnerRequestPreferredExecutionContractActionable(entry) === true
|
|
3118
|
+
|| runnerRequestPreferredExecutionContractTargets(entry).length
|
|
3119
|
+
|| runnerRequestPreferredNextExpectedResponders(entry).length
|
|
3120
|
+
);
|
|
3121
|
+
}
|
|
3122
|
+
|
|
3123
|
+
function runnerRequestPreferredExecutionContractType(entryRaw) {
|
|
3124
|
+
const entry = safeObject(entryRaw);
|
|
3125
|
+
return String(
|
|
3126
|
+
entry.execution_contract_type
|
|
3127
|
+
|| entry.followup_execution_contract_type
|
|
3128
|
+
|| entry.root_execution_contract_type
|
|
3129
|
+
|| "",
|
|
3130
|
+
).trim().toLowerCase();
|
|
3131
|
+
}
|
|
3132
|
+
|
|
3133
|
+
function runnerRequestPreferredExecutionContractActionable(entryRaw) {
|
|
3134
|
+
const entry = safeObject(entryRaw);
|
|
3135
|
+
return entry.execution_contract_actionable === true;
|
|
3136
|
+
}
|
|
3137
|
+
|
|
3138
|
+
function runnerRequestPreferredExecutionContractTargets(entryRaw) {
|
|
3139
|
+
const entry = safeObject(entryRaw);
|
|
3140
|
+
return uniqueOrderedStrings(
|
|
3141
|
+
ensureArray(entry.execution_contract_targets).length
|
|
3142
|
+
? entry.execution_contract_targets
|
|
3143
|
+
: ensureArray(entry.followup_execution_contract_targets).length
|
|
3144
|
+
? entry.followup_execution_contract_targets
|
|
3145
|
+
: ensureArray(entry.root_execution_contract_targets).length
|
|
3146
|
+
? entry.root_execution_contract_targets
|
|
3147
|
+
: [],
|
|
3148
|
+
normalizeTelegramMentionUsername,
|
|
3149
|
+
);
|
|
3150
|
+
}
|
|
3151
|
+
|
|
3152
|
+
function runnerRequestPreferredNextExpectedResponders(entryRaw) {
|
|
3153
|
+
const entry = safeObject(entryRaw);
|
|
3154
|
+
return uniqueOrderedStrings(
|
|
3155
|
+
ensureArray(entry.next_expected_responders).length
|
|
3156
|
+
? entry.next_expected_responders
|
|
3157
|
+
: ensureArray(entry.followup_next_expected_responders).length
|
|
3158
|
+
? entry.followup_next_expected_responders
|
|
3159
|
+
: ensureArray(entry.root_next_expected_responders).length
|
|
3160
|
+
? entry.root_next_expected_responders
|
|
3161
|
+
: [],
|
|
3162
|
+
normalizeTelegramMentionUsername,
|
|
3163
|
+
);
|
|
3164
|
+
}
|
|
3165
|
+
|
|
3166
|
+
function runnerRequestPreferredAIReplyPreview(entryRaw) {
|
|
3167
|
+
const entry = safeObject(entryRaw);
|
|
3168
|
+
return String(
|
|
3169
|
+
entry.ai_reply_preview
|
|
3170
|
+
|| entry.followup_ai_reply_preview
|
|
3171
|
+
|| entry.root_ai_reply_preview
|
|
3172
|
+
|| "",
|
|
3173
|
+
).trim();
|
|
3174
|
+
}
|
|
3175
|
+
|
|
3176
|
+
function runnerRequestPreferredResponseContractValidationStatus(entryRaw) {
|
|
3177
|
+
const entry = safeObject(entryRaw);
|
|
3178
|
+
return String(
|
|
3179
|
+
entry.response_contract_validation_status
|
|
3180
|
+
|| entry.followup_response_contract_validation_status
|
|
3181
|
+
|| entry.root_response_contract_validation_status
|
|
3182
|
+
|| "",
|
|
3183
|
+
).trim().toLowerCase();
|
|
3184
|
+
}
|
|
3185
|
+
|
|
3186
|
+
function runnerRequestPreferredResponseContractValidationReason(entryRaw) {
|
|
3187
|
+
const entry = safeObject(entryRaw);
|
|
3188
|
+
return String(
|
|
3189
|
+
entry.response_contract_validation_reason
|
|
3190
|
+
|| entry.followup_response_contract_validation_reason
|
|
3191
|
+
|| entry.root_response_contract_validation_reason
|
|
3192
|
+
|| "",
|
|
3193
|
+
).trim();
|
|
3194
|
+
}
|
|
3195
|
+
|
|
3196
|
+
function runnerRequestPreferredResponseContractValidationTargets(entryRaw) {
|
|
3197
|
+
const entry = safeObject(entryRaw);
|
|
3198
|
+
return uniqueOrderedStrings(
|
|
3199
|
+
ensureArray(entry.response_contract_validation_targets).length
|
|
3200
|
+
? entry.response_contract_validation_targets
|
|
3201
|
+
: ensureArray(entry.followup_response_contract_validation_targets).length
|
|
3202
|
+
? entry.followup_response_contract_validation_targets
|
|
3203
|
+
: ensureArray(entry.root_response_contract_validation_targets).length
|
|
3204
|
+
? entry.root_response_contract_validation_targets
|
|
3205
|
+
: [],
|
|
3206
|
+
normalizeTelegramMentionUsername,
|
|
3207
|
+
);
|
|
3208
|
+
}
|
|
3209
|
+
|
|
3210
|
+
function runnerRequestPreferredAssignmentValidationStatus(entryRaw) {
|
|
3211
|
+
const entry = safeObject(entryRaw);
|
|
3212
|
+
return String(
|
|
3213
|
+
entry.assignment_validation_status
|
|
3214
|
+
|| entry.followup_assignment_validation_status
|
|
3215
|
+
|| "",
|
|
3216
|
+
).trim().toLowerCase();
|
|
3217
|
+
}
|
|
3218
|
+
|
|
3219
|
+
function runnerRequestPreferredAssignmentValidationReason(entryRaw) {
|
|
3220
|
+
const entry = safeObject(entryRaw);
|
|
3221
|
+
return String(
|
|
3222
|
+
entry.assignment_validation_reason
|
|
3223
|
+
|| entry.followup_assignment_validation_reason
|
|
3224
|
+
|| "",
|
|
3225
|
+
).trim();
|
|
3226
|
+
}
|
|
3227
|
+
|
|
3228
|
+
function runnerRequestPreferredAssignmentValidationModes(entryRaw) {
|
|
3229
|
+
const entry = safeObject(entryRaw);
|
|
3230
|
+
return uniqueOrderedStrings(
|
|
3231
|
+
ensureArray(entry.assignment_validation_modes).length
|
|
3232
|
+
? entry.assignment_validation_modes
|
|
3233
|
+
: ensureArray(entry.followup_assignment_validation_modes).length
|
|
3234
|
+
? entry.followup_assignment_validation_modes
|
|
3235
|
+
: [],
|
|
3236
|
+
(value) => String(value || "").trim().toLowerCase(),
|
|
3237
|
+
);
|
|
3238
|
+
}
|
|
3239
|
+
|
|
3240
|
+
function runnerRequestPreferredDeliveryStatus(entryRaw) {
|
|
3241
|
+
const entry = safeObject(entryRaw);
|
|
3242
|
+
return String(
|
|
3243
|
+
entry.delivery_status
|
|
3244
|
+
|| entry.followup_delivery_status
|
|
3245
|
+
|| "",
|
|
3246
|
+
).trim().toLowerCase();
|
|
3247
|
+
}
|
|
3248
|
+
|
|
3249
|
+
function runnerRequestPreferredArchiveStatus(entryRaw) {
|
|
3250
|
+
const entry = safeObject(entryRaw);
|
|
3251
|
+
return String(
|
|
3252
|
+
entry.archive_status
|
|
3253
|
+
|| entry.followup_archive_status
|
|
3254
|
+
|| "",
|
|
3255
|
+
).trim().toLowerCase();
|
|
3256
|
+
}
|
|
3257
|
+
|
|
3258
|
+
function runnerRequestPreferredTransportError(entryRaw) {
|
|
3259
|
+
const entry = safeObject(entryRaw);
|
|
3260
|
+
return String(
|
|
3261
|
+
entry.transport_error
|
|
3262
|
+
|| entry.followup_transport_error
|
|
3263
|
+
|| "",
|
|
3264
|
+
).trim();
|
|
3265
|
+
}
|
|
3266
|
+
|
|
3267
|
+
function runnerRequestPreferredArchiveError(entryRaw) {
|
|
3268
|
+
const entry = safeObject(entryRaw);
|
|
3269
|
+
return String(
|
|
3270
|
+
entry.archive_error
|
|
3271
|
+
|| entry.followup_archive_error
|
|
3272
|
+
|| "",
|
|
3273
|
+
).trim();
|
|
3274
|
+
}
|
|
3275
|
+
|
|
3276
|
+
function buildRunnerValidationAndDeliverySummary({
|
|
3277
|
+
aiReplyPreview = "",
|
|
3278
|
+
executionContractType = "",
|
|
3279
|
+
executionContractTargets = [],
|
|
3280
|
+
nextExpectedResponders = [],
|
|
3281
|
+
responseContractValidationStatus = "",
|
|
3282
|
+
responseContractValidationReason = "",
|
|
3283
|
+
responseContractValidationTargets = [],
|
|
3284
|
+
assignmentValidationStatus = "",
|
|
3285
|
+
assignmentValidationReason = "",
|
|
3286
|
+
assignmentValidationModes = [],
|
|
3287
|
+
deliveryStatus = "",
|
|
3288
|
+
archiveStatus = "",
|
|
3289
|
+
transportError = "",
|
|
3290
|
+
archiveError = "",
|
|
3291
|
+
} = {}) {
|
|
3292
|
+
return {
|
|
3293
|
+
ai_reply_preview: String(aiReplyPreview || "").trim(),
|
|
3294
|
+
execution_contract_type: String(executionContractType || "").trim().toLowerCase(),
|
|
3295
|
+
execution_contract_targets: uniqueOrderedStrings(
|
|
3296
|
+
ensureArray(executionContractTargets),
|
|
3297
|
+
normalizeTelegramMentionUsername,
|
|
3298
|
+
),
|
|
3299
|
+
next_expected_responders: uniqueOrderedStrings(
|
|
3300
|
+
ensureArray(nextExpectedResponders),
|
|
3301
|
+
normalizeTelegramMentionUsername,
|
|
3302
|
+
),
|
|
3303
|
+
response_contract_validation_status: String(responseContractValidationStatus || "").trim().toLowerCase(),
|
|
3304
|
+
response_contract_validation_reason: String(responseContractValidationReason || "").trim(),
|
|
3305
|
+
response_contract_validation_targets: uniqueOrderedStrings(
|
|
3306
|
+
ensureArray(responseContractValidationTargets),
|
|
3307
|
+
normalizeTelegramMentionUsername,
|
|
3308
|
+
),
|
|
3309
|
+
assignment_validation_status: String(assignmentValidationStatus || "").trim().toLowerCase(),
|
|
3310
|
+
assignment_validation_reason: String(assignmentValidationReason || "").trim(),
|
|
3311
|
+
assignment_validation_modes: uniqueOrderedStrings(
|
|
3312
|
+
ensureArray(assignmentValidationModes),
|
|
3313
|
+
(value) => String(value || "").trim().toLowerCase(),
|
|
3314
|
+
),
|
|
3315
|
+
delivery_status: String(deliveryStatus || "").trim().toLowerCase(),
|
|
3316
|
+
archive_status: String(archiveStatus || "").trim().toLowerCase(),
|
|
3317
|
+
transport_error: String(transportError || "").trim(),
|
|
3318
|
+
archive_error: String(archiveError || "").trim(),
|
|
3319
|
+
};
|
|
3320
|
+
}
|
|
3321
|
+
|
|
3322
|
+
function buildRunnerRequestRootWorkItemSummary(entryRaw) {
|
|
3323
|
+
const entry = safeObject(entryRaw);
|
|
3324
|
+
const rootWorkItemID = String(entry.root_work_item_id || "").trim();
|
|
3325
|
+
if (!rootWorkItemID) {
|
|
3326
|
+
return null;
|
|
3327
|
+
}
|
|
3328
|
+
return {
|
|
3329
|
+
id: rootWorkItemID,
|
|
3330
|
+
title: String(entry.root_work_item_title || "").trim(),
|
|
3331
|
+
status: normalizeRunnerWorkItemStatus(entry.root_work_item_status),
|
|
3332
|
+
thread_id: String(entry.root_thread_id || "").trim(),
|
|
3333
|
+
};
|
|
3334
|
+
}
|
|
3335
|
+
|
|
3336
|
+
function buildRunnerRouteLastResultSummary(routeStateRaw) {
|
|
3337
|
+
const routeState = safeObject(routeStateRaw);
|
|
3338
|
+
const executionContractType = String(
|
|
3339
|
+
routeState.last_followup_execution_contract_type
|
|
3340
|
+
|| routeState.last_normalized_execution_contract_type
|
|
3341
|
+
|| "",
|
|
3342
|
+
).trim().toLowerCase();
|
|
3343
|
+
const executionContractTargets = uniqueOrderedStrings(
|
|
3344
|
+
ensureArray(routeState.last_followup_execution_contract_targets).length
|
|
3345
|
+
? routeState.last_followup_execution_contract_targets
|
|
3346
|
+
: ensureArray(routeState.last_normalized_execution_contract_targets),
|
|
3347
|
+
normalizeTelegramMentionUsername,
|
|
3348
|
+
);
|
|
3349
|
+
const nextExpectedResponders = uniqueOrderedStrings(
|
|
3350
|
+
ensureArray(routeState.last_followup_next_expected_responders).length
|
|
3351
|
+
? routeState.last_followup_next_expected_responders
|
|
3352
|
+
: ensureArray(routeState.last_normalized_execution_next_responders),
|
|
3353
|
+
normalizeTelegramMentionUsername,
|
|
3354
|
+
);
|
|
3355
|
+
const responseContractValidationStatus = String(
|
|
3356
|
+
routeState.last_followup_response_contract_validation_status
|
|
3357
|
+
|| routeState.last_contract_validation_status
|
|
3358
|
+
|| "",
|
|
3359
|
+
).trim().toLowerCase();
|
|
3360
|
+
const responseContractValidationReason = String(
|
|
3361
|
+
routeState.last_followup_response_contract_validation_reason
|
|
3362
|
+
|| routeState.last_contract_validation_reason
|
|
3363
|
+
|| "",
|
|
3364
|
+
).trim();
|
|
3365
|
+
const responseContractValidationTargets = uniqueOrderedStrings(
|
|
3366
|
+
ensureArray(routeState.last_followup_response_contract_validation_targets).length
|
|
3367
|
+
? routeState.last_followup_response_contract_validation_targets
|
|
3368
|
+
: ensureArray(routeState.last_contract_validation_targets),
|
|
3369
|
+
normalizeTelegramMentionUsername,
|
|
3370
|
+
);
|
|
3371
|
+
const assignmentValidationStatus = String(
|
|
3372
|
+
routeState.last_followup_assignment_validation_status
|
|
3373
|
+
|| routeState.last_assignment_validation_status
|
|
3374
|
+
|| "",
|
|
3375
|
+
).trim().toLowerCase();
|
|
3376
|
+
const assignmentValidationReason = String(
|
|
3377
|
+
routeState.last_followup_assignment_validation_reason
|
|
3378
|
+
|| routeState.last_assignment_validation_reason
|
|
3379
|
+
|| "",
|
|
3380
|
+
).trim();
|
|
3381
|
+
const assignmentValidationModes = uniqueOrderedStrings(
|
|
3382
|
+
ensureArray(routeState.last_followup_assignment_validation_modes),
|
|
3383
|
+
(value) => String(value || "").trim().toLowerCase(),
|
|
3058
3384
|
);
|
|
3385
|
+
return {
|
|
3386
|
+
action: String(routeState.last_action || "").trim(),
|
|
3387
|
+
reason: String(routeState.last_reason || "").trim(),
|
|
3388
|
+
intent_type: String(routeState.last_intent_type || "").trim(),
|
|
3389
|
+
...buildRunnerValidationAndDeliverySummary({
|
|
3390
|
+
aiReplyPreview: routeState.last_followup_ai_reply_preview,
|
|
3391
|
+
executionContractType,
|
|
3392
|
+
executionContractTargets,
|
|
3393
|
+
nextExpectedResponders,
|
|
3394
|
+
responseContractValidationStatus,
|
|
3395
|
+
responseContractValidationReason,
|
|
3396
|
+
responseContractValidationTargets,
|
|
3397
|
+
assignmentValidationStatus,
|
|
3398
|
+
assignmentValidationReason,
|
|
3399
|
+
assignmentValidationModes,
|
|
3400
|
+
deliveryStatus: routeState.last_followup_delivery_status,
|
|
3401
|
+
archiveStatus: routeState.last_followup_archive_status,
|
|
3402
|
+
transportError: routeState.last_followup_transport_error,
|
|
3403
|
+
archiveError: routeState.last_followup_archive_error,
|
|
3404
|
+
}),
|
|
3405
|
+
workspace_dir: String(routeState.last_workspace_dir || "").trim(),
|
|
3406
|
+
artifact_validation: String(routeState.last_artifact_validation || "").trim(),
|
|
3407
|
+
artifact_paths: ensureArray(routeState.last_artifact_paths).map((item) => String(item || "").trim()).filter(Boolean),
|
|
3408
|
+
artifact_errors: ensureArray(routeState.last_artifact_errors).map((item) => String(item || "").trim()).filter(Boolean),
|
|
3409
|
+
boundary_violations: ensureArray(routeState.last_boundary_violations).map((item) => safeObject(item)),
|
|
3410
|
+
};
|
|
3411
|
+
}
|
|
3412
|
+
|
|
3413
|
+
function buildRunnerStatusLookupWorkItemSummary({
|
|
3414
|
+
relatedRequest,
|
|
3415
|
+
routeState,
|
|
3416
|
+
currentConversationID,
|
|
3417
|
+
}) {
|
|
3418
|
+
const requestRootWorkItem = buildRunnerRequestRootWorkItemSummary(relatedRequest);
|
|
3419
|
+
const safeRouteState = safeObject(routeState);
|
|
3420
|
+
const routeConversationID = String(safeRouteState.last_conversation_id || "").trim();
|
|
3421
|
+
const activeRootWorkItemID = String(safeRouteState.active_root_work_item_id || "").trim();
|
|
3422
|
+
const activeRootWorkItemTitle = String(safeRouteState.active_root_work_item_title || "").trim();
|
|
3423
|
+
const activeRootWorkItemStatus = normalizeRunnerWorkItemStatus(safeRouteState.active_root_work_item_status);
|
|
3424
|
+
const routeRootWorkItemID = String(safeRouteState.last_root_work_item_id || "").trim();
|
|
3425
|
+
const routeRootWorkItemTitle = String(safeRouteState.last_root_work_item_title || "").trim();
|
|
3426
|
+
const routeRootWorkItemStatus = normalizeRunnerWorkItemStatus(safeRouteState.last_root_work_item_status);
|
|
3427
|
+
const routeWorkItemIDs = ensureArray(safeRouteState.last_work_item_ids).map((item) => String(item || "").trim()).filter(Boolean);
|
|
3428
|
+
const routeWorkItemTitles = ensureArray(safeRouteState.last_work_item_titles).map((item) => String(item || "").trim()).filter(Boolean);
|
|
3429
|
+
return {
|
|
3430
|
+
root_work_item: requestRootWorkItem
|
|
3431
|
+
|| (activeRootWorkItemID
|
|
3432
|
+
? {
|
|
3433
|
+
id: activeRootWorkItemID,
|
|
3434
|
+
title: activeRootWorkItemTitle,
|
|
3435
|
+
status: activeRootWorkItemStatus,
|
|
3436
|
+
}
|
|
3437
|
+
: currentConversationID && routeConversationID === currentConversationID && routeRootWorkItemID
|
|
3438
|
+
? {
|
|
3439
|
+
id: routeRootWorkItemID,
|
|
3440
|
+
title: routeRootWorkItemTitle,
|
|
3441
|
+
status: routeRootWorkItemStatus,
|
|
3442
|
+
}
|
|
3443
|
+
: null),
|
|
3444
|
+
route_work_items: currentConversationID && routeConversationID === currentConversationID && (routeWorkItemIDs.length > 0 || routeWorkItemTitles.length > 0)
|
|
3445
|
+
? {
|
|
3446
|
+
ids: routeWorkItemIDs,
|
|
3447
|
+
titles: routeWorkItemTitles,
|
|
3448
|
+
}
|
|
3449
|
+
: null,
|
|
3450
|
+
};
|
|
3059
3451
|
}
|
|
3060
3452
|
|
|
3061
3453
|
function pickRunnerSharedConversationSourceRequest(entries = [], excludeRequestKey = "") {
|
|
@@ -3648,28 +4040,26 @@ async function claimRunnerRequestForHumanComment({
|
|
|
3648
4040
|
|| referencedRequest.conversation_reply_expectation
|
|
3649
4041
|
|| "",
|
|
3650
4042
|
).trim().toLowerCase(),
|
|
3651
|
-
execution_contract_type:
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
execution_contract_actionable: existing
|
|
3655
|
-
|| sharedConversationSource
|
|
3656
|
-
|| referencedRequest
|
|
4043
|
+
execution_contract_type: runnerRequestPreferredExecutionContractType(existing)
|
|
4044
|
+
|| runnerRequestPreferredExecutionContractType(sharedConversationSource)
|
|
4045
|
+
|| runnerRequestPreferredExecutionContractType(referencedRequest),
|
|
4046
|
+
execution_contract_actionable: runnerRequestPreferredExecutionContractActionable(existing)
|
|
4047
|
+
|| runnerRequestPreferredExecutionContractActionable(sharedConversationSource)
|
|
4048
|
+
|| runnerRequestPreferredExecutionContractActionable(referencedRequest),
|
|
3657
4049
|
execution_contract_targets: uniqueOrderedStrings(
|
|
3658
|
-
|
|
3659
|
-
? existing
|
|
3660
|
-
:
|
|
3661
|
-
? sharedConversationSource
|
|
3662
|
-
: referencedRequest
|
|
4050
|
+
runnerRequestPreferredExecutionContractTargets(existing).length
|
|
4051
|
+
? runnerRequestPreferredExecutionContractTargets(existing)
|
|
4052
|
+
: runnerRequestPreferredExecutionContractTargets(sharedConversationSource).length
|
|
4053
|
+
? runnerRequestPreferredExecutionContractTargets(sharedConversationSource)
|
|
4054
|
+
: runnerRequestPreferredExecutionContractTargets(referencedRequest),
|
|
3663
4055
|
normalizeTelegramMentionUsername,
|
|
3664
4056
|
),
|
|
3665
4057
|
next_expected_responders: uniqueOrderedStrings(
|
|
3666
|
-
|
|
3667
|
-
? existing
|
|
3668
|
-
:
|
|
3669
|
-
? sharedConversationSource
|
|
3670
|
-
:
|
|
3671
|
-
? referencedRequest.next_expected_responders
|
|
3672
|
-
: [],
|
|
4058
|
+
runnerRequestPreferredNextExpectedResponders(existing).length
|
|
4059
|
+
? runnerRequestPreferredNextExpectedResponders(existing)
|
|
4060
|
+
: runnerRequestPreferredNextExpectedResponders(sharedConversationSource).length
|
|
4061
|
+
? runnerRequestPreferredNextExpectedResponders(sharedConversationSource)
|
|
4062
|
+
: runnerRequestPreferredNextExpectedResponders(referencedRequest),
|
|
3673
4063
|
normalizeTelegramMentionUsername,
|
|
3674
4064
|
),
|
|
3675
4065
|
normalized_intent: String(preferredNormalizedIntent || existing.normalized_intent || "").trim().toLowerCase(),
|
|
@@ -3718,92 +4108,15 @@ async function claimRunnerRequestForHumanComment({
|
|
|
3718
4108
|
};
|
|
3719
4109
|
}
|
|
3720
4110
|
|
|
3721
|
-
function isActionableRunnerRequestIntent(rawIntent) {
|
|
3722
|
-
const normalizedIntent = String(rawIntent || "").trim().toLowerCase();
|
|
3723
|
-
return Boolean(normalizedIntent) && !isInformationalRunnerRequestIntent(normalizedIntent);
|
|
3724
|
-
}
|
|
3725
|
-
|
|
3726
|
-
function runnerRequestHasConversationContract(requestRaw) {
|
|
3727
|
-
const request = safeObject(requestRaw);
|
|
3728
|
-
return Boolean(
|
|
3729
|
-
String(request.conversation_id || "").trim()
|
|
3730
|
-
|| String(request.conversation_intent_mode || "").trim()
|
|
3731
|
-
|| String(request.conversation_reply_expectation || "").trim()
|
|
3732
|
-
|| ensureArray(request.conversation_participants).length
|
|
3733
|
-
|| ensureArray(request.conversation_initial_responders).length
|
|
3734
|
-
|| ensureArray(request.conversation_allowed_responders).length
|
|
3735
|
-
);
|
|
3736
|
-
}
|
|
3737
|
-
|
|
3738
|
-
function runnerRequestHasCompleteConversationContract(requestRaw) {
|
|
3739
|
-
const request = safeObject(requestRaw);
|
|
3740
|
-
const intentMode = String(request.conversation_intent_mode || "").trim().toLowerCase();
|
|
3741
|
-
const conversationID = String(request.conversation_id || "").trim();
|
|
3742
|
-
const replyExpectation = String(request.conversation_reply_expectation || "").trim().toLowerCase();
|
|
3743
|
-
const participants = ensureArray(request.conversation_participants);
|
|
3744
|
-
const initialResponders = ensureArray(request.conversation_initial_responders);
|
|
3745
|
-
const allowedResponders = ensureArray(request.conversation_allowed_responders);
|
|
3746
|
-
if (!runnerRequestHasConversationContract(request)) {
|
|
3747
|
-
return false;
|
|
3748
|
-
}
|
|
3749
|
-
if (!conversationID || !intentMode || !replyExpectation) {
|
|
3750
|
-
return false;
|
|
3751
|
-
}
|
|
3752
|
-
if (intentMode === "single_bot") {
|
|
3753
|
-
return allowedResponders.length > 0 || participants.length > 0;
|
|
3754
|
-
}
|
|
3755
|
-
return participants.length > 0 && initialResponders.length > 0 && allowedResponders.length > 0;
|
|
3756
|
-
}
|
|
3757
|
-
|
|
3758
|
-
function runnerRequestHasExecutionContract(requestRaw) {
|
|
3759
|
-
const request = safeObject(requestRaw);
|
|
3760
|
-
return Boolean(
|
|
3761
|
-
String(request.execution_contract_type || "").trim()
|
|
3762
|
-
|| request.execution_contract_actionable === true
|
|
3763
|
-
|| ensureArray(request.execution_contract_targets).length
|
|
3764
|
-
|| ensureArray(request.next_expected_responders).length
|
|
3765
|
-
);
|
|
3766
|
-
}
|
|
3767
|
-
|
|
3768
|
-
function runnerRequestHasCompleteExecutionContract(requestRaw) {
|
|
3769
|
-
const request = safeObject(requestRaw);
|
|
3770
|
-
const executionContractType = String(request.execution_contract_type || "").trim().toLowerCase();
|
|
3771
|
-
const executionTargets = ensureArray(request.execution_contract_targets);
|
|
3772
|
-
const nextExpectedResponders = ensureArray(request.next_expected_responders);
|
|
3773
|
-
if (!runnerRequestHasExecutionContract(request)) {
|
|
3774
|
-
return false;
|
|
3775
|
-
}
|
|
3776
|
-
if (!executionContractType) {
|
|
3777
|
-
return false;
|
|
3778
|
-
}
|
|
3779
|
-
if (executionContractType === "delegation") {
|
|
3780
|
-
return executionTargets.length > 0 || nextExpectedResponders.length > 0;
|
|
3781
|
-
}
|
|
3782
|
-
if (executionContractType === "summary_request") {
|
|
3783
|
-
return nextExpectedResponders.length > 0 || executionTargets.length > 0;
|
|
3784
|
-
}
|
|
3785
|
-
return true;
|
|
3786
|
-
}
|
|
3787
|
-
|
|
3788
|
-
function runnerRequestHasContractSignals(requestRaw) {
|
|
3789
|
-
const request = safeObject(requestRaw);
|
|
3790
|
-
return runnerRequestHasConversationContract(request) || runnerRequestHasExecutionContract(request);
|
|
3791
|
-
}
|
|
3792
|
-
|
|
3793
4111
|
function runnerRequestRequiresActionableContract(requestRaw) {
|
|
3794
4112
|
const request = safeObject(requestRaw);
|
|
3795
|
-
const
|
|
3796
|
-
|
|
3797
|
-
const intentMode = String(request.conversation_intent_mode || "").trim().toLowerCase();
|
|
3798
|
-
if (request.execution_contract_actionable === true) {
|
|
4113
|
+
const executionContractType = runnerRequestPreferredExecutionContractType(request);
|
|
4114
|
+
if (runnerRequestPreferredExecutionContractActionable(request) === true) {
|
|
3799
4115
|
return true;
|
|
3800
4116
|
}
|
|
3801
4117
|
if (["delegation", "direct_result", "summary_request", "final_summary"].includes(executionContractType)) {
|
|
3802
4118
|
return true;
|
|
3803
4119
|
}
|
|
3804
|
-
if (intentMode === "single_bot" && replyExpectation === "actionable") {
|
|
3805
|
-
return true;
|
|
3806
|
-
}
|
|
3807
4120
|
return false;
|
|
3808
4121
|
}
|
|
3809
4122
|
|
|
@@ -3836,13 +4149,9 @@ function truncateRunnerWorkItemTitleText(rawText, maxLength = 96) {
|
|
|
3836
4149
|
|
|
3837
4150
|
function buildRunnerRootWorkItemTitle({ selectedRecord, request }) {
|
|
3838
4151
|
const parsed = safeObject(selectedRecord?.parsedArchive);
|
|
3839
|
-
|
|
4152
|
+
void request;
|
|
3840
4153
|
const requestBody = truncateRunnerWorkItemTitleText(parsed.body || "", 84);
|
|
3841
|
-
const prefix =
|
|
3842
|
-
? "Ctxpack request"
|
|
3843
|
-
: intent === "workitem_mutation"
|
|
3844
|
-
? "Work item request"
|
|
3845
|
-
: "Runner request";
|
|
4154
|
+
const prefix = "Runner request";
|
|
3846
4155
|
if (requestBody) {
|
|
3847
4156
|
return `${prefix}: ${requestBody}`;
|
|
3848
4157
|
}
|
|
@@ -4290,6 +4599,52 @@ function buildRunnerRootWorkItemTransitionPath(currentStatusRaw, targetStatusRaw
|
|
|
4290
4599
|
return [];
|
|
4291
4600
|
}
|
|
4292
4601
|
|
|
4602
|
+
function buildRunnerRouteFollowupSnapshotPatch(selectedRecordRaw, resultRaw = {}) {
|
|
4603
|
+
const parsed = safeObject(safeObject(selectedRecordRaw).parsedArchive);
|
|
4604
|
+
const commentKind = String(parsed.kind || "").trim().toLowerCase();
|
|
4605
|
+
if (["telegram_message", "telegram_edited_message"].includes(commentKind)) {
|
|
4606
|
+
return {};
|
|
4607
|
+
}
|
|
4608
|
+
const result = safeObject(resultRaw);
|
|
4609
|
+
return cleanupRunnerStateRecord({
|
|
4610
|
+
last_followup_ai_reply_preview: String(result.ai_reply_preview || "").trim(),
|
|
4611
|
+
last_followup_execution_contract_type: String(result.execution_contract_type || "").trim().toLowerCase(),
|
|
4612
|
+
last_followup_execution_contract_targets: uniqueOrderedStrings(
|
|
4613
|
+
ensureArray(result.execution_contract_targets),
|
|
4614
|
+
normalizeTelegramMentionUsername,
|
|
4615
|
+
),
|
|
4616
|
+
last_followup_next_expected_responders: uniqueOrderedStrings(
|
|
4617
|
+
ensureArray(result.next_expected_responders),
|
|
4618
|
+
normalizeTelegramMentionUsername,
|
|
4619
|
+
),
|
|
4620
|
+
last_followup_normalized_execution_contract_type: String(result.normalized_execution_contract_type || "").trim().toLowerCase(),
|
|
4621
|
+
last_followup_normalized_execution_contract_targets: uniqueOrderedStrings(
|
|
4622
|
+
ensureArray(result.normalized_execution_contract_targets),
|
|
4623
|
+
normalizeTelegramMentionUsername,
|
|
4624
|
+
),
|
|
4625
|
+
last_followup_normalized_execution_next_responders: uniqueOrderedStrings(
|
|
4626
|
+
ensureArray(result.normalized_execution_next_responders),
|
|
4627
|
+
normalizeTelegramMentionUsername,
|
|
4628
|
+
),
|
|
4629
|
+
last_followup_response_contract_validation_status: String(result.response_contract_validation_status || "").trim().toLowerCase(),
|
|
4630
|
+
last_followup_response_contract_validation_reason: String(result.response_contract_validation_reason || "").trim(),
|
|
4631
|
+
last_followup_response_contract_validation_targets: uniqueOrderedStrings(
|
|
4632
|
+
ensureArray(result.response_contract_validation_targets),
|
|
4633
|
+
normalizeTelegramMentionUsername,
|
|
4634
|
+
),
|
|
4635
|
+
last_followup_assignment_validation_status: String(result.assignment_validation_status || "").trim().toLowerCase(),
|
|
4636
|
+
last_followup_assignment_validation_reason: String(result.assignment_validation_reason || "").trim(),
|
|
4637
|
+
last_followup_assignment_validation_modes: uniqueOrderedStrings(
|
|
4638
|
+
ensureArray(result.assignment_validation_modes),
|
|
4639
|
+
(value) => String(value || "").trim().toLowerCase(),
|
|
4640
|
+
),
|
|
4641
|
+
last_followup_delivery_status: String(result.delivery_status || "").trim().toLowerCase(),
|
|
4642
|
+
last_followup_archive_status: String(result.archive_status || "").trim().toLowerCase(),
|
|
4643
|
+
last_followup_transport_error: String(result.transport_error || "").trim(),
|
|
4644
|
+
last_followup_archive_error: String(result.archive_error || "").trim(),
|
|
4645
|
+
});
|
|
4646
|
+
}
|
|
4647
|
+
|
|
4293
4648
|
function buildRunnerRequestRecoveryPatchFromRouteState(currentStateRaw, requestRaw, routeKeyHint = "") {
|
|
4294
4649
|
const currentState = safeObject(currentStateRaw);
|
|
4295
4650
|
const request = safeObject(requestRaw);
|
|
@@ -4334,6 +4689,44 @@ function buildRunnerRequestRecoveryPatchFromRouteState(currentStateRaw, requestR
|
|
|
4334
4689
|
|| routeState.last_root_work_item_status,
|
|
4335
4690
|
);
|
|
4336
4691
|
}
|
|
4692
|
+
const setFollowupStringPatch = (requestField, routeFields = []) => {
|
|
4693
|
+
if (String(request[requestField] || "").trim()) {
|
|
4694
|
+
return;
|
|
4695
|
+
}
|
|
4696
|
+
const recovered = firstNonEmptyString(routeFields.map((field) => routeState[field]));
|
|
4697
|
+
if (recovered) {
|
|
4698
|
+
patch[requestField] = recovered;
|
|
4699
|
+
}
|
|
4700
|
+
};
|
|
4701
|
+
const setFollowupArrayPatch = (requestField, routeFields = [], normalizer = normalizeTelegramMentionUsername) => {
|
|
4702
|
+
if (ensureArray(request[requestField]).length) {
|
|
4703
|
+
return;
|
|
4704
|
+
}
|
|
4705
|
+
for (const field of ensureArray(routeFields)) {
|
|
4706
|
+
const recovered = uniqueOrderedStrings(ensureArray(routeState[field]), normalizer).filter(Boolean);
|
|
4707
|
+
if (recovered.length) {
|
|
4708
|
+
patch[requestField] = recovered;
|
|
4709
|
+
return;
|
|
4710
|
+
}
|
|
4711
|
+
}
|
|
4712
|
+
};
|
|
4713
|
+
setFollowupStringPatch("followup_ai_reply_preview", ["last_followup_ai_reply_preview"]);
|
|
4714
|
+
setFollowupStringPatch("followup_execution_contract_type", ["last_followup_execution_contract_type"]);
|
|
4715
|
+
setFollowupArrayPatch("followup_execution_contract_targets", ["last_followup_execution_contract_targets"]);
|
|
4716
|
+
setFollowupArrayPatch("followup_next_expected_responders", ["last_followup_next_expected_responders"]);
|
|
4717
|
+
setFollowupStringPatch("followup_normalized_execution_contract_type", ["last_followup_normalized_execution_contract_type", "last_normalized_execution_contract_type"]);
|
|
4718
|
+
setFollowupArrayPatch("followup_normalized_execution_contract_targets", ["last_followup_normalized_execution_contract_targets", "last_normalized_execution_contract_targets"]);
|
|
4719
|
+
setFollowupArrayPatch("followup_normalized_execution_next_responders", ["last_followup_normalized_execution_next_responders", "last_normalized_execution_next_responders"]);
|
|
4720
|
+
setFollowupStringPatch("followup_response_contract_validation_status", ["last_followup_response_contract_validation_status", "last_contract_validation_status"]);
|
|
4721
|
+
setFollowupStringPatch("followup_response_contract_validation_reason", ["last_followup_response_contract_validation_reason", "last_contract_validation_reason"]);
|
|
4722
|
+
setFollowupArrayPatch("followup_response_contract_validation_targets", ["last_followup_response_contract_validation_targets", "last_contract_validation_targets"]);
|
|
4723
|
+
setFollowupStringPatch("followup_assignment_validation_status", ["last_followup_assignment_validation_status", "last_assignment_validation_status"]);
|
|
4724
|
+
setFollowupStringPatch("followup_assignment_validation_reason", ["last_followup_assignment_validation_reason", "last_assignment_validation_reason"]);
|
|
4725
|
+
setFollowupArrayPatch("followup_assignment_validation_modes", ["last_followup_assignment_validation_modes"], (value) => String(value || "").trim().toLowerCase());
|
|
4726
|
+
setFollowupStringPatch("followup_delivery_status", ["last_followup_delivery_status"]);
|
|
4727
|
+
setFollowupStringPatch("followup_archive_status", ["last_followup_archive_status"]);
|
|
4728
|
+
setFollowupStringPatch("followup_transport_error", ["last_followup_transport_error"]);
|
|
4729
|
+
setFollowupStringPatch("followup_archive_error", ["last_followup_archive_error"]);
|
|
4337
4730
|
const requestStatus = normalizeRunnerRequestStatus(request.status);
|
|
4338
4731
|
if (!isFinalRunnerRequestStatus(requestStatus)) {
|
|
4339
4732
|
const routeAction = String(routeState.last_action || "").trim().toLowerCase();
|
|
@@ -4693,6 +5086,7 @@ function markRunnerRequestLifecycle({
|
|
|
4693
5086
|
const nowISO = new Date().toISOString();
|
|
4694
5087
|
const commentKind = String(parsed.kind || "").trim().toLowerCase();
|
|
4695
5088
|
const isRootHumanComment = ["telegram_message", "telegram_edited_message"].includes(commentKind);
|
|
5089
|
+
const isFollowupComment = !isRootHumanComment;
|
|
4696
5090
|
const patch = {
|
|
4697
5091
|
conversation_id: conversationID,
|
|
4698
5092
|
conversation_participants: uniqueOrderedStrings(
|
|
@@ -4757,7 +5151,16 @@ function markRunnerRequestLifecycle({
|
|
|
4757
5151
|
ai_reply_generated_at: aiReplyGenerated === true
|
|
4758
5152
|
? firstNonEmptyString([aiReplyGeneratedAt, existing.ai_reply_generated_at, nowISO])
|
|
4759
5153
|
: String(existing.ai_reply_generated_at || "").trim(),
|
|
4760
|
-
ai_reply_preview: String(
|
|
5154
|
+
ai_reply_preview: String(
|
|
5155
|
+
isRootHumanComment
|
|
5156
|
+
? aiReplyPreview || existing.ai_reply_preview || ""
|
|
5157
|
+
: existing.ai_reply_preview || "",
|
|
5158
|
+
).trim(),
|
|
5159
|
+
followup_ai_reply_preview: String(
|
|
5160
|
+
isFollowupComment
|
|
5161
|
+
? aiReplyPreview || existing.followup_ai_reply_preview || ""
|
|
5162
|
+
: existing.followup_ai_reply_preview || "",
|
|
5163
|
+
).trim(),
|
|
4761
5164
|
root_execution_contract_type: String(
|
|
4762
5165
|
isRootHumanComment
|
|
4763
5166
|
? nextExecutionContractType
|
|
@@ -4803,36 +5206,146 @@ function markRunnerRequestLifecycle({
|
|
|
4803
5206
|
normalizeTelegramMentionUsername,
|
|
4804
5207
|
),
|
|
4805
5208
|
response_contract_validation_status: String(
|
|
4806
|
-
|
|
5209
|
+
isRootHumanComment
|
|
5210
|
+
? responseContractValidationStatus || existing.response_contract_validation_status || ""
|
|
5211
|
+
: existing.response_contract_validation_status || "",
|
|
4807
5212
|
).trim().toLowerCase(),
|
|
4808
5213
|
response_contract_validation_reason: String(
|
|
4809
|
-
|
|
5214
|
+
isRootHumanComment
|
|
5215
|
+
? responseContractValidationReason || existing.response_contract_validation_reason || ""
|
|
5216
|
+
: existing.response_contract_validation_reason || "",
|
|
4810
5217
|
).trim(),
|
|
4811
5218
|
response_contract_validation_targets: uniqueOrderedStrings(
|
|
4812
|
-
ensureArray(responseContractValidationTargets).length
|
|
5219
|
+
isRootHumanComment && ensureArray(responseContractValidationTargets).length
|
|
4813
5220
|
? responseContractValidationTargets
|
|
4814
5221
|
: existing.response_contract_validation_targets,
|
|
4815
5222
|
normalizeTelegramMentionUsername,
|
|
4816
5223
|
),
|
|
4817
|
-
|
|
4818
|
-
|
|
5224
|
+
followup_execution_contract_type: String(
|
|
5225
|
+
isFollowupComment
|
|
5226
|
+
? nextExecutionContractType || existing.followup_execution_contract_type || ""
|
|
5227
|
+
: existing.followup_execution_contract_type || "",
|
|
4819
5228
|
).trim().toLowerCase(),
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
? assignmentValidationModes
|
|
4826
|
-
: existing.assignment_validation_modes,
|
|
4827
|
-
(value) => String(value || "").trim().toLowerCase(),
|
|
5229
|
+
followup_execution_contract_targets: uniqueOrderedStrings(
|
|
5230
|
+
isFollowupComment && ensureArray(executionContractTargets).length
|
|
5231
|
+
? executionContractTargets
|
|
5232
|
+
: existing.followup_execution_contract_targets,
|
|
5233
|
+
normalizeTelegramMentionUsername,
|
|
4828
5234
|
),
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
5235
|
+
followup_next_expected_responders: uniqueOrderedStrings(
|
|
5236
|
+
isFollowupComment && ensureArray(nextExpectedResponders).length
|
|
5237
|
+
? nextExpectedResponders
|
|
5238
|
+
: existing.followup_next_expected_responders,
|
|
5239
|
+
normalizeTelegramMentionUsername,
|
|
5240
|
+
),
|
|
5241
|
+
followup_normalized_execution_contract_type: String(
|
|
5242
|
+
isFollowupComment
|
|
5243
|
+
? normalizedExecutionContractType || existing.followup_normalized_execution_contract_type || ""
|
|
5244
|
+
: existing.followup_normalized_execution_contract_type || "",
|
|
5245
|
+
).trim().toLowerCase(),
|
|
5246
|
+
followup_normalized_execution_contract_targets: uniqueOrderedStrings(
|
|
5247
|
+
isFollowupComment && ensureArray(normalizedExecutionContractTargets).length
|
|
5248
|
+
? normalizedExecutionContractTargets
|
|
5249
|
+
: existing.followup_normalized_execution_contract_targets,
|
|
5250
|
+
normalizeTelegramMentionUsername,
|
|
5251
|
+
),
|
|
5252
|
+
followup_normalized_execution_next_responders: uniqueOrderedStrings(
|
|
5253
|
+
isFollowupComment && ensureArray(normalizedExecutionNextResponders).length
|
|
5254
|
+
? normalizedExecutionNextResponders
|
|
5255
|
+
: existing.followup_normalized_execution_next_responders,
|
|
5256
|
+
normalizeTelegramMentionUsername,
|
|
5257
|
+
),
|
|
5258
|
+
followup_response_contract_validation_status: String(
|
|
5259
|
+
isFollowupComment
|
|
5260
|
+
? responseContractValidationStatus || existing.followup_response_contract_validation_status || ""
|
|
5261
|
+
: existing.followup_response_contract_validation_status || "",
|
|
5262
|
+
).trim().toLowerCase(),
|
|
5263
|
+
followup_response_contract_validation_reason: String(
|
|
5264
|
+
isFollowupComment
|
|
5265
|
+
? responseContractValidationReason || existing.followup_response_contract_validation_reason || ""
|
|
5266
|
+
: existing.followup_response_contract_validation_reason || "",
|
|
5267
|
+
).trim(),
|
|
5268
|
+
followup_response_contract_validation_targets: uniqueOrderedStrings(
|
|
5269
|
+
isFollowupComment && ensureArray(responseContractValidationTargets).length
|
|
5270
|
+
? responseContractValidationTargets
|
|
5271
|
+
: existing.followup_response_contract_validation_targets,
|
|
5272
|
+
normalizeTelegramMentionUsername,
|
|
5273
|
+
),
|
|
5274
|
+
assignment_validation_status: String(
|
|
5275
|
+
isRootHumanComment
|
|
5276
|
+
? assignmentValidationStatus || existing.assignment_validation_status || ""
|
|
5277
|
+
: existing.assignment_validation_status || "",
|
|
5278
|
+
).trim().toLowerCase(),
|
|
5279
|
+
assignment_validation_reason: String(
|
|
5280
|
+
isRootHumanComment
|
|
5281
|
+
? assignmentValidationReason || existing.assignment_validation_reason || ""
|
|
5282
|
+
: existing.assignment_validation_reason || "",
|
|
5283
|
+
).trim(),
|
|
5284
|
+
assignment_validation_modes: uniqueOrderedStrings(
|
|
5285
|
+
isRootHumanComment && ensureArray(assignmentValidationModes).length
|
|
5286
|
+
? assignmentValidationModes
|
|
5287
|
+
: existing.assignment_validation_modes,
|
|
5288
|
+
(value) => String(value || "").trim().toLowerCase(),
|
|
5289
|
+
),
|
|
5290
|
+
followup_assignment_validation_status: String(
|
|
5291
|
+
isFollowupComment
|
|
5292
|
+
? assignmentValidationStatus || existing.followup_assignment_validation_status || ""
|
|
5293
|
+
: existing.followup_assignment_validation_status || "",
|
|
5294
|
+
).trim().toLowerCase(),
|
|
5295
|
+
followup_assignment_validation_reason: String(
|
|
5296
|
+
isFollowupComment
|
|
5297
|
+
? assignmentValidationReason || existing.followup_assignment_validation_reason || ""
|
|
5298
|
+
: existing.followup_assignment_validation_reason || "",
|
|
5299
|
+
).trim(),
|
|
5300
|
+
followup_assignment_validation_modes: uniqueOrderedStrings(
|
|
5301
|
+
isFollowupComment && ensureArray(assignmentValidationModes).length
|
|
5302
|
+
? assignmentValidationModes
|
|
5303
|
+
: existing.followup_assignment_validation_modes,
|
|
5304
|
+
(value) => String(value || "").trim().toLowerCase(),
|
|
5305
|
+
),
|
|
5306
|
+
delivery_status: String(
|
|
5307
|
+
isRootHumanComment
|
|
5308
|
+
? deliveryStatus || existing.delivery_status || ""
|
|
5309
|
+
: existing.delivery_status || "",
|
|
5310
|
+
).trim().toLowerCase(),
|
|
5311
|
+
archive_status: String(
|
|
5312
|
+
isRootHumanComment
|
|
5313
|
+
? archiveStatus || existing.archive_status || ""
|
|
5314
|
+
: existing.archive_status || "",
|
|
5315
|
+
).trim().toLowerCase(),
|
|
5316
|
+
transport_error: String(
|
|
5317
|
+
isRootHumanComment
|
|
5318
|
+
? transportError || existing.transport_error || ""
|
|
5319
|
+
: existing.transport_error || "",
|
|
5320
|
+
).trim(),
|
|
5321
|
+
archive_error: String(
|
|
5322
|
+
isRootHumanComment
|
|
5323
|
+
? archiveError || existing.archive_error || ""
|
|
5324
|
+
: existing.archive_error || "",
|
|
5325
|
+
).trim(),
|
|
5326
|
+
followup_delivery_status: String(
|
|
5327
|
+
isFollowupComment
|
|
5328
|
+
? deliveryStatus || existing.followup_delivery_status || ""
|
|
5329
|
+
: existing.followup_delivery_status || "",
|
|
5330
|
+
).trim().toLowerCase(),
|
|
5331
|
+
followup_archive_status: String(
|
|
5332
|
+
isFollowupComment
|
|
5333
|
+
? archiveStatus || existing.followup_archive_status || ""
|
|
5334
|
+
: existing.followup_archive_status || "",
|
|
5335
|
+
).trim().toLowerCase(),
|
|
5336
|
+
followup_transport_error: String(
|
|
5337
|
+
isFollowupComment
|
|
5338
|
+
? transportError || existing.followup_transport_error || ""
|
|
5339
|
+
: existing.followup_transport_error || "",
|
|
5340
|
+
).trim(),
|
|
5341
|
+
followup_archive_error: String(
|
|
5342
|
+
isFollowupComment
|
|
5343
|
+
? archiveError || existing.followup_archive_error || ""
|
|
5344
|
+
: existing.followup_archive_error || "",
|
|
5345
|
+
).trim(),
|
|
5346
|
+
normalized_intent: nextNormalizedIntent,
|
|
5347
|
+
status: nextStatus,
|
|
5348
|
+
started_at: firstNonEmptyString([existing.started_at, nowISO]),
|
|
4836
5349
|
completed_at: nextStatus === "completed" ? nowISO : String(existing.completed_at || "").trim(),
|
|
4837
5350
|
closed_at: (nextStatus === "closed" || nextStatus === "expired" || nextStatus === "loop_closed")
|
|
4838
5351
|
? nowISO
|
|
@@ -5046,23 +5559,55 @@ function mergeRunnerRequestForServerHydration(localEntryRaw, serverEntryRaw) {
|
|
|
5046
5559
|
preserveLocalStringWhenServerBlank("conversation_summary_bot");
|
|
5047
5560
|
preserveLocalStringWhenServerBlank("conversation_reply_expectation");
|
|
5048
5561
|
preserveLocalStringWhenServerBlank("execution_contract_type");
|
|
5562
|
+
preserveLocalStringWhenServerBlank("normalized_execution_contract_type");
|
|
5563
|
+
preserveLocalStringWhenServerBlank("ai_reply_generated_at");
|
|
5564
|
+
preserveLocalStringWhenServerBlank("ai_reply_preview");
|
|
5049
5565
|
preserveLocalStringWhenServerBlank("root_work_item_id");
|
|
5050
5566
|
preserveLocalStringWhenServerBlank("root_work_item_title");
|
|
5051
5567
|
preserveLocalStringWhenServerBlank("root_work_item_status");
|
|
5052
5568
|
preserveLocalStringWhenServerBlank("root_thread_id");
|
|
5053
5569
|
preserveLocalStringWhenServerBlank("root_work_item_created_at");
|
|
5054
5570
|
preserveLocalStringWhenServerBlank("root_work_item_last_error");
|
|
5571
|
+
preserveLocalStringWhenServerBlank("root_execution_contract_type");
|
|
5572
|
+
preserveLocalStringWhenServerBlank("root_ai_reply_preview");
|
|
5573
|
+
preserveLocalStringWhenServerBlank("root_response_contract_validation_status");
|
|
5574
|
+
preserveLocalStringWhenServerBlank("root_response_contract_validation_reason");
|
|
5575
|
+
preserveLocalStringWhenServerBlank("followup_ai_reply_preview");
|
|
5576
|
+
preserveLocalStringWhenServerBlank("followup_execution_contract_type");
|
|
5577
|
+
preserveLocalStringWhenServerBlank("followup_normalized_execution_contract_type");
|
|
5578
|
+
preserveLocalStringWhenServerBlank("followup_response_contract_validation_status");
|
|
5579
|
+
preserveLocalStringWhenServerBlank("followup_response_contract_validation_reason");
|
|
5580
|
+
preserveLocalStringWhenServerBlank("followup_assignment_validation_status");
|
|
5581
|
+
preserveLocalStringWhenServerBlank("followup_assignment_validation_reason");
|
|
5582
|
+
preserveLocalStringWhenServerBlank("followup_delivery_status");
|
|
5583
|
+
preserveLocalStringWhenServerBlank("followup_archive_status");
|
|
5584
|
+
preserveLocalStringWhenServerBlank("followup_transport_error");
|
|
5585
|
+
preserveLocalStringWhenServerBlank("followup_archive_error");
|
|
5055
5586
|
preserveLocalArrayWhenServerEmpty("conversation_participants");
|
|
5056
5587
|
preserveLocalArrayWhenServerEmpty("conversation_initial_responders");
|
|
5057
5588
|
preserveLocalArrayWhenServerEmpty("conversation_allowed_responders");
|
|
5058
5589
|
preserveLocalArrayWhenServerEmpty("execution_contract_targets");
|
|
5059
5590
|
preserveLocalArrayWhenServerEmpty("next_expected_responders");
|
|
5591
|
+
preserveLocalArrayWhenServerEmpty("normalized_execution_contract_targets");
|
|
5592
|
+
preserveLocalArrayWhenServerEmpty("normalized_execution_next_responders");
|
|
5593
|
+
preserveLocalArrayWhenServerEmpty("root_execution_contract_targets");
|
|
5594
|
+
preserveLocalArrayWhenServerEmpty("root_next_expected_responders");
|
|
5595
|
+
preserveLocalArrayWhenServerEmpty("root_response_contract_validation_targets");
|
|
5596
|
+
preserveLocalArrayWhenServerEmpty("followup_execution_contract_targets");
|
|
5597
|
+
preserveLocalArrayWhenServerEmpty("followup_next_expected_responders");
|
|
5598
|
+
preserveLocalArrayWhenServerEmpty("followup_normalized_execution_contract_targets");
|
|
5599
|
+
preserveLocalArrayWhenServerEmpty("followup_normalized_execution_next_responders");
|
|
5600
|
+
preserveLocalArrayWhenServerEmpty("followup_response_contract_validation_targets");
|
|
5601
|
+
preserveLocalArrayWhenServerEmpty("followup_assignment_validation_modes");
|
|
5060
5602
|
if (serverEntry.conversation_allow_bot_to_bot !== true && localEntry.conversation_allow_bot_to_bot === true) {
|
|
5061
5603
|
merged.conversation_allow_bot_to_bot = true;
|
|
5062
5604
|
}
|
|
5063
5605
|
if (serverEntry.execution_contract_actionable !== true && localEntry.execution_contract_actionable === true) {
|
|
5064
5606
|
merged.execution_contract_actionable = true;
|
|
5065
5607
|
}
|
|
5608
|
+
if (serverEntry.ai_reply_generated !== true && localEntry.ai_reply_generated === true) {
|
|
5609
|
+
merged.ai_reply_generated = true;
|
|
5610
|
+
}
|
|
5066
5611
|
const localStatus = normalizeRunnerRequestStatus(localEntry.status);
|
|
5067
5612
|
const serverStatus = normalizeRunnerRequestStatus(serverEntry.status);
|
|
5068
5613
|
if (isFinalRunnerRequestStatus(localStatus) && !isFinalRunnerRequestStatus(serverStatus)) {
|
|
@@ -7450,17 +7995,26 @@ function summarizeRunnerRequestForStatusLookup(entryRaw) {
|
|
|
7450
7995
|
updated_at: String(entry.updated_at || "").trim(),
|
|
7451
7996
|
source_message_id: intFromRawAllowZero(entry.source_message_id, 0) || undefined,
|
|
7452
7997
|
last_source_message_id: intFromRawAllowZero(entry.last_source_message_id, 0) || undefined,
|
|
7998
|
+
...buildRunnerValidationAndDeliverySummary({
|
|
7999
|
+
aiReplyPreview: runnerRequestPreferredAIReplyPreview(entry),
|
|
8000
|
+
executionContractType: runnerRequestPreferredExecutionContractType(entry),
|
|
8001
|
+
executionContractTargets: runnerRequestPreferredExecutionContractTargets(entry),
|
|
8002
|
+
nextExpectedResponders: runnerRequestPreferredNextExpectedResponders(entry),
|
|
8003
|
+
responseContractValidationStatus: runnerRequestPreferredResponseContractValidationStatus(entry),
|
|
8004
|
+
responseContractValidationReason: runnerRequestPreferredResponseContractValidationReason(entry),
|
|
8005
|
+
responseContractValidationTargets: runnerRequestPreferredResponseContractValidationTargets(entry),
|
|
8006
|
+
assignmentValidationStatus: runnerRequestPreferredAssignmentValidationStatus(entry),
|
|
8007
|
+
assignmentValidationReason: runnerRequestPreferredAssignmentValidationReason(entry),
|
|
8008
|
+
assignmentValidationModes: runnerRequestPreferredAssignmentValidationModes(entry),
|
|
8009
|
+
deliveryStatus: runnerRequestPreferredDeliveryStatus(entry),
|
|
8010
|
+
archiveStatus: runnerRequestPreferredArchiveStatus(entry),
|
|
8011
|
+
transportError: runnerRequestPreferredTransportError(entry),
|
|
8012
|
+
archiveError: runnerRequestPreferredArchiveError(entry),
|
|
8013
|
+
}),
|
|
7453
8014
|
selected_bot_usernames: ensureArray(entry.selected_bot_usernames)
|
|
7454
8015
|
.map((value) => normalizeTelegramMentionUsername(value))
|
|
7455
8016
|
.filter(Boolean),
|
|
7456
|
-
root_work_item:
|
|
7457
|
-
? {
|
|
7458
|
-
id: String(entry.root_work_item_id || "").trim(),
|
|
7459
|
-
title: String(entry.root_work_item_title || "").trim(),
|
|
7460
|
-
status: normalizeRunnerWorkItemStatus(entry.root_work_item_status),
|
|
7461
|
-
thread_id: String(entry.root_thread_id || "").trim(),
|
|
7462
|
-
}
|
|
7463
|
-
: null,
|
|
8017
|
+
root_work_item: buildRunnerRequestRootWorkItemSummary(entry),
|
|
7464
8018
|
};
|
|
7465
8019
|
}
|
|
7466
8020
|
|
|
@@ -7519,6 +8073,150 @@ function pickPreferredStatusLookupRequest(entries = []) {
|
|
|
7519
8073
|
return candidates[0];
|
|
7520
8074
|
}
|
|
7521
8075
|
|
|
8076
|
+
function resolveRunnerStatusLookupRequests({
|
|
8077
|
+
runnerState,
|
|
8078
|
+
route,
|
|
8079
|
+
routeKey,
|
|
8080
|
+
selfBotUsername,
|
|
8081
|
+
currentMessageID,
|
|
8082
|
+
currentConversationID,
|
|
8083
|
+
currentChatID,
|
|
8084
|
+
activeRequestKey,
|
|
8085
|
+
replyChainContext,
|
|
8086
|
+
}) {
|
|
8087
|
+
const requestMatchesCurrentRoute = (entry) => requestEligibleForStatusLookup(
|
|
8088
|
+
entry,
|
|
8089
|
+
routeKey,
|
|
8090
|
+
selfBotUsername,
|
|
8091
|
+
currentMessageID,
|
|
8092
|
+
);
|
|
8093
|
+
const referencedRequestCandidate = safeObject(replyChainContext?.referencedRequest);
|
|
8094
|
+
const selectors = currentConversationID
|
|
8095
|
+
? { conversationID: currentConversationID, chatID: currentChatID }
|
|
8096
|
+
: { chatID: currentChatID };
|
|
8097
|
+
let scopedRequests = findRunnerRequestsForScope(runnerState, route, selectors);
|
|
8098
|
+
if (!scopedRequests.length && currentConversationID) {
|
|
8099
|
+
scopedRequests = findRunnerRequestsForScope(runnerState, route, { chatID: currentChatID });
|
|
8100
|
+
}
|
|
8101
|
+
if (!scopedRequests.length && activeRequestKey) {
|
|
8102
|
+
scopedRequests = findRunnerRequestsForScope(runnerState, route, { requestKey: activeRequestKey });
|
|
8103
|
+
}
|
|
8104
|
+
const statusLookupCandidates = scopedRequests.filter(requestMatchesCurrentRoute);
|
|
8105
|
+
if (
|
|
8106
|
+
Object.keys(referencedRequestCandidate).length > 0
|
|
8107
|
+
&& requestMatchesCurrentRoute(referencedRequestCandidate)
|
|
8108
|
+
&& !statusLookupCandidates.some(
|
|
8109
|
+
(entry) => String(safeObject(entry).request_key || "").trim() === String(referencedRequestCandidate.request_key || "").trim(),
|
|
8110
|
+
)
|
|
8111
|
+
) {
|
|
8112
|
+
statusLookupCandidates.push(referencedRequestCandidate);
|
|
8113
|
+
}
|
|
8114
|
+
return {
|
|
8115
|
+
related_active_request: statusLookupCandidates
|
|
8116
|
+
.filter((entry) => isActiveRunnerRequestStatus(entry.status))[0] || null,
|
|
8117
|
+
related_request: pickPreferredStatusLookupRequest(statusLookupCandidates),
|
|
8118
|
+
};
|
|
8119
|
+
}
|
|
8120
|
+
|
|
8121
|
+
function buildRunnerShowLastRunPayload(lastRunSummaryRaw) {
|
|
8122
|
+
const lastRunSummary = safeObject(lastRunSummaryRaw);
|
|
8123
|
+
return {
|
|
8124
|
+
action: lastRunSummary.action || "-",
|
|
8125
|
+
reason: lastRunSummary.reason || "-",
|
|
8126
|
+
intent_type: lastRunSummary.intent_type || "-",
|
|
8127
|
+
ai_reply_preview: lastRunSummary.ai_reply_preview || "-",
|
|
8128
|
+
execution_contract_type: lastRunSummary.execution_contract_type || "-",
|
|
8129
|
+
execution_contract_targets: ensureArray(lastRunSummary.execution_contract_targets),
|
|
8130
|
+
next_expected_responders: ensureArray(lastRunSummary.next_expected_responders),
|
|
8131
|
+
response_contract_validation_status: lastRunSummary.response_contract_validation_status || "-",
|
|
8132
|
+
response_contract_validation_reason: lastRunSummary.response_contract_validation_reason || "-",
|
|
8133
|
+
response_contract_validation_targets: ensureArray(lastRunSummary.response_contract_validation_targets),
|
|
8134
|
+
assignment_validation_status: lastRunSummary.assignment_validation_status || "-",
|
|
8135
|
+
assignment_validation_reason: lastRunSummary.assignment_validation_reason || "-",
|
|
8136
|
+
assignment_validation_modes: ensureArray(lastRunSummary.assignment_validation_modes),
|
|
8137
|
+
delivery_status: lastRunSummary.delivery_status || "-",
|
|
8138
|
+
archive_status: lastRunSummary.archive_status || "-",
|
|
8139
|
+
transport_error: lastRunSummary.transport_error || "-",
|
|
8140
|
+
archive_error: lastRunSummary.archive_error || "-",
|
|
8141
|
+
workspace_dir: lastRunSummary.workspace_dir || "-",
|
|
8142
|
+
artifact_validation: lastRunSummary.artifact_validation || "-",
|
|
8143
|
+
artifact_paths: ensureArray(lastRunSummary.artifact_paths),
|
|
8144
|
+
artifact_errors: ensureArray(lastRunSummary.artifact_errors),
|
|
8145
|
+
boundary_violations: ensureArray(lastRunSummary.boundary_violations),
|
|
8146
|
+
};
|
|
8147
|
+
}
|
|
8148
|
+
|
|
8149
|
+
function buildRunnerShowActiveExecutionPayload(activeExecutionStateRaw) {
|
|
8150
|
+
const activeExecutionState = safeObject(activeExecutionStateRaw);
|
|
8151
|
+
return {
|
|
8152
|
+
active: activeExecutionState.active === true,
|
|
8153
|
+
stale: activeExecutionState.stale === true,
|
|
8154
|
+
stuck: activeExecutionState.stuck === true,
|
|
8155
|
+
comment_id: String(activeExecutionState.commentID || "").trim(),
|
|
8156
|
+
source_message_id: intFromRawAllowZero(activeExecutionState.sourceMessageID, 0),
|
|
8157
|
+
started_at: String(activeExecutionState.startedAt || "").trim(),
|
|
8158
|
+
age_seconds: intFromRawAllowZero(activeExecutionState.ageSeconds, 0),
|
|
8159
|
+
warning: String(activeExecutionState.warning || "").trim(),
|
|
8160
|
+
};
|
|
8161
|
+
}
|
|
8162
|
+
|
|
8163
|
+
function buildRunnerShowResolvedContext({
|
|
8164
|
+
normalizedRoute,
|
|
8165
|
+
diagnostics,
|
|
8166
|
+
envConfig,
|
|
8167
|
+
resolvedServerBotName,
|
|
8168
|
+
botNameSource,
|
|
8169
|
+
}) {
|
|
8170
|
+
return {
|
|
8171
|
+
resolved_server_identity: {
|
|
8172
|
+
server_bot_name: resolvedServerBotName,
|
|
8173
|
+
server_bot_name_source: botNameSource,
|
|
8174
|
+
server_bot_id: normalizedRoute.botID || "-",
|
|
8175
|
+
telegram_entry_file: String(envConfig?.entryFilePath || "").trim() || "-",
|
|
8176
|
+
},
|
|
8177
|
+
resolved_destination: {
|
|
8178
|
+
destination_label: String(normalizedRoute.destinationLabel || "").trim() || "-",
|
|
8179
|
+
destination_id: String(normalizedRoute.destinationID || "").trim() || "-",
|
|
8180
|
+
destination_source: "route_config",
|
|
8181
|
+
},
|
|
8182
|
+
workspace_mapping: {
|
|
8183
|
+
workspace_dir: diagnostics.workspaceDir || "-",
|
|
8184
|
+
workspace_source: diagnostics.workspaceSource || "-",
|
|
8185
|
+
},
|
|
8186
|
+
execution_profile: {
|
|
8187
|
+
route_role: normalizedRoute.role || "-",
|
|
8188
|
+
role_profile_name: diagnostics.roleProfileName || "-",
|
|
8189
|
+
client: String(diagnostics.roleProfile?.client || "").trim() || "-",
|
|
8190
|
+
model: String(diagnostics.roleProfile?.model || "").trim() || "-",
|
|
8191
|
+
permission_mode: String(diagnostics.roleProfile?.permissionMode || "").trim() || "-",
|
|
8192
|
+
reasoning_effort: String(diagnostics.roleProfile?.reasoningEffort || "").trim() || "-",
|
|
8193
|
+
},
|
|
8194
|
+
};
|
|
8195
|
+
}
|
|
8196
|
+
|
|
8197
|
+
function buildRunnerStatusReplyChainResolution(replyChainContextRaw) {
|
|
8198
|
+
const replyChainContext = safeObject(replyChainContextRaw);
|
|
8199
|
+
return {
|
|
8200
|
+
reason: String(replyChainContext.reason || "").trim(),
|
|
8201
|
+
reply_to_message_id: intFromRawAllowZero(replyChainContext.replyToMessageID, 0) || undefined,
|
|
8202
|
+
anchor_message_id: intFromRawAllowZero(replyChainContext.anchorMessageID, 0) || undefined,
|
|
8203
|
+
};
|
|
8204
|
+
}
|
|
8205
|
+
|
|
8206
|
+
function buildRunnerStatusActiveExecutionSummary(activeExecutionRaw, selfBusyFiltered = false) {
|
|
8207
|
+
const activeExecution = safeObject(activeExecutionRaw);
|
|
8208
|
+
if (!(activeExecution.active && !selfBusyFiltered)) {
|
|
8209
|
+
return null;
|
|
8210
|
+
}
|
|
8211
|
+
return {
|
|
8212
|
+
started_at: String(activeExecution.startedAt || "").trim(),
|
|
8213
|
+
age_seconds: intFromRawAllowZero(activeExecution.ageSeconds, 0),
|
|
8214
|
+
stale: activeExecution.stale === true,
|
|
8215
|
+
stuck: activeExecution.stuck === true,
|
|
8216
|
+
warning: String(activeExecution.warning || "").trim(),
|
|
8217
|
+
};
|
|
8218
|
+
}
|
|
8219
|
+
|
|
7522
8220
|
function buildRunnerStatusQueryLookup({ route, routeState, selectedRecord, runnerStateOverride = null }) {
|
|
7523
8221
|
const parsed = safeObject(selectedRecord?.parsedArchive);
|
|
7524
8222
|
const currentMessageID = intFromRawAllowZero(parsed.messageID, 0);
|
|
@@ -7548,109 +8246,156 @@ function buildRunnerStatusQueryLookup({ route, routeState, selectedRecord, runne
|
|
|
7548
8246
|
const replyChainContext = resolveRunnerReplyChainConversationContext(runnerState, route, selectedRecord);
|
|
7549
8247
|
const currentConversationID = String(parsed.conversationID || replyChainContext.conversationID || "").trim();
|
|
7550
8248
|
const activeRequestKey = String(safeObject(routeState).active_request_key || "").trim();
|
|
7551
|
-
const
|
|
7552
|
-
|
|
8249
|
+
const { related_active_request: relatedActiveRequest, related_request: relatedRequest } = resolveRunnerStatusLookupRequests({
|
|
8250
|
+
runnerState,
|
|
8251
|
+
route,
|
|
7553
8252
|
routeKey,
|
|
7554
8253
|
selfBotUsername,
|
|
7555
8254
|
currentMessageID,
|
|
7556
|
-
|
|
7557
|
-
|
|
7558
|
-
|
|
7559
|
-
|
|
7560
|
-
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
|
|
7565
|
-
|
|
7566
|
-
}
|
|
7567
|
-
if (!scopedRequests.length && activeRequestKey) {
|
|
7568
|
-
scopedRequests = findRunnerRequestsForScope(runnerState, route, { requestKey: activeRequestKey });
|
|
7569
|
-
}
|
|
7570
|
-
const eligibleScopedRequests = scopedRequests.filter(requestMatchesCurrentRoute);
|
|
7571
|
-
const statusLookupCandidates = [...eligibleScopedRequests];
|
|
7572
|
-
if (
|
|
7573
|
-
Object.keys(referencedRequestCandidate).length > 0
|
|
7574
|
-
&& requestMatchesCurrentRoute(referencedRequestCandidate)
|
|
7575
|
-
&& !statusLookupCandidates.some(
|
|
7576
|
-
(entry) => String(safeObject(entry).request_key || "").trim() === String(referencedRequestCandidate.request_key || "").trim(),
|
|
7577
|
-
)
|
|
7578
|
-
) {
|
|
7579
|
-
statusLookupCandidates.push(referencedRequestCandidate);
|
|
7580
|
-
}
|
|
7581
|
-
relatedActiveRequest = statusLookupCandidates
|
|
7582
|
-
.filter((entry) => isActiveRunnerRequestStatus(entry.status))[0] || null;
|
|
7583
|
-
relatedRequest = pickPreferredStatusLookupRequest(statusLookupCandidates);
|
|
7584
|
-
const lastAction = String(safeObject(routeState).last_action || "").trim();
|
|
7585
|
-
const lastReason = String(safeObject(routeState).last_reason || "").trim();
|
|
7586
|
-
const lastIntentType = String(safeObject(routeState).last_intent_type || "").trim();
|
|
7587
|
-
const routeConversationID = String(safeObject(routeState).last_conversation_id || "").trim();
|
|
7588
|
-
const activeRootWorkItemID = String(safeObject(routeState).active_root_work_item_id || "").trim();
|
|
7589
|
-
const activeRootWorkItemTitle = String(safeObject(routeState).active_root_work_item_title || "").trim();
|
|
7590
|
-
const activeRootWorkItemStatus = normalizeRunnerWorkItemStatus(safeObject(routeState).active_root_work_item_status);
|
|
7591
|
-
const routeRootWorkItemID = String(safeObject(routeState).last_root_work_item_id || "").trim();
|
|
7592
|
-
const routeRootWorkItemTitle = String(safeObject(routeState).last_root_work_item_title || "").trim();
|
|
7593
|
-
const routeRootWorkItemStatus = normalizeRunnerWorkItemStatus(safeObject(routeState).last_root_work_item_status);
|
|
7594
|
-
const routeWorkItemIDs = ensureArray(safeObject(routeState).last_work_item_ids).map((item) => String(item || "").trim()).filter(Boolean);
|
|
7595
|
-
const routeWorkItemTitles = ensureArray(safeObject(routeState).last_work_item_titles).map((item) => String(item || "").trim()).filter(Boolean);
|
|
7596
|
-
const requestRootWorkItem = String(safeObject(relatedRequest).root_work_item_id || "").trim()
|
|
7597
|
-
? {
|
|
7598
|
-
id: String(safeObject(relatedRequest).root_work_item_id || "").trim(),
|
|
7599
|
-
title: String(safeObject(relatedRequest).root_work_item_title || "").trim(),
|
|
7600
|
-
status: normalizeRunnerWorkItemStatus(safeObject(relatedRequest).root_work_item_status),
|
|
7601
|
-
thread_id: String(safeObject(relatedRequest).root_thread_id || "").trim(),
|
|
7602
|
-
}
|
|
7603
|
-
: null;
|
|
8255
|
+
currentConversationID,
|
|
8256
|
+
currentChatID,
|
|
8257
|
+
activeRequestKey,
|
|
8258
|
+
replyChainContext,
|
|
8259
|
+
});
|
|
8260
|
+
const lastRouteResult = buildRunnerRouteLastResultSummary(routeState);
|
|
8261
|
+
const workItemSummary = buildRunnerStatusLookupWorkItemSummary({
|
|
8262
|
+
relatedRequest,
|
|
8263
|
+
routeState,
|
|
8264
|
+
currentConversationID,
|
|
8265
|
+
});
|
|
7604
8266
|
return {
|
|
7605
8267
|
kind: "runner_status",
|
|
7606
8268
|
status: (!selfBusyFiltered && activeExecution.active) || relatedActiveRequest
|
|
7607
8269
|
? "running"
|
|
7608
8270
|
: String(safeObject(relatedRequest).status || "").trim() || "idle",
|
|
7609
8271
|
resolved_conversation_id: currentConversationID,
|
|
7610
|
-
reply_chain_resolution:
|
|
7611
|
-
reason: String(replyChainContext.reason || "").trim(),
|
|
7612
|
-
reply_to_message_id: intFromRawAllowZero(replyChainContext.replyToMessageID, 0) || undefined,
|
|
7613
|
-
anchor_message_id: intFromRawAllowZero(replyChainContext.anchorMessageID, 0) || undefined,
|
|
7614
|
-
},
|
|
8272
|
+
reply_chain_resolution: buildRunnerStatusReplyChainResolution(replyChainContext),
|
|
7615
8273
|
self_busy_filtered: selfBusyFiltered,
|
|
7616
|
-
active_execution: activeExecution
|
|
7617
|
-
? {
|
|
7618
|
-
started_at: String(activeExecution.startedAt || "").trim(),
|
|
7619
|
-
age_seconds: intFromRawAllowZero(activeExecution.ageSeconds, 0),
|
|
7620
|
-
stale: activeExecution.stale === true,
|
|
7621
|
-
stuck: activeExecution.stuck === true,
|
|
7622
|
-
warning: String(activeExecution.warning || "").trim(),
|
|
7623
|
-
}
|
|
7624
|
-
: null,
|
|
8274
|
+
active_execution: buildRunnerStatusActiveExecutionSummary(activeExecution, selfBusyFiltered),
|
|
7625
8275
|
related_active_request: relatedActiveRequest ? summarizeRunnerRequestForStatusLookup(relatedActiveRequest) : null,
|
|
7626
8276
|
related_request: relatedRequest ? summarizeRunnerRequestForStatusLookup(relatedRequest) : null,
|
|
7627
|
-
root_work_item:
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
|
|
7651
|
-
|
|
7652
|
-
|
|
8277
|
+
root_work_item: workItemSummary.root_work_item,
|
|
8278
|
+
route_work_items: workItemSummary.route_work_items,
|
|
8279
|
+
last_route_result: lastRouteResult,
|
|
8280
|
+
};
|
|
8281
|
+
}
|
|
8282
|
+
|
|
8283
|
+
function buildProjectWorkspaceLookupResponse({ route, executionPlan, executionOverride }) {
|
|
8284
|
+
const workspace = resolveProjectWorkspaceBindingSummary(
|
|
8285
|
+
route?.projectID,
|
|
8286
|
+
executionPlan?.workspaceDir || route?.workspaceDir || "",
|
|
8287
|
+
);
|
|
8288
|
+
return buildLookupOnlyInformationalReply("project.workspace", {
|
|
8289
|
+
...workspace,
|
|
8290
|
+
}, executionOverride);
|
|
8291
|
+
}
|
|
8292
|
+
|
|
8293
|
+
function buildSmallTalkLookupResponse({ route, messageText, executionOverride }) {
|
|
8294
|
+
return buildLookupOnlyInformationalReply("small_talk", {
|
|
8295
|
+
intent_type: "small_talk",
|
|
8296
|
+
user_message: messageText,
|
|
8297
|
+
bot_name: firstNonEmptyString([route?.botName, route?.serverBotName, route?.server_bot_name, route?.name]),
|
|
8298
|
+
bot_role: String(route?.role || route?.roleProfile || "").trim(),
|
|
8299
|
+
}, executionOverride);
|
|
8300
|
+
}
|
|
8301
|
+
|
|
8302
|
+
function buildProjectBotRolesLookupResponse({ route, executionOverride }) {
|
|
8303
|
+
const payload = buildProjectBotRolesPayload({
|
|
8304
|
+
projectID: route?.projectID,
|
|
8305
|
+
provider: route?.provider,
|
|
8306
|
+
destinationID: route?.destinationID,
|
|
8307
|
+
destinationLabel: route?.destinationLabel,
|
|
8308
|
+
});
|
|
8309
|
+
return buildLookupOnlyInformationalReply("project.bot_roles", {
|
|
8310
|
+
...payload,
|
|
8311
|
+
}, executionOverride);
|
|
8312
|
+
}
|
|
8313
|
+
|
|
8314
|
+
async function buildRunnerStatusLookupOnlyResponse({
|
|
8315
|
+
route,
|
|
8316
|
+
routeState,
|
|
8317
|
+
selectedRecord,
|
|
8318
|
+
runtime,
|
|
8319
|
+
executionOverride,
|
|
8320
|
+
}) {
|
|
8321
|
+
let hydratedRunnerState = null;
|
|
8322
|
+
try {
|
|
8323
|
+
hydratedRunnerState = await hydrateRunnerRequestLedgerFromServer({
|
|
8324
|
+
normalizedRoute: route,
|
|
8325
|
+
runtime,
|
|
8326
|
+
});
|
|
8327
|
+
} catch {}
|
|
8328
|
+
const lookup = buildRunnerStatusQueryLookup({
|
|
8329
|
+
route,
|
|
8330
|
+
routeState,
|
|
8331
|
+
selectedRecord,
|
|
8332
|
+
runnerStateOverride: hydratedRunnerState,
|
|
8333
|
+
});
|
|
8334
|
+
return buildLookupOnlyInformationalReply("runner.status", lookup, executionOverride);
|
|
8335
|
+
}
|
|
8336
|
+
|
|
8337
|
+
async function buildArtifactLocationLookupResponse({
|
|
8338
|
+
route,
|
|
8339
|
+
runtime,
|
|
8340
|
+
messageText,
|
|
8341
|
+
executionOverride,
|
|
8342
|
+
}) {
|
|
8343
|
+
const payload = await locateProjectFilesForQuery({
|
|
8344
|
+
siteBaseURL: runtime.baseURL,
|
|
8345
|
+
projectID: route?.projectID,
|
|
8346
|
+
token: runtime.token,
|
|
8347
|
+
timeoutSeconds: runtime.timeoutSeconds,
|
|
8348
|
+
query: messageText,
|
|
8349
|
+
});
|
|
8350
|
+
return buildLookupOnlyInformationalReply("project.file.locate", {
|
|
8351
|
+
...payload,
|
|
8352
|
+
}, executionOverride);
|
|
8353
|
+
}
|
|
8354
|
+
|
|
8355
|
+
async function resolveLookupOnlyInformationalReply({
|
|
8356
|
+
normalizedIntentType,
|
|
8357
|
+
route,
|
|
8358
|
+
routeState,
|
|
8359
|
+
selectedRecord,
|
|
8360
|
+
runtime,
|
|
8361
|
+
executionPlan,
|
|
8362
|
+
messageText,
|
|
8363
|
+
executionOverride,
|
|
8364
|
+
}) {
|
|
8365
|
+
const lookupHandlers = {
|
|
8366
|
+
small_talk: () => buildSmallTalkLookupResponse({ route, messageText, executionOverride }),
|
|
8367
|
+
workspace_query: () => buildProjectWorkspaceLookupResponse({ route, executionPlan, executionOverride }),
|
|
8368
|
+
bot_role_query: () => buildProjectBotRolesLookupResponse({ route, executionOverride }),
|
|
8369
|
+
status_query: () => buildRunnerStatusLookupOnlyResponse({
|
|
8370
|
+
route,
|
|
8371
|
+
routeState,
|
|
8372
|
+
selectedRecord,
|
|
8373
|
+
runtime,
|
|
8374
|
+
executionOverride,
|
|
8375
|
+
}),
|
|
8376
|
+
artifact_location_query: () => buildArtifactLocationLookupResponse({
|
|
8377
|
+
route,
|
|
8378
|
+
runtime,
|
|
8379
|
+
messageText,
|
|
8380
|
+
executionOverride,
|
|
8381
|
+
}),
|
|
8382
|
+
};
|
|
8383
|
+
const handler = lookupHandlers[normalizedIntentType];
|
|
8384
|
+
return typeof handler === "function" ? handler() : null;
|
|
8385
|
+
}
|
|
8386
|
+
|
|
8387
|
+
function buildLookupOnlyInformationalReply(source, lookup, executionOverride = null) {
|
|
8388
|
+
const response = {
|
|
8389
|
+
handled: true,
|
|
8390
|
+
source: String(source || "").trim(),
|
|
8391
|
+
response_mode: "lookup_only",
|
|
8392
|
+
reply: "",
|
|
8393
|
+
lookup: safeObject(lookup),
|
|
7653
8394
|
};
|
|
8395
|
+
if (executionOverride && typeof executionOverride === "object") {
|
|
8396
|
+
response.execution_override = executionOverride;
|
|
8397
|
+
}
|
|
8398
|
+
return response;
|
|
7654
8399
|
}
|
|
7655
8400
|
|
|
7656
8401
|
async function resolveInformationalQueryReply({
|
|
@@ -7664,20 +8409,19 @@ async function resolveInformationalQueryReply({
|
|
|
7664
8409
|
const normalizedIntentType = String(intentType || "").trim();
|
|
7665
8410
|
const messageText = String(safeObject(selectedRecord?.parsedArchive).body || "").trim();
|
|
7666
8411
|
const executionOverride = buildInformationalMiniExecutionOverride({ route, executionPlan });
|
|
8412
|
+
const lookupOnlyResponse = await resolveLookupOnlyInformationalReply({
|
|
8413
|
+
normalizedIntentType,
|
|
8414
|
+
route,
|
|
8415
|
+
routeState,
|
|
8416
|
+
selectedRecord,
|
|
8417
|
+
runtime,
|
|
8418
|
+
executionPlan,
|
|
8419
|
+
messageText,
|
|
8420
|
+
executionOverride,
|
|
8421
|
+
});
|
|
8422
|
+
return lookupOnlyResponse || null;
|
|
7667
8423
|
if (normalizedIntentType === "small_talk") {
|
|
7668
|
-
return {
|
|
7669
|
-
handled: true,
|
|
7670
|
-
response_mode: "lookup_only",
|
|
7671
|
-
reply: "",
|
|
7672
|
-
source: "small_talk",
|
|
7673
|
-
lookup: {
|
|
7674
|
-
intent_type: "small_talk",
|
|
7675
|
-
user_message: messageText,
|
|
7676
|
-
bot_name: firstNonEmptyString([route?.botName, route?.serverBotName, route?.server_bot_name, route?.name]),
|
|
7677
|
-
bot_role: String(route?.role || route?.roleProfile || "").trim(),
|
|
7678
|
-
},
|
|
7679
|
-
execution_override: executionOverride,
|
|
7680
|
-
};
|
|
8424
|
+
return buildSmallTalkLookupResponse({ route, messageText, executionOverride });
|
|
7681
8425
|
}
|
|
7682
8426
|
/* Dead legacy direct small_talk branch kept commented for reference.
|
|
7683
8427
|
if (false && normalizedIntentType === "small_talk") {
|
|
@@ -7689,41 +8433,31 @@ async function resolveInformationalQueryReply({
|
|
|
7689
8433
|
}
|
|
7690
8434
|
*/
|
|
7691
8435
|
if (normalizedIntentType === "workspace_query") {
|
|
8436
|
+
return buildProjectWorkspaceLookupResponse({
|
|
8437
|
+
route,
|
|
8438
|
+
executionPlan,
|
|
8439
|
+
executionOverride,
|
|
8440
|
+
});
|
|
7692
8441
|
const workspace = resolveProjectWorkspaceBindingSummary(route?.projectID, executionPlan?.workspaceDir || route?.workspaceDir || "");
|
|
7693
8442
|
const workspaceDir = String(workspace.workspace_dir || "").trim();
|
|
7694
8443
|
const reply = workspaceDir
|
|
7695
8444
|
? `현재 이 프로젝트에 바인딩된 로컬 작업 폴더는 "${workspaceDir}" 입니다.`
|
|
7696
8445
|
: "현재 이 프로젝트는 project-workspaces.json에 로컬 작업 폴더가 바인딩되어 있지 않습니다.";
|
|
7697
|
-
return {
|
|
7698
|
-
|
|
7699
|
-
|
|
7700
|
-
reply: "",
|
|
7701
|
-
source: "project.workspace",
|
|
7702
|
-
lookup: {
|
|
7703
|
-
...workspace,
|
|
7704
|
-
},
|
|
7705
|
-
execution_override: executionOverride,
|
|
7706
|
-
};
|
|
8446
|
+
return buildLookupOnlyInformationalReply("project.workspace", {
|
|
8447
|
+
...workspace,
|
|
8448
|
+
}, executionOverride);
|
|
7707
8449
|
}
|
|
7708
8450
|
if (normalizedIntentType === "bot_role_query") {
|
|
7709
|
-
|
|
7710
|
-
projectID: route?.projectID,
|
|
7711
|
-
provider: route?.provider,
|
|
7712
|
-
destinationID: route?.destinationID,
|
|
7713
|
-
destinationLabel: route?.destinationLabel,
|
|
7714
|
-
});
|
|
7715
|
-
return {
|
|
7716
|
-
handled: true,
|
|
7717
|
-
response_mode: "lookup_only",
|
|
7718
|
-
reply: "",
|
|
7719
|
-
source: "project.bot_roles",
|
|
7720
|
-
lookup: {
|
|
7721
|
-
...payload,
|
|
7722
|
-
},
|
|
7723
|
-
execution_override: executionOverride,
|
|
7724
|
-
};
|
|
8451
|
+
return buildProjectBotRolesLookupResponse({ route, executionOverride });
|
|
7725
8452
|
}
|
|
7726
8453
|
if (normalizedIntentType === "status_query") {
|
|
8454
|
+
return buildRunnerStatusLookupOnlyResponse({
|
|
8455
|
+
route,
|
|
8456
|
+
routeState,
|
|
8457
|
+
selectedRecord,
|
|
8458
|
+
runtime,
|
|
8459
|
+
executionOverride,
|
|
8460
|
+
});
|
|
7727
8461
|
let hydratedRunnerState = null;
|
|
7728
8462
|
try {
|
|
7729
8463
|
hydratedRunnerState = await hydrateRunnerRequestLedgerFromServer({
|
|
@@ -7731,18 +8465,13 @@ async function resolveInformationalQueryReply({
|
|
|
7731
8465
|
runtime,
|
|
7732
8466
|
});
|
|
7733
8467
|
} catch {}
|
|
7734
|
-
|
|
7735
|
-
|
|
7736
|
-
|
|
7737
|
-
|
|
7738
|
-
|
|
7739
|
-
|
|
7740
|
-
|
|
7741
|
-
routeState,
|
|
7742
|
-
selectedRecord,
|
|
7743
|
-
runnerStateOverride: hydratedRunnerState,
|
|
7744
|
-
}),
|
|
7745
|
-
};
|
|
8468
|
+
const lookup = buildRunnerStatusQueryLookup({
|
|
8469
|
+
route,
|
|
8470
|
+
routeState,
|
|
8471
|
+
selectedRecord,
|
|
8472
|
+
runnerStateOverride: hydratedRunnerState,
|
|
8473
|
+
});
|
|
8474
|
+
return buildLookupOnlyInformationalReply("runner.status", lookup, executionOverride);
|
|
7746
8475
|
const activeExecution = resolveRunnerActiveExecutionState(routeState);
|
|
7747
8476
|
if (activeExecution.active) {
|
|
7748
8477
|
const startedAt = String(activeExecution.startedAt || "").trim();
|
|
@@ -7774,23 +8503,12 @@ async function resolveInformationalQueryReply({
|
|
|
7774
8503
|
};
|
|
7775
8504
|
}
|
|
7776
8505
|
if (normalizedIntentType === "artifact_location_query") {
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
|
|
7780
|
-
|
|
7781
|
-
|
|
7782
|
-
query: messageText,
|
|
8506
|
+
return buildArtifactLocationLookupResponse({
|
|
8507
|
+
route,
|
|
8508
|
+
runtime,
|
|
8509
|
+
messageText,
|
|
8510
|
+
executionOverride,
|
|
7783
8511
|
});
|
|
7784
|
-
return {
|
|
7785
|
-
handled: true,
|
|
7786
|
-
response_mode: "lookup_only",
|
|
7787
|
-
reply: "",
|
|
7788
|
-
source: "project.file.locate",
|
|
7789
|
-
lookup: {
|
|
7790
|
-
...payload,
|
|
7791
|
-
},
|
|
7792
|
-
execution_override: executionOverride,
|
|
7793
|
-
};
|
|
7794
8512
|
}
|
|
7795
8513
|
return null;
|
|
7796
8514
|
}
|
|
@@ -7801,7 +8519,6 @@ function buildRunnerExecutionDeps() {
|
|
|
7801
8519
|
adjudicateRunnerStartupLoopWithAI,
|
|
7802
8520
|
analyzeHumanConversationIntentWithAI,
|
|
7803
8521
|
auditRoleExecutionPlanWithAI,
|
|
7804
|
-
auditDirectHumanReplyWithAI,
|
|
7805
8522
|
planRoleExecutionWithAI,
|
|
7806
8523
|
repairRoleExecutionPlanWithAI,
|
|
7807
8524
|
normalizeRunnerRoleProfileName,
|
|
@@ -8401,6 +9118,74 @@ async function processRunnerRouteOnce(route, runtime, mode, options = {}) {
|
|
|
8401
9118
|
}
|
|
8402
9119
|
return null;
|
|
8403
9120
|
};
|
|
9121
|
+
const buildSelectedRecordSkippedRecord = (selectedRecord, reason, extra = {}) => ({
|
|
9122
|
+
id: selectedRecord.id,
|
|
9123
|
+
reason: String(reason || "").trim(),
|
|
9124
|
+
messageID: intFromRawAllowZero(selectedRecord?.parsedArchive?.messageID, 0),
|
|
9125
|
+
...safeObject(extra),
|
|
9126
|
+
});
|
|
9127
|
+
const saveSelectedRecordSkipState = (selectedRecord, {
|
|
9128
|
+
action,
|
|
9129
|
+
reason,
|
|
9130
|
+
trigger = "",
|
|
9131
|
+
statePatch = {},
|
|
9132
|
+
}) => {
|
|
9133
|
+
saveRunnerRouteState(
|
|
9134
|
+
routeKey,
|
|
9135
|
+
buildRunnerRouteStateFromComment(selectedRecord, {
|
|
9136
|
+
last_action: String(action || "").trim(),
|
|
9137
|
+
last_reason: String(reason || "").trim(),
|
|
9138
|
+
last_trigger: String(trigger || "").trim(),
|
|
9139
|
+
...safeObject(statePatch),
|
|
9140
|
+
}),
|
|
9141
|
+
);
|
|
9142
|
+
};
|
|
9143
|
+
const pushSelectedRecordSkip = (skippedRecords, selectedRecord, {
|
|
9144
|
+
action,
|
|
9145
|
+
reason,
|
|
9146
|
+
trigger = "",
|
|
9147
|
+
statePatch = {},
|
|
9148
|
+
recordPatch = {},
|
|
9149
|
+
}) => {
|
|
9150
|
+
saveSelectedRecordSkipState(selectedRecord, {
|
|
9151
|
+
action,
|
|
9152
|
+
reason,
|
|
9153
|
+
trigger,
|
|
9154
|
+
statePatch,
|
|
9155
|
+
});
|
|
9156
|
+
skippedRecords.push(
|
|
9157
|
+
buildSelectedRecordSkippedRecord(selectedRecord, reason, recordPatch),
|
|
9158
|
+
);
|
|
9159
|
+
};
|
|
9160
|
+
const finalizeSkippedPendingRecords = async (skippedRecords) => {
|
|
9161
|
+
if (!ensureArray(skippedRecords).length) {
|
|
9162
|
+
return null;
|
|
9163
|
+
}
|
|
9164
|
+
await archiveRunnerDiagnosticComments({
|
|
9165
|
+
comments,
|
|
9166
|
+
skippedRecords,
|
|
9167
|
+
normalizedRoute,
|
|
9168
|
+
bot,
|
|
9169
|
+
archiveThread,
|
|
9170
|
+
runtime,
|
|
9171
|
+
});
|
|
9172
|
+
const distinctReasons = Array.from(new Set(skippedRecords.map((item) => item.reason).filter(Boolean)));
|
|
9173
|
+
const lastSkipped = skippedRecords[skippedRecords.length - 1];
|
|
9174
|
+
return {
|
|
9175
|
+
route_key: routeKey,
|
|
9176
|
+
route_name: normalizedRoute.name,
|
|
9177
|
+
logical_signature: runnerRouteLogicalSignature(normalizedRoute),
|
|
9178
|
+
outcome: "skipped",
|
|
9179
|
+
detail: distinctReasons.join("; ") || "all pending messages were skipped",
|
|
9180
|
+
archive_source: String(archiveThread.source || "").trim() || "-",
|
|
9181
|
+
archive_work_item_id: String(archiveThread.workItemID || "").trim() || "",
|
|
9182
|
+
thread_id: archiveThread.threadID,
|
|
9183
|
+
comment_id: lastSkipped.id,
|
|
9184
|
+
skipped_count: skippedRecords.length,
|
|
9185
|
+
execution_mode: executionPlan.mode,
|
|
9186
|
+
role_profile: executionPlan.roleProfileName,
|
|
9187
|
+
};
|
|
9188
|
+
};
|
|
8404
9189
|
const prepareRunnerRequestClaim = async (selectedRecord, selectedResponderSelectors = [], sharedHumanIntent = null) => {
|
|
8405
9190
|
const parsed = safeObject(selectedRecord?.parsedArchive);
|
|
8406
9191
|
const kind = String(parsed.kind || "").trim().toLowerCase();
|
|
@@ -8437,316 +9222,122 @@ async function processRunnerRouteOnce(route, runtime, mode, options = {}) {
|
|
|
8437
9222
|
archiveThreadID: archiveThread.threadID,
|
|
8438
9223
|
});
|
|
8439
9224
|
};
|
|
8440
|
-
|
|
8441
|
-
const
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
|
|
8446
|
-
|
|
8447
|
-
|
|
8448
|
-
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
8452
|
-
|
|
8453
|
-
|
|
8454
|
-
|
|
8455
|
-
|
|
8456
|
-
|
|
8457
|
-
|
|
8458
|
-
|
|
8459
|
-
|
|
8460
|
-
|
|
8461
|
-
|
|
8462
|
-
|
|
8463
|
-
|
|
8464
|
-
|
|
8465
|
-
|
|
8466
|
-
|
|
8467
|
-
|
|
8468
|
-
|
|
8469
|
-
|
|
8470
|
-
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
|
|
8474
|
-
|
|
8475
|
-
|
|
8476
|
-
|
|
8477
|
-
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
|
|
8482
|
-
|
|
8483
|
-
|
|
8484
|
-
|
|
8485
|
-
|
|
8486
|
-
|
|
8487
|
-
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
|
|
8492
|
-
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
|
|
8498
|
-
|
|
8499
|
-
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
executionPlan,
|
|
8503
|
-
deps: routingExecutionDeps,
|
|
8504
|
-
});
|
|
8505
|
-
if (safeObject(sharedHumanIntentContext).contractNeedsResolution === true) {
|
|
8506
|
-
const reason = "human intent contract is incomplete and requires regeneration";
|
|
8507
|
-
saveRunnerRouteState(
|
|
8508
|
-
routeKey,
|
|
8509
|
-
buildRunnerRouteStateFromComment(selectedRecord, {
|
|
8510
|
-
last_action: "needs_contract",
|
|
8511
|
-
last_reason: reason,
|
|
8512
|
-
last_trigger: "human_intent_contract",
|
|
8513
|
-
}),
|
|
8514
|
-
);
|
|
8515
|
-
skippedRecords.push({
|
|
8516
|
-
id: selectedRecord.id,
|
|
8517
|
-
reason,
|
|
8518
|
-
messageID: intFromRawAllowZero(selectedRecord?.parsedArchive?.messageID, 0),
|
|
8519
|
-
});
|
|
8520
|
-
continue;
|
|
8521
|
-
}
|
|
8522
|
-
const precomputedAdjudication = buildRunnerResponderAdjudicationFromHumanIntent({
|
|
8523
|
-
selectedRecord,
|
|
8524
|
-
normalizedRoute,
|
|
8525
|
-
bot,
|
|
8526
|
-
deps: routingExecutionDeps,
|
|
8527
|
-
precomputedHumanIntent: safeObject(sharedHumanIntentContext).humanIntent || null,
|
|
8528
|
-
});
|
|
8529
|
-
const adjudication = precomputedAdjudication || await resolveRunnerResponderAdjudication({
|
|
8530
|
-
selectedRecord,
|
|
8531
|
-
pendingOrdered: pending.ordered,
|
|
8532
|
-
normalizedRoute,
|
|
8533
|
-
bot,
|
|
8534
|
-
executionPlan,
|
|
8535
|
-
deps: routingExecutionDeps,
|
|
8536
|
-
precomputedHumanIntent: safeObject(sharedHumanIntentContext).humanIntent || null,
|
|
8537
|
-
});
|
|
8538
|
-
const currentBotSelected = ensureArray(adjudication.selected_bot_usernames)
|
|
8539
|
-
.map((value) => String(value || "").trim().replace(/^@+/, "").toLowerCase())
|
|
8540
|
-
.includes(currentBotSelector);
|
|
8541
|
-
if (!currentBotSelected) {
|
|
8542
|
-
saveRunnerRouteState(
|
|
9225
|
+
const buildContinuationResponderAdjudication = (selectedRecord, requestRaw) => {
|
|
9226
|
+
const request = safeObject(requestRaw);
|
|
9227
|
+
const referencedBotUsernames = ensureArray(safeObject(selectedRecord?.parsedArchive).mentionUsernames)
|
|
9228
|
+
.map((value) => normalizeTelegramMentionUsername(value))
|
|
9229
|
+
.filter(Boolean);
|
|
9230
|
+
const selectedBotUsernames = uniqueOrderedStrings(
|
|
9231
|
+
ensureArray(request.next_expected_responders).length
|
|
9232
|
+
? request.next_expected_responders
|
|
9233
|
+
: ensureArray(request.conversation_allowed_responders).length
|
|
9234
|
+
? request.conversation_allowed_responders
|
|
9235
|
+
: ensureArray(request.selected_bot_usernames).length
|
|
9236
|
+
? request.selected_bot_usernames
|
|
9237
|
+
: request.conversation_initial_responders,
|
|
9238
|
+
normalizeTelegramMentionUsername,
|
|
9239
|
+
);
|
|
9240
|
+
return {
|
|
9241
|
+
decision: selectedBotUsernames.length > 1
|
|
9242
|
+
? "multiple_responders"
|
|
9243
|
+
: selectedBotUsernames.length === 1
|
|
9244
|
+
? "single_responder"
|
|
9245
|
+
: "no_responder",
|
|
9246
|
+
selected_bot_usernames: selectedBotUsernames,
|
|
9247
|
+
referenced_bot_usernames: referencedBotUsernames,
|
|
9248
|
+
confidence: "high",
|
|
9249
|
+
reason_code: selectedBotUsernames.length > 0
|
|
9250
|
+
? "continuation_request_contract"
|
|
9251
|
+
: "continuation_request_contract_no_responder",
|
|
9252
|
+
clarification: "",
|
|
9253
|
+
};
|
|
9254
|
+
};
|
|
9255
|
+
const finalizePreparedRunnerRequest = async (selectedRecord, requestClaim) => {
|
|
9256
|
+
const inheritedRootReference = await inheritRunnerReferenceRootWorkItemForRequest({
|
|
9257
|
+
normalizedRoute,
|
|
9258
|
+
selectedRecord,
|
|
9259
|
+
runtime,
|
|
9260
|
+
requestKey: requestClaim.requestKey,
|
|
9261
|
+
});
|
|
9262
|
+
const rootWorkItemClaim = await ensureRunnerRootWorkItemForRequest({
|
|
9263
|
+
normalizedRoute,
|
|
9264
|
+
routeKey,
|
|
9265
|
+
selectedRecord,
|
|
9266
|
+
runtime,
|
|
9267
|
+
requestKey: requestClaim.requestKey,
|
|
9268
|
+
});
|
|
9269
|
+
const claimedRequest = safeObject(
|
|
9270
|
+
loadRunnerRequestByKey(requestClaim.requestKey)
|
|
9271
|
+
|| rootWorkItemClaim.request
|
|
9272
|
+
|| inheritedRootReference.request
|
|
9273
|
+
|| requestClaim.request,
|
|
9274
|
+
);
|
|
9275
|
+
const missingRequiredRootWorkItem = actionableRunnerRequestMissingRootWorkItem(claimedRequest);
|
|
9276
|
+
if (!rootWorkItemClaim.ok || missingRequiredRootWorkItem) {
|
|
9277
|
+
const rootWorkItemFailure = String(
|
|
9278
|
+
rootWorkItemClaim.error
|
|
9279
|
+
|| rootWorkItemClaim.reason
|
|
9280
|
+
|| (missingRequiredRootWorkItem ? "root_work_item_missing" : "root_work_item_create_failed"),
|
|
9281
|
+
).trim() || "root_work_item_create_failed";
|
|
9282
|
+
if (String(requestClaim.requestKey || "").trim()) {
|
|
9283
|
+
markRunnerRequestLifecycle({
|
|
9284
|
+
normalizedRoute,
|
|
9285
|
+
requestKey: requestClaim.requestKey,
|
|
9286
|
+
selectedRecord,
|
|
8543
9287
|
routeKey,
|
|
8544
|
-
|
|
8545
|
-
|
|
8546
|
-
last_reason: String(adjudication.reason_code || "").trim() || "not_selected_by_adjudicator",
|
|
8547
|
-
last_trigger: "responder_adjudication",
|
|
8548
|
-
}),
|
|
8549
|
-
);
|
|
8550
|
-
skippedRecords.push({
|
|
8551
|
-
id: selectedRecord.id,
|
|
8552
|
-
reason: String(adjudication.reason_code || "").trim() || "not_selected_by_adjudicator",
|
|
8553
|
-
messageID: intFromRawAllowZero(selectedRecord?.parsedArchive?.messageID, 0),
|
|
9288
|
+
outcome: "closed",
|
|
9289
|
+
closedReason: rootWorkItemFailure,
|
|
8554
9290
|
});
|
|
8555
|
-
continue;
|
|
8556
|
-
}
|
|
8557
|
-
const requestClaim = await prepareRunnerRequestClaim(
|
|
8558
|
-
selectedRecord,
|
|
8559
|
-
adjudication.selected_bot_usernames,
|
|
8560
|
-
safeObject(sharedHumanIntentContext).humanIntent || null,
|
|
8561
|
-
);
|
|
8562
|
-
if (!requestClaim.ok) {
|
|
8563
9291
|
await syncRunnerRequestLedgerForProjectToServer({
|
|
8564
9292
|
normalizedRoute,
|
|
8565
9293
|
runtime,
|
|
8566
9294
|
});
|
|
8567
|
-
saveRunnerRouteState(
|
|
8568
|
-
routeKey,
|
|
8569
|
-
buildRunnerRouteStateFromComment(selectedRecord, {
|
|
8570
|
-
last_action: "request_skipped",
|
|
8571
|
-
last_reason: String(requestClaim.reason || "request_unavailable").trim() || "request_unavailable",
|
|
8572
|
-
last_trigger: "request_ledger",
|
|
8573
|
-
}),
|
|
8574
|
-
);
|
|
8575
|
-
skippedRecords.push({
|
|
8576
|
-
id: selectedRecord.id,
|
|
8577
|
-
reason: String(requestClaim.reason || "request_unavailable").trim() || "request_unavailable",
|
|
8578
|
-
messageID: intFromRawAllowZero(selectedRecord?.parsedArchive?.messageID, 0),
|
|
8579
|
-
diagnosticType: "skip",
|
|
8580
|
-
contextExcluded: String(requestClaim.reason || "").trim() === "bot_reply_without_active_request",
|
|
8581
|
-
action: "skip_invalid_request_state",
|
|
8582
|
-
closedReason: String(requestClaim.reason || "").trim(),
|
|
8583
|
-
});
|
|
8584
|
-
continue;
|
|
8585
9295
|
}
|
|
8586
|
-
const inheritedRootReference = await inheritRunnerReferenceRootWorkItemForRequest({
|
|
8587
|
-
normalizedRoute,
|
|
8588
|
-
selectedRecord,
|
|
8589
|
-
runtime,
|
|
8590
|
-
requestKey: requestClaim.requestKey,
|
|
8591
|
-
});
|
|
8592
|
-
const rootWorkItemClaim = await ensureRunnerRootWorkItemForRequest({
|
|
8593
|
-
normalizedRoute,
|
|
8594
|
-
routeKey,
|
|
8595
|
-
selectedRecord,
|
|
8596
|
-
runtime,
|
|
8597
|
-
requestKey: requestClaim.requestKey,
|
|
8598
|
-
});
|
|
8599
|
-
const claimedRequest = safeObject(
|
|
8600
|
-
loadRunnerRequestByKey(requestClaim.requestKey)
|
|
8601
|
-
|| rootWorkItemClaim.request
|
|
8602
|
-
|| inheritedRootReference.request
|
|
8603
|
-
|| requestClaim.request,
|
|
8604
|
-
);
|
|
8605
|
-
const missingRequiredRootWorkItem = actionableRunnerRequestMissingRootWorkItem(claimedRequest);
|
|
8606
|
-
if (!rootWorkItemClaim.ok || missingRequiredRootWorkItem) {
|
|
8607
|
-
const rootWorkItemFailure = String(
|
|
8608
|
-
rootWorkItemClaim.error
|
|
8609
|
-
|| rootWorkItemClaim.reason
|
|
8610
|
-
|| (missingRequiredRootWorkItem ? "root_work_item_missing" : "root_work_item_create_failed"),
|
|
8611
|
-
).trim() || "root_work_item_create_failed";
|
|
8612
|
-
if (String(requestClaim.requestKey || "").trim()) {
|
|
8613
|
-
markRunnerRequestLifecycle({
|
|
8614
|
-
normalizedRoute,
|
|
8615
|
-
requestKey: requestClaim.requestKey,
|
|
8616
|
-
selectedRecord,
|
|
8617
|
-
routeKey,
|
|
8618
|
-
outcome: "closed",
|
|
8619
|
-
closedReason: rootWorkItemFailure,
|
|
8620
|
-
});
|
|
8621
|
-
await syncRunnerRequestLedgerForProjectToServer({
|
|
8622
|
-
normalizedRoute,
|
|
8623
|
-
runtime,
|
|
8624
|
-
});
|
|
8625
|
-
}
|
|
8626
|
-
saveRunnerRouteState(
|
|
8627
|
-
routeKey,
|
|
8628
|
-
buildRunnerRouteStateFromComment(selectedRecord, {
|
|
8629
|
-
last_action: "request_skipped",
|
|
8630
|
-
last_reason: rootWorkItemFailure,
|
|
8631
|
-
last_trigger: "work_item_root",
|
|
8632
|
-
last_request_key: String(requestClaim.requestKey || "").trim(),
|
|
8633
|
-
}),
|
|
8634
|
-
);
|
|
8635
|
-
skippedRecords.push({
|
|
8636
|
-
id: selectedRecord.id,
|
|
8637
|
-
reason: rootWorkItemFailure,
|
|
8638
|
-
messageID: intFromRawAllowZero(selectedRecord?.parsedArchive?.messageID, 0),
|
|
8639
|
-
diagnosticType: "skip",
|
|
8640
|
-
action: "skip_missing_root_work_item",
|
|
8641
|
-
closedReason: rootWorkItemFailure,
|
|
8642
|
-
});
|
|
8643
|
-
continue;
|
|
8644
|
-
}
|
|
8645
|
-
saveRunnerRouteState(routeKey, {
|
|
8646
|
-
...buildRunnerActiveExecutionPatch(selectedRecord, requestClaim.requestKey, {
|
|
8647
|
-
id: String(claimedRequest.root_work_item_id || "").trim(),
|
|
8648
|
-
title: String(claimedRequest.root_work_item_title || "").trim(),
|
|
8649
|
-
status: String(claimedRequest.root_work_item_status || "").trim(),
|
|
8650
|
-
}),
|
|
8651
|
-
last_request_key: String(requestClaim.requestKey || "").trim(),
|
|
8652
|
-
last_root_work_item_id: String(claimedRequest.root_work_item_id || "").trim(),
|
|
8653
|
-
last_root_work_item_title: String(claimedRequest.root_work_item_title || "").trim(),
|
|
8654
|
-
last_root_work_item_status: String(claimedRequest.root_work_item_status || "").trim(),
|
|
8655
|
-
});
|
|
8656
|
-
await syncRunnerRequestLedgerForProjectToServer({
|
|
8657
|
-
normalizedRoute,
|
|
8658
|
-
runtime,
|
|
8659
|
-
});
|
|
8660
9296
|
return {
|
|
8661
|
-
|
|
8662
|
-
|
|
8663
|
-
|
|
8664
|
-
|
|
8665
|
-
|
|
8666
|
-
|
|
8667
|
-
|
|
8668
|
-
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
|
|
8672
|
-
|
|
8673
|
-
|
|
8674
|
-
|
|
8675
|
-
routeState: safeObject(loadBotRunnerState().routes[routeKey]),
|
|
8676
|
-
selectedRecord,
|
|
8677
|
-
pendingOrdered: pending.ordered,
|
|
8678
|
-
bot,
|
|
8679
|
-
destination,
|
|
8680
|
-
archiveThread,
|
|
8681
|
-
executionPlan,
|
|
8682
|
-
runtime,
|
|
8683
|
-
managedConversationBots,
|
|
8684
|
-
requestKey: String(requestClaim.requestKey || "").trim(),
|
|
8685
|
-
triggerDecision,
|
|
8686
|
-
responderAdjudication: adjudication,
|
|
8687
|
-
humanIntentContext: sharedHumanIntentContext,
|
|
9297
|
+
ok: false,
|
|
9298
|
+
skip: {
|
|
9299
|
+
kind: "skip",
|
|
9300
|
+
skipAction: "request_skipped",
|
|
9301
|
+
skipReason: rootWorkItemFailure,
|
|
9302
|
+
skipTrigger: "work_item_root",
|
|
9303
|
+
skipStatePatch: {
|
|
9304
|
+
last_request_key: String(requestClaim.requestKey || "").trim(),
|
|
9305
|
+
},
|
|
9306
|
+
skipRecordPatch: {
|
|
9307
|
+
diagnosticType: "skip",
|
|
9308
|
+
action: "skip_missing_root_work_item",
|
|
9309
|
+
closedReason: rootWorkItemFailure,
|
|
9310
|
+
},
|
|
8688
9311
|
},
|
|
8689
9312
|
};
|
|
8690
9313
|
}
|
|
8691
|
-
|
|
8692
|
-
|
|
8693
|
-
|
|
8694
|
-
|
|
8695
|
-
|
|
8696
|
-
|
|
8697
|
-
archiveThread,
|
|
8698
|
-
runtime,
|
|
8699
|
-
});
|
|
8700
|
-
const distinctReasons = Array.from(new Set(skippedRecords.map((item) => item.reason).filter(Boolean)));
|
|
8701
|
-
const lastSkipped = skippedRecords[skippedRecords.length - 1];
|
|
8702
|
-
return {
|
|
8703
|
-
route_key: routeKey,
|
|
8704
|
-
route_name: normalizedRoute.name,
|
|
8705
|
-
logical_signature: runnerRouteLogicalSignature(normalizedRoute),
|
|
8706
|
-
outcome: "skipped",
|
|
8707
|
-
detail: distinctReasons.join("; ") || "all pending messages were skipped",
|
|
8708
|
-
archive_source: String(archiveThread.source || "").trim() || "-",
|
|
8709
|
-
archive_work_item_id: String(archiveThread.workItemID || "").trim() || "",
|
|
8710
|
-
thread_id: archiveThread.threadID,
|
|
8711
|
-
comment_id: lastSkipped.id,
|
|
8712
|
-
skipped_count: skippedRecords.length,
|
|
8713
|
-
execution_mode: executionPlan.mode,
|
|
8714
|
-
role_profile: executionPlan.roleProfileName,
|
|
8715
|
-
};
|
|
8716
|
-
}
|
|
8717
|
-
}
|
|
8718
|
-
const skippedRecords = [];
|
|
8719
|
-
for (const selectedRecord of pending.pending) {
|
|
9314
|
+
return {
|
|
9315
|
+
ok: true,
|
|
9316
|
+
claimedRequest,
|
|
9317
|
+
};
|
|
9318
|
+
};
|
|
9319
|
+
const prepareRunnerSelectedRecordForExecution = async (selectedRecord) => {
|
|
8720
9320
|
const duplicateArchivedSkip = maybeBuildDuplicateArchivedSkip(selectedRecord, refreshedState);
|
|
8721
9321
|
if (duplicateArchivedSkip) {
|
|
8722
|
-
|
|
8723
|
-
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
|
-
|
|
8728
|
-
|
|
8729
|
-
);
|
|
8730
|
-
skippedRecords.push(duplicateArchivedSkip);
|
|
8731
|
-
continue;
|
|
9322
|
+
return {
|
|
9323
|
+
kind: "skip",
|
|
9324
|
+
skipAction: "duplicate_skipped",
|
|
9325
|
+
skipReason: String(duplicateArchivedSkip.reason || "duplicate_archived_source_message").trim(),
|
|
9326
|
+
skipTrigger: "archive_dedupe",
|
|
9327
|
+
skipRecordPatch: duplicateArchivedSkip,
|
|
9328
|
+
};
|
|
8732
9329
|
}
|
|
8733
9330
|
const triggerDecision = evaluateTelegramRunnerTrigger(selectedRecord, normalizedRoute, bot);
|
|
8734
9331
|
if (triggerDecision.shouldRespond !== true) {
|
|
8735
|
-
|
|
8736
|
-
|
|
8737
|
-
|
|
8738
|
-
|
|
8739
|
-
|
|
8740
|
-
|
|
8741
|
-
|
|
8742
|
-
|
|
8743
|
-
|
|
8744
|
-
id: selectedRecord.id,
|
|
8745
|
-
reason: String(triggerDecision.reason || "trigger policy skipped message").trim() || "trigger policy skipped message",
|
|
8746
|
-
messageID: intFromRawAllowZero(selectedRecord?.parsedArchive?.messageID, 0),
|
|
8747
|
-
suppressDiagnostic: true,
|
|
8748
|
-
});
|
|
8749
|
-
continue;
|
|
9332
|
+
return {
|
|
9333
|
+
kind: "skip",
|
|
9334
|
+
skipAction: "trigger_skipped",
|
|
9335
|
+
skipReason: String(triggerDecision.reason || "trigger policy skipped message").trim() || "trigger policy skipped message",
|
|
9336
|
+
skipTrigger: String(triggerDecision.trigger || "").trim() || "trigger_policy",
|
|
9337
|
+
skipRecordPatch: {
|
|
9338
|
+
suppressDiagnostic: true,
|
|
9339
|
+
},
|
|
9340
|
+
};
|
|
8750
9341
|
}
|
|
8751
9342
|
const startupLoopSkipped = await maybeHandleRunnerStartupLoopCandidate({
|
|
8752
9343
|
routeKey,
|
|
@@ -8764,14 +9355,66 @@ async function processRunnerRouteOnce(route, runtime, mode, options = {}) {
|
|
|
8764
9355
|
: false,
|
|
8765
9356
|
});
|
|
8766
9357
|
if (startupLoopSkipped) {
|
|
8767
|
-
|
|
8768
|
-
|
|
9358
|
+
return {
|
|
9359
|
+
kind: "startup_loop_skipped",
|
|
9360
|
+
skippedRecord: startupLoopSkipped.skippedRecord,
|
|
9361
|
+
};
|
|
8769
9362
|
}
|
|
8770
9363
|
const routingExecutionDeps = {
|
|
8771
9364
|
...buildRunnerExecutionDeps(),
|
|
8772
9365
|
managedConversationBots,
|
|
8773
9366
|
resolveConversationPeerBots: resolveRunnerConversationPeers,
|
|
8774
9367
|
};
|
|
9368
|
+
const selectedRecordKind = String(safeObject(selectedRecord?.parsedArchive).kind || "").trim().toLowerCase();
|
|
9369
|
+
if (selectedRecordKind === "bot_reply") {
|
|
9370
|
+
const requestClaim = await prepareRunnerRequestClaim(selectedRecord);
|
|
9371
|
+
if (!requestClaim.ok) {
|
|
9372
|
+
await syncRunnerRequestLedgerForProjectToServer({
|
|
9373
|
+
normalizedRoute,
|
|
9374
|
+
runtime,
|
|
9375
|
+
});
|
|
9376
|
+
return {
|
|
9377
|
+
kind: "skip",
|
|
9378
|
+
skipAction: "request_skipped",
|
|
9379
|
+
skipReason: String(requestClaim.reason || "request_unavailable").trim() || "request_unavailable",
|
|
9380
|
+
skipTrigger: "request_ledger",
|
|
9381
|
+
skipRecordPatch: {
|
|
9382
|
+
diagnosticType: "skip",
|
|
9383
|
+
contextExcluded: String(requestClaim.reason || "").trim() === "bot_reply_without_active_request",
|
|
9384
|
+
action: "skip_invalid_request_state",
|
|
9385
|
+
closedReason: String(requestClaim.reason || "").trim(),
|
|
9386
|
+
},
|
|
9387
|
+
};
|
|
9388
|
+
}
|
|
9389
|
+
const continuationAdjudication = buildContinuationResponderAdjudication(
|
|
9390
|
+
selectedRecord,
|
|
9391
|
+
requestClaim.request,
|
|
9392
|
+
);
|
|
9393
|
+
const currentBotSelected = ensureArray(continuationAdjudication.selected_bot_usernames)
|
|
9394
|
+
.map((value) => String(value || "").trim().replace(/^@+/, "").toLowerCase())
|
|
9395
|
+
.includes(currentBotSelector);
|
|
9396
|
+
if (!currentBotSelected) {
|
|
9397
|
+
return {
|
|
9398
|
+
kind: "skip",
|
|
9399
|
+
skipAction: "adjudication_skipped",
|
|
9400
|
+
skipReason: String(continuationAdjudication.reason_code || "").trim() || "not_selected_by_request_contract",
|
|
9401
|
+
skipTrigger: "request_contract",
|
|
9402
|
+
};
|
|
9403
|
+
}
|
|
9404
|
+
const finalizedRequest = await finalizePreparedRunnerRequest(selectedRecord, requestClaim);
|
|
9405
|
+
if (!finalizedRequest.ok) {
|
|
9406
|
+
return finalizedRequest.skip;
|
|
9407
|
+
}
|
|
9408
|
+
return {
|
|
9409
|
+
kind: "ready",
|
|
9410
|
+
triggerDecision,
|
|
9411
|
+
routingExecutionDeps,
|
|
9412
|
+
sharedHumanIntentContext: null,
|
|
9413
|
+
adjudication: continuationAdjudication,
|
|
9414
|
+
requestClaim,
|
|
9415
|
+
claimedRequest: finalizedRequest.claimedRequest,
|
|
9416
|
+
};
|
|
9417
|
+
}
|
|
8775
9418
|
const sharedHumanIntentContext = await resolveHumanIntentContext({
|
|
8776
9419
|
selectedRecord,
|
|
8777
9420
|
normalizedRoute,
|
|
@@ -8780,30 +9423,31 @@ async function processRunnerRouteOnce(route, runtime, mode, options = {}) {
|
|
|
8780
9423
|
deps: routingExecutionDeps,
|
|
8781
9424
|
});
|
|
8782
9425
|
if (safeObject(sharedHumanIntentContext).contractNeedsResolution === true) {
|
|
8783
|
-
|
|
8784
|
-
|
|
8785
|
-
|
|
8786
|
-
|
|
8787
|
-
|
|
8788
|
-
|
|
8789
|
-
last_trigger: "human_intent_contract",
|
|
8790
|
-
}),
|
|
8791
|
-
);
|
|
8792
|
-
skippedRecords.push({
|
|
8793
|
-
id: selectedRecord.id,
|
|
8794
|
-
reason,
|
|
8795
|
-
messageID: intFromRawAllowZero(selectedRecord?.parsedArchive?.messageID, 0),
|
|
8796
|
-
});
|
|
8797
|
-
continue;
|
|
9426
|
+
return {
|
|
9427
|
+
kind: "skip",
|
|
9428
|
+
skipAction: "needs_contract",
|
|
9429
|
+
skipReason: "human intent contract is incomplete and requires regeneration",
|
|
9430
|
+
skipTrigger: "human_intent_contract",
|
|
9431
|
+
};
|
|
8798
9432
|
}
|
|
8799
|
-
const
|
|
9433
|
+
const precomputedAdjudication = buildRunnerResponderAdjudicationFromHumanIntent({
|
|
8800
9434
|
selectedRecord,
|
|
8801
9435
|
normalizedRoute,
|
|
8802
9436
|
bot,
|
|
8803
9437
|
deps: routingExecutionDeps,
|
|
8804
9438
|
precomputedHumanIntent: safeObject(sharedHumanIntentContext).humanIntent || null,
|
|
8805
9439
|
});
|
|
8806
|
-
const
|
|
9440
|
+
const shouldRequireContractDrivenResponderSelection = selectedRecordKind !== "bot_reply"
|
|
9441
|
+
&& safeObject(selectedRecord?.parsedArchive).senderIsBot !== true;
|
|
9442
|
+
if (!precomputedAdjudication && shouldRequireContractDrivenResponderSelection) {
|
|
9443
|
+
return {
|
|
9444
|
+
kind: "skip",
|
|
9445
|
+
skipAction: "needs_contract",
|
|
9446
|
+
skipReason: "human intent contract did not select any responder",
|
|
9447
|
+
skipTrigger: "human_intent_contract",
|
|
9448
|
+
};
|
|
9449
|
+
}
|
|
9450
|
+
const adjudication = precomputedAdjudication || await resolveRunnerResponderAdjudication({
|
|
8807
9451
|
selectedRecord,
|
|
8808
9452
|
pendingOrdered: pending.ordered,
|
|
8809
9453
|
normalizedRoute,
|
|
@@ -8812,29 +9456,20 @@ async function processRunnerRouteOnce(route, runtime, mode, options = {}) {
|
|
|
8812
9456
|
deps: routingExecutionDeps,
|
|
8813
9457
|
precomputedHumanIntent: safeObject(sharedHumanIntentContext).humanIntent || null,
|
|
8814
9458
|
});
|
|
8815
|
-
const
|
|
9459
|
+
const currentBotSelected = ensureArray(adjudication.selected_bot_usernames)
|
|
8816
9460
|
.map((value) => String(value || "").trim().replace(/^@+/, "").toLowerCase())
|
|
8817
9461
|
.includes(currentBotSelector);
|
|
8818
|
-
if (!
|
|
8819
|
-
|
|
8820
|
-
|
|
8821
|
-
|
|
8822
|
-
|
|
8823
|
-
|
|
8824
|
-
|
|
8825
|
-
}),
|
|
8826
|
-
);
|
|
8827
|
-
skippedRecords.push({
|
|
8828
|
-
id: selectedRecord.id,
|
|
8829
|
-
reason: String(inlineAdjudication.reason_code || "").trim() || "not_selected_by_adjudicator",
|
|
8830
|
-
messageID: intFromRawAllowZero(selectedRecord?.parsedArchive?.messageID, 0),
|
|
8831
|
-
});
|
|
8832
|
-
continue;
|
|
9462
|
+
if (!currentBotSelected) {
|
|
9463
|
+
return {
|
|
9464
|
+
kind: "skip",
|
|
9465
|
+
skipAction: "adjudication_skipped",
|
|
9466
|
+
skipReason: String(adjudication.reason_code || "").trim() || "not_selected_by_adjudicator",
|
|
9467
|
+
skipTrigger: "responder_adjudication",
|
|
9468
|
+
};
|
|
8833
9469
|
}
|
|
8834
|
-
const currentRouteState = safeObject(loadBotRunnerState().routes[routeKey]);
|
|
8835
9470
|
const requestClaim = await prepareRunnerRequestClaim(
|
|
8836
9471
|
selectedRecord,
|
|
8837
|
-
|
|
9472
|
+
adjudication.selected_bot_usernames,
|
|
8838
9473
|
safeObject(sharedHumanIntentContext).humanIntent || null,
|
|
8839
9474
|
);
|
|
8840
9475
|
if (!requestClaim.ok) {
|
|
@@ -8842,84 +9477,136 @@ async function processRunnerRouteOnce(route, runtime, mode, options = {}) {
|
|
|
8842
9477
|
normalizedRoute,
|
|
8843
9478
|
runtime,
|
|
8844
9479
|
});
|
|
8845
|
-
|
|
8846
|
-
|
|
8847
|
-
|
|
8848
|
-
|
|
8849
|
-
|
|
8850
|
-
|
|
9480
|
+
return {
|
|
9481
|
+
kind: "skip",
|
|
9482
|
+
skipAction: "request_skipped",
|
|
9483
|
+
skipReason: String(requestClaim.reason || "request_unavailable").trim() || "request_unavailable",
|
|
9484
|
+
skipTrigger: "request_ledger",
|
|
9485
|
+
skipRecordPatch: {
|
|
9486
|
+
diagnosticType: "skip",
|
|
9487
|
+
contextExcluded: String(requestClaim.reason || "").trim() === "bot_reply_without_active_request",
|
|
9488
|
+
action: "skip_invalid_request_state",
|
|
9489
|
+
closedReason: String(requestClaim.reason || "").trim(),
|
|
9490
|
+
},
|
|
9491
|
+
};
|
|
9492
|
+
}
|
|
9493
|
+
const finalizedRequest = await finalizePreparedRunnerRequest(selectedRecord, requestClaim);
|
|
9494
|
+
if (!finalizedRequest.ok) {
|
|
9495
|
+
return finalizedRequest.skip;
|
|
9496
|
+
}
|
|
9497
|
+
return {
|
|
9498
|
+
kind: "ready",
|
|
9499
|
+
triggerDecision,
|
|
9500
|
+
routingExecutionDeps,
|
|
9501
|
+
sharedHumanIntentContext,
|
|
9502
|
+
adjudication,
|
|
9503
|
+
requestClaim,
|
|
9504
|
+
claimedRequest: finalizedRequest.claimedRequest,
|
|
9505
|
+
};
|
|
9506
|
+
};
|
|
9507
|
+
if (deferExecution) {
|
|
9508
|
+
const skippedRecords = [];
|
|
9509
|
+
for (const selectedRecord of pending.pending) {
|
|
9510
|
+
const preparation = await prepareRunnerSelectedRecordForExecution(selectedRecord);
|
|
9511
|
+
if (preparation.kind === "skip") {
|
|
9512
|
+
pushSelectedRecordSkip(skippedRecords, selectedRecord, {
|
|
9513
|
+
action: preparation.skipAction,
|
|
9514
|
+
reason: preparation.skipReason,
|
|
9515
|
+
trigger: preparation.skipTrigger,
|
|
9516
|
+
statePatch: preparation.skipStatePatch,
|
|
9517
|
+
recordPatch: preparation.skipRecordPatch,
|
|
9518
|
+
});
|
|
9519
|
+
continue;
|
|
9520
|
+
}
|
|
9521
|
+
if (preparation.kind === "startup_loop_skipped") {
|
|
9522
|
+
skippedRecords.push(preparation.skippedRecord);
|
|
9523
|
+
continue;
|
|
9524
|
+
}
|
|
9525
|
+
const {
|
|
9526
|
+
triggerDecision,
|
|
9527
|
+
sharedHumanIntentContext,
|
|
9528
|
+
adjudication,
|
|
9529
|
+
requestClaim,
|
|
9530
|
+
claimedRequest,
|
|
9531
|
+
} = preparation;
|
|
9532
|
+
saveRunnerRouteState(routeKey, {
|
|
9533
|
+
...buildRunnerActiveExecutionPatch(selectedRecord, requestClaim.requestKey, {
|
|
9534
|
+
id: String(claimedRequest.root_work_item_id || "").trim(),
|
|
9535
|
+
title: String(claimedRequest.root_work_item_title || "").trim(),
|
|
9536
|
+
status: String(claimedRequest.root_work_item_status || "").trim(),
|
|
8851
9537
|
}),
|
|
8852
|
-
|
|
8853
|
-
|
|
8854
|
-
|
|
8855
|
-
|
|
8856
|
-
messageID: intFromRawAllowZero(selectedRecord?.parsedArchive?.messageID, 0),
|
|
8857
|
-
diagnosticType: "skip",
|
|
8858
|
-
contextExcluded: String(requestClaim.reason || "").trim() === "bot_reply_without_active_request",
|
|
8859
|
-
action: "skip_invalid_request_state",
|
|
8860
|
-
closedReason: String(requestClaim.reason || "").trim(),
|
|
9538
|
+
last_request_key: String(requestClaim.requestKey || "").trim(),
|
|
9539
|
+
last_root_work_item_id: String(claimedRequest.root_work_item_id || "").trim(),
|
|
9540
|
+
last_root_work_item_title: String(claimedRequest.root_work_item_title || "").trim(),
|
|
9541
|
+
last_root_work_item_status: String(claimedRequest.root_work_item_status || "").trim(),
|
|
8861
9542
|
});
|
|
8862
|
-
|
|
8863
|
-
|
|
8864
|
-
|
|
8865
|
-
|
|
8866
|
-
|
|
8867
|
-
|
|
8868
|
-
|
|
8869
|
-
|
|
8870
|
-
|
|
8871
|
-
|
|
8872
|
-
|
|
8873
|
-
|
|
8874
|
-
|
|
8875
|
-
|
|
8876
|
-
|
|
8877
|
-
|
|
8878
|
-
|
|
8879
|
-
|| rootWorkItemClaim.request
|
|
8880
|
-
|| inheritedRootReference.request
|
|
8881
|
-
|| requestClaim.request,
|
|
8882
|
-
);
|
|
8883
|
-
const missingRequiredRootWorkItem = actionableRunnerRequestMissingRootWorkItem(claimedRequest);
|
|
8884
|
-
if (!rootWorkItemClaim.ok || missingRequiredRootWorkItem) {
|
|
8885
|
-
const rootWorkItemFailure = String(
|
|
8886
|
-
rootWorkItemClaim.error
|
|
8887
|
-
|| rootWorkItemClaim.reason
|
|
8888
|
-
|| (missingRequiredRootWorkItem ? "root_work_item_missing" : "root_work_item_create_failed"),
|
|
8889
|
-
).trim() || "root_work_item_create_failed";
|
|
8890
|
-
if (String(requestClaim.requestKey || "").trim()) {
|
|
8891
|
-
markRunnerRequestLifecycle({
|
|
8892
|
-
normalizedRoute,
|
|
8893
|
-
requestKey: requestClaim.requestKey,
|
|
8894
|
-
selectedRecord,
|
|
9543
|
+
await syncRunnerRequestLedgerForProjectToServer({
|
|
9544
|
+
normalizedRoute,
|
|
9545
|
+
runtime,
|
|
9546
|
+
});
|
|
9547
|
+
return {
|
|
9548
|
+
route_key: routeKey,
|
|
9549
|
+
route_name: normalizedRoute.name,
|
|
9550
|
+
logical_signature: runnerRouteLogicalSignature(normalizedRoute),
|
|
9551
|
+
outcome: "accepted",
|
|
9552
|
+
detail: `accepted comment ${selectedRecord.id} for background execution`,
|
|
9553
|
+
archive_source: String(archiveThread.source || "").trim() || "-",
|
|
9554
|
+
archive_work_item_id: String(archiveThread.workItemID || "").trim() || "",
|
|
9555
|
+
thread_id: archiveThread.threadID,
|
|
9556
|
+
comment_id: selectedRecord.id,
|
|
9557
|
+
execution_mode: executionPlan.mode,
|
|
9558
|
+
role_profile: executionPlan.roleProfileName,
|
|
9559
|
+
deferred_execution: {
|
|
8895
9560
|
routeKey,
|
|
8896
|
-
outcome: "closed",
|
|
8897
|
-
closedReason: rootWorkItemFailure,
|
|
8898
|
-
});
|
|
8899
|
-
await syncRunnerRequestLedgerForProjectToServer({
|
|
8900
9561
|
normalizedRoute,
|
|
9562
|
+
routeState: safeObject(loadBotRunnerState().routes[routeKey]),
|
|
9563
|
+
selectedRecord,
|
|
9564
|
+
pendingOrdered: pending.ordered,
|
|
9565
|
+
bot,
|
|
9566
|
+
destination,
|
|
9567
|
+
archiveThread,
|
|
9568
|
+
executionPlan,
|
|
8901
9569
|
runtime,
|
|
8902
|
-
|
|
9570
|
+
managedConversationBots,
|
|
9571
|
+
requestKey: String(requestClaim.requestKey || "").trim(),
|
|
9572
|
+
triggerDecision,
|
|
9573
|
+
responderAdjudication: adjudication,
|
|
9574
|
+
humanIntentContext: sharedHumanIntentContext,
|
|
9575
|
+
},
|
|
9576
|
+
};
|
|
9577
|
+
}
|
|
9578
|
+
{
|
|
9579
|
+
const skippedOutcome = await finalizeSkippedPendingRecords(skippedRecords);
|
|
9580
|
+
if (skippedOutcome) {
|
|
9581
|
+
return skippedOutcome;
|
|
8903
9582
|
}
|
|
8904
|
-
|
|
8905
|
-
|
|
8906
|
-
|
|
8907
|
-
|
|
8908
|
-
|
|
8909
|
-
|
|
8910
|
-
|
|
8911
|
-
|
|
8912
|
-
|
|
8913
|
-
|
|
8914
|
-
|
|
8915
|
-
|
|
8916
|
-
messageID: intFromRawAllowZero(selectedRecord?.parsedArchive?.messageID, 0),
|
|
8917
|
-
diagnosticType: "skip",
|
|
8918
|
-
action: "skip_missing_root_work_item",
|
|
8919
|
-
closedReason: rootWorkItemFailure,
|
|
9583
|
+
}
|
|
9584
|
+
}
|
|
9585
|
+
const skippedRecords = [];
|
|
9586
|
+
for (const selectedRecord of pending.pending) {
|
|
9587
|
+
const preparation = await prepareRunnerSelectedRecordForExecution(selectedRecord);
|
|
9588
|
+
if (preparation.kind === "skip") {
|
|
9589
|
+
pushSelectedRecordSkip(skippedRecords, selectedRecord, {
|
|
9590
|
+
action: preparation.skipAction,
|
|
9591
|
+
reason: preparation.skipReason,
|
|
9592
|
+
trigger: preparation.skipTrigger,
|
|
9593
|
+
statePatch: preparation.skipStatePatch,
|
|
9594
|
+
recordPatch: preparation.skipRecordPatch,
|
|
8920
9595
|
});
|
|
8921
9596
|
continue;
|
|
8922
9597
|
}
|
|
9598
|
+
if (preparation.kind === "startup_loop_skipped") {
|
|
9599
|
+
skippedRecords.push(preparation.skippedRecord);
|
|
9600
|
+
continue;
|
|
9601
|
+
}
|
|
9602
|
+
const currentRouteState = safeObject(loadBotRunnerState().routes[routeKey]);
|
|
9603
|
+
const {
|
|
9604
|
+
triggerDecision,
|
|
9605
|
+
sharedHumanIntentContext,
|
|
9606
|
+
adjudication: inlineAdjudication,
|
|
9607
|
+
requestClaim,
|
|
9608
|
+
claimedRequest,
|
|
9609
|
+
} = preparation;
|
|
8923
9610
|
saveRunnerRouteState(routeKey, {
|
|
8924
9611
|
...buildRunnerActiveExecutionPatch(selectedRecord, requestClaim.requestKey, {
|
|
8925
9612
|
id: String(claimedRequest.root_work_item_id || "").trim(),
|
|
@@ -9106,31 +9793,11 @@ async function processRunnerRouteOnce(route, runtime, mode, options = {}) {
|
|
|
9106
9793
|
};
|
|
9107
9794
|
}
|
|
9108
9795
|
|
|
9109
|
-
|
|
9110
|
-
await
|
|
9111
|
-
|
|
9112
|
-
|
|
9113
|
-
|
|
9114
|
-
bot,
|
|
9115
|
-
archiveThread,
|
|
9116
|
-
runtime,
|
|
9117
|
-
});
|
|
9118
|
-
const lastSkipped = skippedRecords[skippedRecords.length - 1];
|
|
9119
|
-
const distinctReasons = Array.from(new Set(skippedRecords.map((item) => item.reason).filter(Boolean)));
|
|
9120
|
-
return {
|
|
9121
|
-
route_key: routeKey,
|
|
9122
|
-
route_name: normalizedRoute.name,
|
|
9123
|
-
logical_signature: runnerRouteLogicalSignature(normalizedRoute),
|
|
9124
|
-
outcome: "skipped",
|
|
9125
|
-
detail: distinctReasons.join("; ") || "all pending messages were skipped",
|
|
9126
|
-
archive_source: String(archiveThread.source || "").trim() || "-",
|
|
9127
|
-
archive_work_item_id: String(archiveThread.workItemID || "").trim() || "",
|
|
9128
|
-
thread_id: archiveThread.threadID,
|
|
9129
|
-
comment_id: lastSkipped.id,
|
|
9130
|
-
skipped_count: skippedRecords.length,
|
|
9131
|
-
execution_mode: executionPlan.mode,
|
|
9132
|
-
role_profile: executionPlan.roleProfileName,
|
|
9133
|
-
};
|
|
9796
|
+
{
|
|
9797
|
+
const skippedOutcome = await finalizeSkippedPendingRecords(skippedRecords);
|
|
9798
|
+
if (skippedOutcome) {
|
|
9799
|
+
return skippedOutcome;
|
|
9800
|
+
}
|
|
9134
9801
|
}
|
|
9135
9802
|
|
|
9136
9803
|
return {
|
|
@@ -10353,70 +11020,40 @@ function buildRunnerShowPayload(route, flags = {}) {
|
|
|
10353
11020
|
const resolvedServerBotName = firstNonEmptyString([
|
|
10354
11021
|
normalizedRoute.botName,
|
|
10355
11022
|
matchedTelegramEntry?.serverBotName,
|
|
10356
|
-
"-",
|
|
10357
|
-
]);
|
|
10358
|
-
const envConfig = normalizedRoute.provider
|
|
10359
|
-
? loadProviderEnvConfig(normalizedRoute.provider, {
|
|
10360
|
-
|
|
10361
|
-
|
|
10362
|
-
|
|
10363
|
-
|
|
10364
|
-
: null;
|
|
10365
|
-
|
|
10366
|
-
|
|
10367
|
-
|
|
10368
|
-
|
|
10369
|
-
|
|
10370
|
-
|
|
10371
|
-
|
|
10372
|
-
|
|
10373
|
-
|
|
10374
|
-
|
|
10375
|
-
|
|
10376
|
-
|
|
10377
|
-
|
|
10378
|
-
|
|
10379
|
-
|
|
10380
|
-
|
|
10381
|
-
|
|
10382
|
-
|
|
10383
|
-
|
|
10384
|
-
|
|
10385
|
-
|
|
10386
|
-
workspace_source: diagnostics.workspaceSource || "-",
|
|
10387
|
-
},
|
|
10388
|
-
execution_profile: {
|
|
10389
|
-
route_role: normalizedRoute.role || "-",
|
|
10390
|
-
role_profile_name: diagnostics.roleProfileName || "-",
|
|
10391
|
-
client: String(diagnostics.roleProfile?.client || "").trim() || "-",
|
|
10392
|
-
model: String(diagnostics.roleProfile?.model || "").trim() || "-",
|
|
10393
|
-
permission_mode: String(diagnostics.roleProfile?.permissionMode || "").trim() || "-",
|
|
10394
|
-
reasoning_effort: String(diagnostics.roleProfile?.reasoningEffort || "").trim() || "-",
|
|
10395
|
-
},
|
|
10396
|
-
last_run: {
|
|
10397
|
-
action: String(routeState.last_action || "").trim() || "-",
|
|
10398
|
-
reason: String(routeState.last_reason || "").trim() || "-",
|
|
10399
|
-
intent_type: String(routeState.last_intent_type || "").trim() || "-",
|
|
10400
|
-
workspace_dir: String(routeState.last_workspace_dir || "").trim() || "-",
|
|
10401
|
-
artifact_validation: String(routeState.last_artifact_validation || "").trim() || "-",
|
|
10402
|
-
artifact_paths: ensureArray(routeState.last_artifact_paths).map((item) => String(item || "").trim()).filter(Boolean),
|
|
10403
|
-
artifact_errors: ensureArray(routeState.last_artifact_errors).map((item) => String(item || "").trim()).filter(Boolean),
|
|
10404
|
-
boundary_violations: ensureArray(routeState.last_boundary_violations).map((item) => safeObject(item)),
|
|
10405
|
-
},
|
|
10406
|
-
active_execution: {
|
|
10407
|
-
active: activeExecutionState.active === true,
|
|
10408
|
-
stale: activeExecutionState.stale === true,
|
|
10409
|
-
stuck: activeExecutionState.stuck === true,
|
|
10410
|
-
comment_id: String(activeExecutionState.commentID || "").trim(),
|
|
10411
|
-
source_message_id: intFromRawAllowZero(activeExecutionState.sourceMessageID, 0),
|
|
10412
|
-
started_at: String(activeExecutionState.startedAt || "").trim(),
|
|
10413
|
-
age_seconds: intFromRawAllowZero(activeExecutionState.ageSeconds, 0),
|
|
10414
|
-
warning: String(activeExecutionState.warning || "").trim(),
|
|
10415
|
-
},
|
|
11023
|
+
"-",
|
|
11024
|
+
]);
|
|
11025
|
+
const envConfig = normalizedRoute.provider
|
|
11026
|
+
? loadProviderEnvConfig(normalizedRoute.provider, {
|
|
11027
|
+
botID: normalizedRoute.botID,
|
|
11028
|
+
botName: resolvedServerBotName !== "-" ? resolvedServerBotName : "",
|
|
11029
|
+
route: normalizedRoute,
|
|
11030
|
+
})
|
|
11031
|
+
: null;
|
|
11032
|
+
const lastRunSummary = buildRunnerRouteLastResultSummary(routeState);
|
|
11033
|
+
const lastRunPayload = buildRunnerShowLastRunPayload(lastRunSummary);
|
|
11034
|
+
const activeExecutionPayload = buildRunnerShowActiveExecutionPayload(activeExecutionState);
|
|
11035
|
+
const resolvedContext = buildRunnerShowResolvedContext({
|
|
11036
|
+
normalizedRoute,
|
|
11037
|
+
diagnostics,
|
|
11038
|
+
envConfig,
|
|
11039
|
+
resolvedServerBotName,
|
|
11040
|
+
botNameSource,
|
|
11041
|
+
});
|
|
11042
|
+
return {
|
|
11043
|
+
ok: diagnostics.errors.length === 0,
|
|
11044
|
+
route_name: normalizedRoute.name || runnerRouteKey(normalizedRoute),
|
|
11045
|
+
route_key: runnerRouteKey(normalizedRoute),
|
|
11046
|
+
logical_signature: runnerRouteLogicalSignature(normalizedRoute),
|
|
11047
|
+
route_config_file: runnerConfig.filePath,
|
|
11048
|
+
workspace_registry_file: String(runnerConfig.workspaceRegistryFilePath || botRunnerWorkspaceRegistryFilePath()).trim() || "-",
|
|
11049
|
+
route_config: serializeRunnerRoute(normalizedRoute),
|
|
11050
|
+
...resolvedContext,
|
|
11051
|
+
last_run: lastRunPayload,
|
|
11052
|
+
active_execution: activeExecutionPayload,
|
|
10416
11053
|
route_selection_note: "Routes are the executable unit. Use --route-name in production. --bot-name and --bot-id are convenience selectors that resolve one enabled route only when the match is unique.",
|
|
10417
11054
|
warnings: [
|
|
10418
11055
|
...ensureArray(diagnostics.warnings),
|
|
10419
|
-
...(
|
|
11056
|
+
...(activeExecutionPayload.stuck && activeExecutionPayload.warning ? [activeExecutionPayload.warning] : []),
|
|
10420
11057
|
],
|
|
10421
11058
|
errors: diagnostics.errors,
|
|
10422
11059
|
};
|
|
@@ -10468,6 +11105,20 @@ async function runRunnerShow(flags) {
|
|
|
10468
11105
|
` action: ${payload.last_run.action}`,
|
|
10469
11106
|
` reason: ${payload.last_run.reason}`,
|
|
10470
11107
|
` intent_type: ${payload.last_run.intent_type}`,
|
|
11108
|
+
` ai_reply_preview: ${payload.last_run.ai_reply_preview}`,
|
|
11109
|
+
` execution_contract_type: ${payload.last_run.execution_contract_type}`,
|
|
11110
|
+
` execution_contract_targets: ${payload.last_run.execution_contract_targets.length ? payload.last_run.execution_contract_targets.join(", ") : "-"}`,
|
|
11111
|
+
` next_expected_responders: ${payload.last_run.next_expected_responders.length ? payload.last_run.next_expected_responders.join(", ") : "-"}`,
|
|
11112
|
+
` response_contract_validation_status: ${payload.last_run.response_contract_validation_status}`,
|
|
11113
|
+
` response_contract_validation_reason: ${payload.last_run.response_contract_validation_reason}`,
|
|
11114
|
+
` response_contract_validation_targets: ${payload.last_run.response_contract_validation_targets.length ? payload.last_run.response_contract_validation_targets.join(", ") : "-"}`,
|
|
11115
|
+
` assignment_validation_status: ${payload.last_run.assignment_validation_status}`,
|
|
11116
|
+
` assignment_validation_reason: ${payload.last_run.assignment_validation_reason}`,
|
|
11117
|
+
` assignment_validation_modes: ${payload.last_run.assignment_validation_modes.length ? payload.last_run.assignment_validation_modes.join(", ") : "-"}`,
|
|
11118
|
+
` delivery_status: ${payload.last_run.delivery_status}`,
|
|
11119
|
+
` archive_status: ${payload.last_run.archive_status}`,
|
|
11120
|
+
` transport_error: ${payload.last_run.transport_error}`,
|
|
11121
|
+
` archive_error: ${payload.last_run.archive_error}`,
|
|
10471
11122
|
` workspace_dir: ${payload.last_run.workspace_dir}`,
|
|
10472
11123
|
` artifact_validation: ${payload.last_run.artifact_validation}`,
|
|
10473
11124
|
` artifact_paths: ${payload.last_run.artifact_paths.length ? payload.last_run.artifact_paths.join(", ") : "-"}`,
|
|
@@ -11013,6 +11664,161 @@ function summarizeRunnerTUIPhases(routes = []) {
|
|
|
11013
11664
|
return { counts, warningCount };
|
|
11014
11665
|
}
|
|
11015
11666
|
|
|
11667
|
+
function buildRunnerTUISummaryLine(phaseSummary) {
|
|
11668
|
+
const summary = safeObject(phaseSummary);
|
|
11669
|
+
const counts = safeObject(summary.counts);
|
|
11670
|
+
return `Summary: waiting=${intFromRawAllowZero(counts.waiting, 0)} polling=${intFromRawAllowZero(counts.polling, 0)} running=${intFromRawAllowZero(counts.running, 0)} busy=${intFromRawAllowZero(counts.busy, 0)} replied=${intFromRawAllowZero(counts.replied, 0)} error=${intFromRawAllowZero(counts.error, 0)} warnings=${intFromRawAllowZero(summary.warningCount, 0)}`;
|
|
11671
|
+
}
|
|
11672
|
+
|
|
11673
|
+
function buildRunnerTUIRouteTableHeader() {
|
|
11674
|
+
return [
|
|
11675
|
+
bootstrapPadRight("Route", 24),
|
|
11676
|
+
bootstrapPadRight("Phase", 18),
|
|
11677
|
+
bootstrapPadRight("Age", 7),
|
|
11678
|
+
bootstrapPadRight("AI", 20),
|
|
11679
|
+
bootstrapPadRight("Intent", 18),
|
|
11680
|
+
bootstrapPadRight("Msg", 8),
|
|
11681
|
+
bootstrapPadRight("Next", 8),
|
|
11682
|
+
bootstrapPadRight("Warn", 6),
|
|
11683
|
+
].join(" ");
|
|
11684
|
+
}
|
|
11685
|
+
|
|
11686
|
+
function buildRunnerTUIRouteRow(route, now, useColor) {
|
|
11687
|
+
const currentRoute = safeObject(route);
|
|
11688
|
+
const phase = normalizeRunnerTUIPhase(currentRoute.phase);
|
|
11689
|
+
const aiLabel = truncateRunnerTUIText(
|
|
11690
|
+
currentRoute.client
|
|
11691
|
+
? `${String(currentRoute.client || "").trim()}/${String(currentRoute.model || "").trim() || "-"}`
|
|
11692
|
+
: "-",
|
|
11693
|
+
20,
|
|
11694
|
+
);
|
|
11695
|
+
const ageLabel = formatRunnerTUIAge(now, currentRoute.phase_started_at || currentRoute.updated_at || now);
|
|
11696
|
+
const nextSeconds = Number.isFinite(Number(currentRoute.next_run_at)) && Number(currentRoute.next_run_at) > now
|
|
11697
|
+
? `${Math.max(0, Math.ceil((Number(currentRoute.next_run_at) - now) / 1000))}s`
|
|
11698
|
+
: phase === "ai_running" || phase === "delivering" || phase === "context_suggesting"
|
|
11699
|
+
? "run"
|
|
11700
|
+
: "-";
|
|
11701
|
+
const warningLabel = String(currentRoute.warning || currentRoute.last_error || "").trim() ? "yes" : "-";
|
|
11702
|
+
return [
|
|
11703
|
+
bootstrapPadRight(truncateRunnerTUIText(currentRoute.route_name, 24), 24),
|
|
11704
|
+
colorizeRunnerTUIPhase(phase, 18, useColor),
|
|
11705
|
+
bootstrapPadRight(ageLabel, 7),
|
|
11706
|
+
bootstrapPadRight(aiLabel, 20),
|
|
11707
|
+
bootstrapPadRight(truncateRunnerTUIText(currentRoute.intent_type || "-", 18), 18),
|
|
11708
|
+
bootstrapPadRight(String(currentRoute.source_message_id || "-"), 8),
|
|
11709
|
+
bootstrapPadRight(nextSeconds, 8),
|
|
11710
|
+
bootstrapPadRight(warningLabel, 6),
|
|
11711
|
+
].join(" ");
|
|
11712
|
+
}
|
|
11713
|
+
|
|
11714
|
+
function buildRunnerTUIRouteDetailLine(route) {
|
|
11715
|
+
const currentRoute = safeObject(route);
|
|
11716
|
+
const detailParts = [
|
|
11717
|
+
String(currentRoute.detail || "").trim(),
|
|
11718
|
+
String(currentRoute.planner_client || "").trim() || String(currentRoute.planner_model || "").trim()
|
|
11719
|
+
? `planner=${String(currentRoute.planner_client || "").trim() || "-"}/${String(currentRoute.planner_model || "").trim() || "-"}`
|
|
11720
|
+
: "",
|
|
11721
|
+
String(currentRoute.context_suggestion_status || "").trim()
|
|
11722
|
+
? `context=${String(currentRoute.context_suggestion_status || "").trim()}`
|
|
11723
|
+
: "",
|
|
11724
|
+
String(currentRoute.warning || "").trim()
|
|
11725
|
+
? `warning=${String(currentRoute.warning || "").trim()}`
|
|
11726
|
+
: "",
|
|
11727
|
+
String(currentRoute.last_error || "").trim()
|
|
11728
|
+
? `error=${String(currentRoute.last_error || "").trim()}`
|
|
11729
|
+
: "",
|
|
11730
|
+
].filter(Boolean);
|
|
11731
|
+
return ` ${truncateRunnerTUIText(detailParts.join(" | ") || "-", 116)}`;
|
|
11732
|
+
}
|
|
11733
|
+
|
|
11734
|
+
function buildRunnerTUIRecentEventLine(event) {
|
|
11735
|
+
const currentEvent = safeObject(event);
|
|
11736
|
+
return ` [${String(currentEvent.time || "").trim() || "--:--:--"}] ${truncateRunnerTUIText(currentEvent.route_name, 24)} ${bootstrapPadRight(String(currentEvent.outcome || "-").trim(), 12)} ${truncateRunnerTUIText(currentEvent.detail || "-", 74)}`;
|
|
11737
|
+
}
|
|
11738
|
+
|
|
11739
|
+
function buildRunnerTUIRecentEvent(event, fallbackRouteName = "runner", fallbackOutcome = "-", fallbackDetail = "") {
|
|
11740
|
+
const currentEvent = safeObject(event);
|
|
11741
|
+
return {
|
|
11742
|
+
time: new Date().toLocaleTimeString("en-US", { hour12: false }),
|
|
11743
|
+
route_name: String(currentEvent.route_name || fallbackRouteName || "runner").trim(),
|
|
11744
|
+
outcome: String(currentEvent.outcome || fallbackOutcome || "-").trim(),
|
|
11745
|
+
detail: String(currentEvent.detail || fallbackDetail || "").trim(),
|
|
11746
|
+
};
|
|
11747
|
+
}
|
|
11748
|
+
|
|
11749
|
+
function buildRunnerTUIInitialRouteState(route) {
|
|
11750
|
+
const normalizedRoute = normalizeRunnerRoute(route);
|
|
11751
|
+
const routeKey = runnerRouteKey(normalizedRoute);
|
|
11752
|
+
const now = Date.now();
|
|
11753
|
+
return {
|
|
11754
|
+
route_key: routeKey,
|
|
11755
|
+
route_name: normalizedRoute.name,
|
|
11756
|
+
phase: "waiting",
|
|
11757
|
+
detail: "awaiting next poll",
|
|
11758
|
+
client: "",
|
|
11759
|
+
model: "",
|
|
11760
|
+
planner_client: "",
|
|
11761
|
+
planner_model: "",
|
|
11762
|
+
intent_type: "",
|
|
11763
|
+
source_message_id: "",
|
|
11764
|
+
next_run_at: 0,
|
|
11765
|
+
context_suggestion_status: "",
|
|
11766
|
+
warning: "",
|
|
11767
|
+
last_error: "",
|
|
11768
|
+
phase_started_at: now,
|
|
11769
|
+
updated_at: now,
|
|
11770
|
+
};
|
|
11771
|
+
}
|
|
11772
|
+
|
|
11773
|
+
function appendRunnerTUIRecentEvent(recentEvents, event, fallbackRouteName = "runner", fallbackOutcome = "-", fallbackDetail = "") {
|
|
11774
|
+
const nextEvents = ensureArray(recentEvents);
|
|
11775
|
+
nextEvents.unshift(buildRunnerTUIRecentEvent(event, fallbackRouteName, fallbackOutcome, fallbackDetail));
|
|
11776
|
+
if (nextEvents.length > 8) {
|
|
11777
|
+
nextEvents.length = 8;
|
|
11778
|
+
}
|
|
11779
|
+
}
|
|
11780
|
+
|
|
11781
|
+
function buildRunnerTUIRouteStatePatchFromResult(result, routeState = null, currentRouteState = null) {
|
|
11782
|
+
const current = safeObject(currentRouteState);
|
|
11783
|
+
const currentRouteSnapshot = safeObject(routeState);
|
|
11784
|
+
return {
|
|
11785
|
+
phase: mapRunnerTUIPhaseFromOutcome(result?.outcome),
|
|
11786
|
+
detail: String(result?.detail || "").trim(),
|
|
11787
|
+
intent_type: String(currentRouteSnapshot.last_intent_type || current.intent_type || "").trim(),
|
|
11788
|
+
source_message_id: intFromRawAllowZero(currentRouteSnapshot.last_source_message_id, intFromRawAllowZero(current.source_message_id, 0)) || current.source_message_id,
|
|
11789
|
+
context_suggestion_status: String(result?.context_suggestion_status || currentRouteSnapshot.last_context_suggestion_status || current.context_suggestion_status || "").trim(),
|
|
11790
|
+
warning: String(currentRouteSnapshot.active_execution_warning || result?.warning || "").trim(),
|
|
11791
|
+
last_error: String(currentRouteSnapshot.last_error || "").trim(),
|
|
11792
|
+
};
|
|
11793
|
+
}
|
|
11794
|
+
|
|
11795
|
+
function buildRunnerTUIRouteStatePatchFromExecutionStage({ executionPlan, selectedRecord, phase, detail, warning = "", contextSuggestionStatus = "", intentType = "" }) {
|
|
11796
|
+
const currentExecutionPlan = safeObject(executionPlan);
|
|
11797
|
+
const normalizedPhase = normalizeRunnerTUIPhase(phase);
|
|
11798
|
+
const clearLastError = ["ai_running", "delivering", "context_suggesting", "replied"].includes(normalizedPhase);
|
|
11799
|
+
const plannerFallbackClient = String(currentExecutionPlan.roleProfile?.client || "").trim();
|
|
11800
|
+
const plannerFallbackModel = String(currentExecutionPlan.roleProfile?.model || "").trim();
|
|
11801
|
+
const plannerClient = resolveRolePlannerClient({ env: process.env }) || plannerFallbackClient;
|
|
11802
|
+
const plannerModel = resolveRolePlannerModelDisplayName({
|
|
11803
|
+
env: process.env,
|
|
11804
|
+
fallbackClient: plannerFallbackClient,
|
|
11805
|
+
fallbackModel: plannerFallbackModel,
|
|
11806
|
+
});
|
|
11807
|
+
return {
|
|
11808
|
+
phase: normalizedPhase,
|
|
11809
|
+
detail: String(detail || "").trim(),
|
|
11810
|
+
client: plannerFallbackClient,
|
|
11811
|
+
model: plannerFallbackModel,
|
|
11812
|
+
planner_client: String(plannerClient || "").trim(),
|
|
11813
|
+
planner_model: String(plannerModel || "").trim(),
|
|
11814
|
+
source_message_id: intFromRawAllowZero(safeObject(selectedRecord).parsedArchive?.messageID, 0),
|
|
11815
|
+
intent_type: String(intentType || currentExecutionPlan.intentType || "").trim(),
|
|
11816
|
+
warning: String(warning || "").trim(),
|
|
11817
|
+
context_suggestion_status: String(contextSuggestionStatus || "").trim(),
|
|
11818
|
+
last_error: clearLastError ? "" : undefined,
|
|
11819
|
+
};
|
|
11820
|
+
}
|
|
11821
|
+
|
|
11016
11822
|
function buildRunnerTUIFrame({ routes = [], recentEvents = [], concurrency = 1, now = Date.now(), stopping = false, useColor = false, sourceLabel = "runner start", logFilePath = "" }) {
|
|
11017
11823
|
const lines = [];
|
|
11018
11824
|
const activeCount = ensureArray(routes).filter((item) => ["polling", "ai_running", "delivering", "context_suggesting", "busy"].includes(normalizeRunnerTUIPhase(item.phase))).length;
|
|
@@ -11022,65 +11828,14 @@ function buildRunnerTUIFrame({ routes = [], recentEvents = [], concurrency = 1,
|
|
|
11022
11828
|
if (String(logFilePath || "").trim()) {
|
|
11023
11829
|
lines.push(`Log: ${truncateRunnerTUIText(String(logFilePath || "").trim(), 112)}`);
|
|
11024
11830
|
}
|
|
11025
|
-
lines.push(
|
|
11831
|
+
lines.push(buildRunnerTUISummaryLine(phaseSummary));
|
|
11026
11832
|
lines.push("Ctrl+C to stop. Foreground runner state is shown below.");
|
|
11027
11833
|
lines.push("");
|
|
11028
|
-
lines.push(
|
|
11029
|
-
[
|
|
11030
|
-
bootstrapPadRight("Route", 24),
|
|
11031
|
-
bootstrapPadRight("Phase", 18),
|
|
11032
|
-
bootstrapPadRight("Age", 7),
|
|
11033
|
-
bootstrapPadRight("AI", 20),
|
|
11034
|
-
bootstrapPadRight("Intent", 18),
|
|
11035
|
-
bootstrapPadRight("Msg", 8),
|
|
11036
|
-
bootstrapPadRight("Next", 8),
|
|
11037
|
-
bootstrapPadRight("Warn", 6),
|
|
11038
|
-
].join(" "),
|
|
11039
|
-
);
|
|
11834
|
+
lines.push(buildRunnerTUIRouteTableHeader());
|
|
11040
11835
|
lines.push("-".repeat(120));
|
|
11041
11836
|
for (const route of ensureArray(routes)) {
|
|
11042
|
-
|
|
11043
|
-
|
|
11044
|
-
route.client
|
|
11045
|
-
? `${String(route.client || "").trim()}/${String(route.model || "").trim() || "-"}`
|
|
11046
|
-
: "-",
|
|
11047
|
-
20,
|
|
11048
|
-
);
|
|
11049
|
-
const ageLabel = formatRunnerTUIAge(now, route.phase_started_at || route.updated_at || now);
|
|
11050
|
-
const nextSeconds = Number.isFinite(Number(route.next_run_at)) && Number(route.next_run_at) > now
|
|
11051
|
-
? `${Math.max(0, Math.ceil((Number(route.next_run_at) - now) / 1000))}s`
|
|
11052
|
-
: phase === "ai_running" || phase === "delivering" || phase === "context_suggesting"
|
|
11053
|
-
? "run"
|
|
11054
|
-
: "-";
|
|
11055
|
-
const warningLabel = String(route.warning || route.last_error || "").trim() ? "yes" : "-";
|
|
11056
|
-
lines.push(
|
|
11057
|
-
[
|
|
11058
|
-
bootstrapPadRight(truncateRunnerTUIText(route.route_name, 24), 24),
|
|
11059
|
-
colorizeRunnerTUIPhase(phase, 18, useColor),
|
|
11060
|
-
bootstrapPadRight(ageLabel, 7),
|
|
11061
|
-
bootstrapPadRight(aiLabel, 20),
|
|
11062
|
-
bootstrapPadRight(truncateRunnerTUIText(route.intent_type || "-", 18), 18),
|
|
11063
|
-
bootstrapPadRight(String(route.source_message_id || "-"), 8),
|
|
11064
|
-
bootstrapPadRight(nextSeconds, 8),
|
|
11065
|
-
bootstrapPadRight(warningLabel, 6),
|
|
11066
|
-
].join(" "),
|
|
11067
|
-
);
|
|
11068
|
-
const detailParts = [
|
|
11069
|
-
String(route.detail || "").trim(),
|
|
11070
|
-
String(route.planner_client || "").trim() || String(route.planner_model || "").trim()
|
|
11071
|
-
? `planner=${String(route.planner_client || "").trim() || "-"}/${String(route.planner_model || "").trim() || "-"}`
|
|
11072
|
-
: "",
|
|
11073
|
-
String(route.context_suggestion_status || "").trim()
|
|
11074
|
-
? `context=${String(route.context_suggestion_status || "").trim()}`
|
|
11075
|
-
: "",
|
|
11076
|
-
String(route.warning || "").trim()
|
|
11077
|
-
? `warning=${String(route.warning || "").trim()}`
|
|
11078
|
-
: "",
|
|
11079
|
-
String(route.last_error || "").trim()
|
|
11080
|
-
? `error=${String(route.last_error || "").trim()}`
|
|
11081
|
-
: "",
|
|
11082
|
-
].filter(Boolean);
|
|
11083
|
-
lines.push(` ${truncateRunnerTUIText(detailParts.join(" | ") || "-", 116)}`);
|
|
11837
|
+
lines.push(buildRunnerTUIRouteRow(route, now, useColor));
|
|
11838
|
+
lines.push(buildRunnerTUIRouteDetailLine(route));
|
|
11084
11839
|
}
|
|
11085
11840
|
lines.push("");
|
|
11086
11841
|
lines.push(useColor ? bootstrapColorText("Recent Events", "35") : "Recent Events");
|
|
@@ -11088,9 +11843,7 @@ function buildRunnerTUIFrame({ routes = [], recentEvents = [], concurrency = 1,
|
|
|
11088
11843
|
lines.push(" (none yet)");
|
|
11089
11844
|
} else {
|
|
11090
11845
|
for (const event of ensureArray(recentEvents).slice(0, 8)) {
|
|
11091
|
-
lines.push(
|
|
11092
|
-
` [${String(event.time || "").trim() || "--:--:--"}] ${truncateRunnerTUIText(event.route_name, 24)} ${bootstrapPadRight(String(event.outcome || "-").trim(), 12)} ${truncateRunnerTUIText(event.detail || "-", 74)}`,
|
|
11093
|
-
);
|
|
11846
|
+
lines.push(buildRunnerTUIRecentEventLine(event));
|
|
11094
11847
|
}
|
|
11095
11848
|
}
|
|
11096
11849
|
return lines.join("\n");
|
|
@@ -11102,37 +11855,15 @@ function createRunnerStartTUI({ routes, flags, jsonMode, concurrency, sourceLabe
|
|
|
11102
11855
|
return null;
|
|
11103
11856
|
}
|
|
11104
11857
|
const useColor = bootstrapSupportsANSIColors();
|
|
11105
|
-
const routeStates = new Map(
|
|
11858
|
+
const routeStates = new Map(
|
|
11859
|
+
ensureArray(routes).map((route) => {
|
|
11860
|
+
const routeState = buildRunnerTUIInitialRouteState(route);
|
|
11861
|
+
return [routeState.route_key, routeState];
|
|
11862
|
+
}),
|
|
11863
|
+
);
|
|
11106
11864
|
const recentEvents = [];
|
|
11107
|
-
for (const route of ensureArray(routes)) {
|
|
11108
|
-
const normalizedRoute = normalizeRunnerRoute(route);
|
|
11109
|
-
const routeKey = runnerRouteKey(normalizedRoute);
|
|
11110
|
-
routeStates.set(routeKey, {
|
|
11111
|
-
route_key: routeKey,
|
|
11112
|
-
route_name: normalizedRoute.name,
|
|
11113
|
-
phase: "waiting",
|
|
11114
|
-
detail: "awaiting next poll",
|
|
11115
|
-
client: "",
|
|
11116
|
-
model: "",
|
|
11117
|
-
planner_client: "",
|
|
11118
|
-
planner_model: "",
|
|
11119
|
-
intent_type: "",
|
|
11120
|
-
source_message_id: "",
|
|
11121
|
-
next_run_at: 0,
|
|
11122
|
-
context_suggestion_status: "",
|
|
11123
|
-
warning: "",
|
|
11124
|
-
last_error: "",
|
|
11125
|
-
phase_started_at: Date.now(),
|
|
11126
|
-
updated_at: Date.now(),
|
|
11127
|
-
});
|
|
11128
|
-
}
|
|
11129
11865
|
if (bootstrapEvent && typeof bootstrapEvent === "object") {
|
|
11130
|
-
recentEvents.unshift(
|
|
11131
|
-
time: new Date().toLocaleTimeString("en-US", { hour12: false }),
|
|
11132
|
-
route_name: String(bootstrapEvent.route_name || sourceLabel || "runner").trim(),
|
|
11133
|
-
outcome: String(bootstrapEvent.outcome || "prepared").trim(),
|
|
11134
|
-
detail: String(bootstrapEvent.detail || "").trim(),
|
|
11135
|
-
});
|
|
11866
|
+
recentEvents.unshift(buildRunnerTUIRecentEvent(bootstrapEvent, sourceLabel, "prepared"));
|
|
11136
11867
|
}
|
|
11137
11868
|
let intervalHandle = null;
|
|
11138
11869
|
let disposed = false;
|
|
@@ -11171,57 +11902,27 @@ function createRunnerStartTUI({ routes, flags, jsonMode, concurrency, sourceLabe
|
|
|
11171
11902
|
const routeKey = String(result?.route_key || "").trim();
|
|
11172
11903
|
if (routeKey && routeStates.has(routeKey)) {
|
|
11173
11904
|
const current = safeObject(routeStates.get(routeKey));
|
|
11174
|
-
setRouteState(routeKey,
|
|
11175
|
-
phase: mapRunnerTUIPhaseFromOutcome(result?.outcome),
|
|
11176
|
-
detail: String(result?.detail || "").trim(),
|
|
11177
|
-
intent_type: String(routeState?.last_intent_type || current.intent_type || "").trim(),
|
|
11178
|
-
source_message_id: intFromRawAllowZero(routeState?.last_source_message_id, intFromRawAllowZero(current.source_message_id, 0)) || current.source_message_id,
|
|
11179
|
-
context_suggestion_status: String(result?.context_suggestion_status || routeState?.last_context_suggestion_status || current.context_suggestion_status || "").trim(),
|
|
11180
|
-
warning: String(safeObject(routeState).active_execution_warning || result?.warning || "").trim(),
|
|
11181
|
-
last_error: String(routeState?.last_error || "").trim(),
|
|
11182
|
-
});
|
|
11905
|
+
setRouteState(routeKey, buildRunnerTUIRouteStatePatchFromResult(result, routeState, current));
|
|
11183
11906
|
}
|
|
11184
11907
|
if (!result || ["idle", "busy"].includes(String(result.outcome || "").trim().toLowerCase())) {
|
|
11185
11908
|
return;
|
|
11186
11909
|
}
|
|
11187
|
-
recentEvents.
|
|
11188
|
-
time: new Date().toLocaleTimeString("en-US", { hour12: false }),
|
|
11189
|
-
route_name: String(result.route_name || result.route_key || "").trim(),
|
|
11190
|
-
outcome: String(result.outcome || "").trim(),
|
|
11191
|
-
detail: String(result.detail || "").trim(),
|
|
11192
|
-
});
|
|
11193
|
-
if (recentEvents.length > 8) {
|
|
11194
|
-
recentEvents.length = 8;
|
|
11195
|
-
}
|
|
11910
|
+
appendRunnerTUIRecentEvent(recentEvents, result, String(result.route_name || result.route_key || "").trim());
|
|
11196
11911
|
render(false);
|
|
11197
11912
|
};
|
|
11198
11913
|
|
|
11199
11914
|
const reportExecutionStage = ({ routeKey, executionPlan, selectedRecord, phase, detail, warning = "", contextSuggestionStatus = "", intentType = "" }) => {
|
|
11200
11915
|
const normalizedRouteKey = String(routeKey || "").trim();
|
|
11201
11916
|
if (!normalizedRouteKey || !routeStates.has(normalizedRouteKey)) return;
|
|
11202
|
-
|
|
11203
|
-
|
|
11204
|
-
|
|
11205
|
-
|
|
11206
|
-
|
|
11207
|
-
|
|
11208
|
-
|
|
11209
|
-
|
|
11210
|
-
|
|
11211
|
-
});
|
|
11212
|
-
setRouteState(normalizedRouteKey, {
|
|
11213
|
-
phase: normalizedPhase,
|
|
11214
|
-
detail: String(detail || "").trim(),
|
|
11215
|
-
client: plannerFallbackClient,
|
|
11216
|
-
model: plannerFallbackModel,
|
|
11217
|
-
planner_client: String(plannerClient || "").trim(),
|
|
11218
|
-
planner_model: String(plannerModel || "").trim(),
|
|
11219
|
-
source_message_id: intFromRawAllowZero(safeObject(selectedRecord).parsedArchive?.messageID, 0),
|
|
11220
|
-
intent_type: String(intentType || safeObject(executionPlan).intentType || "").trim(),
|
|
11221
|
-
warning: String(warning || "").trim(),
|
|
11222
|
-
context_suggestion_status: String(contextSuggestionStatus || "").trim(),
|
|
11223
|
-
last_error: clearLastError ? "" : undefined,
|
|
11224
|
-
});
|
|
11917
|
+
setRouteState(normalizedRouteKey, buildRunnerTUIRouteStatePatchFromExecutionStage({
|
|
11918
|
+
executionPlan,
|
|
11919
|
+
selectedRecord,
|
|
11920
|
+
phase,
|
|
11921
|
+
detail,
|
|
11922
|
+
warning,
|
|
11923
|
+
contextSuggestionStatus,
|
|
11924
|
+
intentType,
|
|
11925
|
+
}));
|
|
11225
11926
|
};
|
|
11226
11927
|
|
|
11227
11928
|
const updateNextRunAt = (routeKey, nextRunAt) => {
|
|
@@ -11248,6 +11949,550 @@ function createRunnerStartTUI({ routes, flags, jsonMode, concurrency, sourceLabe
|
|
|
11248
11949
|
};
|
|
11249
11950
|
}
|
|
11250
11951
|
|
|
11952
|
+
function beginRunnerStartRoutePoll({ routeKey, normalizedRoute, tui, runnerLogger }) {
|
|
11953
|
+
tui?.setRouteState(routeKey, {
|
|
11954
|
+
phase: "polling",
|
|
11955
|
+
detail: "checking inbound messages and archive thread",
|
|
11956
|
+
});
|
|
11957
|
+
runnerLogger?.append("route_poll", {
|
|
11958
|
+
route_key: routeKey,
|
|
11959
|
+
route_name: normalizedRoute.name,
|
|
11960
|
+
logical_signature: runnerRouteLogicalSignature(normalizedRoute),
|
|
11961
|
+
});
|
|
11962
|
+
}
|
|
11963
|
+
|
|
11964
|
+
function buildRunnerStartRouteResultLogPayload(result, routeKey, routeName) {
|
|
11965
|
+
return {
|
|
11966
|
+
route_key: String(result?.route_key || routeKey).trim(),
|
|
11967
|
+
route_name: String(result?.route_name || routeName || "").trim(),
|
|
11968
|
+
outcome: String(result?.outcome || "").trim(),
|
|
11969
|
+
detail: String(result?.detail || "").trim(),
|
|
11970
|
+
comment_id: String(result?.comment_id || "").trim(),
|
|
11971
|
+
};
|
|
11972
|
+
}
|
|
11973
|
+
|
|
11974
|
+
function publishRunnerStartRouteResult({ result, routeState = null, routeKey, routeName, runnerLogger, tui, jsonMode }) {
|
|
11975
|
+
runnerLogger?.append("route_result", buildRunnerStartRouteResultLogPayload(result, routeKey, routeName));
|
|
11976
|
+
if (tui) {
|
|
11977
|
+
tui.recordResult(result, routeState);
|
|
11978
|
+
return;
|
|
11979
|
+
}
|
|
11980
|
+
printRunnerResult("start", result, jsonMode);
|
|
11981
|
+
}
|
|
11982
|
+
|
|
11983
|
+
function buildRunnerStartCycleErrorResult({ normalizedRoute, routeKey, errorText, fatalArchiveBootstrapError = false }) {
|
|
11984
|
+
return {
|
|
11985
|
+
route_key: routeKey,
|
|
11986
|
+
route_name: normalizedRoute.name,
|
|
11987
|
+
logical_signature: runnerRouteLogicalSignature(normalizedRoute),
|
|
11988
|
+
outcome: fatalArchiveBootstrapError ? "blocked" : "error",
|
|
11989
|
+
detail: errorText,
|
|
11990
|
+
};
|
|
11991
|
+
}
|
|
11992
|
+
|
|
11993
|
+
function finalizeRunnerStartRouteCycle({ routeKey, normalizedRoute, cycleOutcome, schedules, tui }) {
|
|
11994
|
+
let routeState = safeObject(loadBotRunnerState().routes[routeKey]);
|
|
11995
|
+
let activeExecutionState = resolveRunnerActiveExecutionState(routeState);
|
|
11996
|
+
const successfulCycleOutcome = [
|
|
11997
|
+
"accepted",
|
|
11998
|
+
"busy",
|
|
11999
|
+
"idle",
|
|
12000
|
+
"primed",
|
|
12001
|
+
"skipped",
|
|
12002
|
+
"replied",
|
|
12003
|
+
"dry_run",
|
|
12004
|
+
"delivery_failed_after_generation",
|
|
12005
|
+
].includes(cycleOutcome);
|
|
12006
|
+
const shouldClearLastError = successfulCycleOutcome
|
|
12007
|
+
&& String(routeState.last_error || "").trim();
|
|
12008
|
+
const shouldClearStaleActiveExecution = !activeExecutionState.active
|
|
12009
|
+
&& successfulCycleOutcome
|
|
12010
|
+
&& String(routeState.active_comment_id || "").trim();
|
|
12011
|
+
if (shouldClearLastError || shouldClearStaleActiveExecution) {
|
|
12012
|
+
saveRunnerRouteState(routeKey, {
|
|
12013
|
+
...(shouldClearStaleActiveExecution ? emptyRunnerActiveExecutionPatch() : {}),
|
|
12014
|
+
...(shouldClearLastError ? { last_error: "" } : {}),
|
|
12015
|
+
});
|
|
12016
|
+
routeState = safeObject(loadBotRunnerState().routes[routeKey]);
|
|
12017
|
+
activeExecutionState = resolveRunnerActiveExecutionState(routeState);
|
|
12018
|
+
}
|
|
12019
|
+
tui?.setRouteState(routeKey, {
|
|
12020
|
+
intent_type: String(routeState.last_intent_type || "").trim(),
|
|
12021
|
+
source_message_id: intFromRawAllowZero(routeState.last_source_message_id, 0),
|
|
12022
|
+
warning: String(activeExecutionState.warning || "").trim(),
|
|
12023
|
+
last_error: String(routeState.last_error || "").trim(),
|
|
12024
|
+
});
|
|
12025
|
+
const lastErrorText = String(routeState.last_error || "").trim();
|
|
12026
|
+
const isFatalArchiveBootstrapError = lastErrorText.includes("Archive thread is missing")
|
|
12027
|
+
&& lastErrorText.includes("write access is denied");
|
|
12028
|
+
const nextRunAt = Date.now() + (isFatalArchiveBootstrapError
|
|
12029
|
+
? 60000
|
|
12030
|
+
: Math.max(1000, normalizedRoute.pollIntervalMs));
|
|
12031
|
+
schedules.set(routeKey, nextRunAt);
|
|
12032
|
+
tui?.updateNextRunAt(routeKey, nextRunAt);
|
|
12033
|
+
}
|
|
12034
|
+
|
|
12035
|
+
async function syncRunnerDeferredExecutionRunningState(deferredExecution) {
|
|
12036
|
+
if (!String(deferredExecution?.requestKey || "").trim()) {
|
|
12037
|
+
return;
|
|
12038
|
+
}
|
|
12039
|
+
markRunnerRequestLifecycle({
|
|
12040
|
+
normalizedRoute: deferredExecution.normalizedRoute,
|
|
12041
|
+
requestKey: deferredExecution.requestKey,
|
|
12042
|
+
selectedRecord: deferredExecution.selectedRecord,
|
|
12043
|
+
routeKey: deferredExecution.routeKey,
|
|
12044
|
+
outcome: "running",
|
|
12045
|
+
});
|
|
12046
|
+
const rootWorkItemSync = await syncRunnerRequestRootWorkItemForOutcome({
|
|
12047
|
+
normalizedRoute: deferredExecution.normalizedRoute,
|
|
12048
|
+
runtime: deferredExecution.runtime,
|
|
12049
|
+
requestKey: deferredExecution.requestKey,
|
|
12050
|
+
});
|
|
12051
|
+
const syncedRequest = safeObject(rootWorkItemSync.request);
|
|
12052
|
+
if (String(syncedRequest.root_work_item_id || "").trim()) {
|
|
12053
|
+
saveRunnerRouteState(deferredExecution.routeKey, {
|
|
12054
|
+
active_root_work_item_id: String(syncedRequest.root_work_item_id || "").trim(),
|
|
12055
|
+
active_root_work_item_title: String(syncedRequest.root_work_item_title || "").trim(),
|
|
12056
|
+
active_root_work_item_status: String(syncedRequest.root_work_item_status || "").trim(),
|
|
12057
|
+
last_root_work_item_id: String(syncedRequest.root_work_item_id || "").trim(),
|
|
12058
|
+
last_root_work_item_title: String(syncedRequest.root_work_item_title || "").trim(),
|
|
12059
|
+
last_root_work_item_status: String(syncedRequest.root_work_item_status || "").trim(),
|
|
12060
|
+
});
|
|
12061
|
+
}
|
|
12062
|
+
await syncRunnerRequestLedgerForProjectToServer({
|
|
12063
|
+
normalizedRoute: deferredExecution.normalizedRoute,
|
|
12064
|
+
runtime: deferredExecution.runtime,
|
|
12065
|
+
});
|
|
12066
|
+
}
|
|
12067
|
+
|
|
12068
|
+
async function finalizeRunnerDeferredExecutionSkipped(deferredExecution, processed) {
|
|
12069
|
+
if (String(deferredExecution?.requestKey || "").trim()) {
|
|
12070
|
+
markRunnerRequestLifecycle({
|
|
12071
|
+
normalizedRoute: deferredExecution.normalizedRoute,
|
|
12072
|
+
requestKey: deferredExecution.requestKey,
|
|
12073
|
+
selectedRecord: deferredExecution.selectedRecord,
|
|
12074
|
+
routeKey: deferredExecution.routeKey,
|
|
12075
|
+
outcome: "skipped",
|
|
12076
|
+
closedReason: String(processed?.skippedRecord?.reason || "skipped").trim() || "skipped",
|
|
12077
|
+
});
|
|
12078
|
+
const rootWorkItemSync = await syncRunnerRequestRootWorkItemForOutcome({
|
|
12079
|
+
normalizedRoute: deferredExecution.normalizedRoute,
|
|
12080
|
+
runtime: deferredExecution.runtime,
|
|
12081
|
+
requestKey: deferredExecution.requestKey,
|
|
12082
|
+
});
|
|
12083
|
+
const syncedRequest = safeObject(rootWorkItemSync.request);
|
|
12084
|
+
if (String(syncedRequest.root_work_item_id || "").trim()) {
|
|
12085
|
+
saveRunnerRouteState(deferredExecution.routeKey, {
|
|
12086
|
+
last_root_work_item_id: String(syncedRequest.root_work_item_id || "").trim(),
|
|
12087
|
+
last_root_work_item_title: String(syncedRequest.root_work_item_title || "").trim(),
|
|
12088
|
+
last_root_work_item_status: String(syncedRequest.root_work_item_status || "").trim(),
|
|
12089
|
+
});
|
|
12090
|
+
}
|
|
12091
|
+
await syncRunnerRequestLedgerForProjectToServer({
|
|
12092
|
+
normalizedRoute: deferredExecution.normalizedRoute,
|
|
12093
|
+
runtime: deferredExecution.runtime,
|
|
12094
|
+
});
|
|
12095
|
+
}
|
|
12096
|
+
return {
|
|
12097
|
+
route_key: deferredExecution.routeKey,
|
|
12098
|
+
route_name: deferredExecution.normalizedRoute.name,
|
|
12099
|
+
logical_signature: runnerRouteLogicalSignature(deferredExecution.normalizedRoute),
|
|
12100
|
+
outcome: "skipped",
|
|
12101
|
+
detail: String(processed?.skippedRecord?.reason || "trigger policy skipped message").trim(),
|
|
12102
|
+
archive_source: String(deferredExecution.archiveThread.source || "").trim() || "-",
|
|
12103
|
+
archive_work_item_id: String(deferredExecution.archiveThread.workItemID || "").trim() || "",
|
|
12104
|
+
thread_id: deferredExecution.archiveThread.threadID,
|
|
12105
|
+
comment_id: deferredExecution.selectedRecord.id,
|
|
12106
|
+
execution_mode: deferredExecution.executionPlan.mode,
|
|
12107
|
+
role_profile: deferredExecution.executionPlan.roleProfileName,
|
|
12108
|
+
};
|
|
12109
|
+
}
|
|
12110
|
+
|
|
12111
|
+
async function finalizeRunnerDeferredExecutionProcessed(deferredExecution, processed) {
|
|
12112
|
+
if (String(deferredExecution?.requestKey || "").trim()) {
|
|
12113
|
+
const resolvedIntentType = String(
|
|
12114
|
+
safeObject(loadBotRunnerState().routes[deferredExecution.routeKey]).last_intent_type || "",
|
|
12115
|
+
).trim();
|
|
12116
|
+
markRunnerRequestLifecycle({
|
|
12117
|
+
normalizedRoute: deferredExecution.normalizedRoute,
|
|
12118
|
+
requestKey: deferredExecution.requestKey,
|
|
12119
|
+
selectedRecord: deferredExecution.selectedRecord,
|
|
12120
|
+
routeKey: deferredExecution.routeKey,
|
|
12121
|
+
outcome: processed.kind === "delivery_failed"
|
|
12122
|
+
? "delivery_failed_after_generation"
|
|
12123
|
+
: String(processed.result?.outcome || "replied").trim().toLowerCase(),
|
|
12124
|
+
conversationIDRaw: String(processed.result?.conversation_id || "").trim(),
|
|
12125
|
+
conversationParticipants: ensureArray(processed.result?.conversation_participants),
|
|
12126
|
+
conversationInitialResponders: ensureArray(processed.result?.conversation_initial_responders),
|
|
12127
|
+
allowedResponders: ensureArray(processed.result?.conversation_allowed_responders),
|
|
12128
|
+
conversationLeadBot: String(processed.result?.conversation_lead_bot || "").trim(),
|
|
12129
|
+
conversationSummaryBot: String(processed.result?.conversation_summary_bot || "").trim(),
|
|
12130
|
+
conversationAllowBotToBot: processed.result?.conversation_allow_bot_to_bot === true,
|
|
12131
|
+
conversationReplyExpectation: String(processed.result?.conversation_reply_expectation || "").trim(),
|
|
12132
|
+
executionContractType: String(processed.result?.execution_contract_type || "").trim(),
|
|
12133
|
+
executionContractActionable: processed.result?.execution_contract_actionable === true,
|
|
12134
|
+
executionContractTargets: ensureArray(processed.result?.execution_contract_targets),
|
|
12135
|
+
nextExpectedResponders: ensureArray(processed.result?.next_expected_responders),
|
|
12136
|
+
normalizedExecutionContractType: String(processed.result?.normalized_execution_contract_type || "").trim(),
|
|
12137
|
+
normalizedExecutionContractTargets: ensureArray(processed.result?.normalized_execution_contract_targets),
|
|
12138
|
+
normalizedExecutionNextResponders: ensureArray(processed.result?.normalized_execution_next_responders),
|
|
12139
|
+
currentBotSelector: normalizeTelegramMentionUsername(
|
|
12140
|
+
deferredExecution.bot?.username || deferredExecution.bot?.name,
|
|
12141
|
+
),
|
|
12142
|
+
conversationIntentMode: String(processed.result?.conversation_intent_mode || "").trim(),
|
|
12143
|
+
normalizedIntent: resolvedIntentType,
|
|
12144
|
+
aiReplyGenerated: processed.result?.ai_reply_generated === true,
|
|
12145
|
+
aiReplyGeneratedAt: String(processed.result?.ai_reply_generated_at || "").trim(),
|
|
12146
|
+
aiReplyPreview: String(processed.result?.ai_reply_preview || "").trim(),
|
|
12147
|
+
responseContractValidationStatus: String(processed.result?.response_contract_validation_status || "").trim(),
|
|
12148
|
+
responseContractValidationReason: String(processed.result?.response_contract_validation_reason || "").trim(),
|
|
12149
|
+
responseContractValidationTargets: ensureArray(processed.result?.response_contract_validation_targets),
|
|
12150
|
+
assignmentValidationStatus: String(processed.result?.assignment_validation_status || "").trim(),
|
|
12151
|
+
assignmentValidationReason: String(processed.result?.assignment_validation_reason || "").trim(),
|
|
12152
|
+
assignmentValidationModes: ensureArray(processed.result?.assignment_validation_modes),
|
|
12153
|
+
deliveryStatus: String(processed.result?.delivery_status || "").trim(),
|
|
12154
|
+
archiveStatus: String(processed.result?.archive_status || "").trim(),
|
|
12155
|
+
transportError: String(processed.result?.transport_error || "").trim(),
|
|
12156
|
+
archiveError: String(processed.result?.archive_error || "").trim(),
|
|
12157
|
+
});
|
|
12158
|
+
if (processed.kind !== "delivery_failed") {
|
|
12159
|
+
await ensureRunnerRootWorkItemForRequest({
|
|
12160
|
+
normalizedRoute: deferredExecution.normalizedRoute,
|
|
12161
|
+
routeKey: deferredExecution.routeKey,
|
|
12162
|
+
selectedRecord: deferredExecution.selectedRecord,
|
|
12163
|
+
runtime: deferredExecution.runtime,
|
|
12164
|
+
requestKey: deferredExecution.requestKey,
|
|
12165
|
+
});
|
|
12166
|
+
}
|
|
12167
|
+
const rootWorkItemSync = await syncRunnerRequestRootWorkItemForOutcome({
|
|
12168
|
+
normalizedRoute: deferredExecution.normalizedRoute,
|
|
12169
|
+
runtime: deferredExecution.runtime,
|
|
12170
|
+
requestKey: deferredExecution.requestKey,
|
|
12171
|
+
});
|
|
12172
|
+
const syncedRequest = safeObject(rootWorkItemSync.request);
|
|
12173
|
+
const followupRoutePatch = buildRunnerRouteFollowupSnapshotPatch(
|
|
12174
|
+
deferredExecution.selectedRecord,
|
|
12175
|
+
processed.result,
|
|
12176
|
+
);
|
|
12177
|
+
if (String(syncedRequest.root_work_item_id || "").trim()) {
|
|
12178
|
+
saveRunnerRouteState(deferredExecution.routeKey, {
|
|
12179
|
+
last_root_work_item_id: String(syncedRequest.root_work_item_id || "").trim(),
|
|
12180
|
+
last_root_work_item_title: String(syncedRequest.root_work_item_title || "").trim(),
|
|
12181
|
+
last_root_work_item_status: String(syncedRequest.root_work_item_status || "").trim(),
|
|
12182
|
+
...followupRoutePatch,
|
|
12183
|
+
});
|
|
12184
|
+
} else if (Object.keys(followupRoutePatch).length) {
|
|
12185
|
+
saveRunnerRouteState(deferredExecution.routeKey, followupRoutePatch);
|
|
12186
|
+
}
|
|
12187
|
+
await syncRunnerRequestLedgerForProjectToServer({
|
|
12188
|
+
normalizedRoute: deferredExecution.normalizedRoute,
|
|
12189
|
+
runtime: deferredExecution.runtime,
|
|
12190
|
+
});
|
|
12191
|
+
}
|
|
12192
|
+
return {
|
|
12193
|
+
logical_signature: runnerRouteLogicalSignature(deferredExecution.normalizedRoute),
|
|
12194
|
+
archive_source: String(deferredExecution.archiveThread.source || "").trim() || "-",
|
|
12195
|
+
archive_work_item_id: String(deferredExecution.archiveThread.workItemID || "").trim() || "",
|
|
12196
|
+
...processed.result,
|
|
12197
|
+
};
|
|
12198
|
+
}
|
|
12199
|
+
|
|
12200
|
+
async function finalizeRunnerDeferredExecutionError(deferredExecution, errorText) {
|
|
12201
|
+
const currentRouteState = safeObject(loadBotRunnerState().routes[deferredExecution.routeKey]);
|
|
12202
|
+
saveRunnerRouteState(deferredExecution.routeKey, {
|
|
12203
|
+
...currentRouteState,
|
|
12204
|
+
...emptyRunnerActiveExecutionPatch(),
|
|
12205
|
+
last_error: errorText,
|
|
12206
|
+
});
|
|
12207
|
+
if (String(deferredExecution?.requestKey || "").trim()) {
|
|
12208
|
+
const currentRequest = safeObject(loadRunnerRequestByKey(deferredExecution.requestKey));
|
|
12209
|
+
const resolvedIntentType = String(
|
|
12210
|
+
safeObject(loadBotRunnerState().routes[deferredExecution.routeKey]).last_intent_type
|
|
12211
|
+
|| currentRequest.normalized_intent
|
|
12212
|
+
|| "",
|
|
12213
|
+
).trim();
|
|
12214
|
+
markRunnerRequestLifecycle({
|
|
12215
|
+
normalizedRoute: deferredExecution.normalizedRoute,
|
|
12216
|
+
requestKey: deferredExecution.requestKey,
|
|
12217
|
+
selectedRecord: deferredExecution.selectedRecord,
|
|
12218
|
+
routeKey: deferredExecution.routeKey,
|
|
12219
|
+
outcome: "error",
|
|
12220
|
+
closedReason: errorText || "execution_error",
|
|
12221
|
+
normalizedIntent: resolvedIntentType,
|
|
12222
|
+
});
|
|
12223
|
+
await ensureRunnerRootWorkItemForRequest({
|
|
12224
|
+
normalizedRoute: deferredExecution.normalizedRoute,
|
|
12225
|
+
routeKey: deferredExecution.routeKey,
|
|
12226
|
+
selectedRecord: deferredExecution.selectedRecord,
|
|
12227
|
+
runtime: deferredExecution.runtime,
|
|
12228
|
+
requestKey: deferredExecution.requestKey,
|
|
12229
|
+
});
|
|
12230
|
+
const rootWorkItemSync = await syncRunnerRequestRootWorkItemForOutcome({
|
|
12231
|
+
normalizedRoute: deferredExecution.normalizedRoute,
|
|
12232
|
+
runtime: deferredExecution.runtime,
|
|
12233
|
+
requestKey: deferredExecution.requestKey,
|
|
12234
|
+
});
|
|
12235
|
+
const syncedRequest = safeObject(rootWorkItemSync.request);
|
|
12236
|
+
if (String(syncedRequest.root_work_item_id || "").trim()) {
|
|
12237
|
+
saveRunnerRouteState(deferredExecution.routeKey, {
|
|
12238
|
+
last_root_work_item_id: String(syncedRequest.root_work_item_id || "").trim(),
|
|
12239
|
+
last_root_work_item_title: String(syncedRequest.root_work_item_title || "").trim(),
|
|
12240
|
+
last_root_work_item_status: String(syncedRequest.root_work_item_status || "").trim(),
|
|
12241
|
+
});
|
|
12242
|
+
}
|
|
12243
|
+
await syncRunnerRequestLedgerForProjectToServer({
|
|
12244
|
+
normalizedRoute: deferredExecution.normalizedRoute,
|
|
12245
|
+
runtime: deferredExecution.runtime,
|
|
12246
|
+
});
|
|
12247
|
+
}
|
|
12248
|
+
return {
|
|
12249
|
+
route_key: deferredExecution.routeKey,
|
|
12250
|
+
route_name: deferredExecution.normalizedRoute.name,
|
|
12251
|
+
logical_signature: runnerRouteLogicalSignature(deferredExecution.normalizedRoute),
|
|
12252
|
+
outcome: "error",
|
|
12253
|
+
detail: errorText,
|
|
12254
|
+
archive_source: String(deferredExecution.archiveThread.source || "").trim() || "-",
|
|
12255
|
+
archive_work_item_id: String(deferredExecution.archiveThread.workItemID || "").trim() || "",
|
|
12256
|
+
thread_id: deferredExecution.archiveThread.threadID,
|
|
12257
|
+
comment_id: deferredExecution.selectedRecord.id,
|
|
12258
|
+
};
|
|
12259
|
+
}
|
|
12260
|
+
|
|
12261
|
+
function reportRunnerDeferredExecutionAccepted({ deferredExecution, runnerLogger, tui }) {
|
|
12262
|
+
tui?.reportExecutionStage({
|
|
12263
|
+
routeKey: deferredExecution.routeKey,
|
|
12264
|
+
executionPlan: deferredExecution.executionPlan,
|
|
12265
|
+
selectedRecord: deferredExecution.selectedRecord,
|
|
12266
|
+
phase: "ai_running",
|
|
12267
|
+
detail: `running local AI client for comment ${String(deferredExecution.selectedRecord?.id || "").trim() || "-"}`,
|
|
12268
|
+
});
|
|
12269
|
+
runnerLogger?.append("execution_accepted", {
|
|
12270
|
+
route_key: deferredExecution.routeKey,
|
|
12271
|
+
route_name: deferredExecution.normalizedRoute?.name,
|
|
12272
|
+
comment_id: String(deferredExecution.selectedRecord?.id || "").trim(),
|
|
12273
|
+
source_message_id: intFromRawAllowZero(deferredExecution.selectedRecord?.parsedArchive?.messageID, 0),
|
|
12274
|
+
execution_mode: String(deferredExecution.executionPlan?.mode || "").trim(),
|
|
12275
|
+
role_profile: String(deferredExecution.executionPlan?.roleProfileName || "").trim(),
|
|
12276
|
+
});
|
|
12277
|
+
}
|
|
12278
|
+
|
|
12279
|
+
function createRunnerDeferredExecutionStageReporter({ deferredExecution, runnerLogger, tui }) {
|
|
12280
|
+
return (stage) => {
|
|
12281
|
+
runnerLogger?.append("execution_stage", {
|
|
12282
|
+
route_key: deferredExecution.routeKey,
|
|
12283
|
+
route_name: deferredExecution.normalizedRoute?.name,
|
|
12284
|
+
comment_id: String(deferredExecution.selectedRecord?.id || "").trim(),
|
|
12285
|
+
source_message_id: intFromRawAllowZero(deferredExecution.selectedRecord?.parsedArchive?.messageID, 0),
|
|
12286
|
+
phase: String(safeObject(stage).phase || "").trim(),
|
|
12287
|
+
detail: String(safeObject(stage).detail || "").trim(),
|
|
12288
|
+
intent_type: String(safeObject(stage).intentType || "").trim(),
|
|
12289
|
+
context_suggestion_status: String(safeObject(stage).contextSuggestionStatus || "").trim(),
|
|
12290
|
+
});
|
|
12291
|
+
tui?.reportExecutionStage({
|
|
12292
|
+
routeKey: deferredExecution.routeKey,
|
|
12293
|
+
executionPlan: deferredExecution.executionPlan,
|
|
12294
|
+
selectedRecord: deferredExecution.selectedRecord,
|
|
12295
|
+
...safeObject(stage),
|
|
12296
|
+
});
|
|
12297
|
+
};
|
|
12298
|
+
}
|
|
12299
|
+
|
|
12300
|
+
function publishRunnerDeferredExecutionFinalResult({
|
|
12301
|
+
deferredExecution,
|
|
12302
|
+
finalResult,
|
|
12303
|
+
runnerLogger,
|
|
12304
|
+
tui,
|
|
12305
|
+
jsonMode,
|
|
12306
|
+
}) {
|
|
12307
|
+
const latestRouteState = safeObject(loadBotRunnerState().routes[deferredExecution.routeKey]);
|
|
12308
|
+
runnerLogger?.append("execution_result", {
|
|
12309
|
+
route_key: String(finalResult?.route_key || deferredExecution.routeKey).trim(),
|
|
12310
|
+
route_name: String(finalResult?.route_name || deferredExecution.normalizedRoute?.name || "").trim(),
|
|
12311
|
+
outcome: String(finalResult?.outcome || "").trim(),
|
|
12312
|
+
detail: String(finalResult?.detail || "").trim(),
|
|
12313
|
+
comment_id: String(finalResult?.comment_id || deferredExecution.selectedRecord?.id || "").trim(),
|
|
12314
|
+
source_message_id: intFromRawAllowZero(
|
|
12315
|
+
latestRouteState?.last_source_message_id,
|
|
12316
|
+
intFromRawAllowZero(deferredExecution.selectedRecord?.parsedArchive?.messageID, 0),
|
|
12317
|
+
),
|
|
12318
|
+
intent_type: String(latestRouteState?.last_intent_type || "").trim(),
|
|
12319
|
+
context_suggestion_status: String(
|
|
12320
|
+
finalResult?.context_suggestion_status || latestRouteState?.last_context_suggestion_status || "",
|
|
12321
|
+
).trim(),
|
|
12322
|
+
});
|
|
12323
|
+
if (tui) {
|
|
12324
|
+
tui.recordResult(finalResult, latestRouteState);
|
|
12325
|
+
return;
|
|
12326
|
+
}
|
|
12327
|
+
printRunnerResult("start", finalResult, jsonMode);
|
|
12328
|
+
}
|
|
12329
|
+
|
|
12330
|
+
function handleRunnerStartRouteCycleError({
|
|
12331
|
+
normalizedRoute,
|
|
12332
|
+
routeKey,
|
|
12333
|
+
errorText,
|
|
12334
|
+
runnerLogger,
|
|
12335
|
+
tui,
|
|
12336
|
+
jsonMode,
|
|
12337
|
+
}) {
|
|
12338
|
+
const fatalArchiveBootstrapError = errorText.includes("Archive thread is missing")
|
|
12339
|
+
&& errorText.includes("write access is denied");
|
|
12340
|
+
saveRunnerRouteState(routeKey, {
|
|
12341
|
+
...safeObject(loadBotRunnerState().routes[routeKey]),
|
|
12342
|
+
last_error: errorText,
|
|
12343
|
+
});
|
|
12344
|
+
const result = buildRunnerStartCycleErrorResult({
|
|
12345
|
+
normalizedRoute,
|
|
12346
|
+
routeKey,
|
|
12347
|
+
errorText,
|
|
12348
|
+
fatalArchiveBootstrapError,
|
|
12349
|
+
});
|
|
12350
|
+
publishRunnerStartRouteResult({
|
|
12351
|
+
result,
|
|
12352
|
+
routeKey,
|
|
12353
|
+
routeName: normalizedRoute.name,
|
|
12354
|
+
runnerLogger,
|
|
12355
|
+
tui,
|
|
12356
|
+
jsonMode,
|
|
12357
|
+
});
|
|
12358
|
+
return fatalArchiveBootstrapError ? "blocked" : "error";
|
|
12359
|
+
}
|
|
12360
|
+
|
|
12361
|
+
function publishRunnerStartImmediateResult({
|
|
12362
|
+
result,
|
|
12363
|
+
routeKey,
|
|
12364
|
+
normalizedRoute,
|
|
12365
|
+
runnerLogger,
|
|
12366
|
+
tui,
|
|
12367
|
+
jsonMode,
|
|
12368
|
+
}) {
|
|
12369
|
+
publishRunnerStartRouteResult({
|
|
12370
|
+
result,
|
|
12371
|
+
routeKey,
|
|
12372
|
+
routeName: normalizedRoute.name,
|
|
12373
|
+
runnerLogger,
|
|
12374
|
+
tui,
|
|
12375
|
+
jsonMode,
|
|
12376
|
+
});
|
|
12377
|
+
}
|
|
12378
|
+
|
|
12379
|
+
function resolveRunnerStartDueRoutes(routes, schedules, now = Date.now()) {
|
|
12380
|
+
const dueRoutes = [];
|
|
12381
|
+
let nextSleepMs = 5000;
|
|
12382
|
+
for (const route of routes) {
|
|
12383
|
+
const normalizedRoute = normalizeRunnerRoute(route);
|
|
12384
|
+
const routeKey = runnerRouteKey(normalizedRoute);
|
|
12385
|
+
const nextAt = Number(schedules.get(routeKey) || 0);
|
|
12386
|
+
if (nextAt > now) {
|
|
12387
|
+
nextSleepMs = Math.min(nextSleepMs, Math.max(250, nextAt - now));
|
|
12388
|
+
continue;
|
|
12389
|
+
}
|
|
12390
|
+
dueRoutes.push(normalizedRoute);
|
|
12391
|
+
}
|
|
12392
|
+
return {
|
|
12393
|
+
dueRoutes,
|
|
12394
|
+
nextSleepMs,
|
|
12395
|
+
};
|
|
12396
|
+
}
|
|
12397
|
+
|
|
12398
|
+
function refreshRunnerStartNextSleepMs(routes, schedules, currentNextSleepMs, now = Date.now()) {
|
|
12399
|
+
let nextSleepMs = currentNextSleepMs;
|
|
12400
|
+
for (const route of routes) {
|
|
12401
|
+
const normalizedRoute = normalizeRunnerRoute(route);
|
|
12402
|
+
const routeKey = runnerRouteKey(normalizedRoute);
|
|
12403
|
+
const nextAt = Number(schedules.get(routeKey) || 0);
|
|
12404
|
+
if (nextAt > now) {
|
|
12405
|
+
nextSleepMs = Math.min(nextSleepMs, Math.max(250, nextAt - now));
|
|
12406
|
+
}
|
|
12407
|
+
}
|
|
12408
|
+
return nextSleepMs;
|
|
12409
|
+
}
|
|
12410
|
+
|
|
12411
|
+
function finalizeRunnerDeferredExecutionLoopState({
|
|
12412
|
+
deferredExecution,
|
|
12413
|
+
executionHeartbeat,
|
|
12414
|
+
inFlightExecutions,
|
|
12415
|
+
schedules,
|
|
12416
|
+
tui,
|
|
12417
|
+
}) {
|
|
12418
|
+
executionHeartbeat.stop();
|
|
12419
|
+
inFlightExecutions.delete(deferredExecution.routeKey);
|
|
12420
|
+
const nextRunAt = Date.now() + 250;
|
|
12421
|
+
schedules.set(deferredExecution.routeKey, nextRunAt);
|
|
12422
|
+
tui?.updateNextRunAt(deferredExecution.routeKey, nextRunAt);
|
|
12423
|
+
}
|
|
12424
|
+
|
|
12425
|
+
function createRunnerDeferredExecutionPromise({
|
|
12426
|
+
deferredExecution,
|
|
12427
|
+
executionHeartbeat,
|
|
12428
|
+
inFlightExecutions,
|
|
12429
|
+
schedules,
|
|
12430
|
+
tui,
|
|
12431
|
+
runnerLogger,
|
|
12432
|
+
jsonMode,
|
|
12433
|
+
reportRunnerStage,
|
|
12434
|
+
}) {
|
|
12435
|
+
return (async () => {
|
|
12436
|
+
try {
|
|
12437
|
+
const processed = await processRunnerSelectedRecord({
|
|
12438
|
+
routeKey: deferredExecution.routeKey,
|
|
12439
|
+
normalizedRoute: deferredExecution.normalizedRoute,
|
|
12440
|
+
routeState: deferredExecution.routeState,
|
|
12441
|
+
selectedRecord: deferredExecution.selectedRecord,
|
|
12442
|
+
pendingOrdered: deferredExecution.pendingOrdered,
|
|
12443
|
+
bot: deferredExecution.bot,
|
|
12444
|
+
destination: deferredExecution.destination,
|
|
12445
|
+
archiveThread: deferredExecution.archiveThread,
|
|
12446
|
+
executionPlan: deferredExecution.executionPlan,
|
|
12447
|
+
runtime: deferredExecution.runtime,
|
|
12448
|
+
triggerDecision: deferredExecution.triggerDecision,
|
|
12449
|
+
responderAdjudication: deferredExecution.responderAdjudication,
|
|
12450
|
+
persistedHumanIntentRequest: loadRunnerRequestByKey(deferredExecution.requestKey),
|
|
12451
|
+
precomputedHumanIntentContext: safeObject(deferredExecution.humanIntentContext),
|
|
12452
|
+
deps: {
|
|
12453
|
+
saveRunnerRouteState,
|
|
12454
|
+
startRunnerTypingHeartbeat,
|
|
12455
|
+
runRunnerAIExecution,
|
|
12456
|
+
explainExecutionFailureWithAI,
|
|
12457
|
+
performLocalBotDelivery,
|
|
12458
|
+
serializeRunnerTriggerPolicy,
|
|
12459
|
+
serializeRunnerArchivePolicy,
|
|
12460
|
+
buildRunnerExecutionDeps,
|
|
12461
|
+
buildRunnerDeliveryDeps,
|
|
12462
|
+
buildRunnerRuntimeDeps,
|
|
12463
|
+
managedConversationBots: deferredExecution.managedConversationBots,
|
|
12464
|
+
resolveConversationPeerBots: resolveRunnerConversationPeers,
|
|
12465
|
+
reportRunnerStage,
|
|
12466
|
+
},
|
|
12467
|
+
});
|
|
12468
|
+
if (processed.kind === "skipped") {
|
|
12469
|
+
return await finalizeRunnerDeferredExecutionSkipped(deferredExecution, processed);
|
|
12470
|
+
}
|
|
12471
|
+
return await finalizeRunnerDeferredExecutionProcessed(deferredExecution, processed);
|
|
12472
|
+
} catch (err) {
|
|
12473
|
+
const errorText = String(err?.message || err).trim();
|
|
12474
|
+
return await finalizeRunnerDeferredExecutionError(deferredExecution, errorText);
|
|
12475
|
+
} finally {
|
|
12476
|
+
finalizeRunnerDeferredExecutionLoopState({
|
|
12477
|
+
deferredExecution,
|
|
12478
|
+
executionHeartbeat,
|
|
12479
|
+
inFlightExecutions,
|
|
12480
|
+
schedules,
|
|
12481
|
+
tui,
|
|
12482
|
+
});
|
|
12483
|
+
}
|
|
12484
|
+
})().then((finalResult) => {
|
|
12485
|
+
publishRunnerDeferredExecutionFinalResult({
|
|
12486
|
+
deferredExecution,
|
|
12487
|
+
finalResult,
|
|
12488
|
+
runnerLogger,
|
|
12489
|
+
tui,
|
|
12490
|
+
jsonMode,
|
|
12491
|
+
});
|
|
12492
|
+
return finalResult;
|
|
12493
|
+
});
|
|
12494
|
+
}
|
|
12495
|
+
|
|
11251
12496
|
async function runRunnerStartResolvedRoutes(routes, flags, options = {}) {
|
|
11252
12497
|
const jsonMode = boolFromRaw(flags.json, false);
|
|
11253
12498
|
const sourceLabel = String(safeObject(options).sourceLabel || "runner start").trim() || "runner start";
|
|
@@ -11277,463 +12522,92 @@ async function runRunnerStartResolvedRoutes(routes, flags, options = {}) {
|
|
|
11277
12522
|
}
|
|
11278
12523
|
tui?.start();
|
|
11279
12524
|
while (!stopRequested) {
|
|
11280
|
-
const
|
|
11281
|
-
|
|
11282
|
-
let nextSleepMs = 5000;
|
|
11283
|
-
for (const route of routes) {
|
|
11284
|
-
const normalizedRoute = normalizeRunnerRoute(route);
|
|
11285
|
-
const routeKey = runnerRouteKey(normalizedRoute);
|
|
11286
|
-
const nextAt = Number(schedules.get(routeKey) || 0);
|
|
11287
|
-
if (nextAt > now) {
|
|
11288
|
-
nextSleepMs = Math.min(nextSleepMs, Math.max(250, nextAt - now));
|
|
11289
|
-
continue;
|
|
11290
|
-
}
|
|
11291
|
-
dueRoutes.push(normalizedRoute);
|
|
11292
|
-
}
|
|
12525
|
+
const { dueRoutes, nextSleepMs: initialNextSleepMs } = resolveRunnerStartDueRoutes(routes, schedules, Date.now());
|
|
12526
|
+
let nextSleepMs = initialNextSleepMs;
|
|
11293
12527
|
if (dueRoutes.length > 0) {
|
|
11294
12528
|
const runtime = await resolveRunnerContext(flags);
|
|
11295
12529
|
const dueRouteGroups = groupRunnerRoutesBySchedulingTarget(dueRoutes);
|
|
11296
12530
|
await runTasksWithConcurrencyLimit(dueRouteGroups, concurrency, async (routeGroup) => {
|
|
11297
12531
|
for (const normalizedRoute of ensureArray(routeGroup)) {
|
|
11298
12532
|
const routeKey = runnerRouteKey(normalizedRoute);
|
|
11299
|
-
|
|
11300
|
-
phase: "polling",
|
|
11301
|
-
detail: "checking inbound messages and archive thread",
|
|
11302
|
-
});
|
|
11303
|
-
runnerLogger?.append("route_poll", {
|
|
11304
|
-
route_key: routeKey,
|
|
11305
|
-
route_name: normalizedRoute.name,
|
|
11306
|
-
logical_signature: runnerRouteLogicalSignature(normalizedRoute),
|
|
11307
|
-
});
|
|
12533
|
+
beginRunnerStartRoutePoll({ routeKey, normalizedRoute, tui, runnerLogger });
|
|
11308
12534
|
let cycleOutcome = "polling";
|
|
11309
12535
|
try {
|
|
11310
12536
|
const result = await processRunnerRouteOnce(normalizedRoute, runtime, "start", { deferExecution: true });
|
|
11311
12537
|
cycleOutcome = String(result?.outcome || "").trim().toLowerCase() || "idle";
|
|
11312
12538
|
const deferredExecution = safeObject(result.deferred_execution);
|
|
11313
12539
|
if (deferredExecution.routeKey) {
|
|
11314
|
-
|
|
11315
|
-
|
|
11316
|
-
|
|
11317
|
-
|
|
11318
|
-
phase: "ai_running",
|
|
11319
|
-
detail: `running local AI client for comment ${String(deferredExecution.selectedRecord?.id || "").trim() || "-"}`,
|
|
11320
|
-
});
|
|
11321
|
-
runnerLogger?.append("execution_accepted", {
|
|
11322
|
-
route_key: deferredExecution.routeKey,
|
|
11323
|
-
route_name: deferredExecution.normalizedRoute?.name,
|
|
11324
|
-
comment_id: String(deferredExecution.selectedRecord?.id || "").trim(),
|
|
11325
|
-
source_message_id: intFromRawAllowZero(deferredExecution.selectedRecord?.parsedArchive?.messageID, 0),
|
|
11326
|
-
execution_mode: String(deferredExecution.executionPlan?.mode || "").trim(),
|
|
11327
|
-
role_profile: String(deferredExecution.executionPlan?.roleProfileName || "").trim(),
|
|
12540
|
+
reportRunnerDeferredExecutionAccepted({
|
|
12541
|
+
deferredExecution,
|
|
12542
|
+
runnerLogger,
|
|
12543
|
+
tui,
|
|
11328
12544
|
});
|
|
11329
12545
|
const executionHeartbeat = startRunnerExecutionHeartbeat(
|
|
11330
12546
|
deferredExecution.routeKey,
|
|
11331
12547
|
deferredExecution.selectedRecord,
|
|
11332
12548
|
);
|
|
11333
|
-
|
|
11334
|
-
|
|
11335
|
-
|
|
11336
|
-
|
|
11337
|
-
|
|
11338
|
-
routeKey: deferredExecution.routeKey,
|
|
11339
|
-
outcome: "running",
|
|
11340
|
-
});
|
|
11341
|
-
const rootWorkItemSync = await syncRunnerRequestRootWorkItemForOutcome({
|
|
11342
|
-
normalizedRoute: deferredExecution.normalizedRoute,
|
|
11343
|
-
runtime: deferredExecution.runtime,
|
|
11344
|
-
requestKey: deferredExecution.requestKey,
|
|
11345
|
-
});
|
|
11346
|
-
const syncedRequest = safeObject(rootWorkItemSync.request);
|
|
11347
|
-
if (String(syncedRequest.root_work_item_id || "").trim()) {
|
|
11348
|
-
saveRunnerRouteState(deferredExecution.routeKey, {
|
|
11349
|
-
active_root_work_item_id: String(syncedRequest.root_work_item_id || "").trim(),
|
|
11350
|
-
active_root_work_item_title: String(syncedRequest.root_work_item_title || "").trim(),
|
|
11351
|
-
active_root_work_item_status: String(syncedRequest.root_work_item_status || "").trim(),
|
|
11352
|
-
last_root_work_item_id: String(syncedRequest.root_work_item_id || "").trim(),
|
|
11353
|
-
last_root_work_item_title: String(syncedRequest.root_work_item_title || "").trim(),
|
|
11354
|
-
last_root_work_item_status: String(syncedRequest.root_work_item_status || "").trim(),
|
|
11355
|
-
});
|
|
11356
|
-
}
|
|
11357
|
-
await syncRunnerRequestLedgerForProjectToServer({
|
|
11358
|
-
normalizedRoute: deferredExecution.normalizedRoute,
|
|
11359
|
-
runtime: deferredExecution.runtime,
|
|
11360
|
-
});
|
|
11361
|
-
}
|
|
11362
|
-
const executionPromise = (async () => {
|
|
11363
|
-
try {
|
|
11364
|
-
const processed = await processRunnerSelectedRecord({
|
|
11365
|
-
routeKey: deferredExecution.routeKey,
|
|
11366
|
-
normalizedRoute: deferredExecution.normalizedRoute,
|
|
11367
|
-
routeState: deferredExecution.routeState,
|
|
11368
|
-
selectedRecord: deferredExecution.selectedRecord,
|
|
11369
|
-
pendingOrdered: deferredExecution.pendingOrdered,
|
|
11370
|
-
bot: deferredExecution.bot,
|
|
11371
|
-
destination: deferredExecution.destination,
|
|
11372
|
-
archiveThread: deferredExecution.archiveThread,
|
|
11373
|
-
executionPlan: deferredExecution.executionPlan,
|
|
11374
|
-
runtime: deferredExecution.runtime,
|
|
11375
|
-
triggerDecision: deferredExecution.triggerDecision,
|
|
11376
|
-
responderAdjudication: deferredExecution.responderAdjudication,
|
|
11377
|
-
persistedHumanIntentRequest: loadRunnerRequestByKey(deferredExecution.requestKey),
|
|
11378
|
-
precomputedHumanIntentContext: safeObject(deferredExecution.humanIntentContext),
|
|
11379
|
-
deps: {
|
|
11380
|
-
saveRunnerRouteState,
|
|
11381
|
-
startRunnerTypingHeartbeat,
|
|
11382
|
-
runRunnerAIExecution,
|
|
11383
|
-
explainExecutionFailureWithAI,
|
|
11384
|
-
performLocalBotDelivery,
|
|
11385
|
-
serializeRunnerTriggerPolicy,
|
|
11386
|
-
serializeRunnerArchivePolicy,
|
|
11387
|
-
buildRunnerExecutionDeps,
|
|
11388
|
-
buildRunnerDeliveryDeps,
|
|
11389
|
-
buildRunnerRuntimeDeps,
|
|
11390
|
-
managedConversationBots: deferredExecution.managedConversationBots,
|
|
11391
|
-
resolveConversationPeerBots: resolveRunnerConversationPeers,
|
|
11392
|
-
reportRunnerStage: (stage) => {
|
|
11393
|
-
runnerLogger?.append("execution_stage", {
|
|
11394
|
-
route_key: deferredExecution.routeKey,
|
|
11395
|
-
route_name: deferredExecution.normalizedRoute?.name,
|
|
11396
|
-
comment_id: String(deferredExecution.selectedRecord?.id || "").trim(),
|
|
11397
|
-
source_message_id: intFromRawAllowZero(deferredExecution.selectedRecord?.parsedArchive?.messageID, 0),
|
|
11398
|
-
phase: String(safeObject(stage).phase || "").trim(),
|
|
11399
|
-
detail: String(safeObject(stage).detail || "").trim(),
|
|
11400
|
-
intent_type: String(safeObject(stage).intentType || "").trim(),
|
|
11401
|
-
context_suggestion_status: String(safeObject(stage).contextSuggestionStatus || "").trim(),
|
|
11402
|
-
});
|
|
11403
|
-
tui?.reportExecutionStage({
|
|
11404
|
-
routeKey: deferredExecution.routeKey,
|
|
11405
|
-
executionPlan: deferredExecution.executionPlan,
|
|
11406
|
-
selectedRecord: deferredExecution.selectedRecord,
|
|
11407
|
-
...safeObject(stage),
|
|
11408
|
-
});
|
|
11409
|
-
},
|
|
11410
|
-
},
|
|
11411
|
-
});
|
|
11412
|
-
if (processed.kind === "skipped") {
|
|
11413
|
-
if (String(deferredExecution.requestKey || "").trim()) {
|
|
11414
|
-
markRunnerRequestLifecycle({
|
|
11415
|
-
normalizedRoute: deferredExecution.normalizedRoute,
|
|
11416
|
-
requestKey: deferredExecution.requestKey,
|
|
11417
|
-
selectedRecord: deferredExecution.selectedRecord,
|
|
11418
|
-
routeKey: deferredExecution.routeKey,
|
|
11419
|
-
outcome: "skipped",
|
|
11420
|
-
closedReason: String(processed.skippedRecord?.reason || "skipped").trim() || "skipped",
|
|
11421
|
-
});
|
|
11422
|
-
const rootWorkItemSync = await syncRunnerRequestRootWorkItemForOutcome({
|
|
11423
|
-
normalizedRoute: deferredExecution.normalizedRoute,
|
|
11424
|
-
runtime: deferredExecution.runtime,
|
|
11425
|
-
requestKey: deferredExecution.requestKey,
|
|
11426
|
-
});
|
|
11427
|
-
const syncedRequest = safeObject(rootWorkItemSync.request);
|
|
11428
|
-
if (String(syncedRequest.root_work_item_id || "").trim()) {
|
|
11429
|
-
saveRunnerRouteState(deferredExecution.routeKey, {
|
|
11430
|
-
last_root_work_item_id: String(syncedRequest.root_work_item_id || "").trim(),
|
|
11431
|
-
last_root_work_item_title: String(syncedRequest.root_work_item_title || "").trim(),
|
|
11432
|
-
last_root_work_item_status: String(syncedRequest.root_work_item_status || "").trim(),
|
|
11433
|
-
});
|
|
11434
|
-
}
|
|
11435
|
-
await syncRunnerRequestLedgerForProjectToServer({
|
|
11436
|
-
normalizedRoute: deferredExecution.normalizedRoute,
|
|
11437
|
-
runtime: deferredExecution.runtime,
|
|
11438
|
-
});
|
|
11439
|
-
}
|
|
11440
|
-
return {
|
|
11441
|
-
route_key: deferredExecution.routeKey,
|
|
11442
|
-
route_name: deferredExecution.normalizedRoute.name,
|
|
11443
|
-
logical_signature: runnerRouteLogicalSignature(deferredExecution.normalizedRoute),
|
|
11444
|
-
outcome: "skipped",
|
|
11445
|
-
detail: String(processed.skippedRecord?.reason || "trigger policy skipped message").trim(),
|
|
11446
|
-
archive_source: String(deferredExecution.archiveThread.source || "").trim() || "-",
|
|
11447
|
-
archive_work_item_id: String(deferredExecution.archiveThread.workItemID || "").trim() || "",
|
|
11448
|
-
thread_id: deferredExecution.archiveThread.threadID,
|
|
11449
|
-
comment_id: deferredExecution.selectedRecord.id,
|
|
11450
|
-
execution_mode: deferredExecution.executionPlan.mode,
|
|
11451
|
-
role_profile: deferredExecution.executionPlan.roleProfileName,
|
|
11452
|
-
};
|
|
11453
|
-
}
|
|
11454
|
-
if (String(deferredExecution.requestKey || "").trim()) {
|
|
11455
|
-
const resolvedIntentType = String(
|
|
11456
|
-
safeObject(loadBotRunnerState().routes[deferredExecution.routeKey]).last_intent_type || "",
|
|
11457
|
-
).trim();
|
|
11458
|
-
markRunnerRequestLifecycle({
|
|
11459
|
-
normalizedRoute: deferredExecution.normalizedRoute,
|
|
11460
|
-
requestKey: deferredExecution.requestKey,
|
|
11461
|
-
selectedRecord: deferredExecution.selectedRecord,
|
|
11462
|
-
routeKey: deferredExecution.routeKey,
|
|
11463
|
-
outcome: processed.kind === "delivery_failed"
|
|
11464
|
-
? "delivery_failed_after_generation"
|
|
11465
|
-
: String(processed.result?.outcome || "replied").trim().toLowerCase(),
|
|
11466
|
-
conversationIDRaw: String(processed.result?.conversation_id || "").trim(),
|
|
11467
|
-
conversationParticipants: ensureArray(processed.result?.conversation_participants),
|
|
11468
|
-
conversationInitialResponders: ensureArray(processed.result?.conversation_initial_responders),
|
|
11469
|
-
allowedResponders: ensureArray(processed.result?.conversation_allowed_responders),
|
|
11470
|
-
conversationLeadBot: String(processed.result?.conversation_lead_bot || "").trim(),
|
|
11471
|
-
conversationSummaryBot: String(processed.result?.conversation_summary_bot || "").trim(),
|
|
11472
|
-
conversationAllowBotToBot: processed.result?.conversation_allow_bot_to_bot === true,
|
|
11473
|
-
conversationReplyExpectation: String(processed.result?.conversation_reply_expectation || "").trim(),
|
|
11474
|
-
executionContractType: String(processed.result?.execution_contract_type || "").trim(),
|
|
11475
|
-
executionContractActionable: processed.result?.execution_contract_actionable === true,
|
|
11476
|
-
executionContractTargets: ensureArray(processed.result?.execution_contract_targets),
|
|
11477
|
-
nextExpectedResponders: ensureArray(processed.result?.next_expected_responders),
|
|
11478
|
-
normalizedExecutionContractType: String(processed.result?.normalized_execution_contract_type || "").trim(),
|
|
11479
|
-
normalizedExecutionContractTargets: ensureArray(processed.result?.normalized_execution_contract_targets),
|
|
11480
|
-
normalizedExecutionNextResponders: ensureArray(processed.result?.normalized_execution_next_responders),
|
|
11481
|
-
currentBotSelector: normalizeTelegramMentionUsername(
|
|
11482
|
-
deferredExecution.bot?.username || deferredExecution.bot?.name,
|
|
11483
|
-
),
|
|
11484
|
-
conversationIntentMode: String(processed.result?.conversation_intent_mode || "").trim(),
|
|
11485
|
-
normalizedIntent: resolvedIntentType,
|
|
11486
|
-
aiReplyGenerated: processed.result?.ai_reply_generated === true,
|
|
11487
|
-
aiReplyGeneratedAt: String(processed.result?.ai_reply_generated_at || "").trim(),
|
|
11488
|
-
aiReplyPreview: String(processed.result?.ai_reply_preview || "").trim(),
|
|
11489
|
-
responseContractValidationStatus: String(processed.result?.response_contract_validation_status || "").trim(),
|
|
11490
|
-
responseContractValidationReason: String(processed.result?.response_contract_validation_reason || "").trim(),
|
|
11491
|
-
responseContractValidationTargets: ensureArray(processed.result?.response_contract_validation_targets),
|
|
11492
|
-
assignmentValidationStatus: String(processed.result?.assignment_validation_status || "").trim(),
|
|
11493
|
-
assignmentValidationReason: String(processed.result?.assignment_validation_reason || "").trim(),
|
|
11494
|
-
assignmentValidationModes: ensureArray(processed.result?.assignment_validation_modes),
|
|
11495
|
-
deliveryStatus: String(processed.result?.delivery_status || "").trim(),
|
|
11496
|
-
archiveStatus: String(processed.result?.archive_status || "").trim(),
|
|
11497
|
-
transportError: String(processed.result?.transport_error || "").trim(),
|
|
11498
|
-
archiveError: String(processed.result?.archive_error || "").trim(),
|
|
11499
|
-
});
|
|
11500
|
-
if (processed.kind !== "delivery_failed") {
|
|
11501
|
-
await ensureRunnerRootWorkItemForRequest({
|
|
11502
|
-
normalizedRoute: deferredExecution.normalizedRoute,
|
|
11503
|
-
routeKey: deferredExecution.routeKey,
|
|
11504
|
-
selectedRecord: deferredExecution.selectedRecord,
|
|
11505
|
-
runtime: deferredExecution.runtime,
|
|
11506
|
-
requestKey: deferredExecution.requestKey,
|
|
11507
|
-
});
|
|
11508
|
-
}
|
|
11509
|
-
const rootWorkItemSync = await syncRunnerRequestRootWorkItemForOutcome({
|
|
11510
|
-
normalizedRoute: deferredExecution.normalizedRoute,
|
|
11511
|
-
runtime: deferredExecution.runtime,
|
|
11512
|
-
requestKey: deferredExecution.requestKey,
|
|
11513
|
-
});
|
|
11514
|
-
const syncedRequest = safeObject(rootWorkItemSync.request);
|
|
11515
|
-
if (String(syncedRequest.root_work_item_id || "").trim()) {
|
|
11516
|
-
saveRunnerRouteState(deferredExecution.routeKey, {
|
|
11517
|
-
last_root_work_item_id: String(syncedRequest.root_work_item_id || "").trim(),
|
|
11518
|
-
last_root_work_item_title: String(syncedRequest.root_work_item_title || "").trim(),
|
|
11519
|
-
last_root_work_item_status: String(syncedRequest.root_work_item_status || "").trim(),
|
|
11520
|
-
});
|
|
11521
|
-
}
|
|
11522
|
-
await syncRunnerRequestLedgerForProjectToServer({
|
|
11523
|
-
normalizedRoute: deferredExecution.normalizedRoute,
|
|
11524
|
-
runtime: deferredExecution.runtime,
|
|
11525
|
-
});
|
|
11526
|
-
}
|
|
11527
|
-
return {
|
|
11528
|
-
logical_signature: runnerRouteLogicalSignature(deferredExecution.normalizedRoute),
|
|
11529
|
-
archive_source: String(deferredExecution.archiveThread.source || "").trim() || "-",
|
|
11530
|
-
archive_work_item_id: String(deferredExecution.archiveThread.workItemID || "").trim() || "",
|
|
11531
|
-
...processed.result,
|
|
11532
|
-
};
|
|
11533
|
-
} catch (err) {
|
|
11534
|
-
const currentRouteState = safeObject(loadBotRunnerState().routes[deferredExecution.routeKey]);
|
|
11535
|
-
const errorText = String(err?.message || err).trim();
|
|
11536
|
-
saveRunnerRouteState(deferredExecution.routeKey, {
|
|
11537
|
-
...currentRouteState,
|
|
11538
|
-
...emptyRunnerActiveExecutionPatch(),
|
|
11539
|
-
last_error: errorText,
|
|
11540
|
-
});
|
|
11541
|
-
if (String(deferredExecution.requestKey || "").trim()) {
|
|
11542
|
-
const currentRequest = safeObject(loadRunnerRequestByKey(deferredExecution.requestKey));
|
|
11543
|
-
const resolvedIntentType = String(
|
|
11544
|
-
safeObject(loadBotRunnerState().routes[deferredExecution.routeKey]).last_intent_type
|
|
11545
|
-
|| currentRequest.normalized_intent
|
|
11546
|
-
|| "",
|
|
11547
|
-
).trim();
|
|
11548
|
-
markRunnerRequestLifecycle({
|
|
11549
|
-
normalizedRoute: deferredExecution.normalizedRoute,
|
|
11550
|
-
requestKey: deferredExecution.requestKey,
|
|
11551
|
-
selectedRecord: deferredExecution.selectedRecord,
|
|
11552
|
-
routeKey: deferredExecution.routeKey,
|
|
11553
|
-
outcome: "error",
|
|
11554
|
-
closedReason: errorText || "execution_error",
|
|
11555
|
-
normalizedIntent: resolvedIntentType,
|
|
11556
|
-
});
|
|
11557
|
-
await ensureRunnerRootWorkItemForRequest({
|
|
11558
|
-
normalizedRoute: deferredExecution.normalizedRoute,
|
|
11559
|
-
routeKey: deferredExecution.routeKey,
|
|
11560
|
-
selectedRecord: deferredExecution.selectedRecord,
|
|
11561
|
-
runtime: deferredExecution.runtime,
|
|
11562
|
-
requestKey: deferredExecution.requestKey,
|
|
11563
|
-
});
|
|
11564
|
-
const rootWorkItemSync = await syncRunnerRequestRootWorkItemForOutcome({
|
|
11565
|
-
normalizedRoute: deferredExecution.normalizedRoute,
|
|
11566
|
-
runtime: deferredExecution.runtime,
|
|
11567
|
-
requestKey: deferredExecution.requestKey,
|
|
11568
|
-
});
|
|
11569
|
-
const syncedRequest = safeObject(rootWorkItemSync.request);
|
|
11570
|
-
if (String(syncedRequest.root_work_item_id || "").trim()) {
|
|
11571
|
-
saveRunnerRouteState(deferredExecution.routeKey, {
|
|
11572
|
-
last_root_work_item_id: String(syncedRequest.root_work_item_id || "").trim(),
|
|
11573
|
-
last_root_work_item_title: String(syncedRequest.root_work_item_title || "").trim(),
|
|
11574
|
-
last_root_work_item_status: String(syncedRequest.root_work_item_status || "").trim(),
|
|
11575
|
-
});
|
|
11576
|
-
}
|
|
11577
|
-
await syncRunnerRequestLedgerForProjectToServer({
|
|
11578
|
-
normalizedRoute: deferredExecution.normalizedRoute,
|
|
11579
|
-
runtime: deferredExecution.runtime,
|
|
11580
|
-
});
|
|
11581
|
-
}
|
|
11582
|
-
return {
|
|
11583
|
-
route_key: deferredExecution.routeKey,
|
|
11584
|
-
route_name: deferredExecution.normalizedRoute.name,
|
|
11585
|
-
logical_signature: runnerRouteLogicalSignature(deferredExecution.normalizedRoute),
|
|
11586
|
-
outcome: "error",
|
|
11587
|
-
detail: errorText,
|
|
11588
|
-
archive_source: String(deferredExecution.archiveThread.source || "").trim() || "-",
|
|
11589
|
-
archive_work_item_id: String(deferredExecution.archiveThread.workItemID || "").trim() || "",
|
|
11590
|
-
thread_id: deferredExecution.archiveThread.threadID,
|
|
11591
|
-
comment_id: deferredExecution.selectedRecord.id,
|
|
11592
|
-
};
|
|
11593
|
-
} finally {
|
|
11594
|
-
executionHeartbeat.stop();
|
|
11595
|
-
inFlightExecutions.delete(deferredExecution.routeKey);
|
|
11596
|
-
schedules.set(deferredExecution.routeKey, Date.now() + 250);
|
|
11597
|
-
tui?.updateNextRunAt(deferredExecution.routeKey, Date.now() + 250);
|
|
11598
|
-
}
|
|
11599
|
-
})();
|
|
11600
|
-
inFlightExecutions.set(routeKey, executionPromise);
|
|
11601
|
-
executionPromise.then((finalResult) => {
|
|
11602
|
-
const latestRouteState = safeObject(loadBotRunnerState().routes[deferredExecution.routeKey]);
|
|
11603
|
-
runnerLogger?.append("execution_result", {
|
|
11604
|
-
route_key: String(finalResult?.route_key || deferredExecution.routeKey).trim(),
|
|
11605
|
-
route_name: String(finalResult?.route_name || deferredExecution.normalizedRoute?.name || "").trim(),
|
|
11606
|
-
outcome: String(finalResult?.outcome || "").trim(),
|
|
11607
|
-
detail: String(finalResult?.detail || "").trim(),
|
|
11608
|
-
comment_id: String(finalResult?.comment_id || deferredExecution.selectedRecord?.id || "").trim(),
|
|
11609
|
-
source_message_id: intFromRawAllowZero(latestRouteState?.last_source_message_id, intFromRawAllowZero(deferredExecution.selectedRecord?.parsedArchive?.messageID, 0)),
|
|
11610
|
-
intent_type: String(latestRouteState?.last_intent_type || "").trim(),
|
|
11611
|
-
context_suggestion_status: String(finalResult?.context_suggestion_status || latestRouteState?.last_context_suggestion_status || "").trim(),
|
|
11612
|
-
});
|
|
11613
|
-
if (tui) {
|
|
11614
|
-
tui.recordResult(finalResult, latestRouteState);
|
|
11615
|
-
} else {
|
|
11616
|
-
printRunnerResult("start", finalResult, jsonMode);
|
|
11617
|
-
}
|
|
12549
|
+
await syncRunnerDeferredExecutionRunningState(deferredExecution);
|
|
12550
|
+
const reportRunnerStage = createRunnerDeferredExecutionStageReporter({
|
|
12551
|
+
deferredExecution,
|
|
12552
|
+
runnerLogger,
|
|
12553
|
+
tui,
|
|
11618
12554
|
});
|
|
12555
|
+
const executionPromise = createRunnerDeferredExecutionPromise({
|
|
12556
|
+
deferredExecution,
|
|
12557
|
+
executionHeartbeat,
|
|
12558
|
+
inFlightExecutions,
|
|
12559
|
+
schedules,
|
|
12560
|
+
tui,
|
|
12561
|
+
runnerLogger,
|
|
12562
|
+
jsonMode,
|
|
12563
|
+
reportRunnerStage,
|
|
12564
|
+
});
|
|
12565
|
+
inFlightExecutions.set(routeKey, executionPromise);
|
|
11619
12566
|
const acceptedResult = {
|
|
11620
12567
|
...result,
|
|
11621
12568
|
deferred_execution: undefined,
|
|
11622
12569
|
};
|
|
11623
12570
|
cycleOutcome = String(acceptedResult?.outcome || "accepted").trim().toLowerCase() || "accepted";
|
|
11624
|
-
|
|
11625
|
-
|
|
11626
|
-
|
|
11627
|
-
|
|
11628
|
-
|
|
12571
|
+
publishRunnerStartImmediateResult({
|
|
12572
|
+
result: acceptedResult,
|
|
12573
|
+
routeKey,
|
|
12574
|
+
normalizedRoute,
|
|
12575
|
+
runnerLogger,
|
|
12576
|
+
tui,
|
|
12577
|
+
jsonMode,
|
|
11629
12578
|
});
|
|
11630
|
-
if (tui) {
|
|
11631
|
-
tui.recordResult(acceptedResult);
|
|
11632
|
-
} else {
|
|
11633
|
-
printRunnerResult("start", acceptedResult, jsonMode);
|
|
11634
|
-
}
|
|
11635
|
-
} else if (result.outcome !== "busy") {
|
|
11636
|
-
runnerLogger?.append("route_result", {
|
|
11637
|
-
route_key: String(result?.route_key || routeKey).trim(),
|
|
11638
|
-
route_name: String(result?.route_name || normalizedRoute.name || "").trim(),
|
|
11639
|
-
outcome: String(result?.outcome || "").trim(),
|
|
11640
|
-
detail: String(result?.detail || "").trim(),
|
|
11641
|
-
comment_id: String(result?.comment_id || "").trim(),
|
|
11642
|
-
});
|
|
11643
|
-
if (tui) {
|
|
11644
|
-
tui.recordResult(result);
|
|
11645
|
-
} else {
|
|
11646
|
-
printRunnerResult("start", result, jsonMode);
|
|
11647
|
-
}
|
|
11648
12579
|
} else {
|
|
11649
|
-
|
|
11650
|
-
|
|
11651
|
-
|
|
11652
|
-
|
|
11653
|
-
|
|
11654
|
-
|
|
12580
|
+
publishRunnerStartImmediateResult({
|
|
12581
|
+
result,
|
|
12582
|
+
routeKey,
|
|
12583
|
+
normalizedRoute,
|
|
12584
|
+
runnerLogger,
|
|
12585
|
+
tui,
|
|
12586
|
+
jsonMode,
|
|
11655
12587
|
});
|
|
11656
|
-
tui?.recordResult(result);
|
|
11657
12588
|
}
|
|
11658
12589
|
} catch (err) {
|
|
11659
|
-
|
|
11660
|
-
|
|
11661
|
-
|
|
11662
|
-
|
|
11663
|
-
|
|
11664
|
-
|
|
11665
|
-
|
|
11666
|
-
});
|
|
11667
|
-
const result = {
|
|
11668
|
-
route_key: routeKey,
|
|
11669
|
-
route_name: normalizedRoute.name,
|
|
11670
|
-
logical_signature: runnerRouteLogicalSignature(normalizedRoute),
|
|
11671
|
-
outcome: fatalArchiveBootstrapError ? "blocked" : "error",
|
|
11672
|
-
detail: errorText,
|
|
11673
|
-
};
|
|
11674
|
-
runnerLogger?.append("route_result", {
|
|
11675
|
-
route_key: routeKey,
|
|
11676
|
-
route_name: normalizedRoute.name,
|
|
11677
|
-
outcome: String(result.outcome || "error").trim(),
|
|
11678
|
-
detail: errorText,
|
|
12590
|
+
cycleOutcome = handleRunnerStartRouteCycleError({
|
|
12591
|
+
normalizedRoute,
|
|
12592
|
+
routeKey,
|
|
12593
|
+
errorText: String(err?.message || err),
|
|
12594
|
+
runnerLogger,
|
|
12595
|
+
tui,
|
|
12596
|
+
jsonMode,
|
|
11679
12597
|
});
|
|
11680
|
-
if (tui) {
|
|
11681
|
-
tui.recordResult(result);
|
|
11682
|
-
} else {
|
|
11683
|
-
printRunnerResult("start", result, jsonMode);
|
|
11684
|
-
}
|
|
11685
12598
|
} finally {
|
|
11686
|
-
|
|
11687
|
-
|
|
11688
|
-
|
|
11689
|
-
|
|
11690
|
-
|
|
11691
|
-
|
|
11692
|
-
"primed",
|
|
11693
|
-
"skipped",
|
|
11694
|
-
"replied",
|
|
11695
|
-
"dry_run",
|
|
11696
|
-
"delivery_failed_after_generation",
|
|
11697
|
-
].includes(cycleOutcome);
|
|
11698
|
-
const shouldClearLastError = successfulCycleOutcome
|
|
11699
|
-
&& String(routeState.last_error || "").trim();
|
|
11700
|
-
const shouldClearStaleActiveExecution = !activeExecutionState.active
|
|
11701
|
-
&& successfulCycleOutcome
|
|
11702
|
-
&& String(routeState.active_comment_id || "").trim();
|
|
11703
|
-
if (shouldClearLastError || shouldClearStaleActiveExecution) {
|
|
11704
|
-
saveRunnerRouteState(routeKey, {
|
|
11705
|
-
...(shouldClearStaleActiveExecution ? emptyRunnerActiveExecutionPatch() : {}),
|
|
11706
|
-
...(shouldClearLastError ? { last_error: "" } : {}),
|
|
11707
|
-
});
|
|
11708
|
-
routeState = safeObject(loadBotRunnerState().routes[routeKey]);
|
|
11709
|
-
activeExecutionState = resolveRunnerActiveExecutionState(routeState);
|
|
11710
|
-
}
|
|
11711
|
-
tui?.setRouteState(routeKey, {
|
|
11712
|
-
intent_type: String(routeState.last_intent_type || "").trim(),
|
|
11713
|
-
source_message_id: intFromRawAllowZero(routeState.last_source_message_id, 0),
|
|
11714
|
-
warning: String(activeExecutionState.warning || "").trim(),
|
|
11715
|
-
last_error: String(routeState.last_error || "").trim(),
|
|
12599
|
+
finalizeRunnerStartRouteCycle({
|
|
12600
|
+
routeKey,
|
|
12601
|
+
normalizedRoute,
|
|
12602
|
+
cycleOutcome,
|
|
12603
|
+
schedules,
|
|
12604
|
+
tui,
|
|
11716
12605
|
});
|
|
11717
|
-
const lastErrorText = String(routeState.last_error || "").trim();
|
|
11718
|
-
const isFatalArchiveBootstrapError = lastErrorText.includes("Archive thread is missing")
|
|
11719
|
-
&& lastErrorText.includes("write access is denied");
|
|
11720
|
-
const nextRunAt = Date.now() + (isFatalArchiveBootstrapError
|
|
11721
|
-
? 60000
|
|
11722
|
-
: Math.max(1000, normalizedRoute.pollIntervalMs));
|
|
11723
|
-
schedules.set(routeKey, nextRunAt);
|
|
11724
|
-
tui?.updateNextRunAt(routeKey, nextRunAt);
|
|
11725
12606
|
}
|
|
11726
12607
|
}
|
|
11727
12608
|
});
|
|
11728
12609
|
}
|
|
11729
|
-
|
|
11730
|
-
const normalizedRoute = normalizeRunnerRoute(route);
|
|
11731
|
-
const routeKey = runnerRouteKey(normalizedRoute);
|
|
11732
|
-
const nextAt = Number(schedules.get(routeKey) || 0);
|
|
11733
|
-
if (nextAt > Date.now()) {
|
|
11734
|
-
nextSleepMs = Math.min(nextSleepMs, Math.max(250, nextAt - Date.now()));
|
|
11735
|
-
}
|
|
11736
|
-
}
|
|
12610
|
+
nextSleepMs = refreshRunnerStartNextSleepMs(routes, schedules, nextSleepMs, Date.now());
|
|
11737
12611
|
if (!stopRequested) {
|
|
11738
12612
|
await sleep(Math.max(250, nextSleepMs));
|
|
11739
12613
|
}
|