@oxgeneral/orch 0.2.4 → 0.3.0
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/dist/App-TW35IULR.js +18 -0
- package/dist/agent-FRQKL7YI.js +9 -0
- package/dist/{orchestrator-OMU46RCE.js → chunk-2UC4SVJB.js} +190 -53
- package/dist/chunk-2UC4SVJB.js.map +1 -0
- package/dist/chunk-5AJ4LYO5.js +8 -0
- package/dist/{chunk-45K2XID7.js → chunk-6DWHQPTE.js} +2 -1
- package/dist/chunk-6DWHQPTE.js.map +1 -0
- package/dist/{chunk-POUC4CPC.js → chunk-6MJ7V6VY.js} +2 -2
- package/dist/{chunk-HNKJ4IF7.js → chunk-B4JQM4NU.js} +34 -10
- package/dist/chunk-B4JQM4NU.js.map +1 -0
- package/dist/{chunk-6HENRUYZ.js → chunk-CDFA4IIQ.js} +2 -2
- package/dist/chunk-CHRW4CLD.js +2 -0
- package/dist/{chunk-VAAOW526.js → chunk-GZ2Q56YZ.js} +2 -2
- package/dist/{doctor-service-QEJCE5FK.js → chunk-HMMPM7MF.js} +2 -2
- package/dist/{chunk-AELEEEV3.js → chunk-HSBYJ5C5.js} +27 -7
- package/dist/chunk-HXOMNULD.js +2 -0
- package/dist/{chunk-3TGCIXJA.js → chunk-IQXRQBUK.js} +2 -1
- package/dist/chunk-IQXRQBUK.js.map +1 -0
- package/dist/chunk-L26TK7Y5.js +2 -0
- package/dist/chunk-L3FYR45M.js +2 -0
- package/dist/chunk-LXNRCJ22.js +2 -0
- package/dist/{chunk-TX7WOFCW.js → chunk-MGFMVPRD.js} +4 -7
- package/dist/chunk-MGFMVPRD.js.map +1 -0
- package/dist/chunk-MNXU3KCD.js +2 -0
- package/dist/{chunk-CHIP7O6V.js → chunk-O2MSGW3V.js} +3 -1
- package/dist/chunk-O2MSGW3V.js.map +1 -0
- package/dist/chunk-PJ5DKXGR.js +2 -0
- package/dist/{chunk-2KSBOAW3.js → chunk-QEEM67OA.js} +11 -17
- package/dist/chunk-QEEM67OA.js.map +1 -0
- package/dist/chunk-UMZEA3JT.js +5 -0
- package/dist/{shell-OGTSH4RJ.js → chunk-UW6GUUE6.js} +3 -3
- package/dist/chunk-XDVMX2FO.js +8 -0
- package/dist/chunk-XDVMX2FO.js.map +1 -0
- package/dist/chunk-ZA5Z33GO.js +11 -0
- package/dist/claude-E36EGXUV.js +2 -0
- package/dist/{chunk-IRN2U2NE.js → claude-RIB3RQS5.js} +5 -2
- package/dist/claude-RIB3RQS5.js.map +1 -0
- package/dist/cli.js +1 -199
- package/dist/clipboard-service-PDTSZIR5.js +25 -0
- package/dist/codex-OTZKVESD.js +2 -0
- package/dist/{codex-U7LTJTX6.js → codex-VBUSA2GJ.js} +5 -3
- package/dist/codex-VBUSA2GJ.js.map +1 -0
- package/dist/config-CCSS2P7R.js +2 -0
- package/dist/container-OIXLFSX2.js +6 -0
- package/dist/context-GSMQHQES.js +7 -0
- package/dist/cursor-3DJA6LWS.js +2 -0
- package/dist/{cursor-3DI5GKRF.js → cursor-4QIOTDBW.js} +5 -3
- package/dist/cursor-4QIOTDBW.js.map +1 -0
- package/dist/doctor-KBK5JZBZ.js +2 -0
- package/dist/{chunk-K6DMQERQ.js → doctor-service-F2SXDWHS.js} +3 -1
- package/dist/doctor-service-F2SXDWHS.js.map +1 -0
- package/dist/doctor-service-PB7YBH3F.js +2 -0
- package/dist/goal-RFKFPR7M.js +8 -0
- package/dist/index.d.ts +105 -43
- package/dist/index.js +1817 -5
- package/dist/index.js.map +1 -1
- package/dist/init-WRDFAFS2.js +53 -0
- package/dist/logs-5QHJWMEG.js +12 -0
- package/dist/msg-4SCLBO4K.js +9 -0
- package/dist/orchestrator-FGGXK3N3.js +5 -0
- package/dist/{orchestrator-L6QX2LJ7.js.map → orchestrator-FGGXK3N3.js.map} +1 -1
- package/dist/orchestrator-R7IWZUT6.js +13 -0
- package/dist/process-manager-33H27MQF.js +2 -0
- package/dist/process-manager-A36Y7LHP.js +3 -0
- package/dist/{process-manager-TLZOTO4Y.js.map → process-manager-A36Y7LHP.js.map} +1 -1
- package/dist/registry-BO2PPRNG.js +2 -0
- package/dist/registry-JXXRLJ5J.js +3 -0
- package/dist/{registry-UQAHK77P.js.map → registry-JXXRLJ5J.js.map} +1 -1
- package/dist/run-HSHRELOP.js +3 -0
- package/dist/shell-EOJBDWTH.js +2 -0
- package/dist/{chunk-CIIE6LNG.js → shell-IH2MMTVP.js} +3 -2
- package/dist/shell-IH2MMTVP.js.map +1 -0
- package/dist/status-DLBNWSWM.js +2 -0
- package/dist/task-J6ZN7ALI.js +20 -0
- package/dist/team-MSIBKOQC.js +4 -0
- package/dist/template-engine-MFL5B677.js +3 -0
- package/dist/{template-engine-322SCRR6.js.map → template-engine-MFL5B677.js.map} +1 -1
- package/dist/template-engine-ONIDVD4F.js +2 -0
- package/dist/tui-G4XUFAIP.js +2 -0
- package/dist/update-PC2ENCKU.js +2 -0
- package/dist/update-check-HGMBDYHL.js +2 -0
- package/dist/workspace-manager-KOOYTO7E.js +3 -0
- package/dist/{workspace-manager-G5EQRS72.js → workspace-manager-T6AXG7XL.js} +4 -3
- package/dist/workspace-manager-T6AXG7XL.js.map +1 -0
- package/package.json +2 -1
- package/readme.md +5 -4
- package/scripts/benchmark.ts +304 -0
- package/dist/App-KHUT3IV7.js +0 -4962
- package/dist/agent-V5M2C3OC.js +0 -157
- package/dist/chunk-33QNTNR6.js +0 -46
- package/dist/chunk-6HENRUYZ.js.map +0 -1
- package/dist/chunk-AELEEEV3.js.map +0 -1
- package/dist/chunk-ED47GL3F.js +0 -29
- package/dist/chunk-FRTKB575.js +0 -87
- package/dist/chunk-HXYAZGLP.js +0 -15
- package/dist/chunk-I5WEMARW.js +0 -166
- package/dist/chunk-IZYSGYXG.js +0 -2
- package/dist/chunk-IZYSGYXG.js.map +0 -1
- package/dist/chunk-P6ATSXGL.js +0 -107
- package/dist/chunk-PBFE5V3G.js +0 -2
- package/dist/chunk-PBFE5V3G.js.map +0 -1
- package/dist/chunk-PNE6LQRF.js +0 -5
- package/dist/chunk-POUC4CPC.js.map +0 -1
- package/dist/chunk-QTDKQYZI.js +0 -11
- package/dist/chunk-QTDKQYZI.js.map +0 -1
- package/dist/chunk-VAAOW526.js.map +0 -1
- package/dist/chunk-ZTQ3KWXR.js +0 -13
- package/dist/chunk-ZTQ3KWXR.js.map +0 -1
- package/dist/claude-GH6P2DC5.js +0 -4
- package/dist/claude-S47YTIHU.js +0 -2
- package/dist/claude-S47YTIHU.js.map +0 -1
- package/dist/codex-2CH57B7G.js +0 -2
- package/dist/codex-2CH57B7G.js.map +0 -1
- package/dist/config-LJFM55LN.js +0 -75
- package/dist/container-KPH4HVAJ.js +0 -1532
- package/dist/context-EPSDCJTU.js +0 -83
- package/dist/cursor-QFUNKPCQ.js +0 -2
- package/dist/cursor-QFUNKPCQ.js.map +0 -1
- package/dist/doctor-GHRV5I2S.js +0 -67
- package/dist/doctor-service-QEJCE5FK.js.map +0 -1
- package/dist/doctor-service-TPOMFAIG.js +0 -2
- package/dist/goal-I56QP7HS.js +0 -110
- package/dist/init-EQTGQ4G2.js +0 -165
- package/dist/logs-AK255DEJ.js +0 -207
- package/dist/msg-SQWQLJP6.js +0 -95
- package/dist/orchestrator-L6QX2LJ7.js +0 -2
- package/dist/process-manager-HUVNAPQV.js +0 -2
- package/dist/process-manager-TLZOTO4Y.js +0 -2
- package/dist/registry-PQWRVNF2.js +0 -2
- package/dist/registry-UQAHK77P.js +0 -2
- package/dist/run-PSZURVVL.js +0 -95
- package/dist/shell-5ZNXFGXV.js +0 -3
- package/dist/shell-OGTSH4RJ.js.map +0 -1
- package/dist/status-DTF7D3DV.js +0 -56
- package/dist/task-35SDKXFC.js +0 -209
- package/dist/team-AISPLEJB.js +0 -97
- package/dist/template-engine-322SCRR6.js +0 -2
- package/dist/template-engine-3CDRZNMJ.js +0 -3
- package/dist/tui-AR6PVMBQ.js +0 -230
- package/dist/update-DCCWVISK.js +0 -64
- package/dist/update-check-4YKLGBFB.js +0 -2
- package/dist/workspace-manager-AS4TFA7R.js +0 -3
- package/dist/workspace-manager-AS4TFA7R.js.map +0 -1
|
@@ -1,12 +1,57 @@
|
|
|
1
|
-
|
|
2
|
-
import { DEFAULT_PROMPT_TEMPLATE, buildPromptContext } from './chunk-
|
|
3
|
-
import { resolveFailureStatus, isDispatchable, isTerminal, isBlocked, resolveCompletionStatus, calculateRetryDelay } from './chunk-33QNTNR6.js';
|
|
4
|
-
import { AUTONOMOUS_LABEL } from './chunk-PNE6LQRF.js';
|
|
5
|
-
import { LockConflictError, WorkspaceError, TaskAlreadyRunningError, NoAgentsError } from './chunk-3TGCIXJA.js';
|
|
1
|
+
import { LockConflictError, WorkspaceError, TaskAlreadyRunningError, NoAgentsError } from './chunk-IQXRQBUK.js';
|
|
2
|
+
import { AUTONOMOUS_LABEL, DEFAULT_PROMPT_TEMPLATE, buildPromptContext } from './chunk-B4JQM4NU.js';
|
|
6
3
|
import { dirname } from 'path';
|
|
7
4
|
import fs from 'fs/promises';
|
|
8
5
|
import { execFile } from 'child_process';
|
|
9
6
|
|
|
7
|
+
// src/domain/transitions.ts
|
|
8
|
+
var VALID_TRANSITIONS = {
|
|
9
|
+
todo: ["in_progress", "cancelled"],
|
|
10
|
+
in_progress: ["review", "retrying", "failed", "cancelled"],
|
|
11
|
+
retrying: ["in_progress", "failed", "cancelled"],
|
|
12
|
+
review: ["done", "todo", "cancelled"],
|
|
13
|
+
done: [],
|
|
14
|
+
failed: ["todo", "retrying"],
|
|
15
|
+
cancelled: ["todo"]
|
|
16
|
+
};
|
|
17
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["done", "failed", "cancelled"]);
|
|
18
|
+
function canTransition(from, to) {
|
|
19
|
+
return VALID_TRANSITIONS[from].includes(to);
|
|
20
|
+
}
|
|
21
|
+
function isTerminal(status) {
|
|
22
|
+
return TERMINAL_STATUSES.has(status);
|
|
23
|
+
}
|
|
24
|
+
function isDispatchable(status) {
|
|
25
|
+
return status === "todo" || status === "retrying";
|
|
26
|
+
}
|
|
27
|
+
function isBlocked(task, allTasks) {
|
|
28
|
+
if (task.depends_on.length === 0) return false;
|
|
29
|
+
if (allTasks instanceof Map) {
|
|
30
|
+
return task.depends_on.some((depId) => {
|
|
31
|
+
const dep = allTasks.get(depId);
|
|
32
|
+
return !dep || dep.status !== "done";
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return task.depends_on.some((depId) => {
|
|
36
|
+
const dep = allTasks.find((t) => t.id === depId);
|
|
37
|
+
return !dep || dep.status !== "done";
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function resolveFailureStatus(task) {
|
|
41
|
+
if (task.attempts < task.max_attempts) {
|
|
42
|
+
return "retrying";
|
|
43
|
+
}
|
|
44
|
+
return "failed";
|
|
45
|
+
}
|
|
46
|
+
function resolveCompletionStatus(task, success, _autoApprove) {
|
|
47
|
+
{
|
|
48
|
+
return "review";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function calculateRetryDelay(attempt, baseDelayMs, maxDelayMs) {
|
|
52
|
+
const delay = baseDelayMs * Math.pow(2, attempt);
|
|
53
|
+
return Math.min(delay, maxDelayMs);
|
|
54
|
+
}
|
|
10
55
|
function scopesOverlap(a, b) {
|
|
11
56
|
if (!a?.length || !b?.length) return false;
|
|
12
57
|
for (const pa of a) {
|
|
@@ -16,6 +61,54 @@ function scopesOverlap(a, b) {
|
|
|
16
61
|
}
|
|
17
62
|
return false;
|
|
18
63
|
}
|
|
64
|
+
function computePatternInfo(pattern) {
|
|
65
|
+
const base = pattern.split("*")[0];
|
|
66
|
+
const isFile = !base.endsWith("/");
|
|
67
|
+
const dir = isFile ? dirname(base) : "";
|
|
68
|
+
return { raw: pattern, base, isFile, dir };
|
|
69
|
+
}
|
|
70
|
+
var ScopeIndex = class {
|
|
71
|
+
entries;
|
|
72
|
+
constructor(scopes) {
|
|
73
|
+
this.entries = [];
|
|
74
|
+
for (const scope of scopes) {
|
|
75
|
+
if (scope?.length) {
|
|
76
|
+
for (const p of scope) {
|
|
77
|
+
this.entries.push(computePatternInfo(p));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** Returns true if the given scope overlaps with any pattern in the index. */
|
|
83
|
+
overlapsAny(scope) {
|
|
84
|
+
if (!scope?.length || this.entries.length === 0) return false;
|
|
85
|
+
for (const raw of scope) {
|
|
86
|
+
const info = computePatternInfo(raw);
|
|
87
|
+
for (const entry of this.entries) {
|
|
88
|
+
if (patternsOverlapInfo(info, entry)) return true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
/** Add patterns to the index (e.g. from an approved candidate). */
|
|
94
|
+
add(scope) {
|
|
95
|
+
if (!scope?.length) return;
|
|
96
|
+
for (const p of scope) {
|
|
97
|
+
this.entries.push(computePatternInfo(p));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
get size() {
|
|
101
|
+
return this.entries.length;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
function patternsOverlapInfo(a, b) {
|
|
105
|
+
if (a.raw === b.raw) return true;
|
|
106
|
+
if (a.base.startsWith(b.base) || b.base.startsWith(a.base)) return true;
|
|
107
|
+
if (a.isFile && b.isFile) {
|
|
108
|
+
return a.dir === b.dir && a.dir !== ".";
|
|
109
|
+
}
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
19
112
|
function patternsOverlap(a, b) {
|
|
20
113
|
if (a === b) return true;
|
|
21
114
|
const aBase = a.split("*")[0];
|
|
@@ -28,29 +121,37 @@ function patternsOverlap(a, b) {
|
|
|
28
121
|
}
|
|
29
122
|
return false;
|
|
30
123
|
}
|
|
124
|
+
var acquireMutex = Promise.resolve();
|
|
31
125
|
async function acquireLock(lockPath) {
|
|
32
|
-
|
|
126
|
+
let release;
|
|
127
|
+
const gate = new Promise((r) => {
|
|
128
|
+
release = r;
|
|
129
|
+
});
|
|
130
|
+
const prev = acquireMutex;
|
|
131
|
+
acquireMutex = gate;
|
|
132
|
+
await prev;
|
|
133
|
+
try {
|
|
134
|
+
return await doAcquire(lockPath);
|
|
135
|
+
} finally {
|
|
136
|
+
release();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async function doAcquire(lockPath) {
|
|
33
140
|
const existing = await readLockPid(lockPath);
|
|
34
141
|
if (existing !== null) {
|
|
35
142
|
if (isProcessAlive(existing)) {
|
|
36
143
|
return { acquired: false, pid: existing };
|
|
37
144
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
} catch {
|
|
41
|
-
}
|
|
145
|
+
await fs.unlink(lockPath).catch(() => {
|
|
146
|
+
});
|
|
42
147
|
}
|
|
43
148
|
try {
|
|
44
149
|
const fd = await fs.open(lockPath, "wx");
|
|
45
150
|
await fd.writeFile(String(process.pid), "utf-8");
|
|
46
151
|
await fd.close();
|
|
47
|
-
await fs.unlink(bakPath).catch(() => {
|
|
48
|
-
});
|
|
49
152
|
return { acquired: true, pid: process.pid };
|
|
50
153
|
} catch (err) {
|
|
51
154
|
if (err.code === "EEXIST") {
|
|
52
|
-
await fs.rename(bakPath, lockPath).catch(() => {
|
|
53
|
-
});
|
|
54
155
|
const pid = await readLockPid(lockPath);
|
|
55
156
|
return { acquired: false, pid: pid ?? void 0 };
|
|
56
157
|
}
|
|
@@ -87,7 +188,7 @@ var CachedTaskStore = class {
|
|
|
87
188
|
}
|
|
88
189
|
cache = /* @__PURE__ */ new Map();
|
|
89
190
|
async list(filter) {
|
|
90
|
-
const key = filter
|
|
191
|
+
const key = filter ? `${filter.status ?? ""}:${filter.goalId ?? ""}` : "__all__";
|
|
91
192
|
if (this.cache.has(key)) {
|
|
92
193
|
return this.cache.get(key);
|
|
93
194
|
}
|
|
@@ -115,6 +216,7 @@ var CachedAgentStore = class {
|
|
|
115
216
|
this.inner = inner;
|
|
116
217
|
}
|
|
117
218
|
listCache = null;
|
|
219
|
+
nameCache = /* @__PURE__ */ new Map();
|
|
118
220
|
async list() {
|
|
119
221
|
if (this.listCache) {
|
|
120
222
|
return this.listCache;
|
|
@@ -127,18 +229,26 @@ var CachedAgentStore = class {
|
|
|
127
229
|
return this.inner.get(id);
|
|
128
230
|
}
|
|
129
231
|
async getByName(name) {
|
|
130
|
-
|
|
232
|
+
if (this.nameCache.has(name)) {
|
|
233
|
+
return this.nameCache.get(name) ?? null;
|
|
234
|
+
}
|
|
235
|
+
const result = await this.inner.getByName(name);
|
|
236
|
+
this.nameCache.set(name, result);
|
|
237
|
+
return result;
|
|
131
238
|
}
|
|
132
239
|
async save(agent) {
|
|
133
240
|
await this.inner.save(agent);
|
|
134
241
|
this.listCache = null;
|
|
242
|
+
this.nameCache.clear();
|
|
135
243
|
}
|
|
136
244
|
async delete(id) {
|
|
137
245
|
await this.inner.delete(id);
|
|
138
246
|
this.listCache = null;
|
|
247
|
+
this.nameCache.clear();
|
|
139
248
|
}
|
|
140
249
|
invalidate() {
|
|
141
250
|
this.listCache = null;
|
|
251
|
+
this.nameCache.clear();
|
|
142
252
|
}
|
|
143
253
|
};
|
|
144
254
|
var CachedGoalStore = class {
|
|
@@ -446,7 +556,7 @@ var Orchestrator = class {
|
|
|
446
556
|
await this.deps.agentService.setStatus(entry.agent_id, "idle");
|
|
447
557
|
}
|
|
448
558
|
this.state.running = {};
|
|
449
|
-
this.state.claimed =
|
|
559
|
+
this.state.claimed = /* @__PURE__ */ new Set();
|
|
450
560
|
this.state.pid = void 0;
|
|
451
561
|
this.state.started_at = void 0;
|
|
452
562
|
await this.saveState();
|
|
@@ -594,8 +704,13 @@ var Orchestrator = class {
|
|
|
594
704
|
async reconcile() {
|
|
595
705
|
const state = this.state;
|
|
596
706
|
const now = Date.now();
|
|
597
|
-
|
|
598
|
-
|
|
707
|
+
const runningEntries = Object.entries(state.running);
|
|
708
|
+
const runningTaskData = await Promise.all(
|
|
709
|
+
runningEntries.map(([taskId]) => this.deps.taskStore.get(taskId))
|
|
710
|
+
);
|
|
711
|
+
for (let i = 0; i < runningEntries.length; i++) {
|
|
712
|
+
const [taskId, entry] = runningEntries[i];
|
|
713
|
+
const taskData = runningTaskData[i];
|
|
599
714
|
if (!taskData || isTerminal(taskData.status)) {
|
|
600
715
|
this.abortControllers.delete(taskId);
|
|
601
716
|
delete state.running[taskId];
|
|
@@ -664,12 +779,16 @@ var Orchestrator = class {
|
|
|
664
779
|
});
|
|
665
780
|
}
|
|
666
781
|
}
|
|
667
|
-
|
|
668
|
-
|
|
782
|
+
const dueRetries = [];
|
|
783
|
+
state.retry_queue = state.retry_queue.filter((retry) => {
|
|
669
784
|
if (now >= new Date(retry.due_at).getTime()) {
|
|
670
|
-
|
|
671
|
-
|
|
785
|
+
dueRetries.push(retry.task_id);
|
|
786
|
+
return false;
|
|
672
787
|
}
|
|
788
|
+
return true;
|
|
789
|
+
});
|
|
790
|
+
for (const taskId of dueRetries) {
|
|
791
|
+
await this.dispatchTask(taskId);
|
|
673
792
|
}
|
|
674
793
|
await this.saveState();
|
|
675
794
|
}
|
|
@@ -714,7 +833,8 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
|
|
|
714
833
|
description,
|
|
715
834
|
assignee: agent.id,
|
|
716
835
|
labels: [AUTONOMOUS_LABEL],
|
|
717
|
-
priority: 3
|
|
836
|
+
priority: 3,
|
|
837
|
+
goalId: goal?.id
|
|
718
838
|
});
|
|
719
839
|
anyCreated = true;
|
|
720
840
|
} catch (err) {
|
|
@@ -738,8 +858,9 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
|
|
|
738
858
|
const availableSlots = maxConcurrent - currentRunning;
|
|
739
859
|
if (availableSlots <= 0) return;
|
|
740
860
|
const allTasks = await this.cachedTaskStore.list();
|
|
861
|
+
const taskMap = new Map(allTasks.map((t) => [t.id, t]));
|
|
741
862
|
const candidates = allTasks.filter(
|
|
742
|
-
(t) => isDispatchable(t.status) && !isBlocked(t,
|
|
863
|
+
(t) => isDispatchable(t.status) && !isBlocked(t, taskMap) && !state.running[t.id] && !state.claimed.has(t.id)
|
|
743
864
|
).sort((a, b) => {
|
|
744
865
|
const bTime = b.updated_at ?? "";
|
|
745
866
|
const aTime = a.updated_at ?? "";
|
|
@@ -747,25 +868,21 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
|
|
|
747
868
|
}).slice(0, availableSlots);
|
|
748
869
|
const blockedIds = /* @__PURE__ */ new Set();
|
|
749
870
|
const inProgressScoped = allTasks.filter((t) => t.status === "in_progress" && t.scope?.length);
|
|
750
|
-
|
|
751
|
-
|
|
871
|
+
const scopeIndex = new ScopeIndex(inProgressScoped.map((t) => t.scope));
|
|
872
|
+
for (const candidate of candidates) {
|
|
752
873
|
if (!candidate.scope?.length) continue;
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
overlapping = true;
|
|
765
|
-
break;
|
|
766
|
-
}
|
|
874
|
+
if (scopeIndex.overlapsAny(candidate.scope)) {
|
|
875
|
+
const overlapper = inProgressScoped.find((t) => scopesOverlap(candidate.scope, t.scope));
|
|
876
|
+
this.deps.eventBus.emit({
|
|
877
|
+
type: "task:scope_overlap",
|
|
878
|
+
taskId: candidate.id,
|
|
879
|
+
overlappingTaskId: overlapper?.id ?? candidate.id,
|
|
880
|
+
patterns: candidate.scope
|
|
881
|
+
});
|
|
882
|
+
blockedIds.add(candidate.id);
|
|
883
|
+
} else {
|
|
884
|
+
scopeIndex.add(candidate.scope);
|
|
767
885
|
}
|
|
768
|
-
if (overlapping) blockedIds.add(candidate.id);
|
|
769
886
|
}
|
|
770
887
|
for (const task of candidates) {
|
|
771
888
|
if (blockedIds.has(task.id)) continue;
|
|
@@ -802,13 +919,13 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
|
|
|
802
919
|
throw new TaskAlreadyRunningError(taskId, entry.run_id, entry.agent_id);
|
|
803
920
|
}
|
|
804
921
|
const task = await this.deps.taskService.get(taskId);
|
|
805
|
-
state.claimed.
|
|
922
|
+
state.claimed.add(taskId);
|
|
806
923
|
await this.saveState();
|
|
807
924
|
try {
|
|
925
|
+
const allAgents = await this.cachedAgentStore.list();
|
|
808
926
|
const agent = await this.deps.agentService.findBestAgent(task);
|
|
809
927
|
if (!agent) {
|
|
810
|
-
|
|
811
|
-
if (allAgents2.length === 0) {
|
|
928
|
+
if (allAgents.length === 0) {
|
|
812
929
|
throw new NoAgentsError();
|
|
813
930
|
}
|
|
814
931
|
this.unclaim(taskId);
|
|
@@ -821,7 +938,6 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
|
|
|
821
938
|
this.deps.config
|
|
822
939
|
);
|
|
823
940
|
const template = this.deps.config.prompt?.template ?? DEFAULT_PROMPT_TEMPLATE;
|
|
824
|
-
const allAgents = await this.cachedAgentStore.list();
|
|
825
941
|
const attempt = task.attempts + 1;
|
|
826
942
|
let retryContext;
|
|
827
943
|
if (attempt > 1) {
|
|
@@ -833,15 +949,35 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
|
|
|
833
949
|
};
|
|
834
950
|
}
|
|
835
951
|
}
|
|
836
|
-
const
|
|
837
|
-
const pendingMessages =
|
|
952
|
+
const goalId = task.goalId;
|
|
953
|
+
const [sharedContext, pendingMessages, goalRaw] = await Promise.all([
|
|
954
|
+
this.deps.contextStore?.getAll(),
|
|
955
|
+
this.deps.messageService ? this.deps.messageService.drainMailbox(agent.id, task.id) : [],
|
|
956
|
+
goalId && this.cachedGoalStore ? this.cachedGoalStore.get(goalId).catch(() => null) : null
|
|
957
|
+
]);
|
|
958
|
+
let goalContext;
|
|
959
|
+
if (goalRaw) {
|
|
960
|
+
const allTasks = await this.cachedTaskStore.list();
|
|
961
|
+
const goalTasks = allTasks.filter((t) => t.goalId === goalId);
|
|
962
|
+
const progressEntry = await this.deps.contextStore?.get(`${goalId}-progress`);
|
|
963
|
+
const MAX_GOAL_TASK_NAMES = 30;
|
|
964
|
+
const taskNames = goalTasks.map((t) => `[${t.status}] ${t.title}`);
|
|
965
|
+
goalContext = {
|
|
966
|
+
id: goalRaw.id,
|
|
967
|
+
title: goalRaw.title,
|
|
968
|
+
description: goalRaw.description,
|
|
969
|
+
status: goalRaw.status,
|
|
970
|
+
task_names: taskNames.length > MAX_GOAL_TASK_NAMES ? [...taskNames.slice(0, MAX_GOAL_TASK_NAMES), `... and ${taskNames.length - MAX_GOAL_TASK_NAMES} more`] : taskNames,
|
|
971
|
+
progress: progressEntry?.value
|
|
972
|
+
};
|
|
973
|
+
}
|
|
838
974
|
const context = buildPromptContext(
|
|
839
975
|
task,
|
|
840
976
|
agent,
|
|
841
977
|
attempt,
|
|
842
978
|
workspacePath,
|
|
843
979
|
this.deps.config,
|
|
844
|
-
{ allAgents, retryContext, sharedContext, feedback: task.feedback, messages: pendingMessages.length ? pendingMessages : void 0 }
|
|
980
|
+
{ allAgents, retryContext, sharedContext, feedback: task.feedback, messages: pendingMessages.length ? pendingMessages : void 0, goal: goalContext }
|
|
845
981
|
);
|
|
846
982
|
const prompt = await this.deps.templateEngine.render(template, context);
|
|
847
983
|
const run = await this.deps.runService.create({
|
|
@@ -1018,7 +1154,7 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
|
|
|
1018
1154
|
const agent = await this.deps.agentStore.get(agentId);
|
|
1019
1155
|
const isAutonomousTask = task.labels?.includes(AUTONOMOUS_LABEL);
|
|
1020
1156
|
const autoApprove = isAutonomousTask || agent?.config.approval_policy === "auto";
|
|
1021
|
-
const newStatus = resolveCompletionStatus(
|
|
1157
|
+
const newStatus = resolveCompletionStatus();
|
|
1022
1158
|
await this.deps.runService.finish(runId, "succeeded", tokens);
|
|
1023
1159
|
const runningEntry = state.running[taskId];
|
|
1024
1160
|
const successRuntimeMs = runningEntry ? Date.now() - new Date(runningEntry.started_at).getTime() : 0;
|
|
@@ -1251,8 +1387,7 @@ ${task.proof?.agent_summary ?? ""}`.slice(0, 2e3),
|
|
|
1251
1387
|
await this.saveState();
|
|
1252
1388
|
}
|
|
1253
1389
|
unclaim(taskId) {
|
|
1254
|
-
|
|
1255
|
-
if (idx !== -1) this.state.claimed.splice(idx, 1);
|
|
1390
|
+
this.state.claimed.delete(taskId);
|
|
1256
1391
|
}
|
|
1257
1392
|
/**
|
|
1258
1393
|
* Throw if this instance doesn't own the lock (read-only session).
|
|
@@ -1317,4 +1452,6 @@ function serializeEventData(data, maxLen) {
|
|
|
1317
1452
|
return str.length > maxLen ? str.slice(0, maxLen) + "\u2026" : str;
|
|
1318
1453
|
}
|
|
1319
1454
|
|
|
1320
|
-
export { Orchestrator };
|
|
1455
|
+
export { Orchestrator, canTransition, isBlocked, isDispatchable, isTerminal, resolveFailureStatus };
|
|
1456
|
+
//# sourceMappingURL=chunk-2UC4SVJB.js.map
|
|
1457
|
+
//# sourceMappingURL=chunk-2UC4SVJB.js.map
|