docs/adr/0010-runtime-replay.mdXem bản gốc Bản dịch đầy đủ theo đúng cấu trúc tài liệu; code, liên kết và định danh kỹ thuật được giữ nguyên.
0010. Kitaru phát lại cho người headless decode run — tái sử dụng tính năng phát lại gốc, chỉ xây dựng các công cụ hỗ trợ
Trạng thái: Đã chấp nhận Ngày: 2026-07-02
Bối cảnh
ADR-0008 đã decode runtime headless: Kitaru @flow (runtime/flow.py) chạy tương tự
build_agent() tự động, ghi lại Điểm kiểm tra bền bỉ và nhận Phát lại/Chờ trong
nơi của vòng lặp tương tác. ADR đó đã đóng khung Phát lại trong phạm vi hẹp - tiếp tục sự cố (các điểm kiểm tra đã hoàn thành
được cung cấp từ bộ đệm) và phát lại câu trả lời HITL. Tính năng phát lại của Kitaru có khả năng cao hơn nhiều: flow.replay(exec_id, từ_=<cp>, <flow-input-overrides>, ghi đè={…}) thực hiện lại một lần chạy đã ghi từ bất kỳ điểm kiểm tra nào
với một điều đã thay đổi, vì vậy bạn có thể hỏi chuyện gì sẽ xảy ra nếu bạn giao một mẫu khác
hoặc nhắc nhở - và sau đó phân biệt ngã ba với điều khiển trung thực. Đây là khả năng nổi bật của Kitaru
("đây là phần mà các công cụ khác không thể làm được"), đã được chứng minh là hoạt động ngoại tuyến trên ngăn xếp cục bộ trong
tests/integration/test_runtime_capstone.py (run_agent_task_hitl.replay(exec_id, from_=…) phục vụ
điểm kiểm tra mô hình ngược dòng từ bộ nhớ đệm trong khi bước cuối cùng chạy lại).
Người dùng muốn vòng lặp what-if đó cho decode run. Nguyên tắc thiết kế do người dùng quyết định là
thẳng thừng: ** tận dụng triệt để tính năng phát lại tự nhiên của Kitaru — decode chỉ xây dựng những khả năng hỗ trợ và phát minh lại ở mức tối thiểu
không có gì.** Không có công cụ tìm khác biệt phía decode, không có người chạy nhóm, không có máy ghi đè được triển khai lại.
Sự thật được xác nhận chống lại docs.zenml.io (dòng kitaru 0.18) + SDK đã cài đặt khi xác định phạm vi:
- ** Luồng chuyển tiếp phát lại đối tượng luồng được lập luận dưới dạng kwargs:**
flow.replay(exec_id, from_="cp", model="...", ghi đè={"checkpoint.x": …}). Vì vậy, phần ghi đè mô hình phải là tham số luồng để Kitaru hoán đổi nó được phát lại.client.executions.replay(...)và `` phát lại cuộc hành quyết kitaru --từ --args '{…}' --ghi đè '{…}'are the SDK/CLI mirrors (--args= flow inputs;--ghi đè điểm kiểm tra.X` = thay thế điểm kiểm tra-đầu ra). - Ghi đè chỉ cắn ở hạ lưu
from_. Replay phục vụ mọi thứ ngược dòng từ neo từ cache và thực thi lại neo + con cháu thực sự (capstone: phát lại từ terminal điểm kiểm tra khiến cho bộ đếm chân của mô hình không bị di chuyển). Vì vậy, Ghi đè mô hình chỉ có hiệu lực ở các lượt được thực hiện lại ở hạ lưu--from; để hoán đổi mô hình cho toàn bộ lần chạy, neo tại/trước lần chạy đầu tiên cuộc gọi mẫu. - Điểm kiểm tra mỗi lượt quá thô để có thể neo phát lại trước lệnh gọi mô hình. Tính sẵn sàng phát lại
yêu cầu
checkpoint_strategy="calls". HITL đã có hiệu lực"calls"; mặc định chạy bypass là"turn"(settings.runtime_checkpoint_strategy). "calls"có thể phá vỡ dòng bypass.wait()trích xuất trả về giống như cách đã làm với HITL (_MultipleTerminalStepsOutputError— ADR-0008 §3 sửa đổi 5). Bản sửa lỗi của luồng HITL là một terminal@checkpoint _capture_runtime_output+ một trình đọc hiện vật được đặt tên.- Không thể điền trước thời gian chờ khi phát lại ("phải được giải quyết thông qua luồng đầu vào chờ thông thường").
Lần chạy HITL được phát lại sẽ hỏi lại mọi phê duyệt/câu hỏi trên ngăn xếp cục bộ (capstone
test_replay_re_asks_a_wait_on_the_local_stack). Việc tái sử dụng câu trả lời thực sự cần một ngăn xếp được triển khai. - Mỗi lần gọi công cụ
output=/raise_=mô phỏng là lộ trình của Kitaru, không được xuất xưởng.--overrides checkpoint.Xlà dự phòng hiện tại. Khác biệt và đoàn hệ cũng không phải là API được đóng gói trong 0,18 (đã được kiểm chứng bằng thực nghiệm khi xây dựng nhiệm vụ 070: khôngkitaru diffCLI, khôngforked.diff()/.diff()SDK, khôngkitaru_recipesmô-đun). Khác biệt hôm nay là sự so sánh thủ công của hai vụ hành quyếtkitaru <id>outputs; a cohort is therun_cohortmẫu ví dụ từ repository ví dụ của Kitaru (được xây dựng trênexecutions.replay), rõ ràng là không có trongkitarugói.
Các ràng buộc của dự án được tôn trọng: cơ sở hạ tầng được nhập/gọi trực tiếp (không có trình bao bọc); sự tương tác
REPL và nhật ký JSONL của nó không bị ảnh hưởng (chỉ không có đầu); runtime/ vẫn là mô-đun bị cô lập. ADR này
mở rộng ADR-0008 (không thay thế nó) và được sắp xếp thành các nhiệm vụ 067-070 (tính năng
runtime-replay).
Quyết định
-
Tái sử dụng bản phát lại gốc của Kitaru; decode chỉ hỗ trợ xây dựng.
decode replaylà một lớp bọc mỏng kết thúcrun_agent_task.replay(...)có ngữ nghĩa neo phản chiếu Kitaru 1:1. Khác biệt (sách hướng dẫn hai-executions getso sánh ngày hôm nay), ghi đè điểm kiểm tra và thử nghiệm đoàn hệ (run_cohortmẫu ví dụ) ở trên bề mặt toán tử Kitaru (ví dụ CLI + SDK +); decode không thực hiện lại chúng (nó ghi lại chúng - §6). Điều này giữ cho tính năng này nhỏ gọn và phù hợp với Kitaru lộ trình miễn phí. -
Mô hình dưới dạng tham số luồng có thể phát lại (nhiệm vụ 067). Chủ đề
model: str | None = Nonethông qua_build_model → build_agent → _build_runtime_agent/_build_hitl_runtime_agent → run_agent_task/ run_agent_task_hitl.không córeadscài đặt.<provider>_model(không thay đổi byte); một giá trị ghi đè chỉ id mẫu của nhà cung cấp đang hoạt động. Nhà cung cấp vẫn được lựa chọn bởiLLM_PROVIDER- không trao đổi nhà cung cấp chéo (không phải mục tiêu vĩnh viễn). Trở thành đầu vào luồng chính xác là điều cho phép Kitaru hoán đổi nó quaflow.replay(..., model=…). -
Mặc định
checkpoint_strategy="calls"(nhiệm vụ 068), được đảm bảo an toàn cho vòng lặp."calls"ghi lại một điểm kiểm tra cho mỗi lệnh gọi mô hình/công cụ, vì vậy mọidecode runsẵn sàng phát lại - Bản phát lại có thể neo trước một nội dung cụ thể cuộc gọi mẫu;"turn"(một điểm kiểm tra thô cho mỗi lần chạy) là lựa chọn không tham gia rẻ hơn và chỉ có thể được thực hiện lại toàn bộ."calls"an toàn vòng lặp trên gemini (nhà cung cấp có dây): Kitaru chạy từng điểm kiểm tra trong sở hữuasyncio.runvòng lặp sự kiện, vì vậy, decode sẽ xây dựng ứng dụng khách chế độ luồng của gemini với HTTP duy trì hoạt động bị vô hiệu hóa (_flow_mode_http_client) — không có kết nối gộp nào tồn tại sau một vòng lặp của điểm kiểm tra bị đứt chống lại nó vào lần tiếp theo (RuntimeError('Event loop is closed')) và thời gian chờ của nó sẽ xóa Gemini's Thời hạn tối thiểu 10s. (openrouter/modal chia sẻ vấn đề tiềm ẩn trong"calls"và sẽ cần điều tương tự khách hàng nối dây thông qua họAsyncOpenAI—factory.py.) Nhiệm vụ 068.wait()sửa chữa vẫn còn đất: bỏ qua.wait()nghỉ khai thác trở lại dưới"calls", do đó, luồng thông qua bản sửa lỗi HITL đã vận chuyển (terminal@checkpoint _capture_runtime_output_load_runtime_outputngười đọc; CLI đọc tạo phẩm chứ không phải.wait().output) — mà HITL (luôn luôn"calls") và đường vòng"calls"con đường cả hai đều cần. (Lịch sử: 068 bị lật"turn" → "calls"; một sự thật nhiều lượtdecode runsau đó xuất hiện sự cố vòng lặp sự kiện vòng lặp chéo; thay vì rút lui"turn", decode được thực hiện"calls"an toàn vòng lặp thông qua ứng dụng khách luồng không còn tồn tại, giữ nguyên giá trị mặc định chi tiết.)
-
decode run --model X+ hiển thị exec_id (tác vụ 069). Hiển thị tham số §2 dưới dạng cờ và ngừng loại bỏFlowHandle(hôm naycli.py:364): in câu trả lời ra stdout, sau đóexec_id: <id>+ a paste-readydecode phát lại <id> --model …gợi ý về stderr, vì vậy điểm kiểm tra→vòng lặp phát lại có thể được phát hiện và thiết bị xuất chuẩn luôn sạch sẽ. -
decode replay <exec_id> [--from <cp>] [--model Y]— mỏng, chỉ bỏ qua, 1:1 Kitaru (nhiệm vụ 070). kết thúc tốt đẹprun_agent_task.replay(exec_id, from_=…, model=…).--frombản đồ thẳng tới Kitaru'sfrom_và phản ánh chính xác hành vi của Kitaru - decode không phát minh ra mỏ neo mặc định nào; nếu kitaru yêu cầufrom_,decode replaythể hiện yêu cầu riêng của Kitaru như một đường dây thân thiện.--modelmặc định = phát lại nguyên trạng. In exec_id mới + một gợi ý khác chỉ vào Kitaru đã được xác nhận bề mặt. Chỉ bỏ qua: một HITL exec_id không thân thiện (phát lại HITL yêu cầu lại mỗi lần chờ - §7) và chỉ vàokitaru executions replay. Gửi kèm thử nghiệm tích hợp NGOẠI TUYẾN chứng minh việc hoán đổi mô hình thực hiện lại các lượt rẽ xuôi dòng với mô hình mới. -
Bề mặt toán tử Kitaru vẫn nằm trên Kitaru; decode tài liệu đó (nhiệm vụ 070). AGENTS.md nhận được điểm kiểm tra→phát lại→khác biệt→quyết định vở kịch: quy tắc "ba lần chạy, không phải hai" (Đã quan sát → Đường cơ sở Chạy lại điều khiển → Fork),
kitaru executions replay --args/--overrides,--ghi đè checkpoint.Xlàm bản mô phỏng đầu ra của công cụ (các mô hình trên mỗi công cụ là lộ trình), khác với hướng dẫn sử dụng hai-kitaru executions getso sánh (khôngkitaru diffCLI /forked.diff()trong 0,18), vàrun_cohortmẫu ví dụ (không có trongkitarugói) cho đoàn hệ. -
Việc phát lại HITL với việc sử dụng lại câu trả lời bị hoãn lại. Trên ngăn xếp nội bộ đang xử lý, một lần chạy HITL được phát lại hỏi lại mỗi lần phê duyệt/
ask_user(Kitaru không thể điền trước kết quả chờ đợi; đã được chứng minh bằng capstone). thực việc tái sử dụng câu trả lời cần một ngăn xếp được triển khai, vì vậy nó được đặt ởtasks/future/hitl-replay-answer-reuse.mdvà được chọn ở cột mốc triển khai. Đây là lý do tại sao §5 chỉ có tính năng bỏ qua.
Phi mục tiêu (NG, vĩnh viễn): phía decode diff/cohort lệnh; trao đổi mô hình giữa các nhà cung cấp
phát lại; mỗi cuộc gọi công cụ output=/raise_= giả (sử dụng --overrides checkpoint.X); bất kỳ thay đổi nào đối với
đường dẫn REPL trực tiếp (chỉ không có đầu).
Sơ đồ
flowchart TB
subgraph obs["OBSERVED — the recorded run (task 069)"]
run["decode run --model A 'task'"]
flowA["@flow run_agent_task(task, model=A)"]
cps[("Checkpoints (calls) — task 068<br/>cp1 · cp2 · … · cpN<br/>durable in the Kitaru store")]
outA["answer + exec_id: kr-A (stderr hint)"]
run --> flowA --> cps --> outA
end
subgraph enabler["ENABLER (task 067)"]
param["model: str | None threaded<br/>_build_model → build_agent → seams → flows<br/>overrides only the active provider's model id"]
end
param -. makes model a swappable flow input .-> flowA
subgraph replay["REPLAY — what-if (task 070)"]
rcmd["decode replay kr-A --from cpK --model B"]
cache[("cp1 … cp(K-1)<br/>served from CACHE (model A)")]
reexec["cpK … cpN RE-EXECUTE for real<br/>with Model Override B"]
fork["FORK: new exec kr-B<br/>original_exec_id → kr-A"]
rcmd --> cache
rcmd --> reexec --> fork
end
cps -. flow.replay(kr-A, from_=cpK, model=B) .-> rcmd
subgraph ops["KITARU OPERATOR SURFACE — documented, not wrapped (task 070)"]
baseline["Baseline Rerun (control)<br/>kitaru executions replay kr-A --from cpK"]
diff["compare fork vs baseline (manual)<br/>kitaru executions get kr-B / kr-A → decision · cost · latency Δ"]
over["--overrides 'checkpoint.X': … (tool-output stand-in)"]
cohort["run_cohort example (examples repo,<br/>not in the kitaru package)"]
fork --> diff
baseline --> diff
diff --> decide{{"ship the change? keep / reject"}}
cohort --> decide
end
reexec -. tool-output mock .-> over
subgraph deferred["DEFERRED (tasks/future/)"]
hitl["HITL replay with answer-reuse<br/>needs a DEPLOYED stack — waits re-ask locally"]
end
fork -. bypass-only; HITL exec_id → friendly error .-> hitl
classDef observed fill:#1565c0,stroke:#0d47a1,color:#ffffff;
classDef store fill:#37474f,stroke:#102027,color:#ffffff;
classDef enable fill:#00838f,stroke:#005662,color:#ffffff;
classDef rep fill:#2e7d32,stroke:#1b5e20,color:#ffffff;
classDef opsc fill:#e65100,stroke:#bf360c,color:#ffffff;
classDef defer fill:#6a1b9a,stroke:#38006b,color:#ffffff;
class run,flowA,outA observed;
class cps,cache store;
class param enable;
class rcmd,reexec,fork rep;
class baseline,diff,over,cohort,decide opsc;
class hitl defer;
hậu quả
- Tính năng nhỏ, khả năng lớn. Bốn công cụ hỗ trợ nhỏ (thông số luồng, sửa chữa ghi lại đầu ra bỏ qua, một lá cờ, một lớp bao bọc mỏng) mở khóa vòng lặp phát lại/điều gì xảy ra nếu của Kitaru và quy trình làm việc của người vận hành được xây dựng trên đó (khác biệt, ghi đè điểm kiểm tra, ví dụ về đoàn hệ). Mọi thứ khó khăn đều là của Kitaru, không phải của bộ decode.
- Mặc định
decode runcó thể chơi lại một cách chi tiết."calls"ghi lại một điểm kiểm tra cho mỗi mô hình/công cụ cuộc gọi, do đó, bản phát lại có thể neo trước một cuộc gọi mô hình cụ thể - an toàn vòng lặp trên gemini thông qua keep-alive-free flow client (Quyết định 3; openrouter/modal sẽ cần hệ thống dây điện tương tự).RUNTIME_CHECKPOINT_STRATEGY=turnlà lựa chọn không tham gia rẻ hơn (một điểm kiểm tra mỗi lần chạy), nhưng"turn"run chỉ có thể được phát lại toàn bộ. - Việc hoán đổi mô hình có thể phân tách chuỗi cuộc gọi được ghi lại. Một mô hình khác có thể gọi công cụ khác nhau
hạ lưu của
--from; Kitaru có thể nâng caoKitaruDivergenceError.decode replaybề mặt nó như một dòng thân thiện (đó là kết quả giả định trung thực - sự thay đổi đã chuyển hướng cuộc chạy), không bao giờ truy tìm lại.KitaruStateError(mơ hồ--from) cũng được xử lý tương tự. - Cái
.wait()-dưới-"calls"việc sửa chữa được xác minh trước, không được giả định. Nhiệm vụ 068 đo lường thực tế bỏ qua hành vi trước khi lựa chọn giữa việc giữ.wait().outputvà áp dụng đầu ra HITL tạo tác - mẫu sửa lỗi đã tồn tại, do đó rủi ro bị hạn chế. - Chỉ bỏ qua là giới hạn có chủ ý, được ghi lại. Tính năng phát lại HITL yêu cầu lại mỗi lần chờ trên cục bộ
ngăn xếp (Kitaru không thể điền trước kết quả chờ); việc sử dụng lại câu trả lời được hoãn lại theo cột mốc triển khai
(
tasks/future/).decode replaytừ chối HITL exec_id có hướng dẫn thay vì âm thầm nhắc lại. - CI vẫn ngoại tuyến. Bằng chứng phát lại mới dựa trên capstone
isolated_kitaru_store+ theo kịch bảnFunctionModelđường nối — không có máy chủ, không có mạng, không có khóa — phản ánh mọi thử nghiệm runtime trước đó. - REPL không có kitaru.
decode replaynhập khẩuruntime/lười biếng, giống hệt nhưdecode chạy;nhập decode.clivẫn không bao giờ nhập kitaru. - Mở rộng, không thay thế, ADR-0008. Các quyết định Phát lại/Điểm kiểm tra/Chờ của ADR-0008 vẫn giữ nguyên; cái này
ADR chỉ mở rộng tính năng Phát lại cho trường hợp sử dụng giả định và thêm bốn công cụ hỗ trợ. Bảng thuật ngữ
Replayhàng được mở rộng và tăngModel Override,Fork,Baseline Rerun,Checkpoint Override.