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 Allstageinputs: A Lua list containing all the inputs provided to the agent run command.- When
-f "**/some/glob*.*"is used, each element ininputswill be a FileInfo object. - When
-i "some string"is used, each element will be the corresponding string.
- When
-
In the
# Datastage (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 Allusingaip.flow.before_all_response.
- If from
before_all: The data returned by the# Before Allstage (if any, otherwisenil).
-
In the
# Outputstage (runs per processed input)input: The input item for this cycle (potentially modified by# Data).data: The data returned by the# Datascript for this input (if any, otherwisenil).before_all: The data returned by the# Before Allstage (if any, otherwisenil).ai_response: The AiResponse object containing the result from the AI model.
-
In the
# After Allstage (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# Outputstage for each corresponding input. Will benilfor skipped inputs or if# Outputreturned nothing. The order matches theinputslist.before_all: The data returned by the# Before Allstage (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
optionsproperty is optional, and when present, should be a "table object" (Lua Dictionary Table). starts_withis required and must be a string.extrudeis optional and can be either the string "content" or "fragments".firstis 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 Allto be used in# Data,# Output,# After All; return data from# Datato be used in prompt stages and# Output; return data from# Outputto 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 Allstage can filter or modify theinputslist (list ofFileInfoobjects) but should generally avoid loading file content. - The
# Datastage (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_concurrencysetting to parallelize file loading and processing. - The
# Before Allstage 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.luafiles in thelua/subdirectory relative to your.aipagent file (e.g.,my-agent.aipcanrequire("utils")iflua/utils.luaexists).
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 Allscript. - Allows replacing the entire list of
inputsfor the run. - Allows overriding agent
options(likemodel,input_concurrency) for the run. - Allows setting the
before_alldata that will be passed to subsequent stages. - If you just want to pass data, simply
return { my_data = "value" }. Useaip.flow.before_all_responseonly 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
# Datascript (runs per input). - Allows setting the
datathat will be passed to the prompt and# Outputstages for this specific input. - Allows replacing the
inputvalue itself for this specific input. - Allows overriding agent
optionsfor this specific input. - If you just want to pass data, simply
return { my_data = "value" }. Useaip.flow.data_responseonly 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
# Datascript. - Instructs the agent to completely skip processing this input (no AI call, no
# Outputstage). - The corresponding entry in the
outputslist passed to# After Allwill 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