@sema-agent/server 7.140.0 → 7.142.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 +505 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +142 -25
- package/dist/approval-ask-audit-store.d.ts +54 -38
- package/dist/approval-ask-audit-store.js +58 -39
- package/dist/approval-batch-census.d.ts +27 -0
- package/dist/approval-batch-census.js +27 -0
- package/dist/approval-card.d.ts +39 -24
- package/dist/approval-card.js +6 -3
- 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-reconciler.d.ts +33 -1
- package/dist/approval-reconciler.js +43 -40
- package/dist/approval.d.ts +15 -0
- package/dist/approval.js +10 -0
- package/dist/audit.d.ts +4 -2
- package/dist/audit.js +2 -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 +16 -0
- package/dist/boot/budget-tracing.js +10 -6
- package/dist/boot/device-lane.d.ts +11 -0
- package/dist/boot/device-lane.js +16 -0
- package/dist/boot/engine-lease.d.ts +24 -3
- package/dist/boot/engine-lease.js +9 -2
- package/dist/boot/execution-env.d.ts +24 -4
- package/dist/boot/execution-env.js +34 -27
- package/dist/boot/execution-lane.js +2 -1
- package/dist/boot/exit-boundary.js +5 -4
- package/dist/boot/memory-boundary.d.ts +2 -2
- package/dist/boot/memory-consolidation.d.ts +1 -1
- package/dist/boot/memory-consolidation.js +3 -2
- 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.d.ts +2 -2
- package/dist/boot/reapers.js +4 -3
- package/dist/boot/resolve-spec.js +18 -6
- package/dist/boot/retention-lane.js +5 -3
- package/dist/boot/runner-deps.js +16 -13
- package/dist/boot/runtime-caps.js +3 -2
- package/dist/boot/session-faces.d.ts +1 -1
- package/dist/boot/session-faces.js +8 -6
- package/dist/boot/shutdown.js +8 -2
- package/dist/boot/stage-04-stores.js +3 -2
- package/dist/boot/stage-05-execution-env.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.js +11 -7
- package/dist/boot/stage-06-runners.d.ts +1 -3
- package/dist/boot/stage-06-runners.js +3 -2
- package/dist/boot/stage-07-capability-layer.d.ts +1 -2
- package/dist/boot/stage-07-capability-layer.js +10 -11
- package/dist/boot/stage-08-reapers.d.ts +1 -2
- package/dist/boot/stage-08-reapers.js +3 -2
- package/dist/boot/stage-09-leader.d.ts +1 -2
- package/dist/boot/stage-10-http-server.d.ts +1 -2
- package/dist/boot/stage-10-http-server.js +6 -4
- package/dist/boot/stores.js +13 -6
- package/dist/boot/web-admin.js +18 -17
- 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/scenarios.d.ts +1 -1
- package/dist/capability-facts.d.ts +33 -0
- package/dist/capability-facts.js +32 -0
- package/dist/card-void.d.ts +38 -0
- package/dist/card-void.js +23 -0
- package/dist/config-catalog.js +12 -8
- package/dist/config-provider.d.ts +13 -13
- package/dist/config-provider.js +19 -33
- package/dist/config-types.d.ts +39 -10
- package/dist/config.d.ts +6 -0
- package/dist/config.js +72 -49
- package/dist/delegated-session-owner.d.ts +21 -19
- package/dist/delegated-session-owner.js +1 -1
- package/dist/device-store.d.ts +7 -0
- package/dist/device-store.js +3 -0
- package/dist/execution-config-root.d.ts +22 -0
- package/dist/execution-config-root.js +35 -0
- package/dist/execution-lane-caps.d.ts +50 -2
- package/dist/execution-lane-caps.js +90 -13
- package/dist/execution-placement.d.ts +3 -0
- package/dist/execution-placement.js +7 -0
- package/dist/fleet/drain-entry.d.ts +3 -0
- package/dist/fleet/fleet-bus.d.ts +6 -3
- package/dist/hooks/hook-runner.d.ts +6 -0
- package/dist/hooks/hook-runner.js +30 -1
- package/dist/hosted-posture.d.ts +8 -0
- package/dist/hosted-posture.js +4 -0
- package/dist/http/admission.js +3 -3
- package/dist/http/caller-trust.d.ts +3 -2
- package/dist/http/caller-trust.js +2 -1
- package/dist/http/dispatch.js +8 -2
- package/dist/http/execution-context.d.ts +2 -2
- package/dist/http/idempotency.d.ts +1 -1
- package/dist/http/live-frame.d.ts +24 -0
- package/dist/http/live-frame.js +16 -0
- package/dist/http/principal-gate.d.ts +3 -1
- package/dist/http/principal-gate.js +17 -8
- package/dist/http/resume-legs.js +42 -29
- package/dist/http/route-table.js +4 -0
- package/dist/http/routes/approvals-assistant.js +1 -0
- package/dist/http/routes/attachments.js +18 -0
- package/dist/http/routes/capabilities.js +10 -6
- package/dist/http/routes/diagnostics.d.ts +0 -19
- package/dist/http/routes/diagnostics.js +16 -2
- package/dist/http/routes/memory-bundle.d.ts +2 -2
- package/dist/http/routes/memory-bundle.js +1 -1
- package/dist/http/routes/memory-compliance.js +1 -1
- package/dist/http/routes/memory-policy.js +27 -7
- package/dist/http/routes/run-permission-mode.d.ts +75 -0
- package/dist/http/routes/run-permission-mode.js +170 -0
- package/dist/http/routes/runs.js +3 -3
- package/dist/http/routes/session-memory-sync.d.ts +63 -0
- package/dist/http/routes/session-memory-sync.js +157 -0
- package/dist/http/routes/session-sync.d.ts +3 -6
- package/dist/http/routes/session-sync.js +7 -2
- package/dist/http/routes/sessions-list.d.ts +2 -1
- package/dist/http/routes/sessions.js +5 -4
- package/dist/http/routes/tasks.js +70 -71
- package/dist/http/run-read-face.d.ts +7 -0
- package/dist/http/run-read-face.js +10 -4
- package/dist/http/send.d.ts +6 -1
- package/dist/http/send.js +10 -3
- package/dist/http/server.d.ts +20 -7
- package/dist/http/server.js +2 -4
- package/dist/http/sse-log.d.ts +3 -8
- package/dist/http/stored-body-replay.d.ts +3 -3
- package/dist/http/stored-body-replay.js +3 -1
- 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/identity-source.d.ts +21 -2
- package/dist/identity-source.js +6 -0
- package/dist/instruction-source-notice.d.ts +7 -0
- package/dist/instruction-source-notice.js +6 -6
- package/dist/mcp-assertion-header.d.ts +4 -0
- package/dist/mcp-assertion-header.js +5 -0
- package/dist/memory-incident-sink.d.ts +19 -6
- package/dist/memory-incident-sink.js +8 -4
- package/dist/memory-posture.d.ts +1 -1
- package/dist/memory-scope.d.ts +4 -4
- package/dist/memory-scope.js +1 -1
- package/dist/memory-sync-client.d.ts +35 -23
- package/dist/memory-sync-client.js +122 -52
- package/dist/memory-sync-identity.d.ts +24 -0
- package/dist/memory-sync-identity.js +57 -0
- package/dist/memory-sync.d.ts +7 -1
- package/dist/memory-sync.js +6 -3
- package/dist/observability/fail-open.d.ts +57 -12
- package/dist/observability/fail-open.js +50 -9
- package/dist/observability/metrics.js +0 -1
- package/dist/observability/run-terminal.d.ts +93 -31
- package/dist/observability/run-terminal.js +175 -171
- package/dist/observability/secret-env-scrub.d.ts +20 -1
- package/dist/observability/secret-env-scrub.js +14 -0
- package/dist/orchestration/workflow-completion-inbox.d.ts +5 -2
- package/dist/orchestration/workflow-completion-inbox.js +13 -5
- package/dist/orchestration/workflow-notify-journal.d.ts +5 -3
- package/dist/orchestration/workflow-notify-journal.js +2 -1
- package/dist/permission-mode-admission.d.ts +68 -0
- package/dist/permission-mode-admission.js +23 -0
- package/dist/permission-rule-list.d.ts +55 -6
- package/dist/permission-rule-list.js +52 -5
- package/dist/plugins/approval-ask-store-file.d.ts +14 -4
- package/dist/plugins/approval-ask-store-file.js +48 -7
- package/dist/plugins/approval-ask-store-memory.d.ts +2 -1
- package/dist/plugins/approval-ask-store-memory.js +9 -8
- package/dist/plugins/approval-ask-store-sql.d.ts +42 -10
- package/dist/plugins/approval-ask-store-sql.js +49 -19
- package/dist/plugins/caching-session-store.d.ts +6 -0
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +65 -17
- package/dist/plugins/checkpoint-store-sql.js +74 -3
- package/dist/plugins/device-store-sql.d.ts +5 -2
- package/dist/plugins/device-store-sql.js +4 -1
- package/dist/plugins/execution-placement-sql.d.ts +11 -1
- package/dist/plugins/execution-placement-sql.js +12 -1
- package/dist/plugins/file-run-store.d.ts +7 -2
- package/dist/plugins/file-run-store.js +12 -2
- package/dist/plugins/fork-routing-session-store.d.ts +10 -32
- package/dist/plugins/fork-routing-session-store.js +2 -61
- package/dist/plugins/k8s-exec-protocol.d.ts +4 -1
- package/dist/plugins/k8s-exec-protocol.js +6 -1
- package/dist/plugins/local-checkpoint-store.d.ts +10 -1
- package/dist/plugins/local-checkpoint-store.js +22 -0
- package/dist/plugins/local-session-store.d.ts +260 -39
- package/dist/plugins/local-session-store.js +582 -57
- package/dist/plugins/local-session-window.d.ts +17 -3
- package/dist/plugins/local-session-window.js +7 -13
- package/dist/plugins/local-task-attachment-store.d.ts +12 -2
- package/dist/plugins/local-task-attachment-store.js +67 -43
- package/dist/plugins/memory-key-guards.d.ts +3 -3
- package/dist/plugins/memory-run-store.d.ts +7 -2
- package/dist/plugins/memory-run-store.js +12 -2
- package/dist/plugins/one-time-migrations.d.ts +68 -2
- package/dist/plugins/one-time-migrations.js +120 -4
- package/dist/plugins/pg-pool.js +3 -2
- package/dist/plugins/pg-session-storage.d.ts +2 -0
- package/dist/plugins/pg-session-storage.js +3 -2
- package/dist/plugins/remote-env-e2b.d.ts +47 -7
- package/dist/plugins/remote-env-e2b.js +242 -46
- package/dist/plugins/remote-env-k8s.d.ts +51 -6
- package/dist/plugins/remote-env-k8s.js +234 -44
- package/dist/plugins/remote-env-local-docker.d.ts +40 -14
- package/dist/plugins/remote-env-local-docker.js +127 -33
- package/dist/plugins/run-store-sql.d.ts +11 -3
- package/dist/plugins/run-store-sql.js +13 -4
- package/dist/plugins/sandbox-read-floor.d.ts +273 -0
- package/dist/plugins/sandbox-read-floor.js +608 -0
- package/dist/plugins/session-ownership.d.ts +2 -1
- package/dist/plugins/session-placement.d.ts +17 -4
- package/dist/plugins/session-placement.js +2 -1
- package/dist/plugins/session-store.d.ts +18 -20
- package/dist/plugins/session-store.js +4 -12
- package/dist/plugins/store-backend.d.ts +41 -7
- package/dist/plugins/store-backend.js +22 -4
- package/dist/plugins/store-contracts.d.ts +35 -3
- package/dist/plugins/store-contracts.js +3 -0
- package/dist/plugins/task-attachment-store.d.ts +112 -14
- package/dist/plugins/task-attachment-store.js +221 -28
- package/dist/plugins/tidb-pool.js +2 -1
- package/dist/plugins/tidb-session-store.d.ts +4 -1
- package/dist/plugins/tidb-session-store.js +3 -2
- 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/run-cancel-context.d.ts +34 -0
- package/dist/run-cancel-context.js +7 -0
- package/dist/run-local.js +2 -8
- package/dist/runs.d.ts +39 -12
- package/dist/runs.js +69 -55
- 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 +11 -2
- package/dist/security.js +8 -0
- package/dist/server-secret-env.d.ts +2 -1
- package/dist/server-secret-env.js +2 -4
- package/dist/session-error-wire.d.ts +46 -4
- package/dist/session-error-wire.js +23 -0
- package/dist/session-incarnation.d.ts +9 -3
- package/dist/session-sync-kernel.d.ts +42 -1
- package/dist/session-sync-kernel.js +17 -0
- package/dist/session-sync.js +16 -4
- package/dist/sql-engine-coordinates.d.ts +49 -0
- package/dist/sql-engine-coordinates.js +27 -0
- package/dist/standing-answer-grant.d.ts +31 -2
- package/dist/standing-answer-grant.js +14 -2
- package/dist/store-posture.d.ts +1 -1
- package/dist/task-a2a.d.ts +1 -1
- package/dist/task-mcp.d.ts +1 -1
- package/dist/task-settings.d.ts +62 -27
- package/dist/task-settings.js +105 -29
- package/dist/terminal.d.ts +97 -20
- package/dist/terminal.js +107 -18
- package/dist/tool-approval.d.ts +4 -3
- package/dist/tool-approval.js +12 -14
- package/dist/trace/core-keyset-guard.d.ts +196 -2
- package/dist/trace/engine-notice-wire.d.ts +8 -2
- package/dist/trace/engine-notice-wire.js +4 -2
- package/dist/trace/exit-seat.d.ts +9 -1
- package/dist/trace/exit-seat.js +1 -0
- package/dist/trace/ledger-sink.d.ts +8 -4
- package/dist/trace/ledger-sink.js +2 -2
- package/dist/trace/model-segment.d.ts +2 -2
- package/dist/trace/project.d.ts +18 -1
- package/dist/trace/project.js +16 -0
- package/dist/trace/redact.js +323 -90
- package/dist/trace/self-minted-wire.d.ts +419 -4
- package/dist/trace/self-minted-wire.js +145 -0
- package/dist/trace/wire-projection-faces.d.ts +1 -1
- package/dist/trace/wire-projection-faces.js +1 -1
- package/dist/verifier-pause-card.d.ts +8 -0
- package/dist/verifier-pause-card.js +19 -0
- package/dist/web-admin-client/apply-effective.d.ts +5 -7
- package/dist/web-admin-client/apply-effective.js +22 -2
- package/dist/web-admin-client/candidate-gate.d.ts +1 -1
- package/dist/web-admin-client/effective-keys.js +2 -0
- package/dist/web-admin-client/read-warnings.d.ts +2 -2
- package/dist/web-admin-client/types.d.ts +4 -0
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -2
- package/package.json +2 -2
- package/wire-changes/server@7.141.0.json +367 -0
- package/wire-changes/server@7.142.0.json +639 -0
package/dist/runs.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { defaultTaskRegistry, type CascadeConfig, type CheckpointToken, type RunInternals, type Runner, type SubagentSteerHandle, type TaskResult, type TaskSpec, type TaskStream, type TerminalCause } from "@sema-agent/core";
|
|
2
|
+
import { type CardVoidPort } from "./card-void.js";
|
|
2
3
|
import { type EntryProblem } from "./entry-problems.js";
|
|
3
4
|
import type { SendUserFileEmitter } from "./capabilities/send-user-file-tool.js";
|
|
4
5
|
import type { RunStore } from "./plugins/store-backend.js";
|
|
@@ -181,9 +182,24 @@ export declare function releaseKeyIfZeroWorkRefusal(runStore: {
|
|
|
181
182
|
export declare function createPromptCommitReader(): (ev: {
|
|
182
183
|
readonly type: string;
|
|
183
184
|
}) => string | undefined;
|
|
185
|
+
/** 回退锚写在哪条腿上(探针行的 `leg=`):流式腿 `POST /v1/tasks/stream`、后台腿 `POST /v1/runs`、续跑腿。 */
|
|
186
|
+
export type ResumeAnchorLeg = "stream" | "bg" | "resume";
|
|
187
|
+
/**
|
|
188
|
+
* 回退锚的**唯一**写法(三条腿同一只):**有界** await 写入(单行店操作期限 {@link BASELINE_IO_DEADLINE_MS},与项目指令基线的
|
|
189
|
+
* 读写同一只数、同一只 {@link withinIoDeadline} —— 同为单行 PK 写、同在腿的关键路径上);写失败或到期 ⇒ 不抛(锚是这次提示词能不能
|
|
190
|
+
* 回退的手柄,不是 run 的成败),记一次登记过的 fail-open `server.resume-anchor.capture-failed`(`reason=error|timeout`;计数 + 探针行 + 一次性 warn)。
|
|
191
|
+
* 调用方在本腿的终帧(流式腿的 `done`)**之前** await 它 ⇒ 客户端拿到终帧时锚已落定或已知没落定,没有「锚晚到」的窗;锚店挂住至多让终帧晚一个期限。
|
|
192
|
+
* 到期只放手不取消:那次写照常在飞,迟到落定的锚照样可用(迟到的失败被吞,不重复计数)。
|
|
193
|
+
* 用户面的读数仍只有一处:会话视图用户消息行的 `taskId?`(present-iff 锚在)与 `resumeAt` 的 404 `resume_at.unknown_event`。
|
|
194
|
+
*/
|
|
195
|
+
export declare function settleResumeAnchor(write: () => Promise<void>, where: {
|
|
196
|
+
readonly leg: ResumeAnchorLeg;
|
|
197
|
+
readonly kind: "prompt" | "turn";
|
|
198
|
+
}): Promise<void>;
|
|
184
199
|
export declare class TurnAnchorCapture {
|
|
185
200
|
private readonly capture;
|
|
186
|
-
|
|
201
|
+
/** 这只捕获器在哪条腿上(写失败的 fail-open 探针行带它)。 */
|
|
202
|
+
private readonly leg;
|
|
187
203
|
/** R8 (CC-parity rewind): capture a USER-message anchor straight from the
|
|
188
204
|
* `message_committed{role:"user"}` event — its `entryId` is the persisted user-message `SessionTreeEntry.id`,
|
|
189
205
|
* ALWAYS a valid `resumeAt` target (core accepts a user message; it rejects a tool-result / mid-tool-call
|
|
@@ -197,7 +213,9 @@ export declare class TurnAnchorCapture {
|
|
|
197
213
|
private turnHadTool;
|
|
198
214
|
/** 用户提交是不是提问的唯一读法({@link createPromptCommitReader};附件帧不是提问)。 */
|
|
199
215
|
private readonly promptCommit;
|
|
200
|
-
constructor(capture: ((eventId: string) => Promise<void>) | undefined,
|
|
216
|
+
constructor(capture: ((eventId: string) => Promise<void>) | undefined,
|
|
217
|
+
/** 这只捕获器在哪条腿上(写失败的 fail-open 探针行带它)。 */
|
|
218
|
+
leg: Exclude<ResumeAnchorLeg, "stream">,
|
|
201
219
|
/** R8 (CC-parity rewind): capture a USER-message anchor straight from the
|
|
202
220
|
* `message_committed{role:"user"}` event — its `entryId` is the persisted user-message `SessionTreeEntry.id`,
|
|
203
221
|
* ALWAYS a valid `resumeAt` target (core accepts a user message; it rejects a tool-result / mid-tool-call
|
|
@@ -247,6 +265,20 @@ export declare function parkToolCallId(result: unknown, cs: ParkCheckpointReader
|
|
|
247
265
|
* 不塞进 `checkpointGate`——那是 core 的类型,server 不改其形)。非 park / 无 token / tool-less /
|
|
248
266
|
* 读失败 ⇒ **同一引用**原样返回(键缺席)。graft 不负责 strip——组合序恒为 graft → strip。 */
|
|
249
267
|
export declare function graftParkToolCallId<T>(result: T, cs: ParkCheckpointReader | undefined): Promise<T>;
|
|
268
|
+
/**
|
|
269
|
+
* 🔴 [ref] **停驻没落定就以失败收场的腿:卡的命运先于认领释放**(后台腿与续跑腿同读这一只;动词 = `card-void.ts` 的结算作废)。
|
|
270
|
+
*
|
|
271
|
+
* 腿要以失败收场(行 `failed`、认领释放),而手里的结果是宿主层停驻 —— 引擎交回结果之前已把卡落进 checkpoint 店,卡在本 run 的会话上 ——
|
|
272
|
+
* ⇒ 先把那张卡按它自己的 scope 作废,调用方再放认领。不作废 ⇒ 待决面上留一张卡,兑现它的 run 已经 `failed`、认领已放:决定口照样受理,
|
|
273
|
+
* 续跑在没有认领的会话上驱动(`resume-legs.ts` 认领缺席的成因清单)。顺序承重:先放认领、后作废 ⇒ 两步之间(作废没做成时一直)就是那一形。
|
|
274
|
+
* 停驻没落定的成因不在判据里(停驻行 / 用量行 / 结果到手之后的任何一笔账本写抛):判据只读手里那份结果。
|
|
275
|
+
*
|
|
276
|
+
* `held` = 手里那份结果过了宿主判官之后的形(判官提上来的嵌套停驻同样算;不在本 run 会话上的嵌套停驻 —— cascade 级上的卡 —— 判官不提,
|
|
277
|
+
* 不归本腿作废)。不是停驻 ⇒ 零 I/O。不抛:作废没做成 ⇒ 卡回到「留在待决面上、由兜底收割收走」的形,响亮留痕。
|
|
278
|
+
*/
|
|
279
|
+
export declare function voidHeldParkCard(held: {
|
|
280
|
+
readonly terminal: TerminalCause;
|
|
281
|
+
} | undefined, hostSessionId: string | undefined, cards: CardVoidPort | undefined, leg: "bg" | "resume"): Promise<void>;
|
|
250
282
|
/**
|
|
251
283
|
* Drive a task to completion in the background, persisting its events to the durable run log (S2).
|
|
252
284
|
*
|
|
@@ -339,16 +371,11 @@ approval?: {
|
|
|
339
371
|
declaredFamilies: ReadonlySet<ApprovalFrameFamily>; /** 出处带车道:这条执行上下文的车道(装配点 `durable-run-leg.ts` 写 `ctx.lane`)。 */
|
|
340
372
|
executionLane: import("./execution-lane-caps.js").ExecutionLane;
|
|
341
373
|
},
|
|
342
|
-
/**
|
|
343
|
-
* `suspended` 事件带 `toolCallId`(graft 见 {@link parkToolCallId})
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
kind?: unknown;
|
|
348
|
-
toolCallId?: unknown;
|
|
349
|
-
};
|
|
350
|
-
} | null>;
|
|
351
|
-
},
|
|
374
|
+
/** 本腿结算用的 checkpoint 店(`deps.checkpointStore`),两件事:①[ref] park 投影腿的读口 —— 在场时 durable park 的
|
|
375
|
+
* `suspended` 事件带 `toolCallId`(graft 见 {@link parkToolCallId});②验证门结算时作废验证器自己的停驻卡
|
|
376
|
+
* ({@link voidVerifierPauseCard}:本服务兑现不了的卡不留在待决面上);③停驻没落定就以失败收场时作废手里那张卡({@link voidHeldParkCard})。
|
|
377
|
+
* 缺席 ⇒ ①旧字节逐字不变;②③带凭据的停驻响亮留痕、卡由兜底收割。 */
|
|
378
|
+
checkpointCards?: ParkCheckpointReader & CardVoidPort,
|
|
352
379
|
/** [ref]:装配期(`prepareSpec` → `resolveSpec`)铸下的用户面通告 —— 那一刻本腿的通告口还没开,
|
|
353
380
|
* 所以由本腿在 `registerEngineNoticeLeg` 那一拍连同 `pending` 一起投(投递单点仍是 `route()`)。
|
|
354
381
|
* 缺席 ⇒ 一个字节不投(既有调用方逐字不变)。 */
|
package/dist/runs.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { runWithVerification, runCascade, defaultTaskRegistry, taskNotificationDedupKey, DURABLE_AGENT_HANDLE_RE } from "@sema-agent/core";
|
|
2
2
|
import { atHostBoundary, failureCodeOf, sealResultForExit, outwardPlane } from "./terminal.js";
|
|
3
|
+
import { voidVerifierPauseCard } from "./verifier-pause-card.js";
|
|
4
|
+
import { voidPendingCard } from "./card-void.js";
|
|
3
5
|
import { NOT_IN_ROSTER, entryProblemsFacts } from "./entry-problems.js";
|
|
4
6
|
import { GOVERNANCE_HTTP_STATUS } from "./governance-http-status.js";
|
|
5
7
|
import { TOOL_DECLARATION_HTTP_STATUS } from "./tool-declaration-http-status.js";
|
|
@@ -21,6 +23,7 @@ import { defaultSubagentTailBus } from "./fleet/subagent-tail-bus.js";
|
|
|
21
23
|
import { emitPendingWorkflowCompletions, taskNotificationInboxEntry, taskNotificationStreamKeyOf, NotifiedKeys } from "./orchestration/workflow-completion-inbox.js";
|
|
22
24
|
import { isParkLedgerEventType } from "./trace/ledger-events.js";
|
|
23
25
|
import { recordFailOpen } from "./observability/fail-open.js";
|
|
26
|
+
import { BASELINE_IO_DEADLINE_MS, IoDeadlineExceeded, withinIoDeadline } from "./instruction-source-notice.js";
|
|
24
27
|
import { errorText as errText } from "./observability/err-text.js";
|
|
25
28
|
import { LIVENESS_HEARTBEAT_MS } from "./config-invariants.js";
|
|
26
29
|
export async function backgroundAgentOutput(registry, handle, access, agentStore) {
|
|
@@ -198,16 +201,25 @@ export function createPromptCommitReader() {
|
|
|
198
201
|
return closed.commits[closed.commits.length - 1 - closed.frames];
|
|
199
202
|
};
|
|
200
203
|
}
|
|
204
|
+
export async function settleResumeAnchor(write, where) {
|
|
205
|
+
try {
|
|
206
|
+
await withinIoDeadline(write);
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
const why = err instanceof IoDeadlineExceeded ? `reason=timeout boundMs=${BASELINE_IO_DEADLINE_MS}` : `reason=error error=${err instanceof Error ? err.message : String(err)}`;
|
|
210
|
+
recordFailOpen("server.resume-anchor.capture-failed", `leg=${where.leg} kind=${where.kind} ${why}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
201
213
|
export class TurnAnchorCapture {
|
|
202
214
|
capture;
|
|
203
|
-
|
|
215
|
+
leg;
|
|
204
216
|
captureUser;
|
|
205
217
|
firstTextEventId;
|
|
206
218
|
turnHadTool = false;
|
|
207
219
|
promptCommit = createPromptCommitReader();
|
|
208
|
-
constructor(capture,
|
|
220
|
+
constructor(capture, leg, captureUser) {
|
|
209
221
|
this.capture = capture;
|
|
210
|
-
this.
|
|
222
|
+
this.leg = leg;
|
|
211
223
|
this.captureUser = captureUser;
|
|
212
224
|
}
|
|
213
225
|
onHumanInput(ev) {
|
|
@@ -216,9 +228,9 @@ export class TurnAnchorCapture {
|
|
|
216
228
|
async onMessageCommitted(role, entryId) {
|
|
217
229
|
const committed = { type: "message_committed", role, entryId };
|
|
218
230
|
const prompt = this.promptCommit(committed);
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
231
|
+
const captureUser = this.captureUser;
|
|
232
|
+
if (prompt !== undefined && captureUser)
|
|
233
|
+
await settleResumeAnchor(() => captureUser(prompt), { leg: this.leg, kind: "prompt" });
|
|
222
234
|
}
|
|
223
235
|
onText(eventId) {
|
|
224
236
|
if (this.firstTextEventId === undefined) {
|
|
@@ -231,9 +243,10 @@ export class TurnAnchorCapture {
|
|
|
231
243
|
}
|
|
232
244
|
async onTurnEnd() {
|
|
233
245
|
this.promptCommit({ type: "turn_end" });
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
246
|
+
const capture = this.capture;
|
|
247
|
+
const handle = this.firstTextEventId;
|
|
248
|
+
if (handle && !this.turnHadTool && capture)
|
|
249
|
+
await settleResumeAnchor(() => capture(handle), { leg: this.leg, kind: "turn" });
|
|
237
250
|
this.firstTextEventId = undefined;
|
|
238
251
|
this.turnHadTool = false;
|
|
239
252
|
}
|
|
@@ -259,7 +272,12 @@ export async function graftParkToolCallId(result, cs) {
|
|
|
259
272
|
const id = await parkToolCallId(result, cs);
|
|
260
273
|
return id === undefined ? result : { ...result, toolCallId: id };
|
|
261
274
|
}
|
|
262
|
-
export async function
|
|
275
|
+
export async function voidHeldParkCard(held, hostSessionId, cards, leg) {
|
|
276
|
+
if (held?.terminal.kind !== "paused")
|
|
277
|
+
return;
|
|
278
|
+
await voidPendingCard({ token: held.terminal.token, sessionId: hostSessionId }, cards, "server.park.held-card-void-failed", `leg=${leg}`);
|
|
279
|
+
}
|
|
280
|
+
export async function runInBackground(runner, spec, runStore, taskId, metrics, principal, verify, cascade, instrumentDegenerate, planCacheProbe, persistThinking = false, inflight, preemptable, steerable, modelUsage, elicitation, elicitOwner, captureTurnAnchor, fleetPublisher, captureUserMessageAnchor, question, workflowCompletionInbox, subagentSteer, completionDiagLog, sendUserFile, promptManifests, approval, checkpointCards, pendingEngineNotices, trustedInternals, userInputLedger, acceptance, workspaceRecorder) {
|
|
263
281
|
const startedAt = Date.now();
|
|
264
282
|
metrics?.addGauge("runs_active", 1);
|
|
265
283
|
fleetPublisher?.onStart();
|
|
@@ -274,7 +292,6 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
274
292
|
? mintCancelledResult({ taskId, sessionId: spec.sessionId ?? "", startedAtMs: startedAt, message: "cancelled by user", cause, engineResult })
|
|
275
293
|
: mintCancelledResult({ taskId, sessionId: spec.sessionId ?? "", startedAtMs: startedAt, message: "cancelled by user", cause });
|
|
276
294
|
const recordDone = (result, status) => {
|
|
277
|
-
metrics?.addGauge("runs_active", -1);
|
|
278
295
|
metrics?.inc("tasks_total", { status });
|
|
279
296
|
metrics?.observe("task_duration_seconds", (Date.now() - startedAt) / 1000);
|
|
280
297
|
if (result?.stats.tokens)
|
|
@@ -319,7 +336,7 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
319
336
|
}
|
|
320
337
|
}, HEARTBEAT_MS);
|
|
321
338
|
heartbeat.unref?.();
|
|
322
|
-
const anchor = new TurnAnchorCapture(captureTurnAnchor,
|
|
339
|
+
const anchor = new TurnAnchorCapture(captureTurnAnchor, "bg", captureUserMessageAnchor);
|
|
323
340
|
let reached;
|
|
324
341
|
let observedDone;
|
|
325
342
|
let causeAtDone;
|
|
@@ -333,15 +350,12 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
333
350
|
needs_review: (sealed) => runStore.setNeedsReview(taskId, sealed),
|
|
334
351
|
};
|
|
335
352
|
const parkLeg = async (word, res) => {
|
|
336
|
-
const grafted = await graftParkToolCallId(res,
|
|
353
|
+
const grafted = await graftParkToolCallId(res, checkpointCards);
|
|
337
354
|
await sink.appendParked(word, grafted);
|
|
338
|
-
await flushModelUsage();
|
|
339
355
|
const sealed = sealResultForExit(grafted);
|
|
340
356
|
reached = { kind: word, result: sealed };
|
|
341
357
|
await parkRowWrite[word](sealed);
|
|
342
358
|
acceptance?.settle(sealed);
|
|
343
|
-
metrics?.addGauge("runs_active", -1);
|
|
344
|
-
metrics?.inc("tasks_total", { status: word });
|
|
345
359
|
};
|
|
346
360
|
const settleLegResult = async (engineResult) => {
|
|
347
361
|
const result = atHostBoundary(engineResult, spec.sessionId);
|
|
@@ -359,10 +373,9 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
359
373
|
await runStore.setTerminal(taskId, plane.status, safe, plane.errorMessage ?? null);
|
|
360
374
|
await releaseKeyIfZeroWorkRefusal(runStore, taskId, safe);
|
|
361
375
|
acceptance?.settle(safe);
|
|
362
|
-
recordDone(safe, settledAsCancel ? CANCELLED_CODE : plane.status);
|
|
363
376
|
};
|
|
364
377
|
const instructionLeg = createInstructionSelectionLeg();
|
|
365
|
-
const sink = createLedgerSink({ appendEvent: (seq, type, data) => runStore.appendEvent(taskId, seq, type, data), persistThinking, notifiedKeys, onActivity: (kind, statusData) => recordTurnActivity(taskId, kind, statusData), legSections: () => ({ instructions: instructionLeg.segment(), skills: runSkillsOf(spec) }) });
|
|
378
|
+
const sink = createLedgerSink({ appendEvent: (seq, type, data) => runStore.appendEvent(taskId, seq, type, data), persistThinking, notifiedKeys, onActivity: (kind, statusData) => recordTurnActivity(taskId, kind, statusData), legSections: () => ({ instructions: instructionLeg.segment(), skills: runSkillsOf(spec) }), usage: { modelUsage, taskId } });
|
|
366
379
|
const append = (type, data) => sink.append(type, data);
|
|
367
380
|
const flush = () => sink.flush();
|
|
368
381
|
const flushModelUsage = () => appendModelUsageDelta(append, modelUsage, taskId);
|
|
@@ -454,6 +467,7 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
454
467
|
const result = await compositeLeg();
|
|
455
468
|
observedDone = result;
|
|
456
469
|
causeAtDone = cancelCtrl.cause();
|
|
470
|
+
await voidVerifierPauseCard(result, checkpointCards);
|
|
457
471
|
await flush();
|
|
458
472
|
await flushPromptManifest();
|
|
459
473
|
await settleLegResult(result);
|
|
@@ -547,7 +561,6 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
547
561
|
}
|
|
548
562
|
reached = { kind: "done", result: c };
|
|
549
563
|
await runStore.setTerminal(taskId, "failed", c, outwardPlane(c.terminal).errorMessage ?? null);
|
|
550
|
-
recordDone(c, CANCELLED_CODE);
|
|
551
564
|
}
|
|
552
565
|
}
|
|
553
566
|
catch (err) {
|
|
@@ -585,6 +598,7 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
585
598
|
else {
|
|
586
599
|
settledAsCancel = false;
|
|
587
600
|
const safeMsg = redactErrorMessage(message) ?? message;
|
|
601
|
+
await voidHeldParkCard(observedDone === undefined ? undefined : atHostBoundary(observedDone, spec.sessionId), spec.sessionId, checkpointCards, "bg");
|
|
588
602
|
try {
|
|
589
603
|
await append("failed", { errorMessage: safeMsg });
|
|
590
604
|
}
|
|
@@ -596,48 +610,48 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
596
610
|
}
|
|
597
611
|
catch {
|
|
598
612
|
}
|
|
599
|
-
if (reached?.kind === "done")
|
|
600
|
-
recordDone(reached.result, failureCodeOf(reached.result.terminal) === CANCELLED_CODE ? CANCELLED_CODE : outwardPlane(reached.result.terminal).status);
|
|
601
|
-
else if (reached !== undefined) {
|
|
602
|
-
metrics?.addGauge("runs_active", -1);
|
|
603
|
-
metrics?.inc("tasks_total", { status: reached.kind });
|
|
604
|
-
}
|
|
605
|
-
else if (settledAsCancel) {
|
|
606
|
-
recordDone(null, CANCELLED_CODE);
|
|
607
|
-
}
|
|
608
|
-
else {
|
|
609
|
-
recordDone(null, "failed");
|
|
610
|
-
}
|
|
611
613
|
}
|
|
612
614
|
finally {
|
|
613
615
|
legLive = false;
|
|
614
616
|
unregisterEngineNotice();
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
617
|
+
const verdict = reached?.kind === "done"
|
|
618
|
+
? { kind: "terminal", label: failureCodeOf(reached.result.terminal) === CANCELLED_CODE ? CANCELLED_CODE : outwardPlane(reached.result.terminal).status, result: reached.result }
|
|
619
|
+
: reached !== undefined
|
|
620
|
+
? { kind: "park", word: reached.kind }
|
|
621
|
+
: { kind: "terminal", label: settledAsCancel ? CANCELLED_CODE : "failed", result: null };
|
|
622
|
+
try {
|
|
623
|
+
metrics?.addGauge("runs_active", -1);
|
|
624
|
+
if (verdict.kind === "park")
|
|
625
|
+
metrics?.inc("tasks_total", { status: verdict.word });
|
|
622
626
|
else
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
+
recordDone(verdict.result, verdict.label);
|
|
628
|
+
}
|
|
629
|
+
finally {
|
|
630
|
+
if (fleetPublisher) {
|
|
631
|
+
if (verdict.kind === "park")
|
|
632
|
+
fleetPublisher.onTerminal(verdict.word);
|
|
633
|
+
else if (verdict.result !== null)
|
|
634
|
+
fleetPublisher.onTerminal(verdict.label, fleetRunResiduals(verdict.result));
|
|
635
|
+
else
|
|
636
|
+
fleetPublisher.onTerminal(verdict.label, {
|
|
637
|
+
...(verdict.label === CANCELLED_CODE ? { stoppedBy: "user" } : {}),
|
|
638
|
+
...(spec.sessionId ? { transcriptId: spec.sessionId } : {}),
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
if (steerableStreamRef !== undefined)
|
|
642
|
+
await userInputLedger?.settleLeg(steerableStreamRef);
|
|
643
|
+
if (inflight?.get(taskId) === cancelCtrl)
|
|
644
|
+
inflight.delete(taskId);
|
|
645
|
+
if (preemptable?.get(taskId) === preemptCtrl)
|
|
646
|
+
preemptable.delete(taskId);
|
|
647
|
+
if (steerableStreamRef !== undefined && steerable?.get(taskId) === steerableStreamRef)
|
|
648
|
+
steerable.delete(taskId);
|
|
649
|
+
for (const evict of subagentHandleEvictions)
|
|
650
|
+
evict();
|
|
651
|
+
modelUsage?.clear(taskId);
|
|
652
|
+
promptManifests?.clear(taskId, manifestLease);
|
|
653
|
+
clearInterval(heartbeat);
|
|
627
654
|
}
|
|
628
|
-
if (steerableStreamRef !== undefined)
|
|
629
|
-
await userInputLedger?.settleLeg(steerableStreamRef);
|
|
630
|
-
if (inflight?.get(taskId) === cancelCtrl)
|
|
631
|
-
inflight.delete(taskId);
|
|
632
|
-
if (preemptable?.get(taskId) === preemptCtrl)
|
|
633
|
-
preemptable.delete(taskId);
|
|
634
|
-
if (steerableStreamRef !== undefined && steerable?.get(taskId) === steerableStreamRef)
|
|
635
|
-
steerable.delete(taskId);
|
|
636
|
-
for (const evict of subagentHandleEvictions)
|
|
637
|
-
evict();
|
|
638
|
-
modelUsage?.clear(taskId);
|
|
639
|
-
promptManifests?.clear(taskId, manifestLease);
|
|
640
|
-
clearInterval(heartbeat);
|
|
641
655
|
}
|
|
642
656
|
}
|
|
643
657
|
export const HEARTBEAT_MS = LIVENESS_HEARTBEAT_MS;
|
|
@@ -52,7 +52,10 @@ export interface EgressPolicyInputs {
|
|
|
52
52
|
* 读数 → 缺口(纯函数、全函数:不抛;顺序:读不到的表 → 策略缺席 → 逐节点逐地址 → IPv6)。一张表读不到,只跳过要它的那一判;另一张照判。
|
|
53
53
|
*/
|
|
54
54
|
export declare function sandboxEgressGaps(inputs: EgressPolicyInputs): SandboxEgressGap[];
|
|
55
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* 读数的说法:每个缺口一行 warn `sandbox_egress_policy_gap` + 一次 `recordFailOpen`(P-DEBT);零缺口一行 info `sandbox_egress_policy_checked`。
|
|
57
|
+
* `unreadable` 的 `detail` 是控制面请求的失败句(客户端异常原文)⇒ 经出口座(`operator-log-text`)出门,与起服面其余运维行里的抛出物文本同一读法。
|
|
58
|
+
*/
|
|
56
59
|
export declare function sayEgressPolicyReading(gaps: readonly SandboxEgressGap[], logger: {
|
|
57
60
|
info(msg: string, fields?: Record<string, unknown>): void;
|
|
58
61
|
warn(msg: string, fields?: Record<string, unknown>): void;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BlockList, isIP } from "node:net";
|
|
2
2
|
import { recordFailOpen } from "./observability/fail-open.js";
|
|
3
|
+
import { seatText } from "./trace/exit-seat.js";
|
|
3
4
|
export const SANDBOX_IPV6_WORDS = ["enabled", "disabled"];
|
|
4
5
|
export const SANDBOX_IPV6_DEFAULT = "enabled";
|
|
5
6
|
export function sandboxPodSysctls(ipv6) {
|
|
@@ -229,7 +230,8 @@ export function sayEgressPolicyReading(gaps, logger, namespace) {
|
|
|
229
230
|
}
|
|
230
231
|
for (const gap of gaps) {
|
|
231
232
|
recordFailOpen("server.sandbox-egress.policy-gap", `kind=${gap.kind}${gap.kind === "unreadable" ? ` what=${gap.what}` : ""}`);
|
|
232
|
-
|
|
233
|
+
const shown = gap.kind === "unreadable" ? { ...gap, detail: seatText("operator-log-text", gap.detail) } : gap;
|
|
234
|
+
logger?.warn("sandbox_egress_policy_gap", { namespace, ...shown, effect: effectOf(gap) });
|
|
233
235
|
}
|
|
234
236
|
}
|
|
235
237
|
//# sourceMappingURL=sandbox-egress-policy.js.map
|
|
@@ -38,26 +38,36 @@ export interface SandboxGitPlanePremises {
|
|
|
38
38
|
/** The patch judge's refusal for a pod that carries the broker (`podSpecPatchBrokerRefusal`); `undefined` = the patch may land. */
|
|
39
39
|
readonly patchRefusal: string | undefined;
|
|
40
40
|
readonly brokerImage: string | undefined;
|
|
41
|
-
/** The routed origins (`
|
|
41
|
+
/** The routed origins — the live config's `sandboxGit` block as committed (`config.sandboxGit`); `null` = no block. */
|
|
42
42
|
readonly origins: readonly string[] | null;
|
|
43
43
|
}
|
|
44
|
+
/** The boot's readings the judge needs besides config: the secret seat answer (asked once, by stage 5) and the static patch judge's refusal. */
|
|
45
|
+
export interface SandboxGitPlaneBootReadings {
|
|
46
|
+
readonly secretSeat?: SandboxSecretSeat;
|
|
47
|
+
readonly patchRefusal?: string;
|
|
48
|
+
}
|
|
44
49
|
/** THE judge: the first premise that fails, in the written order; all hold ⇒ on with per-origin rows. Pure. */
|
|
45
50
|
export declare function judgeSandboxGitPlane(p: SandboxGitPlanePremises): SandboxGitPlane;
|
|
46
51
|
/** The secret seat is asked for the plane only when every premise before it holds (a deployment the plane is off for asks nothing for it). */
|
|
47
52
|
export declare function sandboxGitPlaneAsksSecretSeat(p: Pick<SandboxGitPlanePremises, "multiTenant" | "k8sLane" | "callerCredential" | "centerUrl">): boolean;
|
|
48
|
-
/** The premises read from config, plus the two boot readings (seat answer, patch refusal) when the boot has them. */
|
|
49
|
-
export declare function sandboxGitPlanePremisesOf(config: ServiceConfig, readings:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
/** The premises read from the live config, plus the two boot readings (seat answer, patch refusal) when the boot has them. */
|
|
54
|
+
export declare function sandboxGitPlanePremisesOf(config: ServiceConfig, readings: SandboxGitPlaneBootReadings): SandboxGitPlanePremises;
|
|
55
|
+
/** The plane's read-time seat (see the file head): {@link SandboxGitPlaneSeat.now} judges on every call; {@link SandboxGitPlaneSeat.settle} asks the boot's IO premise. */
|
|
56
|
+
export interface SandboxGitPlaneSeat {
|
|
57
|
+
/** The reading now — the judge over the boot readings settled so far and the live config. Synchronous; every reader calls it per read and keeps no copy. */
|
|
58
|
+
now(): SandboxGitPlane;
|
|
59
|
+
/** Asks the secret seat once (stage 5 awaits it), only when the four premises before it hold; a later call asks nothing. */
|
|
60
|
+
settle(): Promise<void>;
|
|
61
|
+
}
|
|
53
62
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
63
|
+
* The plane's ONE seat. `premisesOf` = the premises over the live config (the execution env hands `(r) => sandboxGitPlanePremisesOf(config, r)` — the
|
|
64
|
+
* config object every commit of the effective configuration mutates); `boot.patchRefusal` = the static patch judge's answer (a boot reading from the start);
|
|
65
|
+
* `boot.askSecretSeat` = the lane's secret-seat review (only the k8s lane has one; absent ⇒ never asked ⇒ the seat stays unverified).
|
|
57
66
|
*/
|
|
58
|
-
export declare function
|
|
59
|
-
readonly
|
|
60
|
-
|
|
67
|
+
export declare function createSandboxGitPlaneSeat(premisesOf: (readings: SandboxGitPlaneBootReadings) => SandboxGitPlanePremises, boot: {
|
|
68
|
+
readonly patchRefusal?: string | undefined;
|
|
69
|
+
readonly askSecretSeat?: (() => Promise<SandboxSecretSeat>) | undefined;
|
|
70
|
+
}): SandboxGitPlaneSeat;
|
|
61
71
|
/**
|
|
62
72
|
* Wiring point — does this worker hold the credential the console's vault admits on its resolve endpoint (the worker-assertion token)?
|
|
63
73
|
* The server has no reader for it yet ⇒ `false` (the plane stays off, `no_caller_credential`). Replaced by the plane's vault client.
|
|
@@ -76,6 +86,15 @@ export interface SandboxGitRunRows {
|
|
|
76
86
|
* `sandbox_broker_identity_unread` —— every miss reads as "not sso" ⇒ no broker (fail-closed), none of them throws into the pod's connect.
|
|
77
87
|
*/
|
|
78
88
|
export declare function runIdentitySourceOf(runId: string | undefined, runs: SandboxGitRunRows | undefined, logger?: Pick<Logger, "warn">): Promise<IdentitySource | undefined>;
|
|
89
|
+
/**
|
|
90
|
+
* The k8s run binding's broker-seat reader (the adapter asks it once per pod, `K8sRunEnvSeats.brokerSeatOf`): reads the plane ONCE per pod, before the
|
|
91
|
+
* run-row read — off ⇒ none and no row read at all; on ⇒ {@link sandboxBrokerSeatOf} over that one reading and the row's recorded identity source.
|
|
92
|
+
* `runs` is the late-bound run store (absent ⇒ no row ⇒ not `sso` ⇒ none).
|
|
93
|
+
*/
|
|
94
|
+
export declare function createSandboxBrokerSeatOf(planeNow: () => SandboxGitPlane, brokerImage: string | undefined, runs: (() => SandboxGitRunRows | undefined) | undefined, logger?: Pick<Logger, "warn">): (runId: string | undefined) => Promise<{
|
|
95
|
+
readonly image: string;
|
|
96
|
+
readonly origins: readonly string[];
|
|
97
|
+
} | undefined>;
|
|
79
98
|
/** The broker seat for one run's pod: the plane on ∧ the image set ∧ the run's recorded identity source `sso` ⇒ the image + every origin of the reading (http too); otherwise none. */
|
|
80
99
|
export declare function sandboxBrokerSeatOf(plane: SandboxGitPlane, brokerImage: string | undefined, identitySource: IdentitySource | undefined): {
|
|
81
100
|
readonly image: string;
|
|
@@ -21,7 +21,7 @@ export const SANDBOX_GIT_PLANE_OFF_TEXT = {
|
|
|
21
21
|
secret_seat_denied: `the sandbox Role does not allow secrets ${SANDBOX_SECRET_SEAT_VERBS.lease.join(" / ")} (the lease Secret) in the sandbox namespace`,
|
|
22
22
|
pod_patch_reaches_broker: "the deployment's pod-spec patch could reach the broker container (a podSecurityContext, or a field outside the broker white-list)",
|
|
23
23
|
broker_image_unset: "K8S_SANDBOX_BROKER_IMAGE is not set (the broker container's image; this engine's own image is the recommended value)",
|
|
24
|
-
no_origins:
|
|
24
|
+
no_origins: `the effective configuration routes no git origins to the plane (sandboxGit.origins): the console projects the block only on this worker's own pull (${WEB_ADMIN_ENV.worker}), and a block that fails its contract is read as no origins (log line web_admin_sandbox_git_refused)`,
|
|
25
25
|
};
|
|
26
26
|
const isHttps = (url) => url !== undefined && URL.canParse(url) && new URL(url).protocol === "https:";
|
|
27
27
|
export function judgeSandboxGitPlane(p) {
|
|
@@ -73,11 +73,23 @@ export function sandboxGitPlanePremisesOf(config, readings) {
|
|
|
73
73
|
secretSeat: readings.secretSeat,
|
|
74
74
|
patchRefusal: readings.patchRefusal,
|
|
75
75
|
brokerImage: lane?.provider === "k8s" ? lane.brokerImage : undefined,
|
|
76
|
-
origins:
|
|
76
|
+
origins: config.sandboxGit?.origins.map((e) => e.origin) ?? null,
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
|
-
export function
|
|
80
|
-
|
|
79
|
+
export function createSandboxGitPlaneSeat(premisesOf, boot) {
|
|
80
|
+
let readings = boot.patchRefusal !== undefined ? { patchRefusal: boot.patchRefusal } : {};
|
|
81
|
+
let settled = false;
|
|
82
|
+
return {
|
|
83
|
+
now: () => judgeSandboxGitPlane(premisesOf(readings)),
|
|
84
|
+
settle: async () => {
|
|
85
|
+
if (settled)
|
|
86
|
+
return;
|
|
87
|
+
settled = true;
|
|
88
|
+
if (boot.askSecretSeat === undefined || !sandboxGitPlaneAsksSecretSeat(premisesOf(readings)))
|
|
89
|
+
return;
|
|
90
|
+
readings = { ...readings, secretSeat: await boot.askSecretSeat() };
|
|
91
|
+
},
|
|
92
|
+
};
|
|
81
93
|
}
|
|
82
94
|
export function readSandboxGitCallerCredential(_config) {
|
|
83
95
|
return false;
|
|
@@ -97,6 +109,14 @@ export async function runIdentitySourceOf(runId, runs, logger) {
|
|
|
97
109
|
return undefined;
|
|
98
110
|
}
|
|
99
111
|
}
|
|
112
|
+
export function createSandboxBrokerSeatOf(planeNow, brokerImage, runs, logger) {
|
|
113
|
+
return async (runId) => {
|
|
114
|
+
const plane = planeNow();
|
|
115
|
+
if (plane.state !== "on")
|
|
116
|
+
return undefined;
|
|
117
|
+
return sandboxBrokerSeatOf(plane, brokerImage, await runIdentitySourceOf(runId, runs?.(), logger));
|
|
118
|
+
};
|
|
119
|
+
}
|
|
100
120
|
export function sandboxBrokerSeatOf(plane, brokerImage, identitySource) {
|
|
101
121
|
if (plane.state !== "on" || brokerImage === undefined || brokerImage === "" || identitySource !== "sso")
|
|
102
122
|
return undefined;
|
package/dist/security.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { TaskRequestBody } from "./http/wire-types.js";
|
|
|
6
6
|
import type { StagingHandle } from "./session-sync-kernel.js";
|
|
7
7
|
import type { ClientSessionRowWrite, ReplaySessionRowWrite, ReplaySessionRowWriteOutcome, SessionRowPatch, SessionRowWriteOutcome } from "./session-row.js";
|
|
8
8
|
import type { ExecutionPlacementSeat } from "./execution-placement.js";
|
|
9
|
+
import type { SessionUnreadable } from "./session-error-wire.js";
|
|
9
10
|
import type { ForkTarget, ForkToOutcome } from "./plugins/session-fork.js";
|
|
10
11
|
import { type OwnerlessClaim } from "./delegated-session-owner.js";
|
|
11
12
|
/** One row of the session-list projection (CC /resume picker) — the durable session abstraction's enumeration
|
|
@@ -38,6 +39,12 @@ export interface SessionListItem {
|
|
|
38
39
|
* primitive ∧ the row has an occupant token); additive key, passed through unprojected (`sessions-list.ts`). Same name and meaning as
|
|
39
40
|
* `SessionSummary.rowTag` in `plugins/store-contracts.ts`. */
|
|
40
41
|
rowTag?: string;
|
|
42
|
+
/** The session's archive cannot be read — present-iff the session head's leaf read throws (a list row is a session ROW: its facts live on the
|
|
43
|
+
* row and read fine; this says the CONTENT does not). `errorCode` = the code the session's own reads answer for it (`GET /v1/sessions/:id` /
|
|
44
|
+
* `…/head` / `…/events` / `PATCH` once admitted) — one table, `openFaceFaultWire` in `session-error-wire.ts`, the only minter `sessionUnreadableOf`.
|
|
45
|
+
* A store whose head leaf is a row column (the SQL twins) never carries it. Additive key, passed through unprojected (`sessions-list.ts`).
|
|
46
|
+
* Same name and meaning as `SessionSummary.unreadable` in `plugins/store-contracts.ts`. */
|
|
47
|
+
unreadable?: SessionUnreadable;
|
|
41
48
|
}
|
|
42
49
|
/**
|
|
43
50
|
* 会话店的行格写原语(规则与判序:`session-row.ts` 头注「写原语」)—— 按入口分两只重载:客户端写(PATCH)的结局闭集四员;行重放(2c 导入落定后的那一笔)
|
|
@@ -176,10 +183,10 @@ export declare function legacyUnownedAmnestyOpen(deployment: DeploymentShapeInpu
|
|
|
176
183
|
export type OwnerAwareSessionStore = SessionStore & {
|
|
177
184
|
/** 属主登记(core `SessionStore.register` 的契约:对没有行的 id 建行并记下属主,首写赢;对已有的行什么都不做)。读回走 `headOf`。 */
|
|
178
185
|
register?: (sessionId: string, owner: string | null) => Promise<void>;
|
|
179
|
-
/** [ref] 委派继承律的**认领口** —— 只在记录委派树的店上(
|
|
186
|
+
/** [ref] 委派继承律的**认领口** —— 只在记录委派树的店上(三只持久会话店,只命中 placed 行;不记委派树的店没有):判断时读到的那一位住客仍是无主的 placed 行 ⇒ 写 `owner`,
|
|
180
187
|
* 返回是否写成(只 CAS 子行自己)。唯一调用方 = 停驻挂点的 `settleDelegatedOwner`(`delegated-session-owner.ts`;M23 走同一句 SQL);规则写在那个模块。 */
|
|
181
188
|
claimOwnerless?: OwnerlessClaim;
|
|
182
|
-
/** [ref] placed 分区的元组读口(店的既有读口,一行 PK 读;`undefined` = 普通会话或无此行)。店不交它 = 不实现 placement = 没有 placed 行(
|
|
189
|
+
/** [ref] placed 分区的元组读口(店的既有读口,一行 PK 读;`undefined` = 普通会话或无此行)。店不交它 = 不实现 placement = 没有 placed 行(无 repo 的内存店)。两个读者:
|
|
183
190
|
* ① 会话面的属主门只在属主为 NULL 时读它一次(无主的 placed 行不是公共行,`http/principal-gate.ts` 的 `sessionOwnerCellOf`);
|
|
184
191
|
* ② 会话视图读它投影体顶层 `agent` 键(`audit.ts` 的 `sessionAgentOf`,只在视图读上付):店没有这一面 ⇒ 键缺席,读面不凭别处另铸子代身份。 */
|
|
185
192
|
placementOf?: (sessionId: string) => Promise<SessionPlacementRecord | undefined>;
|
|
@@ -456,6 +463,8 @@ export declare function setSsoScope(req: IncomingMessage, scope: string): void;
|
|
|
456
463
|
export declare function ssoVerifiedScope(req: IncomingMessage): string | undefined;
|
|
457
464
|
export declare function setSsoRole(req: IncomingMessage, role: string): void;
|
|
458
465
|
export declare function ssoVerifiedRole(req: IncomingMessage): string | undefined;
|
|
466
|
+
export declare function setSsoPrincipalInc(req: IncomingMessage, principalInc: string): void;
|
|
467
|
+
export declare function ssoVerifiedPrincipalInc(req: IncomingMessage): string | undefined;
|
|
459
468
|
export declare function verifiedPrincipal(req: IncomingMessage, config: ServiceConfig): string | undefined;
|
|
460
469
|
export {};
|
|
461
470
|
//# sourceMappingURL=security.d.ts.map
|
package/dist/security.js
CHANGED
|
@@ -210,6 +210,14 @@ export function ssoVerifiedRole(req) {
|
|
|
210
210
|
const v = SSO_ROLES.get(req);
|
|
211
211
|
return v !== undefined && v.length > 0 ? v : undefined;
|
|
212
212
|
}
|
|
213
|
+
const SSO_PRINCIPAL_INCS = new WeakMap();
|
|
214
|
+
export function setSsoPrincipalInc(req, principalInc) {
|
|
215
|
+
SSO_PRINCIPAL_INCS.set(req, principalInc);
|
|
216
|
+
}
|
|
217
|
+
export function ssoVerifiedPrincipalInc(req) {
|
|
218
|
+
const v = SSO_PRINCIPAL_INCS.get(req);
|
|
219
|
+
return v !== undefined && v.length > 0 ? v : undefined;
|
|
220
|
+
}
|
|
213
221
|
export function verifiedPrincipal(req, config) {
|
|
214
222
|
const sso = ssoVerifiedPrincipal(req);
|
|
215
223
|
if (sso) {
|
|
@@ -73,7 +73,8 @@ export declare function serverCredentialValueSources(modelApiKeyEnv?: ModelApiKe
|
|
|
73
73
|
* 所以这一次抛只可能是名的问题。
|
|
74
74
|
* · **值臂**:{@link serverCredentialValueSources} 的每一个变量此刻在 env 里的值,逐个交给引擎**同一只**判(不另写「什么算凭据值」的第二份判据):引擎收下 ⇒ 记进值臂;
|
|
75
75
|
* 引擎拒(不是凭据值:空白 / 占位词 / 一个字符重复 / 不足 8 字符;或它是每个子进程都会拿到的变量的值)⇒ 这一个值不扣、名照扣、**不拒启**(与引擎自己的收值口
|
|
76
|
-
* `holdOwnCredentialValues` 同一姿势:不收 + 说一次)
|
|
76
|
+
* `holdOwnCredentialValues` 同一姿势:不收 + 说一次),经留痕座结构化点名那个变量一次 —— `warn` 行 `own_credential_value_not_withheld { name, reason }`
|
|
77
|
+
* ({@link recordOwnCredentialValueNotWithheld};`reason` 是引擎拒句原文,从不回显值;起服第一步还没有 logger 时当拍经进程默认的 JSON 行日志器写 stderr,不缓冲),能力位 `inherit_env.own_credential_values_withheld`
|
|
77
78
|
* 因此答 false(位真 ⇔ 值臂真扣)。引擎拒一个值时声明保持上一份,所以逐个交表的中间态都是上一份的超集。
|
|
78
79
|
* 返回声明的名单(只名、不值)。
|
|
79
80
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { declareWithheldEnv, hostChildEnv, inheritedHostEnv } from "@sema-agent/core";
|
|
2
2
|
import { CONFIG_CATALOG } from "./config-catalog.js";
|
|
3
3
|
import { ENV_NAME_ALLOWLIST_KNOB_NAMES } from "./env-name-allowlist-knobs.js";
|
|
4
|
-
import { recordSecretEnvScrub } from "./observability/secret-env-scrub.js";
|
|
4
|
+
import { recordOwnCredentialValueNotWithheld, recordSecretEnvScrub } from "./observability/secret-env-scrub.js";
|
|
5
5
|
export const CATALOG_SECRET_ENV_NAMES = new Set(CONFIG_CATALOG.filter((spec) => spec.type === "secret").map((spec) => spec.name));
|
|
6
6
|
const NO_MODEL_ENTRIES = Object.freeze({});
|
|
7
7
|
export function serverWithheldEnvNames(modelApiKeyEnv = NO_MODEL_ENTRIES) {
|
|
@@ -31,9 +31,7 @@ export function declareServerWithheldEnv(modelApiKeyEnv = NO_MODEL_ENTRIES) {
|
|
|
31
31
|
catch (e) {
|
|
32
32
|
if (!valueRefusalAnnounced.has(source)) {
|
|
33
33
|
valueRefusalAnnounced.add(source);
|
|
34
|
-
|
|
35
|
-
"the variable name is still withheld under every inheritEnv policy, but a variable holding the same string under another name is not, and GET /v1/capabilities answers inherit_env.own_credential_values_withheld: false. " +
|
|
36
|
-
"Give it a real credential value (at least 8 characters, not a placeholder) to withhold copies of it too.");
|
|
34
|
+
recordOwnCredentialValueNotWithheld({ name: source, reason: e instanceof Error ? e.message : String(e) });
|
|
37
35
|
}
|
|
38
36
|
}
|
|
39
37
|
}
|