@sema-agent/server 7.125.1 → 7.127.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 +229 -2
- package/README.md +2 -2
- package/README.zh-CN.md +2 -2
- package/USAGE.md +346 -145
- package/deploy/sema-up/README.md +1 -1
- package/deploy/sema-up/chart/templates/networkpolicy-sandbox.yaml +57 -0
- package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +32 -1
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +3 -2
- package/deploy/sema-up/chart/templates/server.yaml +2 -1
- package/deploy/sema-up/chart/values.yaml +22 -0
- package/deploy/sema-up/cluster-up.sh +10 -10
- package/deploy/sema-up/kube-up.sh +20 -13
- package/deploy/sema-up/lib/dataroot.sh +1 -1
- package/deploy/sema-up/lib/envf.sh +5 -5
- package/deploy/sema-up/lib/flagshape.sh +5 -5
- package/deploy/sema-up/lib/lanes.py +1 -1
- package/deploy/sema-up/lib/node-addrs.sh +42 -0
- package/deploy/sema-up/lib/parse-machines.py +2 -2
- package/deploy/sema-up/lib/shell-access.sh +1 -1
- package/deploy/sema-up/preflight.sh +4 -4
- package/deploy/sema-up/sema-up.sh +33 -33
- package/deploy/sema-up/smoke.sh +3 -3
- package/deploy/sema-up/stack/compose.yaml +1 -1
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +26 -3
- package/dist/approval-card.d.ts +20 -4
- package/dist/approval-content-kind.d.ts +38 -22
- package/dist/approval-content-kind.js +20 -4
- package/dist/audit.js +3 -0
- package/dist/bench/s1/arms.d.ts +9 -37
- package/dist/bench/s1/arms.js +4 -61
- package/dist/bench/s1/live-deps.d.ts +4 -10
- package/dist/bench/s1/live-deps.js +1 -222
- package/dist/bench/s1/oracle.d.ts +1 -1
- package/dist/bench/s1/reviewer.d.ts +1 -1
- package/dist/bench/s1/row.d.ts +5 -7
- package/dist/bench/s1/row.js +0 -2
- package/dist/bench/s1/run-firm.d.ts +2 -2
- package/dist/bench/s1/run-firm.js +1 -4
- package/dist/bench/s1/runner-ctx.d.ts +17 -29
- package/dist/bench/s1/runner-ctx.js +3 -7
- package/dist/bench/s1/tasks.d.ts +9 -46
- package/dist/bench/s1/tasks.js +4 -63
- package/dist/boot/execution-env.d.ts +38 -26
- package/dist/boot/execution-env.js +87 -41
- package/dist/boot/leader.d.ts +2 -1
- package/dist/boot/memory-boundary.d.ts +1 -1
- package/dist/boot/memory-consolidation.d.ts +37 -3
- package/dist/boot/memory-consolidation.js +18 -2
- package/dist/boot/parked-revive-gate.d.ts +0 -3
- package/dist/boot/parked-revive-gate.js +2 -2
- package/dist/boot/resolve-spec.d.ts +0 -2
- package/dist/boot/resolve-spec.js +12 -17
- package/dist/boot/retention-lane.d.ts +12 -1
- package/dist/boot/retention-lane.js +2 -0
- package/dist/boot/runner-deps.d.ts +7 -6
- package/dist/boot/runner-deps.js +5 -16
- package/dist/boot/session-faces.d.ts +7 -2
- package/dist/boot/session-faces.js +37 -1
- package/dist/boot/stage-03-store-backend.d.ts +1 -0
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -0
- package/dist/boot/stage-05-execution-env.d.ts +2 -2
- package/dist/boot/stage-05-execution-env.js +7 -4
- package/dist/boot/stage-06-runners.d.ts +2 -3
- package/dist/boot/stage-06-runners.js +13 -9
- package/dist/boot/stage-07-capability-layer.d.ts +2 -3
- package/dist/boot/stage-07-capability-layer.js +3 -4
- package/dist/boot/stage-08-reapers.d.ts +2 -3
- package/dist/boot/stage-08-reapers.js +2 -2
- package/dist/boot/stage-09-leader.d.ts +2 -3
- package/dist/boot/stage-09-leader.js +2 -1
- package/dist/boot/stage-10-http-server.d.ts +2 -3
- package/dist/boot/stage-10-http-server.js +2 -2
- package/dist/boot/stores.d.ts +1 -0
- package/dist/boot/stores.js +4 -3
- package/dist/boot/web-admin.d.ts +5 -0
- package/dist/boot/web-admin.js +28 -14
- package/dist/brain.d.ts +2 -2
- package/dist/brain.js +1 -1
- package/dist/capabilities/builtin-tools.d.ts +2 -1
- package/dist/capabilities/composite-members.d.ts +1 -1
- package/dist/capabilities/composite-members.js +1 -1
- package/dist/capabilities/hands-lane.d.ts +9 -6
- package/dist/capabilities/hands-lane.js +2 -2
- package/dist/capabilities/memory-notice.d.ts +27 -22
- package/dist/capabilities/memory-notice.js +15 -17
- package/dist/capabilities/scenarios.d.ts +9 -14
- package/dist/capabilities/scenarios.js +5 -50
- package/dist/capability-facts.d.ts +22 -11
- package/dist/capability-facts.js +13 -6
- package/dist/config-catalog.js +14 -5
- package/dist/config-provider.d.ts +5 -1
- package/dist/config-provider.js +23 -4
- package/dist/config-types.d.ts +19 -2
- package/dist/config.js +41 -6
- package/dist/deployment-governance.d.ts +19 -21
- package/dist/deployment-governance.js +7 -8
- package/dist/env-name-allowlist-knobs.d.ts +5 -5
- package/dist/env-name-allowlist-knobs.js +1 -0
- package/dist/execution-lane-caps.d.ts +12 -0
- package/dist/execution-lane-caps.js +18 -4
- package/dist/fleet/subagent-tail-bus.js +15 -5
- package/dist/hooks/hook-runner.d.ts +84 -30
- package/dist/hooks/hook-runner.js +74 -41
- package/dist/http/admission.js +17 -10
- package/dist/http/durable-run-leg.d.ts +5 -4
- package/dist/http/durable-run-leg.js +2 -4
- package/dist/http/idempotency.d.ts +28 -6
- package/dist/http/idempotency.js +10 -2
- package/dist/http/principal-gate.d.ts +14 -0
- package/dist/http/principal-gate.js +7 -0
- package/dist/http/request-guards.d.ts +2 -1
- package/dist/http/request-guards.js +14 -14
- package/dist/http/resume-legs.d.ts +2 -2
- package/dist/http/resume-legs.js +20 -10
- package/dist/http/route-ctx.d.ts +15 -7
- package/dist/http/routes/a2a-serve.js +11 -7
- package/dist/http/routes/approvals-assistant.js +18 -3
- package/dist/http/routes/background.d.ts +1 -1
- package/dist/http/routes/background.js +1 -1
- package/dist/http/routes/capabilities.js +10 -2
- package/dist/http/routes/mcp-reconnect.js +1 -1
- package/dist/http/routes/runs.d.ts +4 -3
- package/dist/http/routes/runs.js +35 -14
- package/dist/http/routes/session-sync.js +14 -11
- package/dist/http/routes/sessions.js +9 -9
- package/dist/http/routes/side-query.js +6 -19
- package/dist/http/routes/tasks.js +29 -19
- package/dist/http/routes/workflows.js +8 -0
- package/dist/http/server.d.ts +4 -0
- package/dist/http/server.js +3 -5
- package/dist/http/submit-replay.d.ts +15 -8
- package/dist/http/submit-replay.js +6 -0
- package/dist/http/wire-types.d.ts +7 -9
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/internal-run-env.d.ts +30 -0
- package/dist/internal-run-env.js +11 -0
- package/dist/leader/wire.js +3 -2
- package/dist/lsp/manager.js +1 -1
- package/dist/memory-scope.d.ts +19 -7
- package/dist/memory-scope.js +25 -8
- package/dist/observability/fail-open.d.ts +31 -3
- package/dist/observability/fail-open.js +31 -3
- package/dist/observability/metrics.d.ts +0 -1
- package/dist/observability/metrics.js +1 -4
- package/dist/observability/run-terminal.js +72 -4
- package/dist/permission-rule-vocab.d.ts +3 -2
- package/dist/permission-rule-vocab.js +1 -1
- package/dist/plan-cache-probe.d.ts +3 -2
- package/dist/plugins/approval-ask-store-sql.d.ts +1 -1
- package/dist/plugins/caching-session-store.d.ts +42 -22
- package/dist/plugins/caching-session-store.js +19 -9
- package/dist/plugins/checkpoint-store-sql.d.ts +42 -28
- package/dist/plugins/checkpoint-store-sql.js +57 -11
- package/dist/plugins/file-run-store.d.ts +25 -21
- package/dist/plugins/file-run-store.js +70 -34
- package/dist/plugins/k8s-exec-protocol.js +3 -0
- package/dist/plugins/local-checkpoint-store.d.ts +8 -5
- package/dist/plugins/local-checkpoint-store.js +5 -15
- package/dist/plugins/local-session-store.d.ts +66 -7
- package/dist/plugins/local-session-store.js +168 -101
- package/dist/plugins/mailbox-recipient-lifecycle.d.ts +1 -1
- package/dist/plugins/memory-run-store.d.ts +19 -3
- package/dist/plugins/memory-run-store.js +38 -3
- package/dist/plugins/one-time-migrations.d.ts +165 -39
- package/dist/plugins/one-time-migrations.js +51 -144
- package/dist/plugins/pg-pool.js +11 -1
- package/dist/plugins/pg-session-storage.d.ts +2 -0
- package/dist/plugins/pg-session-storage.js +9 -5
- package/dist/plugins/remote-env-adb.d.ts +3 -0
- package/dist/plugins/remote-env-adb.js +1 -0
- package/dist/plugins/remote-env-device.d.ts +3 -0
- package/dist/plugins/remote-env-device.js +1 -0
- package/dist/plugins/remote-env-e2b.d.ts +4 -0
- package/dist/plugins/remote-env-e2b.js +2 -1
- package/dist/plugins/remote-env-host.d.ts +23 -1
- package/dist/plugins/remote-env-host.js +20 -2
- package/dist/plugins/remote-env-k8s.d.ts +264 -41
- package/dist/plugins/remote-env-k8s.js +551 -82
- package/dist/plugins/remote-env-local-docker.d.ts +4 -0
- package/dist/plugins/remote-env-local-docker.js +2 -1
- package/dist/plugins/remote-env-ssh.d.ts +3 -0
- package/dist/plugins/remote-env-ssh.js +1 -0
- package/dist/plugins/retention-store-sql.d.ts +4 -1
- package/dist/plugins/retention-store-sql.js +11 -9
- package/dist/plugins/run-store-sql.d.ts +44 -6
- package/dist/plugins/run-store-sql.js +92 -27
- package/dist/plugins/session-capture-record-store-sql.d.ts +2 -3
- package/dist/plugins/session-store.d.ts +4 -3
- package/dist/plugins/session-store.js +1 -1
- package/dist/plugins/sql-driver.d.ts +2 -1
- package/dist/plugins/store-backend.d.ts +12 -5
- package/dist/plugins/store-backend.js +13 -4
- package/dist/plugins/store-contracts.d.ts +20 -3
- package/dist/plugins/store-open-wait.js +3 -0
- package/dist/plugins/tidb-pool.js +15 -3
- package/dist/plugins/tidb-session-storage.js +3 -2
- package/dist/plugins/tidb-session-store.d.ts +2 -0
- package/dist/plugins/tidb-session-store.js +6 -2
- package/dist/request-key-closure.d.ts +32 -7
- package/dist/request-key-closure.js +25 -9
- package/dist/router/route-orchestration.d.ts +3 -11
- package/dist/router/route-orchestration.js +0 -4
- package/dist/rule-entry-list.js +0 -4
- package/dist/rules-consent.js +3 -0
- package/dist/run-acceptance.d.ts +51 -0
- package/dist/run-acceptance.js +27 -0
- package/dist/run-local.d.ts +5 -4
- package/dist/run-local.js +23 -17
- package/dist/runs.d.ts +7 -11
- package/dist/runs.js +6 -16
- package/dist/sandbox-egress-policy.d.ts +61 -0
- package/dist/sandbox-egress-policy.js +235 -0
- package/dist/security.d.ts +7 -0
- package/dist/security.js +5 -0
- package/dist/server-secret-env.d.ts +10 -4
- package/dist/server-secret-env.js +4 -1
- package/dist/session-error-wire.d.ts +2 -2
- package/dist/session-incarnation.d.ts +46 -2
- package/dist/session-incarnation.js +14 -3
- package/dist/session-sync-kernel.d.ts +10 -3
- package/dist/session-titler.d.ts +5 -3
- package/dist/spec-fields.d.ts +24 -8
- package/dist/spec-fields.js +21 -2
- package/dist/task-workflow.d.ts +6 -4
- package/dist/task-workflow.js +3 -2
- package/dist/tool-approval.d.ts +78 -6
- package/dist/tool-approval.js +7 -3
- package/dist/trace/core-keyset-guard.d.ts +6 -5
- package/dist/trace/engine-notice-wire.d.ts +26 -1
- package/dist/trace/engine-notice-wire.js +7 -2
- package/dist/trace/ledger-events.d.ts +9 -3
- package/dist/trace/ledger-sink.d.ts +7 -0
- package/dist/trace/ledger-sink.js +14 -4
- package/dist/trace/project.d.ts +57 -11
- package/dist/trace/project.js +54 -8
- package/dist/trace/self-minted-wire.d.ts +94 -2
- package/dist/trace/self-minted-wire.js +28 -0
- package/dist/trace/tool-output-media.d.ts +26 -0
- package/dist/trace/tool-output-media.js +57 -0
- package/dist/trace/wire-projection-faces.d.ts +7 -1
- package/dist/trace/wire-projection-faces.js +2 -1
- package/dist/web-admin-client/apply-effective.d.ts +13 -7
- package/dist/web-admin-client/apply-effective.js +11 -26
- package/dist/web-admin-client/apply-ledger.d.ts +2 -2
- package/dist/web-admin-client/candidate-gate.d.ts +39 -4
- package/dist/web-admin-client/candidate-gate.js +9 -2
- package/dist/web-admin-client/facade.d.ts +2 -2
- package/dist/web-admin-client/http-client.d.ts +3 -1
- package/dist/web-admin-client/http-client.js +4 -3
- package/dist/web-admin-client/read-warnings.d.ts +33 -5
- package/dist/web-admin-client/read-warnings.js +41 -6
- package/dist/web-admin-client/types.d.ts +11 -5
- package/dist/workspace-cache.d.ts +45 -0
- package/dist/workspace-cache.js +30 -0
- package/dist/workspace-space-commit.d.ts +116 -0
- package/dist/workspace-space-commit.js +117 -0
- package/dist/workspace-space.d.ts +75 -9
- package/dist/workspace-space.js +52 -1
- package/package.json +4 -4
- package/dist/boot/session-incarnation-seat.d.ts +0 -41
- package/dist/boot/session-incarnation-seat.js +0 -69
- package/dist/capabilities/code-review-council.d.ts +0 -49
- package/dist/capabilities/code-review-council.js +0 -111
- package/dist/capabilities/collab-wire.d.ts +0 -36
- package/dist/capabilities/collab-wire.js +0 -2
- package/dist/capabilities/collab-workflows.d.ts +0 -47
- package/dist/capabilities/collab-workflows.js +0 -90
- package/dist/capabilities/prompts/code-review.d.ts +0 -25
- package/dist/capabilities/prompts/code-review.js +0 -39
- package/dist/capabilities/prompts/team.d.ts +0 -10
- package/dist/capabilities/prompts/team.js +0 -6
- package/dist/capabilities/team.d.ts +0 -113
- package/dist/capabilities/team.js +0 -70
|
@@ -5,6 +5,7 @@ import { isMysqlDupKeyError } from "./sql-errors.js";
|
|
|
5
5
|
import { PLACEMENT_SELECT_COLUMNS, placementFromRow } from "./session-placement.js";
|
|
6
6
|
import { decodeSessionEventPayload } from "./session-event-payload.js";
|
|
7
7
|
import { jsonColumnText } from "./sql-json-column.js";
|
|
8
|
+
import { incarnationFromCell } from "../session-incarnation.js";
|
|
8
9
|
const SESSION_EVENT_BY_TYPE_HINT = "/*+ USE_INDEX(session_event, idx_session_event_type) */";
|
|
9
10
|
export const SESSION_EVENT_LATEST_BY_TYPE_SQL = {
|
|
10
11
|
floor: `SELECT ${SESSION_EVENT_BY_TYPE_HINT} ${jsonColumnText("tidb", "payload")} FROM session_event WHERE session_id = ? AND type = 'compaction' ORDER BY seq DESC LIMIT 1`,
|
|
@@ -39,7 +40,7 @@ export class TiDBSessionStorage extends BaseSessionStorage {
|
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
static async wake(pool, sessionId) {
|
|
42
|
-
const [metaRows] = await pool.query(`SELECT created_at, leaf_id, leaf_seq, ${PLACEMENT_SELECT_COLUMNS} FROM session_meta WHERE session_id = ?`, [sessionId]);
|
|
43
|
+
const [metaRows] = await pool.query(`SELECT created_at, leaf_id, leaf_seq, incarnation, ${PLACEMENT_SELECT_COLUMNS} FROM session_meta WHERE session_id = ?`, [sessionId]);
|
|
43
44
|
const meta = metaRows[0];
|
|
44
45
|
if (!meta)
|
|
45
46
|
return null;
|
|
@@ -47,7 +48,7 @@ export class TiDBSessionStorage extends BaseSessionStorage {
|
|
|
47
48
|
const [eventRows] = await pool.query(`SELECT seq, ${jsonColumnText("tidb", "payload")} FROM session_event WHERE session_id = ? AND seq >= ? ORDER BY seq ASC`, [sessionId, floorSeq]);
|
|
48
49
|
const entries = eventRows.map((r) => decodeSessionEventPayload(r.payload, sessionId, r.seq));
|
|
49
50
|
const placement = placementFromRow(meta);
|
|
50
|
-
const metadata = { id: sessionId, createdAt: toIso(meta.created_at), ...(placement !== undefined ? { placement } : {}) };
|
|
51
|
+
const metadata = { id: sessionId, createdAt: toIso(meta.created_at), incarnation: incarnationFromCell(sessionId, meta.incarnation), ...(placement !== undefined ? { placement } : {}) };
|
|
51
52
|
return new TiDBSessionStorage(pool, sessionId, metadata, entries, meta.leaf_id ?? null, floorEntryId, floorSeq);
|
|
52
53
|
}
|
|
53
54
|
static async computeFloor(pool, sessionId) {
|
|
@@ -63,6 +63,8 @@ export declare class TiDBSessionStore implements SessionStore {
|
|
|
63
63
|
/** S-790:属主 + 化身**一次读**(单行单 SELECT —— 两次独立读在删除 / 重登记的缝里能拼出混世代组合)。`undefined` = 无此会话;
|
|
64
64
|
* 行在而化身为空 ⇒ `SessionIncarnationMissingError`(响亮拒,判据唯一属主 `sessionFaceFromRow`)。 */
|
|
65
65
|
sessionFaceOf(sessionId: string): Promise<SessionFace | undefined>;
|
|
66
|
+
/** core `SessionStore.incarnationOf`(按 id 读住客,给没取会话的那一侧):{@link sessionFaceOf} 的化身那一半 —— 同一次读、同一只解码。 */
|
|
67
|
+
incarnationOf(sessionId: string): Promise<string | undefined>;
|
|
66
68
|
touch(sessionId: string): Promise<void>;
|
|
67
69
|
/** E18 — the session's current leaf `SessionTreeEntry.id` (`session_meta.leaf_id`, set transactionally on every
|
|
68
70
|
* persist). A single SELECT, NO acquire/lock/CAS — safe to call mid-run (write-safety is the append-time CAS, not
|
|
@@ -89,6 +89,9 @@ export class TiDBSessionStore {
|
|
|
89
89
|
return undefined;
|
|
90
90
|
return sessionFaceFromRow(sessionId, rows[0].owner ?? null, rows[0].incarnation);
|
|
91
91
|
}
|
|
92
|
+
async incarnationOf(sessionId) {
|
|
93
|
+
return (await this.sessionFaceOf(sessionId))?.incarnation;
|
|
94
|
+
}
|
|
92
95
|
async touch(sessionId) {
|
|
93
96
|
await this.pool.query("UPDATE session_meta SET updated_at = ? WHERE session_id = ?", [
|
|
94
97
|
new Date(),
|
|
@@ -486,13 +489,14 @@ class TiDBStagingHandle {
|
|
|
486
489
|
const now = new Date();
|
|
487
490
|
await conn.query("INSERT INTO session_meta (session_id, owner, created_at, updated_at, leaf_id, leaf_seq, incarnation) VALUES (?,?,?,?,?,?,?) " +
|
|
488
491
|
"ON DUPLICATE KEY UPDATE owner = VALUES(owner), updated_at = VALUES(updated_at), leaf_id = VALUES(leaf_id), leaf_seq = VALUES(leaf_seq)", [this.realSessionId, owner, now, now, leafId, srcIds.length, mintSessionIncarnation()]);
|
|
489
|
-
const [afterMeta] = await conn.query("SELECT placement_kind FROM session_meta WHERE session_id = ?", [this.realSessionId]);
|
|
492
|
+
const [afterMeta] = await conn.query("SELECT placement_kind, owner, incarnation FROM session_meta WHERE session_id = ?", [this.realSessionId]);
|
|
490
493
|
if (afterMeta[0]?.placement_kind != null) {
|
|
491
494
|
await conn.rollback();
|
|
492
495
|
throw new SessionError("placement_refused", `session ${this.realSessionId} belongs to the ${String(afterMeta[0].placement_kind)} placement partition — a session-sync staged commit cannot overwrite a delegation transcript`);
|
|
493
496
|
}
|
|
497
|
+
const face = sessionFaceFromRow(this.realSessionId, afterMeta[0]?.owner ?? null, afterMeta[0]?.incarnation);
|
|
494
498
|
await conn.commit();
|
|
495
|
-
return { relation: rel.relation };
|
|
499
|
+
return { relation: rel.relation, face };
|
|
496
500
|
}
|
|
497
501
|
catch (err) {
|
|
498
502
|
try {
|
|
@@ -19,6 +19,17 @@ export declare function scanKeyClosure(bag: object, prefix: string, accepted: Re
|
|
|
19
19
|
}): void;
|
|
20
20
|
/** 一张分类表的文案片段(封顶后只报数)。 */
|
|
21
21
|
export declare function keyClosureClause(names: string[], label: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* **场景透传键** —— 它们不属于共享提交面,各属一个场景,由 `capabilities/scenarios.ts` 经
|
|
24
|
+
* `ScenarioRequest` 的索引签名读(亲读那里的 `req.<key>`:除去已在 `TaskRequestBody` 上的 `objective` / `scenario`,
|
|
25
|
+
* 余下只有 `repo` 一个 —— 只喂 discuss 场景与 code-review council 腿的五键随那两条腿删除)。`TaskRequestBody` **刻意不声明**它们(那个类型的
|
|
26
|
+
* 头注逐字成文:场景键属于某一个场景,不属于共享提交面),所以它们只能在这里成文 —— 一个漏登记的场景键
|
|
27
|
+
* 会被本门 400 掉,而那正是「场景收不到它、调用方却拿到 200」的反面:响亮,不静默。
|
|
28
|
+
* 🔴 新场景要读一个新的体键 ⇒ 同批加进本行(加消费点而不加这行 = 那个场景在 wire 上不可用)。
|
|
29
|
+
*/
|
|
30
|
+
declare const TASK_BODY_SCENARIO_KEYS: readonly ["repo"];
|
|
31
|
+
/** 场景透传键的型(wire 变更清单的自铸登记表 `trace/self-minted-wire.ts` 的 `scenarioBodyKey` 按它 `satisfies`)。 */
|
|
32
|
+
export type ScenarioBodyKey = (typeof TASK_BODY_SCENARIO_KEYS)[number];
|
|
22
33
|
/** 剥掉索引签名,只留**具名**键 —— `TaskRequestBody` 上那条 `[k: string]: unknown` 会让
|
|
23
34
|
* `keyof` 退化成 `string`,双向门就永远恒真(零判别力)。
|
|
24
35
|
* 🔴 **导出**(S-405):姊妹门 `request-value-closure.ts` 的双向钉要同一个剥法 —— 抄第二份 = 两处哪天
|
|
@@ -26,12 +37,26 @@ export declare function keyClosureClause(names: string[], label: string): string
|
|
|
26
37
|
export type NamedKeysOf<T> = {
|
|
27
38
|
[K in keyof T as string extends K ? never : number extends K ? never : K]: T[K];
|
|
28
39
|
};
|
|
29
|
-
/**
|
|
30
|
-
* FRESH 提交面的**顶层**键闭集裁决:受理集之外的键 ⇒ 返回拒体(调用方 400 `request.body_shape`);
|
|
31
|
-
* 全部受理 ⇒ `null`。
|
|
32
|
-
*
|
|
33
|
-
* 判据边界(与 settings 那只同源,有意窄):只判**键名**;体本身非对象 ⇒ 本门不判(留给既有的
|
|
34
|
-
* 「missing 'objective' string」那道门,免得同一个体被两句话抢答)。
|
|
35
|
-
*/
|
|
40
|
+
/** FRESH 提交面(`POST /v1/tasks` · `/v1/tasks/stream` · `/v1/runs`)的顶层键裁决。 */
|
|
36
41
|
export declare function taskBodyKeyIssue(raw: unknown): KeyClosureIssue | null;
|
|
42
|
+
declare const RUN_STEER_BODY_KEYS: readonly ["mode", "priority", "text"];
|
|
43
|
+
declare const CONTENT_STEER_BODY_KEYS: readonly ["content"];
|
|
44
|
+
declare const INTERRUPT_STEER_BODY_KEYS: readonly ["text"];
|
|
45
|
+
/** `POST /v1/runs/:id/steer` 的体形(键 = 受理集,值形由路由逐键判)。 */
|
|
46
|
+
export type RunSteerBody = {
|
|
47
|
+
readonly [K in (typeof RUN_STEER_BODY_KEYS)[number]]?: unknown;
|
|
48
|
+
};
|
|
49
|
+
/** 子代 steer / resume 与 workflow 子代 steer 的体形。 */
|
|
50
|
+
export type ContentSteerBody = {
|
|
51
|
+
readonly [K in (typeof CONTENT_STEER_BODY_KEYS)[number]]?: unknown;
|
|
52
|
+
};
|
|
53
|
+
/** `POST /v1/runs/:id/interrupt` 带 text 形的体形。 */
|
|
54
|
+
export type InterruptSteerBody = {
|
|
55
|
+
readonly [K in (typeof INTERRUPT_STEER_BODY_KEYS)[number]]?: unknown;
|
|
56
|
+
};
|
|
57
|
+
/** 送话口的三种体形(闭集;词外是编译错)。 */
|
|
58
|
+
export type SteerBodyForm = "run" | "content" | "interrupt";
|
|
59
|
+
/** 送话口的顶层键裁决(四扇门同一只;`form` 选受理集)。 */
|
|
60
|
+
export declare function steerBodyKeyIssue(raw: unknown, form: SteerBodyForm): KeyClosureIssue | null;
|
|
61
|
+
export {};
|
|
37
62
|
//# sourceMappingURL=request-key-closure.d.ts.map
|
|
@@ -18,9 +18,9 @@ export function keyClosureClause(names, label) {
|
|
|
18
18
|
return `${label}: ${shown.join(", ")}${more > 0 ? ` (+${more} more)` : ""}`;
|
|
19
19
|
}
|
|
20
20
|
const TASK_BODY_DECLARED_KEYS = [
|
|
21
|
-
"a2aPeers", "acceptPartialRestore", "additionalDirectories", "additionalReadDirectories", "agents",
|
|
21
|
+
"a2aPeers", "acceptPartialRestore", "additionalDirectories", "additionalReadDirectories", "agents", "allowTools",
|
|
22
22
|
"appendSystemPrompt", "approvalReach", "attachmentIds", "attachments", "capabilitiesNeeded", "cascade", "clientContext",
|
|
23
|
-
"compaction", "compactionModel", "
|
|
23
|
+
"compaction", "compactionModel", "cwd", "deferTools", "deviceId", "disableSkills", "enableFork",
|
|
24
24
|
"excludeAllTools", "excludeTools", "fileHistory",
|
|
25
25
|
"finalVerification", "forwardSubagentEvents", "images", "inheritEnv", "interactiveTools", "jobId", "limits", "maxCostUsd",
|
|
26
26
|
"maxTokens", "mcpServers", "memory", "memoryCapture", "memoryWrite", "model", "objective", "oneShot", "outputRetries", "outputStyle",
|
|
@@ -30,28 +30,44 @@ const TASK_BODY_DECLARED_KEYS = [
|
|
|
30
30
|
"sessionId", "settings", "skills", "suggestNextPrompts", "systemPrompt", "taskId", "toolMaterializeStrategy",
|
|
31
31
|
"userInvokedSkills", "verify", "verifyRounds",
|
|
32
32
|
];
|
|
33
|
-
const TASK_BODY_SCENARIO_KEYS = ["
|
|
33
|
+
const TASK_BODY_SCENARIO_KEYS = ["repo"];
|
|
34
34
|
const ACCEPTED_BODY = new Set([...TASK_BODY_DECLARED_KEYS, ...TASK_BODY_SCENARIO_KEYS]);
|
|
35
|
-
const
|
|
36
|
-
|
|
35
|
+
const UNSUPPORTED_BODY_KEYS = ["handsReadOnly", "readDenyPatterns", "readFace", "shellGate", "userAttachments", "writeFace"];
|
|
36
|
+
const UNSUPPORTED_BODY = new Set(UNSUPPORTED_BODY_KEYS);
|
|
37
|
+
const UNSUPPORTED_LABEL = "unsupported (an engine seat this service does not read from the request body — set by the deployment, or not offered in this version)";
|
|
38
|
+
function closedBodyKeyIssue(raw, accepted, door) {
|
|
37
39
|
if (raw === null || raw === undefined || typeof raw !== "object" || Array.isArray(raw))
|
|
38
40
|
return null;
|
|
39
41
|
const buckets = { unknown: [], unsupported: [] };
|
|
40
|
-
scanKeyClosure(raw, "",
|
|
42
|
+
scanKeyClosure(raw, "", accepted, UNSUPPORTED_BODY, buckets);
|
|
41
43
|
if (buckets.unknown.length === 0 && buckets.unsupported.length === 0)
|
|
42
44
|
return null;
|
|
43
45
|
buckets.unknown.sort();
|
|
44
46
|
buckets.unsupported.sort();
|
|
45
47
|
const parts = [
|
|
46
|
-
...(buckets.unknown.length > 0 ? [keyClosureClause(buckets.unknown,
|
|
47
|
-
...(buckets.unsupported.length > 0 ? [keyClosureClause(buckets.unsupported,
|
|
48
|
+
...(buckets.unknown.length > 0 ? [keyClosureClause(buckets.unknown, `unknown (not ${door} key — check the spelling)`)] : []),
|
|
49
|
+
...(buckets.unsupported.length > 0 ? [keyClosureClause(buckets.unsupported, UNSUPPORTED_LABEL)] : []),
|
|
48
50
|
];
|
|
49
51
|
return {
|
|
50
52
|
message: `body: unrecognized top-level key(s) — refused rather than dropped, because a dropped key reads as "in effect" to the caller. ` +
|
|
51
53
|
`${parts.join("; ")}. ` +
|
|
52
|
-
`Accepted: ${[...
|
|
54
|
+
`Accepted: ${[...accepted].sort().join(",")}`,
|
|
53
55
|
unknownKeys: buckets.unknown.slice(0, MAX_KEY_ECHO),
|
|
54
56
|
unsupportedKeys: buckets.unsupported.slice(0, MAX_KEY_ECHO),
|
|
55
57
|
};
|
|
56
58
|
}
|
|
59
|
+
export function taskBodyKeyIssue(raw) {
|
|
60
|
+
return closedBodyKeyIssue(raw, ACCEPTED_BODY, "a task-request");
|
|
61
|
+
}
|
|
62
|
+
const RUN_STEER_BODY_KEYS = ["mode", "priority", "text"];
|
|
63
|
+
const CONTENT_STEER_BODY_KEYS = ["content"];
|
|
64
|
+
const INTERRUPT_STEER_BODY_KEYS = ["text"];
|
|
65
|
+
const STEER_DOORS = {
|
|
66
|
+
run: { accepted: new Set(RUN_STEER_BODY_KEYS), door: "a steer-request" },
|
|
67
|
+
content: { accepted: new Set(CONTENT_STEER_BODY_KEYS), door: "a steer-request" },
|
|
68
|
+
interrupt: { accepted: new Set(INTERRUPT_STEER_BODY_KEYS), door: "an interrupt-request" },
|
|
69
|
+
};
|
|
70
|
+
export function steerBodyKeyIssue(raw, form) {
|
|
71
|
+
return closedBodyKeyIssue(raw, STEER_DOORS[form].accepted, STEER_DOORS[form].door);
|
|
72
|
+
}
|
|
57
73
|
//# sourceMappingURL=request-key-closure.js.map
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import { type Autonomy } from "../runtime-governance.js";
|
|
2
2
|
import type { GovernanceOverrides } from "../governance-overrides.js";
|
|
3
|
-
export type OrchestrationMode = "single" | "supervisor"
|
|
3
|
+
export type OrchestrationMode = "single" | "supervisor";
|
|
4
4
|
/** The DETERMINISTIC signals the routing decision reads (extracted by {@link deriveRoutingSignals} from the
|
|
5
5
|
* task's resolved config — no task-content LLM judgement). */
|
|
6
6
|
export interface RoutingSignals {
|
|
7
|
-
/** The caller explicitly chose an orchestration (a `council`/`debate`/`team` request). Honored verbatim —
|
|
8
|
-
* a deliberate choice outranks automatic routing (back-compat + operator intent). */
|
|
9
|
-
explicitMode?: OrchestrationMode;
|
|
10
7
|
/** (a) The task can cause harm its sandbox does NOT contain ⇒ route to SUP prevention. */
|
|
11
8
|
dangerousCapability: boolean;
|
|
12
9
|
/** (b) The task delegates / fans out / is long-horizon ⇒ supervisor goal-keeping + ask-aggregation. */
|
|
@@ -14,19 +11,16 @@ export interface RoutingSignals {
|
|
|
14
11
|
}
|
|
15
12
|
export interface RoutingDecision {
|
|
16
13
|
mode: OrchestrationMode;
|
|
17
|
-
/** A short, audit-friendly machine reason (e.g. `
|
|
14
|
+
/** A short, audit-friendly machine reason (e.g. `danger:prevention-gate` / `default:single`).
|
|
18
15
|
* Emitted on the trace so a routing decision is always explainable (never a silent mode flip). */
|
|
19
16
|
reason: string;
|
|
20
17
|
}
|
|
21
18
|
/**
|
|
22
|
-
* The routing decision (pure). Order matters:
|
|
23
|
-
* else the single default. `team` is NEVER produced here — it only ever appears via {@link RoutingSignals.explicitMode}.
|
|
19
|
+
* The routing decision (pure). Order matters: (a) danger first, then (b) structural, else the single default.
|
|
24
20
|
*/
|
|
25
21
|
export declare function routeOrchestration(s: RoutingSignals): RoutingDecision;
|
|
26
22
|
/** The task facts {@link deriveRoutingSignals} reads — all DETERMINISTIC, resolved before the task runs. */
|
|
27
23
|
export interface RoutingContext {
|
|
28
|
-
/** Caller-explicit orchestration (council/debate/team) — undefined ⇒ the router decides. */
|
|
29
|
-
explicitMode?: OrchestrationMode;
|
|
30
24
|
/** The resolved autonomy for this task — `read-only` hands cannot mutate/egress ⇒ no danger escalation. */
|
|
31
25
|
autonomy?: Autonomy;
|
|
32
26
|
/** The mounted tools can WRITE the project or run a shell (edit_file / write_file / bash). */
|
|
@@ -68,8 +62,6 @@ export declare function routeServiceTask(input: {
|
|
|
68
62
|
hasExecutionEnv: boolean;
|
|
69
63
|
/** The resolved autonomy for the task. */
|
|
70
64
|
autonomy?: Autonomy;
|
|
71
|
-
/** The caller explicitly requested a fan-out (council/debate/team). */
|
|
72
|
-
explicitTeam: boolean;
|
|
73
65
|
}): RoutingDecision;
|
|
74
66
|
/**
|
|
75
67
|
* Resolve whether a task's execution env STRONGLY isolates side effects (a VM/kernel boundary the sandbox tears
|
|
@@ -3,8 +3,6 @@ import { autonomyOverrides } from "../runtime-governance.js";
|
|
|
3
3
|
import { operatorAlwaysHumanAsk } from "../operator-ask.js";
|
|
4
4
|
import { heldRuleName } from "../tool-rule-names.js";
|
|
5
5
|
export function routeOrchestration(s) {
|
|
6
|
-
if (s.explicitMode)
|
|
7
|
-
return { mode: s.explicitMode, reason: `explicit:${s.explicitMode}` };
|
|
8
6
|
if (s.dangerousCapability)
|
|
9
7
|
return { mode: "supervisor", reason: "danger:prevention-gate" };
|
|
10
8
|
if (s.needsGoalKeeping)
|
|
@@ -15,7 +13,6 @@ export function deriveRoutingSignals(ctx) {
|
|
|
15
13
|
const readOnly = ctx.autonomy === "read-only";
|
|
16
14
|
const dangerousCapability = !readOnly && (ctx.canEgress || (ctx.canWriteOrExec && !ctx.isolatedExecEnv));
|
|
17
15
|
return {
|
|
18
|
-
...(ctx.explicitMode ? { explicitMode: ctx.explicitMode } : {}),
|
|
19
16
|
dangerousCapability,
|
|
20
17
|
needsGoalKeeping: ctx.delegatedOrLongHorizon,
|
|
21
18
|
};
|
|
@@ -23,7 +20,6 @@ export function deriveRoutingSignals(ctx) {
|
|
|
23
20
|
export function routeServiceTask(input) {
|
|
24
21
|
const readOnlyHands = autonomyOverrides(input.autonomy).handsReadOnly === true;
|
|
25
22
|
return routeOrchestration(deriveRoutingSignals({
|
|
26
|
-
...(input.explicitTeam ? { explicitMode: "team" } : {}),
|
|
27
23
|
...(input.autonomy ? { autonomy: input.autonomy } : {}),
|
|
28
24
|
canWriteOrExec: input.hasExecutionEnv && !readOnlyHands,
|
|
29
25
|
canEgress: false,
|
package/dist/rule-entry-list.js
CHANGED
|
@@ -27,10 +27,6 @@ export function inertRuleEntryGuidance(i) {
|
|
|
27
27
|
return "`*` names no tool (on an allow list it voids the whole list) — name the tools instead";
|
|
28
28
|
case "namespace_wildcard":
|
|
29
29
|
return "a server segment does not take a wildcard (`mcp__*`) — name the server: mcp__<server> or mcp__<server>__*";
|
|
30
|
-
case "path_pattern":
|
|
31
|
-
return "a write-path or file-pattern entry has no reading on this side — name the tool, or use Read(//<dir>/**) for a directory a Read may cover";
|
|
32
|
-
case "domain":
|
|
33
|
-
return "a domain entry has no reading on this side — name the tool";
|
|
34
30
|
case "content_unsupported":
|
|
35
31
|
return "this tool takes no content form here — name the tool itself, or use Bash(<command>) / Bash(<prefix>:*) for a shell command";
|
|
36
32
|
case "grammar":
|
package/dist/rules-consent.js
CHANGED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **一次提交的「受理」读法** —— 标题器只在引擎**受理**这条 run 之后起(一条律,唯一属主 = 本文件)。
|
|
3
|
+
*
|
|
4
|
+
* ## 受理是哪一刻
|
|
5
|
+
* 引擎把这次提交的 objective 收进会话的那一帧:`human_input{ carrier: "objective", delivery: "applied" }`。它是第一次模型调用
|
|
6
|
+
* 之前的最后一帧;在它之前引擎能拒的一切 —— prepare 门(`config.tool_face_control` / `config.user_invoked_skill_unknown` /
|
|
7
|
+
* `config.memory_capture_unsupported` …)、第一回合前的内联图片准入(`config.image_invalid`)、部署的 UserPromptSubmit 拦截、
|
|
8
|
+
* 开跑前的预算 / 墙钟 —— 都还没让这次输入进会话。`wiring_manifest` 不是受理:它在 prepare 通过时就出了,图片准入与提示拦截
|
|
9
|
+
* 都在它之后(core `run-identity-wiring.js` 推 wiring_manifest,`run-leg.js` 才做图片准入、推 human_input、调模型)。
|
|
10
|
+
*
|
|
11
|
+
* 只回结果、不交流的腿(verify / cascade:core 在自己里面排空每条腿的流,宿主手里没有流)看不到那一帧。它们的受理证据是结果本身:
|
|
12
|
+
* 结果里跑过 turn(`stats.turns > 0`)⇒ objective 进过会话、模型答过。**token 不是证据**:被 UserPromptSubmit 拦下的 objective 不进会话,
|
|
13
|
+
* 而同一条 run 的收尾压缩可以在已有历史的会话上花 token(turns 0、tokens > 0)—— 按 token 判会把被拦下的输入送去起名。
|
|
14
|
+
* 两种证据说的是同一件事,本文件把它们收成一只闩:先到的那一个算数,只算一次。
|
|
15
|
+
*
|
|
16
|
+
* ## 受理之后 / 之前
|
|
17
|
+
* · 受理 ⇒ 标题器起一次(会话没有标题时它才真去生成;判据在标题器里,本文件不重复)。
|
|
18
|
+
* · 没受理就收场(零工作的拒、受理前取消 / 拦截)⇒ 标题器不起:被拒的输入不花一次模型调用,也不被送去起名。
|
|
19
|
+
* 这次提交在提交门铸下的会话行照旧留下(无标题、零消息),与此前同 —— 「提交没让引擎受理就收场」的会话去留是另一件事,不在本文件。
|
|
20
|
+
*
|
|
21
|
+
* ## 谁喂它
|
|
22
|
+
* 三条提交腿(同步 / 流式 / durable)各在两处喂同一只:持流的那一形把每一帧交给 {@link RunAcceptance.observe};终局落行之后调一次
|
|
23
|
+
* {@link RunAcceptance.settle}。腿上不再有「什么时候起标题」的判断,标题器的唯一调用点是本文件的闩。座由提交门在 `prepareSpec` 里
|
|
24
|
+
* 随 spec 一起铸(`PreparedTaskSubmission.acceptance`);不经提交门的内部车道铸一只不带标题器的座,也就不起标题。
|
|
25
|
+
*/
|
|
26
|
+
export interface RunAcceptanceDeps {
|
|
27
|
+
/** 标题器(缺席 = 本部署不自动起名)。 */
|
|
28
|
+
sessionTitler?: {
|
|
29
|
+
maybeTitle(sessionId: string, objective: string, model?: string): void;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export interface RunAcceptanceInput {
|
|
33
|
+
sessionId?: string;
|
|
34
|
+
objective: string;
|
|
35
|
+
/** 本 turn 真实驱动的模型 id(标题器与 turn 同链路)。 */
|
|
36
|
+
model?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface RunAcceptance {
|
|
39
|
+
/** 持流的腿逐帧调用(判哪一帧算受理只在这里)。不抛、不等。 */
|
|
40
|
+
observe(ev: {
|
|
41
|
+
type: string;
|
|
42
|
+
}): void;
|
|
43
|
+
/** 终局落行之后:还没在流上见过受理帧、而结果里跑过 turn(只回结果的腿)⇒ 受理。只读 `stats.turns`。不抛、不等。 */
|
|
44
|
+
settle(result: {
|
|
45
|
+
readonly stats: {
|
|
46
|
+
readonly turns: number;
|
|
47
|
+
};
|
|
48
|
+
}): void;
|
|
49
|
+
}
|
|
50
|
+
export declare function createRunAcceptance(deps: RunAcceptanceDeps, input: RunAcceptanceInput): RunAcceptance;
|
|
51
|
+
//# sourceMappingURL=run-acceptance.d.ts.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
function isObjectiveApplied(ev) {
|
|
2
|
+
if (ev.type !== "human_input")
|
|
3
|
+
return false;
|
|
4
|
+
const h = ev;
|
|
5
|
+
return h.carrier === "objective" && h.delivery === "applied";
|
|
6
|
+
}
|
|
7
|
+
export function createRunAcceptance(deps, input) {
|
|
8
|
+
let accepted = false;
|
|
9
|
+
const accept = () => {
|
|
10
|
+
if (accepted)
|
|
11
|
+
return;
|
|
12
|
+
accepted = true;
|
|
13
|
+
if (input.sessionId)
|
|
14
|
+
deps.sessionTitler?.maybeTitle(input.sessionId, input.objective, input.model);
|
|
15
|
+
};
|
|
16
|
+
return {
|
|
17
|
+
observe(ev) {
|
|
18
|
+
if (!accepted && isObjectiveApplied(ev))
|
|
19
|
+
accept();
|
|
20
|
+
},
|
|
21
|
+
settle(result) {
|
|
22
|
+
if (result.stats.turns > 0)
|
|
23
|
+
accept();
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=run-acceptance.js.map
|
package/dist/run-local.d.ts
CHANGED
|
@@ -14,8 +14,9 @@ export interface RunLocalArgs {
|
|
|
14
14
|
json: boolean;
|
|
15
15
|
/** `--scenario <name>` — pick a capability bundle (default: config.defaultScenario). */
|
|
16
16
|
scenario?: string;
|
|
17
|
-
/** `--session <
|
|
18
|
-
*
|
|
17
|
+
/** `--session <uuid>` — REUSE a session across invocations (durable multi-turn). Only a canonical uuid (any version) is
|
|
18
|
+
* accepted — the same one shape law as the HTTP submit door (`sessionIdShapeIssue`). Default: a fresh id (the session +
|
|
19
|
+
* its events still persist to disk, just not continued). */
|
|
19
20
|
session?: string;
|
|
20
21
|
/** `--workspace <dir>` — the FIXED dir the agent's tool calls operate in (CC-like). Default: the cwd. The
|
|
21
22
|
* agent's file edits PERSIST there (never deleted) — this is the user's own directory, not a sandbox. */
|
|
@@ -96,8 +97,8 @@ export interface LocalGovernanceConfigView extends DeploymentGovernanceConfigVie
|
|
|
96
97
|
* test/run-local.test.ts(该钉已由 🟡 特征化翻成 🔴 正控)。
|
|
97
98
|
* · **禁 memoize**:四个旋钮都是热改字段,每次装配现读活 config(与另两条腿同一姿势)。
|
|
98
99
|
*/
|
|
99
|
-
/**
|
|
100
|
-
export declare function applyLocalGovernance(base: TaskSpec, config: LocalGovernanceConfigView, workspaceDir: string
|
|
100
|
+
/** 豁免根(引擎数据根)不在这里:core 7.49.0 [ref] 起只从 `RunnerDeps.memoryEngineDir` 来(本腿 Runner 装配处,记忆引擎开不开都给)。 */
|
|
101
|
+
export declare function applyLocalGovernance(base: TaskSpec, config: LocalGovernanceConfigView, workspaceDir: string): TaskSpec;
|
|
101
102
|
/** {@link createLocalApprover} 的 io 面(全部可注入,所以两条臂都测得动)。 */
|
|
102
103
|
export interface LocalApproverIo {
|
|
103
104
|
/** 这次调用是不是接在一个人面前(生产里 = `process.stdin.isTTY`)。 */
|
package/dist/run-local.js
CHANGED
|
@@ -38,10 +38,10 @@ import { createRepoClient } from "./capabilities/repo-tools.js";
|
|
|
38
38
|
import { webSearchConfigFromEnv, createWebSearchBackend } from "./plugins/web-search.js";
|
|
39
39
|
import { buildScenarios, gateScenarioRequest, selectScenario, centerScenarios } from "./capabilities/scenarios.js";
|
|
40
40
|
import { createTaskListLane } from "./boot/task-list-lane.js";
|
|
41
|
-
import { pickHandsRunner,
|
|
42
|
-
import { HttpError } from "./security.js";
|
|
41
|
+
import { pickHandsRunner, withoutHands } from "./capabilities/hands-lane.js";
|
|
42
|
+
import { HttpError, sessionIdShapeIssue } from "./security.js";
|
|
43
43
|
import { createMemoryEngineIncidentSink } from "./memory-incident-sink.js";
|
|
44
|
-
import { memoryEngineBackendFor, memoryProjectKeyFor, memorySpecForRequest } from "./memory-scope.js";
|
|
44
|
+
import { fileMemoryEngineRoot, memoryEngineBackendFor, memoryProjectKeyFor, memorySpecForRequest } from "./memory-scope.js";
|
|
45
45
|
import { modelRouteEndpointRefusal } from "./model-route-endpoint.js";
|
|
46
46
|
import { createMemorySyncRunner, createMemorySyncTransport } from "./memory-sync-client.js";
|
|
47
47
|
import { buildPricing, cappedCeiling, createTracer } from "./budget.js";
|
|
@@ -68,9 +68,9 @@ export function parseArgs(argv) {
|
|
|
68
68
|
let workspace;
|
|
69
69
|
let user;
|
|
70
70
|
let json = false;
|
|
71
|
-
const valueFlag = (i, name) => {
|
|
71
|
+
const valueFlag = (i, name, opts = {}) => {
|
|
72
72
|
const v = argv[i];
|
|
73
|
-
if (v === undefined || v.trim() === "" || v.startsWith("--"))
|
|
73
|
+
if (v === undefined || (opts.blankIsValue !== true && v.trim() === "") || v.startsWith("--"))
|
|
74
74
|
throw new UsageError(`${name} needs an argument`);
|
|
75
75
|
return v;
|
|
76
76
|
};
|
|
@@ -82,14 +82,18 @@ export function parseArgs(argv) {
|
|
|
82
82
|
root = valueFlag(++i, "--root");
|
|
83
83
|
else if (a === "--scenario")
|
|
84
84
|
scenario = valueFlag(++i, "--scenario");
|
|
85
|
-
else if (a === "--session")
|
|
86
|
-
session = valueFlag(++i, "--session");
|
|
85
|
+
else if (a === "--session") {
|
|
86
|
+
session = valueFlag(++i, "--session", { blankIsValue: true });
|
|
87
|
+
const issue = sessionIdShapeIssue(session);
|
|
88
|
+
if (issue)
|
|
89
|
+
throw new UsageError(issue);
|
|
90
|
+
}
|
|
87
91
|
else if (a === "--workspace")
|
|
88
92
|
workspace = valueFlag(++i, "--workspace");
|
|
89
93
|
else if (a === "--user")
|
|
90
94
|
user = valueFlag(++i, "--user");
|
|
91
95
|
else if (a === "--help" || a === "-h") {
|
|
92
|
-
throw new UsageError('usage: run-local "<objective>" [--root <dir>] [--json] [--scenario <name>] [--session <
|
|
96
|
+
throw new UsageError('usage: run-local "<objective>" [--root <dir>] [--json] [--scenario <name>] [--session <uuid>] [--workspace <dir>] [--user <id>]');
|
|
93
97
|
}
|
|
94
98
|
else if (a.startsWith("--")) {
|
|
95
99
|
throw new UsageError(`unknown flag: ${a}`);
|
|
@@ -133,8 +137,8 @@ export function missingGatewayRequirements(config) {
|
|
|
133
137
|
return missing;
|
|
134
138
|
}
|
|
135
139
|
const RUN_LOCAL_APPROVAL_SEAT = { kind: "live" };
|
|
136
|
-
export function applyLocalGovernance(base, config, workspaceDir
|
|
137
|
-
return applyRuntimeGovernance({ ...base, toolPolicy: createApprovalBaselinePolicy(config, RUN_LOCAL_APPROVAL_SEAT) }, createDeploymentGovernanceInputs(config, { env: new NodeExecutionEnv({ cwd: workspaceDir }), cwd: workspaceDir }
|
|
140
|
+
export function applyLocalGovernance(base, config, workspaceDir) {
|
|
141
|
+
return applyRuntimeGovernance({ ...base, toolPolicy: createApprovalBaselinePolicy(config, RUN_LOCAL_APPROVAL_SEAT) }, createDeploymentGovernanceInputs(config, { env: new NodeExecutionEnv({ cwd: workspaceDir }), cwd: workspaceDir }));
|
|
138
142
|
}
|
|
139
143
|
const NO_TTY_REFUSAL_REASON = "this run-local invocation has no TTY, so there is no one to put this approval to; it is refused fail-closed instead of being asked.";
|
|
140
144
|
const UNDISPLAYABLE_ARGS_REFUSAL_REASON = "the call's arguments cannot be displayed, so there is nothing a person could review; it is refused fail-closed instead of being asked.";
|
|
@@ -145,6 +149,7 @@ export const NO_TTY_ASK_CLASS_ROW = {
|
|
|
145
149
|
ancestor: { remedy: "terminal_only", autoBudgetReleases: false },
|
|
146
150
|
dangerous_delete: { remedy: "terminal_only", autoBudgetReleases: false },
|
|
147
151
|
unverifiable_delete: { remedy: "terminal_only", autoBudgetReleases: false },
|
|
152
|
+
unverifiable_shell_text: { remedy: "terminal_only", autoBudgetReleases: false },
|
|
148
153
|
transcript_write: { remedy: "terminal_only", autoBudgetReleases: false },
|
|
149
154
|
org_rule: { remedy: "terminal_only", autoBudgetReleases: false },
|
|
150
155
|
governance_unavailable: { remedy: "terminal_only", autoBudgetReleases: false },
|
|
@@ -154,7 +159,7 @@ export const NO_TTY_ASK_CLASS_ROW = {
|
|
|
154
159
|
classifier_no_ruling: { remedy: "terminal_only", autoBudgetReleases: false },
|
|
155
160
|
operator_forced: { remedy: "deployment_mandate", autoBudgetReleases: false },
|
|
156
161
|
shell_floor: { remedy: "shell_gate", autoBudgetReleases: false },
|
|
157
|
-
|
|
162
|
+
target_unresolved: { remedy: "terminal_only", autoBudgetReleases: false },
|
|
158
163
|
probe: { remedy: "terminal_only", autoBudgetReleases: false },
|
|
159
164
|
write_protection: { remedy: "terminal_only", autoBudgetReleases: false },
|
|
160
165
|
tool_marks_mcp: { remedy: "terminal_only", autoBudgetReleases: false },
|
|
@@ -441,6 +446,7 @@ export async function runLocal(argv, deps = {}) {
|
|
|
441
446
|
: undefined;
|
|
442
447
|
const lspManager = hostRx && config.lspHostEnabled && config.requirePrincipal !== true ? createHostLspManager(config, (event, fields) => logger.info(event, fields)) : undefined;
|
|
443
448
|
const memoryEngine = memoryEngineBackendFor(config, root, memoryEngineIncident);
|
|
449
|
+
const engineDataRoot = fileMemoryEngineRoot(config, root);
|
|
444
450
|
try {
|
|
445
451
|
judgeConsolidationValve({ config, memoryEngine });
|
|
446
452
|
}
|
|
@@ -547,6 +553,7 @@ export async function runLocal(argv, deps = {}) {
|
|
|
547
553
|
const sharedRunnerDeps = createSharedRunnerDeps({
|
|
548
554
|
metrics,
|
|
549
555
|
config,
|
|
556
|
+
engineDataRoot,
|
|
550
557
|
governanceSeams,
|
|
551
558
|
logger,
|
|
552
559
|
hands: { commitCoAuthor: "Sema <noreply@vivi-ai.com>" },
|
|
@@ -574,7 +581,7 @@ export async function runLocal(argv, deps = {}) {
|
|
|
574
581
|
const runnerDeps = {
|
|
575
582
|
...sharedRunnerDeps,
|
|
576
583
|
sessionStore,
|
|
577
|
-
...(memoryEngine ? { memoryBackend: memoryEngine.backend
|
|
584
|
+
...(memoryEngine ? { memoryBackend: memoryEngine.backend } : {}),
|
|
578
585
|
onError: engineOnError,
|
|
579
586
|
onAsk,
|
|
580
587
|
...(config.projectMemoryEnabled
|
|
@@ -587,15 +594,14 @@ export async function runLocal(argv, deps = {}) {
|
|
|
587
594
|
const runner = new Runner(runnerDeps);
|
|
588
595
|
const subRunnerDeps = { ...sharedRunnerDeps, sessionStore: new ForkRoutingSessionStore(sessionStore, new TtlSessionStore({ defaultTtlDays: 1 / 24 })), onError: engineOnError, onAsk };
|
|
589
596
|
const subRunner = new Runner(subRunnerDeps);
|
|
590
|
-
const handslessRunner = new Runner(
|
|
591
|
-
const handslessSubRunner = new Runner(withoutExecutionEnv(subRunnerDeps));
|
|
597
|
+
const handslessRunner = new Runner(withoutHands(runnerDeps));
|
|
592
598
|
const skills = loadDeploymentSkills(config);
|
|
593
599
|
const repoClient = config.gitApiBaseUrl ? createRepoClient(config.gitApiKind, config.gitApiBaseUrl, config.gitApiToken) : undefined;
|
|
594
600
|
const webSearchCfg = webSearchConfigFromEnv();
|
|
595
601
|
const webSearch = webSearchCfg ? createWebSearchBackend(webSearchCfg) : undefined;
|
|
596
602
|
const taskListLane = createTaskListLane({ logger });
|
|
597
603
|
const scenarioDeps = {
|
|
598
|
-
runner, subRunner,
|
|
604
|
+
runner, subRunner, model: DEFAULT_MODEL_REF, skills, repoClient, logger,
|
|
599
605
|
...(webSearch ? { webSearch } : {}),
|
|
600
606
|
backgroundAgentStore: fileBackend.backgroundAgentStore,
|
|
601
607
|
taskListStoreFor: taskListLane.storeFor,
|
|
@@ -634,7 +640,7 @@ export async function runLocal(argv, deps = {}) {
|
|
|
634
640
|
}
|
|
635
641
|
const scope = args.user ?? "local";
|
|
636
642
|
const taskTimeoutSec = Math.floor(parseNumOrFailNonNegative("TASK_TIMEOUT_SEC", process.env.TASK_TIMEOUT_SEC || "0"));
|
|
637
|
-
const timeoutSec = taskWallClockSec(taskTimeoutSec, false
|
|
643
|
+
const timeoutSec = taskWallClockSec(taskTimeoutSec, false);
|
|
638
644
|
const mcp = mcpForScenario(config.mcpServers, scenarioName);
|
|
639
645
|
const a2a = a2aForScenario(config.a2aPeers, scenarioName);
|
|
640
646
|
const maxCostUsd = cappedCeiling(undefined, config.maxTaskCostUsd);
|
|
@@ -662,7 +668,7 @@ export async function runLocal(argv, deps = {}) {
|
|
|
662
668
|
...(mcp ? { mcp } : {}),
|
|
663
669
|
...(a2a ? { a2a } : {}),
|
|
664
670
|
...(Object.keys(limits).length > 0 ? { limits } : {}),
|
|
665
|
-
}, config, workspaceDir
|
|
671
|
+
}, config, workspaceDir), onAsk);
|
|
666
672
|
logger.info("run_local_start", { scenario: scenarioName, model: spec.model, sessionId, exec: executionLaneOf(config.remoteExec?.provider) });
|
|
667
673
|
const settleSessionBackground = async () => {
|
|
668
674
|
const reaped = defaultTaskRegistry.reapSessionBackground(sessionId, scope);
|
package/dist/runs.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type { QuestionCoordinator } from "./question.js";
|
|
|
9
9
|
import { type ToolApprovalCoordinator } from "./tool-approval.js";
|
|
10
10
|
import { type FleetRunPublisher } from "./fleet/fleet-bus.js";
|
|
11
11
|
import { type WorkflowCompletionInbox } from "./orchestration/workflow-completion-inbox.js";
|
|
12
|
+
import type { RunAcceptance } from "./run-acceptance.js";
|
|
12
13
|
import type { VerifyRoundsSpec } from "./http/verify-rounds.js";
|
|
13
14
|
import type { UserInputLedger } from "./user-input-ledger.js";
|
|
14
15
|
/**
|
|
@@ -91,14 +92,6 @@ export declare function taskHandleStop(registry: typeof defaultTaskRegistry, han
|
|
|
91
92
|
* 语义上这两种时序是同一件事:本请求赢下了这条 session,而这条 session 的连接是被人断掉的。
|
|
92
93
|
*/
|
|
93
94
|
export declare function markChildrenStoppedByUserOnAbort(signal: AbortSignal, taskId: string, principal: string | null | undefined): void;
|
|
94
|
-
/**
|
|
95
|
-
* A session CAS conflict is swallowed by core into a failed `TaskResult` (it is not thrown from
|
|
96
|
-
* `runTaskStream`), so detect it from the result. Prefer the structured `code` (core ≥1.8); fall
|
|
97
|
-
* back to the conflict wording only for older results without one.
|
|
98
|
-
*/
|
|
99
|
-
export declare function isSessionConflictResult(result: {
|
|
100
|
-
terminal: TerminalCause;
|
|
101
|
-
}): boolean;
|
|
102
95
|
export declare function resumeAtHttpStatus(result: {
|
|
103
96
|
terminal: TerminalCause;
|
|
104
97
|
}): number | undefined;
|
|
@@ -202,8 +195,6 @@ export declare function parkToolCallId(result: unknown, cs: ParkCheckpointReader
|
|
|
202
195
|
* 不塞进 `checkpointGate`——那是 core 的类型,server 不改其形)。非 park / 无 token / tool-less /
|
|
203
196
|
* 读失败 ⇒ **同一引用**原样返回(键缺席)。graft 不负责 strip——组合序恒为 graft → strip。 */
|
|
204
197
|
export declare function graftParkToolCallId<T>(result: T, cs: ParkCheckpointReader | undefined): Promise<T>;
|
|
205
|
-
/** Evict a stale warm-cache entry after a cross-instance write conflict (broken-affinity backstop). */
|
|
206
|
-
export declare function evictIfConflict(runner: Runner, sessionId: string | undefined, result: TaskResult): void;
|
|
207
198
|
/**
|
|
208
199
|
* Drive a task to completion in the background, persisting its events to the durable run log (S2).
|
|
209
200
|
*
|
|
@@ -328,7 +319,12 @@ trustedInternals?: Pick<RunInternals, "workflowParkedResume">,
|
|
|
328
319
|
* 已收敛、未告知的崩溃丢失铸成 `task.user_steer_undrained` / `task.user_followup_undrained`(`cause:"crashed"`,码按受理时的车道选);腿收场时把本腿上的受理 settle 掉。
|
|
329
320
|
* 缺席 ⇒ 两手都不做(与本参数存在之前逐字相同)。
|
|
330
321
|
*/
|
|
331
|
-
userInputLedger?: UserInputLedger
|
|
322
|
+
userInputLedger?: UserInputLedger,
|
|
323
|
+
/**
|
|
324
|
+
* 这次提交的受理座(`src/run-acceptance.ts`):标题器只在引擎受理之后起。普通流形逐帧喂;只回结果的 verify / cascade 形(以及终局写口的
|
|
325
|
+
* 重试腿)终局落行之后收尾一次。缺席 ⇒ 不起标题(起标题此前由路由层在建行时做)。
|
|
326
|
+
*/
|
|
327
|
+
acceptance?: RunAcceptance): Promise<void>;
|
|
332
328
|
/** How often a running instance refreshes its run's updated_at (liveness, independent of events).
|
|
333
329
|
* Must stay strictly below `runStaleSec` (asserted at startup AND on every hot config candidate) or the
|
|
334
330
|
* reaper would race live runs. [ref]:数值的单源是 `config-invariants.ts`(那条不变量的属主),两个消费面
|