18 Migration Guide
18.1 From Python Scripts
18.1.1 Before (Python)
import openai
def run_agent(prompt):
messages = [{"role": "user", "content": prompt}]
while True:
response = openai.chat.completions.create(
model="gpt-4",
messages=messages,
tools=[search_tool, done_tool]
)
if done_called(response):
return extract_result(response)
messages.append(response.choices[0].message)18.1.2 After (Tactus)
local done = require("tactus.tools.done")
search = Tool { ... }
worker = Agent {
model = "openai/gpt-4o",
system_prompt = "...",
tools = {search, done}
}
Procedure {
input = {prompt = field.string{required = true}},
output = {result = field.string{required = true}},
function(input)
worker({message = input.prompt})
repeat worker() until done.called() or Iterations.exceeded(20)
return {result = done.last_result() or ""}
end
}Benefits: - Automatic checkpointing - HITL built-in - BDD testing - Type-safe I/O
18.2 From LangChain/LangGraph
18.2.1 Before (LangGraph)
class State(TypedDict):
messages: list
done: bool
graph = StateGraph(State)
graph.add_node("agent", agent_node)
graph.add_node("tools", tool_node)
graph.add_conditional_edges(...)
app = graph.compile(checkpointer=memory)18.2.2 After (Tactus)
local done = require("tactus.tools.done")
worker = Agent { model = "openai/gpt-4o-mini", tools = {search, done} }
Procedure {
function(input)
repeat worker() until done.called()
return {result = done.last_result() or ""}
end
}Benefits: - Imperative code instead of graph definition - Simpler mental model - Same durability guarantees
18.3 Key Differences
| Python/LangChain | Tactus |
|---|---|
| Classes and decorators | Assignment-based declarations |
| Manual state management | Durable state + checkpoints |
| Graph-based flow | Imperative loops |
| Separate test files | Embedded Specifications([[]]) |
| Multiple files | Single .tac file |
18.4 From Older Tactus Syntax
Older examples often use “named blocks” (e.g., Agent "worker" { ... }). In v5, declarations are assignment-based and referenced as variables:
worker = Agent { ... }
repeat worker() until done.called()18.5 Script Mode (Zero-Wrapper)
Script mode lets Tactus wrap simple Lua scripts as a procedure automatically. It’s useful when migrating a quick script into a full Procedure { ... } file.