@sema-agent/server 7.121.0 → 7.122.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/MIGRATION.md +98 -0
- package/README.md +1 -1
- package/README.zh-CN.md +3 -1
- package/USAGE.md +35 -14
- package/dist/approval-reconciler.d.ts +8 -0
- package/dist/approval-reconciler.js +72 -52
- package/dist/auto-mode-face.d.ts +9 -2
- package/dist/auto-mode-face.js +5 -3
- package/dist/bench/s1/live-deps.js +1 -0
- package/dist/boot/leader.js +1 -0
- package/dist/boot/reapers.d.ts +3 -0
- package/dist/boot/reapers.js +2 -1
- package/dist/boot/resolve-spec.js +1 -4
- package/dist/boot/shutdown.js +6 -1
- package/dist/boot/stage-08-reapers.js +2 -2
- package/dist/capabilities/memory-notice.d.ts +1 -1
- package/dist/config-catalog.js +3 -3
- package/dist/config-center/center-request.d.ts +6 -9
- package/dist/config-center/center-request.js +11 -27
- package/dist/config-types.d.ts +11 -8
- package/dist/config-types.js +1 -1
- package/dist/config.d.ts +2 -2
- package/dist/config.js +23 -35
- package/dist/fleet/drain-entry.d.ts +28 -3
- package/dist/fleet/drain-entry.js +3 -0
- package/dist/fleet/serving-lease.js +13 -15
- package/dist/governance-overrides.d.ts +7 -2
- package/dist/http/admission.js +7 -5
- package/dist/http/approval-sweeps.js +2 -2
- package/dist/http/checkpoint-ctx.d.ts +60 -11
- package/dist/http/checkpoint-ctx.js +23 -9
- package/dist/http/dispatch.js +17 -5
- package/dist/http/resume-legs.js +8 -8
- package/dist/http/route-ctx.d.ts +19 -3
- package/dist/http/route-table.d.ts +3 -0
- package/dist/http/route-table.js +4 -0
- package/dist/http/routes/admin-drain.d.ts +5 -2
- package/dist/http/routes/admin-drain.js +14 -2
- package/dist/http/routes/approvals-assistant.d.ts +1 -0
- package/dist/http/routes/approvals-assistant.js +6 -6
- package/dist/http/routes/capabilities.js +5 -4
- package/dist/http/routes/fleet.d.ts +1 -0
- package/dist/http/routes/fleet.js +1 -1
- package/dist/http/routes/images.d.ts +1 -0
- package/dist/http/routes/images.js +1 -1
- package/dist/http/routes/leader.js +6 -0
- package/dist/http/routes/runs.d.ts +2 -0
- package/dist/http/routes/runs.js +5 -4
- package/dist/http/routes/sessions.d.ts +1 -0
- package/dist/http/routes/sessions.js +1 -1
- package/dist/http/routes/trace-usage.d.ts +1 -0
- package/dist/http/routes/trace-usage.js +1 -1
- package/dist/http/routes/workflows.d.ts +1 -0
- package/dist/http/routes/workflows.js +1 -1
- package/dist/http/send.d.ts +13 -0
- package/dist/http/send.js +9 -0
- package/dist/http/server.d.ts +3 -0
- package/dist/http/stored-body-replay.d.ts +27 -0
- package/dist/http/stored-body-replay.js +23 -0
- package/dist/leader/leader.d.ts +22 -1
- package/dist/leader/leader.js +4 -1
- package/dist/leader/repair-wire.d.ts +1 -1
- package/dist/leader/repair-wire.js +2 -2
- package/dist/leader/run-entry.d.ts +27 -0
- package/dist/leader/run-entry.js +29 -0
- package/dist/leader/wire.d.ts +10 -0
- package/dist/leader/wire.js +15 -10
- package/dist/model-route-url.d.ts +13 -20
- package/dist/model-route-url.js +28 -24
- package/dist/observability/fail-open.d.ts +23 -6
- package/dist/observability/fail-open.js +8 -4
- package/dist/plugins/approval-ask-store-file.d.ts +1 -0
- package/dist/plugins/approval-ask-store-file.js +3 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +1 -0
- package/dist/plugins/approval-ask-store-memory.js +6 -0
- package/dist/plugins/approval-ask-store-sql.d.ts +12 -0
- package/dist/plugins/approval-ask-store-sql.js +4 -0
- package/dist/plugins/one-time-migrations.js +13 -0
- package/dist/plugins/park-commit-watch.d.ts +19 -5
- package/dist/plugins/park-commit-watch.js +24 -17
- package/dist/router/route-orchestration.d.ts +4 -2
- package/dist/router/route-orchestration.js +2 -1
- package/dist/run-local.js +3 -1
- package/dist/runtime-governance.d.ts +44 -32
- package/dist/runtime-governance.js +23 -9
- package/dist/sighup-idle.d.ts +7 -1
- package/dist/sighup-idle.js +4 -4
- package/dist/task-settings.d.ts +37 -14
- package/dist/task-settings.js +20 -20
- package/dist/tool-approval.d.ts +6 -0
- package/dist/tool-approval.js +13 -1
- package/dist/trace/redact.d.ts +3 -3
- package/dist/unattended-permission-mode.d.ts +17 -13
- package/dist/unattended-permission-mode.js +3 -1
- package/dist/url-shape.d.ts +31 -0
- package/dist/url-shape.js +41 -0
- package/package.json +2 -2
- package/scripts/drain-check-local.mjs +1 -1
|
@@ -643,7 +643,7 @@ export const IMAGES_ROUTES = [
|
|
|
643
643
|
{ id: "image-bake-claim-next", path: "/v1/images/bakes/claim", methods: ["POST"] },
|
|
644
644
|
{ id: "image-select", path: "/v1/images/select", methods: ["POST"] },
|
|
645
645
|
{ id: "image-register", path: "/v1/images/register", methods: ["POST"] },
|
|
646
|
-
{ id: "image-bake-events", pattern: /^\/v1\/images\/bakes\/(?<bakeId>[^/]+)\/events$/, label: "/v1/images/bakes/:id/events", methods: ["GET"] },
|
|
646
|
+
{ id: "image-bake-events", pattern: /^\/v1\/images\/bakes\/(?<bakeId>[^/]+)\/events$/, label: "/v1/images/bakes/:id/events", methods: ["GET"], subscription: true },
|
|
647
647
|
{ id: "image-bake-cancel", pattern: /^\/v1\/images\/bakes\/(?<bakeId>[^/]+)\/cancel$/, label: "/v1/images/bakes/:id/cancel", methods: ["POST"] },
|
|
648
648
|
{ id: "image-bake-claim", pattern: /^\/v1\/images\/bakes\/(?<bakeId>[^/]+)\/claim$/, label: "/v1/images/bakes/:id/claim", methods: ["POST"] },
|
|
649
649
|
{ id: "image-bake-ingest", pattern: /^\/v1\/images\/bakes\/(?<bakeId>[^/]+)\/ingest$/, label: "/v1/images/bakes/:id/ingest", methods: ["POST"] },
|
|
@@ -2,6 +2,7 @@ import { sendJson, sendError } from "../send.js";
|
|
|
2
2
|
import { gatedPrincipal, headerStr, sendPrincipalRefusal } from "../principal-gate.js";
|
|
3
3
|
import { assertNever } from "../route-ctx.js";
|
|
4
4
|
import * as facts from "../../capability-facts.js";
|
|
5
|
+
import { leaderEntryRefusal, leaderRunEntry } from "../../leader/run-entry.js";
|
|
5
6
|
export const LEADER_SUBMIT_PATH = "/v1/leader";
|
|
6
7
|
export async function handleLeader(req, res, match, ctx) {
|
|
7
8
|
switch (match.decl.id) {
|
|
@@ -35,6 +36,11 @@ export async function handleLeader(req, res, match, ctx) {
|
|
|
35
36
|
sendError(res, 400, "request.invalid_json", "invalid JSON body");
|
|
36
37
|
return;
|
|
37
38
|
}
|
|
39
|
+
const laneRefusal = leaderEntryRefusal(leaderRunEntry(deps.config.autonomy));
|
|
40
|
+
if (laneRefusal !== undefined) {
|
|
41
|
+
sendError(res, 422, "request.autonomy_lane_refused", laneRefusal);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
38
44
|
const r = await endpoint.handle("POST", LEADER_SUBMIT_PATH, body, requester, headerStr(req.headers["idempotency-key"]) ?? null);
|
|
39
45
|
if (r) {
|
|
40
46
|
sendJson(res, r.status, r.body);
|
|
@@ -72,6 +72,7 @@ export declare const RUNS_ROUTES: readonly [{
|
|
|
72
72
|
readonly pattern: RegExp;
|
|
73
73
|
readonly label: "/v1/runs/:id/events";
|
|
74
74
|
readonly methods: readonly ["GET"];
|
|
75
|
+
readonly subscription: true;
|
|
75
76
|
}, {
|
|
76
77
|
readonly id: "run-detail";
|
|
77
78
|
readonly pattern: RegExp;
|
|
@@ -90,6 +91,7 @@ export declare const RUN_VERBS_ROUTES: readonly [{
|
|
|
90
91
|
readonly pattern: RegExp;
|
|
91
92
|
readonly label: "/v1/runs/:id/subagents/:sub/*";
|
|
92
93
|
readonly methods: readonly ["GET"];
|
|
94
|
+
readonly subscription: true;
|
|
93
95
|
}, {
|
|
94
96
|
readonly id: "run-subagent-steer";
|
|
95
97
|
readonly pattern: RegExp;
|
package/dist/http/routes/runs.js
CHANGED
|
@@ -33,7 +33,8 @@ import { mintAndDriveDurableRun } from "../durable-run-leg.js";
|
|
|
33
33
|
import { RUN_NOT_FOUND_MESSAGE, runNotFoundMessage } from "../route-ctx.js";
|
|
34
34
|
import { withPrincipal } from "../../observability/principal-context.js";
|
|
35
35
|
import { readResumeCtx } from "../resume-ctx-read.js";
|
|
36
|
-
import { storedBodyReplayAnswer, storedBodyReplayLogFields
|
|
36
|
+
import { storedBodyReplayAnswer, storedBodyReplayLogFields } from "../checkpoint-ctx.js";
|
|
37
|
+
import { storedBodyReplayRefusal } from "../stored-body-replay.js";
|
|
37
38
|
const STEER_PRIORITY_WORDS = INJECTION_TIERS.map((tier) => `'${tier}'`);
|
|
38
39
|
const STEER_PRIORITY_UNION = STEER_PRIORITY_WORDS.join(" | ");
|
|
39
40
|
const STEER_PRIORITY_CHOICES = STEER_PRIORITY_WORDS.length <= 2 ? STEER_PRIORITY_WORDS.join(" or ") : `${STEER_PRIORITY_WORDS.slice(0, -1).join(", ")}, or ${STEER_PRIORITY_WORDS[STEER_PRIORITY_WORDS.length - 1]}`;
|
|
@@ -647,7 +648,7 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
647
648
|
mintResult.noResumeCtx = true;
|
|
648
649
|
return;
|
|
649
650
|
}
|
|
650
|
-
const unservable = storedBodyReplayRefusal(resumeRead.ctx);
|
|
651
|
+
const unservable = storedBodyReplayRefusal(resumeRead.ctx, deps.config.autonomy);
|
|
651
652
|
if (unservable !== undefined) {
|
|
652
653
|
mintResult.unservable = unservable;
|
|
653
654
|
return;
|
|
@@ -1662,12 +1663,12 @@ export const RUNS_ROUTES = [
|
|
|
1662
1663
|
{ id: "run-detach", pattern: /^\/v1\/runs\/(?<taskId>[^/]+)\/detach$/, label: "/v1/runs/:id/detach", methods: ["POST"] },
|
|
1663
1664
|
{ id: "run-cancel", pattern: /^\/v1\/runs\/(?<taskId>[^/]+)\/cancel$/, label: "/v1/runs/:id/cancel", methods: ["POST"] },
|
|
1664
1665
|
{ id: "run-compact", pattern: /^\/v1\/runs\/(?<taskId>[^/]+)\/compact$/, label: "/v1/runs/:id/compact", methods: ["POST"] },
|
|
1665
|
-
{ id: "run-events", pattern: /^\/v1\/runs\/(?<taskId>[^/]+)\/events$/, label: "/v1/runs/:id/events", methods: ["GET"] },
|
|
1666
|
+
{ id: "run-events", pattern: /^\/v1\/runs\/(?<taskId>[^/]+)\/events$/, label: "/v1/runs/:id/events", methods: ["GET"], subscription: true },
|
|
1666
1667
|
{ id: "run-detail", pattern: /^\/v1\/runs\/(?<taskId>[^/]+)$/, label: "/v1/runs/:id", methods: ["GET"] },
|
|
1667
1668
|
];
|
|
1668
1669
|
export const RUN_VERBS_ROUTES = [
|
|
1669
1670
|
{ id: "run-subagent-output", pattern: /^\/v1\/runs\/(?<runId>[^/]+)\/subagents\/(?<sub>[^/]+)\/output$/, label: "/v1/runs/:id/subagents/:sub/*", methods: ["GET"] },
|
|
1670
|
-
{ id: "run-subagent-stream", pattern: /^\/v1\/runs\/(?<runId>[^/]+)\/subagents\/(?<sub>[^/]+)\/stream$/, label: "/v1/runs/:id/subagents/:sub/*", methods: ["GET"] },
|
|
1671
|
+
{ id: "run-subagent-stream", pattern: /^\/v1\/runs\/(?<runId>[^/]+)\/subagents\/(?<sub>[^/]+)\/stream$/, label: "/v1/runs/:id/subagents/:sub/*", methods: ["GET"], subscription: true },
|
|
1671
1672
|
{ id: "run-subagent-steer", pattern: /^\/v1\/runs\/(?<runId>[^/]+)\/subagents\/(?<sub>[^/]+)\/steer$/, label: "/v1/runs/:id/subagents/:sub/*", methods: ["POST"] },
|
|
1672
1673
|
{ id: "run-subagent-resume", pattern: /^\/v1\/runs\/(?<runId>[^/]+)\/subagents\/(?<sub>[^/]+)\/resume$/, label: "/v1/runs/:id/subagents/:sub/*", billable: "resume", methods: ["POST"] },
|
|
1673
1674
|
{ id: "run-task-output", pattern: /^\/v1\/runs\/(?<runId>[^/]+)\/tasks\/(?<tid>[^/]+)\/output$/, label: "/v1/runs/:id/tasks/:tid/*", methods: ["GET"] },
|
|
@@ -79,6 +79,7 @@ export declare const SESSIONS_ROUTES: readonly [{
|
|
|
79
79
|
readonly pattern: RegExp;
|
|
80
80
|
readonly label: "/v1/sessions/:id/$verb";
|
|
81
81
|
readonly methods: readonly ["GET"];
|
|
82
|
+
readonly subscription: true;
|
|
82
83
|
}, {
|
|
83
84
|
readonly id: "session-fork";
|
|
84
85
|
readonly pattern: RegExp;
|
|
@@ -844,7 +844,7 @@ export const SESSIONS_ROUTES = [
|
|
|
844
844
|
{ id: "session-mcp", pattern: /^\/v1\/sessions\/(?<sessionId>[^/]+)\/mcp$/, label: "/v1/sessions/:id/$verb", methods: ["GET"] },
|
|
845
845
|
{ id: "session-a2a", pattern: /^\/v1\/sessions\/(?<sessionId>[^/]+)\/a2a$/, label: "/v1/sessions/:id/$verb", methods: ["GET"] },
|
|
846
846
|
{ id: "session-head", pattern: /^\/v1\/sessions\/(?<sessionId>[^/]+)\/head$/, label: "/v1/sessions/:id/$verb", methods: ["GET"] },
|
|
847
|
-
{ id: "session-events", pattern: /^\/v1\/sessions\/(?<sessionId>[^/]+)\/events$/, label: "/v1/sessions/:id/$verb", methods: ["GET"] },
|
|
847
|
+
{ id: "session-events", pattern: /^\/v1\/sessions\/(?<sessionId>[^/]+)\/events$/, label: "/v1/sessions/:id/$verb", methods: ["GET"], subscription: true },
|
|
848
848
|
{ id: "session-fork", pattern: /^\/v1\/sessions\/(?<sessionId>[^/]+)\/fork$/, label: "/v1/sessions/:id/$verb", methods: ["POST"] },
|
|
849
849
|
{ id: "session-policy-get", pattern: /^\/v1\/sessions\/(?<sessionId>[^/]+)\/policy$/, label: "/v1/sessions/:id/$verb", methods: ["GET"] },
|
|
850
850
|
{ id: "session-policy-put", pattern: /^\/v1\/sessions\/(?<sessionId>[^/]+)\/policy$/, label: "/v1/sessions/:id/$verb", methods: ["PUT"] },
|
|
@@ -38,6 +38,7 @@ export declare const TRACE_USAGE_ROUTES: readonly [{
|
|
|
38
38
|
readonly pattern: RegExp;
|
|
39
39
|
readonly label: "/v1/tasks/:id/$sub";
|
|
40
40
|
readonly methods: readonly ["GET"];
|
|
41
|
+
readonly subscription: true;
|
|
41
42
|
}, {
|
|
42
43
|
readonly id: "task-trace-artifacts";
|
|
43
44
|
readonly pattern: RegExp;
|
|
@@ -302,7 +302,7 @@ export const TRACE_USAGE_ROUTES = [
|
|
|
302
302
|
{ id: "task-trace-list", path: "/v1/tasks", methods: ["GET"] },
|
|
303
303
|
{ id: "task-tool-result", pattern: /^\/v1\/tasks\/(?<taskId>[^/]+)\/tool-results\/(?<ref>[^/]+)$/, label: "/v1/tasks/:id/tool-results/:ref", methods: ["GET"] },
|
|
304
304
|
{ id: "task-trace-turns", pattern: /^\/v1\/tasks\/(?<taskId>[^/]+)\/turns$/, label: "/v1/tasks/:id/$sub", methods: ["GET"] },
|
|
305
|
-
{ id: "task-trace-stream", pattern: /^\/v1\/tasks\/(?<taskId>[^/]+)\/stream$/, label: "/v1/tasks/:id/$sub", methods: ["GET"] },
|
|
305
|
+
{ id: "task-trace-stream", pattern: /^\/v1\/tasks\/(?<taskId>[^/]+)\/stream$/, label: "/v1/tasks/:id/$sub", methods: ["GET"], subscription: true },
|
|
306
306
|
{ id: "task-trace-artifacts", pattern: /^\/v1\/tasks\/(?<taskId>[^/]+)\/artifacts$/, label: "/v1/tasks/:id/$sub", methods: ["GET"] },
|
|
307
307
|
{ id: "usage-analytics", pattern: /^\/v1\/usage\/(?<sub>summary|series|breakdown)$/, label: "/v1/usage/$sub", methods: ["GET"] },
|
|
308
308
|
];
|
|
@@ -15,6 +15,7 @@ export declare const WORKFLOWS_ROUTES: readonly [{
|
|
|
15
15
|
readonly pattern: RegExp;
|
|
16
16
|
readonly label: "/v1/workflows/:id/$sub";
|
|
17
17
|
readonly methods: readonly ["GET"];
|
|
18
|
+
readonly subscription: true;
|
|
18
19
|
}, {
|
|
19
20
|
readonly id: "workflow-journal";
|
|
20
21
|
readonly pattern: RegExp;
|
|
@@ -416,7 +416,7 @@ function sendWorkflowsUnavailable(res, why) {
|
|
|
416
416
|
}
|
|
417
417
|
export const WORKFLOWS_ROUTES = [
|
|
418
418
|
{ id: "workflows-list", path: "/v1/workflows", methods: ["GET"] },
|
|
419
|
-
{ id: "workflow-stream", pattern: /^\/v1\/workflows\/(?<runId>[^/]+)\/stream$/, label: "/v1/workflows/:id/$sub", methods: ["GET"] },
|
|
419
|
+
{ id: "workflow-stream", pattern: /^\/v1\/workflows\/(?<runId>[^/]+)\/stream$/, label: "/v1/workflows/:id/$sub", methods: ["GET"], subscription: true },
|
|
420
420
|
{ id: "workflow-journal", pattern: /^\/v1\/workflows\/(?<runId>[^/]+)\/journal$/, label: "/v1/workflows/:id/$sub", methods: ["GET"] },
|
|
421
421
|
{ id: "workflow-detail", pattern: /^\/v1\/workflows\/(?<runId>[^/]+)$/, label: "/v1/workflows/:id", methods: ["GET"] },
|
|
422
422
|
];
|
package/dist/http/send.d.ts
CHANGED
|
@@ -47,6 +47,19 @@ export declare const SSE_MAX_STREAM_MS: number;
|
|
|
47
47
|
* 要么给 approvals 减 type=消费端破坏),属候裁,不在本批的零行为码范围内。
|
|
48
48
|
*/
|
|
49
49
|
export declare const SSE_HEARTBEAT_IDLE_MS = 15000;
|
|
50
|
+
/**
|
|
51
|
+
* S-1281 —— 服务端**主动**收一条已开的 SSE 流:一帧 `event: error`(帧形与流帽那一帧同一套 `{type:"error", errorCode, message}`,
|
|
52
|
+
* 消费端按既有「服务端收流 ⇒ 重连」协议处置,SDK 的流读口把它当一帧事件交出再重连)后 `end()`。
|
|
53
|
+
*
|
|
54
|
+
* 收流的是分派器,不是流自己的泵:泵此刻可能正停在一次 await 上,醒来还会写一帧。Node 上 `end()` 之后、`close` 之前的那一写会发一个
|
|
55
|
+
* `error` 事件(实测 v24.2.0:无监听 ⇒ 进程级未捕获;`close` 之后的写只回 `false`,不再发)。⇒ 先挂一只**只吸收这一种**
|
|
56
|
+
* (`ERR_STREAM_WRITE_AFTER_END`)的监听再 `end()`:那一帧本来就无处可去(连接是我们关的),别的错照旧抛(不改既有失败形)。
|
|
57
|
+
* 已收尾的流不碰(幂等;排空入口与硬停起点各调一次)。
|
|
58
|
+
*/
|
|
59
|
+
export declare function endSseWithError(res: ServerResponse, frame: {
|
|
60
|
+
readonly errorCode: string;
|
|
61
|
+
readonly message: string;
|
|
62
|
+
}): void;
|
|
50
63
|
export declare function sendJson(res: ServerResponse, status: number, body: unknown): void;
|
|
51
64
|
/** A6([ref] lens1 §C3/lens3 §C3a): canonical error-response sender for sites that already carry a
|
|
52
65
|
* machine `errorCode` — `errorCode` is a required positional arg (not optional-bag) so a call site
|
package/dist/http/send.js
CHANGED
|
@@ -17,6 +17,15 @@ export function sseHeaders(res, extra) {
|
|
|
17
17
|
}
|
|
18
18
|
export const SSE_MAX_STREAM_MS = 15 * 60 * 1000;
|
|
19
19
|
export const SSE_HEARTBEAT_IDLE_MS = 15_000;
|
|
20
|
+
export function endSseWithError(res, frame) {
|
|
21
|
+
if (res.writableEnded || res.destroyed)
|
|
22
|
+
return;
|
|
23
|
+
res.on("error", (err) => {
|
|
24
|
+
if (err.code !== "ERR_STREAM_WRITE_AFTER_END")
|
|
25
|
+
throw err;
|
|
26
|
+
});
|
|
27
|
+
res.end(`event: error\ndata: ${JSON.stringify({ type: "error", errorCode: frame.errorCode, message: frame.message })}\n\n`);
|
|
28
|
+
}
|
|
20
29
|
export function sendJson(res, status, body) {
|
|
21
30
|
res.writeHead(status, { "content-type": "application/json" });
|
|
22
31
|
res.end(JSON.stringify(body));
|
package/dist/http/server.d.ts
CHANGED
|
@@ -684,6 +684,9 @@ export interface ServiceDeploymentDeps {
|
|
|
684
684
|
* • [ref]:`attachedStreams` 同样 ASSIGNED BY createServer —— 本副本当前打开着的 SSE 流条数
|
|
685
685
|
* (= 引擎附着租约集的大小)。消费方是 `boot/engine-lease.ts` 的自退判据;与 `inflight` 同族,
|
|
686
686
|
* 同一个共享盒子,不另开第二条 main↔server 的通道。
|
|
687
|
+
* • S-1281:`inflight` 只数**工作** —— 只读订阅流(路由表 `subscription` 列的八条 GET SSE 读面)不进 admission 计数,只进
|
|
688
|
+
* `attachedStreams`;`endSubscriptions`(同样 ASSIGNED BY createServer)发 `draining` 终帧后关掉它们,收尾链在排空进入那一拍与
|
|
689
|
+
* 硬停起点各调一次。
|
|
687
690
|
*/
|
|
688
691
|
drainState?: import("../fleet/drain-entry.js").DrainState;
|
|
689
692
|
/** 编排器片 2 件 3:服务租约此刻的读数(`fleet/serving-lease.ts` 的客户端交出;引擎信号铸点与计费准入判同读)。缺席 = 没装租约客户端
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 「这条停驻行的持久化体在本版上能否重放」—— **唯一**判据(三问一只;五个问点同调:续跑驱动段 `resume-legs.ts` `resolveResumeSpecOrBlocked`、
|
|
3
|
+
* plan_review 的 prepare 段、SLA 拒扫腿的跳过臂 `approval-sweeps.ts`、终态 run 的 steer 铸唤醒卡之前 `routes/runs.ts`;`resolveSpec` 本身留作提交腿的拒点)。
|
|
4
|
+
* 三问的规则、记号、拒句与删除条件的属主 = `http/checkpoint-ctx.ts` 顶注;答复 = 那里的 `storedBodyReplayAnswer`。
|
|
5
|
+
*
|
|
6
|
+
* 为什么判据住在这里而不是 `checkpoint-ctx.ts`:第三问要读体的**生效模式词**(`task-settings.ts` `storedBodyPermissionMode`,请求设置的解析层)与本部署此刻的
|
|
7
|
+
* **入口地板**(`runtime-governance.ts` `autonomyModeFloor`)—— 这两只属主带着配置层的包外依赖;`checkpoint-ctx.ts` 被随包的本地排空脚本经编译产物 import,
|
|
8
|
+
* 它的闭包只许 node 内建 / 引擎包根(`test/drain-check-local.test.ts` 的闭包门)。判据只有这一只,前两问的谓词照旧住在各自属主里。
|
|
9
|
+
*/
|
|
10
|
+
import { type PermissionMode } from "@sema-agent/core";
|
|
11
|
+
import { type Autonomy } from "../runtime-governance.js";
|
|
12
|
+
import { type StoredBodyReplayRefusal } from "./checkpoint-ctx.js";
|
|
13
|
+
import type { CheckpointCtx } from "./route-ctx.js";
|
|
14
|
+
/**
|
|
15
|
+
* 第三问:本行体里的模式词能否按当前读法重放。不能 ⇔ 本部署此刻有入口地板 ∧ 行上没有当前的模式词读法记号 ∧ 体的生效词被地板钳会变
|
|
16
|
+
* (core `clampPermissionMode`,与提交入口的盖章同一只钳)⇒ 返回拒因的两个事实(体的词、地板);能 ⇒ `undefined`。
|
|
17
|
+
*/
|
|
18
|
+
export declare function permissionModeReadingUnstated(ctx: CheckpointCtx, floor: PermissionMode | undefined): {
|
|
19
|
+
stored: PermissionMode | undefined;
|
|
20
|
+
floor: PermissionMode;
|
|
21
|
+
} | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* 三问一只判据:不能重放 ⇒ 返回拒的那条规则;能 ⇒ `undefined`。顺序:allow 读法记号 → 技能拒侧读成空 → 模式词读法记号(几问同中时答先中的那一问 ——
|
|
24
|
+
* 任一问中都不重放,句子只需一句)。`autonomy` = 本部署**此刻**的 `config.autonomy`(活 config:热改即生效);地板由它的唯一属主算,问点不自己算。
|
|
25
|
+
*/
|
|
26
|
+
export declare function storedBodyReplayRefusal(ctx: CheckpointCtx, autonomy: Autonomy | undefined): StoredBodyReplayRefusal | undefined;
|
|
27
|
+
//# sourceMappingURL=stored-body-replay.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { clampPermissionMode } from "@sema-agent/core";
|
|
2
|
+
import { storedBodyPermissionMode } from "../task-settings.js";
|
|
3
|
+
import { autonomyModeFloor } from "../runtime-governance.js";
|
|
4
|
+
import { skillDenyInertEntryOf } from "../rule-entry-list.js";
|
|
5
|
+
import { allowListReadingEraOf, allowListReadingUnstated, permissionModeReadingStated } from "./checkpoint-ctx.js";
|
|
6
|
+
export function permissionModeReadingUnstated(ctx, floor) {
|
|
7
|
+
if (floor === undefined || permissionModeReadingStated(ctx))
|
|
8
|
+
return undefined;
|
|
9
|
+
const stored = storedBodyPermissionMode(ctx.body);
|
|
10
|
+
return clampPermissionMode(stored, floor).effective === stored ? undefined : { stored, floor };
|
|
11
|
+
}
|
|
12
|
+
export function storedBodyReplayRefusal(ctx, autonomy) {
|
|
13
|
+
if (allowListReadingUnstated(ctx))
|
|
14
|
+
return { kind: "allow_list_reading", era: allowListReadingEraOf(ctx) };
|
|
15
|
+
const entry = skillDenyInertEntryOf(ctx.body);
|
|
16
|
+
if (entry !== undefined)
|
|
17
|
+
return { kind: "skill_deny_inert", entry };
|
|
18
|
+
const mode = permissionModeReadingUnstated(ctx, autonomyModeFloor(autonomy));
|
|
19
|
+
if (mode !== undefined)
|
|
20
|
+
return { kind: "permission_mode_reading", ...mode };
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=stored-body-replay.js.map
|
package/dist/leader/leader.d.ts
CHANGED
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
import { type RunnerLike, type WorkerReport } from "./fanout.js";
|
|
16
16
|
import { type ExecStreamLike } from "./diffout.js";
|
|
17
17
|
import { type MergeDeps, type MergeResult } from "./merge.js";
|
|
18
|
-
import { type TaskSpec, type VerifyConfig, type CheckpointToken, type TerminalCause, type ToolSpec, type RepairTerminal, type OracleTier, type RepairResult } from "@sema-agent/core";
|
|
18
|
+
import { type PermissionMode, type TaskSpec, type VerifyConfig, type CheckpointToken, type TerminalCause, type ToolSpec, type RepairTerminal, type OracleTier, type RepairResult } from "@sema-agent/core";
|
|
19
|
+
import { type UnattendedLegSpec } from "../unattended-permission-mode.js";
|
|
19
20
|
/** [ref] Slice 6: drive a worker's resource-suspend auto-resume to a terminal (or bound) state. Exported
|
|
20
21
|
* for unit tests. Loops `resume(token, slice)` WHILE the result's terminal cause is a park on a
|
|
21
22
|
* `resource_limit` gate. Exits on: a terminal cause that is not a park, a park on any OTHER gate
|
|
@@ -64,7 +65,27 @@ export interface ProvisionedWorker {
|
|
|
64
65
|
* python3/tests → PARTIAL. Provision a read-effect exec/probe tool here so the verifier can actually verify. */
|
|
65
66
|
verifierTools?: ToolSpec[];
|
|
66
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* 一条 leader run 的**入口体**(提交体去掉 objective 的那一半)—— 运维 `AUTONOMY` 的模式词地板在这条 run 出生的那一拍读一次、经受理门同一只盖章
|
|
70
|
+
* 盖出来的结果(`run-entry.ts` `leaderRunEntry`);地板缺席 ⇒ `{}`。leader 请求不带调用方的模式词,所以入口词就是地板本身(与 run-local 同)。
|
|
71
|
+
* 本 run 铸的每一条 spec 经 {@link withLeaderLeg} 从这一份取词;worker 的续跑体由它展开(`{ ...entry, objective }`)⇒ 首跑、续跑、修复腿同一个词。
|
|
72
|
+
* 入口词是 `plan` 的 run 进不了这条车道(`run-entry.ts` `leaderEntryRefusal`:worker 会话没有计划审阅通道)—— 受理口与出生处同判,到不了 worker。
|
|
73
|
+
* 热改 `AUTONOMY` 只影响之后起的 leader run:在飞的 run 保持它出生时盖下的这一份。
|
|
74
|
+
*/
|
|
75
|
+
export interface LeaderRunEntry {
|
|
76
|
+
readonly permissionMode?: PermissionMode;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* leader 车道铸 spec 的**唯一**合并口:入口体的词写进 spec,再交给无人值守腿的合并口(`withUnattendedLeg` 的 `default` 钳在入口词之下)。
|
|
80
|
+
* 入口体无词 ⇒ spec 原物交给 `withUnattendedLeg`,与不经本口逐字同。本车道的 spec 自己不带模式词(子任务体只有 objective,其余并进的键是预算 / 审批 / 身份),
|
|
81
|
+
* 所以这里是「写」而不是「钳」。五个出生点(worker 首跑的工厂 / 静态两条车道、集成修复、模块门修复、单代理修复环)都调它、不直调 `withUnattendedLeg`
|
|
82
|
+
* (`test/leader-entry-floor.test.ts` 按语法树数调用点):「这条腿的词从哪来」只有入口体一个答案。
|
|
83
|
+
*/
|
|
84
|
+
export declare function withLeaderLeg<S extends Partial<TaskSpec>>(spec: S, entry: LeaderRunEntry): S & UnattendedLegSpec;
|
|
67
85
|
export interface LeaderDeps {
|
|
86
|
+
/** 本 run 的入口体({@link LeaderRunEntry}:运维地板在 run 出生时盖一次)。必填:没有地板的装配写 `{}` —— 缺席不是「没有地板」的合法拼法。
|
|
87
|
+
* 模块门修复与单代理修复环这两个出生点从这里取词(经 {@link withLeaderLeg})。 */
|
|
88
|
+
entry: LeaderRunEntry;
|
|
68
89
|
/** Plan a task into N disjoint-file sub-tasks (MVP: simple/hand-authored; adaptive replan = scale). */
|
|
69
90
|
plan: (task: string) => Promise<SubtaskSpec[]>;
|
|
70
91
|
/** Provision a leader-owned worker (its env seeded with base at `branch` + an env-bound runner). */
|
package/dist/leader/leader.js
CHANGED
|
@@ -16,6 +16,9 @@ export async function autoResumeOnResource(initial, signal, resume, maxSlices =
|
|
|
16
16
|
}
|
|
17
17
|
return vr;
|
|
18
18
|
}
|
|
19
|
+
export function withLeaderLeg(spec, entry) {
|
|
20
|
+
return withUnattendedLeg(entry.permissionMode === undefined ? spec : { ...spec, permissionMode: entry.permissionMode });
|
|
21
|
+
}
|
|
19
22
|
export async function runLeaderTask(task, durableBaseSha, deps) {
|
|
20
23
|
let subs;
|
|
21
24
|
try {
|
|
@@ -201,7 +204,7 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
|
|
|
201
204
|
}
|
|
202
205
|
deps.logger?.info?.("module_repair", { workerId: r.workerId, attempt: attempt + 1, reason: redactHead(verdict.reason ?? "", 500) });
|
|
203
206
|
try {
|
|
204
|
-
const rr = await w.runner.runTaskStream(
|
|
207
|
+
const rr = await w.runner.runTaskStream(withLeaderLeg({ ...sub.spec, objective: deps.moduleGate.repairObjective(sub, safeVerdictReason), sessionId: `${w.sessionId}-r${attempt + 1}` }, deps.entry)).result();
|
|
205
208
|
if (r.stats && rr?.stats)
|
|
206
209
|
r.stats = { ...r.stats, tokens: (r.stats.tokens ?? 0) + (rr.stats.tokens ?? 0), costMicroUsd: (r.stats.costMicroUsd ?? 0) + (rr.stats.costMicroUsd ?? 0) };
|
|
207
210
|
}
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
import { type Runner, type TaskSpec, type ExecutionEnv, type ExecStep, type OracleTier, type RepairResult, type RepairBundle, type RepairTerminal } from "@sema-agent/core";
|
|
32
32
|
import { type WorkerDiff } from "./repair-oracle.js";
|
|
33
33
|
import type { GraderHandle } from "./grader-env-factory.js";
|
|
34
|
-
import type
|
|
34
|
+
import { type LeaderDeps, type ProvisionedWorker, type SubtaskSpec } from "./leader.js";
|
|
35
35
|
import type { WorkerReport } from "./fanout.js";
|
|
36
36
|
/** The per-run inputs the leader's single-agent repair loop needs, resolved by the wire (§3.3). */
|
|
37
37
|
export interface RepairWireCfg {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { runRepairLoop, delimitUntrusted, } from "@sema-agent/core";
|
|
2
2
|
import { mkRepairOracle } from "./repair-oracle.js";
|
|
3
|
+
import { withLeaderLeg } from "./leader.js";
|
|
3
4
|
import { outwardPlane } from "../terminal.js";
|
|
4
5
|
import { redactHead } from "../observability/run-terminal.js";
|
|
5
|
-
import { withUnattendedLeg } from "../unattended-permission-mode.js";
|
|
6
6
|
function statusForTerminal(t) {
|
|
7
7
|
return t === "fixed" || t === "candidate_only" ? "completed" : "failed";
|
|
8
8
|
}
|
|
@@ -87,7 +87,7 @@ export function attachRepairLoopDeps(deps, resolve) {
|
|
|
87
87
|
deps.repairLoop = {
|
|
88
88
|
run: async (solo, sub) => {
|
|
89
89
|
const cfg = await resolve(solo, sub);
|
|
90
|
-
const implSpec =
|
|
90
|
+
const implSpec = withLeaderLeg({ ...sub.spec, sessionId: solo.sessionId }, deps.entry);
|
|
91
91
|
return runRepairLoopForLeader(solo, implSpec, cfg);
|
|
92
92
|
},
|
|
93
93
|
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 一条 leader run 的**入口体**与「它进不进得了 leader 车道」的唯一判据。
|
|
3
|
+
*
|
|
4
|
+
* 规则(与受理门、run-local 同一条):运维 `AUTONOMY=plan` 是提交入口的模式词地板,盖在每一个 spec 出生点。leader 请求不带调用方的模式词,
|
|
5
|
+
* 所以入口体是一份空体盖上地板(受理门同一只盖章 `task-settings.ts` `stampEntryPermissionMode`;地板的唯一属主 `runtime-governance.ts`
|
|
6
|
+
* `autonomyModeFloor`)。
|
|
7
|
+
*
|
|
8
|
+
* `plan` 是**生命周期词**:它靠人审通道(`plan_review`)出口 —— 一个人批准计划,run 才离开 plan。leader 的 worker 会话**没有**那条通道
|
|
9
|
+
* (计划审阅口按 HTTP run 行找卡,worker 会话没有 run 行;审批回决口答不是工具审批、续跑口也拒)⇒ 入口词是 `plan` 的 leader run 交出计划就停在
|
|
10
|
+
* 一张没有端点能决的卡上,写也无人可答。所以这一档在 leader 车道上**响亮拒**(fail-closed):不静默降级成别的模式、不换成只读手、不给 leader 另造审阅口。
|
|
11
|
+
*
|
|
12
|
+
* 问点两个,调同一只 {@link leaderEntryRefusal}:HTTP 受理口(`http/routes/leader.ts`,422,一条 run 都不建)与 run 出生处(`leader/wire.ts`,
|
|
13
|
+
* 受理之后才被热改成 plan 的那一窄窗,以及不经 HTTP 的调用方 —— run 以同一句拒收场,一只 worker 都不 provision)。
|
|
14
|
+
*/
|
|
15
|
+
import { type Autonomy } from "../runtime-governance.js";
|
|
16
|
+
import type { LeaderRunEntry } from "./leader.js";
|
|
17
|
+
/** 一条 leader run 的入口体:地板读一次、受理门同一只盖章(地板缺席 ⇒ `{}`)。调用方读**活** config(热改只影响之后起的 run)。 */
|
|
18
|
+
export declare function leaderRunEntry(autonomy: Autonomy | undefined): LeaderRunEntry;
|
|
19
|
+
/** 拒句:原因(运维的 plan 地板 × 这条车道没有计划审阅通道)+ 两条出路(改走有计划审阅的 run 车道 / 运维换档)。不含任何配置值之外的回显。
|
|
20
|
+
* 受理口(HTTP 422 的 `error`)与 run 出生处(run 的 `error`)读的是这一份;字节由 `test/api-error-text-freeze.test.ts` 的常量锚格冻。 */
|
|
21
|
+
export declare const LEADER_PLAN_ENTRY_REFUSAL: string;
|
|
22
|
+
/**
|
|
23
|
+
* 入口词进不进得了 leader 车道 —— **唯一**判据。返回拒句;`undefined` = 进得了。闭集穷尽 switch:引擎的模式词表加一词 ⇒ 这里编译红,
|
|
24
|
+
* 逼着回答「那个词靠不靠人审通道出口」。
|
|
25
|
+
*/
|
|
26
|
+
export declare function leaderEntryRefusal(entry: LeaderRunEntry): string | undefined;
|
|
27
|
+
//# sourceMappingURL=run-entry.d.ts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { autonomyModeFloor } from "../runtime-governance.js";
|
|
2
|
+
import { stampEntryPermissionMode } from "../task-settings.js";
|
|
3
|
+
export function leaderRunEntry(autonomy) {
|
|
4
|
+
return stampEntryPermissionMode({}, autonomyModeFloor(autonomy));
|
|
5
|
+
}
|
|
6
|
+
export const LEADER_PLAN_ENTRY_REFUSAL = "this deployment runs with AUTONOMY=plan, which starts every task in plan mode and lets it out of plan mode only when a person approves its plan through plan review; " +
|
|
7
|
+
"a leader task's workers have no plan review channel, so they could neither write nor hand their plan to anyone who can approve it. Nothing was started. " +
|
|
8
|
+
"Submit the work as a run instead (POST /v1/runs, whose plan is reviewed through POST /v1/assistant/tasks/:id/plan_review), " +
|
|
9
|
+
"or ask the operator to set AUTONOMY=read-only or AUTONOMY=ask, under which leader tasks run.";
|
|
10
|
+
export function leaderEntryRefusal(entry) {
|
|
11
|
+
const mode = entry.permissionMode;
|
|
12
|
+
if (mode === undefined)
|
|
13
|
+
return undefined;
|
|
14
|
+
switch (mode) {
|
|
15
|
+
case "plan":
|
|
16
|
+
return LEADER_PLAN_ENTRY_REFUSAL;
|
|
17
|
+
case "default":
|
|
18
|
+
case "acceptEdits":
|
|
19
|
+
case "auto":
|
|
20
|
+
case "bypassPermissions":
|
|
21
|
+
case "dontAsk":
|
|
22
|
+
return undefined;
|
|
23
|
+
default: {
|
|
24
|
+
const unhandled = mode;
|
|
25
|
+
throw new Error(`leader entry word "${String(unhandled)}" has no lane arm`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=run-entry.js.map
|
package/dist/leader/wire.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Brain, type Model, type ModelRoles, type ModelPricing, type TaskSpec, type ExecutionEnvFactory, type RemoteExecutionEnv, type ToolResultStore, type SessionStore, type ExecutionEnv, type RunnerDeps } from "@sema-agent/core";
|
|
2
|
+
import type { Autonomy } from "../runtime-governance.js";
|
|
2
3
|
import type { CheckpointStoreFull } from "../plugins/store-backend.js";
|
|
3
4
|
import { type LeaderDeps, type LeaderResult } from "./leader.js";
|
|
4
5
|
import { type DeploymentPostureSeats } from "../boot/runner-deps.js";
|
|
@@ -63,6 +64,15 @@ export interface LeaderWireConfig {
|
|
|
63
64
|
* fail-OPEN。改成函数席之后每只 Runner 构造时现读,与主车道经 swap 门换代**同代**;已经准备好的腿
|
|
64
65
|
* 保留它准备时的那一份(core 的自然快照语义,两条腿同律)。 */
|
|
65
66
|
deploymentPosture?: () => DeploymentPostureSeats;
|
|
67
|
+
/**
|
|
68
|
+
* 运维 `AUTONOMY`(活 config 的那一位)—— 本车道每条 leader run **出生那一拍**读一次,经 `run-entry.ts` 的 `leaderRunEntry`(入口地板 + 受理门同一只盖章)
|
|
69
|
+
* 盖成这条 run 的入口体(`LeaderDeps.entry`);本 run 铸的每一条 spec 与 worker 的续跑体都从它取词。入口词是 `plan` 的 run 进不了这条车道
|
|
70
|
+
* (`leaderEntryRefusal`:worker 会话没有计划审阅通道)⇒ 出生处即以拒句收场;HTTP 受理口用同一只判据先答 422。
|
|
71
|
+
*
|
|
72
|
+
* 🔴 **函数席**(与 `deploymentPosture` / `durable` 同一条先例):`config.autonomy` 被 config-center 原地热改,boot 期取一次值会把这条腿钉在起服那一刻。
|
|
73
|
+
* **必填**:没有 AUTONOMY 的装配递 `() => undefined` —— 缺席不是「没有地板」的合法拼法(权限轴上不许静默放宽)。
|
|
74
|
+
*/
|
|
75
|
+
autonomy: () => Autonomy | undefined;
|
|
66
76
|
/**
|
|
67
77
|
* [ref]([ref])—— **计费/遥测追踪席**,原样递给本车道的每一只 Runner。唯一属主 =
|
|
68
78
|
* `boot/budget-tracing.ts` 的 `createTracer(...)`(主 runner / subRunner / hook runner 经共享基座吃的
|
package/dist/leader/wire.js
CHANGED
|
@@ -5,7 +5,7 @@ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { tmpdir } from "node:os";
|
|
7
7
|
import { Runner, combinePolicies, createDurableQuestionPolicy, QUESTION_AWAITS_RESUME, delimitUntrusted, hasDestroy, } from "@sema-agent/core";
|
|
8
|
-
import {
|
|
8
|
+
import { leaderEntryRefusal, leaderRunEntry } from "./run-entry.js";
|
|
9
9
|
import { buildCheckpointCtx } from "../http/checkpoint-ctx.js";
|
|
10
10
|
import { RemoteContainerExecutionEnv } from "../plugins/remote-env-e2b.js";
|
|
11
11
|
import { E2B_SANDBOX_HOME } from "../execution-lane-caps.js";
|
|
@@ -14,7 +14,7 @@ import { gitSubprocessEnv } from "../server-secret-env.js";
|
|
|
14
14
|
import { presignS3Url } from "../plugins/s3-presign.js";
|
|
15
15
|
import { buildUploadScript, buildUploadLoopScript, uploadLoopCommand, uploadLoopScriptPath, uploadStepSuffix, fetchUploadedDiff, withStaging, UPLOAD_LOOP_PERIOD_SEC } from "./diffup.js";
|
|
16
16
|
import { pullDiff, safeRev } from "./diffout.js";
|
|
17
|
-
import { runLeaderTask } from "./leader.js";
|
|
17
|
+
import { runLeaderTask, withLeaderLeg } from "./leader.js";
|
|
18
18
|
import { attachRepairLoopDeps } from "./repair-wire.js";
|
|
19
19
|
import { routePlanWithFallback, validateSubtasks } from "./planner.js";
|
|
20
20
|
import { createEngineNoticeSeat } from "../boot/runner-deps.js";
|
|
@@ -171,7 +171,7 @@ export function createLeaderRunner(cfg) {
|
|
|
171
171
|
const p = currentPrincipal();
|
|
172
172
|
return p ? { principal: p } : {};
|
|
173
173
|
};
|
|
174
|
-
const mkRepair = (rawEnv, repoDir, oracleFiles) => {
|
|
174
|
+
const mkRepair = (rawEnv, repoDir, oracleFiles, entry) => {
|
|
175
175
|
if (repairRounds <= 0)
|
|
176
176
|
return undefined;
|
|
177
177
|
return {
|
|
@@ -194,12 +194,12 @@ export function createLeaderRunner(cfg) {
|
|
|
194
194
|
delimitUntrusted("FAILING OUTPUT (untrusted)", errorText),
|
|
195
195
|
].join("\n");
|
|
196
196
|
const res = await runner
|
|
197
|
-
.runTaskStream(
|
|
197
|
+
.runTaskStream(withLeaderLeg({
|
|
198
198
|
objective,
|
|
199
199
|
...principalSpec(),
|
|
200
200
|
sessionId: `leader-repair-${Date.now()}-${round}`,
|
|
201
201
|
limits: { maxCostUsd: repairBudgetUsd, maxWalltimeMs: Math.max(300_000, Math.floor(leaderTimeoutMs / 2)) },
|
|
202
|
-
}))
|
|
202
|
+
}, entry))
|
|
203
203
|
.result();
|
|
204
204
|
if (res.terminal.kind !== "completed")
|
|
205
205
|
throw new Error(`repair round ${round} did not complete (status=${outwardPlane(res.terminal).status})`);
|
|
@@ -226,6 +226,10 @@ export function createLeaderRunner(cfg) {
|
|
|
226
226
|
if (!safeRev(body.baseSha)) {
|
|
227
227
|
return { ok: false, reports: [], cancelled: false, error: "baseSha must be a plain git rev (sha/branch token)" };
|
|
228
228
|
}
|
|
229
|
+
const entry = leaderRunEntry(cfg.autonomy());
|
|
230
|
+
const refused = leaderEntryRefusal(entry);
|
|
231
|
+
if (refused !== undefined)
|
|
232
|
+
return { ok: false, reports: [], cancelled: false, error: refused };
|
|
229
233
|
const injectOracles = async (env) => {
|
|
230
234
|
const ofs = body.oracleFiles ?? [];
|
|
231
235
|
if (ofs.length === 0)
|
|
@@ -268,7 +272,7 @@ export function createLeaderRunner(cfg) {
|
|
|
268
272
|
const provisionWorker = async (sub) => {
|
|
269
273
|
const sessionId = `leader-${sub.workerId}-${Date.now()}`;
|
|
270
274
|
const durable = cfg.durable?.();
|
|
271
|
-
const resumeCtx = buildCheckpointCtx({ body: { objective: sub.spec.objective }, unattendedLeg: true });
|
|
275
|
+
const resumeCtx = buildCheckpointCtx({ body: { ...entry, objective: sub.spec.objective }, unattendedLeg: true });
|
|
272
276
|
let durableSpec = {};
|
|
273
277
|
if (durable) {
|
|
274
278
|
const d = durable;
|
|
@@ -353,7 +357,7 @@ export function createLeaderRunner(cfg) {
|
|
|
353
357
|
},
|
|
354
358
|
})),
|
|
355
359
|
fetchDiff: () => fetchUploadedDiff(getUrl),
|
|
356
|
-
spec:
|
|
360
|
+
spec: withLeaderLeg({ ...workerLimits, ...sub.spec, ...durableSpec, ...resourceSpec, ...principalSpec(), objective: `${sub.spec.objective}${uploadStepSuffix(W)}` }, resumeCtx.body),
|
|
357
361
|
};
|
|
358
362
|
}
|
|
359
363
|
if (!cfg.e2bApiKey)
|
|
@@ -368,7 +372,7 @@ export function createLeaderRunner(cfg) {
|
|
|
368
372
|
runner: keepCtxWarm(new Runner({ brain: cfg.brain, models: cfg.models, roles: cfg.roles, pricing: cfg.pricing, ...onNoticeSeat, ...governanceSeat, ...deploymentPostureSeat(), ...tracerSeat, ...usageWindowSeat, ...promptSourceSeat, ...onErrorSeat, ...(cfg.toolResultStore ? { toolResultStore: cfg.toolResultStore } : {}), ...(cfg.sessionStore ? { sessionStore: cfg.sessionStore } : {}), executionEnv: env })),
|
|
369
373
|
diffEnv: env,
|
|
370
374
|
destroy: () => env.destroy().then(() => { }),
|
|
371
|
-
spec:
|
|
375
|
+
spec: withLeaderLeg({ ...workerLimits, ...sub.spec, ...durableSpec, ...resourceSpec, ...principalSpec() }, resumeCtx.body),
|
|
372
376
|
};
|
|
373
377
|
};
|
|
374
378
|
const provisionIntegrationSandbox = async () => {
|
|
@@ -386,7 +390,7 @@ export function createLeaderRunner(cfg) {
|
|
|
386
390
|
}
|
|
387
391
|
const rawEnv = env;
|
|
388
392
|
const oracleFiles = body.oracleFiles ?? [];
|
|
389
|
-
const repair = mkRepair(rawEnv, repo, oracleFiles);
|
|
393
|
+
const repair = mkRepair(rawEnv, repo, oracleFiles, entry);
|
|
390
394
|
return { env: asIntegrationEnv(env), destroy: reap, ...(repair ? { repair } : {}) };
|
|
391
395
|
}
|
|
392
396
|
if (!cfg.e2bApiKey)
|
|
@@ -404,10 +408,11 @@ export function createLeaderRunner(cfg) {
|
|
|
404
408
|
await env.destroy().catch(() => { });
|
|
405
409
|
throw e;
|
|
406
410
|
}
|
|
407
|
-
return { env: asIntegrationEnv(env), destroy: () => env.destroy().then(() => { }), ...(mkRepair(env, repo, body.oracleFiles ?? []) ? { repair: mkRepair(env, repo, body.oracleFiles ?? []) } : {}) };
|
|
411
|
+
return { env: asIntegrationEnv(env), destroy: () => env.destroy().then(() => { }), ...(mkRepair(env, repo, body.oracleFiles ?? [], entry) ? { repair: mkRepair(env, repo, body.oracleFiles ?? [], entry) } : {}) };
|
|
408
412
|
};
|
|
409
413
|
const push = createCoordinatorPush(body.durableRemote, body.targetRef, ident);
|
|
410
414
|
const deps = {
|
|
415
|
+
entry,
|
|
411
416
|
plan,
|
|
412
417
|
provisionWorker,
|
|
413
418
|
provisionIntegrationSandbox,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** 机读码(拼法随 `config.<键名蛇形>_*` 既有族:`config.model_provider_invalid` / `config.retention_policy_invalid`)。 */
|
|
2
2
|
export declare const GATEWAY_URL_USERINFO_CODE = "config.gateway_url_userinfo";
|
|
3
|
-
/** 同族第二码(S-483 座⑨)
|
|
4
|
-
* (码按**规则**命名,不按键名 —— 键名已经逐字在拒因文案里点过了)。 */
|
|
3
|
+
/** 同族第二码(S-483 座⑨):这一位不是一个层级式 http(s) URL(不透明 / 解析不动 / 非 http(s) —— S-1269 起后者同码)。三根键共用一码,
|
|
4
|
+
* 与上面那只同纪律(码按**规则**命名,不按键名 —— 键名已经逐字在拒因文案里点过了)。 */
|
|
5
5
|
export declare const MODEL_ROUTE_URL_INVALID_CODE = "config.model_route_url_invalid";
|
|
6
6
|
/**
|
|
7
7
|
* 🔴 **第三条臂的机读码(S-514;core 7.24.2 / [ref] 提货)——请求根带 `#fragment`**。
|
|
@@ -12,26 +12,19 @@ export declare const MODEL_ROUTE_URL_INVALID_CODE = "config.model_route_url_inva
|
|
|
12
12
|
*/
|
|
13
13
|
export declare const MODEL_ROUTE_URL_FRAGMENT_CODE = "config.model_route_url_fragment";
|
|
14
14
|
/**
|
|
15
|
-
* 模型路由 base URL 的拒因(`undefined` = 这一位合法)——
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* 🔴 ① 为什么必须在这里、而不是「由别的门管」(S-483 座⑨,与 ME/A2A 两座**同病镜像**):本函数此前先问
|
|
22
|
-
* 凭据位、并把「解析不动」读成**没有**凭据(`urlCarriesUserinfo` 的 `return false`),旁注写着「不是 URL 由
|
|
23
|
-
* 别的门管」—— 而 config 层对这三根**没有**那道门(`config.ts` 与 `config-invariants.ts` 只调本函数)。
|
|
24
|
-
* 于是半写 userinfo `http://user:pass@`(`URL.canParse` 假)与 `alice:pw@host:8000`(不透明 URL,
|
|
25
|
-
* `username`/`password` 恒空)两形被当「无凭据」放行,一路到 brain 装配期才由 core 拒;core 那一臂
|
|
26
|
-
* 今天不回显原值 —— 但**「恰好不漏」不是防线**,而且拒启点越晚,运维越读不出是哪根旋钮配错了。
|
|
27
|
-
* ⇒ 判据改成与铸点**同一只** {@link isHierarchicalUrl}:两处再也不可能各判各的。
|
|
28
|
-
*
|
|
29
|
-
* 🚧 **未闭环(不在本车射程)**:层级式但**非 http(s)** 的形(`ftp://h/v1`,不带 userinfo)今天仍放行 ——
|
|
30
|
-
* `fetch` 对它同样必然失败,但那是第三条臂、是一次新的行为面拒启,按三问另开车(S-483 收车档已登记)。
|
|
31
|
-
*
|
|
32
|
-
* 拒因四件齐:**码** + **哪个 env 键** + **洗过的 URL**(host/port/path 逐字,userinfo 与凭据参数成记号 ——
|
|
15
|
+
* 模型路由 base URL 的拒因(`undefined` = 这一位合法)—— 判由 `url-shape.ts` 那一只,本函数按**首个**拒因选码与出路句:
|
|
16
|
+
* ① 不是层级式 http(s) URL ⇒ `config.model_route_url_invalid`;
|
|
17
|
+
* ② 带 userinfo ⇒ `config.gateway_url_userinfo`;
|
|
18
|
+
* ③ 带 `#fragment` ⇒ `config.model_route_url_fragment`。
|
|
19
|
+
* 拒因四件齐:**码** + **哪个 env 键** + **值的样子**(判官的 `buildRefusalShownUrl`:层级式只到 `scheme://host[:port]` + `/…`,不透明形整只成记号 ——
|
|
33
20
|
* 运维要靠 host 认出是哪一条路由,而密码一个字节都不许进启动错误)+ **出路一句**(点名真实旋钮)。
|
|
34
21
|
*
|
|
22
|
+
* ① 为什么在**声明关口**而不是「由别的门管」(S-483 座⑨):半写 userinfo `http://user:pass@`(解析不动)与 `alice:pw@host:8000`
|
|
23
|
+
* (不透明 URL,`username`/`password` 恒空)两形若被当「无凭据」放行,一路到 brain 装配期才由 core 拒,拒启点越晚运维越读不出
|
|
24
|
+
* 是哪根旋钮配错了;层级式非 http(s)(`ftp://h/v1`)对 `fetch` 同样必然失败(S-1269 起同判,修前放行)。
|
|
25
|
+
* ③ 判在声明关口而不是留给 core 的 brain 构造期(S-514):core 的拒因只过位置律、pathname 逐字,`…/v1/sk-…#note` 那一形的
|
|
26
|
+
* core 拒因会把 path 上的令牌原文打进启动日志 —— 值在到达 core 之前就被这里拒掉,那条文本根本不由 core 铸。
|
|
27
|
+
*
|
|
35
28
|
* @param envKey 出问题的那根 env 旋钮的名字(CSV 键上还带第几项)。
|
|
36
29
|
* @param credentialKnob 这条路由把凭据放哪儿 —— 出路一句点名的旋钮名。
|
|
37
30
|
*/
|