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
+43 -1
View File
@@ -28,6 +28,19 @@ async function recordValidationWithRetry(engine, runId, observation) {
}
}
export function resolveValidationEngineSelection(selection) {
if (selection.shadowEngine === WORKFLOW_ENGINE.LANGGRAPH) {
return selection;
}
if (
selection.engine === WORKFLOW_ENGINE.LANGGRAPH
&& ['active', 'canary', 'shadow'].includes(String(selection.mode ?? ''))
) {
return selection;
}
return null;
}
export function createWorkflowShadowObserver({
configService,
serviceToken = process.env.MEMIND_ORCHESTRATOR_SERVICE_TOKEN,
@@ -66,6 +79,34 @@ export function createWorkflowShadowObserver({
};
}
async function selectValidationEngine({
runId,
requestId,
userId,
workflowName,
}) {
const selection = await configService.selectEngine({
runId,
requestId,
userId,
workflowName,
});
if (!resolveValidationEngineSelection(selection)) {
return { selection, engine: null };
}
const state = await configService.getRuntimeState();
return {
selection,
engine: createRemoteWorkflowEngine({
id: WORKFLOW_ENGINE.LANGGRAPH,
baseUrl: state.config.serviceUrl,
serviceToken,
timeoutMs: state.config.requestTimeoutMs,
fetchImpl,
}),
};
}
async function observeWorkflowRun({
runId,
requestId,
@@ -152,7 +193,7 @@ export function createWorkflowShadowObserver({
workflowName = 'code-run-v1',
observation,
} = {}) {
const { selection, engine } = await selectShadowEngine({
const { selection, engine } = await selectValidationEngine({
runId,
requestId,
userId,
@@ -187,5 +228,6 @@ export function createWorkflowShadowObserver({
export const workflowShadowObserverInternals = {
recordValidationWithRetry,
resolveValidationEngineSelection,
safeError,
};
+72 -1
View File
@@ -3,7 +3,7 @@ import test from 'node:test';
import { MemorySaver } from '@langchain/langgraph';
import { createOrchestratorApp } from './app.mjs';
import { createLangGraphOrchestratorRuntime } from './runtime.mjs';
import { createWorkflowShadowObserver } from './shadow-observer.mjs';
import { createWorkflowShadowObserver, resolveValidationEngineSelection } from './shadow-observer.mjs';
function jsonResponse(body, status = 200) {
return new Response(JSON.stringify(body), {
@@ -25,6 +25,77 @@ async function listen(app) {
};
}
test('resolveValidationEngineSelection accepts active-mode LangGraph engine', () => {
assert.ok(resolveValidationEngineSelection({
engine: 'langgraph',
shadowEngine: null,
mode: 'active',
reason: 'active',
}));
assert.equal(resolveValidationEngineSelection({
engine: 'native',
shadowEngine: null,
mode: 'active',
reason: 'active',
}), null);
});
test('validation observer records observations in active mode without shadowEngine', async () => {
let capturedUrl = null;
const observer = createWorkflowShadowObserver({
configService: {
async selectEngine() {
return {
engine: 'langgraph',
candidateEngine: 'langgraph',
shadowEngine: null,
fallbackEngine: 'native',
reason: 'active',
candidateReason: 'active',
mode: 'active',
configVersion: 6,
dryRun: false,
};
},
async getRuntimeState() {
return {
config: {
serviceUrl: 'http://orchestrator.internal:8093',
requestTimeoutMs: 1200,
},
};
},
},
serviceToken: 'internal-token',
fetchImpl: async (url) => {
capturedUrl = url;
return jsonResponse({
runId: 'run-active-1',
validation: { verdict: 'passed', kind: 'page-data-delivery' },
});
},
});
const result = await observer.observeValidation({
runId: 'run-active-1',
requestId: 'request-active-1',
userId: 'user-1',
observation: {
idempotencyKey: 'run-active-1:page-data-delivery:v1',
taskType: 'page_data_dev',
required: true,
checks: [{ id: 'page_data_binding', status: 'passed' }],
source: 'portal-agent-run',
observedAt: 123,
},
});
assert.equal(result.observed, true);
assert.equal(result.mode, 'active');
assert.equal(result.validation.verdict, 'passed');
assert.match(String(capturedUrl), /\/v1\/runs\/run-active-1\/validation-observations$/);
});
test('shadow observer skips without creating a remote client when mode does not select shadow', async () => {
let fetchCalls = 0;
const observer = createWorkflowShadowObserver({