@sema-agent/server 7.151.0 → 7.152.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 +266 -0
- package/README.md +15 -3
- package/README.zh-CN.md +10 -2
- package/USAGE.md +93 -64
- package/deploy/sema-up/README.md +5 -4
- package/deploy/sema-up/cluster-up.sh +6 -6
- package/deploy/sema-up/kube-up.sh +5 -5
- package/deploy/sema-up/lib/flagshape.sh +36 -8
- package/deploy/sema-up/machines.example.yaml +3 -1
- package/deploy/sema-up/sema-up.sh +22 -16
- package/dist/approval-ask-audit-store.d.ts +1 -1
- package/dist/approval-ask-machine.d.ts +4 -10
- package/dist/approval-ask-retention.d.ts +1 -1
- package/dist/approval-card.d.ts +10 -12
- package/dist/approval-gate-currency.d.ts +8 -8
- package/dist/approval-gate-currency.js +3 -4
- package/dist/approval-hmac.d.ts +17 -1
- package/dist/approval-hmac.js +7 -1
- package/dist/approval-queue-kind.d.ts +1 -1
- package/dist/approval.d.ts +2 -2
- package/dist/approval.js +2 -2
- package/dist/bind-host.d.ts +1 -3
- package/dist/bind-host.js +2 -3
- package/dist/boot/coordinators.d.ts +1 -1
- package/dist/boot/coordinators.js +9 -10
- package/dist/boot/device-lane.js +2 -0
- package/dist/boot/execution-env.d.ts +1 -0
- package/dist/boot/execution-env.js +31 -5
- package/dist/boot/leader.d.ts +31 -30
- package/dist/boot/leader.js +38 -28
- package/dist/boot/leg-path-adjudication.d.ts +40 -0
- package/dist/boot/leg-path-adjudication.js +18 -0
- package/dist/boot/parked-revive-gate.js +3 -15
- package/dist/boot/reapers.d.ts +1 -1
- package/dist/boot/reapers.js +1 -1
- package/dist/boot/resolve-spec.js +12 -26
- package/dist/boot/runner-deps.d.ts +39 -35
- package/dist/boot/runner-deps.js +92 -89
- package/dist/boot/shutdown.d.ts +6 -0
- package/dist/boot/shutdown.js +10 -4
- package/dist/boot/stage-02-web-admin-pull.js +4 -5
- package/dist/boot/stage-05-execution-env.js +2 -1
- package/dist/boot/stage-06-runners.d.ts +2 -0
- package/dist/boot/stage-06-runners.js +10 -4
- package/dist/boot/stage-07-capability-layer.d.ts +1 -0
- package/dist/boot/stage-07-capability-layer.js +1 -1
- 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 -2
- package/dist/boot/stage-10-http-server.d.ts +8 -0
- package/dist/boot/stage-10-http-server.js +11 -15
- package/dist/boot/stores.js +7 -4
- package/dist/boot/web-admin.js +2 -7
- package/dist/capabilities/approvals-push.d.ts +3 -3
- package/dist/capabilities/scenarios.d.ts +28 -13
- package/dist/capabilities/scenarios.js +2 -2
- package/dist/capability-facts.d.ts +22 -20
- package/dist/capability-facts.js +18 -34
- package/dist/card-rule-offers.d.ts +32 -0
- package/dist/card-rule-offers.js +130 -0
- package/dist/config-catalog.js +12 -11
- package/dist/config-dir-trust.js +4 -2
- package/dist/config-invariants.d.ts +18 -7
- package/dist/config-invariants.js +51 -8
- package/dist/config-lkg.d.ts +5 -19
- package/dist/config-lkg.js +8 -62
- package/dist/config-provider.d.ts +1 -1
- package/dist/config-root-migration.d.ts +2 -2
- package/dist/config-types.d.ts +28 -38
- package/dist/config.d.ts +7 -5
- package/dist/config.js +55 -16
- package/dist/control-socket.d.ts +51 -0
- package/dist/control-socket.js +115 -0
- package/dist/deployment-governance.d.ts +2 -1
- package/dist/device-ws-hub.d.ts +7 -0
- package/dist/device-ws-hub.js +7 -1
- package/dist/elicitation.js +2 -2
- package/dist/entry-problems.d.ts +40 -3
- package/dist/entry-problems.js +3 -1
- package/dist/execution-env-refusal.d.ts +8 -2
- package/dist/execution-env-refusal.js +3 -0
- package/dist/fleet/engine-signal.d.ts +12 -29
- package/dist/fleet/engine-signal.js +1 -7
- package/dist/fleet-client.js +2 -5
- package/dist/gate-settlement.d.ts +1 -8
- package/dist/gate-settlement.js +0 -4
- package/dist/history-anchor.js +1 -1
- package/dist/hitl-delivery.d.ts +2 -3
- package/dist/hitl-delivery.js +0 -2
- package/dist/hooks/hook-llm.js +4 -2
- package/dist/hooks/hook-runner.d.ts +3 -2
- package/dist/hooks/hook-runner.js +16 -1
- package/dist/host-decision.d.ts +11 -11
- package/dist/http/active-run-conflict.d.ts +35 -2
- package/dist/http/active-run-conflict.js +48 -19
- package/dist/http/approval-sweeps.d.ts +1 -1
- package/dist/http/approval-sweeps.js +5 -2
- package/dist/http/checkpoint-ctx.d.ts +2 -0
- package/dist/http/checkpoint-ctx.js +1 -0
- package/dist/http/dispatch.d.ts +6 -2
- package/dist/http/dispatch.js +25 -5
- package/dist/http/durable-run-leg.js +0 -1
- package/dist/http/health-reader.d.ts +16 -9
- package/dist/http/health-reader.js +2 -1
- package/dist/http/health-self-report.js +1 -1
- package/dist/http/owner-access.d.ts +2 -3
- package/dist/http/owner-access.js +3 -4
- package/dist/http/principal-gate.d.ts +49 -21
- package/dist/http/principal-gate.js +61 -11
- package/dist/http/request-channel.d.ts +23 -0
- package/dist/http/request-channel.js +9 -0
- package/dist/http/request-guards.js +17 -2
- package/dist/http/resume-ctx-read.js +20 -3
- package/dist/http/resume-legs.d.ts +2 -2
- package/dist/http/resume-legs.js +111 -41
- package/dist/http/route-ctx.d.ts +73 -7
- package/dist/http/route-ctx.js +17 -0
- package/dist/http/route-table.d.ts +4 -0
- package/dist/http/route-table.js +4 -0
- package/dist/http/routes/admin-config-refresh.js +3 -3
- package/dist/http/routes/admin-drain.d.ts +3 -0
- package/dist/http/routes/admin-drain.js +7 -7
- package/dist/http/routes/admin-memory-optout.js +3 -3
- package/dist/http/routes/adoption.js +3 -5
- package/dist/http/routes/approvals-assistant.d.ts +2 -1
- package/dist/http/routes/approvals-assistant.js +95 -48
- package/dist/http/routes/capabilities.d.ts +4 -0
- package/dist/http/routes/capabilities.js +30 -5
- package/dist/http/routes/config-catalog.js +2 -2
- package/dist/http/routes/devices.js +1 -1
- package/dist/http/routes/diagnostics.d.ts +3 -3
- package/dist/http/routes/diagnostics.js +19 -7
- package/dist/http/routes/images.js +10 -10
- package/dist/http/routes/memory-bundle.js +3 -3
- package/dist/http/routes/memory-compliance.js +3 -3
- package/dist/http/routes/memory-consolidation.js +2 -2
- package/dist/http/routes/memory-origin.js +3 -3
- package/dist/http/routes/memory-policy.js +2 -2
- package/dist/http/routes/observability.js +3 -3
- package/dist/http/routes/retention-ops.js +3 -3
- package/dist/http/routes/rules.js +5 -5
- package/dist/http/routes/run-permission-mode.d.ts +2 -1
- package/dist/http/routes/run-permission-mode.js +2 -2
- package/dist/http/routes/runs.d.ts +4 -9
- package/dist/http/routes/runs.js +73 -33
- package/dist/http/routes/session-sync.d.ts +18 -6
- package/dist/http/routes/session-sync.js +38 -36
- package/dist/http/routes/sessions.js +20 -9
- package/dist/http/routes/tasks.js +28 -37
- package/dist/http/routes/workflows.js +1 -1
- package/dist/http/server.d.ts +9 -3
- package/dist/http/server.js +15 -3
- package/dist/http/submit-ctx.d.ts +1 -1
- package/dist/http/submit-ctx.js +2 -0
- package/dist/human-facing-args.d.ts +33 -0
- package/dist/human-facing-args.js +33 -0
- package/dist/index.d.ts +1 -1
- package/dist/k8s-api-credentials.d.ts +29 -0
- package/dist/k8s-api-credentials.js +25 -0
- package/dist/lane-home-probe.d.ts +1 -1
- package/dist/lane-home-probe.js +2 -1
- package/dist/leader/diffup.d.ts +19 -0
- package/dist/leader/diffup.js +7 -0
- package/dist/leader/leader.d.ts +114 -10
- package/dist/leader/leader.js +69 -5
- package/dist/leader/repair-wire.js +2 -2
- package/dist/leader/run-entry.d.ts +2 -1
- package/dist/leader/run-entry.js +1 -1
- package/dist/leader/wire.d.ts +42 -132
- package/dist/leader/wire.js +81 -67
- package/dist/memory-scope.d.ts +20 -9
- package/dist/memory-scope.js +15 -3
- package/dist/model-entry-headers.d.ts +9 -10
- package/dist/model-entry-headers.js +0 -4
- package/dist/model-entry-refusal.d.ts +7 -4
- package/dist/model-entry-refusal.js +11 -5
- package/dist/model-plane-face.d.ts +1 -1
- package/dist/model-plane-face.js +3 -1
- package/dist/model-route-endpoint.d.ts +13 -7
- package/dist/model-route-endpoint.js +14 -11
- package/dist/model-select.d.ts +22 -0
- package/dist/model-select.js +9 -0
- package/dist/model-unreachable-notice.d.ts +11 -0
- package/dist/model-unreachable-notice.js +4 -4
- package/dist/object-store-buckets.d.ts +640 -6
- package/dist/object-store-buckets.js +166 -0
- package/dist/observability/fail-open.d.ts +20 -16
- package/dist/observability/fail-open.js +20 -16
- package/dist/observability/logger.js +3 -1
- package/dist/operator-roster.d.ts +68 -0
- package/dist/operator-roster.js +32 -0
- package/dist/orchestration/workflow-park-decision.d.ts +1 -1
- package/dist/outbound-dispatcher.d.ts +71 -8
- package/dist/outbound-dispatcher.js +48 -7
- package/dist/owner-faces.d.ts +1 -1
- package/dist/parked-decide.d.ts +2 -2
- package/dist/permission-mode-admission.d.ts +59 -26
- package/dist/permission-mode-admission.js +37 -10
- package/dist/plugins/approval-ask-store-file.d.ts +4 -0
- package/dist/plugins/approval-ask-store-file.js +3 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +4 -0
- package/dist/plugins/approval-ask-store-memory.js +7 -1
- package/dist/plugins/approval-ask-store-sql.d.ts +26 -2
- package/dist/plugins/approval-ask-store-sql.js +12 -1
- package/dist/plugins/blob-backend.d.ts +83 -7
- package/dist/plugins/blob-backend.js +57 -6
- package/dist/plugins/checkpoint-index-columns.d.ts +20 -16
- package/dist/plugins/checkpoint-index-columns.js +3 -6
- package/dist/plugins/checkpoint-store-face.d.ts +119 -61
- package/dist/plugins/checkpoint-store-face.js +134 -55
- package/dist/plugins/landed-attendants.d.ts +2 -2
- package/dist/plugins/local-checkpoint-store.d.ts +13 -3
- package/dist/plugins/local-checkpoint-store.js +38 -49
- package/dist/plugins/one-time-migrations.d.ts +51 -21
- package/dist/plugins/one-time-migrations.js +67 -45
- package/dist/plugins/pg-pool.js +11 -9
- package/dist/plugins/remote-env-host.d.ts +29 -10
- package/dist/plugins/remote-env-host.js +99 -19
- package/dist/plugins/remote-env-k8s.d.ts +68 -2
- package/dist/plugins/remote-env-k8s.js +107 -24
- package/dist/plugins/replica-registration.d.ts +1 -1
- package/dist/plugins/replica-registration.js +1 -1
- package/dist/plugins/s3-presign.d.ts +23 -0
- package/dist/plugins/s3-presign.js +37 -3
- package/dist/plugins/scheduler-support.d.ts +2 -2
- package/dist/plugins/scheduler-support.js +0 -3
- package/dist/plugins/schema-indexes.js +2 -0
- package/dist/plugins/send-file-ledger.d.ts +2 -2
- package/dist/plugins/send-file-ledger.js +2 -2
- package/dist/plugins/send-user-file.d.ts +3 -4
- package/dist/plugins/send-user-file.js +56 -52
- package/dist/plugins/session-blob-claim-token.d.ts +15 -0
- package/dist/plugins/session-blob-claim-token.js +20 -0
- package/dist/plugins/session-blob-namespace.d.ts +46 -0
- package/dist/plugins/session-blob-namespace.js +116 -0
- package/dist/plugins/snapshot-bucket-presence.d.ts +25 -2
- package/dist/plugins/snapshot-bucket-presence.js +8 -2
- package/dist/plugins/sql-json-column.d.ts +1 -1
- package/dist/plugins/store-backend.d.ts +44 -2
- package/dist/plugins/store-backend.js +75 -53
- package/dist/plugins/task-attachment-store.d.ts +2 -1
- package/dist/plugins/task-attachment-store.js +5 -1
- package/dist/plugins/tidb-pool.js +19 -24
- package/dist/plugins/workspace-custody.d.ts +4 -3
- package/dist/question.d.ts +2 -1
- package/dist/question.js +5 -13
- package/dist/request-form.d.ts +6 -1
- package/dist/request-form.js +4 -1
- package/dist/rule-issue-reading.d.ts +1 -1
- package/dist/rules-consent.d.ts +1 -1
- package/dist/run-local.js +8 -9
- package/dist/runs.d.ts +17 -8
- package/dist/runs.js +15 -2
- package/dist/runtime-governance.d.ts +2 -2
- package/dist/sema-config-dir.d.ts +2 -1
- package/dist/session-sync.d.ts +27 -11
- package/dist/session-sync.js +15 -7
- package/dist/stores-sql/blob-index-sql.d.ts +30 -9
- package/dist/stores-sql/blob-index-sql.js +40 -21
- package/dist/stores-sql/checkpoint-store-sql.d.ts +54 -27
- package/dist/stores-sql/checkpoint-store-sql.js +70 -146
- package/dist/stores-sql/file-history-store-sql.d.ts +64 -16
- package/dist/stores-sql/file-history-store-sql.js +100 -28
- package/dist/stores-sql/retention-store-sql.js +3 -9
- package/dist/task-settings.d.ts +6 -5
- package/dist/task-settings.js +3 -3
- package/dist/tool-approval.d.ts +342 -518
- package/dist/tool-approval.js +498 -1207
- package/dist/trace/core-keyset-guard.d.ts +1 -1
- package/dist/trace/ledger-events.d.ts +3 -3
- package/dist/trace/project.d.ts +2 -3
- package/dist/trace/redact.js +3 -2
- package/dist/trace/self-minted-wire.d.ts +287 -157
- package/dist/trace/self-minted-wire.js +93 -48
- package/dist/web-admin-client/apply-effective.js +2 -2
- package/dist/web-admin-client/read-warnings.d.ts +2 -2
- package/dist/web-admin-client/read-warnings.js +1 -1
- package/dist/web-admin-client/types.d.ts +1 -1
- package/dist/workspace-space.d.ts +10 -4
- package/dist/workspace-space.js +4 -1
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +1 -1
- package/package.json +6 -2
- package/scripts/embed-minimal.mjs +3 -3
- package/wire-changes/server@7.152.0.json +900 -0
- package/dist/config-d-migration.d.ts +0 -37
- package/dist/config-d-migration.js +0 -60
|
@@ -5,7 +5,7 @@ import { attachmentKindOf, PROJECT_BUNDLE_MIME } from "../project-bundle.js";
|
|
|
5
5
|
import { mysqlDriver, pgDriver } from "./sql-driver.js";
|
|
6
6
|
import { isDupKeyError, retryOnDeadlock } from "./sql-errors.js";
|
|
7
7
|
import { countClientWriteOn } from "./session-withdraw-sql.js";
|
|
8
|
-
import { readAtAddress } from "./blob-backend.js";
|
|
8
|
+
import { isContentAddress, readAtAddress } from "./blob-backend.js";
|
|
9
9
|
import { sealStoreClass } from "./store-boundary.js";
|
|
10
10
|
export const TaskAttachmentRecordSchema = z.object({
|
|
11
11
|
id: z.string(),
|
|
@@ -386,6 +386,8 @@ export class TiDBTaskAttachmentStore {
|
|
|
386
386
|
batch = [];
|
|
387
387
|
};
|
|
388
388
|
for await (const o of lister.listObjects()) {
|
|
389
|
+
if (!isContentAddress(o.hash))
|
|
390
|
+
continue;
|
|
389
391
|
if (nowMs - o.lastModifiedMs < graceMs)
|
|
390
392
|
continue;
|
|
391
393
|
batch.push(o.hash);
|
|
@@ -506,6 +508,8 @@ export class PgTaskAttachmentStore {
|
|
|
506
508
|
batch = [];
|
|
507
509
|
};
|
|
508
510
|
for await (const o of lister.listObjects()) {
|
|
511
|
+
if (!isContentAddress(o.hash))
|
|
512
|
+
continue;
|
|
509
513
|
if (nowMs - o.lastModifiedMs < graceMs)
|
|
510
514
|
continue;
|
|
511
515
|
batch.push(o.hash);
|
|
@@ -33,6 +33,7 @@ import { acquireAdvisoryLock, releaseAdvisoryLock } from "./ensure-schema-lock-p
|
|
|
33
33
|
import { SKILL_EXEMPTION_CUTOFF_ID, markIfAbsentSql, migrationMarkerDdl } from "./one-time-migration-marker.js";
|
|
34
34
|
import { replicaRegistrationDdl } from "./replica-registration.js";
|
|
35
35
|
import { servingRequirementDdl } from "./serving-requirement.js";
|
|
36
|
+
import { sessionBlobNamespaceClaimDdl } from "./session-blob-claim-token.js";
|
|
36
37
|
import { createCloseAwarePool } from "./sql-driver.js";
|
|
37
38
|
export function tidbPoolOptions(tidb) {
|
|
38
39
|
const { host, port, user, password, database, connectionLimit } = tidb;
|
|
@@ -268,12 +269,11 @@ export const SCHEMA_STATEMENTS = [
|
|
|
268
269
|
session_id VARCHAR(190) NOT NULL,
|
|
269
270
|
version INT NOT NULL DEFAULT 1,
|
|
270
271
|
status VARCHAR(16) NOT NULL DEFAULT 'pending',
|
|
271
|
-
tool_name VARCHAR(190) NULL,
|
|
272
272
|
tool_call_id VARCHAR(190) NULL,
|
|
273
|
-
--
|
|
274
|
-
--
|
|
275
|
-
--
|
|
276
|
-
|
|
273
|
+
-- (no display-copy columns: the approval queue row's action facts — tool name, input, risk descriptor, rule offers,
|
|
274
|
+
-- bidi bit — are projected at read time from ONE whole-row decode of checkpoint, the copy a resume executes;
|
|
275
|
+
-- the stored copies tool_name / tool_input / risk_descriptor / rule_suggestions / has_bidi_controls were retired by
|
|
276
|
+
-- one-time migration M54. tool_call_id / bound_input_hash / approval_card / gate_kind stay: readers find rows by them.)
|
|
277
277
|
checkpoint JSON NOT NULL,
|
|
278
278
|
outcome JSON NULL,
|
|
279
279
|
deadline BIGINT NULL,
|
|
@@ -331,25 +331,6 @@ export const SCHEMA_STATEMENTS = [
|
|
|
331
331
|
-- 那条:文本相等性有太多与业务无关的自由度,整数没有。)
|
|
332
332
|
-- **绝不**用它做 resolve 的 OCC:bump 它不影响 core 的 rev 语义。
|
|
333
333
|
pending_steer_rev BIGINT NOT NULL DEFAULT 0,
|
|
334
|
-
-- risk_descriptor (design/80 riskDescriptor inbox): core's INERT CheckpointGate.riskDescriptor ({severity
|
|
335
|
-
-- 1-5, axes, toolName, redacted summary, touchedPaths}), stamped at put() so listPending can surface it +
|
|
336
|
-
-- triage-sort the supervisor inbox by severity DESC — WITHOUT parsing the checkpoint blob per row.
|
|
337
|
-
-- NULL on gates with no descriptor.
|
|
338
|
-
risk_descriptor TEXT NULL,
|
|
339
|
-
-- rule_suggestions ([3683]-2/[3684]② mint 面归因):core 挂在 pendingAction.ruleOffers 上的规则
|
|
340
|
-
-- 候选(design/179 §4;与同步腿 AskRequest.ruleOffers 同一条契约;design/375 换形后载荷=判别联合,列名保留),在 put() 落列 —— 于是
|
|
341
|
-
-- listPending 不必为一格展示材料去拖整只 checkpoint blob(那是整份 suspend 快照)。落列前过
|
|
342
|
-
-- boundedRuleOffers:窄读(坏条丢弃)+ redactSecrets(候选文本由命令原文铸出,而运维队列跨租户
|
|
343
|
-
-- 可见)+ 基数截断。NULL = 无供给(规则车道没武装 / 命令说不出规则 / 这只 ask 规则清不掉),读口
|
|
344
|
-
-- 据此省键而不是铸空数组。
|
|
345
|
-
rule_suggestions TEXT NULL,
|
|
346
|
-
-- has_bidi_controls(S-30① / #356②;core 5.60.0 #438):bidi **在场位** —— core 在 park mint 写在
|
|
347
|
-
-- pendingAction(tool_approval 臂)上的那一位,put() 反范式成列,listPending 据它给 /v1/approvals 与
|
|
348
|
-
-- /v1/approvals/stream 的行铸 hasBidiControls:true(此前耐久运维队列一个位都没有:同一张卡
|
|
349
|
-
-- 「活着看得到告警、park 之后看不到」)。取值 **1 或 NULL、恒不写 0**:core 的契约是 true 或缺席
|
|
350
|
-
-- (缺席 = 没检出 ≠ 干净),一个 0 会把「没检出」谎成「已确认干净」。老行(本列诞生前 park 的)
|
|
351
|
-
-- NULL ⇒ 读口省键。clay 批 2026-07-26 TINYINT(1) 归一先例:布尔列 TiDB 侧 TINYINT(1)。
|
|
352
|
-
has_bidi_controls TINYINT(1) NULL,
|
|
353
334
|
-- execution_outcome / execution_at_ms(S-160;core 7.7.0 #602 的耐久半场):**决定被怎么处置了**的
|
|
354
335
|
-- 结算记录 —— resume 腿上那次调用的 tool_end 帧携带的 GateOutcome,与 outcome 列(决定本身,不可变)
|
|
355
336
|
-- 是两个轴:一个人批了(outcome 里 disposition=allowed),部署自己的复核在 post-CAS 否了他改过的参数
|
|
@@ -365,6 +346,10 @@ export const SCHEMA_STATEMENTS = [
|
|
|
365
346
|
-- plugins/checkpoint-index-columns.ts 的 hostSessionOf 求值一次;存量行由一次性迁移 M49 自 session_id 回填。按会话找卡的读口(决断 / 取消 / 收割 /
|
|
366
347
|
-- 续跑输入回收 / 运维队列行)只读它;session_id 只答「这是哪段对话」。列定义的唯一属主 = 同模块的 CHECKPOINT_HOST_SESSION_COLUMN。
|
|
367
348
|
${CHECKPOINT_HOST_SESSION_COLUMN.mysql},
|
|
349
|
+
-- card_scope_root:这张卡上「不再询问」规则的 project root **铸卡快照**(停驻那一刻由跑这条 run 的副本写一次,读法与问行 rule_scope_root 同义;
|
|
350
|
+
-- 不在兑付时重推)。NULL = 授权发生地在 server 坐标系里不可知(远程沙箱 / 未登记的 host / 多租 host 车道),或行由加这一列之前的构建落下 ⇒
|
|
351
|
+
-- 规则兑付不铸 scope(core 答 scope-unresolved,只会拒不会放宽)。写口 put,读口 cardScopeRootOf;上界同 rule_scope_root(ABSOLUTE_HOST_PATH_MAX)。
|
|
352
|
+
card_scope_root VARCHAR(4096) NULL,
|
|
368
353
|
PRIMARY KEY (token),
|
|
369
354
|
KEY idx_checkpoint_status_deadline (status, deadline),
|
|
370
355
|
KEY idx_checkpoint_session_status (session_id, status),
|
|
@@ -564,6 +549,15 @@ export const SCHEMA_STATEMENTS = [
|
|
|
564
549
|
created_at DATETIME(3) NOT NULL,
|
|
565
550
|
PRIMARY KEY (blob_hash),
|
|
566
551
|
KEY idx_file_history_blob_created (created_at)
|
|
552
|
+
) COLLATE utf8mb4_bin`,
|
|
553
|
+
`CREATE TABLE IF NOT EXISTS file_history_blob_grant (
|
|
554
|
+
scope VARCHAR(64) NOT NULL,
|
|
555
|
+
landing_owner VARBINARY(${PRINCIPAL_MAX_BYTES}) NOT NULL,
|
|
556
|
+
blob_hash CHAR(64) NOT NULL,
|
|
557
|
+
granted_at DATETIME(3) NOT NULL,
|
|
558
|
+
PRIMARY KEY (scope, landing_owner, blob_hash),
|
|
559
|
+
KEY idx_file_history_blob_grant_granted (granted_at),
|
|
560
|
+
KEY idx_file_history_blob_grant_blob (blob_hash)
|
|
567
561
|
) COLLATE utf8mb4_bin`,
|
|
568
562
|
`CREATE TABLE IF NOT EXISTS workflow_journal (
|
|
569
563
|
run_id VARCHAR(191) NOT NULL,
|
|
@@ -784,6 +778,7 @@ export const SCHEMA_STATEMENTS = [
|
|
|
784
778
|
migrationMarkerDdl("mysql"),
|
|
785
779
|
replicaRegistrationDdl("mysql"),
|
|
786
780
|
servingRequirementDdl("mysql"),
|
|
781
|
+
sessionBlobNamespaceClaimDdl("mysql"),
|
|
787
782
|
...TIDB_APPROVAL_ASK_STATEMENTS,
|
|
788
783
|
...TIDB_MEMORY_OPTOUT_GRANT_STATEMENTS,
|
|
789
784
|
...TIDB_SESSION_CAPTURE_OPTOUT_STATEMENTS,
|
|
@@ -8,13 +8,14 @@
|
|
|
8
8
|
* (停驻腿的环境引擎还拿着,续跑腿拿到的就是它);那一只正在收场 ⇒ 等它的收场落定再铸,它欠着的账交给新的这只;没有 ⇒ 铸一只入表。
|
|
9
9
|
* 同一身份同一时刻只有一条腿(会话锁 + run 认领),交回同一只不会让两条腿同时用它。
|
|
10
10
|
* · **工作区的生命归持有它的环境,不归铸它的那一只**:表里每一只成员自己说它此刻持有哪只工作区;一只工作区能不能删 = 表里除问者之外还有没有成员持有它
|
|
11
|
-
* ({@link WorkspaceCustody.holder})——
|
|
11
|
+
* ({@link WorkspaceCustody.holder})—— 没有才删,有就把删交给最后放手的那一只(host 车道另问一句「此刻谁在里面」,见下)。
|
|
12
12
|
*
|
|
13
13
|
* ## 两条车道怎么读同一张表
|
|
14
14
|
* · local-docker:工作区 = 身份派生名的那只容器;一只身份同一时刻只有一只没收场的成员(上面的交回律),容器名又由身份派生 ⇒ 不可能有第二个持有者,成员收场即删
|
|
15
15
|
* (读 {@link WorkspaceCustody.envOf};欠账 = 删除没证实的那只容器,交给同一身份的下一只)。
|
|
16
|
-
* · host:工作区 = 本服务铸的临时根;委派子代按父的工作目录落根 ⇒ 子代的环境与父的共持那只根(铸时问 {@link WorkspaceCustody.holder}
|
|
17
|
-
*
|
|
16
|
+
* · host:工作区 = 本服务铸的临时根;委派子代按父的工作目录落根 ⇒ 子代的环境与父的共持那只根(铸时问 {@link WorkspaceCustody.holder}「谁持有包含这一处的根」,
|
|
17
|
+
* 只能多记持有者)。删只在最后一只持有者放手那一拍、同一同步段里问同一只 `holder`「还有谁持有它,或此刻还没离场、工作目录读得出地在它里面」之后发生 ——
|
|
18
|
+
* 有 ⇒ 不删(在里面的那一只当场接过删除);读不出 ⇒ 不删不交接,留给退出边界;没人才删。父收场时子代还停驻在里面 ⇒ 父不删,子代最后一条腿收场时再判。
|
|
18
19
|
*
|
|
19
20
|
* ## 出表
|
|
20
21
|
* 成员收场落定、什么都不欠、什么都不持有({@link CustodyMember.settled})⇒ 出表;没收场的成员(停驻腿的环境)一直在表里(停驻中被店层取消 / 过期的,引擎不销毁它,它持有的工作区
|
package/dist/question.d.ts
CHANGED
|
@@ -7,7 +7,8 @@ export interface QuestionFrame {
|
|
|
7
7
|
type: "question" | "question_complete";
|
|
8
8
|
questionId: string;
|
|
9
9
|
/** "question" only: the model's structured questions, secret-redacted. UNTRUSTED-for-display (shell renders; never
|
|
10
|
-
* re-feeds a model).
|
|
10
|
+
* re-feeds a model). Always the WHOLE questions — no size cap (the question IS the decision; the same bytes already ride
|
|
11
|
+
* `tool_start.args` uncapped). An unserializable payload emits no frame at all (the ask then reports unavailable). */
|
|
11
12
|
questions?: AskQuestion[];
|
|
12
13
|
/** "question_complete" only: whether the human answered (`answered`) or the ask closed without an answer
|
|
13
14
|
* (`unanswered` — window elapsed / abort / leg-exit sweep). Cosmetic dialog-dismiss. */
|
package/dist/question.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
2
|
import { uuidv7 } from "@sema-agent/core";
|
|
3
|
-
import {
|
|
3
|
+
import { humanFacingArgs } from "./human-facing-args.js";
|
|
4
4
|
import { recordFailOpen } from "./observability/fail-open.js";
|
|
5
5
|
import { refusalBody } from "./http/refusal-body.js";
|
|
6
6
|
import { keyAdmits, ownerCellOf, recoveredSubject } from "./owner-faces.js";
|
|
7
7
|
import { createHitlOpenRace } from "./hitl-delivery.js";
|
|
8
|
-
const MAX_QUESTIONS_BYTES = 16384;
|
|
9
8
|
export const DEFAULT_QUESTION_THROTTLE = {
|
|
10
9
|
maxConcurrentPerRun: 2,
|
|
11
10
|
maxTotalPerRun: 20,
|
|
@@ -48,16 +47,9 @@ export function parseQuestionResponse(body) {
|
|
|
48
47
|
}
|
|
49
48
|
return { ok: true, value: { answers: out } };
|
|
50
49
|
}
|
|
51
|
-
function
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
if (JSON.stringify(redacted).length > MAX_QUESTIONS_BYTES)
|
|
55
|
-
return undefined;
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
return undefined;
|
|
59
|
-
}
|
|
60
|
-
return redacted;
|
|
50
|
+
function presentableQuestions(questions) {
|
|
51
|
+
const shown = humanFacingArgs(questions, "question");
|
|
52
|
+
return shown.kind === "whole" ? shown.value : undefined;
|
|
61
53
|
}
|
|
62
54
|
export class QuestionCoordinator {
|
|
63
55
|
als = new AsyncLocalStorage();
|
|
@@ -90,7 +82,7 @@ export class QuestionCoordinator {
|
|
|
90
82
|
const rc = this.countersFor(ctx.taskId);
|
|
91
83
|
if (rc.inflight >= this.throttle.maxConcurrentPerRun || rc.total >= this.throttle.maxTotalPerRun)
|
|
92
84
|
return UNAVAILABLE;
|
|
93
|
-
const questions =
|
|
85
|
+
const questions = presentableQuestions(req.questions);
|
|
94
86
|
if (!questions)
|
|
95
87
|
return UNAVAILABLE;
|
|
96
88
|
const id = uuidv7();
|
package/dist/request-form.d.ts
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import type { IncomingMessage } from "node:http";
|
|
17
17
|
import { type TaskHostPostureScope, type TaskWriteFaceInput } from "./hosted-posture.js";
|
|
18
18
|
import { type ToolListSide } from "./rule-entry-list.js";
|
|
19
|
-
import { type Scenario } from "./owner-brands.js";
|
|
19
|
+
import { type Scenario, type Subject } from "./owner-brands.js";
|
|
20
20
|
import type { PermissionMode } from "@sema-agent/core";
|
|
21
21
|
import type { ServiceConfig } from "./config-types.js";
|
|
22
22
|
import type { TaskRequestBody } from "./http/wire-types.js";
|
|
@@ -25,6 +25,11 @@ import type { TaskRequestBody } from "./http/wire-types.js";
|
|
|
25
25
|
* (只在提交腿:读面没有体)。没带头 ⇒ 体原样(缺席 ⇒ 门走指派链)。
|
|
26
26
|
*/
|
|
27
27
|
export declare function scenarioRequestedBy(headerScenario: Scenario | undefined, bodyScenario: unknown): unknown;
|
|
28
|
+
/**
|
|
29
|
+
* {@link scenarioRequestedBy} 的主体形:场景头读**验过的主体**带的那一格(分派层判过在册,判决已记忆化),显式点名 = 体 `scenario`(提交受理门)或读面的 `?scenario=`。
|
|
30
|
+
* 受理门与读面(`GET /v1/capabilities/scenario` · `GET /v1/capabilities/mcp` · 两张会话面板)同调这一只 —— 同一只请求形在读面上点到的场景与提交时逐字同。
|
|
31
|
+
*/
|
|
32
|
+
export declare function scenarioRequestedBySubject(subject: Subject | undefined, named: unknown): unknown;
|
|
28
33
|
/**
|
|
29
34
|
* `inheritEnv:"all"` 的车道与射程两判(值形判在 `request-value-closure.ts` 的 `inheritEnvFieldIssue`,先于本函数):只有 host 车道消费这一位 ⇒ 别的车道 400 + 机读位
|
|
30
35
|
* `reason: lane_not_host`;射程读写容纳面那一只谓词(`hosted-posture.ts` 腿④)⇒ 托管 422 `request.host_posture_refused`。`"scrub"` 是缺省,任何车道受理。
|
package/dist/request-form.js
CHANGED
|
@@ -16,6 +16,9 @@ export function scenarioRequestedBy(headerScenario, bodyScenario) {
|
|
|
16
16
|
}
|
|
17
17
|
return headerScenario;
|
|
18
18
|
}
|
|
19
|
+
export function scenarioRequestedBySubject(subject, named) {
|
|
20
|
+
return scenarioRequestedBy(subject === undefined ? undefined : partsOf(subject).scenario, named);
|
|
21
|
+
}
|
|
19
22
|
export function assertInheritEnvServed(body, config) {
|
|
20
23
|
if (body.inheritEnv !== "all")
|
|
21
24
|
return;
|
|
@@ -61,7 +64,7 @@ export function assertRequestFormBeforeMint(body, req, config) {
|
|
|
61
64
|
assertToolListsReadable(body);
|
|
62
65
|
assertRequestA2aEntries(snapshotRequestA2a(body.a2aPeers, { reread: false }));
|
|
63
66
|
assertRequestImages(body.images);
|
|
64
|
-
|
|
67
|
+
scenarioRequestedBySubject(subject, body.scenario);
|
|
65
68
|
assertAttachmentIdsShape(body.attachmentIds);
|
|
66
69
|
assertWriteFaceAdmitted(effectivePermissionMode(body, parseTaskSettings(body.settings).settings), config);
|
|
67
70
|
const ruleTables = ruleTablesRefusalWithoutTaskRoot(body, config);
|
|
@@ -51,7 +51,7 @@ export type PersonFacingRuleIssue = {
|
|
|
51
51
|
* 码与句逐字是 core 的;`libraryOption` 不进句子、也不进出口(出口只有 `code` / `guidance`)。
|
|
52
52
|
*/
|
|
53
53
|
export declare function deploymentRuleRefusal(issue: PermissionRuleIssue): {
|
|
54
|
-
readonly code:
|
|
54
|
+
readonly code: PermissionRuleIssue["code"];
|
|
55
55
|
readonly guidance: string;
|
|
56
56
|
};
|
|
57
57
|
export {};
|
package/dist/rules-consent.d.ts
CHANGED
|
@@ -467,7 +467,7 @@ export type CardRulePersisted = {
|
|
|
467
467
|
* 导出成一只纯函数 —— 在本层照抄一个更严的校验器会把 `Bash(adb *)` 这条**成因形**当场误拒。」
|
|
468
468
|
*
|
|
469
469
|
* 现况:那只纯函数到货了,于是**文本能独立判定的那一半**({@link precheckEditedRuleText} 的语法门
|
|
470
|
-
* + 覆盖门)
|
|
470
|
+
* + 覆盖门)搬到了**裁决之前**—— 决断口 `POST /v1/tasks/:taskId/asks/:askId/decision` 在结算之前就 400,卡**还在**
|
|
471
471
|
* (与 `persistRule.rule` 的形/上限 400 同一姿势,那条 400 早就是这个形)。所以壳今天可以渲
|
|
472
472
|
* 「改一下再来」,而且真能来。
|
|
473
473
|
*
|
package/dist/run-local.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { DEFAULT_MODEL_REF, pickUserModel } from "./model-select.js";
|
|
3
3
|
import { defaultModelRefusal, modelNotAllowedMessage, modelUnavailableMessage } from "./model-entry-refusal.js";
|
|
4
|
-
import { servedModelTableLeg } from "./model-select.js";
|
|
4
|
+
import { modelRefusalLegOf, servedModelTableLeg } from "./model-select.js";
|
|
5
5
|
import { outwardPlane, sealResultForExit } from "./terminal.js";
|
|
6
6
|
import { join } from "node:path";
|
|
7
7
|
import { realpathSync } from "node:fs";
|
|
@@ -22,12 +22,11 @@ import { buildUnpricedCeilingNotice, isRosterGateArmed, loadConfig, logConfigDia
|
|
|
22
22
|
import { admitLocalDataRoot } from "./plugins/local-data-root-admission.js";
|
|
23
23
|
import { openLocalBackend } from "./plugins/store-backend.js";
|
|
24
24
|
import { runAndLogOneTimeMigrations } from "./plugins/one-time-migrations.js";
|
|
25
|
-
import { configLocalRoot, createConfigProvider } from "./config-provider.js";
|
|
25
|
+
import { configLocalRoot, configSourceKind, createConfigProvider } from "./config-provider.js";
|
|
26
26
|
import { CONFIG_DOMAIN_INVALID_NOTE, buildCandidateRejectedFields, buildCandidateRejectionNotes, judgeConfigCandidate } from "./web-admin-client/candidate-gate.js";
|
|
27
27
|
import { buildUnreadConfigFileFields, buildUnreadConfigKeyFields } from "./web-admin-client/read-warnings.js";
|
|
28
28
|
import { composeExecutionLane, settleHostLaneShell, settleReadDenyFloor } from "./boot/execution-lane.js";
|
|
29
29
|
import { judgeConsolidationValve } from "./boot/memory-consolidation.js";
|
|
30
|
-
import { logConfigDirMigration, migrateLocalConfigDirectory } from "./config-d-migration.js";
|
|
31
30
|
import { logEnvModelsMigration, runEnvModelsMigration } from "./config-root-migration.js";
|
|
32
31
|
import { assertLocalConfigDirTrusted, ConfigDirUntrustedError } from "./config-dir-trust.js";
|
|
33
32
|
import { ConfigPullError, asConfigPullError, configPullFailureNote } from "./config-pull-failure.js";
|
|
@@ -376,7 +375,6 @@ export async function runLocal(argv, deps = {}) {
|
|
|
376
375
|
await printErr(err instanceof Error ? err.message : String(err));
|
|
377
376
|
return 2;
|
|
378
377
|
}
|
|
379
|
-
logConfigDirMigration(logger, await migrateLocalConfigDirectory(root));
|
|
380
378
|
let config;
|
|
381
379
|
try {
|
|
382
380
|
config = await composeExecutionLane(loaded, { configSource: "local", localRoot: root, logger, entry: RUN_LOCAL_LANE_ENTRY });
|
|
@@ -435,10 +433,11 @@ export async function runLocal(argv, deps = {}) {
|
|
|
435
433
|
else
|
|
436
434
|
logger.warn("config_apply_refused", { source: configProvider.kind, err: String(err), note: "the candidate failed to apply at boot — running on env (run-local has no LKG); none of the candidate's domains is adopted; this is not a reachability failure" });
|
|
437
435
|
}
|
|
438
|
-
const
|
|
436
|
+
const webAdminIsConfigSource = configSourceKind(config) === "remote";
|
|
437
|
+
const noDefaultModel = defaultModelRefusal({ models: config.models, modelRefusals: config.modelRefusals, candidateRejectionNotes }, modelRefusalLegOf(servedModelTableLeg(config), webAdminIsConfigSource));
|
|
439
438
|
if (noDefaultModel !== undefined)
|
|
440
439
|
throw new Error(noDefaultModel);
|
|
441
|
-
const routeVerdict = judgeServedModelRoute(config, { envTableIsPlaceholder: false });
|
|
440
|
+
const routeVerdict = judgeServedModelRoute(config, { envTableIsPlaceholder: false, webAdminIsConfigSource });
|
|
442
441
|
if (routeVerdict !== undefined)
|
|
443
442
|
throw new Error(routeVerdict.reason);
|
|
444
443
|
warnAssumedContextWindows(config, logger, { envTableIsPlaceholder: false });
|
|
@@ -612,6 +611,7 @@ export async function runLocal(argv, deps = {}) {
|
|
|
612
611
|
assertGovernanceAssemblable(config);
|
|
613
612
|
const { registrations: deploymentMods } = await assembleDeploymentMods({ metrics, brandIdentity: true, declaration: config.modsDeclaration, logger });
|
|
614
613
|
const sharedRunnerDeps = createSharedRunnerDeps({
|
|
614
|
+
onError: engineOnError,
|
|
615
615
|
metrics,
|
|
616
616
|
config,
|
|
617
617
|
engineDataRoot,
|
|
@@ -643,7 +643,6 @@ export async function runLocal(argv, deps = {}) {
|
|
|
643
643
|
...sharedRunnerDeps,
|
|
644
644
|
sessionStore,
|
|
645
645
|
...(memoryEngine ? { memoryBackend: memoryEngine.backend } : {}),
|
|
646
|
-
onError: engineOnError,
|
|
647
646
|
onAsk,
|
|
648
647
|
...(config.projectMemoryEnabled
|
|
649
648
|
? {
|
|
@@ -653,7 +652,7 @@ export async function runLocal(argv, deps = {}) {
|
|
|
653
652
|
: {}),
|
|
654
653
|
};
|
|
655
654
|
const runner = new Runner(runnerDeps);
|
|
656
|
-
const subRunnerDeps = { ...sharedRunnerDeps, sessionStore: new ForkRoutingSessionStore(sessionStore, new TtlSessionStore({ defaultTtlDays: 1 / 24 })),
|
|
655
|
+
const subRunnerDeps = { ...sharedRunnerDeps, sessionStore: new ForkRoutingSessionStore(sessionStore, new TtlSessionStore({ defaultTtlDays: 1 / 24 })), onAsk };
|
|
657
656
|
const subRunner = new Runner(subRunnerDeps);
|
|
658
657
|
const handslessRunner = new Runner(withoutHands(runnerDeps));
|
|
659
658
|
const deploymentSkills = loadDeploymentSkills(config, logger);
|
|
@@ -677,7 +676,7 @@ export async function runLocal(argv, deps = {}) {
|
|
|
677
676
|
const sessionId = args.session ?? uuidv7();
|
|
678
677
|
let cap;
|
|
679
678
|
try {
|
|
680
|
-
scenarioName = await createScenarioGate({ config, scenarios, principalCaps: undefined, logger }, "enforce")(undefined, args.scenario);
|
|
679
|
+
scenarioName = (await createScenarioGate({ config, scenarios, principalCaps: undefined, logger }, "enforce")(undefined, args.scenario)).scenario;
|
|
681
680
|
cap = selectScenario(scenarios, scenarioName)({ scenario: scenarioName, objective: args.objective }, undefined, { sessionId });
|
|
682
681
|
}
|
|
683
682
|
catch (err) {
|
package/dist/runs.d.ts
CHANGED
|
@@ -137,8 +137,14 @@ export declare function releaseKeyIfZeroWorkRefusal(runStore: {
|
|
|
137
137
|
releaseIdemKey(taskId: string): Promise<void>;
|
|
138
138
|
}, taskId: string, result: Pick<TaskResult, "terminal" | "stats">): Promise<void>;
|
|
139
139
|
/**
|
|
140
|
-
* E18 resume-at — per-turn anchor capture, shared by runInBackground, the resume-leg driveResume
|
|
141
|
-
* leg's plain form so the (single, tricky) capture rule can't drift between the stream-drain loops.
|
|
140
|
+
* E18 resume-at — per-turn anchor capture, shared by runInBackground, the resume-leg driveResume, the `POST /v1/tasks/stream`
|
|
141
|
+
* leg AND the sync `POST /v1/tasks` leg's plain form so the (single, tricky) capture rule can't drift between the stream-drain loops.
|
|
142
|
+
*
|
|
143
|
+
* **One write moment for every leg**: an anchor is written in the drain loop the moment the event that decides it arrives
|
|
144
|
+
* (the prompt anchor on its `message_committed`, a turn anchor on its `turn_end`) — never deferred to a leg's finish /
|
|
145
|
+
* disconnect branch. A process that is killed (SIGKILL / host crash / OOM) runs no finish branch, so a deferred write is a
|
|
146
|
+
* write that a killed run never makes; the engine's file-history boundary for the prompt is already on disk by then, and
|
|
147
|
+
* the anchor is the only thing that translates the caller's handle to it.
|
|
142
148
|
*
|
|
143
149
|
* A "turn" in core = ONE assistant message + its tool batch. resume-at is valid ONLY at a SETTLED rewindable boundary
|
|
144
150
|
* — core's prepare-task accepts "user messages or finished assistant-text turns" and REJECTS an assistant message that
|
|
@@ -156,8 +162,8 @@ export declare function releaseKeyIfZeroWorkRefusal(runStore: {
|
|
|
156
162
|
* observable instead of a silent feature outage.
|
|
157
163
|
*/
|
|
158
164
|
/**
|
|
159
|
-
* 「这一次用户消息提交是不是这个 run 的**开场提示**」的唯一读法 ——
|
|
160
|
-
*
|
|
165
|
+
* 「这一次用户消息提交是不是这个 run 的**开场提示**」的唯一读法 —— 四条腿(后台腿 / 续跑腿 / 同步腿 `POST /v1/tasks` / 流式腿 `POST /v1/tasks/stream`)的用户回退锚
|
|
166
|
+
* 都经 {@link TurnAnchorCapture} 调这一只;调用点零各自判、零按正文判,交出一次写一次(「最后一次交出的赢」= 锚店按键 upsert)。
|
|
161
167
|
*
|
|
162
168
|
* **回退锚 = 该轮开场提示,一个 run 一个(开场窗 + 闩)**:run 一开始就开着一个**开场窗**,收集第一次模型输出之前的 user 提交;窗关上之后(闩上),同 run 的 user-role 提交 ——
|
|
163
169
|
* 用户打断时引擎收尾追加的「[Request interrupted by user]」、第一次模型调用前后排进来的 steer 正文、答完之后再来的 steer —— 一律不交。这是 CC「rewind to the message that started this turn」的
|
|
@@ -180,7 +186,7 @@ export declare function releaseKeyIfZeroWorkRefusal(runStore: {
|
|
|
180
186
|
* · 带附件的提交,窗内又应用了一条别的输入(`human_input{applied}`,如第一次模型调用前排进来的 steer;事件先于它的正文提交到手)⇒ 窗里多了一条别人的消息,数 N 会落在帧后面的 steer 上 ⇒ 不猜。
|
|
181
187
|
* 不带附件的提交不看输入条数:多条 applied 输入可以合成一条提交(续跑把停驻的 steer 与 wake 文本并成一条续跑消息),按修前同读校正到窗内最后一条。排队未应用(`delivery: "queued"`)的输入不动窗。窗还开着时继续攒,直到被关上。
|
|
182
188
|
* · 「不猜」= 这个 run 不落(带附件)或不校正(不带附件),且窗关上之后闩上 —— 其后的 user 提交(steer 正文、打断标记)不是开场提示,不顶上来;拿这次 run 的 taskId 去 `resumeAt`
|
|
183
|
-
* 得 404 `resume_at.unknown_event`(
|
|
189
|
+
* 得 404 `resume_at.unknown_event`(文案说「它是一条没有锚的提问」,不点名成因 —— `history-anchor.ts`)。
|
|
184
190
|
* 窗关上之前一个 user 提交都没有就关了(续跑腿里先到的是工具结果 / 助手消息)⇒ 窗照开着,不闩:那一条之后第一条 user 提交才是这个 run 里的第一条。
|
|
185
191
|
*
|
|
186
192
|
* 已知边界(引擎在 `message_committed` 上带来源标 / 输入标之日见下):
|
|
@@ -189,7 +195,7 @@ export declare function releaseKeyIfZeroWorkRefusal(runStore: {
|
|
|
189
195
|
* · 不带附件、第一次模型输出之前就应用了一条 steer:校正到窗内最后一条 = steer 正文(与修前同读)。
|
|
190
196
|
*
|
|
191
197
|
* 退役条件:引擎在落盘的帧上(`message_committed`)带上来源标(附件标记 / 引擎消息标)之日,本读法整体换成「第一条非引擎消息」(零计数、无窗口、无校正、无拒臂),
|
|
192
|
-
* 窗口 / 严格吻合 /
|
|
198
|
+
* 窗口 / 严格吻合 / 不猜三臂一并删除,领头排队消息的边界随之消失。
|
|
193
199
|
*/
|
|
194
200
|
export declare function createPromptCommitReader(): (ev: {
|
|
195
201
|
readonly type: string;
|
|
@@ -200,7 +206,8 @@ export type ResumeAnchorLeg = "stream" | "sync" | "bg" | "resume";
|
|
|
200
206
|
* 回退锚的**唯一**写法(四条腿同一只):**有界** await 写入(单行店操作期限 {@link BASELINE_IO_DEADLINE_MS},与项目指令基线的
|
|
201
207
|
* 读写同一只数、同一只 {@link withinIoDeadline} —— 同为单行 PK 写、同在腿的关键路径上);写失败或到期 ⇒ 不抛(锚是这次提示词能不能
|
|
202
208
|
* 回退的手柄,不是 run 的成败),记一次登记过的 fail-open `server.resume-anchor.capture-failed`(`reason=error|timeout`;计数 + 探针行 + 一次性 warn)。
|
|
203
|
-
*
|
|
209
|
+
* 调用方在决定这只锚的那一帧到手时就 await 它({@link TurnAnchorCapture}:提示锚在开场提示的提交上,四条腿同一个时机)⇒ 早于本腿的终帧(流式腿的 `done`、同步腿的 200 应答)——
|
|
210
|
+
* 客户端拿到终帧时锚已落定或已知没落定,没有「锚晚到」的窗;进程在终帧之前被强杀,已到手的那一笔也已落定。锚店挂住至多让那一帧之后的处理晚一个期限。
|
|
204
211
|
* 到期只放手不取消:那次写照常在飞,迟到落定的锚照样可用(迟到的失败被吞,不重复计数)。
|
|
205
212
|
* 用户面的读数仍只有一处:会话视图用户消息行的 `taskId?`(present-iff 锚在)与 `resumeAt` 的 404 `resume_at.unknown_event`。
|
|
206
213
|
*/
|
|
@@ -256,9 +263,11 @@ export declare class TurnAnchorCapture {
|
|
|
256
263
|
private turnHadTool;
|
|
257
264
|
/** 用户提交是不是开场提示的唯一读法({@link createPromptCommitReader};开场窗 + 闩 —— 开场提示之后打断标记 / steer 不改锚;附件帧不是提问)。 */
|
|
258
265
|
private readonly promptCommit;
|
|
266
|
+
/** 上一笔提示锚写的落定(临时锚 → 校正写同一把键;下一笔等它落定再发,见 {@link TurnAnchorCapture.onMessageCommitted})。从不拒。 */
|
|
267
|
+
private promptLanding;
|
|
259
268
|
constructor(capture: ((eventId: string, held: () => boolean) => Promise<void>) | undefined,
|
|
260
269
|
/** 这只捕获器在哪条腿上(写失败的 fail-open 探针行带它)。 */
|
|
261
|
-
leg:
|
|
270
|
+
leg: ResumeAnchorLeg,
|
|
262
271
|
/** R8 (CC-parity rewind): capture a USER-message anchor straight from the
|
|
263
272
|
* `message_committed{role:"user"}` event — its `entryId` is the persisted user-message `SessionTreeEntry.id`,
|
|
264
273
|
* ALWAYS a valid `resumeAt` target (core accepts a user message; it rejects a tool-result / mid-tool-call
|
package/dist/runs.js
CHANGED
|
@@ -290,6 +290,7 @@ export class TurnAnchorCapture {
|
|
|
290
290
|
firstTextEventId;
|
|
291
291
|
turnHadTool = false;
|
|
292
292
|
promptCommit = createPromptCommitReader();
|
|
293
|
+
promptLanding = Promise.resolve();
|
|
293
294
|
constructor(capture, leg, captureUser) {
|
|
294
295
|
this.capture = capture;
|
|
295
296
|
this.leg = leg;
|
|
@@ -302,8 +303,20 @@ export class TurnAnchorCapture {
|
|
|
302
303
|
const committed = { type: "message_committed", role, entryId };
|
|
303
304
|
const prompt = this.promptCommit(committed);
|
|
304
305
|
const captureUser = this.captureUser;
|
|
305
|
-
if (prompt
|
|
306
|
-
|
|
306
|
+
if (prompt === undefined || !captureUser)
|
|
307
|
+
return;
|
|
308
|
+
const prior = this.promptLanding;
|
|
309
|
+
let landed;
|
|
310
|
+
this.promptLanding = new Promise((resolve) => { landed = resolve; });
|
|
311
|
+
await settleResumeAnchor(async (held) => {
|
|
312
|
+
try {
|
|
313
|
+
await prior;
|
|
314
|
+
await captureUser(prompt, held);
|
|
315
|
+
}
|
|
316
|
+
finally {
|
|
317
|
+
landed();
|
|
318
|
+
}
|
|
319
|
+
}, { leg: this.leg, kind: "prompt" });
|
|
307
320
|
}
|
|
308
321
|
onText(eventId) {
|
|
309
322
|
if (this.firstTextEventId === undefined) {
|
|
@@ -93,8 +93,8 @@ export declare function compileCommandPolicyLayers(rules: CommandRule[] | undefi
|
|
|
93
93
|
* 盖在每一个 spec 出生点一次(词 = {@link entryPermissionMode} 的 `effective`):受理门盖进存储的提交体(`task-settings.ts` `stampEntryPermissionMode`)、run-local 盖在它自建的 spec 上、
|
|
94
94
|
* leader run 盖在它出生时的入口体上(`leader/run-entry.ts`;入口词是 `plan` 的 leader run 进不了那条车道 —— worker 会话没有计划审阅通道 ⇒ 受理口响亮拒)。此后一条 run 的模式词
|
|
95
95
|
* 只有存储体一个源,写者是每一个出生点(新的持久化写都经 `http/checkpoint-ctx.ts` `buildCheckpointCtx`)、`plan_review` 写回与续跑口(停驻 run 的存储体被重放之前过一次**现**地板、
|
|
96
|
-
* 钳过的随 CAS 赢点写回;`permission-mode-admission.ts` `stampReplayEntryMode
|
|
97
|
-
* 被批准的计划会在下一次挂起→续跑被拉回 plan;续跑口不是按段折 ——
|
|
96
|
+
* 钳过的随 CAS 赢点写回;`permission-mode-admission.ts` `stampReplayEntryMode`,写据说那一格是地板的出口 —— `plan_review` 批准 —— 写下的且仍是它写下的那一格 ⇒ 原样读)。按段折一个模式词 = 第二个源:
|
|
97
|
+
* 被批准的计划会在下一次挂起→续跑被拉回 plan;续跑口不是按段折 —— 它与提交口同一只入口一步,写的是同一个源,且不碰出口写下的那一格。收紧入参的型上因此没有 `permissionMode`(`governance-overrides.ts`)。(上一个发布版本里本档不碰模式词,按段折的是只读手 +
|
|
98
98
|
* 写面 `roots`、与 `read-only` 同形 —— 运维 plan 那时根本不进 plan 模式,见下一段。)
|
|
99
99
|
*
|
|
100
100
|
* 🔴 **为什么 `plan` 不再与 `read-only` 同形**:修前两档同映「只读手 + roots」,外加 `resolve-spec.ts` 见只读手就剥委派工具 —— 于是 `plan` 有三套
|
|
@@ -30,7 +30,8 @@ export declare function provisionSemaConfigDir(config: {
|
|
|
30
30
|
* (与记忆根那一判共用同一只规范形,那一判的失败方向是多报,这一判的是漏报;如实披露)。
|
|
31
31
|
* 句子只描述位置关系,后果限定在引擎**缺省**写保护表上:用 `WRITE_PROTECTED_TABLE_REPLACE` 去掉那一行的部署不受影响(这一行不读那张表),可忽略它。
|
|
32
32
|
*
|
|
33
|
-
* 规范形读不出(
|
|
33
|
+
* 规范形读不出(两边路径上有一段没有搜索权限 / 链接成环,或盘上竞态:探完到取值之间目录被挪走 / 搜索权限被收)⇒ 不给位置结论(看不见的一段不当成「还不存在」),
|
|
34
|
+
* 披露面也不得把起服打死:响亮报另一行 `sema_config_root_workspace_check_unavailable`(类名 + 机器码),起服照常。
|
|
34
35
|
* 位置:HTTP 服务在装配第 2 段执行车道合成之后(读的是合成后的车道与工作区底),`run-local` 在工作区定下之后 —— 车道在这两处才定形,所以不与 {@link provisionSemaConfigDir} 同一拍。
|
|
35
36
|
*/
|
|
36
37
|
export declare function announceConfigRootEnclosingWorkspace(config: {
|
package/dist/session-sync.d.ts
CHANGED
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
import type { StoreBackend } from "./plugins/store-backend.js";
|
|
49
49
|
import { type SyncRelation } from "./session-sync-kernel.js";
|
|
50
50
|
import type { SessionTreeEntry, SessionRulesRecord, FileHistoryError, FileHistoryExport } from "@sema-agent/core";
|
|
51
|
-
import type { ServiceBlobExchange, ServiceFileHistoryStore } from "./plugins/store-backend.js";
|
|
51
|
+
import type { ServiceBlobExchange, ServiceFileHistoryStore, SqlBlobPutResult, SyncLanding } from "./plugins/store-backend.js";
|
|
52
52
|
/**
|
|
53
53
|
* core 7.55.0 [ref] T2([ref]):一只会话的文件历史**读不全**(撕裂 / 读不出的边界、读不出的跟踪集 —— 店的 `exportHistory` 答 `{ ok: false }`,`adopt_failed`
|
|
54
54
|
* 带店判的 `permanence`)。它**不是**「没有历史」:读成 `null` 的同步会把这只会话的全部 rewind 历史丢在路上、还答成功。会话同步的两只拉取口
|
|
@@ -66,19 +66,38 @@ export declare class FileHistoryUnreadableError extends Error {
|
|
|
66
66
|
*/
|
|
67
67
|
export declare function exportedFileHistory(store: Pick<ServiceFileHistoryStore, "exportHistory">, sessionId: string): Promise<FileHistoryExport | null>;
|
|
68
68
|
/** A blob getter: content-addressed bytes for a sha256 hash, or `undefined` if the source can't supply them.
|
|
69
|
-
*
|
|
70
|
-
* content-addressed history bytes lazily (the live PUSH route's `importHistory` replay). */
|
|
69
|
+
* The live PUSH route's `importHistory` replay reads one — always the getter of a {@link VisibleBlobs} answer (never an unscoped read of the store). */
|
|
71
70
|
export type BlobGetter = (hash: string) => Promise<Uint8Array | undefined>;
|
|
72
71
|
/**
|
|
73
72
|
* 「这只文件历史店能不能交换 blob」的**唯一**读法:店的 `blobExchange` 组,经 core 的判官 `fileHistoryBlobExchangeOf` 读 —— 没有组 ⇒ `undefined`
|
|
74
73
|
* (core 的 local 文件店);整组 ⇒ 三只成员(判官已绑好);缺一员 / 组不是对象 / 店还带退役的标记词 ⇒ 判官拒(`config.invalid_argument`,响亮,不是「没有」)。
|
|
75
|
-
*
|
|
74
|
+
* 会话同步的 blob 面 {@link landingBlobFacesOf} 读它取字节;交换组的 `put` / `has` 路由不握有 —— 读它们的是 core 契约套件与店自己的按落点来历面(经它写字节、问在场)。
|
|
76
75
|
* 返回型收窄到本仓的 {@link ServiceBlobExchange}:判官交回的是店自己那一组的成员(只绑定、不包装),店型声明的组就是那一型。
|
|
77
76
|
*/
|
|
78
77
|
export declare function blobExchangeOf(store: ServiceFileHistoryStore): ServiceBlobExchange | undefined;
|
|
79
|
-
/**
|
|
80
|
-
*
|
|
81
|
-
|
|
78
|
+
/**
|
|
79
|
+
* 一次可见性读的答案:这个落点此刻看得见的 hash 集,和**只答这几枚**的取值口(集外的一律 `undefined` —— 重放观察到它,答与预检同一个 `missing_blob`)。
|
|
80
|
+
* 预检的答案就是重放取值口的许可集:第一阶段读一次、冻结进暂存随第二阶段走 —— 覆盖写的擦除排在重放之前,擦掉旧图不改许可。
|
|
81
|
+
*/
|
|
82
|
+
export interface VisibleBlobs {
|
|
83
|
+
readonly hashes: ReadonlySet<string>;
|
|
84
|
+
readonly get: BlobGetter;
|
|
85
|
+
}
|
|
86
|
+
/** 什么都看不见的答案:信封不引用 blob,或这台部署没有 blob 面(下面 {@link landingBlobFacesOf} 答 `undefined`)。 */
|
|
87
|
+
export declare const NO_VISIBLE_BLOBS: VisibleBlobs;
|
|
88
|
+
/**
|
|
89
|
+
* 会话同步路由读写 blob 的**唯一**面(按落点):上传 = 店的按落点来历面 `putAt`(核址 → 字节 → 授予);可见 = 店的 `visibleAt`,取字节经交换组的 `get`、只放行可见集里的那几枚。
|
|
90
|
+
* 预检、identical 自愈臂与提交臂的重放取值、`GET …/sync/history/blobs/:hash` 三口读的是同一只 `visible`。
|
|
91
|
+
*/
|
|
92
|
+
export interface LandingBlobFaces {
|
|
93
|
+
put(landing: SyncLanding, hash: string, bytes: Uint8Array): Promise<SqlBlobPutResult>;
|
|
94
|
+
visible(landing: SyncLanding, hashes: readonly string[]): Promise<VisibleBlobs>;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* 「这只文件历史店有没有会话同步的 blob 面」的**唯一**读法(能力事实 `sessionSyncFileHistory` 读它):交换组({@link blobExchangeOf})∧ 按落点来历面(`blobLanding`)两样都在 ⇒ 面;
|
|
98
|
+
* 缺一样 ⇒ `undefined`(fail-closed:给不出按落点可见性的店没有 blob 两口 —— 只有交换组而无来历面,就只能按全局内容地址表答「在不在」,那正是这只面要关掉的预言机)。
|
|
99
|
+
*/
|
|
100
|
+
export declare function landingBlobFacesOf(store: ServiceFileHistoryStore): LandingBlobFaces | undefined;
|
|
82
101
|
/**
|
|
83
102
|
* The portable state of ONE session, ready to replay into another backend. Blobs are deliberately NOT inlined
|
|
84
103
|
* (§5: a turn's working-tree blobs can be tens of MiB → OOM/413 if buffered); each snapshot carries only its
|
|
@@ -149,10 +168,7 @@ export interface SessionManifest {
|
|
|
149
168
|
export declare function exportSessionManifest(sessionId: string, srcBackend: StoreBackend,
|
|
150
169
|
/** [ref]:文件历史读**装配结果**(捕获脸),不直取 `srcBackend.fileHistory()` —— 「这台部署有没有文件历史店」
|
|
151
170
|
* 只在 `assembleFileHistory` 判一次。同一个后端铸的同一只店,四店同源的不变式不变。 */
|
|
152
|
-
historyStore: ServiceFileHistoryStore): Promise<
|
|
153
|
-
manifest: SessionManifest;
|
|
154
|
-
getBlob: BlobGetter;
|
|
155
|
-
} | null>;
|
|
171
|
+
historyStore: ServiceFileHistoryStore): Promise<SessionManifest | null>;
|
|
156
172
|
/**
|
|
157
173
|
* §7 DRY-RUN — classify what importing `sessionId` from `srcBackend` into `dstBackend` WOULD do, WITHOUT writing
|
|
158
174
|
* anything (the shell can present a keep-local / keep-cloud / fork-new choice up front).
|
package/dist/session-sync.js
CHANGED
|
@@ -24,9 +24,21 @@ export async function exportedFileHistory(store, sessionId) {
|
|
|
24
24
|
export function blobExchangeOf(store) {
|
|
25
25
|
return fileHistoryBlobExchangeOf(store);
|
|
26
26
|
}
|
|
27
|
-
export
|
|
27
|
+
export const NO_VISIBLE_BLOBS = { hashes: new Set(), get: async () => undefined };
|
|
28
|
+
export function landingBlobFacesOf(store) {
|
|
28
29
|
const exchange = blobExchangeOf(store);
|
|
29
|
-
|
|
30
|
+
const provenance = store.blobLanding;
|
|
31
|
+
if (exchange === undefined || provenance === undefined)
|
|
32
|
+
return undefined;
|
|
33
|
+
return {
|
|
34
|
+
put: (landing, hash, bytes) => provenance.putAt(landing, hash, bytes),
|
|
35
|
+
visible: async (landing, hashes) => {
|
|
36
|
+
if (hashes.length === 0)
|
|
37
|
+
return NO_VISIBLE_BLOBS;
|
|
38
|
+
const seen = await provenance.visibleAt(landing, hashes);
|
|
39
|
+
return { hashes: seen, get: async (hash) => (seen.has(hash) ? exchange.get(hash) : undefined) };
|
|
40
|
+
},
|
|
41
|
+
};
|
|
30
42
|
}
|
|
31
43
|
function ownerAware(backend) {
|
|
32
44
|
return backend.session();
|
|
@@ -57,7 +69,6 @@ export async function exportSessionManifest(sessionId, srcBackend, historyStore)
|
|
|
57
69
|
if (summaryOf === undefined)
|
|
58
70
|
throw new Error("exportSessionManifest: the session store has no row read face (sessionSummaryOf) — the sessionSync fact should have refused this deployment");
|
|
59
71
|
const row = await summaryOf(sessionId);
|
|
60
|
-
const getBlob = blobGetterOf(fs);
|
|
61
72
|
const declared = new Set(entryIds);
|
|
62
73
|
const soundAnchors = anchors.filter((a) => {
|
|
63
74
|
if (anchorEntryDeclared(declared, a.entryId))
|
|
@@ -65,10 +76,7 @@ export async function exportSessionManifest(sessionId, srcBackend, historyStore)
|
|
|
65
76
|
recordFailOpen("server.session-sync.dangling-anchor-export", `sessionId=${brief(sessionId)} eventId=${brief(a.eventId)} entryId=${brief(a.entryId)}`);
|
|
66
77
|
return false;
|
|
67
78
|
});
|
|
68
|
-
return {
|
|
69
|
-
manifest: { sessionId, entryIds, entryCount: entryIds.length, leafId, fileHistory, policy, anchors: soundAnchors, ...(row !== undefined ? { title: row.title, pinned: row.pinned } : {}) },
|
|
70
|
-
getBlob,
|
|
71
|
-
};
|
|
79
|
+
return { sessionId, entryIds, entryCount: entryIds.length, leafId, fileHistory, policy, anchors: soundAnchors, ...(row !== undefined ? { title: row.title, pinned: row.pinned } : {}) };
|
|
72
80
|
}
|
|
73
81
|
export async function planSync(sessionId, srcBackend, dstBackend) {
|
|
74
82
|
const srcEntries = (await ownerAware(srcBackend).exportEntries?.(sessionId)) ?? null;
|