@sema-agent/server 7.141.0 → 7.143.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 +657 -0
- package/USAGE.md +102 -30
- package/dist/adoption/plan.js +22 -0
- package/dist/approval-ask-audit-store.d.ts +61 -43
- package/dist/approval-ask-audit-store.js +69 -44
- package/dist/approval-ask-machine.d.ts +15 -7
- package/dist/approval-ask-machine.js +10 -4
- package/dist/approval-card.d.ts +126 -27
- package/dist/approval-card.js +103 -23
- package/dist/approval-crash-convergence.d.ts +17 -7
- package/dist/approval-crash-convergence.js +94 -22
- package/dist/approval-deny-reasons.d.ts +34 -30
- package/dist/approval-deny-reasons.js +21 -6
- package/dist/approval-policy-settlement.d.ts +1 -1
- package/dist/approval-queue-kind.d.ts +27 -0
- package/dist/approval-queue-kind.js +6 -0
- package/dist/approval-reconciler.d.ts +41 -9
- package/dist/approval-reconciler.js +45 -42
- package/dist/audit.js +4 -2
- package/dist/auth-bridge.d.ts +9 -6
- package/dist/auth-bridge.js +9 -3
- package/dist/boot/adoption.js +2 -1
- package/dist/boot/budget-tracing.d.ts +17 -1
- package/dist/boot/budget-tracing.js +10 -6
- package/dist/boot/device-lane.d.ts +1 -1
- package/dist/boot/execution-env.d.ts +24 -4
- package/dist/boot/execution-env.js +26 -23
- package/dist/boot/execution-lane.js +2 -1
- package/dist/boot/exit-boundary.js +5 -4
- package/dist/boot/governance-seams.d.ts +26 -41
- package/dist/boot/governance-seams.js +61 -28
- package/dist/boot/late-binds.d.ts +7 -4
- package/dist/boot/late-binds.js +3 -1
- package/dist/boot/leader.js +2 -4
- package/dist/boot/memory-consolidation.d.ts +0 -8
- package/dist/boot/memory-consolidation.js +5 -4
- package/dist/boot/parked-revive-gate.js +2 -1
- package/dist/boot/permission-rules-audit.d.ts +0 -28
- package/dist/boot/permission-rules-audit.js +2 -1
- package/dist/boot/read-deny-anchor-audit.js +2 -1
- package/dist/boot/reapers.js +9 -7
- package/dist/boot/resolve-spec.d.ts +1 -1
- package/dist/boot/resolve-spec.js +19 -10
- package/dist/boot/retention-lane.js +5 -3
- package/dist/boot/runner-deps.d.ts +10 -7
- package/dist/boot/runner-deps.js +20 -29
- package/dist/boot/runtime-caps.js +3 -2
- package/dist/boot/session-faces.js +4 -3
- package/dist/boot/shutdown.d.ts +9 -0
- package/dist/boot/shutdown.js +19 -4
- package/dist/boot/stage-02-web-admin-pull.js +3 -0
- package/dist/boot/stage-03-store-backend.d.ts +4 -1
- package/dist/boot/stage-03-store-backend.js +1 -2
- package/dist/boot/stage-04-stores.d.ts +5 -2
- package/dist/boot/stage-04-stores.js +6 -7
- package/dist/boot/stage-05-execution-env.d.ts +6 -3
- package/dist/boot/stage-05-execution-env.js +8 -6
- package/dist/boot/stage-06-runners.d.ts +6 -3
- package/dist/boot/stage-06-runners.js +3 -4
- package/dist/boot/stage-07-capability-layer.d.ts +6 -3
- package/dist/boot/stage-07-capability-layer.js +7 -2
- package/dist/boot/stage-08-reapers.d.ts +6 -3
- package/dist/boot/stage-08-reapers.js +3 -2
- package/dist/boot/stage-09-leader.d.ts +6 -3
- package/dist/boot/stage-10-http-server.d.ts +6 -3
- package/dist/boot/stage-10-http-server.js +14 -5
- package/dist/boot/stores.d.ts +5 -2
- package/dist/boot/stores.js +10 -9
- package/dist/boot/web-admin.d.ts +5 -1
- package/dist/boot/web-admin.js +48 -36
- package/dist/boot/webfetch-summarize-lane.js +2 -1
- package/dist/boot/workflow-orchestration.js +3 -2
- package/dist/capabilities/builtin-tools.d.ts +2 -1
- package/dist/capabilities/builtin-tools.js +2 -4
- package/dist/capabilities/composite-members.d.ts +2 -1
- package/dist/capabilities/composite-members.js +2 -1
- package/dist/capabilities/hands-lane.d.ts +9 -39
- package/dist/capabilities/hands-lane.js +8 -13
- package/dist/capabilities/mcp-probe.d.ts +3 -2
- package/dist/capabilities/scenarios.d.ts +11 -1
- package/dist/capabilities/scenarios.js +1 -0
- package/dist/capabilities/skills.d.ts +1 -17
- package/dist/capabilities/skills.js +0 -8
- package/dist/capability-facts.d.ts +31 -7
- package/dist/capability-facts.js +27 -4
- package/dist/card-void.d.ts +6 -9
- package/dist/config-catalog.js +2 -1
- package/dist/config-dir-trust.js +58 -29
- package/dist/config-invariants.d.ts +7 -1
- package/dist/config-invariants.js +7 -0
- package/dist/config-provider.d.ts +10 -0
- package/dist/config-provider.js +15 -4
- package/dist/config-root-migration.d.ts +13 -0
- package/dist/config-root-migration.js +99 -0
- package/dist/config-types.d.ts +19 -8
- package/dist/config.d.ts +10 -3
- package/dist/config.js +18 -4
- package/dist/delegated-session-owner.d.ts +5 -3
- package/dist/delegated-session-owner.js +1 -1
- package/dist/device-ws-protocol.d.ts +1 -0
- package/dist/device-ws-protocol.js +2 -1
- package/dist/env-model-table-gate.d.ts +53 -0
- package/dist/env-model-table-gate.js +53 -0
- package/dist/execution-lane-caps.d.ts +2 -1
- package/dist/fleet/fleet-bus.d.ts +34 -55
- package/dist/fleet/fleet-bus.js +35 -100
- package/dist/fleet/fleet-reconciler.d.ts +4 -4
- package/dist/fleet/fleet-reconciler.js +1 -1
- package/dist/fleet/subagent-tail-bus.d.ts +14 -11
- package/dist/fleet/subagent-tail-bus.js +15 -28
- package/dist/hooks/hook-runner.d.ts +6 -0
- package/dist/hooks/hook-runner.js +58 -8
- package/dist/host-decision.d.ts +54 -20
- package/dist/host-decision.js +42 -14
- package/dist/http/admission.d.ts +1 -1
- package/dist/http/admission.js +7 -3
- package/dist/http/approval-sweeps.js +11 -8
- package/dist/http/caller-trust.d.ts +1 -1
- package/dist/http/dispatch.js +4 -2
- package/dist/http/durable-run-leg.js +2 -2
- package/dist/http/engine-refusal.d.ts +16 -0
- package/dist/http/engine-refusal.js +17 -0
- package/dist/http/execution-context.d.ts +2 -2
- package/dist/http/idempotency.d.ts +1 -1
- package/dist/http/memory-compliance-failure-reply.d.ts +1 -3
- package/dist/http/memory-compliance-failure-reply.js +4 -6
- package/dist/http/owner-access.d.ts +11 -0
- package/dist/http/owner-access.js +13 -0
- package/dist/http/principal-gate.d.ts +3 -1
- package/dist/http/principal-gate.js +17 -8
- package/dist/http/resume-legs.d.ts +21 -7
- package/dist/http/resume-legs.js +76 -58
- package/dist/http/resume-restatement.d.ts +39 -0
- package/dist/http/resume-restatement.js +25 -0
- package/dist/http/route-ctx.d.ts +35 -10
- package/dist/http/route-ctx.js +1 -1
- package/dist/http/route-table.js +2 -0
- package/dist/http/routes/approvals-assistant.d.ts +9 -1
- package/dist/http/routes/approvals-assistant.js +142 -31
- package/dist/http/routes/attachments.js +18 -0
- package/dist/http/routes/capabilities.js +16 -4
- package/dist/http/routes/memory-policy.d.ts +2 -2
- package/dist/http/routes/memory-policy.js +27 -7
- package/dist/http/routes/notify-wake.js +23 -25
- package/dist/http/routes/rules.js +48 -13
- package/dist/http/routes/runs.js +12 -11
- package/dist/http/routes/session-memory-sync.d.ts +91 -0
- package/dist/http/routes/session-memory-sync.js +174 -0
- package/dist/http/routes/session-sync.js +13 -20
- package/dist/http/routes/sessions-list.d.ts +2 -1
- package/dist/http/routes/sessions.d.ts +2 -2
- package/dist/http/routes/sessions.js +22 -23
- package/dist/http/routes/tasks.js +34 -54
- package/dist/http/run-read-face.d.ts +7 -0
- package/dist/http/run-read-face.js +9 -3
- package/dist/http/send.d.ts +5 -0
- package/dist/http/send.js +9 -2
- package/dist/http/server.d.ts +27 -15
- package/dist/http/server.js +4 -6
- package/dist/http/stored-body-replay.js +15 -4
- package/dist/http/submit-replay.d.ts +4 -3
- package/dist/http/submit-replay.js +2 -2
- package/dist/http/sync-submit-body.d.ts +21 -4
- package/dist/http/sync-submit-body.js +13 -0
- package/dist/http/wire-types.d.ts +17 -7
- package/dist/identity-source.d.ts +21 -2
- package/dist/identity-source.js +6 -0
- package/dist/leader/leader.js +5 -2
- package/dist/leader/wire.d.ts +7 -1
- package/dist/leader/wire.js +6 -5
- package/dist/leg-facts.d.ts +37 -0
- package/dist/leg-facts.js +15 -0
- package/dist/memory-bundle-engine.d.ts +1 -4
- package/dist/memory-bundle-engine.js +2 -2
- package/dist/memory-incident-sink.d.ts +19 -6
- package/dist/memory-incident-sink.js +8 -4
- package/dist/memory-operator-faces.d.ts +30 -66
- package/dist/memory-operator-faces.js +17 -88
- package/dist/memory-scope-stores.d.ts +38 -40
- package/dist/memory-scope-stores.js +51 -36
- package/dist/memory-scope.d.ts +0 -9
- package/dist/memory-scope.js +0 -9
- package/dist/memory-sync-client.d.ts +21 -21
- package/dist/memory-sync-client.js +62 -43
- package/dist/memory-sync-identity.d.ts +24 -0
- package/dist/memory-sync-identity.js +57 -0
- package/dist/memory-sync.d.ts +27 -5
- package/dist/memory-sync.js +29 -7
- package/dist/model-plane-face.d.ts +13 -7
- package/dist/model-plane-face.js +2 -1
- package/dist/observability/fail-open.d.ts +47 -14
- package/dist/observability/fail-open.js +37 -11
- package/dist/observability/run-terminal.d.ts +92 -34
- package/dist/observability/run-terminal.js +171 -162
- package/dist/orchestration/workflow-completion-inbox.d.ts +5 -19
- package/dist/orchestration/workflow-completion-inbox.js +0 -12
- package/dist/orchestration/workflow-notify-journal.d.ts +3 -2
- package/dist/orchestration/workflow-park-decision.d.ts +8 -3
- package/dist/orchestration/workflow-park-decision.js +5 -3
- package/dist/org-delivery-gate.d.ts +11 -0
- package/dist/org-delivery-gate.js +19 -1
- package/dist/parked-decide.d.ts +13 -9
- package/dist/parked-decide.js +7 -7
- package/dist/parked-revive-surface.js +1 -1
- package/dist/peer-inbound-face.d.ts +127 -0
- package/dist/peer-inbound-face.js +158 -0
- package/dist/permission-rule-list.d.ts +13 -9
- package/dist/permission-rule-list.js +7 -3
- package/dist/plugins/approval-ask-store-file.d.ts +14 -4
- package/dist/plugins/approval-ask-store-file.js +64 -11
- package/dist/plugins/approval-ask-store-memory.d.ts +2 -1
- package/dist/plugins/approval-ask-store-memory.js +17 -14
- package/dist/plugins/approval-ask-store-sql.d.ts +70 -23
- package/dist/plugins/approval-ask-store-sql.js +79 -30
- package/dist/plugins/checkpoint-store-sql.d.ts +4 -4
- package/dist/plugins/checkpoint-store-sql.js +9 -7
- package/dist/plugins/file-history-store-sql.d.ts +24 -18
- package/dist/plugins/file-history-store-sql.js +24 -19
- package/dist/plugins/file-run-store.d.ts +35 -1
- package/dist/plugins/file-run-store.js +108 -9
- package/dist/plugins/imported-layer-root-retirement.d.ts +82 -0
- package/dist/plugins/imported-layer-root-retirement.js +96 -0
- package/dist/plugins/local-checkpoint-store.d.ts +1 -1
- package/dist/plugins/local-checkpoint-store.js +2 -2
- package/dist/plugins/local-session-store.d.ts +42 -9
- package/dist/plugins/local-session-store.js +83 -33
- package/dist/plugins/local-task-attachment-store.d.ts +12 -2
- package/dist/plugins/local-task-attachment-store.js +67 -43
- package/dist/plugins/mailbox-recipient-lifecycle.d.ts +9 -31
- package/dist/plugins/mailbox-recipient-lifecycle.js +4 -0
- package/dist/plugins/mailbox-store-sql.d.ts +12 -8
- package/dist/plugins/mailbox-store-sql.js +76 -7
- package/dist/plugins/memory-key-guards.d.ts +3 -3
- package/dist/plugins/memory-run-store.d.ts +6 -1
- package/dist/plugins/memory-run-store.js +11 -1
- package/dist/plugins/memory-sync-store-pg.d.ts +15 -0
- package/dist/plugins/memory-sync-store-pg.js +21 -0
- package/dist/plugins/memory-sync-store-tidb.d.ts +2 -0
- package/dist/plugins/memory-sync-store-tidb.js +13 -1
- package/dist/plugins/one-time-migrations.d.ts +58 -2
- package/dist/plugins/one-time-migrations.js +161 -4
- package/dist/plugins/org-delivery-quota-store.d.ts +1 -1
- package/dist/plugins/org-delivery-quota-store.js +2 -12
- package/dist/plugins/park-commit-watch.d.ts +1 -1
- package/dist/plugins/permission-rule-store-file.d.ts +10 -1
- package/dist/plugins/permission-rule-store-file.js +15 -2
- package/dist/plugins/permission-rule-store-sql.d.ts +31 -1
- package/dist/plugins/permission-rule-store-sql.js +35 -2
- package/dist/plugins/remote-env-device.d.ts +8 -11
- package/dist/plugins/remote-env-device.js +6 -3
- package/dist/plugins/remote-env-e2b.d.ts +23 -4
- package/dist/plugins/remote-env-e2b.js +111 -28
- package/dist/plugins/remote-env-k8s.d.ts +61 -22
- package/dist/plugins/remote-env-k8s.js +133 -33
- package/dist/plugins/remote-env-local-docker.d.ts +15 -3
- package/dist/plugins/remote-env-local-docker.js +40 -12
- package/dist/plugins/retention-store-sql.d.ts +2 -2
- package/dist/plugins/run-store-sql.d.ts +9 -1
- package/dist/plugins/run-store-sql.js +9 -1
- package/dist/plugins/sandbox-read-floor.d.ts +5 -7
- package/dist/plugins/sandbox-read-floor.js +2 -7
- package/dist/plugins/sql-errors.d.ts +10 -1
- package/dist/plugins/sql-errors.js +13 -0
- package/dist/plugins/store-backend.d.ts +33 -35
- package/dist/plugins/store-backend.js +10 -1
- package/dist/plugins/store-contracts.d.ts +50 -1
- package/dist/plugins/store-contracts.js +6 -0
- package/dist/plugins/task-attachment-store.d.ts +112 -14
- package/dist/plugins/task-attachment-store.js +207 -29
- package/dist/plugins/tool-result-store-sql.d.ts +9 -8
- package/dist/plugins/tool-result-store-sql.js +23 -2
- package/dist/plugins/wiring-section-codec.d.ts +32 -0
- package/dist/plugins/wiring-section-codec.js +55 -0
- package/dist/plugins/workspace-fill.d.ts +60 -0
- package/dist/plugins/workspace-fill.js +106 -0
- package/dist/project-bundle.d.ts +38 -0
- package/dist/project-bundle.js +609 -0
- package/dist/rule-entry-list.d.ts +3 -2
- package/dist/rule-entry-list.js +5 -1
- package/dist/rules-consent.d.ts +28 -5
- package/dist/rules-consent.js +40 -28
- package/dist/run-local.js +11 -13
- package/dist/runs.d.ts +12 -8
- package/dist/runs.js +6 -8
- package/dist/runtime-governance.d.ts +1 -1
- package/dist/sandbox-egress-policy.d.ts +4 -1
- package/dist/sandbox-egress-policy.js +3 -1
- package/dist/sandbox-git-plane.d.ts +31 -12
- package/dist/sandbox-git-plane.js +24 -4
- package/dist/security.d.ts +9 -0
- package/dist/security.js +8 -0
- package/dist/server-secret-env.d.ts +4 -0
- package/dist/session-error-wire.d.ts +36 -0
- package/dist/session-error-wire.js +13 -0
- package/dist/session-incarnation.d.ts +1 -1
- package/dist/session-notify-door.d.ts +106 -0
- package/dist/session-notify-door.js +93 -0
- package/dist/session-sync.d.ts +9 -14
- package/dist/session-sync.js +5 -5
- package/dist/session-workspace.d.ts +3 -13
- package/dist/session-workspace.js +0 -9
- package/dist/standing-answer-grant.d.ts +5 -0
- package/dist/standing-answer-grant.js +10 -0
- package/dist/stores-sql/session-policy-store-sql.d.ts +4 -2
- package/dist/stores-sql/session-policy-store-sql.js +3 -13
- package/dist/task-mcp.d.ts +1 -1
- package/dist/task-settings.d.ts +21 -10
- package/dist/task-settings.js +46 -13
- package/dist/terminal.d.ts +39 -19
- package/dist/terminal.js +65 -22
- package/dist/tool-approval.d.ts +56 -37
- package/dist/tool-approval.js +78 -71
- package/dist/trace/core-keyset-guard.d.ts +134 -14
- package/dist/trace/engine-notice-wire.d.ts +9 -3
- package/dist/trace/engine-notice-wire.js +7 -3
- package/dist/trace/exit-seat.d.ts +9 -2
- package/dist/trace/exit-seat.js +1 -0
- package/dist/trace/ledger-sink.d.ts +10 -6
- package/dist/trace/ledger-sink.js +2 -2
- package/dist/trace/model-segment.d.ts +55 -25
- package/dist/trace/model-segment.js +101 -33
- package/dist/trace/project.d.ts +25 -5
- package/dist/trace/project.js +22 -0
- package/dist/trace/redact.d.ts +61 -9
- package/dist/trace/redact.js +1490 -468
- package/dist/trace/self-minted-wire.d.ts +745 -24
- package/dist/trace/self-minted-wire.js +239 -9
- package/dist/trace/wire-projection-faces.d.ts +2 -2
- package/dist/trace/wire-projection-faces.js +2 -2
- package/dist/verifier-pause-card.d.ts +33 -5
- package/dist/verifier-pause-card.js +15 -10
- package/dist/web-admin-client/apply-effective.d.ts +12 -16
- package/dist/web-admin-client/apply-effective.js +109 -9
- package/dist/web-admin-client/effective-keys.js +2 -0
- package/dist/web-admin-client/types.d.ts +4 -0
- package/dist/workspace-space.d.ts +19 -3
- package/dist/workspace-space.js +8 -4
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -1
- package/package.json +3 -2
- package/wire-changes/server@7.142.0.json +639 -0
- package/wire-changes/server@7.143.0.json +1167 -0
|
@@ -57,6 +57,12 @@
|
|
|
57
57
|
*
|
|
58
58
|
* core 给闭集加一个词 ⇒ 下面的 `switch` 编译红,由人裁定它在两面上的答复,而不是让它静默落进某个恰好存在的臂
|
|
59
59
|
* ([ref] 词表纪律;同形先例 `session-policy-wire.ts` 的 `sessionPolicyErrorHttp`)。
|
|
60
|
+
*
|
|
61
|
+
* ## 读一只会话的存档时的故障:一张表、两个读者({@link openFaceFaultWire})
|
|
62
|
+
* open 面映射有臂 ⇒ 那一格;否则(open 面留白的词,与不是 `SessionError` 的读故障 —— I/O 级的 EACCES / EISDIR …,core 的读腿只吞 ENOENT、其余 errno 原样抛)
|
|
63
|
+
* ⇒ 通用 500 {@link INTERNAL_ERROR_WIRE}。读者:① 全局兜底(`http/server.ts`:路由里逃出来的故障就按它答 —— 会话视图 / 头探针 / 事件流 / 改名门放行之后对坏档答的码
|
|
64
|
+
* 都出自这里);② 会话列表行的 `unreadable`({@link sessionUnreadableOf}:列表行 = 会话行,头的叶子读不出 ⇒ 行带标记,码 = 打开它时读口答的那一个)。
|
|
65
|
+
* 两个读者读同一只函数,列表说的码与读口答的码不会分叉。
|
|
60
66
|
*/
|
|
61
67
|
import { SessionError } from "@sema-agent/core";
|
|
62
68
|
/** core `SessionError` 的码闭集(core 不从包根导出这个型名 ⇒ 从导出类的 `code` 键派生,不手抄)。 */
|
|
@@ -96,6 +102,18 @@ export declare class StampedSessionArchiveError extends SessionError {
|
|
|
96
102
|
readonly sessionId: string;
|
|
97
103
|
constructor(sessionId: string);
|
|
98
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* local 店的具名拒(唯一铸点 `plugins/local-session-store.ts` 的 `metaRead`):这只会话的**属主读不出**。会话的行事实(属主 / 化身)只住在会话元数据边档的那一格;
|
|
107
|
+
* 7.104.0 之前写下、此后从没被读过的会话没有这一格,要从存档补铸它(第一次读时的惯例),存档又用不了(会话头坏 / 截断 / 日志结构走不通)——
|
|
108
|
+
* 于是没有任何一位调用方能被判成它的属主。要读它的行事实的店方法(`headOf` / 执行席的读 / 会话元数据读口)抛本错。
|
|
109
|
+
*
|
|
110
|
+
* 码与句子**就是**那只存档故障的(`cause` = 它;码不另铸 —— 只会是 `corrupt_session` / `invalid_session`,读不出而说不出在不在的 I/O 级故障不换型):
|
|
111
|
+
* 不认识本型的站点看到的与此前逐字相同(`sessionErrorHttp` 按码映射,wire 与运维日志不变)。认识本型的站点 —— 会话读面的属主读
|
|
112
|
+
* (`http/owner-access.ts` 的 `foldOwnerUnreadable`)—— 把它读成「没有这一行」:与对非属主、对不存在的会话同一只 404,原故障进运维日志。
|
|
113
|
+
*/
|
|
114
|
+
export declare class SessionOwnerUnreadableError extends SessionError {
|
|
115
|
+
constructor(code: "corrupt_session" | "invalid_session", fault: SessionError);
|
|
116
|
+
}
|
|
99
117
|
/** {@link StampedSessionArchiveError} 的 wire 固定句(fork 与改日志的推送同一句;不点名会话 id;出路在句里 —— 从头再同步照样撞)。 */
|
|
100
118
|
export declare const STAMPED_SESSION_ARCHIVE_SENTENCE = "this session's stored archive still carries an owner stamp written by an earlier server version, so it cannot be forked or have its log replaced; nothing was written \u2014 delete the session and push it again";
|
|
101
119
|
/**
|
|
@@ -103,6 +121,24 @@ export declare const STAMPED_SESSION_ARCHIVE_SENTENCE = "this session's stored a
|
|
|
103
121
|
* 按码答复不同),其余按码({@link sessionErrorHttp})。
|
|
104
122
|
*/
|
|
105
123
|
export declare function sessionErrorWireOf(e: SessionError, face: SessionErrorFace): SessionErrorWire | undefined;
|
|
124
|
+
/**
|
|
125
|
+
* 全局兜底的末臂:open 面映射没有臂的故障(登记过的留白词;不是 `SessionError` 的故障)⇒ 通用 500,句子固定(故障的原句只进运维日志 `request_error`,
|
|
126
|
+
* 不上 wire —— I/O 级的原句带 errno 与盘上路径)。
|
|
127
|
+
*/
|
|
128
|
+
export declare const INTERNAL_ERROR_WIRE: SessionErrorWire & {
|
|
129
|
+
readonly sentence: string;
|
|
130
|
+
};
|
|
131
|
+
/** 一只读存档的故障在 open 面上的 wire 答复(两个读者见文件头注「一张表、两个读者」):有臂 ⇒ 那一格;否则 {@link INTERNAL_ERROR_WIRE}。 */
|
|
132
|
+
export declare function openFaceFaultWire(fault: unknown): SessionErrorWire;
|
|
133
|
+
/**
|
|
134
|
+
* 会话列表行的加性键 `unreadable`:这只会话的头的叶子读不出(存档读不出)。present-iff 读不出;`errorCode` = 读口打开这只会话时答的码
|
|
135
|
+
* (`GET /v1/sessions/:id` / `…/head` / `…/events` / `PATCH` 门放行之后)。今天读得到的值:`corrupt_session`(会话头坏)· `internal.error`(I/O 级)。
|
|
136
|
+
*/
|
|
137
|
+
export interface SessionUnreadable {
|
|
138
|
+
readonly errorCode: string;
|
|
139
|
+
}
|
|
140
|
+
/** {@link SessionUnreadable} 的唯一铸点(列表行的那只标记;码经 {@link openFaceFaultWire},与全局兜底同表)。 */
|
|
141
|
+
export declare function sessionUnreadableOf(fault: unknown): SessionUnreadable;
|
|
106
142
|
export declare function sessionErrorHttp(code: SessionErrorCode, face: SessionErrorFace): SessionErrorWire | undefined;
|
|
107
143
|
export declare function isSessionErrorCode(code: string): code is SessionErrorCode;
|
|
108
144
|
//# sourceMappingURL=session-error-wire.d.ts.map
|
|
@@ -13,6 +13,12 @@ export class StampedSessionArchiveError extends SessionError {
|
|
|
13
13
|
this.name = "StampedSessionArchiveError";
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
+
export class SessionOwnerUnreadableError extends SessionError {
|
|
17
|
+
constructor(code, fault) {
|
|
18
|
+
super(code, fault.message, fault);
|
|
19
|
+
this.name = "SessionOwnerUnreadableError";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
16
22
|
export const STAMPED_SESSION_ARCHIVE_SENTENCE = "this session's stored archive still carries an owner stamp written by an earlier server version, so it cannot be forked or have its log replaced; nothing was written — delete the session and push it again";
|
|
17
23
|
const CORRUPT_SESSION = { status: 500, errorCode: "corrupt_session" };
|
|
18
24
|
const STORED_LOG_INVALID = { status: 500, errorCode: "invalid_session" };
|
|
@@ -23,6 +29,13 @@ const STAMPED_SESSION_ARCHIVE = { status: 409, errorCode: "conflict", sentence:
|
|
|
23
29
|
export function sessionErrorWireOf(e, face) {
|
|
24
30
|
return e instanceof StampedSessionArchiveError ? STAMPED_SESSION_ARCHIVE : sessionErrorHttp(e.code, face);
|
|
25
31
|
}
|
|
32
|
+
export const INTERNAL_ERROR_WIRE = { status: 500, errorCode: "internal.error", sentence: "internal error" };
|
|
33
|
+
export function openFaceFaultWire(fault) {
|
|
34
|
+
return (fault instanceof SessionError ? sessionErrorWireOf(fault, "open") : undefined) ?? INTERNAL_ERROR_WIRE;
|
|
35
|
+
}
|
|
36
|
+
export function sessionUnreadableOf(fault) {
|
|
37
|
+
return { errorCode: openFaceFaultWire(fault).errorCode };
|
|
38
|
+
}
|
|
26
39
|
export function sessionErrorHttp(code, face) {
|
|
27
40
|
switch (code) {
|
|
28
41
|
case "corrupt_session":
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* 所以化身与属主不是同一条律(读法分三种,见下「两读」)。删除随行消失,同 id 重新登记铸新的。
|
|
12
12
|
* · **两读(住客的三种问法,各读各的格,不混用)**:
|
|
13
13
|
* K1 **住客自己的记录**(工作区、记忆、空间分区……按「这一位住客」落的东西)只按化身绑 —— 同一位住客的属主换代(推送重戳 / 认领)不换住客,记录照落;
|
|
14
|
-
* K2 **以「这一行的这一代」为条件的写**(执行放置的换绑 /
|
|
14
|
+
* K2 **以「这一行的这一代」为条件的写**(执行放置的换绑 / 收回、执行上下文的复核、会话通知门投递前的复核 —— 条目按属主排空)比属主与化身整对,判官 = core 的行期望判官 `sessionRowMatches`
|
|
15
15
|
* (`execution-placement.ts` 的 `sameOccupant`,SQL `incarnation = ? AND owner <=> ?` 的对位)—— 读与写之间属主换了一代 ⇒ 不是判过的那一行;
|
|
16
16
|
* K0 **只问属主的门**(授权门、暂存提交的属主 CAS)只读属主那一格。三种都读会话**行**;local 店的行 = 会话元数据边档那一格(引擎仓里的存档是匿名内容仓,
|
|
17
17
|
* 存档头上的属主不是行事实 —— `plugins/local-session-store.ts` 头注)。
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🔴 **会话通知门 —— 一只会话外的事件进一只会话,只有这一处,两臂**。
|
|
3
|
+
*
|
|
4
|
+
* ## 门
|
|
5
|
+
* · **目标** = 会话 + 调用方判过的那一位住客(那一次头读的属主与化身令牌)+ 那一位无主时条目盖谁。门**不**替调用方判授权(属主门在调用方);门只保证交到的是那一位。
|
|
6
|
+
* · **活**:这只会话在本副本有活流 —— 判据一读:`runStore.getActiveTaskId(会话)` 交回的 run 在本副本的活流登记簿里(`steerableRuns`,属主是 HTTP 服务)
|
|
7
|
+
* ⇒ core `TaskStream.notify(事件, { priority: "next" })`。core 铸 `task_type: "external"`(外来的事件穿不上引擎内部车道的类型),载荷校验 / 消毒 / 围栏全在
|
|
8
|
+
* core;档位**写死** `"next"`(最早边界投递;core 的无参缺省是收官座 `"later"`,不写就静默推迟到 run 收尾)。core 的明确拒(码以 `notify.` 开头)原样交回;
|
|
9
|
+
* 别的抛 = 活流刚收尾的竞态 ⇒ 落空闲臂。
|
|
10
|
+
* · **空闲**:这只会话的完成收件箱(`externalNotificationInboxEntry`,external 键域;脱敏 / 限长在入箱口内)⇒ 下次开流排空成 `task_notification` 帧。
|
|
11
|
+
* 部署没有收件箱 ⇒ 如实交回 `no_inbox`(调用方各自答:HTTP 门 501,引擎完成告警)。
|
|
12
|
+
* · **复核住客**:两臂的投递动作(注入 / 入箱)之前**紧邻**一次头读,与目标的住客比 —— 判官是仓里那一只 `sameOccupant`(`execution-placement.ts`:属主 ∧ 化身,
|
|
13
|
+
* 写口与执行上下文解析器判的也是它):不在 ⇒ `withdrawn: gone`;两样里任一样变了 ⇒ `withdrawn: replaced`。会话店不铸化身(嵌入方自建的店)时两侧都没有令牌,
|
|
14
|
+
* 判官只剩属主那一半:属主没变 ⇒ 投,变了 ⇒ 撤回。这一读是动作之前的最后一次让出:判活读(及活臂刚收尾时的那次注入)都在它前面 ——
|
|
15
|
+
* 令牌永不复用,此刻还是那一位 ⇒ 判活读那一刻也是那一位 ⇒ 判出的 run 是它的 run。
|
|
16
|
+
* · **条目属主** = 目标住客的属主(调用方判过的那一读;复核放行 ⇒ 与这一读的属主逐字相等);那一位无主 ⇒ `ownerlessEntryOwner`(调用方交)。
|
|
17
|
+
*
|
|
18
|
+
* ## 竞态(两个调用方同一句话,只写在这里)
|
|
19
|
+
* · 判活之后、注入之前活流收尾:core 对已收尾的 run 不抛,按会话暂存、本进程同一会话的下一个 run 开轮时投递(core `notify` 契约);抛了 ⇒ 空闲臂(入箱前再复核一次)。
|
|
20
|
+
* · 判空闲之后、入箱之前同一会话开了新流:新腿开流那一拍的排空可能已读过收件箱 ⇒ 这一条在**再下一次**开流排空(至少一次,晚一次开流)。
|
|
21
|
+
* · 跨副本:活流在别的副本 ⇒ 本副本判空闲 ⇒ 入箱(收件箱随 run 店同一后端,哪个副本开流都排得到)。
|
|
22
|
+
* · 复核之后、入箱写落库之前别的副本删了这只会话并同 id 重新登记:条目带的是判过那一位的属主 —— 排空时按属主比开流者,另一位属主排不到;
|
|
23
|
+
* 同一属主重新登记的那一只会排到它(余窗 = 一次入箱写的时长;这一形不再收窄)。
|
|
24
|
+
*
|
|
25
|
+
* ## 调用方(两只,都经 {@link SessionNotifyDoor.deliver},不各写一份臂)
|
|
26
|
+
* · `POST /v1/sessions/:id/notify`(`http/routes/notify-wake.ts`):入站鉴权、验型、属主门在路由;属主 = 会话行的属主。
|
|
27
|
+
* · **Runner 之外的后台子代完成**({@link createBackgroundCompletionRelay}):停驻赎回腿的复活、操作员 `handle.resume` —— 这些续跑不是哪一次 run 内的调用,
|
|
28
|
+
* 没有调用车道(`ToolExecuteContext.onTaskNotification`),引擎把完成交给委派工具挂载期的 `background.notify`;那只 sink 在 `capabilities/scenarios.ts` 接一次,
|
|
29
|
+
* 交到委派树根会话的这只门。Runner 之内的调用照旧走调用车道(引擎 `resolveCompletionSink` = 调用 ?? 挂载),这只门不经手。
|
|
30
|
+
*/
|
|
31
|
+
import type { ExternalNotificationInput, SessionHead, SubagentToolOptions, TaskStream } from "@sema-agent/core";
|
|
32
|
+
import { type WorkflowCompletionInbox } from "./orchestration/workflow-completion-inbox.js";
|
|
33
|
+
import type { DelegationRootWitness } from "./delegated-session-owner.js";
|
|
34
|
+
import type { HeadRead } from "./session-incarnation.js";
|
|
35
|
+
import type { Logger } from "./observability/logger.js";
|
|
36
|
+
/** 门的一次投递结局(闭集;调用方 `switch` 穷尽)。 */
|
|
37
|
+
export type SessionNotifyOutcome = {
|
|
38
|
+
readonly delivery: "live";
|
|
39
|
+
} | {
|
|
40
|
+
readonly delivery: "parked";
|
|
41
|
+
}
|
|
42
|
+
/** core 的明确拒(`notify.invalid_payload` 等):码与句原样。 */
|
|
43
|
+
| {
|
|
44
|
+
readonly delivery: "refused";
|
|
45
|
+
readonly code: string;
|
|
46
|
+
readonly message: string;
|
|
47
|
+
}
|
|
48
|
+
/** 会话空闲而部署没有收件箱:这一条无处可放。 */
|
|
49
|
+
| {
|
|
50
|
+
readonly delivery: "no_inbox";
|
|
51
|
+
}
|
|
52
|
+
/** 投递动作之前的复核:会话不在(`gone`)/ 住客不是目标那一位(`replaced`)⇒ 没交。 */
|
|
53
|
+
| {
|
|
54
|
+
readonly delivery: "withdrawn";
|
|
55
|
+
readonly reason: "gone" | "replaced";
|
|
56
|
+
};
|
|
57
|
+
/** 投递目标。 */
|
|
58
|
+
export interface SessionNotifyTarget {
|
|
59
|
+
readonly sessionId: string;
|
|
60
|
+
/** 调用方判过的那一位住客:那一次头读的属主与化身令牌(化身缺席 = 那一读里没有令牌;复核见头注)。它的属主也是收件箱条目的属主(排空时与开流者比对)。 */
|
|
61
|
+
readonly occupant: Pick<SessionHead, "owner" | "incarnation">;
|
|
62
|
+
/** 那一位无主(`occupant.owner === null`)时条目盖的属主(`null` = 无主条目,谁开流都排)。 */
|
|
63
|
+
readonly ownerlessEntryOwner: string | null;
|
|
64
|
+
}
|
|
65
|
+
export interface SessionNotifyDoor {
|
|
66
|
+
deliver(target: SessionNotifyTarget, event: ExternalNotificationInput): Promise<SessionNotifyOutcome>;
|
|
67
|
+
}
|
|
68
|
+
/** 门要读的四样(都由 HTTP 服务交:活流登记簿是它的,run 店、会话店与收件箱是它的依赖)。 */
|
|
69
|
+
export interface SessionNotifyDoorIo {
|
|
70
|
+
/** 会话 → 它的在飞 run(run 店的单活认领读)。部署没有 run 店 ⇒ 交 `undefined` ⇒ 恒判空闲。读失败按空闲。 */
|
|
71
|
+
readonly activeTaskIdOf: (sessionId: string) => Promise<string | null | undefined>;
|
|
72
|
+
/** 本副本持活 core 流的腿(taskId → 流)。 */
|
|
73
|
+
readonly liveRuns: ReadonlyMap<string, Pick<TaskStream, "notify">>;
|
|
74
|
+
readonly inbox: WorkflowCompletionInbox | undefined;
|
|
75
|
+
/** 会话店的按 id 头读(复核住客的那一读)。店没有 ⇒ `undefined`:调用方先判(路由 501;后台完成 relay 照交,门响亮抛 ⇒ relay 告警)。 */
|
|
76
|
+
readonly headOf: HeadRead | undefined;
|
|
77
|
+
}
|
|
78
|
+
export declare function createSessionNotifyDoor(io: SessionNotifyDoorIo): SessionNotifyDoor;
|
|
79
|
+
/** 委派工具挂载期的完成 sink 的型(取自 core 的选项型,不手抄)。 */
|
|
80
|
+
export type BackgroundCompletionSink = NonNullable<NonNullable<SubagentToolOptions["background"]>["notify"]>;
|
|
81
|
+
/** 把一只委派树根见证变成挂载期 sink 的工厂(`ScenarioDeps.backgroundCompletionSinkFor` 的型)。 */
|
|
82
|
+
export type BackgroundCompletionSinkFor = (root: DelegationRootWitness) => BackgroundCompletionSink;
|
|
83
|
+
export interface BackgroundCompletionRelayIo {
|
|
84
|
+
/** 会话通知门。门的属主是 HTTP 服务、场景层先于它装配 ⇒ 晚绑取值;未绑 ⇒ 交不出去(告警)。 */
|
|
85
|
+
readonly door: () => SessionNotifyDoor | undefined;
|
|
86
|
+
/** 交不出去的那一行告警写到这里(本仓的 `Logger`:写口自己吞掉输出故障、不抛 —— relay 的收尾臂依赖这一条)。 */
|
|
87
|
+
readonly logger: Pick<Logger, "warn">;
|
|
88
|
+
}
|
|
89
|
+
/** 交不出去的成因(闭集;告警 `background_completion_undelivered` 的 `reason`)。 */
|
|
90
|
+
export type BackgroundCompletionUndelivered = "root_gone" | "root_replaced" | "door_unbound" | "refused" | "no_inbox" | "relay_failed";
|
|
91
|
+
/**
|
|
92
|
+
* **Runner 之外的后台子代完成 → 委派树根会话的会话通知门**(挂载期 `background.notify` 的唯一实现)。
|
|
93
|
+
*
|
|
94
|
+
* · **地址** = 场景层交出的委派树根见证(`ScenarioContext.delegationRoot`:会话 id + 判断那一刻的根住客)—— 停驻赎回面按行上的 `rootSessionId`
|
|
95
|
+
* 与赎回腿写口放行的那一位住客交,请求腿按本请求会话与受理时那一读交;不读完成帧上的任何键定址。一层行的根就是父会话;更深的行(孙代)报给根 ——
|
|
96
|
+
* 委派终态的受众是整棵委派树的根会话(孙代的父是一只没人开流的委派会话,交给它等于没交)。
|
|
97
|
+
* · **目标住客 = 见证的那一位**(属主与化身,见证铸点那一读):门在投递动作之前紧邻地复核(头注「复核住客」)—— 不在 ⇒ 不交(`root_gone`);
|
|
98
|
+
* 不是见证的那一位(删了、同 id 被重新登记、属主变了)⇒ 不交(`root_replaced`):这棵树的结果不交给同 id 的下一位住客。条目属主 = 见证的属主;
|
|
99
|
+
* 根无主 ⇒ 无主条目(relay 不是谁的请求,没有请求主体可落)。见证那一读里根行不在(化身 `null`)⇒ 目标住客 = 「无主、无令牌」,只有不铸化身的店上
|
|
100
|
+
* 此刻也无主的根与它同(铸化身的店上它恒不同 ⇒ 不交,与停驻挂点「见证不在而根在 ⇒ 否决」同向)。
|
|
101
|
+
* · **事件** = 完成帧的 `task_id` / `status` / `summary` / `result` / `seq`(后台子代的 `seq` = 停驻周期号,同一只子代两次复活的完成在收件箱折叠键上不相撞)。
|
|
102
|
+
* 帧上别的键不过门:门的事件型只有这几位(活臂 core 铸 external,空闲臂入箱同一形),两臂一个形。
|
|
103
|
+
* · 交不出去一律一行 warn(`background_completion_undelivered`,带成因),不抛回引擎(sink 是 fire-and-forget)。
|
|
104
|
+
*/
|
|
105
|
+
export declare function createBackgroundCompletionRelay(io: BackgroundCompletionRelayIo): BackgroundCompletionSinkFor;
|
|
106
|
+
//# sourceMappingURL=session-notify-door.d.ts.map
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { externalNotificationInboxEntry } from "./orchestration/workflow-completion-inbox.js";
|
|
2
|
+
import { sameOccupant } from "./execution-placement.js";
|
|
3
|
+
export function createSessionNotifyDoor(io) {
|
|
4
|
+
async function recheck(target) {
|
|
5
|
+
if (io.headOf === undefined)
|
|
6
|
+
throw new Error("session notify door: the session store has no head read (headOf); the occupant cannot be re-checked before delivery");
|
|
7
|
+
const head = await io.headOf(target.sessionId);
|
|
8
|
+
if (head === undefined)
|
|
9
|
+
return { delivery: "withdrawn", reason: "gone" };
|
|
10
|
+
return sameOccupant(target.occupant, head) ? undefined : { delivery: "withdrawn", reason: "replaced" };
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
async deliver(target, event) {
|
|
14
|
+
const liveTaskId = await io.activeTaskIdOf(target.sessionId).catch(() => undefined);
|
|
15
|
+
if (liveTaskId !== undefined && liveTaskId !== null && io.liveRuns.has(liveTaskId)) {
|
|
16
|
+
const withdrawn = await recheck(target);
|
|
17
|
+
if (withdrawn !== undefined)
|
|
18
|
+
return withdrawn;
|
|
19
|
+
const live = io.liveRuns.get(liveTaskId);
|
|
20
|
+
if (live !== undefined) {
|
|
21
|
+
try {
|
|
22
|
+
await live.notify(event, { priority: "next" });
|
|
23
|
+
return { delivery: "live" };
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
const code = e.code;
|
|
27
|
+
if (typeof code === "string" && code.startsWith("notify."))
|
|
28
|
+
return { delivery: "refused", code, message: e instanceof Error ? e.message : "invalid notification" };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (io.inbox === undefined)
|
|
33
|
+
return { delivery: "no_inbox" };
|
|
34
|
+
const withdrawn = await recheck(target);
|
|
35
|
+
if (withdrawn !== undefined)
|
|
36
|
+
return withdrawn;
|
|
37
|
+
await io.inbox.enqueue(externalNotificationInboxEntry(target.sessionId, target.occupant.owner ?? target.ownerlessEntryOwner, { task_type: "external", ...event }, Date.now()));
|
|
38
|
+
return { delivery: "parked" };
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export function createBackgroundCompletionRelay(io) {
|
|
43
|
+
return (root) => (n) => {
|
|
44
|
+
void relayToRoot(io, root, n).catch((err) => io.logger.warn("background_completion_undelivered", { ...completionFields(root, n), reason: "relay_failed", error: err instanceof Error ? err.message : String(err) }));
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
async function relayToRoot(io, root, n) {
|
|
48
|
+
const undelivered = (reason, extra) => io.logger.warn("background_completion_undelivered", { ...completionFields(root, n), reason, ...extra });
|
|
49
|
+
const door = io.door();
|
|
50
|
+
if (door === undefined)
|
|
51
|
+
return undelivered("door_unbound");
|
|
52
|
+
const out = await door.deliver({ sessionId: root.sessionId, occupant: { owner: root.owner, incarnation: root.incarnation ?? undefined }, ownerlessEntryOwner: null }, completionEvent(n));
|
|
53
|
+
switch (out.delivery) {
|
|
54
|
+
case "live":
|
|
55
|
+
case "parked":
|
|
56
|
+
return;
|
|
57
|
+
case "refused":
|
|
58
|
+
return undelivered("refused", { code: out.code });
|
|
59
|
+
case "no_inbox":
|
|
60
|
+
return undelivered("no_inbox");
|
|
61
|
+
case "withdrawn":
|
|
62
|
+
return undelivered(withdrawnReason(out.reason));
|
|
63
|
+
default: {
|
|
64
|
+
const unhandled = out;
|
|
65
|
+
throw new Error(`unhandled session notify outcome: ${JSON.stringify(unhandled)}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function withdrawnReason(reason) {
|
|
70
|
+
switch (reason) {
|
|
71
|
+
case "gone":
|
|
72
|
+
return "root_gone";
|
|
73
|
+
case "replaced":
|
|
74
|
+
return "root_replaced";
|
|
75
|
+
default: {
|
|
76
|
+
const unhandled = reason;
|
|
77
|
+
throw new Error(`unhandled withdrawn reason: ${JSON.stringify(unhandled)}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function completionEvent(n) {
|
|
82
|
+
return {
|
|
83
|
+
task_id: n.task_id,
|
|
84
|
+
status: n.status,
|
|
85
|
+
summary: n.summary,
|
|
86
|
+
...(n.result !== undefined ? { result: n.result } : {}),
|
|
87
|
+
...(n.seq !== undefined ? { seq: n.seq } : {}),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function completionFields(root, n) {
|
|
91
|
+
return { sessionId: root.sessionId, taskId: n.task_id, taskType: n.task_type, status: n.status };
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=session-notify-door.js.map
|
package/dist/session-sync.d.ts
CHANGED
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
import type { StoreBackend } from "./plugins/store-backend.js";
|
|
47
47
|
import { type SyncRelation } from "./session-sync-kernel.js";
|
|
48
48
|
import { type SessionTreeEntry, type SessionRulesRecord, type FileHistoryError, type FileHistoryExport, type FileHistoryResult, type SessionPermissionRules, type StoredSessionRules, type SessionPolicyStore } from "@sema-agent/core";
|
|
49
|
-
import type { ServiceFileHistoryStore, ServiceSessionPolicyStore, ResumeAnchorStore } from "./plugins/store-backend.js";
|
|
49
|
+
import type { ServiceBlobExchange, ServiceFileHistoryStore, ServiceSessionPolicyStore, ResumeAnchorStore } from "./plugins/store-backend.js";
|
|
50
50
|
/**
|
|
51
51
|
* core 7.55.0 [ref] T2([ref]):一只会话的文件历史**读不全**(撕裂 / 读不出的边界、读不出的跟踪集 —— 店的 `exportHistory` 答 `{ ok: false }`,`adopt_failed`
|
|
52
52
|
* 带店判的 `permanence`)。它**不是**「没有历史」:读成 `null` 的同步会把这只会话的全部 rewind 历史丢在路上、还答成功。会话同步的两只拉取口
|
|
@@ -67,20 +67,15 @@ export declare function exportedFileHistory(store: Pick<ServiceFileHistoryStore,
|
|
|
67
67
|
* Returned by {@link exportSessionManifest} (closes over the source store); consumed wherever a caller pulls
|
|
68
68
|
* content-addressed history bytes lazily (the live PUSH route's `importHistory` replay). */
|
|
69
69
|
export type BlobGetter = (hash: string) => Promise<Uint8Array | undefined>;
|
|
70
|
-
/** blob 两面(`putBlob` / `getBlob`)齐备的文件历史店(marker 门,不做名字探测:local 的引擎文件店带同名私有助手)。 */
|
|
71
|
-
export type SyncBlobHistoryStore = ServiceFileHistoryStore & {
|
|
72
|
-
readonly syncBlobFaces: true;
|
|
73
|
-
} & {
|
|
74
|
-
[P in "putBlob" | "getBlob"]-?: NonNullable<ServiceFileHistoryStore[P]>;
|
|
75
|
-
};
|
|
76
70
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
71
|
+
* 「这只文件历史店能不能交换 blob」的**唯一**读法:店的 `blobExchange` 组,经 core 的判官 `fileHistoryBlobExchangeOf` 读 —— 没有组 ⇒ `undefined`
|
|
72
|
+
* (core 的 local 文件店);整组 ⇒ 三只成员(判官已绑好);缺一员 / 组不是对象 / 店还带退役的标记词 ⇒ 判官拒(`config.invalid_argument`,响亮,不是「没有」)。
|
|
73
|
+
* 能力事实 `sessionSyncFileHistory`(capability-facts)与取值口 {@link blobGetterOf} 都读它 —— 事实说有,取值口就通到同一组的 `get`;事实说没有,取值口恒空。
|
|
74
|
+
* 返回型收窄到本仓的 {@link ServiceBlobExchange}:判官交回的是店自己那一组的成员(只绑定、不包装),店型声明的组就是那一型。
|
|
80
75
|
*/
|
|
81
|
-
export declare function
|
|
82
|
-
/** 一只文件历史店自己的 blob 取值口({@link BlobGetter}):从 {@link
|
|
83
|
-
* 拉取面(manifest 的 `getBlob`)、identical
|
|
76
|
+
export declare function blobExchangeOf(store: ServiceFileHistoryStore): ServiceBlobExchange | undefined;
|
|
77
|
+
/** 一只文件历史店自己的 blob 取值口({@link BlobGetter}):从 {@link blobExchangeOf} 派生 —— 有交换组 ⇒ 组的 `get`;没有(core 的 local 文件店)⇒ 恒答 `undefined`(「这里取不到」)。
|
|
78
|
+
* 拉取面(manifest 的 `getBlob`)、identical 自愈臂、提交臂三处读同一只,不各写一份「无组则 undefined」。 */
|
|
84
79
|
export declare function blobGetterOf(store: ServiceFileHistoryStore): BlobGetter;
|
|
85
80
|
/** The history-import capability face of a `FileHistoryStore` (`importHistory` is OPTIONAL on the core
|
|
86
81
|
* contract — a store without it cannot be a 2c history sink). */
|
|
@@ -123,7 +118,7 @@ export type FileHistoryReplayFailure = Extract<FileHistoryReplayResult, {
|
|
|
123
118
|
* The alternative (keeping the old graph) would wedge every retry on the same typed conflict forever.
|
|
124
119
|
*
|
|
125
120
|
* 缺 blob 的事实只在这里读一次:每次尝试给店的 getter 都包一层观察,店取到 `undefined` 就记下那枚 hash(按次计,替换臂的第二次尝试从空白起),
|
|
126
|
-
* 失败时随结果交出({@link FileHistoryReplayResult.missingBlob})。预检({@link sessionSyncFileHistory} 事实 + `
|
|
121
|
+
* 失败时随结果交出({@link FileHistoryReplayResult.missingBlob})。预检({@link sessionSyncFileHistory} 事实 + 交换组的 `has`)管「这台部署根本收不到 / 索引里没有」,
|
|
127
122
|
* 这里管「预检过了而这一枚取不到」(对象存储里已丢 / 校验和不符按缺席读 / 预检与重放之间被孤儿回收清走)—— 同一只不变量的两端,wire 上同一个词。
|
|
128
123
|
*/
|
|
129
124
|
export declare function replayFileHistory(store: ServiceFileHistoryStore, scope: string, envelope: FileHistoryExport, srcGetBlob: BlobGetter, opts: {
|
package/dist/session-sync.js
CHANGED
|
@@ -2,7 +2,7 @@ import { anchorEntryDeclared, classifySyncRelationship } from "./session-sync-ke
|
|
|
2
2
|
import { recordFailOpen } from "./observability/fail-open.js";
|
|
3
3
|
import { loosenReasons, normalizeRules } from "@sema-agent/core";
|
|
4
4
|
import { headReadOf } from "./session-incarnation.js";
|
|
5
|
-
import { judgeSessionRulesWrite } from "@sema-agent/core";
|
|
5
|
+
import { fileHistoryBlobExchangeOf, judgeSessionRulesWrite } from "@sema-agent/core";
|
|
6
6
|
export class FileHistoryUnreadableError extends Error {
|
|
7
7
|
sessionId;
|
|
8
8
|
failure;
|
|
@@ -22,12 +22,12 @@ export async function exportedFileHistory(store, sessionId) {
|
|
|
22
22
|
throw new FileHistoryUnreadableError(sessionId, exported.error);
|
|
23
23
|
return exported.history;
|
|
24
24
|
}
|
|
25
|
-
export function
|
|
26
|
-
return store
|
|
25
|
+
export function blobExchangeOf(store) {
|
|
26
|
+
return fileHistoryBlobExchangeOf(store);
|
|
27
27
|
}
|
|
28
28
|
export function blobGetterOf(store) {
|
|
29
|
-
const
|
|
30
|
-
return
|
|
29
|
+
const exchange = blobExchangeOf(store);
|
|
30
|
+
return exchange ? exchange.get : async () => undefined;
|
|
31
31
|
}
|
|
32
32
|
export function fileHistoryImportFace(fs) {
|
|
33
33
|
const candidate = fs?.importHistory;
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* 门在 `trace/core-keyset-guard.ts` ⑰ 读同一张表)。**唯一写者** = 腿的记录座 {@link createSessionWorkspaceRecorder}
|
|
12
12
|
* (持流的四条腿逐帧喂同一只;委派子代转上来的帧 —— 带 `parentToolCallId` / `sourceTaskId` / `bgAgentId` —— 不是这条腿的位置,不认)。
|
|
13
13
|
* 每一笔写**在腿的流循环里等完**(不排队、没有在飞的写:腿从任何出口离开时都没有它的写还悬着 ⇒ 写恒落在这条腿的 run 认领之内,
|
|
14
|
-
* 同一会话的下一条腿不会被一笔晚到的写盖掉),并且**只写受理时见证到的那一位住客**(
|
|
14
|
+
* 同一会话的下一条腿不会被一笔晚到的写盖掉),并且**只写受理时见证到的那一位住客**(这条腿的部署事实 `sessionWitness`,`leg-facts.ts`:resolveSpec
|
|
15
15
|
* 受理时读会话行的化身那一读,同一只值也是委派树根的见证)—— 会话被删掉又以同一 id 重建之后,上一位住客的腿写不进新住客的行。
|
|
16
16
|
* · **每条腿声明一个值**:`TaskSpec.projectId` = 这次提交自己带的 `projectId`(新提交的请求体;续跑腿重放的是持久化的同一个体)
|
|
17
17
|
* ?? 会话行上最后一帧的 `project.id` —— **只当它是调用方声明过的**(`source: "declared"`:没有记号的检出里声明就是身份,行存它就是为了接着声明);
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
* · **行读在 run 认领之前**(resolveSpec 的每一读都是):同一会话两次提交交叠、后一次的装配读行之后前一次才落定并放认领 ⇒ 后一次读到的是更早
|
|
35
35
|
* 一条腿的项目(有记号的检出里多一次 409,没有记号的检出里续声明旧项目)。修法要把声明的装配挪到认领之后,不在本模块补第二个写者。
|
|
36
36
|
*/
|
|
37
|
-
import type { TaskEvent
|
|
37
|
+
import type { TaskEvent } from "@sema-agent/core";
|
|
38
38
|
import type { DelegationRootWitness } from "./delegated-session-owner.js";
|
|
39
39
|
/**
|
|
40
40
|
* `workspace_changed` 帧在会话行上的样子(**唯一**一张表;表序 = 存储形的键序)。`forward` = 原值存进行;`strip` = 不进行。
|
|
@@ -84,16 +84,6 @@ export interface SessionWorkspaceStore {
|
|
|
84
84
|
}
|
|
85
85
|
/** 店有没有这一面 —— 结构判(包装店 `CachingSessionStore` 逐方法转发,判的是能力不是名字)。没有 ⇒ 不记、不读(core 的内存 dev 店)。 */
|
|
86
86
|
export declare function sessionWorkspaceStoreOf(store: unknown): SessionWorkspaceStore | undefined;
|
|
87
|
-
/**
|
|
88
|
-
* 这条腿的会话**在受理时**是哪一位住客(会话 id + 化身令牌)的 spec 字段键 —— 与 run 名册 / 执行车道字段同一形:symbol 键随 spread / rest 解构走
|
|
89
|
-
* (续跑腿的 `taskConfig` 是 rest 解构出来的),对引擎的键面不可见(JSON / 结构化克隆跳过 symbol 键)。铸点唯一 = resolveSpec 出口
|
|
90
|
-
* ({@link stampLegSessionWitness}),值 = 受理时读会话行的那**一**读(同一只值也交给场景层作委派树根的见证);读点唯一 = {@link legSessionWitnessOf}。
|
|
91
|
-
*/
|
|
92
|
-
export declare const LEG_SESSION_WITNESS_FIELD: unique symbol;
|
|
93
|
-
/** 铸见证(**单一属主**:只许 resolveSpec 的出口调用)。`writable:false` + `configurable:false`:同一只 spec 被第二次铸 ⇒ 当场 TypeError。缺席 ⇒ 不铸。 */
|
|
94
|
-
export declare function stampLegSessionWitness<T extends TaskSpec>(spec: T, witness: DelegationRootWitness | undefined): T;
|
|
95
|
-
/** 读见证。`undefined` = 这只 spec 不是本仓装配出口产的,或这条腿没有会话 ⇒ 记录座不写(没有住客可认)。入参收 `object`:续跑腿手里是 rest 解构出来的 taskConfig。 */
|
|
96
|
-
export declare function legSessionWitnessOf(spec: object): DelegationRootWitness | undefined;
|
|
97
87
|
/**
|
|
98
88
|
* 一帧 → 会话行上那一格的值。只认这条腿**自己的**帧(腿身份三键任一在场 = 委派子代转上来的,不是这条腿站在哪里);
|
|
99
89
|
* 按表投影后过存储形的同一只读者(写得进的就是读得出的)。读不出(引擎不会铸出这种帧)⇒ 不记、计一次。
|
|
@@ -109,7 +99,7 @@ export interface SessionWorkspaceRecorder {
|
|
|
109
99
|
}
|
|
110
100
|
/**
|
|
111
101
|
* 记录座的**唯一**铸点(四条持流腿各在开流时铸一只:后台腿 `runs.ts`、活流腿与同步腿 `http/routes/tasks.ts`、续跑腿 `http/resume-legs.ts`),
|
|
112
|
-
* `witness` =
|
|
102
|
+
* `witness` = 这条腿的受理见证(部署事实 `LegFacts.sessionWitness`,`leg-facts.ts`;嵌入方自带装配器 ⇒ 缺席)。店没有这一面、或见证缺席 / 受理时这只会话还没有住客令牌 ⇒
|
|
113
103
|
* 一只什么都不做的座(诚实缺席:认不出住客就不写 —— 写错住客比少记一次坏)。
|
|
114
104
|
*
|
|
115
105
|
* 失败方向(F 类):写失败(库抖 / 盘满 / 锁等待超时)⇒ 行停在上一帧,计一次;下一帧照写。放行的最坏后果 = 下一条不带 `projectId` 的提交读到旧的
|
|
@@ -19,15 +19,6 @@ export function sessionWorkspaceStoreOf(store) {
|
|
|
19
19
|
return undefined;
|
|
20
20
|
return { readSessionWorkspace: s.readSessionWorkspace.bind(s), recordSessionWorkspace: s.recordSessionWorkspace.bind(s) };
|
|
21
21
|
}
|
|
22
|
-
export const LEG_SESSION_WITNESS_FIELD = Symbol("sema-server.legSessionWitness");
|
|
23
|
-
export function stampLegSessionWitness(spec, witness) {
|
|
24
|
-
if (witness !== undefined)
|
|
25
|
-
Object.defineProperty(spec, LEG_SESSION_WITNESS_FIELD, { value: Object.freeze({ ...witness }), enumerable: true, writable: false, configurable: false });
|
|
26
|
-
return spec;
|
|
27
|
-
}
|
|
28
|
-
export function legSessionWitnessOf(spec) {
|
|
29
|
-
return spec[LEG_SESSION_WITNESS_FIELD];
|
|
30
|
-
}
|
|
31
22
|
export function sessionWorkspaceOfFrame(ev) {
|
|
32
23
|
if (ev.type !== "workspace_changed")
|
|
33
24
|
return undefined;
|
|
@@ -35,6 +35,11 @@ export type GrantBinding = {
|
|
|
35
35
|
/** 载体上的授予绑定 —— 只读引擎的词(读法见文件头注):摘要是串 ⇒ bound;摘要不在且词是 `not_bindable` ⇒ none;其余 ⇒ unreadable。
|
|
36
36
|
* 形参是任意对象(载体不论):读自持久层的停驻行(运维队列行的投影、`/decide` 的原始行)两座都按 `unknown` 读,结构上满足 {@link StandingAnswerCard} 的载体照传。 */
|
|
37
37
|
export declare function grantBindingOf(card: StandingAnswerCard | object): GrantBinding;
|
|
38
|
+
/**
|
|
39
|
+
* 同一只问的两份授予绑定读数取严(7.143.0;读者 = `tool-approval.ts` 幂等重入那一臂:这一腿的请求 × 行上记着的事实座)。
|
|
40
|
+
* 两份逐臂同 ⇒ 那一份;不同(含任一份 `unreadable`)⇒ `unreadable`(本会话放行记不住)。只收窄、永不放宽任一份。
|
|
41
|
+
*/
|
|
42
|
+
export declare function agreedGrantBinding(a: GrantBinding, b: GrantBinding): GrantBinding;
|
|
38
43
|
/** 授予绑定在读面上的形:恰一臂 —— 摘要,或缺席词(闭集 core `BOUND_GRANT_ABSENCES`)。 */
|
|
39
44
|
export type GrantBindingArm = {
|
|
40
45
|
readonly boundGrantDigest: string;
|
|
@@ -7,6 +7,16 @@ export function grantBindingOf(card) {
|
|
|
7
7
|
const word = "boundGrantAbsence" in card ? card.boundGrantAbsence : undefined;
|
|
8
8
|
return digest === undefined && word === NOT_BINDABLE ? { kind: "none" } : { kind: "unreadable" };
|
|
9
9
|
}
|
|
10
|
+
export function agreedGrantBinding(a, b) {
|
|
11
|
+
switch (a.kind) {
|
|
12
|
+
case "none":
|
|
13
|
+
return b.kind === "none" ? a : { kind: "unreadable" };
|
|
14
|
+
case "bound":
|
|
15
|
+
return b.kind === "bound" && b.digest === a.digest ? a : { kind: "unreadable" };
|
|
16
|
+
case "unreadable":
|
|
17
|
+
return a;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
10
20
|
export function grantBindingArm(binding) {
|
|
11
21
|
switch (binding.kind) {
|
|
12
22
|
case "bound":
|
|
@@ -86,8 +86,10 @@ export declare class SqlSessionPolicyStore implements SessionPolicyStore {
|
|
|
86
86
|
* `main`'s statement sequence, zero mark table involved): InnoDB 1 winner / 7 `ER_LOCK_DEADLOCK`, TiDB 0,
|
|
87
87
|
* PG 0 — i.e. this is a PRE-EXISTING MySQL-leg defect that [ref]'s lock-shape site made visible, not a new one.
|
|
88
88
|
* After the first insert commits, the retried writers find the row and take the UPDATE path (record lock,
|
|
89
|
-
* no gap) ⇒ the loop converges in one extra round per missing-row window; the bound is the suite's concurrency
|
|
90
|
-
*
|
|
89
|
+
* no gap) ⇒ the loop converges in one extra round per missing-row window; the bound is the suite's concurrency
|
|
90
|
+
* (a writer is picked at most once per missing-row window, and there are 1 + this round's erases of them) —
|
|
91
|
+
* the repo's one bound, `DEADLOCK_RETRY_LIMIT`, owned with the loop itself by `retryOnDeadlock` in `sql-errors.ts`.
|
|
92
|
+
* Lock-WAIT-TIMEOUT is deliberately NOT retried (`isDeadlockError`'s own note: it is a latency signal,
|
|
91
93
|
* and retrying it multiplies an already-long wait).
|
|
92
94
|
*/
|
|
93
95
|
private retrying;
|
|
@@ -4,10 +4,9 @@ import { SESSION_RULES_COLUMN } from "../plugins/session-rules-column.js";
|
|
|
4
4
|
import { decodeJsonColumn, isJsonColumnBodyProblem, jsonColumnText } from "../plugins/sql-json-column.js";
|
|
5
5
|
import { pgHasUnstorable } from "../plugins/pg-safe-json.js";
|
|
6
6
|
import { mysqlDriver, pgDriver } from "../plugins/sql-driver.js";
|
|
7
|
-
import {
|
|
7
|
+
import { isDupKeyError, retryOnDeadlock } from "../plugins/sql-errors.js";
|
|
8
8
|
export const policyKeyFor = (sessionId, principal) => createHash("sha256").update(JSON.stringify([sessionId, principal ?? null])).digest("hex");
|
|
9
9
|
const policyKey = policyKeyFor;
|
|
10
|
-
const RETRY_LIMIT = 8;
|
|
11
10
|
const RULES = SESSION_RULES_COLUMN.name;
|
|
12
11
|
export function readSessionRulesBody(body) {
|
|
13
12
|
const read = readSessionRulesShape(body);
|
|
@@ -129,17 +128,8 @@ export class SqlSessionPolicyStore {
|
|
|
129
128
|
return structuredClone({ ...clean, rev: nextRev, gen: nextGen });
|
|
130
129
|
}));
|
|
131
130
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
try {
|
|
135
|
-
return await attempt();
|
|
136
|
-
}
|
|
137
|
-
catch (e) {
|
|
138
|
-
if (tries < RETRY_LIMIT && (this.isDupKey(e) || isDeadlockError(this.db.dialect, e)))
|
|
139
|
-
continue;
|
|
140
|
-
throw e;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
131
|
+
retrying(attempt) {
|
|
132
|
+
return retryOnDeadlock(this.db.dialect, attempt, (e) => this.isDupKey(e));
|
|
143
133
|
}
|
|
144
134
|
async deleteBySession(sessionId) {
|
|
145
135
|
const sealed = await this.retrying(() => this.tx(async (conn) => {
|
package/dist/task-mcp.d.ts
CHANGED
|
@@ -71,7 +71,7 @@ export declare const MCP_SERVER_ENTRY_KEYS: readonly ["allowTools", "contentOrig
|
|
|
71
71
|
/** `transport.kind:"stdio"` 的键闭集 = stdio 臂处置表的键(`env` 是件,其余进声明)。 */
|
|
72
72
|
export declare const STDIO_MCP_TRANSPORT_KEYS: readonly ("env" | "kind" | "args" | "command")[];
|
|
73
73
|
/** `transport.kind:"http"` 的键闭集 = http 臂处置表的键(`headers` 是件,`assertionHeader` 承载不发送,其余进声明)。 */
|
|
74
|
-
export declare const HTTP_MCP_TRANSPORT_KEYS: readonly ("headers" | "
|
|
74
|
+
export declare const HTTP_MCP_TRANSPORT_KEYS: readonly ("headers" | "url" | "kind" | "principalHeader" | "assertionHeader")[];
|
|
75
75
|
/**
|
|
76
76
|
* Does THIS deployment honor caller-supplied per-request MCP servers? TRUE for a SINGLE-USER deployment
|
|
77
77
|
* (deployment-shape row `multiTenant` does not hold) — the requester is the super-admin of their own worker, so their `.mcp.json` is
|