@saadnvd1/agent-os 0.3.581 → 0.3.582
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/lib/tasks/queue.ts +21 -10
- package/lib/tasks/schedule.ts +9 -5
- package/package.json +1 -1
package/lib/tasks/queue.ts
CHANGED
|
@@ -189,7 +189,10 @@ const workspaceOf = (projectId: string) =>
|
|
|
189
189
|
// gives its slot back until it resumes. A quick change
|
|
190
190
|
// runs no agent, so it holds none. Without a
|
|
191
191
|
// workspace, the project is the scope.
|
|
192
|
-
function runningIn(
|
|
192
|
+
function runningIn(
|
|
193
|
+
scope: { workspaceId: string | null; projectId: string },
|
|
194
|
+
forSlots = false
|
|
195
|
+
) {
|
|
193
196
|
const where = scope.workspaceId
|
|
194
197
|
? `p.workspace_id = @ws`
|
|
195
198
|
: `p.id = @project AND p.workspace_id IS NULL`;
|
|
@@ -199,6 +202,7 @@ function runningIn(scope: { workspaceId: string | null; projectId: string }) {
|
|
|
199
202
|
`SELECT s.id FROM sessions s JOIN projects p ON p.id = s.project_id
|
|
200
203
|
WHERE ${where} AND s.archived_at IS NULL AND s.quick_of IS NULL
|
|
201
204
|
AND (s.pause_state IS NULL OR s.pause_state != 'paused')
|
|
205
|
+
${forSlots ? `AND NOT (COALESCE(s.plan_only, 0) = 1 AND COALESCE(s.plan_phase, '') != 'implementing')` : ""}
|
|
202
206
|
AND s.task_status IN (${IN_FLIGHT.map((s) => `'${s}'`).join(", ")})`
|
|
203
207
|
)
|
|
204
208
|
.all({ ws: scope.workspaceId, project: scope.projectId }) as {
|
|
@@ -214,7 +218,8 @@ function startingIn(workspaceId: string): number {
|
|
|
214
218
|
db
|
|
215
219
|
.prepare(
|
|
216
220
|
`SELECT COUNT(*) AS n FROM task_queue q JOIN projects p ON p.id = q.project_id
|
|
217
|
-
WHERE q.status = 'starting' AND p.workspace_id =
|
|
221
|
+
WHERE q.status = 'starting' AND p.workspace_id = ?
|
|
222
|
+
AND q.plan_only IS NULL`
|
|
218
223
|
)
|
|
219
224
|
.get(workspaceId) as { n: number }
|
|
220
225
|
).n
|
|
@@ -315,7 +320,8 @@ const waitingIn = (workspaceId: string) =>
|
|
|
315
320
|
.prepare(
|
|
316
321
|
`SELECT COUNT(*) AS n FROM task_queue q JOIN projects p ON p.id = q.project_id
|
|
317
322
|
WHERE q.status = 'queued' AND p.workspace_id = ?
|
|
318
|
-
AND q.after_task IS NULL AND q.after_any IS NULL
|
|
323
|
+
AND q.after_task IS NULL AND q.after_any IS NULL
|
|
324
|
+
AND q.plan_only IS NULL`
|
|
319
325
|
)
|
|
320
326
|
.get(workspaceId) as { n: number }
|
|
321
327
|
).n;
|
|
@@ -344,9 +350,10 @@ export function queueIfNeeded(req: QueueRequest): QueuedTaskView | null {
|
|
|
344
350
|
} else if (after)
|
|
345
351
|
afterTask = resolveAfter(after, req.originWorkspaceId ?? workspaceId).id;
|
|
346
352
|
const full =
|
|
353
|
+
!req.planOnly &&
|
|
347
354
|
limit !== null &&
|
|
348
355
|
!!workspaceId &&
|
|
349
|
-
(runningIn({ workspaceId, projectId: project.id }).length +
|
|
356
|
+
(runningIn({ workspaceId, projectId: project.id }, true).length +
|
|
350
357
|
startingIn(workspaceId) >=
|
|
351
358
|
limit ||
|
|
352
359
|
waitingIn(workspaceId) > 0);
|
|
@@ -360,6 +367,7 @@ export function queueIfNeeded(req: QueueRequest): QueuedTaskView | null {
|
|
|
360
367
|
const loaded =
|
|
361
368
|
!waits &&
|
|
362
369
|
!full &&
|
|
370
|
+
!req.planOnly &&
|
|
363
371
|
!!req.originWorkspaceId &&
|
|
364
372
|
loadHeldStart(project.id, req.prompt, setting);
|
|
365
373
|
if (!waits && !full && !loaded) return null;
|
|
@@ -523,9 +531,10 @@ export const queuedView = (id: string) =>
|
|
|
523
531
|
|
|
524
532
|
// Why an automatic start has to wait, or null. A start now by a person
|
|
525
533
|
// isn't held.
|
|
526
|
-
function autoHold(workspaceId: string | null): Hold | null {
|
|
534
|
+
function autoHold(workspaceId: string | null, planOnly = false): Hold | null {
|
|
527
535
|
if (workspaceId && isPaused(workspaceId))
|
|
528
536
|
return { code: "orch_paused", text: "Waiting: the orchestrator is paused" };
|
|
537
|
+
if (planOnly) return null;
|
|
529
538
|
const window = brakesEnabled() ? windowRefusal(readUsage()) : null;
|
|
530
539
|
return window ? { code: "window", text: `Waiting: ${window}` } : null;
|
|
531
540
|
}
|
|
@@ -609,7 +618,7 @@ async function startRow(
|
|
|
609
618
|
return "failed";
|
|
610
619
|
}
|
|
611
620
|
if (!opts.force) {
|
|
612
|
-
const held = autoHold(workspaceId);
|
|
621
|
+
const held = autoHold(workspaceId, !!r.plan_only);
|
|
613
622
|
if (held) {
|
|
614
623
|
if (r.note !== held.text)
|
|
615
624
|
patch(r.id, { note: held.text, wait_code: held.code });
|
|
@@ -621,7 +630,8 @@ async function startRow(
|
|
|
621
630
|
if (
|
|
622
631
|
workspaceId &&
|
|
623
632
|
limit !== null &&
|
|
624
|
-
|
|
633
|
+
!r.plan_only &&
|
|
634
|
+
runningIn({ workspaceId, projectId: r.project_id }, true).length +
|
|
625
635
|
startingIn(workspaceId) >=
|
|
626
636
|
limit
|
|
627
637
|
)
|
|
@@ -643,7 +653,7 @@ async function startRow(
|
|
|
643
653
|
}
|
|
644
654
|
if (!claimed) return "held";
|
|
645
655
|
const placed = opts.placement ?? null;
|
|
646
|
-
if (!opts.force)
|
|
656
|
+
if (!opts.force && !r.plan_only)
|
|
647
657
|
recordAutoStart(placed?.hostId ?? LOCAL, !!opts.heavy, Date.now());
|
|
648
658
|
// A linked machine's start never sees this machine's held messages: they
|
|
649
659
|
// go with the brief it is sent.
|
|
@@ -747,7 +757,7 @@ function groupFor(
|
|
|
747
757
|
const scope = { workspaceId, projectId };
|
|
748
758
|
return {
|
|
749
759
|
inFlight:
|
|
750
|
-
runningIn(scope).length +
|
|
760
|
+
runningIn(scope, true).length +
|
|
751
761
|
(workspaceId ? (reserved.get(workspaceId) ?? 0) : 0) +
|
|
752
762
|
startingRows,
|
|
753
763
|
limit: limitOf(workspaceId) ?? Number.POSITIVE_INFINITY,
|
|
@@ -814,8 +824,9 @@ function candidateOf(
|
|
|
814
824
|
heavy: heavyNeeds(needs),
|
|
815
825
|
needsUnmet: !remote && !meetsNeeds(needs, machineCapabilities()),
|
|
816
826
|
remote,
|
|
827
|
+
planOnly: !!r.plan_only,
|
|
817
828
|
before,
|
|
818
|
-
auto: autoHold(r.workspace_id),
|
|
829
|
+
auto: autoHold(r.workspace_id, !!r.plan_only),
|
|
819
830
|
any,
|
|
820
831
|
},
|
|
821
832
|
};
|
package/lib/tasks/schedule.ts
CHANGED
|
@@ -82,6 +82,9 @@ export interface Candidate {
|
|
|
82
82
|
needsUnmet: boolean;
|
|
83
83
|
// Starts on another machine: this one's load doesn't matter to it.
|
|
84
84
|
remote: boolean;
|
|
85
|
+
// A plan-only task before approval: it reads code and writes one file, so
|
|
86
|
+
// load, spacing and the slot limit don't apply. Pause and `after` still do.
|
|
87
|
+
planOnly?: boolean;
|
|
85
88
|
// `after X` hold, from the caller (it needs the database).
|
|
86
89
|
before: Hold | null;
|
|
87
90
|
// Orchestrator Pause and the usage window, which hold after `after`.
|
|
@@ -127,11 +130,12 @@ const seconds = (ms: number) => Math.max(1, Math.ceil(ms / 1000));
|
|
|
127
130
|
|
|
128
131
|
// The machine holds, in order. Null: it may start here now.
|
|
129
132
|
export function machineHold(
|
|
130
|
-
c: Pick<Candidate, "heavy" | "needsUnmet" | "remote" | "priority"
|
|
133
|
+
c: Pick<Candidate, "heavy" | "needsUnmet" | "remote" | "priority"> &
|
|
134
|
+
Partial<Pick<Candidate, "planOnly">>,
|
|
131
135
|
m: MachineView,
|
|
132
136
|
now: number
|
|
133
137
|
): Hold | null {
|
|
134
|
-
if (c.remote) return null;
|
|
138
|
+
if (c.remote || c.planOnly) return null;
|
|
135
139
|
if (c.needsUnmet) return { code: "needs", text: `Waiting: needs a Mac` };
|
|
136
140
|
if (!m.enabled) return null;
|
|
137
141
|
if (m.reading)
|
|
@@ -226,7 +230,7 @@ export function planStarts(
|
|
|
226
230
|
priority: c.priority,
|
|
227
231
|
});
|
|
228
232
|
if (hold) return void plan.explain.set(c.id, view(hold));
|
|
229
|
-
if (inFlight >= group.limit)
|
|
233
|
+
if (!c.planOnly && inFlight >= group.limit)
|
|
230
234
|
return void plan.explain.set(
|
|
231
235
|
c.id,
|
|
232
236
|
view({
|
|
@@ -240,8 +244,8 @@ export function planStarts(
|
|
|
240
244
|
if (free) used.add(free);
|
|
241
245
|
plan.consume.set(c.id, free);
|
|
242
246
|
}
|
|
243
|
-
inFlight += 1;
|
|
244
|
-
if (!c.remote) {
|
|
247
|
+
if (!c.planOnly) inFlight += 1;
|
|
248
|
+
if (!c.remote && !c.planOnly) {
|
|
245
249
|
m.lastAutoStartAt = now;
|
|
246
250
|
if (c.heavy) {
|
|
247
251
|
m.lastHeavyStartAt = now;
|