feat(orchestrator): observe Page Data validation

This commit is contained in:
john
2026-07-25 14:16:57 +08:00
parent e02495a6c0
commit 417aa9c78b
17 changed files with 784 additions and 16 deletions
+154 -3
View File
@@ -111,6 +111,43 @@ function messageText(message) {
.join('\n');
}
function isPageDataWorkflowRequested(userMessage, taskType = null) {
const metadata = userMessage?.metadata ?? {};
const runMetadata = metadata?.[RUN_METADATA_KEY] ?? metadata?.agentRun ?? {};
const normalizedTaskType = String(
taskType ?? runMetadata?.taskType ?? metadata?.taskType ?? '',
).trim().toLowerCase();
const selectedSkill = String(
runMetadata?.selectedChatSkill ?? metadata?.selectedChatSkill ?? '',
).trim();
const displayText = String(metadata?.displayText ?? '').trim()
|| deriveUserFacingText(messageText(userMessage));
return runMetadata?.pgRequired === true
|| runMetadata?.pageDataAiderWorkflow === true
|| normalizedTaskType === 'page_data_dev'
|| normalizedTaskType === 'page_data_dev_complex'
|| selectedSkill === 'page-data-collect'
|| isPageDataIntent(displayText);
}
function pageDataFailureCheckId(code) {
switch (String(code ?? '').trim().toUpperCase()) {
case 'PAGE_DATA_DELIVERY_FAILED':
return 'page_data_binding';
case 'PAGE_DATA_DELIVERABLE_MISSING':
return 'page_data_deliverable';
case 'DELIVERABLE_DATA_STORAGE_FORBIDDEN':
return 'page_data_storage_policy';
case 'REQUIRED_REVIEW_EXECUTOR_MISMATCH':
case 'REQUIRED_EXECUTOR_UNAVAILABLE':
return 'independent_review';
case 'TOOL_GATEWAY_VALIDATION_FAILED':
return 'code_validation';
default:
return 'agent_run_completion';
}
}
function buildFreshSessionContext(conversation, { maxMessages = 16, maxChars = 12_000 } = {}) {
const visible = [];
for (const message of Array.isArray(conversation) ? conversation : []) {
@@ -394,6 +431,7 @@ function getRunOptionsFromMessage(userMessage) {
? String(runMetadata.reviewExecutor).trim().toLowerCase()
: null,
pageDataAiderWorkflow: runMetadata?.pageDataAiderWorkflow === true,
pgRequired: runMetadata?.pgRequired === true,
forceDeepReasoning: runMetadata?.forceDeepReasoning === true || metadata?.forceDeepReasoning === true,
validation: normalizeToolGatewayValidation(runMetadata?.validation ?? metadata?.toolGatewayValidation),
sessionMessageCount: normalizeSessionMessageCount(
@@ -475,6 +513,7 @@ export function createAgentRunGateway({
syncUserPagesOnSuccess = null,
observePersonalMemoryOnSuccess = null,
observeWorkflowRun = null,
observeWorkflowValidation = null,
isSessionExternallyBusy = null,
validateRunDeliverables = null,
quiesceSessionOnTerminal = null,
@@ -637,9 +676,78 @@ export function createAgentRunGateway({
logger: console,
});
const validationDispatcher = createShadowObservationDispatcher({
observe: observeWorkflowValidation,
maxConcurrent: maxConcurrentShadowObservations,
maxQueued: maxQueuedShadowObservations,
onCompleted: async (input, result, context) => {
if (!result?.observed) {
await appendEvent(input.runId, 'workflow_validation_observation_skipped', {
reason: result?.reason ?? 'shadow_validation_not_selected',
});
return;
}
await appendEvent(input.runId, 'workflow_validation_observation_completed', {
engine: result.engine ?? 'langgraph',
mode: result.mode ?? 'shadow',
configVersion: result.configVersion ?? null,
kind: result.validation?.kind ?? 'page-data-delivery',
verdict: result.validation?.verdict ?? null,
latencyMs: Math.max(0, nowMs() - context.enqueuedAt),
});
},
onFailed: async (input, error, context) => {
await appendEvent(input.runId, 'workflow_validation_observation_failed', {
code: String(error?.code ?? 'WORKFLOW_VALIDATION_OBSERVATION_FAILED').slice(0, 128),
message: String(error instanceof Error ? error.message : error).slice(0, 1000),
latencyMs: Math.max(0, nowMs() - context.enqueuedAt),
}).catch(() => {});
},
onSkipped: async (input, context) => {
await appendEvent(input.runId, 'workflow_validation_observation_skipped', {
reason: context.reason,
});
},
logger: console,
});
function dispatchShadowObservation(input) {
if (input.toolMode !== 'code') return;
shadowDispatcher.dispatch(input);
const pageDataRequired = isPageDataWorkflowRequested(input.userMessage, input.taskType);
if (input.toolMode !== 'code' && !pageDataRequired) return;
shadowDispatcher.dispatch({
...input,
taskType: input.taskType || (pageDataRequired ? 'page_data_dev' : null),
pageDataRequired,
});
}
function dispatchPageDataValidationObservation({
row,
runId,
checks,
metrics = null,
}) {
const userMessage = parseDbJsonColumn(row?.user_message_json, {}) ?? {};
const runOptions = getRunOptionsFromMessage(userMessage);
if (!isPageDataWorkflowRequested(userMessage, runOptions.taskType)) return false;
return validationDispatcher.dispatch({
runId,
requestId: row?.request_id ?? null,
userId: row?.user_id ?? null,
workflowName: 'code-run-v1',
observation: {
idempotencyKey: `${runId}:page-data-delivery:v1`,
taskType: runOptions.taskType || 'page_data_dev',
required: true,
checks,
metrics: {
pageCount: Number(metrics?.pageCount ?? 0),
publicationCount: Number(metrics?.publicationCount ?? 0),
},
source: 'portal-agent-run',
observedAt: nowMs(),
},
});
}
async function appendRunSnapshot(runId) {
@@ -1464,6 +1572,8 @@ export function createAgentRunGateway({
}, { expectedStatus: 'running' });
return;
}
const userMessage = parseDbJsonColumn(row.user_message_json, {}) ?? {};
const runOptions = getRunOptionsFromMessage(userMessage);
assertRequiredImageGenerationCompleted(row, routing, toolEvidence);
// `row` was loaded before this worker claimed the run, so its started_at
// can still be null. Refresh it before scoping workspace files to the
@@ -1490,7 +1600,8 @@ export function createAgentRunGateway({
}
const runDisplayText = extractRunDisplayText(row);
const selectedSkill = selectedRunSkill(row);
const pageDataIntent = isPageDataIntent(runDisplayText)
const pageDataIntent = isPageDataWorkflowRequested(userMessage, runOptions.taskType)
|| isPageDataIntent(runDisplayText)
|| selectedSkill === 'page-data-collect'
|| routing?.suggestedSkill === 'page-data-collect';
const pageGenerationIntent = isPageGenerationIntent(runDisplayText)
@@ -1557,6 +1668,35 @@ export function createAgentRunGateway({
error_message: null,
}, { expectedStatus: 'running' });
if (!marked) return false;
if (pageDataIntent) {
dispatchPageDataValidationObservation({
row,
runId,
checks: [
{ id: 'agent_run_completion', status: 'passed' },
{
id: 'page_data_binding',
status: typeof syncUserPagesOnSuccess === 'function' ? 'passed' : 'skipped',
},
{
id: 'page_data_storage_policy',
status: typeof validateRunDeliverables === 'function' ? 'passed' : 'skipped',
},
{
id: 'page_data_deliverable',
status: requiresPageDeliverable ? 'passed' : 'skipped',
},
{
id: 'independent_review',
status: runOptions.reviewExecutor ? 'passed' : 'skipped',
},
],
metrics: {
pageCount: deliverables?.pageCount ?? 0,
publicationCount: deliverables?.publicationCount ?? 0,
},
});
}
if (typeof observePersonalMemoryOnSuccess === 'function') {
await observePersonalMemoryOnSuccess({
userId: row.user_id,
@@ -1639,6 +1779,17 @@ export function createAgentRunGateway({
}
: {}),
}, { expectedStatus: 'running' });
if (!retryable) {
dispatchPageDataValidationObservation({
row,
runId,
checks: [{
id: pageDataFailureCheckId(err?.code),
status: 'failed',
codes: [String(err?.code ?? 'AGENT_RUN_FAILED')],
}],
});
}
if (retryable && autoDispatch) {
setTimeout(() => dispatchRun(runId), retryDelaysMs[nextAttempt - 1]);
}