Skip to content

Commit c45a9e7

Browse files
committed
feat(loop): integrate ideas queue into planning phase
Implement comprehensive ideas queue integration: Before planning phase: 1. Load all ideas from .opencoder/ideas/ 2. Handle three cases: - 0 ideas: Continue with autonomous planning - 1 idea: Use directly without AI selection - 2+ ideas: AI selects simplest/quick-win considering dependencies For selected idea: - Log summary and (for multiple) AI's selection reason - Delete idea file before planning (prevent retry loops) - Generate plan specifically for idea - Fall back to autonomous planning if idea planning fails Logging includes: - Number of ideas found - Selected idea filename - Idea summary (first line or ~100 chars) - AI's reasoning for selection Error handling: - Gracefully skip invalid/unreadable ideas - Fall back to autonomous planning on failure - Continue loop on selection failure Signed-off-by: leocavalcante <[email protected]>
1 parent 753f4c3 commit c45a9e7

File tree

1 file changed

+108
-12
lines changed

1 file changed

+108
-12
lines changed

src/loop.zig

Lines changed: 108 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const config = @import("config.zig");
1111
const state = @import("state.zig");
1212
const fsutil = @import("fs.zig");
1313
const plan = @import("plan.zig");
14+
const ideas = @import("ideas.zig");
1415
const evaluator = @import("evaluator.zig");
1516
const Logger = @import("logger.zig").Logger;
1617
const 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

Comments
 (0)