@sema-agent/server 7.137.0 → 7.138.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 +328 -139
- package/README.md +1 -0
- package/README.zh-CN.md +1 -0
- package/USAGE.md +67 -20
- package/dist/approval-card.d.ts +21 -14
- package/dist/approval-card.js +1 -0
- package/dist/audit.js +1 -0
- package/dist/background-agent-name.d.ts +5 -0
- package/dist/background-agent-name.js +5 -0
- package/dist/boot/budget-tracing.d.ts +1 -12
- package/dist/boot/deployment-mods.d.ts +46 -16
- package/dist/boot/deployment-mods.js +82 -6
- package/dist/boot/governance-seams.d.ts +10 -17
- package/dist/boot/governance-seams.js +5 -17
- package/dist/boot/leader.d.ts +3 -0
- package/dist/boot/leader.js +1 -0
- package/dist/boot/org-delivery.js +15 -2
- package/dist/boot/resolve-spec.d.ts +3 -0
- package/dist/boot/resolve-spec.js +23 -12
- package/dist/boot/retention-lane.d.ts +11 -5
- package/dist/boot/retention-lane.js +2 -2
- package/dist/boot/runner-deps.d.ts +7 -3
- package/dist/boot/runner-deps.js +1 -0
- package/dist/boot/stage-04-stores.d.ts +1 -12
- package/dist/boot/stage-05-execution-env.d.ts +3 -12
- package/dist/boot/stage-05-execution-env.js +7 -4
- package/dist/boot/stage-06-runners.d.ts +3 -12
- package/dist/boot/stage-06-runners.js +5 -2
- package/dist/boot/stage-07-capability-layer.d.ts +3 -12
- package/dist/boot/stage-07-capability-layer.js +2 -2
- package/dist/boot/stage-08-reapers.d.ts +3 -12
- package/dist/boot/stage-09-leader.d.ts +3 -12
- package/dist/boot/stage-09-leader.js +2 -2
- package/dist/boot/stage-10-http-server.d.ts +3 -12
- package/dist/boot/stage-10-http-server.js +4 -2
- package/dist/boot/web-admin.d.ts +5 -2
- package/dist/boot/web-admin.js +3 -3
- package/dist/brain.js +5 -5
- package/dist/budget.d.ts +17 -15
- package/dist/budget.js +2 -2
- package/dist/capabilities/mcp-probe.d.ts +36 -11
- package/dist/capabilities/mcp-probe.js +44 -5
- package/dist/capability-facts.d.ts +6 -0
- package/dist/capability-facts.js +5 -0
- package/dist/checkpoint-identity.d.ts +13 -6
- package/dist/config-catalog.js +7 -1
- package/dist/config-types.d.ts +15 -7
- package/dist/config.js +8 -5
- package/dist/deployment-shape.d.ts +6 -6
- package/dist/gate-settlement.d.ts +71 -0
- package/dist/gate-settlement.js +40 -0
- package/dist/hooks/classic-stations.d.ts +1 -0
- package/dist/hooks/classic-stations.js +1 -0
- package/dist/hooks/command-spawn.d.ts +2 -2
- package/dist/hooks/hook-runner.js +14 -14
- package/dist/http/admission.js +4 -2
- package/dist/http/dispatch.d.ts +4 -0
- package/dist/http/dispatch.js +3 -0
- package/dist/http/durable-run-leg.js +4 -2
- package/dist/http/memory-compliance-failure-reply.js +3 -0
- package/dist/http/resume-legs.d.ts +5 -11
- package/dist/http/resume-legs.js +136 -91
- package/dist/http/route-ctx.d.ts +30 -51
- package/dist/http/route-ctx.js +2 -5
- package/dist/http/routes/a2a-serve.js +10 -4
- package/dist/http/routes/agents-roster.d.ts +1 -1
- package/dist/http/routes/agents-roster.js +5 -1
- package/dist/http/routes/approvals-assistant.js +6 -6
- package/dist/http/routes/capabilities.js +12 -10
- package/dist/http/routes/mcp-reconnect.d.ts +3 -2
- package/dist/http/routes/mcp-reconnect.js +7 -5
- package/dist/http/routes/memory-consolidation.d.ts +1 -1
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/rules.js +3 -3
- package/dist/http/routes/runs.js +11 -7
- package/dist/http/routes/sessions.js +6 -4
- package/dist/http/routes/side-query.js +2 -3
- package/dist/http/routes/tasks.js +792 -780
- package/dist/http/server.d.ts +31 -25
- package/dist/http/wire-types.d.ts +14 -6
- package/dist/identity-source.d.ts +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/leader/wire.d.ts +7 -0
- package/dist/leader/wire.js +5 -4
- package/dist/mcp-assertion-header.d.ts +51 -40
- package/dist/mcp-assertion-header.js +10 -11
- package/dist/mcp-authorization-face.d.ts +27 -0
- package/dist/mcp-authorization-face.js +15 -0
- package/dist/memory-operator-faces.d.ts +13 -4
- package/dist/memory-operator-faces.js +1 -17
- package/dist/memory-sync-client.js +72 -57
- package/dist/memory-sync.d.ts +1 -1
- package/dist/model-route-gap.d.ts +6 -22
- package/dist/model-route-gap.js +7 -5
- package/dist/mods-declaration.d.ts +110 -0
- package/dist/mods-declaration.js +109 -0
- package/dist/observability/err-text.d.ts +5 -0
- package/dist/observability/err-text.js +9 -0
- package/dist/observability/fail-open.d.ts +5 -1
- package/dist/observability/fail-open.js +5 -1
- package/dist/observability/secret-env-scrub.d.ts +1 -1
- package/dist/observability/secret-env-scrub.js +1 -1
- package/dist/parked-decide.d.ts +15 -2
- package/dist/parked-decide.js +14 -8
- package/dist/peer-seat.d.ts +150 -0
- package/dist/peer-seat.js +239 -0
- package/dist/permission-rule-vocab.d.ts +7 -7
- package/dist/permission-rule-vocab.js +3 -3
- package/dist/plain-string-record.d.ts +38 -0
- package/dist/plain-string-record.js +38 -0
- package/dist/plugins/background-agent-store-sql.js +6 -3
- package/dist/plugins/caching-session-store.d.ts +5 -0
- package/dist/plugins/caching-session-store.js +6 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +15 -20
- package/dist/plugins/checkpoint-store-sql.js +8 -8
- package/dist/plugins/file-history-store-sql.js +3 -2
- package/dist/plugins/k8s-pod-reaper.d.ts +2 -8
- package/dist/plugins/k8s-pod-reaper.js +3 -3
- package/dist/plugins/local-checkpoint-store.d.ts +1 -11
- package/dist/plugins/local-checkpoint-store.js +0 -1
- package/dist/plugins/local-session-store.d.ts +66 -27
- package/dist/plugins/local-session-store.js +60 -28
- package/dist/plugins/mailbox-store-sql.d.ts +11 -3
- package/dist/plugins/mailbox-store-sql.js +103 -15
- package/dist/plugins/memory-sync-store-pg.d.ts +16 -5
- package/dist/plugins/memory-sync-store-tidb.d.ts +3 -3
- package/dist/plugins/one-time-migrations.d.ts +6 -3
- package/dist/plugins/one-time-migrations.js +3 -4
- package/dist/plugins/permission-rule-store-sql.js +21 -13
- package/dist/plugins/pg-session-storage.d.ts +10 -2
- package/dist/plugins/pg-session-storage.js +18 -5
- package/dist/plugins/remote-env-adb.d.ts +3 -1
- package/dist/plugins/remote-env-adb.js +1 -1
- package/dist/plugins/remote-env-device.d.ts +3 -1
- package/dist/plugins/remote-env-device.js +1 -1
- package/dist/plugins/remote-env-e2b.d.ts +2 -0
- package/dist/plugins/remote-env-e2b.js +1 -1
- package/dist/plugins/remote-env-host.d.ts +3 -1
- package/dist/plugins/remote-env-host.js +1 -1
- package/dist/plugins/remote-env-k8s.d.ts +3 -1
- package/dist/plugins/remote-env-k8s.js +1 -1
- package/dist/plugins/remote-env-local-docker.d.ts +2 -0
- package/dist/plugins/remote-env-local-docker.js +1 -1
- package/dist/plugins/remote-env-ssh.d.ts +3 -1
- package/dist/plugins/remote-env-ssh.js +1 -1
- package/dist/plugins/retention-store-sql.d.ts +14 -2
- package/dist/plugins/retention-store-sql.js +6 -0
- package/dist/plugins/session-fork.d.ts +10 -13
- package/dist/plugins/session-fork.js +5 -25
- package/dist/plugins/session-ownership.d.ts +7 -0
- package/dist/plugins/session-ownership.js +5 -0
- package/dist/plugins/session-workspace-cell.d.ts +17 -0
- package/dist/plugins/session-workspace-cell.js +38 -0
- package/dist/plugins/store-backend.js +7 -7
- package/dist/plugins/tidb-pool.js +6 -0
- package/dist/plugins/tidb-session-store.d.ts +17 -2
- package/dist/plugins/tidb-session-store.js +16 -5
- package/dist/plugins/tool-result-store-sql.d.ts +13 -6
- package/dist/plugins/tool-result-store-sql.js +8 -7
- package/dist/plugins/worktree-isolation.d.ts +3 -2
- package/dist/plugins/worktree-isolation.js +1 -7
- package/dist/project-identity.d.ts +1 -14
- package/dist/project-identity.js +0 -4
- package/dist/rules-consent.js +6 -4
- package/dist/run-local.js +12 -6
- package/dist/runs.d.ts +7 -1
- package/dist/runs.js +6 -1
- package/dist/sandbox-git-plane.d.ts +2 -2
- package/dist/server-secret-env.d.ts +6 -3
- package/dist/server-secret-env.js +4 -2
- package/dist/session-incarnation.d.ts +4 -5
- package/dist/session-incarnation.js +2 -2
- package/dist/session-workspace.d.ts +130 -0
- package/dist/session-workspace.js +83 -0
- package/dist/spec-fields.d.ts +1 -1
- package/dist/standing-answer-grant.d.ts +2 -13
- package/dist/standing-answer-grant.js +0 -7
- package/dist/task-a2a.d.ts +44 -14
- package/dist/task-a2a.js +46 -20
- package/dist/task-mcp.d.ts +33 -20
- package/dist/task-mcp.js +46 -22
- package/dist/tool-approval.d.ts +32 -8
- package/dist/tool-approval.js +49 -12
- package/dist/trace/core-keyset-guard.d.ts +33 -18
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +2 -0
- package/dist/trace/exit-seat.d.ts +20 -1
- package/dist/trace/exit-seat.js +3 -0
- package/dist/trace/extension-call-face.d.ts +33 -0
- package/dist/trace/extension-call-face.js +39 -0
- package/dist/trace/project.d.ts +25 -7
- package/dist/trace/project.js +29 -3
- package/dist/trace/redact.js +42 -13
- package/dist/trace/self-minted-wire.d.ts +129 -10
- package/dist/trace/self-minted-wire.js +62 -3
- package/dist/trace/wire-projection-faces.d.ts +6 -6
- package/dist/trace/wire-projection-faces.js +6 -5
- package/dist/user-authored-text.d.ts +2 -2
- package/dist/user-authored-text.js +16 -1
- package/dist/web-admin-client/center-request.d.ts +3 -2
- package/dist/web-admin-client/center-request.js +2 -3
- package/dist/web-admin-client/skills-mcp.d.ts +8 -4
- package/dist/web-admin-client/skills-mcp.js +31 -18
- package/dist/web-admin-client/types.d.ts +5 -0
- package/package.json +3 -3
- package/wire-changes/server@7.138.0.json +446 -0
- package/dist/http/mcp-remote-text.d.ts +0 -5
- package/dist/http/mcp-remote-text.js +0 -7
|
@@ -46,7 +46,7 @@ export class RemoteContainerExecutionEnv {
|
|
|
46
46
|
this.homeDir = config.homeDir;
|
|
47
47
|
this.sandboxApi = deps.sandboxApi ?? Sandbox;
|
|
48
48
|
}
|
|
49
|
-
capabilities = { isolation: true, suspendable: true, canonicalPathAuthoritative: true };
|
|
49
|
+
capabilities = { isolation: true, suspendable: true, canonicalPathAuthoritative: true, sharesProcessTable: false };
|
|
50
50
|
workspaceHandle() {
|
|
51
51
|
if (!this.handle) {
|
|
52
52
|
throw new RemoteExecutionError("connect_failed", "workspaceHandle() called before connect()");
|
|
@@ -71,14 +71,16 @@ export declare class RemoteHostExecutionEnv implements RemoteExecutionEnv, Sched
|
|
|
71
71
|
* (RPC 断、传输掉),不是「一个它看不见的命名空间」⇒ 读边界的执行期复核**拒**,而不是让词法判决站着。
|
|
72
72
|
* 缺席是今天每个适配器的读法(整链沉默 ⇒ 词法判决成立、命令照跑),所以这一声明是**收紧**方向。
|
|
73
73
|
* 严格读法 `=== true`(core `canonicalPathIsAuthoritative`);`isSuspendable` 一族同样严格,对本仓的
|
|
74
|
-
* 布尔字面量零影响(
|
|
74
|
+
* 布尔字面量零影响(四键都写死字面 `true`/`false`,不存在「非布尔值被读成缺席」那一形 —— 那一形由
|
|
75
75
|
* core 的 `config.execution_env_capability_invalid` 普查响亮播报,本仓的受众表已登记)。
|
|
76
76
|
* 谁该声明由闭集门看着(`test/execution-lane-caps.test.ts` 的逐 lane 对账:新 lane 不表态 = 编译红)。
|
|
77
77
|
*/
|
|
78
|
+
/** `sharesProcessTable`(core 7.57.0,必填):命令是本进程 spawn 的子进程(同一张进程表),引擎的模式杀守卫对它照 NodeExecutionEnv 一样问 `pgrep`。 */
|
|
78
79
|
readonly capabilities: {
|
|
79
80
|
isolation: boolean;
|
|
80
81
|
suspendable: boolean;
|
|
81
82
|
canonicalPathAuthoritative: boolean;
|
|
83
|
+
sharesProcessTable: boolean;
|
|
82
84
|
};
|
|
83
85
|
/** R7 自唤醒: structural delegation to the injected scheduler backend. `hasScheduler(env)` checks BOTH the method
|
|
84
86
|
* presence (always, since we implement the interface) AND `schedulerCapabilities.supported===true` — which is only
|
|
@@ -37,7 +37,7 @@ const UNSUPPORTED_SCHEDULER_CAPS = {
|
|
|
37
37
|
maxScheduledHorizonSec: 0,
|
|
38
38
|
};
|
|
39
39
|
export class RemoteHostExecutionEnv {
|
|
40
|
-
capabilities = { isolation: false, suspendable: false, canonicalPathAuthoritative: true };
|
|
40
|
+
capabilities = { isolation: false, suspendable: false, canonicalPathAuthoritative: true, sharesProcessTable: true };
|
|
41
41
|
get schedulerCapabilities() {
|
|
42
42
|
return this.cfg.scheduler?.schedulerCapabilities ?? UNSUPPORTED_SCHEDULER_CAPS;
|
|
43
43
|
}
|
|
@@ -296,14 +296,16 @@ export declare class RemoteK8sExecutionEnv implements RemoteExecutionEnv, Backgr
|
|
|
296
296
|
* (RPC 断、传输掉),不是「一个它看不见的命名空间」⇒ 读边界的执行期复核**拒**,而不是让词法判决站着。
|
|
297
297
|
* 缺席是今天每个适配器的读法(整链沉默 ⇒ 词法判决成立、命令照跑),所以这一声明是**收紧**方向。
|
|
298
298
|
* 严格读法 `=== true`(core `canonicalPathIsAuthoritative`);`isSuspendable` 一族同样严格,对本仓的
|
|
299
|
-
* 布尔字面量零影响(
|
|
299
|
+
* 布尔字面量零影响(四键都写死字面 `true`/`false`,不存在「非布尔值被读成缺席」那一形 —— 那一形由
|
|
300
300
|
* core 的 `config.execution_env_capability_invalid` 普查响亮播报,本仓的受众表已登记)。
|
|
301
301
|
* 谁该声明由闭集门看着(`test/execution-lane-caps.test.ts` 的逐 lane 对账:新 lane 不表态 = 编译红)。
|
|
302
302
|
*/
|
|
303
|
+
/** `sharesProcessTable`(core 7.57.0,必填):命令跑在沙箱 pod 自己的 PID 命名空间里(不开 hostPID),不在本进程所在的进程表。 */
|
|
303
304
|
readonly capabilities: {
|
|
304
305
|
isolation: boolean;
|
|
305
306
|
suspendable: boolean;
|
|
306
307
|
canonicalPathAuthoritative: true;
|
|
308
|
+
sharesProcessTable: false;
|
|
307
309
|
};
|
|
308
310
|
cwd: string;
|
|
309
311
|
private podName?;
|
|
@@ -268,7 +268,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
268
268
|
this.logger = config.logger;
|
|
269
269
|
this.onWorkspaceSnapshot = config.onWorkspaceSnapshot;
|
|
270
270
|
this.cacheMisses = config.cacheMisses;
|
|
271
|
-
this.capabilities = { isolation: true, suspendable: !!this.cfg.s3Snapshot, canonicalPathAuthoritative: true };
|
|
271
|
+
this.capabilities = { isolation: true, suspendable: !!this.cfg.s3Snapshot, canonicalPathAuthoritative: true, sharesProcessTable: false };
|
|
272
272
|
const bgMax = Math.max(1, Math.min(K8S_BG_MAX_TIMEOUT_SEC, Math.floor(this.cfg.timeoutMs / 1000)));
|
|
273
273
|
this.backgroundCapabilities = {
|
|
274
274
|
supported: true,
|
|
@@ -62,10 +62,12 @@ export interface LocalDockerEnvDeps {
|
|
|
62
62
|
}
|
|
63
63
|
export declare class RemoteLocalDockerExecutionEnv implements RemoteExecutionEnv {
|
|
64
64
|
/** DUAL-MODE-DESIGN §5: a container is a real isolation boundary; v1 has no managed memory snapshot. */
|
|
65
|
+
/** `sharesProcessTable`(core 7.57.0,必填):命令跑在本机容器自己的 PID 命名空间里(不传 `--pid=host`),不在本进程所在的进程表。 */
|
|
65
66
|
readonly capabilities: {
|
|
66
67
|
isolation: boolean;
|
|
67
68
|
suspendable: boolean;
|
|
68
69
|
canonicalPathAuthoritative: boolean;
|
|
70
|
+
sharesProcessTable: boolean;
|
|
69
71
|
};
|
|
70
72
|
/** Working directory inside the container; relative paths resolve against it (ExecutionEnv contract). */
|
|
71
73
|
cwd: string;
|
|
@@ -21,7 +21,7 @@ const unsupported = (op) => ({
|
|
|
21
21
|
error: new RemoteExecutionError("unsupported", `${op} is not supported on a local-docker target (v1: a container is an isolation boundary but not a managed memory snapshot; capabilities.suspendable=false)`),
|
|
22
22
|
});
|
|
23
23
|
export class RemoteLocalDockerExecutionEnv {
|
|
24
|
-
capabilities = { isolation: true, suspendable: false, canonicalPathAuthoritative: true };
|
|
24
|
+
capabilities = { isolation: true, suspendable: false, canonicalPathAuthoritative: true, sharesProcessTable: false };
|
|
25
25
|
cwd;
|
|
26
26
|
get homeDir() {
|
|
27
27
|
return this.homeSeat.home;
|
|
@@ -59,14 +59,16 @@ export declare class RemoteSshExecutionEnv implements RemoteExecutionEnv {
|
|
|
59
59
|
* (RPC 断、传输掉),不是「一个它看不见的命名空间」⇒ 读边界的执行期复核**拒**,而不是让词法判决站着。
|
|
60
60
|
* 缺席是今天每个适配器的读法(整链沉默 ⇒ 词法判决成立、命令照跑),所以这一声明是**收紧**方向。
|
|
61
61
|
* 严格读法 `=== true`(core `canonicalPathIsAuthoritative`);`isSuspendable` 一族同样严格,对本仓的
|
|
62
|
-
* 布尔字面量零影响(
|
|
62
|
+
* 布尔字面量零影响(四键都写死字面 `true`/`false`,不存在「非布尔值被读成缺席」那一形 —— 那一形由
|
|
63
63
|
* core 的 `config.execution_env_capability_invalid` 普查响亮播报,本仓的受众表已登记)。
|
|
64
64
|
* 谁该声明由闭集门看着(`test/execution-lane-caps.test.ts` 的逐 lane 对账:新 lane 不表态 = 编译红)。
|
|
65
65
|
*/
|
|
66
|
+
/** `sharesProcessTable`(core 7.57.0,必填):命令跑在 SSH 目标机上;目标恰是本机(或本进程所在容器的宿主)时命令与本进程同表,这一形今天没有配置面可声明 `true`。 */
|
|
66
67
|
readonly capabilities: {
|
|
67
68
|
isolation: boolean;
|
|
68
69
|
suspendable: boolean;
|
|
69
70
|
canonicalPathAuthoritative: boolean;
|
|
71
|
+
sharesProcessTable: boolean;
|
|
70
72
|
};
|
|
71
73
|
/** Working directory; relative paths resolve against it (ExecutionEnv contract). Starts at mountPath. */
|
|
72
74
|
cwd: string;
|
|
@@ -18,7 +18,7 @@ function exitCodeForSignalKill(signal) {
|
|
|
18
18
|
return 128 + (signalNumber(`SIG${signal}`) ?? 9);
|
|
19
19
|
}
|
|
20
20
|
export class RemoteSshExecutionEnv {
|
|
21
|
-
capabilities = { isolation: false, suspendable: false, canonicalPathAuthoritative: true };
|
|
21
|
+
capabilities = { isolation: false, suspendable: false, canonicalPathAuthoritative: true, sharesProcessTable: false };
|
|
22
22
|
cwd;
|
|
23
23
|
conn;
|
|
24
24
|
sftpPromise;
|
|
@@ -52,7 +52,11 @@ import { type SqlDriver, type SqlTxConn } from "./sql-driver.js";
|
|
|
52
52
|
import { type IndexSpec } from "./ensure-index.js";
|
|
53
53
|
import type { EndedSpace } from "../workspace-space.js";
|
|
54
54
|
/**
|
|
55
|
-
* 三只**被托管**的 SQL 店(session / checkpoint / tool-result)
|
|
55
|
+
* 三只**被托管**的 SQL 店(session / checkpoint / tool-result)在扫车道开着时的 `retention` 声明常量。
|
|
56
|
+
*
|
|
57
|
+
* 🔴 **谁说这个词**(引擎 7.58.0 起:店说 `"managed"` 而部署不跑执行器 ⇒ 锁不锁都拒启):「这只店的行有没有人按期删」不是店类自己知道的事,
|
|
58
|
+
* 是装配它的部署知道的事。唯一事实 = 扫车道开不开({@link retentionSweepRuns});后端铸店时按它给词({@link sqlStoreRetention}),
|
|
59
|
+
* 交给引擎启动检查的执行器读同一个事实(开 ⇒ 执行器,关 ⇒ `null`)。店构造不给词 ⇒ `"none"`(引擎对缺席的同一读法)。
|
|
56
60
|
*
|
|
57
61
|
* 🔴 为什么是一个共享常量而不是各写各的字面量:这一格是 core `assertRetentionCapability` 的**唯一**读点,
|
|
58
62
|
* 三只店的答案必须同进同退 —— 哪天本能力从某只店的行上撤了(比如 tool_result 改由别处清),漏改一处
|
|
@@ -66,8 +70,16 @@ import type { EndedSpace } from "../workspace-space.js";
|
|
|
66
70
|
* file/in-memory 形没有任何东西会按期删它们的行 ⇒ 显式 `"none"`(缺席也读 none,但显式是文档义务)。
|
|
67
71
|
*/
|
|
68
72
|
export declare const MANAGED_RETENTION: RetentionDeclaration;
|
|
69
|
-
/** file/in-memory
|
|
73
|
+
/** file/in-memory 形、以及扫车道关着的 SQL 店的诚实声明(见 {@link MANAGED_RETENTION} 的读法说明)。 */
|
|
70
74
|
export declare const UNMANAGED_RETENTION: RetentionDeclaration;
|
|
75
|
+
/** 本部署跑不跑托管留存的扫车道(`RETENTION_SWEEP_INTERVAL_SEC > 0`)—— 三只 SQL 店的声明与交给引擎启动检查的执行器只读这一处。 */
|
|
76
|
+
export declare function retentionSweepRuns(sweep: {
|
|
77
|
+
readonly intervalSec: number;
|
|
78
|
+
}): boolean;
|
|
79
|
+
/** 后端铸三只被托管的 SQL 店时交给店的词:扫车道开 ⇒ `"managed"`,关 ⇒ `"none"`。 */
|
|
80
|
+
export declare function sqlStoreRetention(sweep: {
|
|
81
|
+
readonly intervalSec: number;
|
|
82
|
+
}): RetentionDeclaration;
|
|
71
83
|
/** 追加式审计表(设计稿 §6)。 */
|
|
72
84
|
export declare const RETENTION_AUDIT_TABLE = "retention_audit";
|
|
73
85
|
/** per-domain 法务保留标记(设计稿 §5)——**行在 = 该域整体冻结**。 */
|
|
@@ -5,6 +5,12 @@ import { ensureIndexes } from "./ensure-index.js";
|
|
|
5
5
|
import { incarnationFromCell } from "../session-incarnation.js";
|
|
6
6
|
export const MANAGED_RETENTION = "managed";
|
|
7
7
|
export const UNMANAGED_RETENTION = "none";
|
|
8
|
+
export function retentionSweepRuns(sweep) {
|
|
9
|
+
return sweep.intervalSec > 0;
|
|
10
|
+
}
|
|
11
|
+
export function sqlStoreRetention(sweep) {
|
|
12
|
+
return retentionSweepRuns(sweep) ? MANAGED_RETENTION : UNMANAGED_RETENTION;
|
|
13
|
+
}
|
|
8
14
|
export const RETENTION_AUDIT_TABLE = "retention_audit";
|
|
9
15
|
export const RETENTION_HOLD_TABLE = "retention_hold";
|
|
10
16
|
export const RETENTION_LEASE_TABLE = "retention_lease";
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* ## 规则(一句)
|
|
5
5
|
* 「fork 拷到哪一条」只有引擎一只判官:`settledForkOptions(源会话)` 答 `{}`(整份日志)或 `{ entryId: <在飞轮的父>, position: "at" }`(拷到那一条为止)。
|
|
6
|
-
* 本仓的店不写第二份「什么算在飞」—— local 店把它的答案原样交给引擎自己的 `repo.fork`;两只 SQL 孪生没有 `repo.fork`(它们按行搬字节)
|
|
6
|
+
* 本仓的店不写第二份「什么算在飞」—— local 店把它的答案原样交给引擎自己的 `repo.fork`;两只 SQL 孪生没有 `repo.fork`(它们按行搬字节),按答案挑行也是引擎的一只
|
|
7
|
+
* (`selectForkRows`,引擎 7.59.0 包根导出:同一条父链走法、同一组拒词);本文件只给它这两只孪生的行形(`entry_id` / `parent_id` 两列):
|
|
7
8
|
* · `{}` ⇒ 整份日志(含别的分支),叶 = 源会话的叶(与引擎 `getEntriesToFork` 的无 `entryId` 臂同);
|
|
8
9
|
* · `at` 点 ⇒ 根到分叉点那一条**路径**上的条目(与引擎 `getPathToRoot(entryId)` 同:路径,不是日志前缀,别的分支不随),叶 = 分叉点。
|
|
9
10
|
*
|
|
@@ -11,24 +12,20 @@
|
|
|
11
12
|
* 拷贝要的是**整份**持久日志(压缩地板绕过 —— 唤醒只装 `[地板..叶]`,从唤醒里拷会丢地板之前的全部历史);判官要的只是叶链上最近几条(它是引擎的一份纯函数,
|
|
12
13
|
* 吃一只 `Session`):唤醒出来的会话 `getEntry` 在地板之下会回读持久日志,所以判官在压缩过的会话上也看得见整条叶链。
|
|
13
14
|
*/
|
|
14
|
-
import {
|
|
15
|
-
/** 引擎答的分叉点(`{}` = 整份;`entryId` + `position: "at"` = 拷到这一条为止)。 */
|
|
16
|
-
export type ForkPoint = Awaited<ReturnType<typeof settledForkOptions>>;
|
|
15
|
+
import { type ForkPoint, type ForkRowShape, type SessionStorage } from "@sema-agent/core";
|
|
17
16
|
/** 问引擎:这只(已唤醒的)源会话从哪里拷。SQL 孪生用它;local 店手里就是引擎的 `Session`,直接调 `settledForkOptions`。 */
|
|
18
17
|
export declare function forkPointOf(storage: SessionStorage): Promise<ForkPoint>;
|
|
19
|
-
/**
|
|
18
|
+
/** 两只 SQL 孪生整份日志里的一行(两孪生选同一组列):父链两键交引擎挑行,其余三列原样搬进新会话、不读内容。 */
|
|
20
19
|
export interface ForkLogRow {
|
|
21
20
|
readonly entry_id: string;
|
|
22
21
|
readonly parent_id: string | null;
|
|
22
|
+
readonly type: string;
|
|
23
|
+
readonly payload: unknown;
|
|
24
|
+
readonly ts: unknown;
|
|
23
25
|
}
|
|
24
26
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* 分叉点不在日志里 ⇒ `invalid_fork_target`、路径中途的父不在日志里 ⇒ `invalid_session`(引擎 `getEntriesToFork` / `getPathToRoot` 同词同句);分叉点之上的父链成环 ⇒ `invalid_session`、
|
|
28
|
-
* 句子与引擎的父链守卫同(守卫类不在包根,走法是同一个意思:走过的条目再踩一次 = 环;沿用它的句子,让同一件事在三种后端上说同一句话);`position` 不是 `at` ⇒ 响亮拒(本函数只认引擎今天答的两形)。
|
|
27
|
+
* 两只 SQL 孪生的行怎么交给引擎的 `selectForkRows`(按答案挑行 + 新会话的叶;分叉点不在日志里 ⇒ `invalid_fork_target`、路径中途悬空父 / 父链成环 ⇒ `invalid_session`,
|
|
28
|
+
* 引擎的原词原句)。本仓不再自写父链走法 —— 那曾是与引擎 `getPathToRoot` 同义的第二份。
|
|
29
29
|
*/
|
|
30
|
-
export declare
|
|
31
|
-
rows: R[];
|
|
32
|
-
leafId: string | null;
|
|
33
|
-
};
|
|
30
|
+
export declare const FORK_LOG_ROW_SHAPE: ForkRowShape<ForkLogRow>;
|
|
34
31
|
//# sourceMappingURL=session-fork.d.ts.map
|
|
@@ -1,29 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { StoredSession, settledForkOptions } from "@sema-agent/core";
|
|
2
2
|
export async function forkPointOf(storage) {
|
|
3
3
|
return settledForkOptions(new StoredSession(storage));
|
|
4
4
|
}
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
throw new SessionError("invalid_fork_target", `fork point ${point.entryId} comes with a position this store does not copy (${String(point.position)}) — only the engine's "at" point is read here`);
|
|
10
|
-
}
|
|
11
|
-
const byId = new Map();
|
|
12
|
-
for (const r of rows)
|
|
13
|
-
byId.set(r.entry_id, r);
|
|
14
|
-
const onPath = new Set();
|
|
15
|
-
let cursor = point.entryId;
|
|
16
|
-
while (cursor !== null) {
|
|
17
|
-
if (onPath.has(cursor)) {
|
|
18
|
-
throw new SessionError("invalid_session", `Entry ${cursor} is its own ancestor (parent chain cycles at ${cursor}) — start a new session, or fork from an entry above the loop`);
|
|
19
|
-
}
|
|
20
|
-
const row = byId.get(cursor);
|
|
21
|
-
if (row === undefined) {
|
|
22
|
-
throw new SessionError(cursor === point.entryId ? "invalid_fork_target" : "invalid_session", `Entry ${cursor} not found`);
|
|
23
|
-
}
|
|
24
|
-
onPath.add(cursor);
|
|
25
|
-
cursor = row.parent_id;
|
|
26
|
-
}
|
|
27
|
-
return { rows: rows.filter((r) => onPath.has(r.entry_id)), leafId: point.entryId };
|
|
28
|
-
}
|
|
5
|
+
export const FORK_LOG_ROW_SHAPE = {
|
|
6
|
+
idOf: (row) => row.entry_id,
|
|
7
|
+
parentOf: (row) => row.parent_id,
|
|
8
|
+
};
|
|
29
9
|
//# sourceMappingURL=session-fork.js.map
|
|
@@ -22,4 +22,11 @@ export declare function forkOwnerOf(requested: string | null | undefined, source
|
|
|
22
22
|
* 「首写」由调用方判(已记下属主的会话上的调用照旧静默不改,不经这里)。判官 = {@link isSessionOwnerValue}(core 7.56.0 [ref] `principalNameOf`)。
|
|
23
23
|
*/
|
|
24
24
|
export declare function assertFirstOwnerWritable(sessionId: string, owner: unknown): asserts owner is string | null;
|
|
25
|
+
/**
|
|
26
|
+
* 导入者的属主 —— 换装的写腿(公开 `importEntries` / `replaceEntries` 与暂存提交)把调用方给的属主重戳进会话行之前的唯一读法:
|
|
27
|
+
* 主体名或 `null`(匿名)⇒ 原样交回;别的一切(空串、空白串、带控制 / 分隔 / 非连接符格式字符的串、非串)⇒ `TypeError` 响亮拒 ——
|
|
28
|
+
* 与引擎导入口拒同一类值时同一类错、同一句开头(引擎那一判只作用于交给它的属主,而换装交给引擎的是存档自己的戳,所以这一判在本仓)。
|
|
29
|
+
* 调用方在读写任何东西之前判,拒了就一个字节没写。判官 = {@link isSessionOwnerValue}(core `principalNameOf`),不在本仓另写规则。
|
|
30
|
+
*/
|
|
31
|
+
export declare function importerOwnerOf(owner: unknown): string | null;
|
|
25
32
|
//# sourceMappingURL=session-ownership.d.ts.map
|
|
@@ -22,4 +22,9 @@ export function assertFirstOwnerWritable(sessionId, owner) {
|
|
|
22
22
|
throw new SessionError("storage", `register(${sessionId}): a first ownership write must carry a principal name or null (anonymous), got ${ownerValueFault(owner)} — ` +
|
|
23
23
|
"a value that names nobody would leave the session claimable by anyone or ownable by no one; refusing, nothing written");
|
|
24
24
|
}
|
|
25
|
+
export function importerOwnerOf(owner) {
|
|
26
|
+
if (isSessionOwnerValue(owner))
|
|
27
|
+
return owner;
|
|
28
|
+
throw new TypeError(`session owner must be a principal name or null (anonymous), got ${ownerValueFault(owner)} — an import stamps it as the session's owner; refusing, nothing written`);
|
|
29
|
+
}
|
|
25
30
|
//# sourceMappingURL=session-ownership.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { SessionWorkspace } from "../session-workspace.js";
|
|
2
|
+
import { type JsonColumnReader } from "./sql-json-column.js";
|
|
3
|
+
/** 列定义的唯一属主(两方言 DDL 内插它;存量库缺这一列 ⇒ 起服列册对账拒启,拒句里的 ALTER 由建表语句生成)。 */
|
|
4
|
+
export declare const SESSION_META_WORKSPACE_COLUMN: {
|
|
5
|
+
readonly name: "workspace";
|
|
6
|
+
readonly tidb: "workspace JSON NULL";
|
|
7
|
+
readonly pg: "workspace JSONB";
|
|
8
|
+
};
|
|
9
|
+
/** 这一格的形读者(三只店与帧投影同一只;写前也过它 —— 写得进的就是读得出的)。 */
|
|
10
|
+
export declare const readSessionWorkspaceCell: JsonColumnReader<SessionWorkspace>;
|
|
11
|
+
/** 这一格的失败留痕 tag(F 类;登记行在 `observability/fail-open.ts`)。记录座(写 / 帧)与本文件(读)同一只。 */
|
|
12
|
+
export declare const SESSION_WORKSPACE_DEGRADED: "server.session-workspace.record-degraded";
|
|
13
|
+
/** 值 → 这一格的文本。`encode` 是该承载的编码器(MySQL 协议与 local:`JSON.stringify`;PG:`pgSafeJsonStringify`)。写前过形读者,不合形响亮抛、什么都不写。 */
|
|
14
|
+
export declare function encodeSessionWorkspaceCell(workspace: SessionWorkspace, encode: (value: unknown) => string, sessionId: string): string;
|
|
15
|
+
/** 一格(已按文本投影;SQL NULL / local 缺键 ⇒ 调用方传 `null`)→ 值。坏体 ⇒ 读作没有记录并计一次(见文件头);读腿漏投影 ⇒ 抛。 */
|
|
16
|
+
export declare function decodeSessionWorkspaceCell(cell: unknown, sessionId: string): SessionWorkspace | undefined;
|
|
17
|
+
//# sourceMappingURL=session-workspace-cell.d.ts.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { PROJECT_ID_REGEX } from "@sema-agent/core";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { recordFailOpen } from "../observability/fail-open.js";
|
|
4
|
+
import { assertJsonColumnWritable, createZodColumnReader, decodeJsonColumn, isJsonColumnBodyProblem } from "./sql-json-column.js";
|
|
5
|
+
export const SESSION_META_WORKSPACE_COLUMN = {
|
|
6
|
+
name: "workspace",
|
|
7
|
+
tidb: "workspace JSON NULL",
|
|
8
|
+
pg: "workspace JSONB",
|
|
9
|
+
};
|
|
10
|
+
const SESSION_WORKSPACE_SHAPE = z.object({
|
|
11
|
+
cwd: z.string().min(1),
|
|
12
|
+
root: z.string().min(1),
|
|
13
|
+
entered: z.object({ dir: z.string().min(1), byPath: z.literal(true).optional() }).optional(),
|
|
14
|
+
project: z.object({ id: z.string().regex(PROJECT_ID_REGEX), source: z.enum(["marker", "declared"]) }).optional(),
|
|
15
|
+
remote: z.boolean(),
|
|
16
|
+
});
|
|
17
|
+
export const readSessionWorkspaceCell = createZodColumnReader(SESSION_WORKSPACE_SHAPE);
|
|
18
|
+
export const SESSION_WORKSPACE_DEGRADED = "server.session-workspace.record-degraded";
|
|
19
|
+
const where = (sessionId) => `session_meta.workspace for session ${sessionId}`;
|
|
20
|
+
export function encodeSessionWorkspaceCell(workspace, encode, sessionId) {
|
|
21
|
+
const text = encode(workspace);
|
|
22
|
+
assertJsonColumnWritable(text, readSessionWorkspaceCell, where(sessionId));
|
|
23
|
+
return text;
|
|
24
|
+
}
|
|
25
|
+
export function decodeSessionWorkspaceCell(cell, sessionId) {
|
|
26
|
+
if (cell === null)
|
|
27
|
+
return undefined;
|
|
28
|
+
try {
|
|
29
|
+
return decodeJsonColumn(cell, readSessionWorkspaceCell, where(sessionId));
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
if (!isJsonColumnBodyProblem(e))
|
|
33
|
+
throw e;
|
|
34
|
+
recordFailOpen(SESSION_WORKSPACE_DEGRADED, `op=read ${e.where} problem=${e.problem}`);
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=session-workspace-cell.js.map
|
|
@@ -53,7 +53,7 @@ import { TiDBSessionStore } from "./tidb-session-store.js";
|
|
|
53
53
|
import { PgSessionStore } from "./pg-session-storage.js";
|
|
54
54
|
import { TiDBSharedMemoryStore, PgSharedMemoryStore } from "./shared-memory-store-sql.js";
|
|
55
55
|
import { TiDBAdoptionLogStore, PgAdoptionLogStore } from "./adoption-log-sql.js";
|
|
56
|
-
import { TiDBRetentionStore, PgRetentionStore } from "./retention-store-sql.js";
|
|
56
|
+
import { TiDBRetentionStore, PgRetentionStore, sqlStoreRetention } from "./retention-store-sql.js";
|
|
57
57
|
import { TiDBRetentionLaneStore, PgRetentionLaneStore } from "./retention-lane-store-sql.js";
|
|
58
58
|
import { createSqlPermissionRuleStores } from "./permission-rule-store-sql.js";
|
|
59
59
|
import { createFilePermissionRuleStores } from "./permission-rule-store-file.js";
|
|
@@ -149,9 +149,9 @@ class TiDBBackend {
|
|
|
149
149
|
workflowParkDecisions() { return (this.parkDecisionsInst ??= new SqlWorkflowParkDecisionStore(this.run())); }
|
|
150
150
|
parkDecisionsInst;
|
|
151
151
|
sharedMemoryStore(authorizer) { return new TiDBSharedMemoryStore(this.pool, authorizer); }
|
|
152
|
-
checkpoint(logger) { return new TiDBCheckpointStore(this.pool, logger); }
|
|
152
|
+
checkpoint(logger) { return new TiDBCheckpointStore(this.pool, logger, { retention: sqlStoreRetention(this.config.retentionSweep) }); }
|
|
153
153
|
checkpointReadView() { return this.checkpoint(); }
|
|
154
|
-
toolResult() { return new TiDBToolResultStore(this.pool); }
|
|
154
|
+
toolResult() { return new TiDBToolResultStore(this.pool, { retention: sqlStoreRetention(this.config.retentionSweep) }); }
|
|
155
155
|
imageIndex() { return new TiDBImageIndex(this.pool); }
|
|
156
156
|
imageBake() { return new TiDBImageBake(this.pool); }
|
|
157
157
|
leaderRun() { return new TiDBLeaderRunStore(this.pool); }
|
|
@@ -161,7 +161,7 @@ class TiDBBackend {
|
|
|
161
161
|
breaker(onWriteFail) { return new TiDBBreakerState(this.pool, onWriteFail); }
|
|
162
162
|
costQuota(limitMicroUsd, windowMs, onDegraded) { return new TiDBCostQuota(this.pool, limitMicroUsd, windowMs, undefined, onDegraded, this.config.dbQueryTimeoutMs); }
|
|
163
163
|
rateLimiter(limit, onDegraded) { return new TiDBRateLimiter(this.pool, limit, undefined, undefined, onDegraded, this.config.dbQueryTimeoutMs); }
|
|
164
|
-
session() { return new TiDBSessionStore(this.pool, { log: createLogger(this.config.logLevel) }); }
|
|
164
|
+
session() { return new TiDBSessionStore(this.pool, { log: createLogger(this.config.logLevel), retention: sqlStoreRetention(this.config.retentionSweep) }); }
|
|
165
165
|
adoptionLog() { return new TiDBAdoptionLogStore(this.pool); }
|
|
166
166
|
mysqlPool() { return this.pool; }
|
|
167
167
|
pgPool() { return undefined; }
|
|
@@ -203,9 +203,9 @@ class PgBackend {
|
|
|
203
203
|
workflowParkDecisions() { return (this.parkDecisionsInst ??= new SqlWorkflowParkDecisionStore(this.run())); }
|
|
204
204
|
parkDecisionsInst;
|
|
205
205
|
sharedMemoryStore(authorizer) { return new PgSharedMemoryStore(this.pool, authorizer); }
|
|
206
|
-
checkpoint(logger) { return new PgCheckpointStore(this.pool, logger); }
|
|
206
|
+
checkpoint(logger) { return new PgCheckpointStore(this.pool, logger, { retention: sqlStoreRetention(this.config.retentionSweep) }); }
|
|
207
207
|
checkpointReadView() { return this.checkpoint(); }
|
|
208
|
-
toolResult() { return new PgToolResultStore(this.pool); }
|
|
208
|
+
toolResult() { return new PgToolResultStore(this.pool, { retention: sqlStoreRetention(this.config.retentionSweep) }); }
|
|
209
209
|
imageIndex() { return new PgImageIndex(this.pool); }
|
|
210
210
|
imageBake() { return new PgImageBake(this.pool); }
|
|
211
211
|
leaderRun() { return new PgLeaderRunStore(this.pool); }
|
|
@@ -215,7 +215,7 @@ class PgBackend {
|
|
|
215
215
|
breaker(onWriteFail) { return new PgBreakerState(this.pool, onWriteFail); }
|
|
216
216
|
costQuota(limitMicroUsd, windowMs, onDegraded) { return new PgCostQuota(this.pool, limitMicroUsd, windowMs, undefined, onDegraded, this.config.dbQueryTimeoutMs); }
|
|
217
217
|
rateLimiter(limit, onDegraded) { return new PgRateLimiter(this.pool, limit, undefined, undefined, onDegraded, this.config.dbQueryTimeoutMs); }
|
|
218
|
-
session() { return new PgSessionStore(this.pool, { log: createLogger(this.config.logLevel) }); }
|
|
218
|
+
session() { return new PgSessionStore(this.pool, { log: createLogger(this.config.logLevel), retention: sqlStoreRetention(this.config.retentionSweep) }); }
|
|
219
219
|
adoptionLog() { return new PgAdoptionLogStore(this.pool); }
|
|
220
220
|
mysqlPool() { return undefined; }
|
|
221
221
|
pgPool() { return this.pool; }
|
|
@@ -7,6 +7,7 @@ import { TIDB_ADOPTION_LOG_STATEMENTS } from "./adoption-log-sql.js";
|
|
|
7
7
|
import { TIDB_PERMISSION_RULE_STATEMENTS } from "./permission-rule-store-sql.js";
|
|
8
8
|
import { TIDB_RETENTION_STATEMENTS } from "./retention-store-sql.js";
|
|
9
9
|
import { SESSION_META_INCARNATION_COLUMN } from "../session-incarnation.js";
|
|
10
|
+
import { SESSION_META_WORKSPACE_COLUMN } from "./session-workspace-cell.js";
|
|
10
11
|
import { RUN_IDENTITY_COLUMNS } from "../identity-source.js";
|
|
11
12
|
import { SESSION_RULES_COLUMN } from "./session-rules-column.js";
|
|
12
13
|
import { SESSION_TITLE_MAX_CHARS } from "../session-row.js";
|
|
@@ -73,6 +74,11 @@ export const SCHEMA_STATEMENTS = [
|
|
|
73
74
|
-- (CLAUDE.md / .claude/CLAUDE.md / AGENTS.md / .claude/AGENTS.md)。服务端元数据:不进模型上下文、不进 wire
|
|
74
75
|
-- 会话面;住在会话行上 ⇒ 随会话删除 / 留存清扫一起消失,fork 出的新行为 NULL(新会话首 run 同样只写不发)。
|
|
75
76
|
instruction_source VARCHAR(64) NULL,
|
|
77
|
+
-- workspace:本会话上一条腿**自己的**最后一帧 workspace_changed(引擎 7.58.0 的整份快照:cwd / root / entered / project / remote)。
|
|
78
|
+
-- NULL = 还没有任何腿记过;唯一写者 = 腿的记录座(src/session-workspace.ts),列属主 = src/plugins/session-workspace-cell.ts
|
|
79
|
+
-- (列定义、形读者、编解码;存量库缺这一列 ⇒ 起服列册对账拒启,拒句里给出 ALTER)。下一条腿的 TaskSpec.projectId 读它的 project.id。
|
|
80
|
+
-- 服务端元数据:不进 wire 会话面、不进模型上下文;住在会话行上 ⇒ 随会话删除 / 留存清扫一起消失,fork 出的新行为 NULL。
|
|
81
|
+
${SESSION_META_WORKSPACE_COLUMN.tidb},
|
|
76
82
|
-- #292 C18(core 5.48.0 design/323)subagent 转录持久化 —— placement 元组,**创建时一次落行、
|
|
77
83
|
-- first-write 不可变**(register 的 ON DUPLICATE 臂永不重写这六列)。判别位 = placement_kind:
|
|
78
84
|
-- 在场 ⇒ 该会话住在 placement 分区里(不上宿主枚举、claim 形 acquire 恒拒、release=真删除、
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { type AcquiredSession, type PlacedSessionRow, type SessionHead, type SessionPlacementRecord, type SessionStore, type SessionTreeEntry } from "@sema-agent/core";
|
|
14
14
|
import type { Pool } from "mysql2/promise";
|
|
15
15
|
import { type InstructionSourceBaseline } from "../instruction-source-notice.js";
|
|
16
|
+
import type { SessionWorkspace } from "../session-workspace.js";
|
|
17
|
+
import type { RetentionDeclaration } from "@sema-agent/core";
|
|
16
18
|
import { type SessionFace } from "../session-incarnation.js";
|
|
17
19
|
import type { SessionSummary } from "./store-contracts.js";
|
|
18
20
|
import type { SessionRowPatch } from "../session-row.js";
|
|
@@ -21,9 +23,9 @@ import { type PlacementAcquireOpts } from "./session-placement.js";
|
|
|
21
23
|
import { type StagingHandle } from "../session-sync-kernel.js";
|
|
22
24
|
export declare class TiDBSessionStore implements SessionStore {
|
|
23
25
|
private readonly pool;
|
|
24
|
-
/**
|
|
26
|
+
/** 托管留存声明 = 装配交给它的词(后端按扫车道开不开给;不给 ⇒ `"none"`)。读法逐字见
|
|
25
27
|
* `retention-store-sql.ts` 的 {@link MANAGED_RETENTION}。 */
|
|
26
|
-
readonly retention:
|
|
28
|
+
readonly retention: RetentionDeclaration;
|
|
27
29
|
/** [ref] C18(core 5.48.0 [ref]):placement **声明**。六条义务的实装点逐条见
|
|
28
30
|
* {@link SQL_SESSION_PLACEMENTS} 顶注与本类的 acquire / listSessions / release / listPlaced /
|
|
29
31
|
* placementOf 各处的 `[ref]` 注。 */
|
|
@@ -38,6 +40,7 @@ export declare class TiDBSessionStore implements SessionStore {
|
|
|
38
40
|
private readonly log;
|
|
39
41
|
constructor(pool: Pool, opts?: {
|
|
40
42
|
readonly log?: OrphanOwnerLog;
|
|
43
|
+
readonly retention?: RetentionDeclaration;
|
|
41
44
|
});
|
|
42
45
|
acquire(sessionId?: string, opts?: PlacementAcquireOpts): Promise<AcquiredSession>;
|
|
43
46
|
private load;
|
|
@@ -165,6 +168,18 @@ export declare class TiDBSessionStore implements SessionStore {
|
|
|
165
168
|
* 在期限内拒。⚠️ mysql2 的超时是客户端侧的 —— 拒之后那条连接仍被挂着的命令占到服务端结束(S-9 同形,如实披露)。
|
|
166
169
|
*/
|
|
167
170
|
recordInstructionSource(sessionId: string, expected: InstructionSourceBaseline, source: string | null): Promise<void>;
|
|
171
|
+
/**
|
|
172
|
+
* 会话行的位置与项目那一格(`session_meta.workspace`;域律 `src/session-workspace.ts`,列属主 `session-workspace-cell.ts`)。
|
|
173
|
+
* 一行 PK 读,按文本投影、恰好解一次;行不在 / 格为 NULL ⇒ `undefined`;格读不出 ⇒ 读作没有记录并计一次(F 类,见列属主头注)。
|
|
174
|
+
*/
|
|
175
|
+
readSessionWorkspace(sessionId: string): Promise<SessionWorkspace | undefined>;
|
|
176
|
+
/**
|
|
177
|
+
* 整格覆写(最后一帧胜;唯一调用方 = 腿的记录座,它在腿的流循环里一笔一笔等写完)。**住客围栏**:只写化身仍是 `incarnation` 的那一行 ——
|
|
178
|
+
* 行不在、或同 id 已换了住客 ⇒ 0 行、不抛(那一行不是这条腿的)。**不**碰 `updated_at`(那是会话活动时刻,留存腿按它判龄;记下站在哪里不是一次会话活动)。
|
|
179
|
+
* 走店的一般查询面(与腿循环里的账本追加同一形,不另设每查询的客户端超时):mysql2 的客户端超时只是不再等,服务端照把那条 UPDATE 跑完 ——
|
|
180
|
+
* 一笔「放弃等待却仍会落地」的写正是这条腿离开之后还能盖掉下一条腿的那一形。卡住的上界归服务端(锁等待超时)与部署的池策略。
|
|
181
|
+
*/
|
|
182
|
+
recordSessionWorkspace(sessionId: string, incarnation: string, workspace: SessionWorkspace): Promise<void>;
|
|
168
183
|
/**
|
|
169
184
|
* E17 — fork a session: copy its WHOLE durable history to a NEW uuidv7 session owned by `owner`, mirroring
|
|
170
185
|
* core's `PgSessionRepo.fork`. Entry ids / parent links are per-session and copy VERBATIM; only `seq` is
|
|
@@ -4,7 +4,8 @@ import { decodeSessionEventPayload } from "./session-event-payload.js";
|
|
|
4
4
|
import { jsonColumnText } from "./sql-json-column.js";
|
|
5
5
|
import { escapeLike } from "./sql-escape.js";
|
|
6
6
|
import { BASELINE_IO_DEADLINE_MS, decodeInstructionSource, encodeInstructionSource } from "../instruction-source-notice.js";
|
|
7
|
-
import {
|
|
7
|
+
import { decodeSessionWorkspaceCell, encodeSessionWorkspaceCell } from "./session-workspace-cell.js";
|
|
8
|
+
import { MANAGED_RETENTION, UNMANAGED_RETENTION } from "./retention-store-sql.js";
|
|
8
9
|
import { carriedIncarnation, headFromRow, mintSessionIncarnation, sessionFaceFromRow } from "../session-incarnation.js";
|
|
9
10
|
import { contentForkRelation, fastForwardSharedContentDiverged } from "../session-sync-content.js";
|
|
10
11
|
import { CLAIM_OWNERLESS_PLACED_SQL, claimOwnerlessParams, createPlacedSessionRow } from "../delegated-session-owner.js";
|
|
@@ -12,16 +13,18 @@ import { createLogger } from "../observability/logger.js";
|
|
|
12
13
|
import { placementCapabilityOf, LIST_PLACED_BATCH, PLACEMENT_SELECT_COLUMNS, placedRowFromRow, placementFromRow, placementInsertValues, SQL_SESSION_PLACEMENTS, } from "./session-placement.js";
|
|
13
14
|
import { classifySyncRelationshipByIds, SyncConflictError, StagedCommitOwnerChangedError, stagingIdFor, STAGING_ID_MARKER, STAGING_GC_GRACE_MS, } from "../session-sync-kernel.js";
|
|
14
15
|
import { assertFirstOwnerWritable, forkOwnerOf, isSessionOwnerValue } from "./session-ownership.js";
|
|
15
|
-
import {
|
|
16
|
+
import { selectForkRows } from "@sema-agent/core";
|
|
17
|
+
import { FORK_LOG_ROW_SHAPE, forkPointOf } from "./session-fork.js";
|
|
16
18
|
export class TiDBSessionStore {
|
|
17
19
|
pool;
|
|
18
|
-
retention
|
|
20
|
+
retention;
|
|
19
21
|
placements = SQL_SESSION_PLACEMENTS;
|
|
20
22
|
pending = new Map();
|
|
21
23
|
log;
|
|
22
24
|
constructor(pool, opts = {}) {
|
|
23
25
|
this.pool = pool;
|
|
24
26
|
this.log = opts.log ?? createLogger();
|
|
27
|
+
this.retention = opts.retention ?? UNMANAGED_RETENTION;
|
|
25
28
|
}
|
|
26
29
|
async acquire(sessionId, opts) {
|
|
27
30
|
if (!sessionId) {
|
|
@@ -247,6 +250,14 @@ export class TiDBSessionStore {
|
|
|
247
250
|
await this.pool.query({ sql: "UPDATE session_meta SET instruction_source = ? WHERE session_id = ? AND instruction_source IS NULL", timeout: BASELINE_IO_DEADLINE_MS }, [next, sessionId]);
|
|
248
251
|
}
|
|
249
252
|
}
|
|
253
|
+
async readSessionWorkspace(sessionId) {
|
|
254
|
+
const [rows] = await this.pool.query(`SELECT ${jsonColumnText("tidb", "workspace")} FROM session_meta WHERE session_id = ?`, [sessionId]);
|
|
255
|
+
const row = rows[0];
|
|
256
|
+
return row === undefined ? undefined : decodeSessionWorkspaceCell(row.workspace, sessionId);
|
|
257
|
+
}
|
|
258
|
+
async recordSessionWorkspace(sessionId, incarnation, workspace) {
|
|
259
|
+
await this.pool.query("UPDATE session_meta SET workspace = ? WHERE session_id = ? AND incarnation = ?", [encodeSessionWorkspaceCell(workspace, JSON.stringify, sessionId), sessionId, incarnation]);
|
|
260
|
+
}
|
|
250
261
|
async fork(sourceId, owner) {
|
|
251
262
|
const [metaRows] = await this.pool.query("SELECT leaf_id, owner FROM session_meta WHERE session_id = ?", [sourceId]);
|
|
252
263
|
if (!metaRows[0])
|
|
@@ -258,7 +269,7 @@ export class TiDBSessionStore {
|
|
|
258
269
|
return null;
|
|
259
270
|
const point = await forkPointOf(storage);
|
|
260
271
|
const [allRows] = await this.pool.query(`SELECT entry_id, parent_id, type, ${jsonColumnText("tidb", "payload")}, ts FROM session_event WHERE session_id = ? ORDER BY seq ASC`, [sourceId]);
|
|
261
|
-
const { rows: eventRows, leafId: forkLeafId } =
|
|
272
|
+
const { rows: eventRows, leafId: forkLeafId } = selectForkRows(allRows, leafId, point, FORK_LOG_ROW_SHAPE);
|
|
262
273
|
const newId = uuidv7();
|
|
263
274
|
const now = new Date();
|
|
264
275
|
const conn = await this.pool.getConnection();
|
|
@@ -353,7 +364,7 @@ export class TiDBSessionStore {
|
|
|
353
364
|
}
|
|
354
365
|
await conn.query("DELETE FROM session_event WHERE session_id = ?", [sessionId]);
|
|
355
366
|
await conn.query("DELETE FROM session_meta WHERE session_id = ? AND owner <=> ? AND placement_kind IS NULL", [sessionId, owner]);
|
|
356
|
-
await this.insertValidatedLog(conn, sessionId, owner, validated, carriedIncarnation(sessionId, placedRows[0] === undefined ? undefined : {
|
|
367
|
+
await this.insertValidatedLog(conn, sessionId, owner, validated, carriedIncarnation(sessionId, placedRows[0] === undefined ? undefined : { incarnation: placedRows[0].incarnation }));
|
|
357
368
|
await conn.commit();
|
|
358
369
|
}
|
|
359
370
|
catch (err) {
|
|
@@ -2,6 +2,7 @@ import type { ToolResultProvenance, ToolResultStore, ToolResultSlice, ToolResult
|
|
|
2
2
|
import type { Pool as MySqlPool } from "mysql2/promise";
|
|
3
3
|
import type { Pool as PgPool, PoolClient as PgPoolClient } from "pg";
|
|
4
4
|
import { type SqlDriver } from "./sql-driver.js";
|
|
5
|
+
import type { RetentionDeclaration } from "@sema-agent/core";
|
|
5
6
|
import { type IndexSpec } from "./ensure-index.js";
|
|
6
7
|
/** PG schema for the tool_result table — the PG translation of tidb-pool.ts's tool_result DDL
|
|
7
8
|
* (LONGTEXT→TEXT, DATETIME(3)→TIMESTAMPTZ(3), inline KEY→separate CREATE INDEX). Disjoint from other stores'
|
|
@@ -29,10 +30,12 @@ export declare function assertToolResultProvenanceSchema(query: (sql: string) =>
|
|
|
29
30
|
/** Dual-dialect durable ToolResultStore. See the file header for the dialect-delta ledger. */
|
|
30
31
|
export declare class SqlToolResultStore implements ToolResultStore {
|
|
31
32
|
protected readonly db: SqlDriver;
|
|
32
|
-
/**
|
|
33
|
-
*
|
|
34
|
-
readonly retention:
|
|
35
|
-
constructor(db: SqlDriver
|
|
33
|
+
/** 托管留存声明 = 装配交给它的词(后端按扫车道开不开给;不给 ⇒ `"none"`)。读法与「为什么 SQL 店答 managed 而三方法的实现体在
|
|
34
|
+
* `retention-store-sql.ts`」逐字见 {@link MANAGED_RETENTION}(扫车道开着时本店的 `tool_result` 行由那只聚合店按期清:随会话树删 + 孤儿腿)。 */
|
|
35
|
+
readonly retention: RetentionDeclaration;
|
|
36
|
+
constructor(db: SqlDriver, opts?: {
|
|
37
|
+
readonly retention?: RetentionDeclaration;
|
|
38
|
+
});
|
|
36
39
|
/** Pick the dialect's SQL text. Both statements stay written out at the call site ON PURPOSE. */
|
|
37
40
|
private q;
|
|
38
41
|
/** D1(试剂盒揪出,[ref] 语义):ref 是主键,而 `deleteBySession` 只认**记录下来的出处**与单射的
|
|
@@ -97,10 +100,14 @@ export declare class SqlToolResultStore implements ToolResultStore {
|
|
|
97
100
|
}
|
|
98
101
|
/** MySQL-protocol (TiDB) binding — historical class name + ctor shape preserved. */
|
|
99
102
|
export declare class TiDBToolResultStore extends SqlToolResultStore {
|
|
100
|
-
constructor(pool: MySqlPool
|
|
103
|
+
constructor(pool: MySqlPool, opts?: {
|
|
104
|
+
readonly retention?: RetentionDeclaration;
|
|
105
|
+
});
|
|
101
106
|
}
|
|
102
107
|
/** PostgreSQL binding — historical class name + ctor shape preserved. */
|
|
103
108
|
export declare class PgToolResultStore extends SqlToolResultStore {
|
|
104
|
-
constructor(pool: PgPool
|
|
109
|
+
constructor(pool: PgPool, opts?: {
|
|
110
|
+
readonly retention?: RetentionDeclaration;
|
|
111
|
+
});
|
|
105
112
|
}
|
|
106
113
|
//# sourceMappingURL=tool-result-store-sql.d.ts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MAX_MINTED_TOOL_RESULT_REF_CHARS, assertSafeToolResultRef, assertToolResultProvenanceMatch, normalizeToolResultProvenance } from "@sema-agent/core";
|
|
2
2
|
import { pgSanitizeText } from "./pg-safe-json.js";
|
|
3
3
|
import { mysqlDriver, pgDriver } from "./sql-driver.js";
|
|
4
|
-
import { MANAGED_RETENTION } from "./retention-store-sql.js";
|
|
4
|
+
import { MANAGED_RETENTION, UNMANAGED_RETENTION } from "./retention-store-sql.js";
|
|
5
5
|
import { ensureIndexes } from "./ensure-index.js";
|
|
6
6
|
export const PG_TOOL_RESULT_SCHEMA = [
|
|
7
7
|
`CREATE TABLE IF NOT EXISTS tool_result (
|
|
@@ -49,9 +49,10 @@ export async function assertToolResultProvenanceSchema(query, dialect) {
|
|
|
49
49
|
}
|
|
50
50
|
export class SqlToolResultStore {
|
|
51
51
|
db;
|
|
52
|
-
retention
|
|
53
|
-
constructor(db) {
|
|
52
|
+
retention;
|
|
53
|
+
constructor(db, opts = {}) {
|
|
54
54
|
this.db = db;
|
|
55
|
+
this.retention = opts.retention ?? UNMANAGED_RETENTION;
|
|
55
56
|
}
|
|
56
57
|
q(tidb, pg) {
|
|
57
58
|
return this.db.dialect === "tidb" ? tidb : pg;
|
|
@@ -128,13 +129,13 @@ export class SqlToolResultStore {
|
|
|
128
129
|
}
|
|
129
130
|
}
|
|
130
131
|
export class TiDBToolResultStore extends SqlToolResultStore {
|
|
131
|
-
constructor(pool) {
|
|
132
|
-
super(mysqlDriver(pool));
|
|
132
|
+
constructor(pool, opts) {
|
|
133
|
+
super(mysqlDriver(pool), opts);
|
|
133
134
|
}
|
|
134
135
|
}
|
|
135
136
|
export class PgToolResultStore extends SqlToolResultStore {
|
|
136
|
-
constructor(pool) {
|
|
137
|
-
super(pgDriver(pool));
|
|
137
|
+
constructor(pool, opts) {
|
|
138
|
+
super(pgDriver(pool), opts);
|
|
138
139
|
}
|
|
139
140
|
}
|
|
140
141
|
//# sourceMappingURL=tool-result-store-sql.js.map
|
|
@@ -54,8 +54,9 @@ export declare function withWorktreeIsolation(baseFactory: ExecutionEnvFactory,
|
|
|
54
54
|
* post-kill Runner hook). NEVER throws (a prune failure is logged, never fatal).
|
|
55
55
|
*
|
|
56
56
|
* NOTE: `git worktree prune` only deregisters worktrees whose DIRECTORY is missing. A crashed run that left
|
|
57
|
-
* the dir intact is NOT reaped by prune alone — that is acceptable for v1 (the worktree lives under
|
|
58
|
-
*
|
|
57
|
+
* the dir intact is NOT reaped by prune alone — that is acceptable for v1 (the worktree lives under core's known
|
|
58
|
+
* managed parent `<repoRoot>/<WORKTREE_PARENT>/` on its own `sema/<name>` branch and is human-/script-reapable;
|
|
59
|
+
* a stricter age-based sweep is a follow-on).
|
|
59
60
|
*/
|
|
60
61
|
export declare function reapOrphanWorktrees(baseEnvForGit: ExecutionEnv, repoRoot: string, logger?: WorktreeIsolationLogger): Promise<void>;
|
|
61
62
|
//# sourceMappingURL=worktree-isolation.d.ts.map
|