# AIPack Flow Specification

This document describes the `aip.flow` module and how it controls the execution lifecycle of an Agent.

## Overview

The `aip.flow` module provides functions that return "Directive Tables". These tables are recognized by the Agent Executor to alter the normal sequential flow of stages.

When a directive is returned:
1. It immediately interrupts the current stage.
2. It propagates back to the Agent Executor.
3. The Executor performs the requested action (Skip, Redo, etc.).

## Directives

### `aip.flow.skip(reason?)`

Instructs the executor to stop processing the current task and move to the next one.
- **BeforeAll**: Skips the entire run.
- **Data**: Skips the current input item.
- **Output**: Skips finishing the current task (output is recorded as a skip).

### `aip.flow.redo_run()`

Instructs the executor to finish the current active tasks and then restart the entire agent execution from the beginning.
- This is useful for self-correcting agents or when the agent needs to reload its own code/configuration.
- This directive is valid only when returned from:
  - `# Before All`
  - `# After All`
- Returning it from:
  - `# Data`
  - `# Output`
  fails with an explicit stage error:
  - `aip.flow.redo_run() can be returned only from # Before All or # After All stages.`
- Redo is propagated as a run-level request, then scheduled by the executor as a follow-up `Redo` action.
- Automatic redo chaining is supported, meaning a redo-triggered rerun can request redo again and continue the cycle.
- Before dispatching the next redo action, the executor waits `500ms`.
- The initial top-level run starts with redo count `0`.
- Each accepted redo transition increments the redo count by `1` for the next rerun.
- The current redo count is exposed to Lua through `CTX.RUN_FLOW_REDO_COUNT`.
- `CTX.RUN_FLOW_REDO_COUNT` is absent for a normal first run and present for redo-chain reruns.

### `aip.flow.before_all_response(data)`

Used in `before_all` to override inputs or options for the run.

### `aip.flow.data_response(data)`
Used in `data` to override the input or options for a single task.

## Flow Interruption Logic

### Stage-based behavior

- **BeforeAll**: If `skip` or `redo` is returned, the `Data` and `Ai` stages are never entered.
- **Data**: If `skip` is returned for a specific input, the `Ai` and `Output` stages for that input are bypassed. If `redo` is returned, the stage fails with the explicit error `aip.flow.redo_run() can be returned only from # Before All or # After All stages.` because redo is not allowed from `# Data`.
- **Output**: If `redo` is returned, the stage fails with the explicit error `aip.flow.redo_run() can be returned only from # Before All or # After All stages.` because redo is not allowed from `# Output`.
- **AfterAll**: If `redo` is returned, the overall run is marked for redo.

### Redo lifecycle

The redo behavior is split between the run pipeline and the executor.

- The run pipeline detects `_aipack_ = { kind = "Redo" }` and surfaces this as `redo_requested = true` in the run response.
- The executor owns the redo scheduling policy.
- The run context carries the current redo count for the active run.
- When a run or redo-run completes successfully with `redo_requested = true`, the executor:
  - refreshes and stores the latest `RunRedoCtx`
  - increments the redo count for the next rerun
  - waits `500ms`
  - enqueues the next `ExecActionEvent::Redo`
- This applies to:
  - the initial `Run` path
  - the `Redo` path itself

This design ensures redo is not a one-shot follow-up. As long as each completed rerun keeps requesting redo, the executor continues to schedule the next redo cycle.

### Redo count flow

- A normal first run begins a new redo chain with count `0`.
- If `aip.flow.redo_run()` is returned from an allowed stage, the current run completes and requests a redo.
- The next rerun receives redo count `1`.
- If that rerun requests redo again, the following rerun receives redo count `2`, and so on.
- Starting a new top-level run resets the redo count to `0`.
- Invalid redo attempts from unsupported stages do not advance the count because no redo transition is accepted.

### Design considerations

- Redo scheduling is intentionally centralized in the executor instead of being recursively handled inside the run pipeline.
- The stored redo context must be refreshed after each successful rerun so the next redo uses the latest execution context.
- If a redo execution fails, the previous redo context should remain available for manual retry behavior.
- The `500ms` wait is a pacing delay before dispatching the next full redo event.
- Redo count is carried by run context so flow logic can observe the current chain position without coupling to executor internals.
- Resetting the count on a new top-level run prevents leakage across unrelated executions.

### Propagation
Directives are wrapped in an `_aipack_` internal table structure:

```json
{
  "_aipack_": {
    "kind": "Redo"
  }
}
```

The runtime detects these patterns in the values returned by Lua scripts and executes the corresponding logic.

