UNPKG

mcp-casual-interview

Version:

MCP server for casual interview preparation workflow management

99 lines 5.1 kB
import { toStructuredCallToolResult } from '../util.js'; import { formatProgressUpdateMessage, errorMessages } from './prompts.js'; // Domain layer imports import { WorkflowStateEffects, ErrorMapping } from '../../../effect/workflow-state/index.js'; import { WorkflowPolicies } from '../../../domain/term/interview-workflow/index.js'; import { ProgressViewQueries } from '../../../domain/read/progress-view/index.js'; /** * Maps completed step to next workflow state */ const getNextWorkflowState = (completedStep) => { return WorkflowPolicies.StateTransitions.getNextState(completedStep); }; /** * Maps domain WorkflowState to schema ResponseWorkflowStateType */ const mapWorkflowStateToSchemaType = (domainState) => { const mapping = { 'not_started': 'not_started', 'information_initially_registered': 'initial_info_registered', 'career_summary_created': 'career_summary_created', 'match_position_determined': 'match_position_determined', 'match_degree_prediagnosed': 'match_degree_diagnosed', 'attract_plan_determined': 'attract_plan_determined', 'completed': 'completed' }; return mapping[domainState]; }; /** * Maps domain progress response to MCP output schema */ const mapProgressResponseToOutput = (currentState, nextAction) => { return { currentState: mapWorkflowStateToSchemaType(currentState), nextAction: nextAction }; }; /** * Progress update handler using domain layer orchestration */ export const progressUpdateHandler = async (args) => { // 1. Get current workflow state from effect layer const currentStateResult = await WorkflowStateEffects.getWorkflowState(); if (currentStateResult.isErr()) { const workflowError = ErrorMapping.mapStorageErrorToWorkflowError(currentStateResult.error); return toStructuredCallToolResult([errorMessages.storageError(workflowError.message)], { error: workflowError.message }, true); } const previousState = currentStateResult.value; // 2. Set completed step as the new current state const newCurrentState = args.completedStep; // 3. Validate state transition to the completed step if (!WorkflowPolicies.StateTransitions.canTransition(previousState, newCurrentState)) { const nextValidState = WorkflowPolicies.StateTransitions.getNextState(previousState); const errorMessage = nextValidState ? errorMessages.invalidTransitionWithGuidance(previousState, newCurrentState, nextValidState) : errorMessages.invalidTransition(previousState, newCurrentState); return toStructuredCallToolResult([errorMessage], { error: 'Invalid state transition', currentState: previousState, expectedNext: nextValidState }, true); } // 4. Check if step is already completed (idempotency check) const previousStateMapping = { 'not_started': 'not_started', 'information_initially_registered': 'initial_info_registered', 'career_summary_created': 'career_summary_created', 'match_position_determined': 'match_position_determined', 'match_degree_prediagnosed': 'match_degree_diagnosed', 'attract_plan_determined': 'attract_plan_determined', 'completed': 'completed' }; const requestedStepName = args.completedStep; if (WorkflowPolicies.StateTransitions.canTransition(requestedStepName, previousState) === false && previousState !== requestedStepName) { // If we can't transition from requested step to current state, it means the step might already be completed const currentMappedState = previousStateMapping[previousState]; if (currentMappedState !== 'initial_info_registered') { // Allow restarting from initial state return toStructuredCallToolResult([errorMessages.alreadyCompleted(requestedStepName)], { warning: 'Step already completed' }, false); } } // 5. Update workflow state in effect layer const updateResult = await WorkflowStateEffects.setWorkflowState(newCurrentState); if (updateResult.isErr()) { const workflowError = ErrorMapping.mapStorageErrorToWorkflowError(updateResult.error); return toStructuredCallToolResult([errorMessages.storageError(workflowError.message)], { error: workflowError.message }, true); } // 6. Build read model view from new state const progressView = ProgressViewQueries.fromState(newCurrentState); // 7. Map domain data to MCP output schema const outputData = mapProgressResponseToOutput(newCurrentState, progressView.nextAction.message); // 7.1. Add notion URL if provided if (args.notionUrl) { outputData.notionUrl = args.notionUrl; } // 8. Format for human consumption const message = formatProgressUpdateMessage({ previousState: mapWorkflowStateToSchemaType(previousState), currentState: outputData.currentState, nextAction: outputData.nextAction, notionUrl: args.notionUrl }); return toStructuredCallToolResult([message], outputData, false); }; //# sourceMappingURL=handler.js.map