oh-pi 0.1.59 → 0.1.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -159,7 +159,7 @@ interface WaveOptions {
|
|
|
159
159
|
/**
|
|
160
160
|
* 并发执行一批蚂蚁,自适应调节并发度
|
|
161
161
|
*/
|
|
162
|
-
async function runAntWave(opts: WaveOptions): Promise<"ok"> {
|
|
162
|
+
async function runAntWave(opts: WaveOptions): Promise<"ok" | "budget"> {
|
|
163
163
|
const { nest, cwd, caste, signal, callbacks, currentModel } = opts;
|
|
164
164
|
const casteModel = opts.modelOverrides?.[caste] || currentModel;
|
|
165
165
|
const config = { ...DEFAULT_ANT_CONFIGS[caste], model: casteModel };
|
|
@@ -168,7 +168,14 @@ async function runAntWave(opts: WaveOptions): Promise<"ok"> {
|
|
|
168
168
|
let consecutiveRateLimits = 0; // 连续限流计数
|
|
169
169
|
const retriedTasks = new Set<string>(); // 防止重复重试
|
|
170
170
|
|
|
171
|
-
const runOne = async (): Promise<"done" | "empty" | "rate_limited"> => {
|
|
171
|
+
const runOne = async (): Promise<"done" | "empty" | "rate_limited" | "budget"> => {
|
|
172
|
+
// Budget 刹车:预算用完就不出发(drone 免费,不检查)
|
|
173
|
+
const state = nest.getState();
|
|
174
|
+
if (state.maxCost != null && caste !== "drone") {
|
|
175
|
+
const spent = state.ants.reduce((s, a) => s + a.usage.cost, 0);
|
|
176
|
+
if (spent >= state.maxCost) return "budget";
|
|
177
|
+
}
|
|
178
|
+
|
|
172
179
|
const task = nest.nextPendingTask(caste);
|
|
173
180
|
if (!task) return "empty";
|
|
174
181
|
if (!nest.claimTask(task.id, "queen")) return "empty";
|
|
@@ -280,12 +287,16 @@ async function runAntWave(opts: WaveOptions): Promise<"ok"> {
|
|
|
280
287
|
}
|
|
281
288
|
|
|
282
289
|
const batch = Math.min(slotsAvailable, pending.length);
|
|
283
|
-
const promises: Promise<"done" | "empty" | "rate_limited">[] = [];
|
|
290
|
+
const promises: Promise<"done" | "empty" | "rate_limited" | "budget">[] = [];
|
|
284
291
|
for (let i = 0; i < batch; i++) {
|
|
285
292
|
promises.push(runOne());
|
|
286
293
|
}
|
|
287
294
|
const results = await Promise.all(promises);
|
|
288
295
|
|
|
296
|
+
if (results.includes("budget")) {
|
|
297
|
+
return "budget";
|
|
298
|
+
}
|
|
299
|
+
|
|
289
300
|
// 429 处理:降低并发 + 渐进退避(2s → 5s → 10s,上限 10s)
|
|
290
301
|
if (results.includes("rate_limited")) {
|
|
291
302
|
consecutiveRateLimits++;
|
|
@@ -431,9 +442,8 @@ export async function runColony(opts: QueenOptions): Promise<ColonyState> {
|
|
|
431
442
|
emitSignal("working", `${workerTasks.length} tasks to do`);
|
|
432
443
|
await runAntWave({ ...waveBase, caste: "worker" });
|
|
433
444
|
|
|
434
|
-
//
|
|
435
|
-
|
|
436
|
-
while (rounds < 3) {
|
|
445
|
+
// 处理工蚁产生的子任务(budget 驱动,无硬限制)
|
|
446
|
+
while (true) {
|
|
437
447
|
// 先跑 drone 子任务
|
|
438
448
|
const pendingDrones = nest.getAllTasks().filter(t => t.caste === "drone" && t.status === "pending");
|
|
439
449
|
if (pendingDrones.length > 0) await runAntWave({ ...waveBase, caste: "drone" });
|
|
@@ -442,9 +452,15 @@ export async function runColony(opts: QueenOptions): Promise<ColonyState> {
|
|
|
442
452
|
t.caste === "worker" && (t.status === "pending" || t.status === "blocked")
|
|
443
453
|
);
|
|
444
454
|
if (remaining.length === 0) break;
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
455
|
+
callbacks.onPhase?.("working", `${remaining.length} sub-tasks from workers...`);
|
|
456
|
+
const result = await runAntWave({ ...waveBase, caste: "worker" });
|
|
457
|
+
if (result === "budget") {
|
|
458
|
+
nest.updateState({ status: "budget_exceeded", finishedAt: Date.now() });
|
|
459
|
+
emitSignal("budget_exceeded", "Budget exhausted");
|
|
460
|
+
const budgetState = nest.getState();
|
|
461
|
+
callbacks.onComplete?.(budgetState);
|
|
462
|
+
return budgetState;
|
|
463
|
+
}
|
|
448
464
|
}
|
|
449
465
|
|
|
450
466
|
// ═══ Auto-check: run tsc before soldier review ═══
|