Qwen3.5-4B-Soyuz-VibeApps (merged bf16)
Continued SFT of AlexWortega/qwen35-4b-soyuz-merged
on AlexWortega/vibeapps-chat-fabric
— an agentic, single-file web-app builder. Given a non-technical user's request, it drives a coding
loop with write / edit / bash tool-calls to produce one self-contained index.html
(inline CSS + vanilla JS) and iterates over the user's follow-up critique.
~8.4 GB safetensors, merged (no PEFT needed).
Training
- LoRA r=64, α=128 on every text-decoder Linear (attention + MLP + GatedDeltaNet projections), base frozen, then merged. lr 1e-4, 3 epochs, AdamW, fla deltanet kernels + Liger fused-CE, grad-checkpointing, 32k context, 1× A6000.
- Data prep of
vibeapps-chat-fabric(1,329 multi-turn agentic traces, persona drives the agent over ~3 turns):- filter-to-fit 32k — traces are long (median ~36k tok, the agent rewrites the whole file via
write/edit); only traces that fit completely are kept so code targets are never truncated. require_satisfied— keep only the 819 traces the persona ultimately accepted (drop 510 never-satisfied "failed builds"). After the length filter: 465 training traces.- per-turn
turn_satisfiedmasking is deliberately off (the persona only marks satisfaction on the final turn, so masking earlier turns would drop the initial app-build — the core skill). - machine-path sanitization (
/home/.../pi-app-factory/runs/.../app→/workspace/app).
- filter-to-fit 32k — traces are long (median ~36k tok, the agent rewrites the whole file via
- Final train loss 0.41 → 0.24.
Usage
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
m = AutoModelForCausalLM.from_pretrained(
"AlexWortega/qwen35-4b-soyuz-vibeapps-merged", dtype=torch.bfloat16, device_map="cuda")
tok = AutoTokenizer.from_pretrained("AlexWortega/qwen35-4b-soyuz-vibeapps-merged")
msgs = [
{"role": "system", "content": "You are a coding agent building a small self-contained app. "
"Prefer one index.html with inline CSS + vanilla JS. Working dir: /workspace/app"},
{"role": "user", "content": "Сделай Pomodoro-таймер с круговым прогрессом в тёмном неоновом стиле."},
]
ids = tok.apply_chat_template(msgs, add_generation_prompt=True, return_tensors="pt").to("cuda")
out = m.generate(ids, max_new_tokens=4096, do_sample=True, temperature=0.7, top_p=0.9)
print(tok.decode(out[0][ids.shape[1]:]))
The model emits Hermes-style <tool_call>{"name": "write", "arguments": {"path": ..., "content": ...}}</tool_call>
blocks — run it inside a tool-execution loop (stop on <|im_end|>, execute the tool, feed the
<tool_response> back) for a real agentic build.
Evaluation: terminal-bench-2 (with and without pi-agent)
This model was evaluated on terminal-bench-2 two ways:
Without pi-agent (canonical Terminus-2 harness, served bf16 via sglang). On the 13 tasks the base Soyuz-4B solved, the vibeapps continued-SFT kept the agentic skills: 12 / 13 strict pass@5 — modernize-scientific-stack 5/5, hf-model-inference 4/5, kv-store-grpc 4/5, git-leak-recovery 3/5, openssl 3/5, multi-source 3/5, sqlite 3/5, configure-git 2/5, fix-git 2/5, portfolio 2/5, build-cython-ext 1/5, nginx 1/5; only prove-plus-comm 0/5. I.e. app-building SFT did not cause catastrophic forgetting of terminal-agent ability.
With pi-agent (live pi coding-agent tool-loop). Driven by the pi coding agent in a real read/bash/edit/write loop (persona critic over 3 turns), the model built a complete 29.5 KB single-file NEON BREAKOUT game end-to-end — power-ups (laser, multi-ball), particles, score/lives, canvas RAF loop — directly validating the training in production.
Takeaway: this variant is the right choice for agentic single-file app building (in-browser pi-agent / Terminus), whereas later RL variants tuned on single-shot coding regressed on agentic use.
Related
| Asset | Link |
|---|---|
| Base (Soyuz-4B) | qwen35-4b-soyuz-merged |
| Training data | vibeapps-chat-fabric |
W&B: https://wandb.ai/alexwortega/fast-qwen35-sft (run soyuz-4b-vibeapps-lora-r64)