fix(agent): restore active-task routing and active-mode validation observation
Memind CI / Test, build, and release guards (push) Successful in 5m23s

Keep correction follow-ups on Agent using session transcript and active task
context, and let Page Data validation reach Orchestrator when mode is active
instead of requiring shadowEngine.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-08-27 12:15:15 +08:00
parent f95d766f69
commit aecde46ff6
6 changed files with 662 additions and 20 deletions
+118 -3
View File
@@ -3,7 +3,7 @@ import fs from 'node:fs/promises';
import path from 'node:path';
import { isRunStreamReplayEnabled } from './agent-run-stream.mjs';
import { isDirectChatSessionId } from './direct-chat-service.mjs';
import { CHAT_INTENT_ROUTE, resolveGatewayAgentSessionId, resolveLegacyRouteFromClassification, logRouterDecisionShadow } from './chat-intent-router.mjs';
import { CHAT_INTENT_ROUTE, formatRouterTranscript, resolveGatewayAgentSessionId, resolveLegacyRouteFromClassification, logRouterDecisionShadow } from './chat-intent-router.mjs';
import { resolveSessionAccess } from './session-broker.mjs';
import {
loadSnapshotMessages,
@@ -617,6 +617,103 @@ function resolveEffectiveToolMode(runOptions) {
return runOptions?.pageDataAiderWorkflow ? 'chat' : (runOptions?.toolMode ?? 'chat');
}
const ACTIVE_TASK_CONTEXT_MAX_AGE_MS = 4 * 60 * 60 * 1000;
function parseIntentRoutedEvent(dataJson) {
if (!dataJson) return null;
const payload = typeof dataJson === 'string'
? (() => {
try {
return JSON.parse(dataJson);
} catch {
return null;
}
})()
: dataJson;
if (!payload || typeof payload !== 'object') return null;
return {
route: payload.route ?? payload.decision?.route ?? null,
suggestedSkill: payload.suggestedSkill ?? payload.suggested_skill ?? null,
reason: payload.reason ?? null,
};
}
export async function resolveActiveTaskContext(pool, {
userId,
sessionId,
excludeRunId = null,
nowMs: nowMsFn = Date.now,
} = {}) {
if (!pool || !userId || !sessionId || isDirectChatSessionId(sessionId)) {
return null;
}
const params = [userId, sessionId];
let excludeClause = '';
if (excludeRunId) {
excludeClause = ' AND r.id <> ?';
params.push(excludeRunId);
}
const [rows] = await pool.query(
`SELECT r.id, r.status, r.error_message, r.created_at, r.updated_at,
(
SELECT e.data_json
FROM h5_agent_run_events e
WHERE e.run_id = r.id AND e.event_type = 'intent_routed'
ORDER BY e.created_at ASC
LIMIT 1
) AS intent_json
FROM h5_agent_runs r
WHERE r.user_id = ? AND r.agent_session_id = ?${excludeClause}
ORDER BY r.created_at DESC
LIMIT 1`,
params,
);
const row = rows?.[0];
if (!row) return null;
const intent = parseIntentRoutedEvent(row.intent_json);
const legacyRoute = String(intent?.route ?? '').trim();
const agentRoute = legacyRoute === 'agent'
|| legacyRoute === CHAT_INTENT_ROUTE.AGENT
|| legacyRoute === 'agent_orchestration';
if (!agentRoute) return null;
const referenceMs = Math.max(Number(row.updated_at) || 0, Number(row.created_at) || 0);
if (referenceMs > 0 && nowMsFn() - referenceMs > ACTIVE_TASK_CONTEXT_MAX_AGE_MS) {
return null;
}
return {
hasRecentAgentTask: true,
lastRunId: row.id,
lastRunStatus: String(row.status ?? '').trim() || null,
lastRunFailed: String(row.status ?? '').trim() === 'failed',
lastSuggestedSkill: intent?.suggestedSkill ?? null,
lastRoute: legacyRoute,
lastIntentReason: intent?.reason ?? null,
lastErrorMessage: row.error_message
? String(row.error_message).slice(0, 500)
: null,
};
}
export async function resolveRouterTranscript(sessionSnapshotService, {
sessionId,
userId = null,
excludeLatestUserText = null,
} = {}) {
if (!sessionSnapshotService?.get || !sessionId || isDirectChatSessionId(sessionId)) {
return '';
}
const snapshot = await sessionSnapshotService.get(sessionId).catch(() => null);
if (!snapshot) return '';
if (userId && snapshot?.session?.user_id && snapshot.session.user_id !== userId) {
return '';
}
const messages = Array.isArray(snapshot?.messages) ? snapshot.messages : [];
return formatRouterTranscript(messages, { excludeLatestUserText });
}
function restoreCursorFallbackUserMessage(userMessage) {
const message = (userMessage && typeof userMessage === 'object' && !Array.isArray(userMessage))
? { ...userMessage }
@@ -1547,13 +1644,29 @@ export function createAgentRunGateway({
}
}
async function resolveRunRouting(row, userMessage, runOptions) {
async function resolveRunRouting(row, userMessage, runOptions, { runId = null } = {}) {
if (!chatIntentRouter?.classify) return null;
const enabled = chatIntentRouter.isEnabled
? await Promise.resolve(chatIntentRouter.isEnabled()).catch(() => false)
: true;
if (!enabled) return null;
const grantedSkills = await resolveGrantedSkills(row.user_id);
const activeTaskContext = await resolveActiveTaskContext(pool, {
userId: row.user_id,
sessionId: row.agent_session_id ?? null,
excludeRunId: runId,
}).catch(() => null);
const displayText = userMessage?.metadata?.displayText
?? deriveUserFacingText(
typeof userMessage?.content?.find === 'function'
? (userMessage.content.find((item) => item?.type === 'text')?.text ?? '')
: '',
);
const recentTranscript = await resolveRouterTranscript(sessionSnapshotService, {
sessionId: row.agent_session_id ?? null,
userId: row.user_id,
excludeLatestUserText: displayText,
}).catch(() => '');
return chatIntentRouter.classify({
userId: row.user_id,
userMessage,
@@ -1562,6 +1675,8 @@ export function createAgentRunGateway({
toolMode: runOptions.toolMode,
forceDeepReasoning: runOptions.forceDeepReasoning,
grantedSkills,
activeTaskContext,
recentTranscript,
});
}
@@ -1624,7 +1739,7 @@ export function createAgentRunGateway({
policyBlocked: true,
};
}
const routing = await resolveRunRouting(row, userMessage, runOptions);
const routing = await resolveRunRouting(row, userMessage, runOptions, { runId });
const routingDecision = resolveLegacyRouteFromClassification(routing) ?? routing?.route ?? null;
const cursorFirstApplied = applyCursorFirstAgentExecution(userMessage, runOptions, {
routingDecision,