@sema-agent/server 7.110.0 → 7.112.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 +16 -0
- package/dist/approval-ask-audit-store.d.ts +38 -25
- package/dist/approval-ask-audit-store.js +26 -59
- package/dist/bench/s1/run-firm.d.ts +11 -0
- package/dist/bench/s1/run-firm.js +47 -32
- package/dist/boot/coordinators.js +1 -1
- package/dist/boot/session-faces.d.ts +4 -0
- package/dist/boot/session-faces.js +3 -1
- package/dist/boot/stage-07-capability-layer.d.ts +1 -0
- package/dist/boot/stage-07-capability-layer.js +4 -3
- package/dist/boot/stage-08-reapers.d.ts +1 -0
- package/dist/boot/stage-09-leader.d.ts +1 -0
- package/dist/boot/stage-09-leader.js +2 -1
- package/dist/boot/stage-10-http-server.d.ts +1 -0
- package/dist/boot/workflow-orchestration.js +1 -1
- package/dist/hooks/hook-runner.d.ts +5 -0
- package/dist/hooks/hook-runner.js +45 -1
- package/dist/http/admission.js +6 -1
- package/dist/http/resume-legs.d.ts +6 -15
- package/dist/http/resume-legs.js +33 -14
- package/dist/http/route-ctx.d.ts +28 -11
- package/dist/http/routes/approvals-assistant.js +1 -1
- package/dist/http/routes/runs.js +17 -7
- package/dist/http/routes/tasks.d.ts +3 -2
- package/dist/http/routes/tasks.js +45 -51
- package/dist/http/server.d.ts +1 -1
- package/dist/http/server.js +1 -2
- package/dist/index.d.ts +1 -1
- package/dist/instruction-selection.d.ts +34 -0
- package/dist/instruction-selection.js +23 -0
- package/dist/observability/corrupt-read-seat.d.ts +18 -0
- package/dist/observability/corrupt-read-seat.js +18 -0
- package/dist/observability/fail-open.d.ts +20 -4
- package/dist/observability/fail-open.js +17 -4
- package/dist/orchestration/workflow-agent-session-index.d.ts +12 -23
- package/dist/orchestration/workflow-agent-session-index.js +11 -50
- package/dist/orchestration/workflow-notify-journal.d.ts +11 -8
- package/dist/orchestration/workflow-notify-journal.js +20 -36
- package/dist/plugins/file-outcome-sink.d.ts +4 -1
- package/dist/plugins/file-outcome-sink.js +9 -3
- package/dist/plugins/file-run-store.js +3 -3
- package/dist/plugins/retention-store-sql.d.ts +1 -1
- package/dist/plugins/retention-store-sql.js +2 -0
- package/dist/plugins/store-backend.js +1 -0
- package/dist/plugins/store-contracts.d.ts +59 -9
- package/dist/plugins/store-contracts.js +10 -0
- package/dist/plugins/user-input-ledger-file.d.ts +4 -2
- package/dist/plugins/user-input-ledger-file.js +11 -1
- package/dist/plugins/user-input-ledger-sql.d.ts +14 -4
- package/dist/plugins/user-input-ledger-sql.js +46 -18
- package/dist/project-memory.d.ts +10 -2
- package/dist/project-memory.js +5 -2
- package/dist/run-cancel-context.d.ts +59 -7
- package/dist/run-cancel-context.js +26 -0
- package/dist/runs.d.ts +7 -5
- package/dist/runs.js +22 -16
- package/dist/trace/ledger-sink.d.ts +4 -0
- package/dist/trace/ledger-sink.js +1 -1
- package/dist/trace/project.d.ts +11 -3
- package/dist/trace/project.js +6 -5
- package/dist/trace/self-minted-wire.d.ts +48 -0
- package/dist/trace/self-minted-wire.js +17 -0
- package/dist/trace/wire-projection-faces.d.ts +3 -3
- package/dist/trace/wire-projection-faces.js +4 -2
- package/dist/user-input-ledger.d.ts +101 -48
- package/dist/user-input-ledger.js +52 -35
- package/package.json +3 -3
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { recordFailOpen } from "../observability/fail-open.js";
|
|
1
2
|
import { isDupKeyError } from "./sql-errors.js";
|
|
2
3
|
import { mysqlDriver, pgDriver } from "./sql-driver.js";
|
|
3
4
|
import { assertPageLimit, CRASHED_CAUSE, SETTLE_HOW_WORDS, USER_INPUT_KIND_WORDS, USER_INPUT_OPEN_SCAN_MAX, USER_INPUT_SESSION_READ_MAX, } from "../user-input-ledger.js";
|
|
@@ -12,35 +13,57 @@ function rowState(r) {
|
|
|
12
13
|
case "settled": {
|
|
13
14
|
const how = String(r["settle_how"]);
|
|
14
15
|
if (!Object.hasOwn(SETTLE_HOW_WORDS, how) || !Number.isFinite(at))
|
|
15
|
-
|
|
16
|
+
return undefined;
|
|
16
17
|
return { kind: "settled", how: how, atMs: at };
|
|
17
18
|
}
|
|
18
19
|
case "converged":
|
|
19
20
|
if (!Number.isFinite(at))
|
|
20
|
-
|
|
21
|
+
return undefined;
|
|
21
22
|
return { kind: "converged", cause: CRASHED_CAUSE, atMs: at };
|
|
22
23
|
default:
|
|
23
|
-
|
|
24
|
+
return undefined;
|
|
24
25
|
}
|
|
25
|
-
throw new Error(`${USER_INPUT_ACCEPTANCE_TABLE} row ${String(r["accept_id"])}: unreadable state (${String(r["state"])} / ${String(r["settle_how"])} / ${String(r["state_at_ms"])})`);
|
|
26
26
|
}
|
|
27
|
-
function
|
|
27
|
+
function readRow(r) {
|
|
28
28
|
const input = String(r["input_kind"]);
|
|
29
29
|
if (!Object.hasOwn(USER_INPUT_KIND_WORDS, input))
|
|
30
|
-
|
|
30
|
+
return { ok: false, reason: `input_kind ${input} is not a ledger word` };
|
|
31
|
+
const state = rowState(r);
|
|
32
|
+
if (state === undefined)
|
|
33
|
+
return { ok: false, reason: `unreadable state (${String(r["state"])} / ${String(r["settle_how"])} / ${String(r["state_at_ms"])})` };
|
|
31
34
|
const announcedAt = r["announced_at_ms"] == null ? undefined : Number(r["announced_at_ms"]);
|
|
32
35
|
return {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
ok: true,
|
|
37
|
+
acceptance: {
|
|
38
|
+
acceptId: String(r["accept_id"]),
|
|
39
|
+
input: input,
|
|
40
|
+
messageId: String(r["message_id"]),
|
|
41
|
+
sessionId: String(r["session_id"]),
|
|
42
|
+
taskId: String(r["task_id"]),
|
|
43
|
+
writer: String(r["writer"]),
|
|
44
|
+
acceptedAtMs: Number(r["accepted_at_ms"]),
|
|
45
|
+
state,
|
|
46
|
+
...(announcedAt !== undefined ? { announced: { atMs: announcedAt, taskId: String(r["announced_task_id"]) } } : {}),
|
|
47
|
+
},
|
|
42
48
|
};
|
|
43
49
|
}
|
|
50
|
+
function readRows(rows, op) {
|
|
51
|
+
const out = [];
|
|
52
|
+
for (const r of rows) {
|
|
53
|
+
const read = readRow(r);
|
|
54
|
+
if (read.ok)
|
|
55
|
+
out.push(read.acceptance);
|
|
56
|
+
else
|
|
57
|
+
recordFailOpen("server.user-input-ledger.corrupt-record-skipped", `table=${USER_INPUT_ACCEPTANCE_TABLE} op=${op} accept_id=${String(r["accept_id"])} ${read.reason}`);
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
function rawCursor(r) {
|
|
62
|
+
const acceptedAtMs = Number(r["accepted_at_ms"]);
|
|
63
|
+
if (!Number.isFinite(acceptedAtMs))
|
|
64
|
+
throw new Error(`${USER_INPUT_ACCEPTANCE_TABLE} row ${String(r["accept_id"])}: accepted_at_ms ${String(r["accepted_at_ms"])} is not a number — cannot page past it`);
|
|
65
|
+
return { acceptedAtMs, acceptId: String(r["accept_id"]) };
|
|
66
|
+
}
|
|
44
67
|
export class SqlUserInputLedgerStore {
|
|
45
68
|
db;
|
|
46
69
|
constructor(db) {
|
|
@@ -76,16 +99,21 @@ export class SqlUserInputLedgerStore {
|
|
|
76
99
|
const { rows } = after === undefined
|
|
77
100
|
? await this.db.query(this.q(`SELECT ${COLUMNS} FROM ${USER_INPUT_ACCEPTANCE_TABLE} WHERE state = 'open' ORDER BY accepted_at_ms, accept_id LIMIT ${limit}`, `SELECT ${COLUMNS} FROM ${USER_INPUT_ACCEPTANCE_TABLE} WHERE state = 'open' ORDER BY accepted_at_ms, accept_id LIMIT ${limit}`), [])
|
|
78
101
|
: await this.db.query(this.q(`SELECT ${COLUMNS} FROM ${USER_INPUT_ACCEPTANCE_TABLE} WHERE state = 'open' AND (accepted_at_ms > ? OR (accepted_at_ms = ? AND accept_id > ?)) ORDER BY accepted_at_ms, accept_id LIMIT ${limit}`, `SELECT ${COLUMNS} FROM ${USER_INPUT_ACCEPTANCE_TABLE} WHERE state = 'open' AND (accepted_at_ms > $1 OR (accepted_at_ms = $2 AND accept_id > $3)) ORDER BY accepted_at_ms, accept_id LIMIT ${limit}`), [after.acceptedAtMs, after.acceptedAtMs, after.acceptId]);
|
|
79
|
-
|
|
102
|
+
const open = readRows(rows, "listOpen");
|
|
103
|
+
return rows.length === limit ? { open, next: rawCursor(rows[rows.length - 1]) } : { open };
|
|
80
104
|
}
|
|
81
105
|
async listCrashed(sessionId) {
|
|
82
106
|
const { rows } = await this.db.query(this.q(`SELECT ${COLUMNS} FROM ${USER_INPUT_ACCEPTANCE_TABLE} WHERE session_id = ? AND state = 'converged' ORDER BY accepted_at_ms DESC, accept_id DESC LIMIT ${USER_INPUT_SESSION_READ_MAX}`, `SELECT ${COLUMNS} FROM ${USER_INPUT_ACCEPTANCE_TABLE} WHERE session_id = $1 AND state = 'converged' ORDER BY accepted_at_ms DESC, accept_id DESC LIMIT ${USER_INPUT_SESSION_READ_MAX}`), [sessionId]);
|
|
83
|
-
return rows
|
|
107
|
+
return readRows(rows, "listCrashed").reverse();
|
|
84
108
|
}
|
|
85
109
|
async listUnannounced(sessionId, limit) {
|
|
86
110
|
const n = assertPageLimit("listUnannounced", limit);
|
|
87
111
|
const { rows } = await this.db.query(this.q(`SELECT ${COLUMNS} FROM ${USER_INPUT_ACCEPTANCE_TABLE} WHERE session_id = ? AND state = 'converged' AND announced_at_ms IS NULL ORDER BY accepted_at_ms, accept_id LIMIT ${n}`, `SELECT ${COLUMNS} FROM ${USER_INPUT_ACCEPTANCE_TABLE} WHERE session_id = $1 AND state = 'converged' AND announced_at_ms IS NULL ORDER BY accepted_at_ms, accept_id LIMIT ${n}`), [sessionId]);
|
|
88
|
-
return rows
|
|
112
|
+
return readRows(rows, "listUnannounced");
|
|
113
|
+
}
|
|
114
|
+
async deleteBySession(sessionId) {
|
|
115
|
+
const res = await this.db.query(this.q(`DELETE FROM ${USER_INPUT_ACCEPTANCE_TABLE} WHERE session_id = ?`, `DELETE FROM ${USER_INPUT_ACCEPTANCE_TABLE} WHERE session_id = $1`), [sessionId]);
|
|
116
|
+
return res.affected;
|
|
89
117
|
}
|
|
90
118
|
}
|
|
91
119
|
export class TiDBUserInputLedgerStore extends SqlUserInputLedgerStore {
|
package/dist/project-memory.d.ts
CHANGED
|
@@ -25,7 +25,8 @@ interface ProjectMemoryCtx {
|
|
|
25
25
|
* every CLAUDE file it finds, per directory level up the ancestor chain, whereas this loader reads one root and
|
|
26
26
|
* takes the single first hit. */
|
|
27
27
|
declare const INSTRUCTION_FILE_CHAIN: readonly ["CLAUDE.md", ".claude/CLAUDE.md", "AGENTS.md", ".claude/AGENTS.md"];
|
|
28
|
-
|
|
28
|
+
/** 一个链成员(相对项目根的拼写)。导出给 S-961 的 wire 段与它的值闭集登记(`trace/self-minted-wire.ts`)—— 链长一员,两处 tsc 跟着红。 */
|
|
29
|
+
export type InstructionChainMember = (typeof INSTRUCTION_FILE_CHAIN)[number];
|
|
29
30
|
/** Recover (root, rel) for a path the LOADER declared — every declared path is `root + one chain member`.
|
|
30
31
|
* The probe needs this to re-run the loader's parent-directory symlink gate each round (self-review: the probe
|
|
31
32
|
* checked only the final component, so swapping `.claude` for a symlink out of the repo MID-RUN made the probe
|
|
@@ -33,7 +34,7 @@ type ChainMember = (typeof INSTRUCTION_FILE_CHAIN)[number];
|
|
|
33
34
|
* calls it with the host `node:path`. */
|
|
34
35
|
export declare function instructionChainCoordinates(absPath: string, p?: PlatformPath): {
|
|
35
36
|
root: string;
|
|
36
|
-
rel:
|
|
37
|
+
rel: InstructionChainMember;
|
|
37
38
|
} | null;
|
|
38
39
|
/**
|
|
39
40
|
* Build a `loadProjectMemory` for the host lane. Returns null (skip) unless hands are enabled AND cwd is a local
|
|
@@ -54,6 +55,13 @@ export declare function instructionChainCoordinates(absPath: string, p?: Platfor
|
|
|
54
55
|
* an absolute local directory) is "not applicable", not "none" — it never reaches the mint (O6, see `LoadOutcome`). The member is the one the snapshot carries — a cache hit answers the cached pick, so
|
|
55
56
|
* the notice follows what the model actually reads, not the disk (a same-process edit changes nothing until the
|
|
56
57
|
* snapshot is re-read: restart, post-compact, or a new session).
|
|
58
|
+
*
|
|
59
|
+
* S-961 — the same statement (same predicate, same member) also settles the calling LEG's `wiring_manifest.instructions`
|
|
60
|
+
* segment through {@link settleLegInstructionStatement} (`instruction-selection.ts`): the leg scope is the run identity
|
|
61
|
+
* the ctx does not carry, and the first call inside a leg's scope whose `ctx.sessionId` equals the leg's session is that
|
|
62
|
+
* leg's own prepare (a session-less adhoc leg falls back to plain first-call; [ref] X1). The segment projects
|
|
63
|
+
* `instructionFile`, not `instructionSources`: an empty selected file with no git narrative returns no answer and so no
|
|
64
|
+
* `instructionSources`, yet it IS the pick (it shadows every member below it) — and the notice reads the same value.
|
|
57
65
|
*/
|
|
58
66
|
export declare function makeLoadProjectMemory(opts: {
|
|
59
67
|
logger?: {
|
package/dist/project-memory.js
CHANGED
|
@@ -3,6 +3,7 @@ import { execFile } from "node:child_process";
|
|
|
3
3
|
import { createHmac, randomBytes } from "node:crypto";
|
|
4
4
|
import hostPath, { isAbsolute, join } from "node:path";
|
|
5
5
|
import { announceInstructionSource } from "./instruction-source-notice.js";
|
|
6
|
+
import { settleLegInstructionStatement } from "./instruction-selection.js";
|
|
6
7
|
import { gitSubprocessEnv } from "./server-secret-env.js";
|
|
7
8
|
import { redactSecrets } from "./trace/redact.js";
|
|
8
9
|
const INSTRUCTION_FILE_CHAIN = ["CLAUDE.md", ".claude/CLAUDE.md", "AGENTS.md", ".claude/AGENTS.md"];
|
|
@@ -92,8 +93,10 @@ export function makeLoadProjectMemory(opts) {
|
|
|
92
93
|
const seat = opts.instructionSource;
|
|
93
94
|
return async (ctx) => {
|
|
94
95
|
const outcome = await loadOutcome(ctx);
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
const statement = outcome.walked && !ctx.isSubagent ? { stated: true, file: outcome.instructionFile } : { stated: false };
|
|
97
|
+
settleLegInstructionStatement(statement, ctx.sessionId);
|
|
98
|
+
if (seat && ctx.sessionId && statement.stated)
|
|
99
|
+
await announceInstructionSource(seat, ctx.sessionId, statement.file);
|
|
97
100
|
return outcome.answer;
|
|
98
101
|
};
|
|
99
102
|
async function loadOutcome(ctx) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PersistedTaskResult, RunCancelContext } from "./plugins/store-contracts.js";
|
|
1
|
+
import type { AbortCause, PersistedTaskResult, RunCancelContext } from "./plugins/store-contracts.js";
|
|
2
2
|
/**
|
|
3
3
|
* @param taskId 这条 run 的账本 id(turn 活性登记的键)。
|
|
4
4
|
* @param startedAtMs 这条 run 起跑的墙钟时刻(epoch ms):取消腿手上有行就用行的 `createdAt`,
|
|
@@ -43,11 +43,23 @@ export declare const CANCELLED_CODE = "cancelled";
|
|
|
43
43
|
* · `cancelContext`:已经有快照就不重铸(重铸会把「上一条引擎事件多久以前」重新计时)。
|
|
44
44
|
*
|
|
45
45
|
* ## 为什么不判「这条 failed 是不是 abort 形」
|
|
46
|
-
*
|
|
47
|
-
* `
|
|
46
|
+
* 判据在**调用点**:调用点问的是「本腿这次是不是被 server 中止了」—— 本腿 {@link RunAbort} 句柄上登记的成因
|
|
47
|
+
* (`cause()` 在场),那是 server 自己的事实。让本函数去嗅 `terminal.message` 的字面就是再造事实
|
|
48
48
|
* —— [ref] 二那次事故的同一个形。
|
|
49
|
+
*
|
|
50
|
+
* ## S-947:成因(`abortCause`)与码、快照**同进同退**
|
|
51
|
+
* `cause` 是**必填**:本函数是 server 铸取消终局的唯一出口,而每一次取消都有一个发起者 ⇒ 「本仓铸的取消终局上恒有
|
|
52
|
+
* `abortCause`」由签名保证,不靠调用方记得。它走与补码、补快照**同一条**空座闸 —— 引擎给的终局不是无码的 failed
|
|
53
|
+
* (与中止赛跑跑完了 / 引擎自带码)⇒ 整只原样返回,成因也不挂(那条终局不是这次中止的结果,挂上就是「完成了却带着取消便签」)。
|
|
49
54
|
*/
|
|
50
|
-
export declare function mintCancelledResult(args: {
|
|
55
|
+
export declare function mintCancelledResult<R extends PersistedTaskResult>(args: CancelMintArgs & {
|
|
56
|
+
engineResult: R;
|
|
57
|
+
}): R;
|
|
58
|
+
export declare function mintCancelledResult(args: CancelMintArgs & {
|
|
59
|
+
engineResult?: undefined;
|
|
60
|
+
}): PersistedTaskResult;
|
|
61
|
+
/** {@link mintCancelledResult} 的公共实参(`engineResult` 另列:在场与否决定返回型)。 */
|
|
62
|
+
interface CancelMintArgs {
|
|
51
63
|
/** 这条 run 的账本 id(活性登记的键;账本不在场时给空串,快照按「证不出」处理)。 */
|
|
52
64
|
taskId: string;
|
|
53
65
|
/** 会话 id(合成形要写进结果;引擎给了结果时不用)。 */
|
|
@@ -56,7 +68,47 @@ export declare function mintCancelledResult(args: {
|
|
|
56
68
|
startedAtMs: number;
|
|
57
69
|
/** 合成形的失败文案(引擎给了终局时不用)。 */
|
|
58
70
|
message: string;
|
|
59
|
-
/**
|
|
60
|
-
|
|
61
|
-
}
|
|
71
|
+
/** S-947:这次取消的发起者(本腿 {@link RunAbort} 句柄上登记的那一个;park 中直接终局化的取消动词给 `"cancel_verb"`)。 */
|
|
72
|
+
cause: AbortCause;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* S-947 —— 没有 `done` 可落的取消形在账本上的那一行(`failed`):**从铸好的取消终局投影**,不手抄。
|
|
76
|
+
*
|
|
77
|
+
* 账本 `failed` 行是平面形(`errorMessage` / `errorCode` 顶层),所以成因也在顶层、与 `errorCode` 并列;有 `done` 可落的
|
|
78
|
+
* 那几形,成因随 `done.result` 走(结果本身带它)。两形同一个来源 = 同一只取消终局,不是两处各写一份。
|
|
79
|
+
* 返回纯数据 ⇒ `build*`。
|
|
80
|
+
*/
|
|
81
|
+
export declare function buildCancelledLedgerRow(c: PersistedTaskResult): {
|
|
82
|
+
errorMessage?: string;
|
|
83
|
+
errorCode?: string;
|
|
84
|
+
abortCause?: AbortCause;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* S-947 —— 一条 run 腿的**中止句柄**:server 中止这条腿的唯一入口,也是「为什么中止」的唯一登记处。
|
|
88
|
+
*
|
|
89
|
+
* ## 为什么是句柄、不是一张按 taskId 键控的表
|
|
90
|
+
* 修前这件事由 `cancelledViaVerb: Set<taskId>`(「这次是取消动词」一个词)+ 各腿手写的生命周期(登记 / finally 里按身份守卫删 /
|
|
91
|
+
* 同步腿「删之前先取」)承担:一个键控在 **taskId** 上的旁表,要防的病都来自键与腿不同寿 —— 快速续跑在旧腿 finally 之前
|
|
92
|
+
* 用同一 taskId 登记新腿、旧腿收尾删掉新腿的条目;同步腿必须在删之前取值。成因挂在**腿自己的中止控制器**上之后,
|
|
93
|
+
* 这些规则一条都不需要:句柄与腿同寿,换腿就是换句柄,没有可删、可串、可漏的旁表。
|
|
94
|
+
*
|
|
95
|
+
* ## 先到先得(first-writer-wins)
|
|
96
|
+
* 第一次 `abort(cause)` 生效并登记成因;之后的调用全是 no-op(信号早已中止,成因不改写)—— 断连之后又到了取消动词、
|
|
97
|
+
* 取消之后又断连,终局说的都是**真正让这条腿停下来**的那一个。`AbortController.abort()` 自身就是幂等的,本句柄只是在
|
|
98
|
+
* 「第一次」那一刻把词记下。
|
|
99
|
+
*
|
|
100
|
+
* ## 引擎看到的东西不变
|
|
101
|
+
* 中止走 `AbortController.abort()` 的默认原因(引擎、provider 的 fetch、子进程看到的仍是标准 `AbortError`)—— 成因**不**塞进
|
|
102
|
+
* `signal.reason`:那会改掉引擎与 provider 层收到的拒绝值,是在下游改上游接缝的输入(立宪禁区)。
|
|
103
|
+
*/
|
|
104
|
+
export interface RunAbort {
|
|
105
|
+
/** 交给引擎的那只信号(`spec.signal` / 审批 / 提问 ALS 的 `abortSignal` / 子代 stoppedBy 归因都用它)。 */
|
|
106
|
+
readonly signal: AbortSignal;
|
|
107
|
+
/** 以 `cause` 中止本腿。已中止 ⇒ no-op(成因不改写)。 */
|
|
108
|
+
abort(cause: AbortCause): void;
|
|
109
|
+
/** 让本腿停下来的那次中止的成因;未中止 ⇒ `undefined`。 */
|
|
110
|
+
cause(): AbortCause | undefined;
|
|
111
|
+
}
|
|
112
|
+
export declare function createRunAbort(): RunAbort;
|
|
113
|
+
export {};
|
|
62
114
|
//# sourceMappingURL=run-cancel-context.d.ts.map
|
|
@@ -23,6 +23,7 @@ export function mintCancelledResult(args) {
|
|
|
23
23
|
...engine,
|
|
24
24
|
terminal: { ...engine.terminal, code: CANCELLED_CODE },
|
|
25
25
|
...(engine.cancelContext === undefined && ctx !== undefined ? { cancelContext: ctx } : {}),
|
|
26
|
+
abortCause: args.cause,
|
|
26
27
|
};
|
|
27
28
|
}
|
|
28
29
|
return {
|
|
@@ -32,6 +33,31 @@ export function mintCancelledResult(args) {
|
|
|
32
33
|
result: "",
|
|
33
34
|
stats: { turns: 0, tokens: 0, usageMissing: true },
|
|
34
35
|
...(ctx ? { cancelContext: ctx } : {}),
|
|
36
|
+
abortCause: args.cause,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function buildCancelledLedgerRow(c) {
|
|
40
|
+
const t = c.terminal;
|
|
41
|
+
return {
|
|
42
|
+
...(t.kind === "failed" && t.message !== undefined ? { errorMessage: t.message } : {}),
|
|
43
|
+
...(t.kind === "failed" && t.code !== undefined ? { errorCode: t.code } : {}),
|
|
44
|
+
...(c.abortCause !== undefined ? { abortCause: c.abortCause } : {}),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export function createRunAbort() {
|
|
48
|
+
const ctrl = new AbortController();
|
|
49
|
+
let landed;
|
|
50
|
+
return {
|
|
51
|
+
signal: ctrl.signal,
|
|
52
|
+
abort(cause) {
|
|
53
|
+
if (ctrl.signal.aborted)
|
|
54
|
+
return;
|
|
55
|
+
landed = cause;
|
|
56
|
+
ctrl.abort();
|
|
57
|
+
},
|
|
58
|
+
cause() {
|
|
59
|
+
return landed;
|
|
60
|
+
},
|
|
35
61
|
};
|
|
36
62
|
}
|
|
37
63
|
//# sourceMappingURL=run-cancel-context.js.map
|
package/dist/runs.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { defaultTaskRegistry, type CascadeConfig, type CheckpointToken, type Run
|
|
|
2
2
|
import type { SendUserFileEmitter } from "./capabilities/send-user-file-tool.js";
|
|
3
3
|
import type { RunStore } from "./plugins/store-backend.js";
|
|
4
4
|
import type { Metrics } from "./observability/metrics.js";
|
|
5
|
+
import { type RunAbort } from "./run-cancel-context.js";
|
|
5
6
|
import type { ModelUsageTracker, PromptManifestTracker } from "./budget.js";
|
|
6
7
|
import type { ElicitationCoordinator } from "./elicitation.js";
|
|
7
8
|
import type { QuestionCoordinator } from "./question.js";
|
|
@@ -259,10 +260,11 @@ export declare function evictIfConflict(runner: Runner, sessionId: string | unde
|
|
|
259
260
|
* text); tool/lifecycle events are recorded individually. Per-token live streaming stays on the
|
|
260
261
|
* synchronous `/v1/tasks/stream` endpoint. Never throws — failures are recorded on the run.
|
|
261
262
|
*
|
|
262
|
-
* Cancellation (POST /v1/runs/:id/cancel): the run registers
|
|
263
|
-
* fast path — the cancel handler aborts it directly) and its heartbeat tick polls the durable
|
|
264
|
-
* `cancel_requested` flag (cross-replica, ≤HEARTBEAT_MS lag)
|
|
265
|
-
* status "failed" + errorCode "cancelled" (metric label "cancelled"); the entry is removed in
|
|
263
|
+
* Cancellation (POST /v1/runs/:id/cancel): the run registers its abort handle (S-947 `RunAbort`) in `inflight`
|
|
264
|
+
* (same-replica fast path — the cancel handler aborts it directly) and its heartbeat tick polls the durable
|
|
265
|
+
* `cancel_requested` flag (cross-replica, ≤HEARTBEAT_MS lag); both abort with `cancel_verb`. Either way the run settles
|
|
266
|
+
* to status "failed" + errorCode "cancelled" + `result.abortCause` (metric label "cancelled"); the entry is removed in
|
|
267
|
+
* `finally`.
|
|
266
268
|
*
|
|
267
269
|
* Preemption (POST /v1/assistant/tasks/:id/preempt, [ref] seam #2): a SECOND, INDEPENDENT controller
|
|
268
270
|
* (`preemptCtrl`, registered in `preemptable`) carries the scheduler's graceful "yield this task" — when raised,
|
|
@@ -281,7 +283,7 @@ export declare function evictIfConflict(runner: Runner, sessionId: string | unde
|
|
|
281
283
|
export declare function runInBackground(runner: Runner, spec: TaskSpec, runStore: RunStore, taskId: string, metrics?: Metrics, principal?: string, verify?: VerifyRoundsSpec, // 快审 F1:number 参升整对象——cost 顶随传
|
|
282
284
|
cascade?: CascadeConfig, instrumentDegenerate?: (result: TaskResult) => void, planCacheProbe?: {
|
|
283
285
|
record: (scope: string | undefined, objective: string, completed: boolean) => void;
|
|
284
|
-
}, persistThinking?: boolean, inflight?: Map<string,
|
|
286
|
+
}, persistThinking?: boolean, inflight?: Map<string, RunAbort>, preemptable?: Map<string, AbortController>, steerable?: Map<string, TaskStream>, modelUsage?: ModelUsageTracker, elicitation?: ElicitationCoordinator,
|
|
285
287
|
/** E23: the VERIFIED principal (gatedPrincipal) that may answer this run's elicitations — matches the respond
|
|
286
288
|
* owner-gate's identity source (NOT the cost-attribution `principal`, which on a direct door is the self-asserted
|
|
287
289
|
* header → can be null while a JWT principal exists). Falls back to the run owner when not supplied. */
|
package/dist/runs.js
CHANGED
|
@@ -6,12 +6,13 @@ import { isSessionErrorCode, sessionErrorHttp } from "./session-error-wire.js";
|
|
|
6
6
|
import { redactErrorMessage } from "./observability/run-terminal.js";
|
|
7
7
|
import { withPrincipal } from "./observability/principal-context.js";
|
|
8
8
|
import { withModelReachScope } from "./model-reach-scope.js";
|
|
9
|
+
import { createInstructionSelectionLeg } from "./instruction-selection.js";
|
|
9
10
|
import { redactSecrets } from "./trace/redact.js";
|
|
10
11
|
import { taskNotificationEventData, appendModelUsageDelta, appendPromptManifest, attachModelUsage } from "./trace/project.js";
|
|
11
12
|
import { createLedgerSink } from "./trace/ledger-sink.js";
|
|
12
13
|
import { registerEngineNoticeLeg } from "./trace/engine-notice-wire.js";
|
|
13
14
|
import { recordTurnActivity } from "./turn-activity.js";
|
|
14
|
-
import { CANCELLED_CODE, mintCancelledResult } from "./run-cancel-context.js";
|
|
15
|
+
import { buildCancelledLedgerRow, CANCELLED_CODE, createRunAbort, mintCancelledResult } from "./run-cancel-context.js";
|
|
15
16
|
import { createApprovalCardEmitter, resolveApprovalLeg } from "./tool-approval.js";
|
|
16
17
|
import { fleetRunResiduals, isFleetAgentTerminalNotification } from "./fleet/fleet-bus.js";
|
|
17
18
|
import { defaultSubagentTailBus } from "./fleet/subagent-tail-bus.js";
|
|
@@ -177,14 +178,16 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
177
178
|
const startedAt = Date.now();
|
|
178
179
|
metrics?.addGauge("runs_active", 1);
|
|
179
180
|
fleetPublisher?.onStart();
|
|
180
|
-
const cancelCtrl =
|
|
181
|
+
const cancelCtrl = createRunAbort();
|
|
181
182
|
inflight?.set(taskId, cancelCtrl);
|
|
182
183
|
markChildrenStoppedByUserOnAbort(cancelCtrl.signal, taskId, principal);
|
|
183
184
|
const preemptEligible = verify === undefined && cascade === undefined;
|
|
184
185
|
const preemptCtrl = new AbortController();
|
|
185
186
|
if (preemptEligible)
|
|
186
187
|
preemptable?.set(taskId, preemptCtrl);
|
|
187
|
-
const cancelledResult = (engineResult) =>
|
|
188
|
+
const cancelledResult = (cause, engineResult) => engineResult !== undefined
|
|
189
|
+
? mintCancelledResult({ taskId, sessionId: spec.sessionId ?? "", startedAtMs: startedAt, message: "cancelled by user", cause, engineResult })
|
|
190
|
+
: mintCancelledResult({ taskId, sessionId: spec.sessionId ?? "", startedAtMs: startedAt, message: "cancelled by user", cause });
|
|
188
191
|
const recordDone = (result, status) => {
|
|
189
192
|
metrics?.addGauge("runs_active", -1);
|
|
190
193
|
metrics?.inc("tasks_total", { status });
|
|
@@ -221,7 +224,7 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
221
224
|
void runStore.heartbeat(taskId, owner).catch(() => { metrics?.inc("run_signal_poll_errors_total", { kind: "heartbeat" }); });
|
|
222
225
|
if (!cancelCtrl.signal.aborted) {
|
|
223
226
|
void runStore.isCancelRequested(taskId, owner).then((c) => { if (c)
|
|
224
|
-
cancelCtrl.abort(); }).catch(() => { metrics?.inc("run_signal_poll_errors_total", { kind: "cancel" }); });
|
|
227
|
+
cancelCtrl.abort("cancel_verb"); }).catch(() => { metrics?.inc("run_signal_poll_errors_total", { kind: "cancel" }); });
|
|
225
228
|
}
|
|
226
229
|
if (preemptEligible && !preemptCtrl.signal.aborted) {
|
|
227
230
|
void runStore.isPreemptRequested(taskId, owner).then((p) => { if (p)
|
|
@@ -232,7 +235,7 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
232
235
|
const anchor = new TurnAnchorCapture(captureTurnAnchor, () => metrics?.inc("resume_anchor_capture_failed"), captureUserMessageAnchor);
|
|
233
236
|
let reached;
|
|
234
237
|
let observedDone;
|
|
235
|
-
let
|
|
238
|
+
let causeAtDone;
|
|
236
239
|
let settledAsCancel = false;
|
|
237
240
|
let steerableStreamRef;
|
|
238
241
|
let legLive = true;
|
|
@@ -247,7 +250,8 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
247
250
|
metrics?.addGauge("runs_active", -1);
|
|
248
251
|
metrics?.inc("tasks_total", { status: "needs_review" });
|
|
249
252
|
};
|
|
250
|
-
const
|
|
253
|
+
const instructionLeg = createInstructionSelectionLeg();
|
|
254
|
+
const sink = createLedgerSink({ appendEvent: (seq, type, data) => runStore.appendEvent(taskId, seq, type, data), persistThinking, notifiedKeys, onActivity: (kind, statusData) => recordTurnActivity(taskId, kind, statusData), instructionsSegment: instructionLeg.segment });
|
|
251
255
|
const append = (type, data) => sink.append(type, data);
|
|
252
256
|
const flush = () => sink.flush();
|
|
253
257
|
const flushModelUsage = () => appendModelUsageDelta(append, modelUsage, taskId);
|
|
@@ -362,7 +366,7 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
362
366
|
for await (const ev of stream) {
|
|
363
367
|
if (ev.type === "done") {
|
|
364
368
|
observedDone = ev.result;
|
|
365
|
-
|
|
369
|
+
causeAtDone = cancelCtrl.cause();
|
|
366
370
|
}
|
|
367
371
|
fleetPublisher?.onEvent(ev);
|
|
368
372
|
await flushPromptManifest();
|
|
@@ -400,7 +404,7 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
400
404
|
}
|
|
401
405
|
evictIfConflict(runner, spec.sessionId, ev.result);
|
|
402
406
|
{
|
|
403
|
-
const settled =
|
|
407
|
+
const settled = causeAtDone !== undefined ? cancelledResult(causeAtDone, ev.result) : ev.result;
|
|
404
408
|
settledAsCancel = failureCodeOf(settled.terminal) === CANCELLED_CODE;
|
|
405
409
|
const safe = await withModelUsage(sealResultForExit(settled));
|
|
406
410
|
await sink.appendDone(safe);
|
|
@@ -422,7 +426,7 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
422
426
|
await append("suggestions", { suggestions: suggestions.map((s) => redactSecrets(s)) });
|
|
423
427
|
}
|
|
424
428
|
};
|
|
425
|
-
await withModelReachScope(spec.sessionId, () => withPrincipal(principal, () => {
|
|
429
|
+
await instructionLeg.run(spec.sessionId, () => withModelReachScope(spec.sessionId, () => withPrincipal(principal, () => {
|
|
426
430
|
const withElicit = elicitation
|
|
427
431
|
? () => elicitation.runWithContext({ taskId, owner: elicitOwner ?? owner, emit: elicitEmit, abortSignal: cancelCtrl.signal }, runBody)
|
|
428
432
|
: runBody;
|
|
@@ -445,18 +449,19 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
445
449
|
return sendUserFile
|
|
446
450
|
? sendUserFile.runWithContext({ taskId, emit: (frame) => { const { type, ...rest } = frame; return append(type, rest); } }, withApproval)
|
|
447
451
|
: withApproval();
|
|
448
|
-
}));
|
|
449
|
-
|
|
452
|
+
})));
|
|
453
|
+
const cleanCancelCause = cancelCtrl.cause();
|
|
454
|
+
if (!reached && cleanCancelCause !== undefined) {
|
|
450
455
|
try {
|
|
451
456
|
await flush();
|
|
452
457
|
}
|
|
453
458
|
catch (e) {
|
|
454
459
|
recordFailOpen("server.runs.terminal-ledger-write-failed", `arm=flush-clean-cancel ${errText(e)}`);
|
|
455
460
|
}
|
|
456
|
-
const c = cancelledResult();
|
|
461
|
+
const c = cancelledResult(cleanCancelCause);
|
|
457
462
|
settledAsCancel = failureCodeOf(c.terminal) === CANCELLED_CODE;
|
|
458
463
|
try {
|
|
459
|
-
await append("failed",
|
|
464
|
+
await append("failed", buildCancelledLedgerRow(c));
|
|
460
465
|
}
|
|
461
466
|
catch (e) {
|
|
462
467
|
recordFailOpen("server.runs.terminal-ledger-write-failed", `arm=append-clean-cancel ${errText(e)}`);
|
|
@@ -467,6 +472,7 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
467
472
|
}
|
|
468
473
|
}
|
|
469
474
|
catch (err) {
|
|
475
|
+
const thrownCancelCause = cancelCtrl.cause();
|
|
470
476
|
const message = errText(err);
|
|
471
477
|
try {
|
|
472
478
|
try {
|
|
@@ -486,11 +492,11 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
486
492
|
else if (reached?.kind === "needs_review") {
|
|
487
493
|
await runStore.setNeedsReview(taskId, reached.result);
|
|
488
494
|
}
|
|
489
|
-
else if (
|
|
490
|
-
const c = cancelledResult();
|
|
495
|
+
else if (thrownCancelCause !== undefined && observedDone === undefined) {
|
|
496
|
+
const c = cancelledResult(thrownCancelCause);
|
|
491
497
|
settledAsCancel = failureCodeOf(c.terminal) === CANCELLED_CODE;
|
|
492
498
|
try {
|
|
493
|
-
await append("failed",
|
|
499
|
+
await append("failed", buildCancelledLedgerRow(c));
|
|
494
500
|
}
|
|
495
501
|
catch (e) {
|
|
496
502
|
recordFailOpen("server.runs.terminal-ledger-write-failed", `arm=append-thrown-cancel ${errText(e)}`);
|
|
@@ -2,6 +2,7 @@ import { type TerminalCause } from "@sema-agent/core";
|
|
|
2
2
|
import { brainStatusEventData } from "./project.js";
|
|
3
3
|
import { NotifiedKeys } from "../orchestration/workflow-completion-inbox.js";
|
|
4
4
|
import { type LedgerEventType, type ParkLedgerEventType } from "./ledger-events.js";
|
|
5
|
+
import type { InstructionsSegment } from "../instruction-selection.js";
|
|
5
6
|
/**
|
|
6
7
|
* LedgerSink — the SINGLE "stream event → durable runs-ledger" projection, shared by the background leg
|
|
7
8
|
* (runs.ts `runInBackground`) and the sync `/v1/tasks/stream` detach lane (server.ts, `x-detach-on-disconnect`).
|
|
@@ -115,5 +116,8 @@ export declare function createLedgerSink(opts: {
|
|
|
115
116
|
* 各传自己看得见的那个词(位①=流事件 `ev.type`,位②=账本行 `type`);拿不到类型的打点方
|
|
116
117
|
* (core 的 onActivity 第五席、resume 腿手动打点)省参,`kind` 诚实缺席(见 turn-activity.ts)。 */
|
|
117
118
|
onActivity?: (kind?: string, statusData?: Record<string, unknown>) => void;
|
|
119
|
+
/** S-961:这条腿的 `wiring_manifest.instructions` 段(腿的 `InstructionSelectionLeg.segment`)。**必填**:账本行与 live 帧是
|
|
120
|
+
* 同一条腿的两个载体,段必须来自同一只腿;在投帧那一刻读(core 推帧之前已 await 过 loader)。返回 `undefined` ⇒ 段缺席。 */
|
|
121
|
+
instructionsSegment: () => InstructionsSegment | undefined;
|
|
118
122
|
}): LedgerSink;
|
|
119
123
|
//# sourceMappingURL=ledger-sink.d.ts.map
|
|
@@ -97,7 +97,7 @@ export function createLedgerSink(opts) {
|
|
|
97
97
|
await append("workspace_changed", workspaceChangedEventData(ev));
|
|
98
98
|
break;
|
|
99
99
|
case "wiring_manifest":
|
|
100
|
-
await append("wiring_manifest", wiringManifestEventData(ev));
|
|
100
|
+
await append("wiring_manifest", wiringManifestEventData(ev, opts.instructionsSegment()));
|
|
101
101
|
break;
|
|
102
102
|
case "tool_roster_delta": {
|
|
103
103
|
const rosterDelta = toolRosterDeltaEventData(ev);
|
package/dist/trace/project.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ import type { RunEvent, RunRecord } from "../plugins/store-contracts.js";
|
|
|
28
28
|
import type { ModelUsageDelta, ModelUsageTracker, PromptManifestRecord } from "../budget.js";
|
|
29
29
|
import { type SemaProvenanceInput } from "./sema-provenance.js";
|
|
30
30
|
import type { LedgerEventType } from "./ledger-events.js";
|
|
31
|
+
import type { InstructionsSegment } from "../instruction-selection.js";
|
|
31
32
|
/** 账本写口的统一签名 —— `type` 是**闭集**(`ledger-events.ts`):新型必须先登记,否则调用点编译红
|
|
32
33
|
* (codex 交叉复审 F2:别名门 `ap("x")` 与动态首参让纯词法门结构性抓不全)。 */
|
|
33
34
|
type AppendFn = (type: LedgerEventType, data: unknown) => Promise<void>;
|
|
@@ -719,11 +720,18 @@ export declare function toolRosterDeltaEventData(ev: {
|
|
|
719
720
|
eventId?: unknown;
|
|
720
721
|
parentToolCallId?: unknown;
|
|
721
722
|
}): Record<string, unknown> | undefined;
|
|
723
|
+
/**
|
|
724
|
+
* 🔴 S-961(7.111.0)**第二参 `instructions` 必传**(值可以是 `undefined`):`wiring_manifest` 上唯一一段**本仓自铸**的段
|
|
725
|
+
* —— 这条腿的 project-memory loader 选中的指令文件链成员,`{ selected: string[] }`。它不在 core 的 manifest 里(core 不持有
|
|
726
|
+
* 选择规则),所以不从 `ev` 读:每条投帧的腿把**自己那只** `InstructionSelectionLeg.segment()` 递进来。必传而不是可选 ——
|
|
727
|
+
* 漏递的腿当场 tsc 红,而不是静默投出一个「缺席」(缺席在 wire 上是一句话:「这条腿没有关于指令文件的陈述」)。
|
|
728
|
+
* `undefined` ⇒ 段缺席;`{ selected: [] }` ⇒ 显式空(走了链、没选中)。登记:`wire-projection-faces.ts` 租户行 `minted`。
|
|
729
|
+
*/
|
|
722
730
|
export declare function wiringManifestEventData(ev: {
|
|
723
731
|
manifest?: unknown;
|
|
724
732
|
eventId?: unknown;
|
|
725
733
|
parentToolCallId?: unknown;
|
|
726
|
-
}): Record<string, unknown>;
|
|
734
|
+
}, instructions: InstructionsSegment | undefined): Record<string, unknown>;
|
|
727
735
|
/**
|
|
728
736
|
* `wiring_manifest` 的 **operator 投影**([ref] 件一)—— {@link wiringManifestEventData} 的租户形加上
|
|
729
737
|
* `governance` 段与 core 的真 `configFingerprint`。
|
|
@@ -759,7 +767,7 @@ export declare function wiringManifestOperatorEventData(ev: {
|
|
|
759
767
|
manifest?: unknown;
|
|
760
768
|
eventId?: unknown;
|
|
761
769
|
parentToolCallId?: unknown;
|
|
762
|
-
}): Record<string, unknown>;
|
|
770
|
+
}, instructions: InstructionsSegment | undefined): Record<string, unknown>;
|
|
763
771
|
/**
|
|
764
772
|
* `wiring_manifest` 的**唯一分叉点**(S-528)—— 两条知道调用方身份的 live 消费腿共用它:
|
|
765
773
|
* `/v1/tasks/stream` 的 SSE 帧,与 `POST /v1/tasks`(非流式)200 体里的 `wiringManifest` 起手回执。
|
|
@@ -780,7 +788,7 @@ export declare function wiringManifestFaceEventData(ev: {
|
|
|
780
788
|
manifest?: unknown;
|
|
781
789
|
eventId?: unknown;
|
|
782
790
|
parentToolCallId?: unknown;
|
|
783
|
-
}, operatorFace: boolean): Record<string, unknown>;
|
|
791
|
+
}, operatorFace: boolean, instructions: InstructionsSegment | undefined): Record<string, unknown>;
|
|
784
792
|
/**
|
|
785
793
|
* `human_input`(core 5.14.0 [ref] 新 `TaskEvent` 臂)—— 「谁把什么喂进了这条 run」的生命周期账本
|
|
786
794
|
* 帧(objective / 实时 steer / nextTurn / parked-steer 续跑 / wake 五个载体共用一个投影点)。
|
package/dist/trace/project.js
CHANGED
|
@@ -464,7 +464,7 @@ export function toolRosterDeltaEventData(ev) {
|
|
|
464
464
|
}
|
|
465
465
|
return { delta: ev.delta, ...identityFields(ev) };
|
|
466
466
|
}
|
|
467
|
-
export function wiringManifestEventData(ev) {
|
|
467
|
+
export function wiringManifestEventData(ev, instructions) {
|
|
468
468
|
const str = (v) => (typeof v === "string" && v.length > 0 ? v : undefined);
|
|
469
469
|
const bool = (v) => (typeof v === "boolean" ? v : undefined);
|
|
470
470
|
const num = (v) => (typeof v === "number" && Number.isFinite(v) ? v : undefined);
|
|
@@ -630,11 +630,12 @@ export function wiringManifestEventData(ev) {
|
|
|
630
630
|
...(lsp !== undefined ? { lsp } : {}),
|
|
631
631
|
...(hands !== undefined ? { hands } : {}),
|
|
632
632
|
...(writeProtection !== undefined ? { writeProtection } : {}),
|
|
633
|
+
...(instructions !== undefined ? { instructions: { selected: [...instructions.selected] } } : {}),
|
|
633
634
|
...identityFields(ev),
|
|
634
635
|
};
|
|
635
636
|
}
|
|
636
|
-
export function wiringManifestOperatorEventData(ev) {
|
|
637
|
-
const tenant = wiringManifestEventData(ev);
|
|
637
|
+
export function wiringManifestOperatorEventData(ev, instructions) {
|
|
638
|
+
const tenant = wiringManifestEventData(ev, instructions);
|
|
638
639
|
const str = (v) => (typeof v === "string" && v.length > 0 ? v : undefined);
|
|
639
640
|
const bool = (v) => (typeof v === "boolean" ? v : undefined);
|
|
640
641
|
const sec = (v) => (typeof v === "object" && v !== null && !Array.isArray(v) ? { ...v } : undefined);
|
|
@@ -678,8 +679,8 @@ export function wiringManifestOperatorEventData(ev) {
|
|
|
678
679
|
...(str(m.configFingerprint) !== undefined ? { configFingerprint: m.configFingerprint } : {}),
|
|
679
680
|
};
|
|
680
681
|
}
|
|
681
|
-
export function wiringManifestFaceEventData(ev, operatorFace) {
|
|
682
|
-
return operatorFace ? wiringManifestOperatorEventData(ev) : wiringManifestEventData(ev);
|
|
682
|
+
export function wiringManifestFaceEventData(ev, operatorFace, instructions) {
|
|
683
|
+
return operatorFace ? wiringManifestOperatorEventData(ev, instructions) : wiringManifestEventData(ev, instructions);
|
|
683
684
|
}
|
|
684
685
|
export function humanInputEventData(ev) {
|
|
685
686
|
const str = (v) => (typeof v === "string" && v.length > 0 ? v : undefined);
|
|
@@ -32,6 +32,54 @@ export declare const SELF_MINTED_WIRE: {
|
|
|
32
32
|
};
|
|
33
33
|
};
|
|
34
34
|
};
|
|
35
|
+
/**
|
|
36
|
+
* S-961(7.111.0):`wiring_manifest.instructions.selected[]` 的成员值 = 指令文件链的成员(相对 cwd 的拼写)。属主是 `project-memory.ts`
|
|
37
|
+
* 的 `INSTRUCTION_FILE_CHAIN`([ref] 序:CLAUDE 族先、AGENTS 族后,首中即选)—— 链加 / 删一员 ⇒ 本行 `satisfies` 编译红,登记跟着动。
|
|
38
|
+
* 段本身(键)登记在 `wire-projection-faces.ts` 的 `wiring_manifest_tenant.minted`。
|
|
39
|
+
*/
|
|
40
|
+
readonly wiringInstructionsSelected: {
|
|
41
|
+
readonly at: "wiring_manifest instructions.selected[](本腿 loader 选中的链成员;段缺席 = 本腿无陈述)";
|
|
42
|
+
readonly members: {
|
|
43
|
+
"CLAUDE.md": {
|
|
44
|
+
attr: string;
|
|
45
|
+
since: string;
|
|
46
|
+
};
|
|
47
|
+
".claude/CLAUDE.md": {
|
|
48
|
+
attr: string;
|
|
49
|
+
since: string;
|
|
50
|
+
};
|
|
51
|
+
"AGENTS.md": {
|
|
52
|
+
attr: string;
|
|
53
|
+
since: string;
|
|
54
|
+
};
|
|
55
|
+
".claude/AGENTS.md": {
|
|
56
|
+
attr: string;
|
|
57
|
+
since: string;
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* S-947(7.112.0):server 发起的中止在取消终局上留下的机读成因 —— `PersistedTaskResult.abortCause`,与 `cancelContext` 同住、同铸点、
|
|
63
|
+
* 同在场闸(在场 ⇔ 这条终局就是 server 那次中止铸出来的取消终局)。逐词站点见契约 §5.0d。键本身是 run 结果上的 server 侧记键
|
|
64
|
+
* (`store-contracts.ts` 的 `PersistedResultSideKeys`),不是事件投影面的键 ⇒ 不在 `wire-projection-faces.ts`。
|
|
65
|
+
*/
|
|
66
|
+
readonly abortCause: {
|
|
67
|
+
readonly at: "run 结果 result.abortCause(GET /v1/runs/:id → result · done.result · POST /v1/tasks 200 体顶层 · 账本 done 行 result / 无 done 的取消形账本 failed 行顶层)";
|
|
68
|
+
readonly members: {
|
|
69
|
+
client_disconnected: {
|
|
70
|
+
attr: string;
|
|
71
|
+
since: string;
|
|
72
|
+
};
|
|
73
|
+
ask_park_grace_exhausted: {
|
|
74
|
+
attr: string;
|
|
75
|
+
since: string;
|
|
76
|
+
};
|
|
77
|
+
cancel_verb: {
|
|
78
|
+
attr: string;
|
|
79
|
+
since: string;
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
};
|
|
35
83
|
/**
|
|
36
84
|
* 会话所有者自助抹除面的**已分类拒** → HTTP 状态(S-930 起与 operator 面 `POST /v1/memory/erase` 同一只映射;`since` 记的是**本面**
|
|
37
85
|
* 自哪一版起这样答 —— 7.107.0 及以前本面只认前两只,其余落 500 `internal.error`)。
|