AIPACK Lua Application model
Here is the Lua application model and concepts.
The full Lua APIs (aip.
module) can be found in lua-apis
Convention and Flow
aipack injects the following modules/variables into the various script stages:
-
In all Lua script stages (
# Before All
,# Data
,# Output
,# After All
)aip
: The AIPACK Lua API module - A set of utility functions and submodules for convenience, common logic, and control flow.CTX
: A table containing contextual constants like paths and agent info.
-
In the
# Before All
stageinputs
: A Lua list containing all the inputs provided to the agent run command.- When
-f "**/some/glob*.*"
is used, each element ininputs
will be a FileInfo object. - When
-i "some string"
is used, each element will be the corresponding string.
- When
-
In the
# Data
stage (runs per input)input
: The individual input item being processed for this cycle.- If from
-f
, it's a FileInfo object. - If from
-i
, it's a string. - Can be modified by the return value of
# Before All
usingaip.flow.before_all_response
.
- If from
before_all
: The data returned by the# Before All
stage (if any, otherwisenil
).
-
In the
# Output
stage (runs per processed input)input
: The input item for this cycle (potentially modified by# Data
).data
: The data returned by the# Data
script for this input (if any, otherwisenil
).before_all
: The data returned by the# Before All
stage (if any, otherwisenil
).ai_response
: The AiResponse object containing the result from the AI model.
-
In the
# After All
stage (runs once at the end)inputs
: The final list of all inputs that were processed (potentially modified by# Before All
).outputs
: A Lua list containing the values returned by the# Output
stage for each corresponding input. Will benil
for skipped inputs or if# Output
returned nothing. The order matches theinputs
list.before_all
: The data returned by the# Before All
stage (if any, otherwisenil
).
Note that Lua types in the aipack documentation are expressed in a simplified TypeScript notation as it is clear and concise.
For example:
options?: {starts_with: string, extrude?: "content" | "fragments", first?: number | boolean}
- Would mean:
- The
options
property is optional, and when present, should be a "table object" (Lua Dictionary Table). starts_with
is required and must be a string.extrude
is optional and can be either the string "content" or "fragments".first
is optional and can be a number or boolean.
- The
- Lua types map closely: tables for objects/dictionaries, tables with sequential integer keys for lists/arrays, strings, numbers, booleans, nil.
- For functions that return multiple values, a characteristic of Lua, the return will be expressed like:
some_fun(name: string, options?: {...}): table, string | nil
- This means that the function will return two values: first a value of type table, and second a value that is either a string or nil.
Important Lua considerations and best practices
- The scripting model is designed to pass data between stages (e.g., return data from
# Before All
to be used in# Data
,# Output
,# After All
; return data from# Data
to be used in prompt stages and# Output
; return data from# Output
to be aggregated in# After All
). - It is not possible to return Lua functions or userdata between stages. Only serializable data (tables, strings, numbers, booleans, nil) can be reliably passed.
- As a best practice, when processing multiple files (via
-f
):- The
# Before All
stage can filter or modify theinputs
list (list ofFileInfo
objects) but should generally avoid loading file content. - The
# Data
stage (which runs per file) is the best place to load the content of the current file (aip.file.load(input.path)
) because this allows theinput_concurrency
setting to parallelize file loading and processing. - The
# Before All
stage is suitable for preparing common resources (e.g., ensuring a shared output file exists) and returning common configuration or paths viabefore_all
.
- The
- You can use Lua's
require("my-module")
function to include custom Lua code. Place your.lua
files in thelua/
subdirectory relative to your.aip
agent file (e.g.,my-agent.aip
canrequire("utils")
iflua/utils.lua
exists).
aip.flow
The aip.flow
Lua module provides special functions that return structured tables to control the agent's execution flow. These should be used as the return
value of the corresponding script stage (# Before All
or # Data
).
See aip.flow documentation in lua-apis for detailed API signatures.
Before All Stage Flow Control
-
aip.flow.before_all_response({ inputs?: list, options?: table, before_all?: table })
:- Returned from the
# Before All
script. - Allows replacing the entire list of
inputs
for the run. - Allows overriding agent
options
(likemodel
,input_concurrency
) for the run. - Allows setting the
before_all
data that will be passed to subsequent stages. - If you just want to pass data, simply
return { my_data = "value" }
. Useaip.flow.before_all_response
only when modifying inputs or options.
-- Example (# Before All script) -- Filter inputs and set a global path local filtered_inputs = {} for _, input in ipairs(inputs) do if input.ext == "md" then table.insert(filtered_inputs, input) end end return aip.flow.before_all_response({ inputs = filtered_inputs, before_all = { output_summary = "output/summary.md" } })
- Returned from the
Data Stage Flow Control
-
aip.flow.data_response({ data?: table, input?: any, options?: table })
:- Returned from the
# Data
script (runs per input). - Allows setting the
data
that will be passed to the prompt and# Output
stages for this specific input. - Allows replacing the
input
value itself for this specific input. - Allows overriding agent
options
for this specific input. - If you just want to pass data, simply
return { my_data = "value" }
. Useaip.flow.data_response
only when modifying the input or options for this cycle.
-- Example (# Data script) -- Load content and potentially use a stronger model for large files local file = aip.file.load(input.path) local response_data = { file_content = file.content } if #file.content > 10000 then return aip.flow.data_response({ data = response_data, options = { model = "gpt-4o" } -- Use a different model for this large file }) else return response_data -- Just return the data for prompt/output stages end
- Returned from the
-
aip.flow.skip(reason?: string)
:- Returned from the
# Data
script. - Instructs the agent to completely skip processing this input (no AI call, no
# Output
stage). - The corresponding entry in the
outputs
list passed to# After All
will benil
.
-- Example (# Data script) -- Skip empty files if not input.path then return aip.flow.skip("Input has no path") end local file = aip.file.load(input.path) -- Skip if content is only whitespace if not file.content:find("%S") then return aip.flow.skip("File is empty or whitespace only: " .. input.path) end return { file_content = file.content } -- Proceed normally
- Returned from the