@@ -11,6 +11,7 @@ const config = @import("config.zig");
1111const state = @import ("state.zig" );
1212const fsutil = @import ("fs.zig" );
1313const plan = @import ("plan.zig" );
14+ const ideas = @import ("ideas.zig" );
1415const evaluator = @import ("evaluator.zig" );
1516const Logger = @import ("logger.zig" ).Logger ;
1617const Executor = @import ("executor.zig" ).Executor ;
@@ -74,18 +75,113 @@ pub const Loop = struct {
7475
7576 // Planning phase
7677 if (! fsutil .fileExists (self .paths .current_plan ) or self .st .phase == .planning ) {
77- const result = self .executor .runPlanning (self .st .cycle ) catch | err | {
78- self .log .logError ("" );
79- self .log .logErrorFmt ("[Cycle {d}] Planning phase failed: {s}" , .{ self .st .cycle , @errorName (err ) });
80- self .log .logError (" The AI was unable to create a development plan" );
81- self .log .logError (" This could be due to:" );
82- self .log .logError (" - OpenCode CLI issues (check installation)" );
83- self .log .logError (" - Model API unavailability or rate limits" );
84- self .log .logError (" - Network connectivity problems" );
85- self .log .logErrorFmt (" Retrying after backoff..." , .{});
86- self .backoffSleep ();
87- continue ;
88- };
78+ // Check for ideas first
79+ var idea_list = ideas .loadAllIdeas (self .paths .ideas_dir , self .allocator , self .cfg .max_file_size ) catch null ;
80+
81+ var result : ExecutionResult = .failure ;
82+
83+ if (idea_list ) | * list | {
84+ defer list .deinit ();
85+
86+ if (list .ideas .len == 1 ) {
87+ // Single idea - use it directly
88+ const selected = & list .ideas [0 ];
89+ self .log .sayFmt ("[Cycle {d}] Found 1 idea: {s}" , .{ self .st .cycle , selected .filename });
90+
91+ const summary = selected .getSummary (self .allocator ) catch "(unable to get summary)" ;
92+ defer self .allocator .free (summary );
93+ self .log .sayFmt ("[Cycle {d}] Summary: {s}" , .{ self .st .cycle , summary });
94+
95+ // Remove the idea file before planning
96+ ideas .removeIdeaByPath (selected .path ) catch | err | {
97+ self .log .logErrorFmt ("Warning: Failed to remove idea file: {s}" , .{@errorName (err )});
98+ };
99+
100+ // Run planning for this idea
101+ result = self .executor .runIdeaPlanning (
102+ selected .content ,
103+ selected .filename ,
104+ self .st .cycle ,
105+ ) catch | err | {
106+ self .log .logError ("" );
107+ self .log .logErrorFmt ("[Cycle {d}] Idea planning failed: {s}" , .{ self .st .cycle , @errorName (err ) });
108+ self .log .logError (" The AI was unable to create a plan for the idea" );
109+ self .log .logErrorFmt (" Retrying after backoff..." , .{});
110+ self .backoffSleep ();
111+ continue ;
112+ };
113+ } else {
114+ // Multiple ideas - AI selects simplest one
115+ self .log .sayFmt ("[Cycle {d}] Found {d} idea(s) in queue" , .{ self .st .cycle , list .ideas .len });
116+
117+ // Format ideas for AI selection
118+ const formatted = ideas .formatIdeasForSelection (list .ideas , self .allocator ) catch | err | {
119+ self .log .logErrorFmt ("Failed to format ideas for selection: {s}" , .{@errorName (err )});
120+ // Fall through to normal planning below
121+ result = .failure ;
122+ continue ;
123+ };
124+ defer self .allocator .free (formatted );
125+
126+ // Have AI select the simplest idea
127+ const selection = self .executor .runIdeaSelection (formatted , self .st .cycle ) catch null ;
128+
129+ if (selection ) | sel | {
130+ defer self .allocator .free (sel .reason );
131+
132+ if (sel .index < list .ideas .len ) {
133+ const selected = & list .ideas [sel .index ];
134+ self .log .sayFmt ("[Cycle {d}] Selected idea: {s}" , .{ self .st .cycle , selected .filename });
135+
136+ const summary = selected .getSummary (self .allocator ) catch "(unable to get summary)" ;
137+ defer self .allocator .free (summary );
138+ self .log .sayFmt ("[Cycle {d}] Summary: {s}" , .{ self .st .cycle , summary });
139+ self .log .sayFmt ("[Cycle {d}] Reason: {s}" , .{ self .st .cycle , sel .reason });
140+
141+ // Remove the idea file before planning
142+ ideas .removeIdeaByPath (selected .path ) catch | err | {
143+ self .log .logErrorFmt ("Warning: Failed to remove idea file: {s}" , .{@errorName (err )});
144+ };
145+
146+ // Run planning for this specific idea
147+ result = self .executor .runIdeaPlanning (
148+ selected .content ,
149+ selected .filename ,
150+ self .st .cycle ,
151+ ) catch | err | {
152+ self .log .logError ("" );
153+ self .log .logErrorFmt ("[Cycle {d}] Idea planning failed: {s}" , .{ self .st .cycle , @errorName (err ) });
154+ self .log .logError (" The AI was unable to create a plan for the idea" );
155+ self .log .logErrorFmt (" Retrying after backoff..." , .{});
156+ self .backoffSleep ();
157+ continue ;
158+ };
159+ } else {
160+ self .log .logErrorFmt ("AI selected invalid idea index: {d}" , .{sel .index });
161+ result = .failure ;
162+ }
163+ } else {
164+ self .log .logError ("AI failed to select an idea, falling back to autonomous planning" );
165+ result = .failure ;
166+ }
167+ }
168+ }
169+
170+ // If no ideas or idea planning failed, do normal autonomous planning
171+ if (result == .failure ) {
172+ result = self .executor .runPlanning (self .st .cycle ) catch | err | {
173+ self .log .logError ("" );
174+ self .log .logErrorFmt ("[Cycle {d}] Planning phase failed: {s}" , .{ self .st .cycle , @errorName (err ) });
175+ self .log .logError (" The AI was unable to create a development plan" );
176+ self .log .logError (" This could be due to:" );
177+ self .log .logError (" - OpenCode CLI issues (check installation)" );
178+ self .log .logError (" - Model API unavailability or rate limits" );
179+ self .log .logError (" - Network connectivity problems" );
180+ self .log .logErrorFmt (" Retrying after backoff..." , .{});
181+ self .backoffSleep ();
182+ continue ;
183+ };
184+ }
89185
90186 if (result == .failure ) {
91187 self .log .logError ("" );
0 commit comments