AI coding agent hoạt động bằng cách gọi tools — đọc file, chạy lệnh, tìm kiếm. Mỗi lần gọi là một round-trip tới LLM, và mỗi round-trip gửi lại toàn bộ context: system prompt, lịch sử hội thoại, định nghĩa tools.
Một task đơn giản — đọc 3 file rồi grep — tốn 4 round-trips. Context phình ra theo từng lượt:
LLM → read(file1) → 50k tokens
LLM → read(file2) → 55k tokens
LLM → read(file3) → 60k tokens
LLM → grep(pattern) → 65k tokens
─────────
~230k tokens
4 lần gọi, mỗi lần kéo theo cả đống context cũ. Đây là bottleneck lớn nhất về tốc độ lẫn chi phí.
Ý tưởng đơn giản: thay vì LLM gọi từng tool, LLM viết một đoạn JavaScript gọi tất cả cùng lúc. Engine chạy đoạn code đó locally rồi trả kết quả về trong một lượt duy nhất.
async () => {
const [a, b, c, d] = await Promise.all([
codemode.read({ path: "file1" }),
codemode.read({ path: "file2" }),
codemode.read({ path: "file3" }),
codemode.grep({ pattern: "TODO", path: "src/" }),
]);
return { a, b, c, d };
}4 round-trips thành 1. ~230k tokens thành ~50k. Các tool calls còn chạy song song qua Promise.all().
Luồng xử lý gồm 4 bước:
LLM viết code
↓ normalize — chuẩn hóa thành async arrow function
↓ execute — chạy trong sandbox, dispatch tool calls
↓ bridge — emit events để TUI render từng sub-tool
↓
Kết quả trả về LLM
LLM không viết code mù. Engine đọc JSON Schema của từng tool, convert sang TypeScript declarations, rồi nhúng vào tool description:
interface ReadInput {
/** File path to read */
path: string;
/** Line range [start, end] */
range?: number[];
}
declare const codemode: {
/** Read file contents */
read: (input: ReadInput) => Promise<unknown>;
/** Execute shell command */
bash: (input: BashInput) => Promise<unknown>;
};LLM nhìn thấy typed API này nên viết code đúng interface ngay từ đầu — không cần đoán tên hàm hay format tham số.
Bên trong sandbox, codemode là một Proxy object. Bất kỳ method call nào cũng được dispatch tới tool tương ứng:
const codemode = new Proxy({}, {
get: (_target, prop: string) => {
const fn = fns[prop];
if (!fn) return async () => { throw new Error(`Tool "${prop}" not found`) };
return async (args = {}) => fn(args);
},
});codemode.bash(...) → bash tool. codemode.read(...) → read tool. Không cần hardcode danh sách — thêm tool mới tự động có trong API.
LLM không phải lúc nào cũng viết code hoàn chỉnh. Normalizer xử lý mọi trường hợp:
- Đã là
async () => { ... }→ giữ nguyên - Code rời rạc → wrap vào async function, tự thêm
returncho expression cuối - Một dòng đơn → wrap với auto-return
Code chạy qua new AsyncFunction() với các globals nguy hiểm (process, require, Bun, globalThis) bị shadow thành undefined. console.log redirect vào logs riêng. Timeout 5 phút, hỗ trợ abort signal.
Đây là soft sandbox — mục đích hướng LLM viết code đúng API, không phải chống mã độc.
Mỗi codemode.* call emit event tool_start / tool_done / tool_error. TUI nhận events và render từng sub-tool giống hệt tool call bình thường — bash hiện bash box, read hiện file preview, grep hiện kết quả tìm kiếm. Người dùng không thấy khác biệt gì.
Code Mode là một package độc lập (packages/codemode/), tích hợp vào coding-agent qua 3 điểm:
- Setting
codemode.enabled— bật/tắt trong Settings, mặc định bật - Tool registry — khi bật, wrap tất cả tools thành một tool
codeduy nhất. Các tool cần tương tác người dùng (ask,report_finding, ...) được giữ nguyên - TUI renderer — render sub-tools bên trong code block y hệt tool calls thường
Code Mode không thêm khả năng mới — agent vẫn dùng cùng bộ tools. Nó thay đổi cách gọi: từ gọi lần lượt sang viết code điều phối. Ít round-trips, ít tokens, chạy song song, nhanh hơn.