TaskRunner

Config-driven task template that wires core libraries together

task template

Library Implementation

-- TaskRunner.lua
-- Configurable task template to reduce boilerplate in task scripts

local TaskStateMachine = require("TaskStateMachine")
local SubtaskExecutor = require("SubtaskExecutor")
local CommonChecks = require("CommonChecks")
local TaskHelpers = require("TaskHelpers")
local CoordinationHelpers = require("CoordinationHelpers")

local TaskRunner = {}

-- Create a task implementation from config
function TaskRunner.create(config)
    local cfg = config or {}
    local timeoutSeconds = cfg.timeoutSeconds or 300
    local flags = cfg.flags or {}
    local hooks = cfg.hooks or {}
    local state = nil

    local function init(params)
        local success, msg = CommonChecks.initChecks(params)
        if not success then
            return false, msg
        end

        local subtaskNames = cfg.subtasks or {}
        state = TaskStateMachine.new(subtaskNames)
        state.startTime = vrf.getSimulationTime()
        state.data = params or {}
        TaskHelpers.setData(state, "fallbackNotified", false)

        if flags.activateSensors then
            ActivateSensors{}
        end

        if flags.captureTargetLocation and params and params.targetLocation then
            TaskHelpers.setData(state, "targetLocation", params.targetLocation)
        end

        if hooks.onInit then
            local hookOk, hookMsg = hooks.onInit(state, params)
            if hookOk == false then
                return false, hookMsg
            end
        end

        return TaskStateMachine.transition(state, "READY", "Task initialized successfully")
    end

    local function tick()
        if TaskHelpers.isTimeout(state.startTime, timeoutSeconds) then
            return "FAILURE", "Task timeout exceeded"
        end

        if state.current == "READY" then
            if flags.sendStartReport then
                CoordinationHelpers.sendProgressReport(state, "READY", "Starting task execution")
            end

            if hooks.onReady then
                local nextState, hookMsg = hooks.onReady(state)
                if nextState then
                    return TaskStateMachine.transition(state, nextState, hookMsg or "Ready")
                end
            end

            return TaskStateMachine.transition(state, "EXECUTING", "Beginning execution")
        elseif state.current == "EXECUTING" then
            local canContinue, checkMsg = CommonChecks.preExecutionChecks()
            if not canContinue then
                return "FAILURE", checkMsg
            end

            if flags.enableParallelSensing then
                ActivateSensors{}
            end

            if flags.requireAmmoForEngagement and not HasAmmo{} then
                if flags.enableAttackFallback then
                    TaskHelpers.setData(state, "fallbackReason", "Insufficient ammo")
                    return TaskStateMachine.transition(state, "FALLBACK", "Insufficient ammo")
                end
                return "FAILURE", "Insufficient ammo"
            end

            if flags.requireEngagementAuth then
                local target = TaskHelpers.getData(state, "target", nil)
                local canEngage, msg = CommonChecks.canEngage(target)
                if not canEngage then
                    if flags.enableAttackFallback then
                        TaskHelpers.setData(state, "fallbackReason", msg)
                        return TaskStateMachine.transition(state, "FALLBACK", msg)
                    end
                    return "FAILURE", msg
                end
            end

            if hooks.onExecuting then
                local action, hookMsg = hooks.onExecuting(state)
                if action == "FAILURE" or action == "COMPLETE" then
                    return action, hookMsg
                end
            end

            local currentIdx = SubtaskExecutor.getCurrentSubtask(state)
            if not currentIdx then
                local execOk, execMsg = SubtaskExecutor.executeNext(state)
                if not execOk then
                    return "FAILURE", execMsg
                end
            end

            if TaskStateMachine.allSubtasksComplete(state) then
                return TaskStateMachine.transition(state, "COMPLETING", "All subtasks executed")
            end

            local progress = SubtaskExecutor.getProgress(state)
            local statusMsg = string.format("Executing subtasks (%.0f%% complete)", progress * 100)
            return "CONTINUE", statusMsg
        elseif state.current == "FALLBACK" then
            local notified = TaskHelpers.getData(state, "fallbackNotified", false)
            if not notified then
                local reason = TaskHelpers.getData(state, "fallbackReason", "Fallback engaged")
                if flags.sendFallbackReport then
                    CoordinationHelpers.sendProgressReport(state, "FALLBACK", reason)
                end
                if flags.requestSupport then
                    local loc = TaskHelpers.getData(state, "targetLocation", nil)
                    CoordinationHelpers.requestSupport("SUPPORT", {location = loc, urgency = "IMMEDIATE"})
                end
                TaskHelpers.setData(state, "fallbackNotified", true)
            end

            local waitSeconds = flags.fallbackWaitSeconds or 30
            if TaskHelpers.wait(state, waitSeconds) then
                TaskHelpers.setData(state, "fallbackNotified", false)
                return TaskStateMachine.transition(state, "EXECUTING", "Retrying execution")
            end

            return "CONTINUE", "Fallback active"
        elseif state.current == "COMPLETING" then
            if hooks.onCompleting then
                local action, hookMsg = hooks.onCompleting(state)
                if action == "FAILURE" or action == "COMPLETE" then
                    return action, hookMsg
                end
            end

            local complete, completeMsg = CommonChecks.missionCompleteChecks()
            if complete == true then
                if flags.sendCompletionReport then
                    CoordinationHelpers.sendCompletionReport(state, true, "Mission accomplished")
                end
                return TaskStateMachine.transition(state, "COMPLETE", "Task completed successfully")
            elseif complete == false then
                return "FAILURE", completeMsg
            end

            return "CONTINUE", "Verifying mission completion"
        elseif state.current == "COMPLETE" then
            if hooks.onComplete then
                local action, hookMsg = hooks.onComplete(state)
                if action then
                    return action, hookMsg
                end
            end
            return "COMPLETE", "Task completed successfully"
        end

        return "CONTINUE", TaskHelpers.formatStatus(state, "Task in progress")
    end

    return {init = init, tick = tick}
end

return TaskRunner
6922 characters

Usage Example

-- Usage example:
local TaskRunner = require("TaskRunner")

local config = {
    subtasks = {"Plan", "Move", "Execute", "Assess"},
    timeoutSeconds = 300,
    flags = {
        activateSensors = true,
        captureTargetLocation = true,
        enableParallelSensing = true,
        requireAmmoForEngagement = true,
        requireEngagementAuth = true,
        enableAttackFallback = true,
        sendStartReport = true,
        sendFallbackReport = true,
        requestSupport = true,
        sendCompletionReport = true,
        fallbackWaitSeconds = 30
    }
}

return TaskRunner.create(config)

Quick Reference

Import Statement

local TaskRunner = require("TaskRunner")

Category

task template

Key Features

  • Reusable utility functions
  • Common task operations
  • Helper methods