Wire the reviewer and assert reflection on the wire
main injects the AI service as the reviewer alongside the other roles. A web test drives a session to Review and asserts the recap rides the state payload, then to the next Planning and asserts the carry-forward does too. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -45,7 +45,8 @@ func main() {
|
|||||||
ctrl.SetCoach(svc)
|
ctrl.SetCoach(svc)
|
||||||
ctrl.SetDriftJudge(svc)
|
ctrl.SetDriftJudge(svc)
|
||||||
ctrl.SetNudge(svc)
|
ctrl.SetNudge(svc)
|
||||||
log.Printf("ai: %s backend (coach + drift judge + nudge)", backend.Name())
|
ctrl.SetReviewer(svc)
|
||||||
|
log.Printf("ai: %s backend (coach + drift judge + nudge + reviewer)", backend.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wire the Tasks port: Amazing Marvin via ampy's `am` CLI. The command is
|
// Wire the Tasks port: Amazing Marvin via ampy's `am` CLI. The command is
|
||||||
|
|||||||
@@ -317,6 +317,51 @@ func TestPlanningStatePayloadCarriesKnowledge(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type stubReviewer struct {
|
||||||
|
refl ai.Reflection
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s stubReviewer) Review(ctx context.Context, finished, history string) (ai.Reflection, error) {
|
||||||
|
return s.refl, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReflectionFlowsToReviewThenPlanning(t *testing.T) {
|
||||||
|
s := newTestServer(t)
|
||||||
|
s.ctrl.SetReviewer(stubReviewer{refl: ai.Reflection{Recap: "held focus well", CarryForward: "start in the editor"}})
|
||||||
|
r := s.Router()
|
||||||
|
_ = post(t, r, "/planning", "")
|
||||||
|
body := `{"next_action":"a","success_condition":"b","timebox_secs":1500}`
|
||||||
|
if w := post(t, r, "/commitment", body); w.Code != http.StatusOK {
|
||||||
|
t.Fatalf("/commitment code %d body %s", w.Code, w.Body.String())
|
||||||
|
}
|
||||||
|
if w := post(t, r, "/complete", ""); w.Code != http.StatusOK {
|
||||||
|
t.Fatalf("/complete code %d", w.Code)
|
||||||
|
}
|
||||||
|
deadline := time.Now().Add(2 * time.Second)
|
||||||
|
for time.Now().Before(deadline) {
|
||||||
|
if rv := s.ctrl.State().Reflection; rv != nil && rv.Status == "ready" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(5 * time.Millisecond)
|
||||||
|
}
|
||||||
|
js := s.stateJSON()
|
||||||
|
if !strings.Contains(js, `"recap":"held focus well"`) {
|
||||||
|
t.Fatalf("review payload missing recap: %s", js)
|
||||||
|
}
|
||||||
|
|
||||||
|
// End -> Locked -> Planning: the carry-forward should surface on planning.
|
||||||
|
if w := post(t, r, "/end", ""); w.Code != http.StatusOK {
|
||||||
|
t.Fatalf("/end code %d", w.Code)
|
||||||
|
}
|
||||||
|
if w := post(t, r, "/planning", ""); w.Code != http.StatusOK {
|
||||||
|
t.Fatalf("/planning code %d", w.Code)
|
||||||
|
}
|
||||||
|
js2 := s.stateJSON()
|
||||||
|
if !strings.Contains(js2, `"carry_forward":"start in the editor"`) {
|
||||||
|
t.Fatalf("planning payload missing carry-forward: %s", js2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestKnowledgePathSelectionReloads(t *testing.T) {
|
func TestKnowledgePathSelectionReloads(t *testing.T) {
|
||||||
s := newTestServer(t)
|
s := newTestServer(t)
|
||||||
s.ctrl.SetKnowledge(stubSource{profile: knowledge.Profile{Path: "/default"}})
|
s.ctrl.SetKnowledge(stubSource{profile: knowledge.Profile{Path: "/default"}})
|
||||||
|
|||||||
Reference in New Issue
Block a user