Skip to main content
Glama

apply_plan

Apply validated edit steps to a DOCX document in a single batch operation, ensuring all changes pass validation before implementation.

Instructions

Validate and apply a batch of edit steps (replace_text, insert_paragraph) to a document in one call. Validates all steps first; applies only if all pass. Accepts inline steps or a plan_file_path. Compatible with merge_plans output.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
file_pathYesPath to the DOCX file.
stepsNoJSON array of edit steps. Each step needs step_id, operation, and operation-specific fields.
plan_file_pathNoPath to a .json file containing an array of edit steps. Mutually exclusive with steps.

Implementation Reference

  • The main entry point for the `apply_plan` tool. It handles loading, normalizing, validating, and executing a sequence of steps (replace_text or insert_paragraph) on a DOCX file.
    export async function applyPlan(
      manager: SessionManager,
      params: {
        file_path?: string;
        steps?: unknown[];
        plan_file_path?: string;
      },
    ): Promise<ToolResponse> {
      try {
        // Validate mutual exclusivity of steps and plan_file_path
        if (params.steps && params.plan_file_path) {
          return err(
            'INVALID_PARAMS',
            'Cannot provide both steps and plan_file_path. Use one or the other.',
          );
        }
    
        if (!params.steps && !params.plan_file_path) {
          return err(
            'INVALID_PARAMS',
            'Must provide either steps (JSON array) or plan_file_path.',
          );
        }
    
        // Load steps
        let rawSteps: unknown[];
        if (params.plan_file_path) {
          const loaded = await loadStepsFromFile(params.plan_file_path);
          if (loaded.error) return loaded.error;
          rawSteps = loaded.steps;
        } else {
          rawSteps = params.steps!;
        }
    
        // Normalize steps
        const { steps, errors: normErrors } = normalizeSteps(rawSteps);
        if (normErrors.length > 0) {
          return err(
            'NORMALIZATION_ERROR',
            `Step normalization failed with ${normErrors.length} error(s): ${normErrors.join('; ')}`,
          );
        }
    
        if (steps.length === 0) {
          return err('EMPTY_PLAN', 'Plan contains no valid steps.');
        }
    
        // Resolve session
        const resolved = await resolveSessionForTool(manager, params, { toolName: 'apply_plan' });
        if (!resolved.ok) return resolved.response;
        const { session } = resolved;
    
        // Validation phase — check ALL steps before applying
        const validations = validateSteps(steps, session.doc);
        const overallValid = validations.every((v) => v.valid);
    
        if (!overallValid) {
          return {
            success: false,
            error: {
              code: 'VALIDATION_FAILED',
              message: `Plan validation failed: ${validations.filter((v) => !v.valid).length} of ${steps.length} step(s) have errors.`,
              hint: 'Fix the reported errors and resubmit.',
            },
            overall_valid: false,
            steps: validations,
          };
        }
    
        // Collect warnings
        const allWarnings = validations.flatMap((v) => v.warnings.map((w) => ({ step_id: v.step_id, warning: w })));
    
        // Apply phase — execute steps sequentially
        const result = await executeSteps(manager, manager.normalizePath(session.originalPath), steps);
    
        if (result.failed_step_id !== undefined) {
          return {
            success: false,
            error: {
              code: 'APPLY_PARTIAL_FAILURE',
              message: `Plan execution stopped at step '${result.failed_step_id}' (index ${result.failed_step_index}).`,
              hint: 'Completed steps have already been applied. Reapply to original DOCX if rollback is needed.',
            },
            file_path: manager.normalizePath(session.originalPath),
            completed_count: result.completed_step_ids.length,
            completed_step_ids: result.completed_step_ids,
            failed_step_id: result.failed_step_id,
            failed_step_index: result.failed_step_index,
            failed_step_error: result.failed_step_error,
            step_results: result.step_results,
            ...(allWarnings.length > 0 ? { warnings: allWarnings } : {}),
          };
        }
    
        return ok({
          file_path: manager.normalizePath(session.originalPath),
          edit_count: session.editCount,
          completed_count: result.completed_step_ids.length,
          completed_step_ids: result.completed_step_ids,
          step_results: result.step_results,
          ...(allWarnings.length > 0 ? { warnings: allWarnings } : {}),
        });
      } catch (e: unknown) {
        return err('APPLY_PLAN_ERROR', `Failed to apply plan: ${errorMessage(e)}`);
      }
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/UseJunior/safe-docx'

If you have feedback or need assistance with the MCP directory API, please join our Discord server