feat: фаза ready — черновик готов как есть, без требований к изменённым полям
Аналитик теперь может вернуть phase=ready, когда черновик уже полный и менять нечего. Раньше модель не могла это выразить и возвращала пустой propose, который валидатор резал A3 (нет изменённых полей). - analyst: case ready в validateResponse (без требований к полям) - core: propose и ready обрабатываются одинаково (applyDraft + E1 + ready) - prompt/analyst.md: контракт фаз обновлён (ask|propose|ready|abort) - тест TestDecideReady + README: раздел фаз аналитика
This commit is contained in:
@@ -173,6 +173,8 @@ func validateResponse(ar *AnalystResponse) error {
|
||||
if ar.Title == "" && ar.Goal == "" && len(ar.Repos) == 0 && ar.Why == "" && ar.AC == "" {
|
||||
return fmt.Errorf("phase=propose, но нет ни одного изменённого поля")
|
||||
}
|
||||
case "ready":
|
||||
// черновик уже полный и готов как есть — изменённых полей НЕ требуется
|
||||
case "abort":
|
||||
// abort_reason — не обязателен, но желателен
|
||||
default:
|
||||
|
||||
@@ -87,6 +87,23 @@ func TestDecideAbort(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecideReady(t *testing.T) {
|
||||
// ready с пустыми изменёнными полями — ВАЛИДНО (черновик готов как есть)
|
||||
a := &Analyst{Runner: &mockRunner{result: &opencode.Result{
|
||||
RC: 0,
|
||||
Stdout: `{"type":"text","part":{"text":"{\"phase\":\"ready\",\"chat_reply\":\"Черновик готов, запускаю.\"}"}}`,
|
||||
}}, Worktree: "/tmp"}
|
||||
|
||||
history := []core.Message{{Role: "user", Content: "Сделай калькулятор"}}
|
||||
dec, err := a.Decide(context.Background(), history, storage.Task{}, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Decide err: %v", err)
|
||||
}
|
||||
if dec.Phase != "ready" {
|
||||
t.Errorf("Phase = %q, want ready", dec.Phase)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeFail(t *testing.T) {
|
||||
a := &Analyst{Runner: &mockRunner{result: &opencode.Result{
|
||||
RC: 0,
|
||||
|
||||
@@ -24,6 +24,14 @@ var promptTemplate = template.Must(template.New("analyst").Parse(`Ты — ан
|
||||
| why | зачем это нужно, контекст |
|
||||
| ac | acceptance criteria — конкретный результат, что считается готовым |
|
||||
|
||||
Изменяй в JSON только те поля, которые надо поменять; что менять не надо — пустой строкой.
|
||||
|
||||
**Фаза ответа (phase):**
|
||||
- `ask` — данных не хватает: задай вопросы (до 3), черновик не меняешь.
|
||||
- `propose` — черновик ДОСТАТОЧЕН и ты ВНОСИШЬ правки: заполни изменяемые поля (title/goal/repos/why/ac), в chat_reply — краткое резюме.
|
||||
- `ready` — черновик уже ПОЛНЫЙ и готов как есть, менять НЕЧЕГО: phase="ready", все поля изменений оставь пустыми, в chat_reply — резюме и подтверждение готовности. Задачу можно отправлять агенту-кодеру.
|
||||
- `abort` — тема не про код / не подходит: phase="abort" с abort_reason.
|
||||
|
||||
{{- if .Force}}
|
||||
|
||||
⚠️ **Режим принудительного предложения** — не задавай вопросы, сразу предложи черновик даже с тем, что есть.
|
||||
@@ -46,7 +54,7 @@ var promptTemplate = template.Must(template.New("analyst").Parse(`Ты — ан
|
||||
|
||||
**Ответь строго JSON-объектом, без лишнего текста:**
|
||||
{
|
||||
"phase": "ask|propose|abort",
|
||||
"phase": "ask|propose|ready|abort",
|
||||
"title": "название (только если меняешь)",
|
||||
"goal": "цель (только если меняешь)",
|
||||
"repos": ["имя_репо_1", "имя_репо_2"],
|
||||
|
||||
Reference in New Issue
Block a user