@sema-agent/server 7.41.0 → 7.42.0-rc.1
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/USAGE.md +6 -0
- package/dist/leader/merge.js +15 -5
- package/dist/leader/repair-oracle.js +4 -2
- package/dist/plugins/remote-env-adb.js +12 -4
- package/dist/plugins/remote-env-host.js +10 -1
- package/dist/plugins/remote-env-local-docker.js +9 -1
- package/dist/plugins/remote-env-ssh.js +12 -4
- package/package.json +2 -2
package/USAGE.md
CHANGED
|
@@ -243,6 +243,12 @@ MODEL_CASCADE_LADDER=deepseek-flash,deepseek-pro # 目录里的模型名,cheap
|
|
|
243
243
|
行与编号高水位一并抹掉(同 anchors/附件/快照的级联)——会话 id 可被重新认领,残留就等于把上一位
|
|
244
244
|
主人的任务标题与编号进度交给下一个化身。
|
|
245
245
|
- 多实例边界:同一数据根同时只允许一个实例(BootLock 独占,第二个进程拒启;死主自愈含 SIGKILL)。
|
|
246
|
+
core 5.54.0 起拒启错误带**可分派 code**(`FileStoreLockError`,message 点名占用方 pid),运维按码
|
|
247
|
+
三动作:`store.dir_in_use`=另一个活进程持有该目录 → 停掉它(或换数据根/迁 SQL 后端);
|
|
248
|
+
`store.dir_claiming`=另一进程正在接管崩溃者留下的锁 → **瞬态,稍候重试**(接管方要么完成要么
|
|
249
|
+
自己也被收割);`store.lock_unreadable`=锁文件坏形(无 owner 可解析/嵌套接管残留)→ 人工处置,
|
|
250
|
+
message 会点名要删的文件,**不要盲删数据根下其它东西**。server 刻意不 catch 这族错(fail-fast:
|
|
251
|
+
两进程共用 file 数据目录是禁止形,静默容忍比拒启更坏)。
|
|
246
252
|
`DB_BACKEND=memory` 并非全无盘:workflow 相关账本仍挂数据根下——多个 memory 形引擎**不要共用**
|
|
247
253
|
数据根/HOME(1.309 起并发 boot 不再拒启,但账本内容级共享仍不受支持)。
|
|
248
254
|
|
package/dist/leader/merge.js
CHANGED
|
@@ -16,6 +16,12 @@ export async function mergeBranches(reports, baseSha, deps) {
|
|
|
16
16
|
let destroy;
|
|
17
17
|
// Track the current stage so a THROWN error is attributed to the right phase (not always "provision").
|
|
18
18
|
let phase = "diff-out";
|
|
19
|
+
// [4953]② declared OUTSIDE the try (same pattern as `phase`) so the catch-all can still disclose them:
|
|
20
|
+
// spend/repair/measure that already HAPPENED must ride the thrown-failure return too — the leader folds
|
|
21
|
+
// conflictResolverCostUsd into the next round's budget, and a throw doesn't un-spend it.
|
|
22
|
+
let conflictResolverCostUsd = 0; // 🔴 capture the bounded conflict-resolver agent's spend (was dropped → S1 TEAM-cost undercount)
|
|
23
|
+
let repairMeta;
|
|
24
|
+
let measure;
|
|
19
25
|
try {
|
|
20
26
|
// 1. pull each worker's diff OUT of its container (M2). A failed diff quarantines that worker, aborts merge.
|
|
21
27
|
const patches = [];
|
|
@@ -39,7 +45,6 @@ export async function mergeBranches(reports, baseSha, deps) {
|
|
|
39
45
|
// 3. apply each patch --3way (council#3: keeps conflict context; capture .rej on failure, quarantine).
|
|
40
46
|
phase = "apply";
|
|
41
47
|
const conflictsResolved = [];
|
|
42
|
-
let conflictResolverCostUsd = 0; // 🔴 capture the bounded conflict-resolver agent's spend (was dropped → S1 TEAM-cost undercount)
|
|
43
48
|
for (const p of patches) {
|
|
44
49
|
const patchPath = `/tmp/${p.workerId}.patch`;
|
|
45
50
|
await env.writeFile(patchPath, p.patch);
|
|
@@ -71,7 +76,6 @@ export async function mergeBranches(reports, baseSha, deps) {
|
|
|
71
76
|
// Bounded integration-repair (search 2026-06-14): a clean-merge-but-failing-build used to be terminal.
|
|
72
77
|
// If the sandbox supplied a `repair`, run the repair agent IN this merged tree (it edits the working tree;
|
|
73
78
|
// the squash commit below captures worker patches + repair together), then re-run testCmd. Up to maxRounds.
|
|
74
|
-
let repairMeta;
|
|
75
79
|
if (test.exitCode !== 0 && integ.repair && integ.repair.maxRounds > 0) {
|
|
76
80
|
let cost = 0;
|
|
77
81
|
let round = 0;
|
|
@@ -97,7 +101,6 @@ export async function mergeBranches(reports, baseSha, deps) {
|
|
|
97
101
|
// 4b. truecorrect MEASURE (design/59) — run the thorough hidden oracle IN this sandbox (E2B), where the merged
|
|
98
102
|
// code already lives, NOT on the CPU-contended control plane (fixes the frontier-multi oracle spawn-timeout
|
|
99
103
|
// that thinned n). Pure observation: never gates `ok`, just reports into MergeResult.measure.
|
|
100
|
-
let measure;
|
|
101
104
|
if (deps.measureCmd) {
|
|
102
105
|
const mr = await env.exec(deps.measureCmd, { cwd: repo });
|
|
103
106
|
measure = mr.exitCode === 0 ? { pass: true } : { pass: false, reason: (mr.stdout + " " + mr.stderr).slice(-200) };
|
|
@@ -163,8 +166,15 @@ export async function mergeBranches(reports, baseSha, deps) {
|
|
|
163
166
|
}
|
|
164
167
|
catch (e) {
|
|
165
168
|
// Honour the "never throws" contract: a thrown pullWorkerDiff/provision/exec becomes a typed failure,
|
|
166
|
-
// attributed to the stage it threw in (not a blanket "provision").
|
|
167
|
-
|
|
169
|
+
// attributed to the stage it threw in (not a blanket "provision"). [4953]②: spend/repair/measure that
|
|
170
|
+
// already happened before the throw ride this return too (same tail as every explicit failure return).
|
|
171
|
+
return {
|
|
172
|
+
ok: false, phase, reason: `merge aborted in ${phase}: ${e instanceof Error ? e.message : String(e)}`,
|
|
173
|
+
quarantine: mergeable.map((r) => r.workerId),
|
|
174
|
+
...(measure ? { measure } : {}),
|
|
175
|
+
...(repairMeta ? { repair: repairMeta } : {}),
|
|
176
|
+
...(conflictResolverCostUsd > 0 ? { conflictResolverCostUsd } : {}),
|
|
177
|
+
};
|
|
168
178
|
}
|
|
169
179
|
finally {
|
|
170
180
|
// council#15: destroy the sandbox on EVERY exit path. Guarded because we may bail (diff-out) or throw
|
|
@@ -133,8 +133,10 @@ export function mkRepairOracle(cfg) {
|
|
|
133
133
|
// fork2.2 — bind the EXACT graded bytes (the diff that produced this verdict) so the caller surfaces the
|
|
134
134
|
// candidate the human reviews == the bytes that were graded (not a later re-pull that may differ).
|
|
135
135
|
cfg.onGraded?.({ diff: diff.patch, hash: diffHash, passed });
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
// [4953]① `retries` = how many re-isolations actually RAN (the cross-repo contract's wording) — the
|
|
137
|
+
// first-clear-fail short-circuit means this can be < K, and reporting the configured cap was a lie.
|
|
138
|
+
cfg.log?.("repair_oracle_verdict", { tier, passed, flaky, retries: verdicts.length });
|
|
139
|
+
return { tier, passed, flaky, retries: verdicts.length, ...(passed && !flaky ? {} : { trace: lastTrace || "oracle rejected the candidate" }) };
|
|
138
140
|
};
|
|
139
141
|
}
|
|
140
142
|
//# sourceMappingURL=repair-oracle.js.map
|
|
@@ -260,10 +260,18 @@ export class RemoteAdbExecutionEnv {
|
|
|
260
260
|
if (finished)
|
|
261
261
|
break;
|
|
262
262
|
const waitMs = idleMs ? Math.max(1, idleMs - (Date.now() - lastChunk)) : 30_000;
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
263
|
+
// [4947] A-002.11 sibling: clear the losing timer — wake() firing first used to leave it armed.
|
|
264
|
+
let waitTimer;
|
|
265
|
+
try {
|
|
266
|
+
await new Promise((r) => {
|
|
267
|
+
wake = r;
|
|
268
|
+
waitTimer = setTimeout(r, waitMs);
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
finally {
|
|
272
|
+
if (waitTimer !== undefined)
|
|
273
|
+
clearTimeout(waitTimer);
|
|
274
|
+
}
|
|
267
275
|
if (idleMs && !finished && Date.now() - lastChunk >= idleMs) {
|
|
268
276
|
throw new RemoteExecutionError("timeout", `execStream idle > ${idleMs}ms (device hang / disconnected)`);
|
|
269
277
|
}
|
|
@@ -1102,7 +1102,16 @@ export class RemoteHostExecutionEnv {
|
|
|
1102
1102
|
break;
|
|
1103
1103
|
// idle/liveness bound: no chunk within readTimeoutMs → typed timeout (a hung command).
|
|
1104
1104
|
const waitMs = idleMs != null ? Math.max(1, idleMs - (Date.now() - lastChunk)) : 30_000;
|
|
1105
|
-
|
|
1105
|
+
// [4947] A-002.11 sibling: the losing side of this race must be cleared — wake() firing first
|
|
1106
|
+
// used to leave the timer armed for up to waitMs (30s), one per drain round on long streams.
|
|
1107
|
+
let waitTimer;
|
|
1108
|
+
try {
|
|
1109
|
+
await new Promise((r) => { wake = r; waitTimer = setTimeout(r, waitMs); });
|
|
1110
|
+
}
|
|
1111
|
+
finally {
|
|
1112
|
+
if (waitTimer !== undefined)
|
|
1113
|
+
clearTimeout(waitTimer);
|
|
1114
|
+
}
|
|
1106
1115
|
if (idleMs != null && !finished && Date.now() - lastChunk >= idleMs) {
|
|
1107
1116
|
finished = true;
|
|
1108
1117
|
kill();
|
|
@@ -350,7 +350,15 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
350
350
|
if (finished)
|
|
351
351
|
break;
|
|
352
352
|
const waitMs = idleMs != null ? Math.max(1, idleMs - (Date.now() - lastChunk)) : 30_000;
|
|
353
|
-
|
|
353
|
+
// [4947] A-002.11 sibling: clear the losing timer — wake() firing first used to leave it armed.
|
|
354
|
+
let waitTimer;
|
|
355
|
+
try {
|
|
356
|
+
await new Promise((r) => { wake = r; waitTimer = setTimeout(r, waitMs); });
|
|
357
|
+
}
|
|
358
|
+
finally {
|
|
359
|
+
if (waitTimer !== undefined)
|
|
360
|
+
clearTimeout(waitTimer);
|
|
361
|
+
}
|
|
354
362
|
if (idleMs != null && !finished && Date.now() - lastChunk >= idleMs) {
|
|
355
363
|
finished = true;
|
|
356
364
|
try {
|
|
@@ -480,10 +480,18 @@ export class RemoteSshExecutionEnv {
|
|
|
480
480
|
break;
|
|
481
481
|
// idle/liveness bound: no chunk within readTimeoutMs → typed timeout (unreachable host)
|
|
482
482
|
const waitMs = idleMs ? Math.max(1, idleMs - (Date.now() - lastChunk)) : 30_000;
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
483
|
+
// [4947] A-002.11 sibling: clear the losing timer — wake() firing first used to leave it armed.
|
|
484
|
+
let waitTimer;
|
|
485
|
+
try {
|
|
486
|
+
await new Promise((r) => {
|
|
487
|
+
wake = r;
|
|
488
|
+
waitTimer = setTimeout(r, waitMs);
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
finally {
|
|
492
|
+
if (waitTimer !== undefined)
|
|
493
|
+
clearTimeout(waitTimer);
|
|
494
|
+
}
|
|
487
495
|
if (idleMs && !finished && Date.now() - lastChunk >= idleMs)
|
|
488
496
|
throw new RemoteExecutionError("timeout", `execStream idle > ${idleMs}ms (provider hang / unreachable host)`);
|
|
489
497
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.42.0-rc.1",
|
|
4
4
|
"description": "Sema Server — the server/API implementation layer for Sema, wiring core, registry, model providers, and cloud agent execution. Built on @sema-agent/core.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"build:binary:run-local:darwin-arm64": "bun build --compile --target=bun-darwin-arm64 src/run-local.ts --outfile dist/run-local-darwin-arm64"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@sema-agent/core": "^5.
|
|
57
|
+
"@sema-agent/core": "^5.54.0",
|
|
58
58
|
"@sema-agent/registry-core": "^0.19.0",
|
|
59
59
|
"e2b": "^2.28.0",
|
|
60
60
|
"libsodium-wrappers": "^0.8.4",
|