@sema-agent/server 7.136.0 → 7.138.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION.md +501 -139
- package/README.md +1 -0
- package/README.zh-CN.md +1 -0
- package/USAGE.md +149 -34
- package/deploy/sema-up/README.md +14 -0
- package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +7 -1
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +7 -1
- package/dist/approval-card.d.ts +21 -14
- package/dist/approval-card.js +1 -0
- package/dist/approval-content-kind.d.ts +6 -0
- package/dist/approval-content-kind.js +7 -0
- package/dist/approval-gate-currency.d.ts +48 -6
- package/dist/approval-gate-currency.js +16 -9
- package/dist/approval-hmac.d.ts +13 -1
- package/dist/approval-hmac.js +1 -1
- package/dist/approval.js +3 -3
- package/dist/audit.js +1 -0
- package/dist/auth-bridge.js +2 -2
- package/dist/background-agent-name.d.ts +5 -0
- package/dist/background-agent-name.js +5 -0
- package/dist/boot/budget-tracing.d.ts +1 -12
- package/dist/boot/deployment-mods.d.ts +46 -16
- package/dist/boot/deployment-mods.js +82 -6
- package/dist/boot/execution-env.d.ts +24 -1
- package/dist/boot/execution-env.js +69 -6
- package/dist/boot/governance-seams.d.ts +10 -17
- package/dist/boot/governance-seams.js +5 -17
- package/dist/boot/leader.d.ts +3 -0
- package/dist/boot/leader.js +1 -0
- package/dist/boot/org-delivery.js +15 -2
- package/dist/boot/reapers.d.ts +3 -0
- package/dist/boot/reapers.js +15 -1
- package/dist/boot/resolve-spec.d.ts +7 -0
- package/dist/boot/resolve-spec.js +36 -26
- package/dist/boot/retention-lane.d.ts +11 -5
- package/dist/boot/retention-lane.js +2 -2
- package/dist/boot/runner-deps.d.ts +7 -3
- package/dist/boot/runner-deps.js +1 -0
- package/dist/boot/stage-03-store-backend.d.ts +1 -1
- package/dist/boot/stage-04-stores.d.ts +2 -13
- package/dist/boot/stage-05-execution-env.d.ts +6 -13
- package/dist/boot/stage-05-execution-env.js +17 -5
- package/dist/boot/stage-06-runners.d.ts +6 -13
- package/dist/boot/stage-06-runners.js +10 -3
- package/dist/boot/stage-07-capability-layer.d.ts +7 -13
- package/dist/boot/stage-07-capability-layer.js +3 -3
- package/dist/boot/stage-08-reapers.d.ts +7 -13
- package/dist/boot/stage-08-reapers.js +2 -1
- package/dist/boot/stage-09-leader.d.ts +7 -13
- package/dist/boot/stage-09-leader.js +2 -2
- package/dist/boot/stage-10-http-server.d.ts +7 -13
- package/dist/boot/stage-10-http-server.js +6 -3
- package/dist/boot/stores.d.ts +1 -1
- package/dist/boot/web-admin.d.ts +5 -2
- package/dist/boot/web-admin.js +3 -3
- package/dist/brain.js +5 -5
- package/dist/broker/broker.d.ts +89 -0
- package/dist/broker/broker.js +287 -0
- package/dist/broker/constants.d.ts +39 -0
- package/dist/broker/constants.js +15 -0
- package/dist/broker/http1.d.ts +111 -0
- package/dist/broker/http1.js +256 -0
- package/dist/broker/lease-book.d.ts +87 -0
- package/dist/broker/lease-book.js +142 -0
- package/dist/broker/lease-file.d.ts +60 -0
- package/dist/broker/lease-file.js +127 -0
- package/dist/broker/main.d.ts +2 -0
- package/dist/broker/main.js +20 -0
- package/dist/budget.d.ts +17 -15
- package/dist/budget.js +2 -2
- package/dist/capabilities/composite-members.d.ts +2 -1
- package/dist/capabilities/composite-members.js +2 -1
- package/dist/capabilities/engine-capabilities.js +1 -0
- package/dist/capabilities/mcp-probe.d.ts +36 -11
- package/dist/capabilities/mcp-probe.js +44 -5
- package/dist/capabilities/scenarios.d.ts +23 -8
- package/dist/capabilities/scenarios.js +13 -8
- package/dist/capabilities/skills.d.ts +28 -5
- package/dist/capabilities/skills.js +8 -0
- package/dist/capability-facts.d.ts +6 -0
- package/dist/capability-facts.js +5 -0
- package/dist/center-credential-renewer.js +5 -1
- package/dist/checkpoint-ctx-seal-m28.d.ts +3 -10
- package/dist/checkpoint-ctx-seal-m28.js +1 -1
- package/dist/checkpoint-identity.d.ts +13 -6
- package/dist/config-catalog.js +16 -7
- package/dist/config-types.d.ts +24 -7
- package/dist/config.d.ts +1 -1
- package/dist/config.js +42 -13
- package/dist/deployment-governance.d.ts +2 -2
- package/dist/deployment-governance.js +7 -9
- package/dist/deployment-shape.d.ts +6 -6
- package/dist/device-ws-protocol.d.ts +1 -0
- package/dist/device-ws-protocol.js +2 -1
- package/dist/file-history-disclosure.d.ts +4 -2
- package/dist/file-history-disclosure.js +2 -0
- package/dist/gate-settlement.d.ts +71 -0
- package/dist/gate-settlement.js +40 -0
- package/dist/hooks/classic-stations.d.ts +12 -54
- package/dist/hooks/classic-stations.js +1 -0
- package/dist/hooks/command-spawn.d.ts +2 -2
- package/dist/hooks/hook-runner.js +14 -14
- package/dist/http/admission.js +14 -9
- package/dist/http/approval-sweeps.js +4 -3
- package/dist/http/caller-trust.d.ts +2 -1
- package/dist/http/caller-trust.js +1 -3
- package/dist/http/checkpoint-ctx.d.ts +48 -7
- package/dist/http/checkpoint-ctx.js +40 -0
- package/dist/http/dispatch.d.ts +4 -0
- package/dist/http/dispatch.js +18 -10
- package/dist/http/durable-run-leg.d.ts +5 -1
- package/dist/http/durable-run-leg.js +5 -3
- package/dist/http/health-self-report.d.ts +2 -2
- package/dist/http/memory-compliance-failure-reply.js +3 -0
- package/dist/http/principal-gate.d.ts +15 -10
- package/dist/http/principal-gate.js +48 -9
- package/dist/http/resume-legs.d.ts +7 -31
- package/dist/http/resume-legs.js +185 -126
- package/dist/http/route-ctx.d.ts +38 -53
- package/dist/http/route-ctx.js +2 -5
- package/dist/http/routes/a2a-serve.js +10 -4
- package/dist/http/routes/agents-roster.d.ts +1 -1
- package/dist/http/routes/agents-roster.js +5 -1
- package/dist/http/routes/approvals-assistant.js +24 -10
- package/dist/http/routes/capabilities.js +23 -11
- package/dist/http/routes/mcp-reconnect.d.ts +3 -2
- package/dist/http/routes/mcp-reconnect.js +7 -7
- package/dist/http/routes/memory-consolidation.d.ts +1 -1
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/rules.js +3 -3
- package/dist/http/routes/runs.js +13 -8
- package/dist/http/routes/session-sync.js +42 -6
- package/dist/http/routes/sessions.js +6 -3
- package/dist/http/routes/side-query.js +2 -3
- package/dist/http/routes/tasks.js +794 -780
- package/dist/http/server.d.ts +35 -25
- package/dist/http/stored-body-replay.d.ts +3 -3
- package/dist/http/stored-body-replay.js +6 -1
- package/dist/http/wire-types.d.ts +66 -33
- package/dist/identity-source.d.ts +65 -0
- package/dist/identity-source.js +45 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/leader/wire.d.ts +7 -0
- package/dist/leader/wire.js +5 -4
- package/dist/mcp-assertion-header.d.ts +51 -40
- package/dist/mcp-assertion-header.js +10 -11
- package/dist/mcp-authorization-face.d.ts +27 -0
- package/dist/mcp-authorization-face.js +15 -0
- package/dist/memory-operator-faces.d.ts +13 -4
- package/dist/memory-operator-faces.js +1 -17
- package/dist/memory-store-refusal.d.ts +3 -3
- package/dist/memory-sync-client.js +72 -57
- package/dist/memory-sync.d.ts +1 -1
- package/dist/model-entry-refusal.d.ts +2 -0
- package/dist/model-entry-refusal.js +11 -0
- package/dist/model-route-gap.d.ts +6 -22
- package/dist/model-route-gap.js +7 -5
- package/dist/model-select.d.ts +6 -17
- package/dist/model-select.js +0 -3
- package/dist/mods-declaration.d.ts +110 -0
- package/dist/mods-declaration.js +109 -0
- package/dist/namespaced-rule-name.d.ts +1 -1
- package/dist/observability/err-text.d.ts +5 -0
- package/dist/observability/err-text.js +9 -0
- package/dist/observability/fail-open.d.ts +17 -1
- package/dist/observability/fail-open.js +17 -1
- package/dist/observability/metrics.js +1 -1
- package/dist/observability/run-terminal.js +1 -0
- package/dist/observability/secret-env-scrub.d.ts +1 -1
- package/dist/observability/secret-env-scrub.js +1 -1
- package/dist/operator-ask.d.ts +2 -2
- package/dist/org-delivery-gate.js +1 -1
- package/dist/org-memory-admission.d.ts +2 -2
- package/dist/org-memory-admission.js +39 -2
- package/dist/parked-decide.d.ts +15 -2
- package/dist/parked-decide.js +17 -10
- package/dist/peer-directory.js +2 -0
- package/dist/peer-seat.d.ts +150 -0
- package/dist/peer-seat.js +239 -0
- package/dist/permission-rule-list.d.ts +2 -2
- package/dist/permission-rule-vocab.d.ts +7 -7
- package/dist/permission-rule-vocab.js +3 -3
- package/dist/plain-string-record.d.ts +38 -0
- package/dist/plain-string-record.js +38 -0
- package/dist/plugins/background-agent-store-sql.js +6 -3
- package/dist/plugins/caching-session-store.d.ts +5 -0
- package/dist/plugins/caching-session-store.js +6 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +34 -29
- package/dist/plugins/checkpoint-store-sql.js +14 -14
- package/dist/plugins/file-history-store-sql.js +10 -16
- package/dist/plugins/file-run-store.js +8 -2
- package/dist/plugins/k8s-exec-protocol.d.ts +69 -13
- package/dist/plugins/k8s-exec-protocol.js +116 -28
- package/dist/plugins/k8s-pod-delete-failure.d.ts +25 -0
- package/dist/plugins/k8s-pod-delete-failure.js +17 -0
- package/dist/plugins/k8s-pod-reaper.d.ts +106 -0
- package/dist/plugins/k8s-pod-reaper.js +122 -0
- package/dist/plugins/local-checkpoint-store.d.ts +4 -17
- package/dist/plugins/local-checkpoint-store.js +3 -4
- package/dist/plugins/local-session-store.d.ts +66 -27
- package/dist/plugins/local-session-store.js +60 -28
- package/dist/plugins/mailbox-store-sql.d.ts +11 -3
- package/dist/plugins/mailbox-store-sql.js +103 -15
- package/dist/plugins/memory-run-store.js +2 -0
- package/dist/plugins/memory-sync-store-pg.d.ts +16 -5
- package/dist/plugins/memory-sync-store-tidb.d.ts +3 -3
- package/dist/plugins/one-time-migrations.d.ts +34 -12
- package/dist/plugins/one-time-migrations.js +51 -9
- package/dist/plugins/permission-rule-store-file.js +2 -2
- package/dist/plugins/permission-rule-store-sql.d.ts +17 -17
- package/dist/plugins/permission-rule-store-sql.js +37 -30
- package/dist/plugins/pg-pool.js +4 -0
- package/dist/plugins/pg-session-storage.d.ts +10 -2
- package/dist/plugins/pg-session-storage.js +20 -7
- package/dist/plugins/remote-env-adb.d.ts +6 -1
- package/dist/plugins/remote-env-adb.js +2 -1
- package/dist/plugins/remote-env-device.d.ts +6 -1
- package/dist/plugins/remote-env-device.js +5 -1
- package/dist/plugins/remote-env-e2b.d.ts +5 -0
- package/dist/plugins/remote-env-e2b.js +2 -1
- package/dist/plugins/remote-env-file-error.d.ts +8 -1
- package/dist/plugins/remote-env-file-error.js +7 -1
- package/dist/plugins/remote-env-host.d.ts +10 -2
- package/dist/plugins/remote-env-host.js +8 -2
- package/dist/plugins/remote-env-k8s.d.ts +140 -11
- package/dist/plugins/remote-env-k8s.js +277 -15
- package/dist/plugins/remote-env-local-docker.d.ts +5 -0
- package/dist/plugins/remote-env-local-docker.js +2 -1
- package/dist/plugins/remote-env-ssh.d.ts +6 -1
- package/dist/plugins/remote-env-ssh.js +2 -1
- package/dist/plugins/retention-store-sql.d.ts +14 -2
- package/dist/plugins/retention-store-sql.js +6 -0
- package/dist/plugins/run-store-sql.js +10 -4
- package/dist/plugins/session-fork.d.ts +10 -13
- package/dist/plugins/session-fork.js +5 -25
- package/dist/plugins/session-ownership.d.ts +24 -3
- package/dist/plugins/session-ownership.js +24 -5
- package/dist/plugins/session-workspace-cell.d.ts +17 -0
- package/dist/plugins/session-workspace-cell.js +38 -0
- package/dist/plugins/sql-errors.d.ts +23 -2
- package/dist/plugins/sql-errors.js +15 -0
- package/dist/plugins/store-backend.js +7 -7
- package/dist/plugins/store-contracts.d.ts +10 -1
- package/dist/plugins/store-fault.d.ts +2 -2
- package/dist/plugins/store-fault.js +4 -2
- package/dist/plugins/tidb-pool.js +13 -0
- package/dist/plugins/tidb-session-store.d.ts +17 -2
- package/dist/plugins/tidb-session-store.js +18 -7
- package/dist/plugins/tool-result-store-sql.d.ts +13 -6
- package/dist/plugins/tool-result-store-sql.js +8 -7
- package/dist/plugins/worktree-isolation.d.ts +3 -2
- package/dist/plugins/worktree-isolation.js +1 -7
- package/dist/project-identity.d.ts +1 -14
- package/dist/project-identity.js +0 -4
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +31 -2
- package/dist/request-value-closure.js +7 -1
- package/dist/rule-entry-list.d.ts +3 -2
- package/dist/rule-entry-list.js +2 -2
- package/dist/rules-consent.js +12 -7
- package/dist/run-local.d.ts +2 -2
- package/dist/run-local.js +12 -6
- package/dist/runs.d.ts +7 -1
- package/dist/runs.js +8 -2
- package/dist/runtime-governance.d.ts +5 -5
- package/dist/sandbox-git-lease.d.ts +49 -0
- package/dist/sandbox-git-lease.js +60 -0
- package/dist/sandbox-git-plane.d.ts +84 -0
- package/dist/sandbox-git-plane.js +105 -0
- package/dist/security.d.ts +16 -4
- package/dist/security.js +8 -3
- package/dist/server-secret-env.d.ts +12 -3
- package/dist/server-secret-env.js +18 -2
- package/dist/session-error-wire.d.ts +14 -6
- package/dist/session-error-wire.js +2 -1
- package/dist/session-incarnation.d.ts +4 -5
- package/dist/session-incarnation.js +2 -2
- package/dist/session-policy-wire.d.ts +1 -1
- package/dist/session-policy-wire.js +2 -2
- package/dist/session-sync.d.ts +1 -1
- package/dist/session-workspace.d.ts +130 -0
- package/dist/session-workspace.js +83 -0
- package/dist/spec-fields.d.ts +44 -14
- package/dist/spec-fields.js +33 -12
- package/dist/standing-answer-grant.d.ts +2 -13
- package/dist/standing-answer-grant.js +0 -7
- package/dist/stored-request-prompt-profile-m30.d.ts +49 -0
- package/dist/stored-request-prompt-profile-m30.js +25 -0
- package/dist/task-a2a.d.ts +44 -14
- package/dist/task-a2a.js +46 -20
- package/dist/task-mcp.d.ts +34 -21
- package/dist/task-mcp.js +46 -22
- package/dist/task-settings.d.ts +2 -2
- package/dist/tool-approval.d.ts +43 -9
- package/dist/tool-approval.js +57 -15
- package/dist/tool-rule-names.d.ts +5 -0
- package/dist/trace/core-keyset-guard.d.ts +34 -19
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +4 -0
- package/dist/trace/exit-seat.d.ts +20 -1
- package/dist/trace/exit-seat.js +5 -2
- package/dist/trace/extension-call-face.d.ts +33 -0
- package/dist/trace/extension-call-face.js +39 -0
- package/dist/trace/ledger-sink.d.ts +4 -5
- package/dist/trace/ledger-sink.js +3 -7
- package/dist/trace/project.d.ts +62 -10
- package/dist/trace/project.js +49 -9
- package/dist/trace/redact.d.ts +18 -6
- package/dist/trace/redact.js +154 -60
- package/dist/trace/self-minted-wire.d.ts +500 -7
- package/dist/trace/self-minted-wire.js +182 -1
- package/dist/trace/wire-projection-faces.d.ts +7 -5
- package/dist/trace/wire-projection-faces.js +9 -4
- package/dist/user-authored-text.d.ts +2 -2
- package/dist/user-authored-text.js +16 -1
- package/dist/web-admin-client/apply-effective.js +0 -1
- package/dist/web-admin-client/center-request.d.ts +23 -4
- package/dist/web-admin-client/center-request.js +42 -8
- package/dist/web-admin-client/http-client.js +6 -6
- package/dist/web-admin-client/skills-mcp.d.ts +8 -4
- package/dist/web-admin-client/skills-mcp.js +31 -18
- package/dist/web-admin-client/types.d.ts +10 -5
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +11 -5
- package/package.json +3 -3
- package/wire-changes/server@7.137.0.json +825 -0
- package/wire-changes/server@7.138.0.json +446 -0
package/dist/http/route-ctx.d.ts
CHANGED
|
@@ -27,8 +27,12 @@ import type { CapabilitiesLocal } from "./routes/capabilities.js";
|
|
|
27
27
|
import type { SessionsLocal } from "./routes/sessions.js";
|
|
28
28
|
import type { SessionSyncLocal } from "./routes/session-sync.js";
|
|
29
29
|
import type { PlanApprovePermissionModeAfter } from "../task-settings.js";
|
|
30
|
+
import type { GateSighting } from "../approval-gate-currency.js";
|
|
30
31
|
import type { VerifyRoundsSpec } from "./verify-rounds.js";
|
|
31
32
|
import type { RunAbort } from "../run-cancel-context.js";
|
|
33
|
+
import type { RunIdentity } from "../identity-source.js";
|
|
34
|
+
import type { PeerLease } from "../peer-seat.js";
|
|
35
|
+
import type { GateCommitment, GateSettlementEvidence } from "../gate-settlement.js";
|
|
32
36
|
/** 跨域可变状态 = lens1 §C2 实测的那 8 条「运行期登记簿」,一个对象。
|
|
33
37
|
* [ref]:`cancelledViaVerb`(按 taskId 键控的「这次是取消动词」旁表)删除 —— 中止成因改挂在每条腿自己的
|
|
34
38
|
* {@link RunAbort} 句柄上(`inflightRuns` 的值),同寿同删,不再有一张与腿不同寿的旁表。 */
|
|
@@ -146,6 +150,12 @@ export interface PreparedTaskSubmission {
|
|
|
146
150
|
* 不经提交门的内部车道(`/decide` 的宿主新 turn)铸一只不带标题器的座:不起标题。
|
|
147
151
|
*/
|
|
148
152
|
acceptance: import("../run-acceptance.js").RunAcceptance;
|
|
153
|
+
/**
|
|
154
|
+
* 这次装配的**宿主租约**:受理漏斗在装配之前开(`peerDesk.lease("fresh")`),装配在它之下登记交给引擎的对端声明;漏斗成功即把它交到这里 ——
|
|
155
|
+
* 拿到本产物的那只函数紧接着写 `try { … } finally { prepared.peerLease.release() }`,其后每个出口(早退、合流败方、建行拒、驱动返回)按构造都放。
|
|
156
|
+
* 活过那段作用域的驱动(后台腿)经 `heldFor(prepared.peerLease, () => …)` 自持一只,自己落定才放。续跑家族的内部车道交它自己漏斗开的那一只。
|
|
157
|
+
*/
|
|
158
|
+
peerLease: PeerLease;
|
|
149
159
|
}
|
|
150
160
|
/**
|
|
151
161
|
* 一条会话的**续跑重建输入**(`checkpoint_ctx` 的行体)—— 提交腿写一次,续跑腿读它重建 spec。
|
|
@@ -250,6 +260,11 @@ export interface DriveResumeArgs {
|
|
|
250
260
|
sessionId: string;
|
|
251
261
|
ctx: CheckpointCtx;
|
|
252
262
|
};
|
|
263
|
+
/**
|
|
264
|
+
* 这条续跑的**宿主租约**(续跑漏斗 `resolveResumeSpecOrBlocked` 开、装配在它之下登记对端声明;调用方作用域的 `finally` 放)。
|
|
265
|
+
* 驱动腿经 `heldFor(args.peerLease, () => driveResumeLeg(…))` 自持一只:受理早回的那一形里,腿活过调用方作用域,自己落定才放。
|
|
266
|
+
*/
|
|
267
|
+
peerLease: PeerLease;
|
|
253
268
|
/** [ref]:续跑腿的执行 Runner。resume 会用同一条 resolveSpec 重解析场景,故与首跑选同一只 —— 否则
|
|
254
269
|
* 一次续跑就把手带 band 重新 mount 回来(收窄只在首跑成立 = 没成立)。 */
|
|
255
270
|
runner: Runner;
|
|
@@ -259,6 +274,12 @@ export interface DriveResumeArgs {
|
|
|
259
274
|
taskConfig: Omit<TaskSpec, "objective" | "sessionId">;
|
|
260
275
|
resumeObjective: string;
|
|
261
276
|
outcome: ResumeOutcome;
|
|
277
|
+
/**
|
|
278
|
+
* 🔴 **这条腿到达边界时能证什么**(必填 —— 缺 = 编译错;闭集,语义属主 = `gate-settlement.ts` 的 {@link GateCommitment})。同一条驱动路径既续本请求点名的门
|
|
279
|
+
* (`/decide` 引擎臂、`/resume`、`/plan_review` ⇒ `gate_resolved`,带执行**前**从选中那一行捕获、过了信任边界的身份),也替宿主投递(wake ⇒ `delivered`)。
|
|
280
|
+
* 它只是分类:位由受理点与终局体两个边界按它铸,从不只凭这一句声明铸;缺席的取消出口(`checkpoint.resume_aborted` / 抛出臂)不铸。
|
|
281
|
+
*/
|
|
282
|
+
commitment: GateCommitment;
|
|
262
283
|
verifyRounds: VerifyRoundsSpec | undefined;
|
|
263
284
|
/**
|
|
264
285
|
* **R-1**(车CJ 收车档 §10 R-1;[ref] 批落地)—— 本条 resume 腿**装配期**铸下的用户面通告
|
|
@@ -281,11 +302,13 @@ export interface DriveResumeArgs {
|
|
|
281
302
|
/** [ref]/[ref]:调用方声明「本腿的 park 是终局后纯 park,session claim 已随终局 finalize 删除」——
|
|
282
303
|
* getActiveTaskId 缺席时**铸新 canonical taskId + createRun 全生命周期行**(wake 续跑=同 session 新一轮
|
|
283
304
|
* turn),而不是无行裸跑(不可取消/无计费归因/无 durable append/fleet 不可见,且 core `spec.taskId ??
|
|
284
|
-
* sessionId` fallback 会把 lastRunId 铸成 sessionId)。`source` 进 run 行元数据(runMeta
|
|
305
|
+
* sessionId` fallback 会把 lastRunId 铸成 sessionId)。`source` 进 run 行元数据(runMeta 同列,只作归因);`identity` = 新行的身份元组(调用方经
|
|
306
|
+
* `runIdentityOf(req, config, 卡属主)` 读凭据门铸下的那一份:按下按钮的就是卡属主才有,否则空)。
|
|
285
307
|
* decide/answer/plan_review 腿**不设**此位:它们的 claim 在 park 期间特意保留,缺席=行被 reap 的竞态,
|
|
286
308
|
* 维持既有兜底(checkpoint token 同拍过期 ⇒ resumeStream 拒),不铸新行。 */
|
|
287
309
|
mintFreshRun?: {
|
|
288
310
|
source: string;
|
|
311
|
+
identity: RunIdentity | null;
|
|
289
312
|
};
|
|
290
313
|
/** `/decide` 第三条车道交给本腿的那一件决定投递(语义属主 = {@link WorkflowDecisionDelivery} 顶注)。缺席 ⇒ 只摊决定行(其余四条 resume 腿恒缺席)。 */
|
|
291
314
|
workflowDecision?: WorkflowDecisionDelivery;
|
|
@@ -429,10 +452,7 @@ export interface RouteLegs {
|
|
|
429
452
|
decider?: {
|
|
430
453
|
principal?: string;
|
|
431
454
|
explicitOperator: boolean;
|
|
432
|
-
}): Promise<
|
|
433
|
-
status: number;
|
|
434
|
-
body: object;
|
|
435
|
-
}>;
|
|
455
|
+
}): Promise<ResumeLegOutcome>;
|
|
436
456
|
/** notify-wake 域:唤醒一条 parked checkpoint。 */
|
|
437
457
|
resumeWake(sessionId: string, message: string | undefined, caller: string | undefined, req: IncomingMessage | undefined,
|
|
438
458
|
/** [ref] 件 S-1:透传给 {@link DriveResumeArgs.acceptEarly}(200 受理语义)。HTTP `/wake` 腿传 `true`
|
|
@@ -440,7 +460,7 @@ export interface RouteLegs {
|
|
|
440
460
|
acceptEarly?: boolean,
|
|
441
461
|
/** 透传给 {@link DriveResumeArgs.workflowDecision}。HTTP `/wake` 腿**不设**此位 —— 它是 `/decide` 第三条车道投递腿的专用席,
|
|
442
462
|
* 而两条腿共用这一条驱动路径正是 `notify-wake.ts` 那条「wake 会烧模型,所以复用 resume 家族的同一条腿」的成文纪律。 */
|
|
443
|
-
workflowDecision?: WorkflowDecisionDelivery): Promise<
|
|
463
|
+
workflowDecision?: WorkflowDecisionDelivery): Promise<ResumeLegOutcome>;
|
|
444
464
|
/**
|
|
445
465
|
* assistant plan_review 三态腿的**纯读段**([ref],7.97.0):选卡 → 属主轻读 → 载入 → 行级 scope → 门类 → 这条决断
|
|
446
466
|
* 唯一的一次 ctx 读。任何一步拒 ⇒ `{ok:false, answer}`(不改任何状态;端点在消费一次性 nonce **之前**把它答出去);
|
|
@@ -457,7 +477,9 @@ export interface RouteLegs {
|
|
|
457
477
|
decider?: {
|
|
458
478
|
principal?: string;
|
|
459
479
|
explicitOperator: boolean;
|
|
460
|
-
}
|
|
480
|
+
},
|
|
481
|
+
/** [ref]:决断方看到的那道门(决断体的 `checkpointId`);不是当前门 ⇒ `409 approval_stale`(`approval_stale` 律,语义属主 = `resume-legs.ts` 的同名形参顶注)。 */
|
|
482
|
+
sighting?: GateSighting): Promise<{
|
|
461
483
|
readonly ok: false;
|
|
462
484
|
readonly answer: {
|
|
463
485
|
status: number;
|
|
@@ -475,10 +497,7 @@ export interface RouteLegs {
|
|
|
475
497
|
acceptEarly?: boolean,
|
|
476
498
|
/** [ref]:批准之后这条会话继续用的 permission mode(闭集 `PLAN_APPROVE_PERMISSION_MODES_AFTER`;只在把计划带出 plan 的决定
|
|
477
499
|
* —— `approve` / `edit` —— 上有意义,缺席 ⇒ `"default"`)。语义与判据的唯一属主 = `resume-legs.ts` 的同名形参顶注。 */
|
|
478
|
-
permissionModeAfter?: PlanApprovePermissionModeAfter): Promise<
|
|
479
|
-
status: number;
|
|
480
|
-
body: object;
|
|
481
|
-
}>;
|
|
500
|
+
permissionModeAfter?: PlanApprovePermissionModeAfter): Promise<ResumeLegOutcome>;
|
|
482
501
|
}
|
|
483
502
|
/**
|
|
484
503
|
* [ref] 件 S-2 —— resume 族**受理点的断连留痕**(裁定:维持 detach,补观察面)。
|
|
@@ -667,48 +686,13 @@ export type RouteDecl = RouteDispatchDecl | RouteGateDecl;
|
|
|
667
686
|
* api-error-text-freeze 基线流程。
|
|
668
687
|
*/
|
|
669
688
|
/**
|
|
670
|
-
* resume
|
|
671
|
-
*
|
|
672
|
-
* `decisionCommitted` —— **这条腿的终局是在引擎受理了这次决定之后才结出来的**([ref] X5,7.112.0):本腿走到了「引擎交回结果」那一步
|
|
673
|
-
* (`resumeStream` / `resumeWithVerification` 解析 = core 的全部 pre-CAS 门 + checkpoint resolve CAS 都过了 —— 受理点的判据属主
|
|
674
|
-
* = {@link DriveResumeArgs.acceptEarly} 顶注),之后才收场。只由 `driveResumeLeg` 走完引擎那一步的终局出口铸;`CheckpointError` 臂、
|
|
675
|
-
* 「中止抛穿」臂、一切 4xx / 拒绝出口一律**不铸**(缺席 ⇒ 证不出提交,读者按「没提交」读 —— fail-closed)。
|
|
676
|
-
*
|
|
677
|
-
* 读者:`/decide` 的两道「这次决定提交了没有」门 —— [ref] 迟到结算留痕(`noteLateSettleIfAccepted`)与 remember 豁免落店
|
|
678
|
-
* (`routes/approvals-assistant.ts`)。它们原先只读 wire 体的 `errorCode !== "cancelled"`(「取消 = 决定没提交」),[ref] 给续跑腿补了
|
|
679
|
-
* 「引擎受理之后才被取消」的取消终局之后,`cancelled` 不再等价「没提交」⇒ 两门改读本位:`200 ∧ (errorCode≠cancelled ∨ decisionCommitted)`。
|
|
680
|
-
* 🔴 为什么不放进 `result.cancelContext`(主会话初稿的落点):那只快照的契约是「分诊材料,不是状态机输入:任何门 / CAS / resume 判定都不许
|
|
681
|
-
* 读它」(`plugins/store-contracts.ts` `RunCancelContext` 顶注)—— 这两道门正是判定;而且门读的是 `/decide` 的平面体、看不到结果对象。
|
|
682
|
-
* 受理与否是腿自己的控制流事实,在腿上说,零 wire 变更。
|
|
683
|
-
*/
|
|
684
|
-
export interface EngineLegOutcome {
|
|
685
|
-
status: number;
|
|
686
|
-
body: object;
|
|
687
|
-
decisionCommitted?: true;
|
|
688
|
-
}
|
|
689
|
-
/**
|
|
690
|
-
* **workflow 宿主腿的结局(wake / fresh)—— 型上就没有 `decisionCommitted`**([ref] ②,7.113.0;`never` 让「这条路径不铸」成为**编译事实**,不是靠人记)。
|
|
691
|
-
*
|
|
692
|
-
* 为什么这条路径不该有该位:`/decide` 的 workflow 第三条车道(`resumeCheckpoint` 的 parked 分流,`planWorkflowParkedDecide` 之后)与 `POST /v1/sessions/:id/wake`
|
|
693
|
-
* 把决定 / 消息交给**宿主会话的下一跑**(`resumeWake` / `startFreshHostTurn`)。它们的 200 只到「已交给宿主的下一跑」—— 子代 checkpoint 的 resolve CAS 发生在
|
|
694
|
-
* workflow 引擎自己驱动那一步,server 观察不到(`resume-legs.ts` 该分流处「刻意不落 `late_settle`」同源)。「这次决定被引擎受理了」这句话在这里**没有可说的对象**,
|
|
695
|
-
* 于是 `decisionCommitted` 在这条路径上语义含混(修前:`resumeWake` 的收尾是 `driveResumeIntoRunLog` 的 `ResumeLegOutcome`,非受理点早返形(无 `acceptEarly`)下它会把
|
|
696
|
-
* 引擎腿的 `decisionCommitted:true` 原样带出去 —— 型被声明返回型 `{status, body}` 擦掉了,运行期仍在)。读者核实:两道提交门(`noteLateSettleIfAccepted` 迟到结算留痕、
|
|
697
|
-
* `/decide` 的 remember 豁免落店)在这条路径上今天**零读取**(前者该分流直接 `return`、不调;后者的 `pendingGrant` 只由引擎腿的 `onResumeCommitted` 回调置位,宿主腿不调它,且 `planWorkflowParkedDecide` 对 workflow 车道的 `remember` 本就 fail-closed 拒 —— `decide.workflow_remember_unsupported`,`parked-decide.ts`)——
|
|
698
|
-
* 无读者 ⇒ 剥掉该位,而不是留一个「铸了也没人读、读了不知道什么意思」的位。出口经 {@link buildHostLegOutcome} 只带 `status` / `body`。
|
|
689
|
+
* resume 家族一条腿的结局:HTTP 应答(`status` / `body`)。「这次决定提交了没有」只有一种说法 —— 体上的结清证据 `decisionCommitted`
|
|
690
|
+
* (唯一铸点 / 唯一读法 = `gate-settlement.ts`);进程内不另带第二个提交位。
|
|
699
691
|
*/
|
|
700
|
-
export interface
|
|
692
|
+
export interface ResumeLegOutcome {
|
|
701
693
|
status: number;
|
|
702
694
|
body: object;
|
|
703
|
-
decisionCommitted?: never;
|
|
704
695
|
}
|
|
705
|
-
/** resume 家族一条腿的结局:引擎腿(可带 `decisionCommitted`)∪ workflow 宿主腿(型上没有)。`out.decisionCommitted === true` 同时收窄到引擎腿。 */
|
|
706
|
-
export type ResumeLegOutcome = EngineLegOutcome | HostLegOutcome;
|
|
707
|
-
/** 把任意腿的结局折成宿主腿结局:**只带 `status` / `body`**(丢掉引擎腿的 `decisionCommitted` —— 见 {@link HostLegOutcome})。纯数据。 */
|
|
708
|
-
export declare function buildHostLegOutcome(out: {
|
|
709
|
-
status: number;
|
|
710
|
-
body: object;
|
|
711
|
-
}): HostLegOutcome;
|
|
712
696
|
/**
|
|
713
697
|
* **「决定/续跑已受理」那一枚 200 收据的单一铸点**([ref])。
|
|
714
698
|
*
|
|
@@ -718,11 +702,12 @@ export declare function buildHostLegOutcome(out: {
|
|
|
718
702
|
* 都不该加**;写成两份字面量,漂开的那天没有任何东西会说话。
|
|
719
703
|
*
|
|
720
704
|
* `bindingEnforced` 的语义不因铸点而变(「这次决定按绑定坐标受理,不是盲目放行」),故两腿同带。
|
|
705
|
+
*
|
|
706
|
+
* `evidence` = 结清证据(`gate-settlement.ts`):引擎续跑腿的受理点交 `buildSettlementEvidence({ at: "engine_accepted", … })` 铸的那一份
|
|
707
|
+
* (`gate_resolved` 腿 ⇒ 位 + 身份;wake 的 `delivered` ⇒ 空);没跨过任何边界的回执(宿主新一跑、同一决定重投)交 `NO_SETTLEMENT_EVIDENCE`。
|
|
708
|
+
* 调用方不手写证据键 —— 体上的两键只有那一只铸点。
|
|
721
709
|
*/
|
|
722
|
-
export declare function acceptedResumingReceipt(taskId: string, sessionId: string):
|
|
723
|
-
status: number;
|
|
724
|
-
body: object;
|
|
725
|
-
};
|
|
710
|
+
export declare function acceptedResumingReceipt(taskId: string, sessionId: string, evidence: GateSettlementEvidence): ResumeLegOutcome;
|
|
726
711
|
/** 一条腿的结局是不是一张「已受理」回执,是 ⇒ 回执上那一跑的 `taskId`(同一张回执的读法与 {@link acceptedResumingReceipt} 住在一起;
|
|
727
712
|
* `/decide` 的 workflow 车道据它把投递那一跑记在决定行上)。 */
|
|
728
713
|
export declare function acceptedTaskIdOf(out: {
|
package/dist/http/route-ctx.js
CHANGED
|
@@ -21,11 +21,8 @@ export function assertNever(x) {
|
|
|
21
21
|
throw new Error(`unreachable route id: ${String(x)}`);
|
|
22
22
|
}
|
|
23
23
|
export const ROUTE_METHOD_ORDER = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
24
|
-
export function
|
|
25
|
-
return { status:
|
|
26
|
-
}
|
|
27
|
-
export function acceptedResumingReceipt(taskId, sessionId) {
|
|
28
|
-
return { status: 200, body: { taskId, sessionId, status: "resuming", bindingEnforced: true } };
|
|
24
|
+
export function acceptedResumingReceipt(taskId, sessionId, evidence) {
|
|
25
|
+
return { status: 200, body: { taskId, sessionId, status: "resuming", bindingEnforced: true, ...evidence } };
|
|
29
26
|
}
|
|
30
27
|
export function acceptedTaskIdOf(out) {
|
|
31
28
|
const body = out.body;
|
|
@@ -272,11 +272,17 @@ async function handleMessageSend({ req, res, ctx, params, serve, runStore }) {
|
|
|
272
272
|
const prepared = await ctx.legs.prepareSpec(req, res, body, (e) => {
|
|
273
273
|
typed = e;
|
|
274
274
|
});
|
|
275
|
-
if (
|
|
276
|
-
|
|
277
|
-
|
|
275
|
+
if (!prepared) {
|
|
276
|
+
if (typed)
|
|
277
|
+
throw rpcErrorFromTypedFailure(typed, skillId);
|
|
278
278
|
return undefined;
|
|
279
|
-
|
|
279
|
+
}
|
|
280
|
+
try {
|
|
281
|
+
receipt = await createDurableRun(req, res, ctx, prepared, idem);
|
|
282
|
+
}
|
|
283
|
+
finally {
|
|
284
|
+
prepared.peerLease.release();
|
|
285
|
+
}
|
|
280
286
|
}
|
|
281
287
|
if (!receipt)
|
|
282
288
|
return undefined;
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* · **能力位同源**:`capabilities.agentRoster` 与这里的 501 谓词是同一个 `deps.backgroundAgentStore`。
|
|
26
26
|
*/
|
|
27
27
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
28
|
-
import type
|
|
28
|
+
import { type BackgroundAgentRowSummary } from "@sema-agent/core";
|
|
29
29
|
import type { RouteCtx, RouteMatch, RouteIdsOf } from "../route-ctx.js";
|
|
30
30
|
/** 名册窗的扫描上限(与 fleet 的终态窗同姿势:读面要有界)。窗满时回体带 `truncated:true`,
|
|
31
31
|
* `total` 于是诚实地是「窗内行数」而不是租户全量 —— 一个悄悄封顶的 total 比没有 total 更坏。 */
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { chosenAgentName } from "@sema-agent/core";
|
|
1
2
|
import { sendJson, sendError } from "../send.js";
|
|
2
3
|
import { fleetViewOf, sendUnauthorized } from "../principal-gate.js";
|
|
3
4
|
import { assertNever } from "../route-ctx.js";
|
|
4
5
|
import * as facts from "../../capability-facts.js";
|
|
6
|
+
import { backgroundAgentNameOf } from "../../background-agent-name.js";
|
|
5
7
|
export const ROSTER_SCAN_LIMIT = 500;
|
|
6
8
|
const ROSTER_STATUSES = ["running", "parked", "completed", "failed", "killed"];
|
|
7
9
|
const ROSTER_KEY_DISPOSITION = {
|
|
@@ -24,9 +26,11 @@ export function rosterAgentId(row) {
|
|
|
24
26
|
return row.handle;
|
|
25
27
|
}
|
|
26
28
|
function projectRow(r) {
|
|
29
|
+
const name = backgroundAgentNameOf(r);
|
|
27
30
|
return {
|
|
28
31
|
handle: rosterAgentId(r),
|
|
29
|
-
|
|
32
|
+
name,
|
|
33
|
+
...(chosenAgentName(r.handle, name) === undefined ? { anonymous: true } : {}),
|
|
30
34
|
...(r.agentType !== undefined ? { agentType: r.agentType } : {}),
|
|
31
35
|
status: r.status,
|
|
32
36
|
spawnedAt: r.spawnedAt,
|
|
@@ -22,29 +22,31 @@ import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal, sessionCaller
|
|
|
22
22
|
import { readOwnedRun, readOwnedSession } from "../owner-access.js";
|
|
23
23
|
import { governanceOriginOf } from "../../runtime-governance.js";
|
|
24
24
|
import { deploymentListAsks } from "../../approval.js";
|
|
25
|
-
import {
|
|
25
|
+
import { grantBindingOf } from "../../standing-answer-grant.js";
|
|
26
26
|
import { sendResumeOutcome } from "../route-ctx.js";
|
|
27
27
|
import { assertNever } from "../route-ctx.js";
|
|
28
28
|
import * as facts from "../../capability-facts.js";
|
|
29
29
|
import { storeFaultClassOf } from "../../plugins/store-fault.js";
|
|
30
30
|
import { recordFailOpen } from "../../observability/fail-open.js";
|
|
31
|
-
import { durableRowIdentity } from "../../checkpoint-identity.js";
|
|
31
|
+
import { MAX_CHECKPOINT_ID_CHARS, durableRowIdentity } from "../../checkpoint-identity.js";
|
|
32
32
|
import { MAX_KEY_ECHO, keyClosureClause, scanKeyClosure } from "../../request-key-closure.js";
|
|
33
33
|
import { fieldConflictFacts } from "../../field-conflict.js";
|
|
34
|
+
import { buildSettlementEvidence, decisionCommittedOf } from "../../gate-settlement.js";
|
|
34
35
|
const DECIDE_BODY_DECLARED_KEYS = [
|
|
35
36
|
"answer", "boundCallId", "boundInputHash", "checkpointToken", "decidedBy", "decision", "feedback", "reason", "remember", "updatedInput",
|
|
36
37
|
];
|
|
37
38
|
const DECIDE_PROOF_COVERED_KEYS = ["answer", "boundCallId", "boundInputHash", "decision", "reason"];
|
|
38
39
|
const DECIDE_NOT_IN_PROOF_KEYS = ["checkpointToken", "decidedBy", "feedback", "remember", "updatedInput"];
|
|
39
40
|
const PLAN_REVIEW_BODY_DECLARED_KEYS = [
|
|
40
|
-
"boundCallId", "decidedBy", "decision", "editedPlan", "permissionModeAfter", "reason",
|
|
41
|
+
"boundCallId", "checkpointId", "decidedBy", "decision", "editedPlan", "permissionModeAfter", "reason",
|
|
41
42
|
];
|
|
42
|
-
const PLAN_REVIEW_PROOF_COVERED_KEYS = ["boundCallId", "decision", "editedPlan", "permissionModeAfter", "reason"];
|
|
43
|
+
const PLAN_REVIEW_PROOF_COVERED_KEYS = ["boundCallId", "checkpointId", "decision", "editedPlan", "permissionModeAfter", "reason"];
|
|
43
44
|
const PLAN_REVIEW_NOT_IN_PROOF_KEYS = ["decidedBy"];
|
|
44
45
|
const PROOF_SLOT_OF = {
|
|
45
46
|
answer: "answer",
|
|
46
47
|
boundCallId: "boundCallId",
|
|
47
48
|
boundInputHash: "boundInputHash",
|
|
49
|
+
checkpointId: "checkpointId",
|
|
48
50
|
decision: "decision",
|
|
49
51
|
editedPlan: "boundInputHash",
|
|
50
52
|
permissionModeAfter: "permissionModeAfter",
|
|
@@ -258,6 +260,7 @@ async function decideIdempotentReplay(cs, args) {
|
|
|
258
260
|
decision,
|
|
259
261
|
bindingEnforced: true,
|
|
260
262
|
...(executionOutcome !== undefined ? { executionOutcome } : {}),
|
|
263
|
+
...buildSettlementEvidence({ at: "replay_matched" }),
|
|
261
264
|
},
|
|
262
265
|
};
|
|
263
266
|
}
|
|
@@ -351,8 +354,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
351
354
|
sendError(res, 404, "request.route_unsupported", "not found");
|
|
352
355
|
return;
|
|
353
356
|
}
|
|
354
|
-
|
|
355
|
-
sendJson(res, 200, { exemptions: rows.filter((r) => callGrantBindingOf({ toolName: r.toolName }).kind === "none") });
|
|
357
|
+
sendJson(res, 200, { exemptions: await deps.approvalExemptionStore.list(exSessionId) });
|
|
356
358
|
return;
|
|
357
359
|
}
|
|
358
360
|
if (exToolName === undefined) {
|
|
@@ -625,6 +627,17 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
625
627
|
}
|
|
626
628
|
}
|
|
627
629
|
const planNonce = typeof body.boundCallId === "string" ? body.boundCallId : undefined;
|
|
630
|
+
if (body.checkpointId !== undefined) {
|
|
631
|
+
if (typeof body.checkpointId !== "string" || body.checkpointId.length === 0) {
|
|
632
|
+
sendError(res, 400, "request.field_invalid", "checkpointId must be a non-empty string (the identity of the plan gate you decided on: read terminal.checkpointId on the run result, or the checkpointId on its approvals / inbox entry)");
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
if (body.checkpointId.length > MAX_CHECKPOINT_ID_CHARS) {
|
|
636
|
+
sendError(res, 400, "request.field_invalid", `checkpointId too large (max ${MAX_CHECKPOINT_ID_CHARS} chars)`);
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
const sighting = typeof body.checkpointId === "string" ? { face: "checkpointId", value: body.checkpointId } : undefined;
|
|
628
641
|
const run = await runStore.getRun(taskId);
|
|
629
642
|
if (!run) {
|
|
630
643
|
if (deps.config.directDoorActive) {
|
|
@@ -647,6 +660,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
647
660
|
const hdr = (n) => { const h = req.headers[n]; return Array.isArray(h) ? h[0] : h; };
|
|
648
661
|
const proof = verifyDirectDoorProof({ jwt: hdr(PRINCIPAL_TOKEN_HEADER), mac: hdr(APPROVAL_MAC_HEADER), kid: hdr(APPROVAL_MAC_KID_HEADER) }, buildApprovalEnvelope(run.sessionId, PLAN_REVIEW_PROOF_COVERED_KEYS, {
|
|
649
662
|
boundCallId: planNonce ?? null,
|
|
663
|
+
checkpointId: sighting?.value,
|
|
650
664
|
decision,
|
|
651
665
|
editedPlan: decision === "edit" ? editedPlanBinding(body.editedPlan) : null,
|
|
652
666
|
permissionModeAfter: isPlanApprovePermissionModeAfter(body.permissionModeAfter) ? body.permissionModeAfter : undefined,
|
|
@@ -665,7 +679,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
665
679
|
sendError(res, 404, "not_found.run", "task not found");
|
|
666
680
|
return;
|
|
667
681
|
}
|
|
668
|
-
const plan = await preparePlanReview(run.sessionId, { taskId, principalPresent: principal !== undefined }, { principal: deciderPrincipal, explicitOperator });
|
|
682
|
+
const plan = await preparePlanReview(run.sessionId, { taskId, principalPresent: principal !== undefined }, { principal: deciderPrincipal, explicitOperator }, sighting);
|
|
669
683
|
if (!plan.ok) {
|
|
670
684
|
sendResumeOutcome(res, plan.answer, deps.logger);
|
|
671
685
|
return;
|
|
@@ -857,8 +871,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
857
871
|
}
|
|
858
872
|
: undefined;
|
|
859
873
|
const out = await resumeCheckpoint(sessionId, decision, body.reason ?? undefined, hostDecisionFacts(decidedBy, deciderPrincipal), req, answer, binding, grantOnCommit, true, { principal: deciderPrincipal, explicitOperator });
|
|
860
|
-
|
|
861
|
-
if (pendingGrant !== undefined && out.status === 200 && (outErrorCode !== "cancelled" || out.decisionCommitted === true) && deps.approvalExemptionStore) {
|
|
874
|
+
if (pendingGrant !== undefined && decisionCommittedOf(out) && deps.approvalExemptionStore) {
|
|
862
875
|
try {
|
|
863
876
|
await deps.approvalExemptionStore.grant(pendingGrant.sessionId, pendingGrant.toolName, deciderPrincipal ?? null);
|
|
864
877
|
rememberApplied = true;
|
|
@@ -900,6 +913,7 @@ function approvalsReadFailureOf(err) {
|
|
|
900
913
|
case "corrupt":
|
|
901
914
|
return "approvals.read_corrupt";
|
|
902
915
|
case "connection":
|
|
916
|
+
case "deployment":
|
|
903
917
|
case "unclassified":
|
|
904
918
|
return "approvals.read_unavailable";
|
|
905
919
|
default: {
|
|
@@ -940,7 +954,7 @@ function projectPendingForWire(row, deployment) {
|
|
|
940
954
|
governanceForced: governanceForced === true,
|
|
941
955
|
requiresRealApproval: row.requiresRealApproval === true,
|
|
942
956
|
mandated: row.mandated === true || row.ruleOffersAbsence === "mandated",
|
|
943
|
-
grantBinding:
|
|
957
|
+
grantBinding: grantBindingOf(row),
|
|
944
958
|
classes: row.classes,
|
|
945
959
|
deploymentListQuestion,
|
|
946
960
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PERMISSION_MODES, USER_ATTACHMENT_SEAT, expandTiers, reasoningEffortLevelsOf, routePairingStatus } from "@sema-agent/core";
|
|
1
|
+
import { PERMISSION_MODES, USER_ATTACHMENT_SEAT, expandTiers, reasoningEffortLevelsOf, routePairingStatus, thinkingOffSpelled } from "@sema-agent/core";
|
|
2
2
|
import { modelImageInput, modelReasoningDecl, isAtMentionable, selectableAliasNames, selectableCatalog } from "../../model-select.js";
|
|
3
3
|
import { buildDroppedEntriesWire } from "../../web-admin-client/read-warnings.js";
|
|
4
4
|
import { buildCandidateRejectedWire } from "../../web-admin-client/candidate-gate.js";
|
|
@@ -12,7 +12,7 @@ import { leaderEntryRefusal, leaderRunEntry } from "../../leader/run-entry.js";
|
|
|
12
12
|
import { autonomyKeepsOpenWriteFace, autonomyModeFloor } from "../../runtime-governance.js";
|
|
13
13
|
import { DEVICE_PROTOCOL_VERSION, DEVICE_WS_PATH } from "../../device-ws-protocol.js";
|
|
14
14
|
import { a2aInjectionHonored } from "../../task-a2a.js";
|
|
15
|
-
import { buildEmptyMcpProbeFace, buildMcpInjectionRefusal, buildMcpProbeCacheKey, buildMcpProbeInflightRefusal, buildMcpProbeRateKey, buildMcpProbeRateRefusal, createMcpProbeLocal, buildMcpProbeDeclarationRefusal, buildMcpProbeIncompleteRefusal, McpProbeIncomplete, McpProbeMisaligned, MCP_PROBE_HTTP_STATUS, MCP_PROBE_MAX_INFLIGHT, MCP_PROBE_VERDICT_TIMEOUT_MS, createMcpProbeWalk, readMcpProbeBody, } from "../../capabilities/mcp-probe.js";
|
|
15
|
+
import { buildEmptyMcpProbeFace, buildMcpInjectionRefusal, buildMcpProbeCacheKey, buildMcpProbeInflightRefusal, buildMcpProbeRateKey, buildMcpProbeRateRefusal, createMcpProbeLocal, buildMcpProbeDeclarationRefusal, buildMcpProbeIncompleteRefusal, McpProbeIncomplete, McpProbeMisaligned, MCP_PROBE_HTTP_STATUS, MCP_PROBE_MAX_INFLIGHT, MCP_PROBE_VERDICT_TIMEOUT_MS, countMcpProbeDeclarations, createMcpProbeWalk, readMcpProbeBody, } from "../../capabilities/mcp-probe.js";
|
|
16
16
|
import { mcpForScenario } from "../../web-admin-client/facade.js";
|
|
17
17
|
import { sendScenarioNotFound } from "../scenario-read-face.js";
|
|
18
18
|
import { sendJson, sendError } from "../send.js";
|
|
@@ -23,6 +23,7 @@ import { projectWriteProtectionCapability } from "../../write-protection.js";
|
|
|
23
23
|
import { projectStoreCapability } from "../../store-posture.js";
|
|
24
24
|
import { projectWebSearchCapability } from "../../plugins/web-search.js";
|
|
25
25
|
import { projectExecutionLaneCapability } from "../../capabilities/execution-lane.js";
|
|
26
|
+
import { judgeSandboxGitPlane, sandboxGitPlanePremisesOf } from "../../sandbox-git-plane.js";
|
|
26
27
|
import { MCP_ASSERTION_HEADER_SENT } from "../../mcp-assertion-header.js";
|
|
27
28
|
import { gateCompositeMembers } from "../../capabilities/composite-members.js";
|
|
28
29
|
import { projectApprovalsStreamLiveCapability } from "../../capabilities/approvals-push.js";
|
|
@@ -86,9 +87,17 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
86
87
|
artifacts: facts.durableRuns(deps).available,
|
|
87
88
|
approvals: facts.checkpointPark(deps).available,
|
|
88
89
|
approvalReadRootGrant: facts.readRootGrant(deps).available,
|
|
90
|
+
modsDeploymentPackages: facts.deploymentModPackages(deps).available ? true : undefined,
|
|
89
91
|
sessions: facts.sessionAuditView(deps).available,
|
|
90
92
|
deviceExecutor: facts.deviceLane(deps).available
|
|
91
|
-
? {
|
|
93
|
+
? {
|
|
94
|
+
enabled: true,
|
|
95
|
+
protocolVersion: DEVICE_PROTOCOL_VERSION,
|
|
96
|
+
maxInflightPerDevice: deps.config.remoteExec?.provider === "device" ? (deps.config.remoteExec.maxInflightPerDevice ?? 4) : 4,
|
|
97
|
+
wsPath: DEVICE_WS_PATH,
|
|
98
|
+
management: facts.deviceManagement(deps).available,
|
|
99
|
+
...(deps.config.remoteExec?.provider === "device" && deps.config.remoteExec.relayUrl !== undefined ? { relayUrl: deps.config.remoteExec.relayUrl } : {}),
|
|
100
|
+
}
|
|
92
101
|
: false,
|
|
93
102
|
sessionEvents: facts.sessionEventStream(deps).available,
|
|
94
103
|
fleet: facts.fleetStream(deps).available
|
|
@@ -180,6 +189,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
180
189
|
approvalFrameFamilies: [...facts.approvalFrameFamilies(streamApprovalFact)],
|
|
181
190
|
approvalDecisionNote: true,
|
|
182
191
|
approvalDecidedBy: true,
|
|
192
|
+
planReviewCheckpointId: true,
|
|
183
193
|
permissionModes: [...PERMISSION_MODES],
|
|
184
194
|
sessionReadRedaction: true,
|
|
185
195
|
sideQuery: true,
|
|
@@ -224,6 +234,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
224
234
|
configCatalog: facts.configCatalog(deps).available,
|
|
225
235
|
sealedKey: projectSealedKeyCapability(deps.sealedKeyPublic),
|
|
226
236
|
workspaceSync: ((space, cache) => space.available || cache.available ? { ...(space.available ? space.policy : {}), ...(cache.available ? { cache: cache.cache } : {}) } : undefined)(facts.workspaceSpace(deps.config), facts.workspaceCache(deps.config)),
|
|
237
|
+
credentialPlane: { sandboxGit: deps.sandboxGitPlane ?? judgeSandboxGitPlane(sandboxGitPlanePremisesOf(deps.config, {})) },
|
|
227
238
|
}));
|
|
228
239
|
return;
|
|
229
240
|
}
|
|
@@ -239,7 +250,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
239
250
|
return;
|
|
240
251
|
}
|
|
241
252
|
const scenarioName = await deps.scenarioGate(principal, scenarioParams[0]);
|
|
242
|
-
await serveMcpProbeFace(res, ctx, principal, mcpForScenario(deps.config.mcpServers, scenarioName) ?? []
|
|
253
|
+
await serveMcpProbeFace(res, ctx, principal, { declaredBy: "deployment", specs: mcpForScenario(deps.config.mcpServers, scenarioName) ?? [] });
|
|
243
254
|
return;
|
|
244
255
|
}
|
|
245
256
|
case "capability-mcp-probe": {
|
|
@@ -257,7 +268,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
257
268
|
sendMcpProbeRefusal(res, ctx, parsed.refusal, "bad_request");
|
|
258
269
|
return;
|
|
259
270
|
}
|
|
260
|
-
await serveMcpProbeFace(res, ctx, principal,
|
|
271
|
+
await serveMcpProbeFace(res, ctx, principal, { declaredBy: "caller", drafts: parsed.drafts });
|
|
261
272
|
return;
|
|
262
273
|
}
|
|
263
274
|
case "models": {
|
|
@@ -272,6 +283,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
272
283
|
provider: m.provider,
|
|
273
284
|
...(modelReasoningDecl(m) !== undefined ? { reasoning: modelReasoningDecl(m) } : {}),
|
|
274
285
|
...(modelImageInput(m) !== "undeclared" ? { vision: modelImageInput(m) === "yes" } : {}),
|
|
286
|
+
supportsThinkingOff: thinkingOffSpelled(m),
|
|
275
287
|
...(m.contextWindow ? { contextWindow: m.contextWindow } : {}),
|
|
276
288
|
...(m.maxTokens ? { maxOutputTokens: m.maxTokens } : {}),
|
|
277
289
|
...((levels) => (levels !== undefined ? { supportedEffortLevels: [...levels] } : {}))(reasoningEffortLevelsOf(m)),
|
|
@@ -312,18 +324,18 @@ function sendMcpProbeRefusal(res, ctx, refusal, outcome, retryAfterSec) {
|
|
|
312
324
|
...(retryAfterSec !== undefined ? { retryAfterSec } : {}),
|
|
313
325
|
});
|
|
314
326
|
}
|
|
315
|
-
async function serveMcpProbeFace(res, ctx, principal,
|
|
327
|
+
async function serveMcpProbeFace(res, ctx, principal, input) {
|
|
316
328
|
const { deps } = ctx;
|
|
317
329
|
const local = ctx.local.capabilities.mcpProbe;
|
|
318
|
-
if (
|
|
330
|
+
if (countMcpProbeDeclarations(input) === 0) {
|
|
319
331
|
deps.metrics?.inc("mcp_probe_total", { outcome: "empty" });
|
|
320
332
|
sendJson(res, 200, buildEmptyMcpProbeFace());
|
|
321
333
|
return;
|
|
322
334
|
}
|
|
323
|
-
const key = buildMcpProbeCacheKey(principal,
|
|
335
|
+
const key = buildMcpProbeCacheKey(principal, input);
|
|
324
336
|
const hit = local.cached(key, Date.now());
|
|
325
337
|
if (hit !== undefined) {
|
|
326
|
-
await answerMcpProbe(res, ctx, hit, "cached", declaredBy);
|
|
338
|
+
await answerMcpProbe(res, ctx, hit, "cached", input.declaredBy);
|
|
327
339
|
return;
|
|
328
340
|
}
|
|
329
341
|
if (local.inflight() >= MCP_PROBE_MAX_INFLIGHT) {
|
|
@@ -335,9 +347,9 @@ async function serveMcpProbeFace(res, ctx, principal, specs, declaredBy) {
|
|
|
335
347
|
sendMcpProbeRefusal(res, ctx, buildMcpProbeRateRefusal(), "rate_limited", verdict.retryAfterSec);
|
|
336
348
|
return;
|
|
337
349
|
}
|
|
338
|
-
const walk = createMcpProbeWalk(
|
|
350
|
+
const walk = createMcpProbeWalk(input, principal, deps.peerDesk);
|
|
339
351
|
local.remember(key, Date.now(), walk);
|
|
340
|
-
await answerMcpProbe(res, ctx, walk.answer, "probed", declaredBy);
|
|
352
|
+
await answerMcpProbe(res, ctx, walk.answer, "probed", input.declaredBy);
|
|
341
353
|
}
|
|
342
354
|
async function answerMcpProbe(res, ctx, answer, outcome, declaredBy) {
|
|
343
355
|
const { deps } = ctx;
|
|
@@ -25,8 +25,9 @@
|
|
|
25
25
|
* `unsupported` 挂 409 更会把「这条 run 没有 MCP 面」谎报成一个活性问题。
|
|
26
26
|
*
|
|
27
27
|
* ── 下一步动作按 `status`,不解析 `reason`(core [ref] 键表逐字)────────────────────────────────
|
|
28
|
-
* `status.errorCode` / `status.httpStatus` 是机器面(`
|
|
29
|
-
*
|
|
28
|
+
* `status.errorCode` / `status.httpStatus` 是机器面(`unauthorized` 是一扇要用户授权的门 —— 引擎 7.59.0 起 401 与带 `insufficient_scope` 的 403 读这个词、不再是
|
|
29
|
+
* `http_status` + 状态数;`spawn_failed` 是
|
|
30
|
+
* 缺二进制);`reason` 是**人读**的一句话(它可能嵌远端文本:引擎铸点抹过请求回显与同主体词表,出门经出口座 `mcp-remote-text` 行 —— 同一个脱敏器、界 200 —— 投出),
|
|
30
31
|
* 消费端**不许**解析它。名册**按 `tools` 的在场性**投成 `toolNames`(present-iff),**不按 `outcome`**。
|
|
31
32
|
*
|
|
32
33
|
* ── 查找与拒绝形(与 steer / capture-optout **同一只**,不新造)───────────────────────────────────
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { isParkedRunStatus, isTerminalRunStatus, runProvenElsewhere } from "../../plugins/store-contracts.js";
|
|
3
|
-
import { redactSecrets } from "../../trace/redact.js";
|
|
4
3
|
import { DeadlineExceeded, MCP_DIAL_DEADLINE_MS, raceDeadline } from "../mcp-dial-deadline.js";
|
|
5
4
|
import { sendJson, sendError } from "../send.js";
|
|
6
5
|
import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal } from "../principal-gate.js";
|
|
@@ -8,9 +7,9 @@ import {} from "../route-ctx.js";
|
|
|
8
7
|
import { assertNever, SESSION_NOT_FOUND_MESSAGE } from "../route-ctx.js";
|
|
9
8
|
import * as facts from "../../capability-facts.js";
|
|
10
9
|
import { sessionOwnerCellOf } from "../../security.js";
|
|
10
|
+
import { seatText } from "../../trace/exit-seat.js";
|
|
11
|
+
import { projectMcpAuthorization } from "../../mcp-authorization-face.js";
|
|
11
12
|
const BodySchema = z.object({ server: z.string().min(1).max(190) }).strict();
|
|
12
|
-
const NEUTRALIZED_TEXT_MAX = 200;
|
|
13
|
-
const humanText = (s) => redactSecrets(s).slice(0, NEUTRALIZED_TEXT_MAX);
|
|
14
13
|
function outcomeOf(coreOutcome) {
|
|
15
14
|
switch (coreOutcome) {
|
|
16
15
|
case "reconnected": return "accepted";
|
|
@@ -26,8 +25,9 @@ function projectStatus(s) {
|
|
|
26
25
|
...(s.errorCode !== undefined ? { errorCode: s.errorCode } : {}),
|
|
27
26
|
...(s.httpStatus !== undefined ? { httpStatus: s.httpStatus } : {}),
|
|
28
27
|
...(s.delivered !== undefined ? { delivered: s.delivered } : {}),
|
|
28
|
+
...((a) => (a !== undefined ? { authorization: a } : {}))(projectMcpAuthorization(s.authorization)),
|
|
29
29
|
...(s.serverInfo !== undefined ? { serverInfo: s.serverInfo } : {}),
|
|
30
|
-
...(s.error !== undefined ? { error:
|
|
30
|
+
...(s.error !== undefined ? { error: seatText("mcp-remote-text", String(s.error)) } : {}),
|
|
31
31
|
...(s.transportClosed !== undefined ? { transportClosed: s.transportClosed } : {}),
|
|
32
32
|
};
|
|
33
33
|
}
|
|
@@ -36,7 +36,7 @@ function projectListingIncomplete(l) {
|
|
|
36
36
|
reason: l.reason,
|
|
37
37
|
pages: l.pages,
|
|
38
38
|
...(l.budgetMs !== undefined ? { budgetMs: l.budgetMs } : {}),
|
|
39
|
-
...(l.error !== undefined ? { error:
|
|
39
|
+
...(l.error !== undefined ? { error: seatText("mcp-remote-text", l.error) } : {}),
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
42
|
function projectResult(r) {
|
|
@@ -48,7 +48,7 @@ function projectResult(r) {
|
|
|
48
48
|
added: r.added,
|
|
49
49
|
removed: r.removed,
|
|
50
50
|
...(r.tools !== undefined ? { toolNames: r.tools.map((t) => t.name) } : {}),
|
|
51
|
-
...(r.reason !== undefined ? { reason:
|
|
51
|
+
...(r.reason !== undefined ? { reason: seatText("mcp-remote-text", r.reason) } : {}),
|
|
52
52
|
...(r.status !== undefined ? { status: projectStatus(r.status) } : {}),
|
|
53
53
|
...(r.listingIncomplete !== undefined ? { listingIncomplete: projectListingIncomplete(r.listingIncomplete) } : {}),
|
|
54
54
|
};
|
|
@@ -114,7 +114,7 @@ export async function handleMcpReconnect(req, res, match, ctx) {
|
|
|
114
114
|
const msg = e instanceof Error ? e.message : String(e);
|
|
115
115
|
switch (code) {
|
|
116
116
|
case "mcp.reconnect_unavailable":
|
|
117
|
-
sendJson(res, 200, { taskId: activeTaskId, sessionId, server, outcome: "unsupported", reason:
|
|
117
|
+
sendJson(res, 200, { taskId: activeTaskId, sessionId, server, outcome: "unsupported", reason: seatText("mcp-remote-text", msg) });
|
|
118
118
|
return;
|
|
119
119
|
case "steering.invalid_content":
|
|
120
120
|
sendError(res, 422, "steering.invalid_content", msg);
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* · 调用方显式给 `scope` ⇒ 用它 —— 哪怕它不在 `MEMORY_CONSOLIDATION_SCOPES` 里。
|
|
25
25
|
* 🔴 那张表**不是授权边界**:本仓今天没有任何授权源能对一个 operator 收窄 scope(`gateMemoryScope`
|
|
26
26
|
* 的 operator 支在查目录之前就 allow;`org-memory-admission` 明写 v1 不中央收窄 operator 声明的
|
|
27
|
-
* scope —— 全文见 `src/memory-operator-faces.ts`
|
|
27
|
+
* scope —— 全文见 `src/memory-operator-faces.ts` `MemoryComplianceFaces.erase` 的「授权座只有一只」段)。在本层拿它当
|
|
28
28
|
* 白名单就是**发明第二套授权语义**,与 `gateMemoryScope` 对同一个身份给出相反答案;
|
|
29
29
|
* · 省略 `scope` ⇒ 只有表**恰好一条**时才有缺省(那条就是这台部署的库);零条或两条以上一律 400,
|
|
30
30
|
* 并把候选列进文案 —— 让运维一眼看到「我该点哪一个」。
|
|
@@ -114,7 +114,7 @@ export declare function buildClearanceRowWire(r: OriginClearanceRow): {
|
|
|
114
114
|
baseRev: string;
|
|
115
115
|
origin: {
|
|
116
116
|
at: number;
|
|
117
|
-
cause?: "static" | "
|
|
117
|
+
cause?: "static" | "unattributed" | "observed" | "derived" | undefined;
|
|
118
118
|
taint: "external";
|
|
119
119
|
};
|
|
120
120
|
};
|
|
@@ -7,7 +7,7 @@ import { createLogger } from "../../observability/logger.js";
|
|
|
7
7
|
import { RULE_IMPORT_RETRY_AFTER_SEC, RULE_SCOPE_REFUSAL_SENTENCE, MAX_RULE_SCOPE_CHARS, buildCcImportLayerRootRefusal, parseRuleScope, serializeRuleScope } from "../../rules-consent.js";
|
|
8
8
|
import { hasControlOrBidi } from "@sema-agent/settings-schema";
|
|
9
9
|
import { IMPORTED_SETTINGS_LAYERS, MAX_RULE_TEXT_CHARS, PERSISTED_RULE_MATCHES, RULE_ADD_ORIGINS, RULE_BEHAVIORS, isValidDurableScope } from "@sema-agent/core";
|
|
10
|
-
import {
|
|
10
|
+
import { isDirectWritableRuleBehavior } from "../../permission-rule-vocab.js";
|
|
11
11
|
const logger = createLogger();
|
|
12
12
|
export const RULES_CC_IMPORT_PREPARE_PATH = "/v1/rules/cc-import/prepare";
|
|
13
13
|
export const RULES_CC_IMPORT_REDEEM_PATH = "/v1/rules/cc-import/redeem";
|
|
@@ -50,9 +50,9 @@ const LocalImportRowSchema = z
|
|
|
50
50
|
rule: z.string().min(1).max(MAX_RULE_TEXT_CHARS),
|
|
51
51
|
scope: z.string().min(1).max(MAX_RULE_SCOPE_CHARS),
|
|
52
52
|
behavior: z.enum(RULE_BEHAVIORS),
|
|
53
|
-
tool: z.string().min(1).max(190)
|
|
53
|
+
tool: z.string().min(1).max(190),
|
|
54
54
|
match: z.enum(PERSISTED_RULE_MATCHES),
|
|
55
|
-
command: z.string().
|
|
55
|
+
command: z.string().max(MAX_RULE_TEXT_CHARS),
|
|
56
56
|
adds: z.array(LocalImportAddSchema).max(64),
|
|
57
57
|
})
|
|
58
58
|
.strict();
|