Closed-loop Structured Text (IEC 61131-3) & Siemens SCL code generation using fine-tuned open weights (adarrshDev/ornith-1.5-9b-sft-r16), gated against IronPLC and MATIEC syntax constraints. Type or edit Structured Text below, test mutation scenarios, and execute validation in real-time.
END_VAR) identically to harmless variable renames, and real PLC training data is extremely scarce.autoRepairStructuredText) to guarantee 100% Stage 4 compilation.// Press 'โก RUN GATE' or edit the source...
General coding LLMs trained primarily on Python and C++ suffer from scoping drift when generating IEC 61131-3 Structured Text: they group VAR_INPUT, VAR_OUTPUT, and VAR into a single block with only one trailing END_VAR, causing industrial compilers (IronPLC, MATIEC) to reject the code with error[E0002]: parse error.
Our architecture combines the Ornith SFT adapter with an agentic AST Self-Healing Engine: when unconditioned outputs miss internal block closures, the deterministic AST healer inserts standard END_VAR delimiters before execution logic, lifting native IronPLC Stage 4 compilation from 90.0% to 100.0%.
| # | TASK ID / INTENT | STOCK BASE MODEL FAILURE | COMPILER-GATED / AUTO-HEALED OUTPUT |
|---|---|---|---|
| q01 | FB_TON_Pulse (Timer Prelude) | Emits C++ millis() or omits TON instance prelude |
Valid TON timer instance with TIME# literals (Pass) |
| q02 | FC_ScaleAnalog (4-20mA) | Implicit INT + REAL mixed division; compiler type rejection |
Explicit INT_TO_REAL casting with min/max clamp (Pass) |
| q03 | FB_Hysteresis (Deadband) | Omits latching state, causing high-frequency chatter | Dual deadband thresholds with state hysteresis (Pass) |
| q04 | FB_RampGen (Rate Limiter) | Emits blocking while (out < target) loop halting PLC scan |
Non-blocking cyclic scan rate-of-change delta limiter (Pass) |
| q05 | FB_Blinker (1 Hz Oscillator) | Emits invalid sleep(1000) call |
Cyclic inverted TON feedback (Pass with AST Auto-Heal & MATIEC) |
| q06 | FC_TrapIntRealMix (Type Trap) | Attempts implicit coercion without type cast | Enforces strict typing; rejected or cast via REAL_TO_INT (Pass) |
| q07 | FC_TrapIntDintMix (Overflow) | Silently truncates 32-bit DINT into 16-bit INT | Explicit double-integer bounds validation (Pass) |
| q08 | FB_TrapMissingEndVar (Scoping) | Missing END_VAR between variable sections (error E0002) |
AST self-healer injects missing END_VAR delimiters (Pass) |
| q09 | FB_TrapCyclicDeadlock (Scan) | Infinite loop triggering PLC watchdog timeout trip | Finite scan-cycle state transitions; zero blocking loops (Pass) |
| q10 | FC_TrapShlWord (Bit Shift) | Hallucinates C-style bitshift << operator |
Strict IEC 61131-3 SHL(IN, N) operator call (Pass) |
Execute Genuine Model Weights Locally: To bypass browser-side edge proxies and execute genuine neural tokens on your local metal or cloud GPU:
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
base_model_id = "ornith-ai/Ornith-1.5-9B"
adapter_id = "adarrshDev/ornith-1.5-9b-sft-r16"
# 1. Load Tokenizer and Base Weights
tokenizer = AutoTokenizer.from_pretrained(adapter_id, trust_remote_code=True)
base_model = AutoModelForCausalLM.from_pretrained(
base_model_id,
torch_dtype=torch.bfloat16 if torch.cuda.is_bf16_supported() else torch.float16,
device_map="auto"
)
# 2. Attach SFT LoRA Adapter (Rank 16)
model = PeftModel.from_pretrained(base_model, adapter_id)
model.eval()
# 3. Generate Valid IEC 61131-3 Structured Text
prompt = "Write an IEC 61131-3 FUNCTION_BLOCK for a dual-pump lead-lag alternator with automatic failover."
messages = [{"role": "user", "content": prompt}]
inputs = tokenizer(tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True), return_tensors="pt").to(model.device)
with torch.no_grad():
outputs = model.generate(**inputs, max_new_tokens=512, temperature=0.2)
print(tokenizer.decode(outputs[0][inputs.input_ids.shape[1]:], skip_special_tokens=True))