@sema-agent/server 7.122.0 → 7.124.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 +209 -0
- package/README.md +7 -2
- package/README.zh-CN.md +5 -2
- package/USAGE.md +76 -56
- package/dist/approval-ask-audit-store.d.ts +27 -32
- package/dist/approval-ask-audit-store.js +10 -9
- package/dist/approval-crash-convergence.d.ts +2 -2
- package/dist/approval-crash-convergence.js +5 -5
- package/dist/approval-deny-reasons.d.ts +163 -51
- package/dist/approval-deny-reasons.js +79 -8
- package/dist/approval-policy-settlement.d.ts +4 -1
- package/dist/approval-policy-settlement.js +3 -2
- package/dist/approval-reconciler.d.ts +3 -3
- package/dist/approval-reconciler.js +10 -10
- package/dist/approval.d.ts +1 -1
- package/dist/approval.js +1 -1
- package/dist/audit.d.ts +1 -1
- package/dist/audit.js +53 -23
- package/dist/auth-bridge.d.ts +8 -8
- package/dist/auth-bridge.js +6 -6
- package/dist/auth-keys.d.ts +2 -2
- package/dist/auto-mode-face.d.ts +13 -9
- package/dist/auto-mode-face.js +8 -7
- package/dist/boot/budget-tracing.js +1 -1
- package/dist/boot/execution-env.js +1 -0
- package/dist/boot/leader.d.ts +1 -1
- package/dist/boot/memory-consolidation.d.ts +4 -4
- package/dist/boot/org-memory.d.ts +3 -3
- package/dist/boot/org-memory.js +5 -5
- package/dist/boot/resolve-spec.js +7 -7
- package/dist/boot/runner-deps.d.ts +1 -1
- package/dist/boot/runtime-caps.d.ts +1 -1
- package/dist/boot/runtime-caps.js +10 -10
- package/dist/boot/shutdown.d.ts +2 -2
- package/dist/boot/shutdown.js +2 -2
- package/dist/boot/side-query-lane.d.ts +3 -3
- package/dist/boot/{stage-02-registry-pull.d.ts → stage-02-web-admin-pull.d.ts} +2 -2
- package/dist/boot/{stage-02-registry-pull.js → stage-02-web-admin-pull.js} +4 -4
- package/dist/boot/stage-03-store-backend.d.ts +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.d.ts +1 -1
- package/dist/boot/stage-06-runners.d.ts +2 -2
- package/dist/boot/stage-06-runners.js +6 -6
- package/dist/boot/stage-07-capability-layer.d.ts +2 -2
- package/dist/boot/stage-07-capability-layer.js +6 -5
- package/dist/boot/stage-08-reapers.d.ts +3 -3
- package/dist/boot/stage-08-reapers.js +3 -3
- package/dist/boot/stage-09-leader.d.ts +3 -3
- package/dist/boot/stage-09-leader.js +7 -7
- package/dist/boot/stage-10-http-server.d.ts +3 -3
- package/dist/boot/stage-10-http-server.js +19 -19
- package/dist/boot/unpriced-ceiling-verdict.d.ts +1 -1
- package/dist/boot/{config-center.d.ts → web-admin.d.ts} +11 -11
- package/dist/boot/{config-center.js → web-admin.js} +39 -20
- package/dist/boot/webfetch-summarize-lane.d.ts +2 -2
- package/dist/brain.d.ts +1 -1
- package/dist/brain.js +1 -1
- package/dist/budget.d.ts +3 -3
- package/dist/canonical-json.d.ts +2 -2
- package/dist/capabilities/center-plugins.d.ts +1 -1
- package/dist/capabilities/center-wiring.d.ts +12 -5
- package/dist/capabilities/center-wiring.js +11 -2
- package/dist/capabilities/composite-members.d.ts +1 -1
- package/dist/capabilities/composite-members.js +1 -1
- package/dist/capabilities/scenarios.js +2 -2
- package/dist/capabilities/team.d.ts +1 -1
- package/dist/capabilities/tool-defer.d.ts +1 -1
- package/dist/center-credential-renewer.d.ts +1 -1
- package/dist/center-credential-renewer.js +7 -7
- package/dist/center-credential.d.ts +9 -9
- package/dist/center-credential.js +6 -6
- package/dist/config-catalog.d.ts +7 -10
- package/dist/config-catalog.js +16 -16
- package/dist/config-d-migration.d.ts +32 -0
- package/dist/config-d-migration.js +59 -0
- package/dist/config-invariants.d.ts +14 -4
- package/dist/config-invariants.js +31 -2
- package/dist/config-lkg.d.ts +34 -11
- package/dist/config-lkg.js +76 -48
- package/dist/config-provider.d.ts +26 -21
- package/dist/config-provider.js +25 -27
- package/dist/config-types.d.ts +59 -50
- package/dist/config.d.ts +17 -54
- package/dist/config.js +99 -181
- package/dist/execution-lane-caps.d.ts +1 -1
- package/dist/fleet/drain-entry.d.ts +1 -1
- package/dist/fleet/engine-signal.d.ts +61 -30
- package/dist/fleet/engine-signal.js +29 -5
- package/dist/fleet/fleet-bus.d.ts +12 -3
- package/dist/fleet/fleet-bus.js +13 -9
- package/dist/fleet/serving-lease.d.ts +3 -3
- package/dist/fleet/serving-lease.js +1 -1
- package/dist/fleet-client.d.ts +15 -13
- package/dist/fleet-client.js +9 -7
- package/dist/fleet-lease.d.ts +3 -3
- package/dist/fleet-lease.js +2 -2
- package/dist/host-lsp-manager.d.ts +1 -1
- package/dist/hosted-posture.d.ts +4 -4
- package/dist/http/admission.js +4 -4
- package/dist/http/checkpoint-ctx.d.ts +20 -3
- package/dist/http/checkpoint-ctx.js +13 -5
- package/dist/http/dispatch.js +7 -16
- package/dist/http/durable-run-leg.js +2 -1
- package/dist/http/health-self-report.d.ts +7 -4
- package/dist/http/health-self-report.js +3 -3
- package/dist/http/idempotency.d.ts +1 -1
- package/dist/http/resume-legs.d.ts +4 -3
- package/dist/http/resume-legs.js +31 -18
- package/dist/http/route-ctx.d.ts +8 -0
- package/dist/http/routes/admin-config-refresh.d.ts +1 -1
- package/dist/http/routes/admin-config-refresh.js +1 -1
- package/dist/http/routes/admin-drain.d.ts +1 -1
- package/dist/http/routes/admin-drain.js +5 -4
- package/dist/http/routes/approvals-assistant.js +4 -4
- package/dist/http/routes/capabilities.js +6 -5
- package/dist/http/routes/config-catalog.js +2 -3
- package/dist/http/routes/diagnostics.js +1 -1
- package/dist/http/routes/runs.js +8 -4
- package/dist/http/routes/sessions-list.js +2 -1
- package/dist/http/routes/sessions.js +2 -5
- package/dist/http/routes/side-query.js +3 -3
- package/dist/http/routes/tasks.js +3 -2
- package/dist/http/run-meta.d.ts +1 -1
- package/dist/http/run-meta.js +2 -2
- package/dist/http/server.d.ts +7 -7
- package/dist/http/server.js +1 -1
- package/dist/http/stored-body-replay.d.ts +4 -3
- package/dist/http/stored-body-replay.js +5 -5
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/key-resolver.d.ts +1 -1
- package/dist/leader/leader.d.ts +7 -6
- package/dist/leader/leader.js +3 -1
- package/dist/leader/run-entry.d.ts +2 -2
- package/dist/leader/run-entry.js +3 -3
- package/dist/leader/wire.d.ts +4 -4
- package/dist/leader/wire.js +2 -1
- package/dist/main.js +1 -1
- package/dist/mcp-tool-faces.d.ts +2 -2
- package/dist/model-entry-refusal.d.ts +20 -11
- package/dist/model-entry-refusal.js +22 -17
- package/dist/model-provider.d.ts +2 -2
- package/dist/model-route-endpoint.d.ts +22 -2
- package/dist/model-route-endpoint.js +9 -3
- package/dist/model-route-gap.d.ts +103 -0
- package/dist/model-route-gap.js +80 -0
- package/dist/model-route-url.d.ts +1 -1
- package/dist/model-route-url.js +2 -1
- package/dist/model-select.d.ts +24 -21
- package/dist/model-select.js +22 -17
- package/dist/namespaced-rule-name.d.ts +16 -30
- package/dist/namespaced-rule-name.js +2 -20
- package/dist/observability/fail-open.d.ts +0 -4
- package/dist/observability/fail-open.js +0 -4
- package/dist/observability/metrics.d.ts +1 -1
- package/dist/org-memory-admission.d.ts +1 -1
- package/dist/plugins/approval-ask-store-file.d.ts +4 -2
- package/dist/plugins/approval-ask-store-file.js +3 -3
- package/dist/plugins/approval-ask-store-memory.d.ts +4 -3
- package/dist/plugins/approval-ask-store-memory.js +10 -4
- package/dist/plugins/approval-ask-store-sql.d.ts +16 -2
- package/dist/plugins/approval-ask-store-sql.js +20 -13
- package/dist/plugins/caching-session-store.d.ts +0 -10
- package/dist/plugins/caching-session-store.js +0 -3
- package/dist/plugins/file-run-store.js +9 -3
- package/dist/plugins/leader-run-store-sql.d.ts +3 -2
- package/dist/plugins/leader-run-store-sql.js +3 -2
- package/dist/plugins/local-session-store.d.ts +20 -27
- package/dist/plugins/local-session-store.js +19 -17
- package/dist/plugins/memory-run-store.js +9 -3
- package/dist/plugins/one-time-migrations.js +51 -0
- package/dist/plugins/scheduler-support.d.ts +26 -7
- package/dist/plugins/scheduler-support.js +96 -53
- package/dist/plugins/session-policy-store-sql.js +1 -2
- package/dist/plugins/store-backend.js +1 -1
- package/dist/plugins/store-contracts.d.ts +20 -4
- package/dist/plugins/web-search.d.ts +1 -1
- package/dist/plugins/web-search.js +2 -1
- package/dist/plugins/workflow-run-store-sql.d.ts +4 -2
- package/dist/posture-source.d.ts +1 -1
- package/dist/read-face-posture.d.ts +3 -3
- package/dist/read-face-posture.js +1 -1
- package/dist/rule-entry-list.d.ts +3 -13
- package/dist/rule-entry-list.js +1 -12
- package/dist/run-local.js +10 -7
- package/dist/runtime-caps-resolver.d.ts +4 -4
- package/dist/runtime-caps-resolver.js +2 -2
- package/dist/runtime-governance.d.ts +36 -13
- package/dist/runtime-governance.js +7 -2
- package/dist/sealed-key.d.ts +4 -4
- package/dist/sealed-key.js +3 -2
- package/dist/security.d.ts +3 -3
- package/dist/service-version.d.ts +1 -1
- package/dist/service-version.js +5 -0
- package/dist/session-policy-wire.d.ts +47 -49
- package/dist/session-policy-wire.js +41 -36
- package/dist/session-sync.d.ts +5 -1
- package/dist/session-sync.js +2 -1
- package/dist/session-titler.d.ts +0 -11
- package/dist/session-titler.js +3 -5
- package/dist/shared-memory-scope-authorizer.d.ts +4 -4
- package/dist/spec-fields.d.ts +4 -4
- package/dist/spec-fields.js +1 -4
- package/dist/task-a2a.d.ts +1 -1
- package/dist/task-settings.d.ts +4 -5
- package/dist/task-settings.js +5 -8
- package/dist/tool-approval.d.ts +43 -4
- package/dist/tool-approval.js +147 -98
- package/dist/trace/core-keyset-guard.d.ts +1 -1
- package/dist/trace/project.d.ts +3 -3
- package/dist/trace/redact.d.ts +2 -23
- package/dist/trace/redact.js +1 -6
- package/dist/trace/self-minted-wire.d.ts +147 -3
- package/dist/trace/self-minted-wire.js +50 -9
- package/dist/unattended-permission-mode.d.ts +3 -3
- package/dist/unattended-permission-mode.js +2 -2
- package/dist/url-refusal.d.ts +35 -0
- package/dist/url-refusal.js +15 -0
- package/dist/user-authored-text.d.ts +31 -0
- package/dist/user-authored-text.js +18 -0
- package/dist/{config-center → web-admin-client}/apply-effective.d.ts +13 -70
- package/dist/{config-center → web-admin-client}/apply-effective.js +104 -121
- package/dist/{config-center → web-admin-client}/apply-ledger.d.ts +2 -2
- package/dist/{config-center → web-admin-client}/center-request.d.ts +7 -7
- package/dist/{config-center → web-admin-client}/center-request.js +5 -4
- package/dist/{config-center → web-admin-client}/effective-keys.d.ts +1 -3
- package/dist/{config-center → web-admin-client}/effective-keys.js +0 -9
- package/dist/{config-center → web-admin-client}/facade.d.ts +6 -6
- package/dist/{config-center → web-admin-client}/facade.js +2 -2
- package/dist/{config-center → web-admin-client}/http-client.d.ts +6 -10
- package/dist/{config-center → web-admin-client}/http-client.js +15 -15
- package/dist/{config-center → web-admin-client}/pull-state.d.ts +1 -1
- package/dist/{config-center → web-admin-client}/read-face.js +4 -4
- package/dist/web-admin-client/read-warnings.d.ts +137 -0
- package/dist/web-admin-client/read-warnings.js +168 -0
- package/dist/{config-center → web-admin-client}/restart-signal.d.ts +5 -3
- package/dist/{config-center → web-admin-client}/restart-signal.js +3 -4
- package/dist/{config-center → web-admin-client}/skills-mcp.d.ts +1 -1
- package/dist/{config-center → web-admin-client}/skills-mcp.js +13 -13
- package/dist/{config-center → web-admin-client}/stage-limits.d.ts +1 -7
- package/dist/{config-center → web-admin-client}/stage-limits.js +6 -7
- package/dist/{config-center → web-admin-client}/types.d.ts +19 -47
- package/package.json +3 -3
- package/skills/find-skills.md +2 -2
- package/dist/config-center/read-warnings.d.ts +0 -109
- package/dist/config-center/read-warnings.js +0 -110
- package/dist/url-shape.d.ts +0 -31
- package/dist/url-shape.js +0 -41
- /package/dist/{config-center → web-admin-client}/apply-ledger.js +0 -0
- /package/dist/{config-center → web-admin-client}/hot-keys-registry.d.ts +0 -0
- /package/dist/{config-center → web-admin-client}/hot-keys-registry.js +0 -0
- /package/dist/{config-center → web-admin-client}/mcp-revocation.d.ts +0 -0
- /package/dist/{config-center → web-admin-client}/mcp-revocation.js +0 -0
- /package/dist/{config-center → web-admin-client}/pull-state.js +0 -0
- /package/dist/{config-center → web-admin-client}/read-face.d.ts +0 -0
- /package/dist/{config-center → web-admin-client}/types.js +0 -0
|
@@ -5,31 +5,35 @@
|
|
|
5
5
|
*
|
|
6
6
|
* 1. **一只铸点,三个出口**:{@link mintEngineSignal} 是「引擎此刻自己说自己什么」的唯一来源。`GET /health`(诊断面)、
|
|
7
7
|
* `GET /readyz`(就绪探针)与 fleet 心跳(`fleet-client.ts`)各读它**一次**,再按各自的出口形投影;没有出口另算一遍
|
|
8
|
-
* 就绪 / 重启 / 代际 /
|
|
8
|
+
* 就绪 / 排空 / 重启 / 代际 / 租约 / 世代账,也没有出口绕过它去读 `deps` 上的这些输入。
|
|
9
9
|
* 2. **就绪**仍只有一只谓词(`http/readiness.ts` 的 `readinessOf`),铸点把它的判决原样带上(`verdict`)。`/readyz` 200 ⇔
|
|
10
10
|
* `ready ∧ ¬draining ∧ leaseState ≠ denied` —— 后两项不是新判据:`draining` 本来就是就绪原因,而租约被拒**同一拍**经
|
|
11
11
|
* 唯一的排空入口进入排空(`fleet/serving-lease.ts`),所以「被拒 ⇒ 排空 ⇒ 不就绪」是构造出来的,不靠第二只谓词。
|
|
12
12
|
* `leaseState = expired` **不**进就绪(中心不可达不是本实例的病,见租约模块头注)。
|
|
13
|
-
* 3. **重启**:`restart` = 已发布的重启信号;没有已发布信号而有一只**扣着**的候选(
|
|
13
|
+
* 3. **重启**:`restart` = 已发布的重启信号;没有已发布信号而有一只**扣着**的候选(web-admin 的保留候选状态机)且它确有被扣的片时,
|
|
14
14
|
* 铸 `{reasons: 被扣的片, version, since, withheld: true}`(「要重启,但此刻换掉本实例会丢它手里的候选」)。已发布的信号恒胜(那几片
|
|
15
15
|
* 是安全可重启的,扣着的片不阻止它们);被扣的片为空(只差发布重试)⇒ 不是重启事实,不铸(契约 `RestartSignal.reasons` 至少一词;
|
|
16
16
|
* 那一形的面只有每拍一行运维 warn + 计数)。「扣着」在两出口上只有这一种读法(7.120.x 的 `/health.modelPlaneDeferred` 本版删除)。
|
|
17
17
|
* 合成只在 {@link buildRestartSignal} 一处,`restartState()` 是它唯一的调用方 —— 两个出口读的是同一只取值口。
|
|
18
|
-
* 4.
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
18
|
+
* 4. **代际**:`generation` = env `FLEET_GENERATION` 的回声(规范十进制串;非规范在 boot 拒启,见 `config.ts`);缺席 ⇔ 非 fleet 成员。
|
|
19
|
+
* **身份不是引擎态**:`instanceId`(本进程起步自铸的那一只,`boot/stage-03` 的 uuidv7)是体的身份,只在两出口体的**顶层**说一次,
|
|
20
|
+
* 铸点不读它、契约形里不重复它。
|
|
21
|
+
* 5. **两形一读(展开 / 收缩)**:两出口今天各发两形 —— 嵌套键 {@link ENGINE_SIGNAL_KEY}(契约 `EngineSignal` 整只,{@link buildEngineSignal}),
|
|
22
|
+
* 与 8.0 扁平方言(布尔 `draining` + `drainingSince`、`/health` 就绪时不带 `ready`、`restart`、成员三键、`/health` 的世代账)。两形读的是
|
|
23
|
+
* **同一次**铸点读数里的**同一个字段**,投影全在本模块({@link buildEngineSignal} / {@link heartbeatReadinessKeys} / {@link healthDrainingKeys} /
|
|
24
|
+
* {@link fleetMembershipKeys} / {@link healthConfigLedgerKeys}),出口文件不拼引擎态的键。排空在两形上读的都是排空**事实**(`EngineDraining`,
|
|
25
|
+
* 三键齐才在),不是就绪原因 —— 所以「`engineSignal.draining` 在场 ⇔ 扁平 `draining` 为真、`drainingSince` = `engineSignal.draining.since`」
|
|
26
|
+
* 是构造出来的,不靠「唯一入口整组写四键」这条运行时不变量(那条不变量只管就绪原因与事实一致)。
|
|
27
|
+
* 心跳体 = 契约 `InstanceAnnouncement` + 嵌套键这一只:契约包 10.x 的心跳形还没有它的座位,10.x 中心按默认 strip 解析丢掉它、照收心跳;
|
|
28
|
+
* 世代账扁平两键契约心跳形没有座位,只上 `/health`(嵌套形里有,两出口都带)。非 fleet 部署的扁平键与 7.122.0 逐字同。
|
|
29
|
+
* 收缩:扁平布尔对(`draining` / `drainingSince`)settings-schema 12.0.0 从契约形删、本引擎 7.124.0+ 删发(届时删它们的投影);嵌套键名在
|
|
30
|
+
* 契约包自有这只常量的那一版提货时改读它。
|
|
27
31
|
* 6. **租约四态的词表属主是契约包**(`LeaseState`):本模块的读数型 {@link ServingLeaseView} 按它逐词对齐(下面的编译期断言两向钉),
|
|
28
32
|
* 契约加一个词 ⇒ 本仓编译红,不会悄悄多出一个本仓读不出的态。
|
|
29
33
|
*
|
|
30
|
-
* 模块形:纯函数(
|
|
34
|
+
* 模块形:纯函数(契约包只 import 型;值 import 只有两只纯叶 `http/readiness.ts` 与 `fleet/drain-entry.ts`)—— `http/` 与 `fleet-client.ts` 都读它,不许长出回环。
|
|
31
35
|
*/
|
|
32
|
-
import type { EngineDraining, InstanceAnnouncement, LeaseState, RestartSignal } from "@sema-agent/settings-schema/fleet";
|
|
36
|
+
import type { EngineDraining, EngineSignal, InstanceAnnouncement, LeaseState, RestartSignal } from "@sema-agent/settings-schema/fleet";
|
|
33
37
|
import { type ReadinessInputs, type ReadinessVerdict } from "../http/readiness.js";
|
|
34
38
|
/**
|
|
35
39
|
* 租约此刻的读数(租约客户端交出;纯数据)。态的词表 = 契约 `LeaseState`(四词的语义在契约注里:`none` 不生效 / `granted` 持有 /
|
|
@@ -50,7 +54,7 @@ export type ServingLeaseView = {
|
|
|
50
54
|
export type FleetMembershipKeys = Pick<InstanceAnnouncement, "generation" | "leaseState" | "leaseUntil">;
|
|
51
55
|
/** 非 fleet 成员 / 没装租约客户端时的读数(唯一拼法)。 */
|
|
52
56
|
export declare const LEASE_NONE: ServingLeaseView;
|
|
53
|
-
/** 扣着的候选(
|
|
57
|
+
/** 扣着的候选(web-admin 的 `planeDeferredNoHandoff` 投影):版本、起扣时刻、被扣的重启片。 */
|
|
54
58
|
export interface RetainedCandidate {
|
|
55
59
|
readonly version: number;
|
|
56
60
|
readonly since: number;
|
|
@@ -58,7 +62,7 @@ export interface RetainedCandidate {
|
|
|
58
62
|
}
|
|
59
63
|
/**
|
|
60
64
|
* 重启事实的**唯一**合成点(规则 3):已发布信号恒胜;否则扣着的候选有被扣的片 ⇒ `withheld:true` 的信号;否则缺席。
|
|
61
|
-
* `build*` = 纯数据。泛型让
|
|
65
|
+
* `build*` = 纯数据。泛型让 web-admin 交进来的窄型(`EngineRestartSignal`,`reasons` 是片闭集)原样回来。
|
|
62
66
|
*/
|
|
63
67
|
export declare function buildRestartSignal<R extends RestartSignal>(published: R | undefined, retained: (RetainedCandidate & {
|
|
64
68
|
readonly blocked?: readonly R["reasons"][number][];
|
|
@@ -68,8 +72,8 @@ export declare const CONFIG_HANDOFF_STATES: readonly ["missing"];
|
|
|
68
72
|
export type ConfigHandoffState = (typeof CONFIG_HANDOFF_STATES)[number];
|
|
69
73
|
/**
|
|
70
74
|
* `/health.configHandoff`(只在 `/health`,不上心跳)—— 一件**事故**:**在场 ⇔ 部署声明了耐久接力 ∧ 应用着的那一代没在下一次起服将用的身份的桶里确认耐久落盘**
|
|
71
|
-
* (
|
|
72
|
-
* 的身份选桶;部署形门在
|
|
75
|
+
* (web-admin 的接力账 {@link ConfigHandoffLedger}:最后确认耐久的那一代 + 写进的那只身份桶,对比应用着的那一代 + 此刻的凭证身份 —— 离线起服按此刻
|
|
76
|
+
* 的身份选桶;部署形门在 web-admin 的取值口,读判「handoff confirmed」的同一只谓词)。凭证换了人(换了身份)而新身份的桶里没有这一代 ⇒ 在场。覆盖 LKG 发布失败(含保留候选、启动期技能债)与部分应用(某组被整拒、其余组已热应用,LKG 停在上一个完整世代)两形。**部署形**不在这里报:
|
|
73
77
|
* 没有耐久声明(`CONFIG_LKG_DURABLE` 不真 / LKG 关)的部署「重启靠中心重拉」是配置时声明的事实 ⇒ 恒缺席;本地腿 / 没有配置管道 ⇒ 缺席。
|
|
74
78
|
* 与 `restart.withheld` 两个事实两张脸(可同在):要不要重启归 `restart`,声明了的接力缺不缺归本键。
|
|
75
79
|
* `version` = 应用着的那一代;`since` = 这一代开始没有确认接力的时刻(持续缺着时不刷新,确认即清)。
|
|
@@ -79,7 +83,7 @@ export interface ConfigHandoff {
|
|
|
79
83
|
readonly version: number;
|
|
80
84
|
readonly since: number;
|
|
81
85
|
}
|
|
82
|
-
/** 配置接力账(
|
|
86
|
+
/** 配置接力账(web-admin 持有,`/health.configHandoff` 的唯一来源):应用着的那一代、最后一次确认耐久接力的那一代与它写进的身份桶、
|
|
83
87
|
* 下一次起服将用的身份(此刻的凭证身份 —— 离线起服选桶读的同一只)。 */
|
|
84
88
|
export interface ConfigHandoffLedger {
|
|
85
89
|
readonly applied?: number;
|
|
@@ -92,11 +96,18 @@ export interface ConfigHandoffLedger {
|
|
|
92
96
|
/** 「接力缺着」的**唯一**判据(纯):应用过一代 ∧ 最后确认耐久的不是「这一代 ∧ 下一次起服将用的身份桶」。 */
|
|
93
97
|
export declare function configHandoffMissing(ledger: ConfigHandoffLedger): boolean;
|
|
94
98
|
/** `configHandoff` 的**唯一**合成点(纯):缺着 ⇒ `{ state: "missing", version: 应用着的那一代, since }`;否则缺席。`since` 由持账方锁存(发现缺着的那一拍)。
|
|
95
|
-
* `build*` = 纯数据;
|
|
99
|
+
* `build*` = 纯数据;web-admin 的 `configHandoffState()` 是唯一调用方。 */
|
|
96
100
|
export declare function buildConfigHandoff(ledger: ConfigHandoffLedger, since: number | undefined): ConfigHandoff | undefined;
|
|
101
|
+
/** 世代账的一次读数(web-admin 的 `configApplyState()` 交出的那一份里本模块读的五键;`/health` 扁平五键与嵌套形的两键读同一份)。 */
|
|
102
|
+
export interface ConfigLedgerReading {
|
|
103
|
+
readonly configTargetVersion: number;
|
|
104
|
+
readonly configAppliedVersion: number;
|
|
105
|
+
readonly configTargetOrdinal: number;
|
|
106
|
+
readonly configAppliedOrdinal: number;
|
|
107
|
+
readonly configApplyStaleMs?: number;
|
|
108
|
+
}
|
|
97
109
|
/** 铸点读的输入 —— `ServiceDeps` 上的同名键(HTTP 面与心跳读的是**同一个**对象)。 */
|
|
98
110
|
export interface EngineSignalInputs extends ReadinessInputs {
|
|
99
|
-
readonly instanceId?: string;
|
|
100
111
|
/** `config.fleetGeneration` = env `FLEET_GENERATION` 的回声(boot 已判规范;缺席 ⇔ 非 fleet 成员)。 */
|
|
101
112
|
readonly config?: {
|
|
102
113
|
readonly fleetGeneration?: string;
|
|
@@ -108,34 +119,54 @@ export interface EngineSignalInputs extends ReadinessInputs {
|
|
|
108
119
|
};
|
|
109
120
|
readonly restartState?: () => RestartSignal | undefined;
|
|
110
121
|
readonly servingLease?: () => ServingLeaseView;
|
|
111
|
-
readonly configApplyState?: () =>
|
|
112
|
-
readonly configTargetVersion: number;
|
|
113
|
-
readonly configAppliedVersion: number;
|
|
114
|
-
} | undefined;
|
|
122
|
+
readonly configApplyState?: () => ConfigLedgerReading | undefined;
|
|
115
123
|
}
|
|
116
124
|
/** 铸出的信号(纯数据)。 */
|
|
117
125
|
export interface EngineSignalFacts {
|
|
118
126
|
/** 就绪判(`readinessOf` 原样)。 */
|
|
119
127
|
readonly verdict: ReadinessVerdict;
|
|
120
|
-
/** 在场 ⇔ 排空中(契约 `EngineDraining`:动作 / 起点 / 期限)。 */
|
|
128
|
+
/** 在场 ⇔ 排空中(契约 `EngineDraining`:动作 / 起点 / 期限)—— 两出口两形读排空的唯一字段(规则 5)。 */
|
|
121
129
|
readonly draining?: EngineDraining;
|
|
122
130
|
readonly restart?: RestartSignal;
|
|
123
131
|
readonly generation?: string;
|
|
124
|
-
readonly instanceId?: string;
|
|
125
132
|
readonly lease: ServingLeaseView;
|
|
126
|
-
|
|
127
|
-
readonly
|
|
133
|
+
/** 世代账的那一次读数(未接线 ⇒ 缺席)。 */
|
|
134
|
+
readonly configApply?: ConfigLedgerReading;
|
|
128
135
|
}
|
|
129
136
|
/** **唯一**铸点(活判,每次调用现读输入)。 */
|
|
130
137
|
export declare function mintEngineSignal(deps: EngineSignalInputs): EngineSignalFacts;
|
|
138
|
+
/**
|
|
139
|
+
* 两出口体上嵌套引擎信号的键名(规则 5;两出口同一只拼法)。契约包 10.x 没有这只常量(它的心跳形也没有这一座位);契约包自有它的那一版
|
|
140
|
+
* 提货时,本常量删、改读契约包的。
|
|
141
|
+
*/
|
|
142
|
+
export declare const ENGINE_SIGNAL_KEY = "engineSignal";
|
|
143
|
+
/** 体上的嵌套引擎信号:键 {@link ENGINE_SIGNAL_KEY},值 = 契约 `EngineSignal`。 */
|
|
144
|
+
export type EngineSignalCarrier = {
|
|
145
|
+
readonly [ENGINE_SIGNAL_KEY]: EngineSignal;
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* 契约形 `EngineSignal` 的**唯一**投影(规则 5;两出口同调,同一次读数 ⇒ 同值同序)。键序照契约形:`ready` 恒说;`draining` = 排空事实;
|
|
149
|
+
* `restart` = 取值口交出的那个对象;成员三键 = {@link fleetMembershipKeys};世代账两键 = 同一次读数。身份不在这里(规则 4)。`build*` = 纯数据。
|
|
150
|
+
*/
|
|
151
|
+
export declare function buildEngineSignal(s: EngineSignalFacts): EngineSignal;
|
|
131
152
|
/**
|
|
132
153
|
* fleet 成员身份三键的**唯一**投影(两出口同调,同值同序):`generation` / `leaseState` / `leaseUntil`。
|
|
133
154
|
* 在场律:非 fleet 成员(无 `generation`)⇒ 空对象(两出口逐字节同 7.120.0);成员 ⇒ `generation` + `leaseState` 恒在,
|
|
134
155
|
* `leaseUntil` 只在 `granted`。
|
|
135
156
|
*/
|
|
136
157
|
export declare function fleetMembershipKeys(s: EngineSignalFacts): FleetMembershipKeys;
|
|
137
|
-
/**
|
|
138
|
-
export declare function
|
|
158
|
+
/** 心跳的 8.0 扁平方言 `ready` / `draining`(恒带,`false` 也带):`ready` = 就绪判,`draining` = 排空事实在场(规则 5,与嵌套形读同一个字段)。 */
|
|
159
|
+
export declare function heartbeatReadinessKeys(s: EngineSignalFacts): Pick<InstanceAnnouncement, "ready" | "draining">;
|
|
160
|
+
/** `/health` 的 8.0 扁平排空对:只在排空中带 —— `draining: true` + `drainingSince` = 排空事实的 `since`(规则 5,与嵌套形读同一个字段)。 */
|
|
161
|
+
export declare function healthDrainingKeys(s: EngineSignalFacts): {
|
|
162
|
+
readonly draining?: true;
|
|
163
|
+
readonly drainingSince?: number;
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* `/health` 的世代账扁平键(未接线 ⇒ 全缺席):target / applied 两版本(与嵌套形同一次读数)+ 两只收货序数(进程内单调,「见过多少代 / 停在哪一代」
|
|
167
|
+
* 的推进判据)+ `configApplyStaleMs`(两者持续不等的时长,收敛即缺席)。只上 `/health`(契约心跳形没有这些座位)。
|
|
168
|
+
*/
|
|
169
|
+
export declare function healthConfigLedgerKeys(s: EngineSignalFacts): Partial<ConfigLedgerReading>;
|
|
139
170
|
/**
|
|
140
171
|
* `/health.restartRequired`(冗余顶层布尔,壳读它决定要不要问用户重启)的投影:在场 ⇔ 有**可执行**的重启信号
|
|
141
172
|
* (`restart` 在场且未被扣)—— 与 7.120.0 的读数逐字同(那时被扣的候选根本不出 `restart`)。
|
|
@@ -23,15 +23,24 @@ export function mintEngineSignal(deps) {
|
|
|
23
23
|
const ds = deps.drainState;
|
|
24
24
|
const draining = ds === undefined ? undefined : drainingFactOf(ds);
|
|
25
25
|
const restart = deps.restartState?.();
|
|
26
|
-
const
|
|
26
|
+
const configApply = deps.configApplyState?.();
|
|
27
27
|
return {
|
|
28
28
|
verdict,
|
|
29
29
|
...(draining !== undefined ? { draining } : {}),
|
|
30
30
|
...(restart !== undefined ? { restart } : {}),
|
|
31
31
|
...(deps.config?.fleetGeneration !== undefined ? { generation: deps.config.fleetGeneration } : {}),
|
|
32
|
-
...(deps.instanceId !== undefined ? { instanceId: deps.instanceId } : {}),
|
|
33
32
|
lease: deps.servingLease?.() ?? LEASE_NONE,
|
|
34
|
-
...(
|
|
33
|
+
...(configApply !== undefined ? { configApply } : {}),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export const ENGINE_SIGNAL_KEY = "engineSignal";
|
|
37
|
+
export function buildEngineSignal(s) {
|
|
38
|
+
return {
|
|
39
|
+
ready: s.verdict.ready,
|
|
40
|
+
...(s.draining !== undefined ? { draining: s.draining } : {}),
|
|
41
|
+
...(s.restart !== undefined ? { restart: s.restart } : {}),
|
|
42
|
+
...fleetMembershipKeys(s),
|
|
43
|
+
...(s.configApply !== undefined ? { configTargetVersion: s.configApply.configTargetVersion, configAppliedVersion: s.configApply.configAppliedVersion } : {}),
|
|
35
44
|
};
|
|
36
45
|
}
|
|
37
46
|
export function fleetMembershipKeys(s) {
|
|
@@ -51,8 +60,23 @@ export function fleetMembershipKeys(s) {
|
|
|
51
60
|
}
|
|
52
61
|
}
|
|
53
62
|
}
|
|
54
|
-
export function
|
|
55
|
-
return
|
|
63
|
+
export function heartbeatReadinessKeys(s) {
|
|
64
|
+
return { ready: s.verdict.ready, draining: s.draining !== undefined };
|
|
65
|
+
}
|
|
66
|
+
export function healthDrainingKeys(s) {
|
|
67
|
+
return s.draining === undefined ? {} : { draining: true, drainingSince: s.draining.since };
|
|
68
|
+
}
|
|
69
|
+
export function healthConfigLedgerKeys(s) {
|
|
70
|
+
const g = s.configApply;
|
|
71
|
+
if (g === undefined)
|
|
72
|
+
return {};
|
|
73
|
+
return {
|
|
74
|
+
configTargetVersion: g.configTargetVersion,
|
|
75
|
+
configAppliedVersion: g.configAppliedVersion,
|
|
76
|
+
configTargetOrdinal: g.configTargetOrdinal,
|
|
77
|
+
configAppliedOrdinal: g.configAppliedOrdinal,
|
|
78
|
+
...(g.configApplyStaleMs !== undefined ? { configApplyStaleMs: g.configApplyStaleMs } : {}),
|
|
79
|
+
};
|
|
56
80
|
}
|
|
57
81
|
export function restartActionable(s) {
|
|
58
82
|
return s.restart !== undefined && s.restart.withheld !== true;
|
|
@@ -566,6 +566,7 @@ export declare function fleetRunPublisher(bus: FleetEventBus | undefined, run: {
|
|
|
566
566
|
name?: string;
|
|
567
567
|
toolName?: string;
|
|
568
568
|
parentToolCallId?: string;
|
|
569
|
+
workflowRunId?: string;
|
|
569
570
|
status?: string;
|
|
570
571
|
seq?: number;
|
|
571
572
|
}) => void;
|
|
@@ -576,6 +577,7 @@ export declare function fleetRunPublisher(bus: FleetEventBus | undefined, run: {
|
|
|
576
577
|
name?: string;
|
|
577
578
|
usage?: unknown;
|
|
578
579
|
parentToolCallId?: string;
|
|
580
|
+
workflowRunId?: string;
|
|
579
581
|
status?: string;
|
|
580
582
|
seq?: number;
|
|
581
583
|
}) => void;
|
|
@@ -639,13 +641,20 @@ export declare function fleetRunResiduals(result: {
|
|
|
639
641
|
* session attribution → unscoped, back-compat visible). Names ride the same redactSecrets discipline.
|
|
640
642
|
*/
|
|
641
643
|
export declare function fleetBackgroundChildPublisher(bus?: FleetEventBus, log?: (msg: string, fields: Record<string, unknown>) => void): (e: import("@sema-agent/core").BackgroundChildEvent) => void;
|
|
644
|
+
/**
|
|
645
|
+
* 🔴 **run 的短名 —— 一只折法、一个输入**:输入 = run 行的预览(`user-authored-text.ts` 的 `buildRunObjectivePreview` 的产物,run 行上存的就是它);
|
|
646
|
+
* fleet 行的 `name`(发布时由 objective 现算同一只预览)与 `GET /v1/assistant/tasks` 的 `name`(读 run 行上存的预览)读同一只,
|
|
647
|
+
* 同一个 run 两面同名。预览是 `""`(有记录、剥完没有用户正文)⇒ `(notification turn)`;否则单行折叠、超过 48 字截断带 `…`。预览已脱敏。
|
|
648
|
+
* 入参只收「有记录」的预览:列上的 NULL(没记录)不是通告轮,由读面自己按契约缺席,不进这只折法。
|
|
649
|
+
*/
|
|
650
|
+
export declare function buildRunName(preview: string): string;
|
|
642
651
|
/** BC-1 (clay-decided 2026-06-27): a top-level run's fleet-row `name` = a SHORT, single-line **objective preview**
|
|
643
652
|
* (the readable "what is this task" label) — NOT the full objective dumped in, and NOT duplicated into `description`.
|
|
644
653
|
* `description` is left to the publisher's LIVE-ACTIVITY update (`onEvent` tool_start → the current tool), so the row
|
|
645
654
|
* shows `name`=objective + `description`=current activity (two DISTINCT things, killing the earlier "objective shown
|
|
646
|
-
* twice" dup).
|
|
647
|
-
*
|
|
648
|
-
*
|
|
655
|
+
* twice" dup). (A subagent CHILD row's name = its agent-type — BC-2.)
|
|
656
|
+
* 一只折法({@link buildRunName}),输入 = 与 run 行同一只预览(用户写的那段 → 脱敏 → 截):`GET /v1/assistant/tasks`
|
|
657
|
+
* 读 run 行上存的预览、过同一只折法 ⇒ 同一个 run 两面同名。剥完没有用户正文 ⇒ `(notification turn)`;闭集外的 XML 头当普通正文标。 */
|
|
649
658
|
export declare function fleetRunLabels(objective: string | undefined): {
|
|
650
659
|
name: string;
|
|
651
660
|
};
|
package/dist/fleet/fleet-bus.js
CHANGED
|
@@ -3,6 +3,7 @@ import { DURABLE_AGENT_HANDLE_RE, deriveAgentDisplayStatus, isDelegatedAgentTerm
|
|
|
3
3
|
import { persistedPlaneOf } from "../terminal.js";
|
|
4
4
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
5
5
|
import { redactSecrets } from "../trace/redact.js";
|
|
6
|
+
import { buildRunObjectivePreview } from "../user-authored-text.js";
|
|
6
7
|
export function isFleetAgentTerminalNotification(n) {
|
|
7
8
|
return isDelegatedAgentTerminal(n);
|
|
8
9
|
}
|
|
@@ -206,6 +207,7 @@ export function fleetRunPublisher(bus, run) {
|
|
|
206
207
|
let settledLeg = false;
|
|
207
208
|
const childId = (taskId) => `${run.runId} ${taskId}`;
|
|
208
209
|
const tickStatus = (st) => (st === "completed" ? "completed" : st === "failed" ? "failed" : "running");
|
|
210
|
+
const workflowRunIdField = (ev) => (ev.workflowRunId ? { workflowRunId: ev.workflowRunId } : {});
|
|
209
211
|
const toolUsesOf = (usage) => {
|
|
210
212
|
const t = usage?.toolUses;
|
|
211
213
|
return typeof t === "number" ? t : undefined;
|
|
@@ -269,7 +271,7 @@ export function fleetRunPublisher(bus, run) {
|
|
|
269
271
|
childStartedAt.set(cid, Date.now());
|
|
270
272
|
if (ev.parentToolCallId)
|
|
271
273
|
childByToolCall.set(ev.parentToolCallId, cid);
|
|
272
|
-
bus.publishTask({ id: cid, sourceLane: "run-leg", ...(childName !== undefined ? { name: childName, agentType: childName } : {}), parentId: run.runId, scope: run.scope, ...sessionField, status: tickStatus(ev.status), tokens: sumTokens(ev.usage), ...(typeof ev.seq === "number" ? { cycleSeq: ev.seq } : {}), ...(() => { const t = toolUsesOf(ev.usage); return t !== undefined ? { toolUses: t } : {}; })(), elapsedMs: Date.now() - childStartedAt.get(cid) });
|
|
274
|
+
bus.publishTask({ id: cid, sourceLane: "run-leg", ...(childName !== undefined ? { name: childName, agentType: childName } : {}), parentId: run.runId, scope: run.scope, ...sessionField, ...workflowRunIdField(ev), status: tickStatus(ev.status), tokens: sumTokens(ev.usage), ...(typeof ev.seq === "number" ? { cycleSeq: ev.seq } : {}), ...(() => { const t = toolUsesOf(ev.usage); return t !== undefined ? { toolUses: t } : {}; })(), elapsedMs: Date.now() - childStartedAt.get(cid) });
|
|
273
275
|
}
|
|
274
276
|
else if (ev.type === "tool_start" && ev.toolName) {
|
|
275
277
|
bus.publishTask({ id: run.runId, description: ev.toolName });
|
|
@@ -290,7 +292,7 @@ export function fleetRunPublisher(bus, run) {
|
|
|
290
292
|
childStartedAt.set(cid, Date.now());
|
|
291
293
|
if (ev.parentToolCallId)
|
|
292
294
|
childByToolCall.set(ev.parentToolCallId, cid);
|
|
293
|
-
bus.publishTask({ id: cid, sourceLane: "run-leg", ...(fwdName !== undefined ? { name: fwdName, agentType: fwdName } : {}), parentId, scope: run.scope, ...sessionField, status: tickStatus(ev.status), tokens: sumTokens(ev.usage), ...(typeof ev.seq === "number" ? { cycleSeq: ev.seq } : {}), ...(() => { const t = toolUsesOf(ev.usage); return t !== undefined ? { toolUses: t } : {}; })(), elapsedMs: Date.now() - childStartedAt.get(cid) });
|
|
295
|
+
bus.publishTask({ id: cid, sourceLane: "run-leg", ...(fwdName !== undefined ? { name: fwdName, agentType: fwdName } : {}), parentId, scope: run.scope, ...sessionField, ...workflowRunIdField(ev), status: tickStatus(ev.status), tokens: sumTokens(ev.usage), ...(typeof ev.seq === "number" ? { cycleSeq: ev.seq } : {}), ...(() => { const t = toolUsesOf(ev.usage); return t !== undefined ? { toolUses: t } : {}; })(), elapsedMs: Date.now() - childStartedAt.get(cid) });
|
|
294
296
|
},
|
|
295
297
|
onChildTerminal(taskId, status, altId, toolUseId) {
|
|
296
298
|
if (settledLeg)
|
|
@@ -612,14 +614,16 @@ export function fleetBackgroundChildPublisher(bus, log) {
|
|
|
612
614
|
handleTerminal(e, m);
|
|
613
615
|
};
|
|
614
616
|
}
|
|
617
|
+
const NOTIFICATION_TURN_NAME = "(notification turn)";
|
|
618
|
+
const RUN_NAME_CHARS = 48;
|
|
619
|
+
export function buildRunName(preview) {
|
|
620
|
+
const oneLine = preview.replace(/\s+/g, " ").trim();
|
|
621
|
+
if (oneLine === "")
|
|
622
|
+
return NOTIFICATION_TURN_NAME;
|
|
623
|
+
return oneLine.length > RUN_NAME_CHARS ? `${oneLine.slice(0, RUN_NAME_CHARS - 1)}…` : oneLine;
|
|
624
|
+
}
|
|
615
625
|
export function fleetRunLabels(objective) {
|
|
616
|
-
|
|
617
|
-
if (!oneLine)
|
|
618
|
-
return { name: "task" };
|
|
619
|
-
if (/^<[a-z][a-z0-9_-]*[\s>/]/i.test(oneLine))
|
|
620
|
-
return { name: "(notification turn)" };
|
|
621
|
-
const name = oneLine.length > 48 ? `${oneLine.slice(0, 47)}…` : oneLine;
|
|
622
|
-
return { name };
|
|
626
|
+
return { name: buildRunName(buildRunObjectivePreview(objective ?? "")) };
|
|
623
627
|
}
|
|
624
628
|
export function isTerminalFleetStatus(status) {
|
|
625
629
|
switch (status) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import { type CenterEndpoint } from "../
|
|
1
|
+
import { type WebAdminCapabilities } from "@sema-agent/settings-schema/fleet";
|
|
2
|
+
import { type CenterEndpoint } from "../web-admin-client/center-request.js";
|
|
3
3
|
import { type DrainEntry } from "./drain-entry.js";
|
|
4
4
|
import type { ServingLeaseView } from "./engine-signal.js";
|
|
5
5
|
/** 续租请求的上界(ms)—— 与 fleet 心跳同量级(不在提交热路径上)。 */
|
|
@@ -34,7 +34,7 @@ export interface ServingLeaseClientOpts {
|
|
|
34
34
|
}
|
|
35
35
|
export interface ServingLeaseClient {
|
|
36
36
|
/** 一次中心能力读数(`undefined` = `undeclared`,中心没宣告 = 不支持)。每一次读数调一次;`unreadable` 不是读数,不调(`fleet-client.ts` `capabilityReadingOf`)。 */
|
|
37
|
-
noteCenterCapabilities(caps:
|
|
37
|
+
noteCenterCapabilities(caps: WebAdminCapabilities | undefined): void;
|
|
38
38
|
/** 此刻的租约读数(铸点与准入判读它)。 */
|
|
39
39
|
view(): ServingLeaseView;
|
|
40
40
|
/** 起步读黏性拒(装配层在唯一排空入口装好之后调一次)。 */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { SERVING_LEASE_TTL_DEFAULT_MS, readServingLeaseResponse } from "@sema-agent/settings-schema/fleet";
|
|
4
|
-
import { centerFetch } from "../
|
|
4
|
+
import { centerFetch } from "../web-admin-client/center-request.js";
|
|
5
5
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
6
6
|
import { leaseDrainActionId } from "./drain-entry.js";
|
|
7
7
|
export const SERVING_LEASE_FETCH_TIMEOUT_MS = 5_000;
|
package/dist/fleet-client.d.ts
CHANGED
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Fleet worker-side wiring(announce/heartbeat + usage 批报;契约 = registry-core 0.1.48+
|
|
3
|
-
* `/fleet`,center 端点 =
|
|
3
|
+
* `/fleet`,center 端点 = web-admin `/api/fleet/*`)。设计要点:
|
|
4
4
|
* - **可选分层(D3),两条环各自有门(S-866 ④)**:客户端在中心车道配齐时启动(`centerLaneConfigured` —— baseUrl + 声明了
|
|
5
5
|
* 凭证 + worker,与租约管理器、用量累加器**同一只**谓词);**用量环**只要这三件;**公告环**(announce / 心跳 / 注销)另要
|
|
6
6
|
* 配置席 `fleetAdvertiseAddress`(env `FLEET_ADVERTISE_ADDRESS`,`loadConfig` 解析一次;可达性是运维的话,不自猜:k8s pod IP /
|
|
7
7
|
* docker alias / 127.0.0.1:port 只有部署环境自己知道)。不配中心的部署零行为变化;配了中心而不公告的引擎只报用量、不注册(7.105.0 及以前它连用量都不报)。
|
|
8
8
|
* - **announce=注册=心跳同形状幂等 upsert**:boot 后(listen 之后)POST 一次 + 每 heartbeatMs 续。
|
|
9
|
-
* `ready` / `draining`
|
|
10
|
-
* 与 `/health.ready`、`GET /readyz
|
|
11
|
-
* `draining
|
|
12
|
-
*
|
|
9
|
+
* `ready` / `draining` 两字段由引擎信号铸点的同一次读铸(S-740:`ready` = `http/readiness.ts` `readinessOf` 的判,
|
|
10
|
+
* 与 `/health.ready`、`GET /readyz`、计费提交门同源;= roster 已落 ∧ ¬draining),`draining` = 排空事实在场(与嵌套
|
|
11
|
+
* `engineSignal.draining` 同一个字段,`fleet/engine-signal.ts` 规则 5)。修前 `ready = !isDraining()`,不含 roster ⇒ roster 未落时
|
|
12
|
+
* 心跳说「就绪」而计费提交在 503。
|
|
13
|
+
* - **`engineSignal`(7.123.0)**:引擎态整只(契约 `EngineSignal`),与扁平键同一次读数;契约包 10.x 的心跳形没有它的座位(10.x 中心
|
|
14
|
+
* 默认 strip 解析丢掉它、照收心跳);扁平布尔 `draining` settings-schema 12.0.0 删、本引擎 7.124.0+ 删发。
|
|
13
15
|
* - **`restart?`(S-741)**:在场 ⇔ 本副本必须重启才能应用配置 —— 取自 `/health.restart` **同一只**取值口(装配层接
|
|
14
|
-
* `deployment.restartState`,
|
|
16
|
+
* `deployment.restartState`,web-admin 的 `restartState()`),同一个对象,形 = settings-schema `RestartSignal`;
|
|
15
17
|
* 缺席即键缺席(中心按行整体替换,不合并 —— 一条不带它的心跳就是「不再需要」)。
|
|
16
18
|
* - **`modelRefusals?`(S-768)**:在场 ⇔ 本副本对最近一次被判的中心候选目录有可报的拒(逐条名 → 码 / 模型面组拒码)—— 取自
|
|
17
19
|
* `/health.modelRefusals` **同一只**取值口(装配层接 `deployment.modelRefusalsState`),同一个对象,形 = settings-schema
|
|
18
20
|
* `ModelRefusalsSignal`;缺席即键缺席(同 `restart`)。
|
|
19
21
|
* - **自报状态翻转即刻再 announce**(第一时间自摘流 / 自挂流 / 报重启 / 报拒因,比任何观测都快):draining 翻转由收尾链直调
|
|
20
|
-
* `announceNow`;roster 落地、restart 信号与模型拒因变化由装配层把
|
|
22
|
+
* `announceNow`;roster 落地、restart 信号与模型拒因变化由装配层把 web-admin 的 `onSelfReportChange` 接到 `announceNow`
|
|
21
23
|
* (两处 = 两类输入各自的唯一写者,触发都是 `announceNow`)。退出前 DELETE(显式注销,幂等)。
|
|
22
24
|
* - **usage 批报**:tracer 的 `brain.call` 已带 ALS principal —— FleetUsageAccumulator 按 principal×model
|
|
23
25
|
* 累计,每窗口(默认 60s,半开 [windowStartMs, windowEndMs))POST /api/fleet/usage。幂等键
|
|
@@ -25,9 +27,9 @@
|
|
|
25
27
|
* 向前合并不会双计 —— 只延迟,不丢量)。
|
|
26
28
|
* - 全部 fire-and-forget + swallow-guarded:fleet 面是运维旁路,绝不影响任务面;网络错误只 warn 一次/连败类。
|
|
27
29
|
*/
|
|
28
|
-
import { UsageReport, type CapabilityReading, type
|
|
30
|
+
import { UsageReport, type CapabilityReading, type WebAdminCapabilities, type ModelRefusalsSignal } from "@sema-agent/settings-schema/fleet";
|
|
29
31
|
import { type EngineSignalFacts } from "./fleet/engine-signal.js";
|
|
30
|
-
import { type CenterEndpoint } from "./
|
|
32
|
+
import { type CenterEndpoint } from "./web-admin-client/center-request.js";
|
|
31
33
|
/** Bound on distinct principal×model keys per window — a runaway/multi-tenant burst collapses into
|
|
32
34
|
* `__other__` instead of growing unbounded (same posture as budget.ts cardinalityGuard). */
|
|
33
35
|
export declare const FLEET_USAGE_KEY_CAP = 1024;
|
|
@@ -80,8 +82,8 @@ export interface FleetClientOpts {
|
|
|
80
82
|
advertiseAddress?: string | undefined;
|
|
81
83
|
version: string;
|
|
82
84
|
/** 编排器片 2 件 1:引擎信号的**一只铸点**(装配层接 `mintEngineSignal(deployment)` —— `/health` 与 `/readyz` 读的同一只、同一个 deps 组)。
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
+
* 每条公告现铸**一次**,嵌套 `engineSignal` 与扁平 `ready` / `draining` / `restart` / 代际与租约三键都取自这一次(不会撕裂成 `ready:true` +
|
|
86
|
+
* `draining:true`,也不会出现心跳与 `/health` 各算一份重启或租约)。修前是 `readiness` + `restart` 两只取值口(S-740 / S-741),合进这一只。 */
|
|
85
87
|
signal: () => EngineSignalFacts;
|
|
86
88
|
/** S-768:模型拒因信号(装配层接 `/health` 同一只取值口 `deployment.modelRefusalsState`)。每条公告现读一次;`undefined` ⇒ 公告不带
|
|
87
89
|
* `modelRefusals` 键。必填:与 `restart` 同 —— 心跳面没有「不知道有没有拒」这一形(老引擎不发这个键,中心按 `version` 判「不可知」)。 */
|
|
@@ -89,7 +91,7 @@ export interface FleetClientOpts {
|
|
|
89
91
|
/** 编排器片 2:每一次**能力读数**交出去一次(装配层接服务租约客户端的 `noteCenterCapabilities`)。规则见 {@link capabilityReadingOf}:
|
|
90
92
|
* 只有 `declared`(交出宣告的位)与 `undeclared`(交 `undefined` = 老中心没宣告)是读数;`unreadable`(体读不出 / 不是对象 /
|
|
91
93
|
* `capabilities` 键在场而形坏)不是读数 ⇒ 不调,上一次读数与它的钟原样。失败的公告同样不调(没听到 ≠ 没有)。 */
|
|
92
|
-
onCenterCapabilities?: (caps:
|
|
94
|
+
onCenterCapabilities?: (caps: WebAdminCapabilities | undefined) => void;
|
|
93
95
|
usage?: FleetUsageAccumulator;
|
|
94
96
|
heartbeatMs?: number;
|
|
95
97
|
usageWindowMs?: number;
|
|
@@ -146,7 +148,7 @@ export declare function startFleetClient(opts: FleetClientOpts): FleetClient;
|
|
|
146
148
|
* deployments); an address set while only the worker is missing is warned (half-configured announce).
|
|
147
149
|
*/
|
|
148
150
|
export declare function startFleetClientFromConfig(cfg: {
|
|
149
|
-
|
|
151
|
+
webAdmin?: (CenterEndpoint & {
|
|
150
152
|
worker?: string;
|
|
151
153
|
}) | undefined;
|
|
152
154
|
fleetAdvertiseAddress?: string | undefined;
|
package/dist/fleet-client.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { InstanceAnnouncement, UsageReport, DEFAULT_HEARTBEAT_MS, readCapabilityReading } from "@sema-agent/settings-schema/fleet";
|
|
2
|
-
import {
|
|
3
|
-
import { centerFetch, centerLaneConfigured } from "./
|
|
2
|
+
import { ENGINE_SIGNAL_KEY, buildEngineSignal, fleetMembershipKeys, heartbeatReadinessKeys } from "./fleet/engine-signal.js";
|
|
3
|
+
import { centerFetch, centerLaneConfigured } from "./web-admin-client/center-request.js";
|
|
4
4
|
import { recordFailOpen } from "./observability/fail-open.js";
|
|
5
|
+
import { WEB_ADMIN_ENV } from "@sema-agent/settings-schema";
|
|
5
6
|
export const FLEET_USAGE_KEY_CAP = 1024;
|
|
6
7
|
export const FLEET_CLIENT_FETCH_TIMEOUT_MS = 5000;
|
|
7
8
|
export class FleetUsageAccumulator {
|
|
@@ -99,18 +100,19 @@ export function startFleetClient(opts) {
|
|
|
99
100
|
return;
|
|
100
101
|
try {
|
|
101
102
|
const signal = opts.signal();
|
|
103
|
+
const engineSignal = buildEngineSignal(signal);
|
|
102
104
|
const modelRefusals = opts.modelRefusals();
|
|
103
105
|
const body = {
|
|
104
106
|
instanceId: opts.instanceId,
|
|
105
107
|
worker: opts.center.worker,
|
|
106
108
|
address,
|
|
107
109
|
version: opts.version,
|
|
108
|
-
|
|
109
|
-
draining: drainingFlag(signal),
|
|
110
|
+
...heartbeatReadinessKeys(signal),
|
|
110
111
|
heartbeatMs,
|
|
111
112
|
...(signal.restart !== undefined ? { restart: signal.restart } : {}),
|
|
112
113
|
...(modelRefusals !== undefined ? { modelRefusals } : {}),
|
|
113
114
|
...fleetMembershipKeys(signal),
|
|
115
|
+
[ENGINE_SIGNAL_KEY]: engineSignal,
|
|
114
116
|
};
|
|
115
117
|
const { res } = await send("fleet-instances", "POST", body);
|
|
116
118
|
if (!res.ok)
|
|
@@ -229,14 +231,14 @@ export function startFleetClient(opts) {
|
|
|
229
231
|
return { announceNow, stopRouting, flushFinalUsage };
|
|
230
232
|
}
|
|
231
233
|
export function startFleetClientFromConfig(cfg, opts) {
|
|
232
|
-
const cc = cfg.
|
|
234
|
+
const cc = cfg.webAdmin;
|
|
233
235
|
const address = cfg.fleetAdvertiseAddress;
|
|
234
236
|
if (!centerLaneConfigured(cfg)) {
|
|
235
237
|
if (address !== undefined && cc?.baseUrl && cc.credential.declared) {
|
|
236
|
-
opts.logger?.warn("fleet_client_no_worker_scope", { note:
|
|
238
|
+
opts.logger?.warn("fleet_client_no_worker_scope", { note: `FLEET_ADVERTISE_ADDRESS set but ${WEB_ADMIN_ENV.worker} missing — announce needs the worker (dispatch key); fleet client not started` });
|
|
237
239
|
}
|
|
238
240
|
return undefined;
|
|
239
241
|
}
|
|
240
|
-
return startFleetClient({ ...opts, center: cfg.
|
|
242
|
+
return startFleetClient({ ...opts, center: cfg.webAdmin, advertiseAddress: address });
|
|
241
243
|
}
|
|
242
244
|
//# sourceMappingURL=fleet-client.js.map
|
package/dist/fleet-lease.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type CenterEndpoint } from "./
|
|
1
|
+
import { type CenterEndpoint } from "./web-admin-client/center-request.js";
|
|
2
2
|
/** 负缓存 TTL:非 lease-enforced 的 principal 多久后再问一次 center(entitlement 升级为 lease 的收敛上界)。 */
|
|
3
3
|
export declare const NOT_LEASE_TTL_MS: number;
|
|
4
4
|
/** center 判 budget exhausted 后,多久内的重复提交直接拒绝而不再打 center(防 per-request 打爆)。 */
|
|
@@ -141,11 +141,11 @@ export declare class FleetLeaseManager {
|
|
|
141
141
|
/**
|
|
142
142
|
* Env/config gate:中心车道配齐({@link centerLaneConfigured} —— 与 fleet 用量环 / 用量累加器**同一只**谓词,S-866 ④)即启;
|
|
143
143
|
* 不需要 FLEET_ADVERTISE_ADDRESS(它是出站消费面,不是入站可达性声明)。缺任一件 → undefined,非 fleet 部署零行为变化。
|
|
144
|
-
* S-651:按**声明**装、不按内容装 —— `
|
|
144
|
+
* S-651:按**声明**装、不按内容装 —— `SEMA_WEB_ADMIN_TOKEN_FILE`(`WEB_ADMIN_ENV.tokenFile`)在场而
|
|
145
145
|
* 文件此刻不可读,管理器照样装上(每次协商取值,失败走响亮的鉴权失败臂;文件恢复即恢复)。
|
|
146
146
|
*/
|
|
147
147
|
export declare function createFleetLeaseFromEnv(cfg: {
|
|
148
|
-
|
|
148
|
+
webAdmin?: (CenterEndpoint & {
|
|
149
149
|
worker?: string;
|
|
150
150
|
}) | undefined;
|
|
151
151
|
fleetLeaseFailClosed: boolean;
|
package/dist/fleet-lease.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { QuotaLease, leaseExhausted, shouldRenewLease } from "@sema-agent/settings-schema/fleet";
|
|
2
2
|
import { CenterCredentialUnavailableError } from "./center-credential.js";
|
|
3
|
-
import { centerFetch, centerLaneConfigured } from "./
|
|
3
|
+
import { centerFetch, centerLaneConfigured } from "./web-admin-client/center-request.js";
|
|
4
4
|
export const NOT_LEASE_TTL_MS = 10 * 60 * 1000;
|
|
5
5
|
export const EXHAUSTED_RETRY_MS = 30 * 1000;
|
|
6
6
|
export const LEASE_PRINCIPAL_CAP = 4096;
|
|
@@ -174,7 +174,7 @@ export class FleetLeaseManager {
|
|
|
174
174
|
export function createFleetLeaseFromEnv(cfg, opts) {
|
|
175
175
|
if (!centerLaneConfigured(cfg))
|
|
176
176
|
return undefined;
|
|
177
|
-
const cc = cfg.
|
|
177
|
+
const cc = cfg.webAdmin;
|
|
178
178
|
return new FleetLeaseManager({ ...opts, center: { baseUrl: cc.baseUrl, credential: cc.credential, worker: cc.worker }, failMode: cfg.fleetLeaseFailClosed ? "closed" : "open" });
|
|
179
179
|
}
|
|
180
180
|
//# sourceMappingURL=fleet-lease.js.map
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*
|
|
19
19
|
* ## 时刻
|
|
20
20
|
* env 在**构造时**取一次快照(boot / run-local 起腿时),而不是 core 默认那样每次 spawn 现取:`NodeLspManagerOptions.env`
|
|
21
|
-
* 是一份静态记录。本仓的 `process.env` 是 boot 期输入(
|
|
21
|
+
* 是一份静态记录。本仓的 `process.env` 是 boot 期输入(热配置走 web-admin,不改 `process.env`),两者在本仓部署上同值。
|
|
22
22
|
*
|
|
23
23
|
* ## 点名放行(S-699,`LSP_ENV_ALLOW`)
|
|
24
24
|
* 剥除会连语言服务器自己的真实依赖一起剥掉(`.npmrc` 的 `${NPM_TOKEN}` 插值、rust-analyzer `cargo metadata` 私有 registry 的
|
package/dist/hosted-posture.d.ts
CHANGED
|
@@ -30,11 +30,11 @@
|
|
|
30
30
|
* (`PRINCIPAL_JWT_PUBKEYS/ISS/AUD` 任一在场;`AUTH_BRIDGE_ISSUER` 显式在场),[ref] ① 裁 (a) 撤回:
|
|
31
31
|
* · **真假阳**:本机自起引擎、配了 principal-JWT / auth-bridge 签发方的单用户部署(web-admin 8090 真案)
|
|
32
32
|
* 在 7.98.0 被判托管而拒启,只能滚回 7.93.5;
|
|
33
|
-
* · **与回退 issuer 不同判**:auth-bridge 的 `??
|
|
33
|
+
* · **与回退 issuer 不同判**:auth-bridge 的 `?? webAdmin.baseUrl` 回退(`boot/stage-09-leader.ts`)
|
|
34
34
|
* 从来不算证据,而回退桥的引擎同样把单用户授予开给每一个验签通过的 registry JWT 调用者 —— 同一个
|
|
35
35
|
* 租户轴事实,「显式写了 issuer」与「从 center 推出 issuer」是同一形。裁定后两者同判。
|
|
36
36
|
* ⇒ 签发方配置是**身份验签轴**(谁的 JWT 算数),不是租户轴(这台机器有几个主人)。「受控于控制面」
|
|
37
|
-
* (`
|
|
37
|
+
* (`SEMA_WEB_ADMIN_*`,含 worker 名)同理是 fleet 管理轴,本判据同样不读。
|
|
38
38
|
*
|
|
39
39
|
* 随两臂一起删掉的(按类删干净,规则集变小):S-564 腿①「托管 ∧ 未开 `REQUIRE_PRINCIPAL` ⇒ 拒启」
|
|
40
40
|
* (判据只剩读 `requirePrincipal` 的那一臂之后,那条合取恒假 ⇒ 结构上不可达)及其跨键不变量行;
|
|
@@ -44,9 +44,9 @@
|
|
|
44
44
|
*
|
|
45
45
|
* 假阳 = 一台单用户部署被收走一个它一直在用的能力(7.98.0 时还会被拒启)。词表不收任何推断臂:
|
|
46
46
|
* · ❌ `PRINCIPAL_JWT_*` / `AUTH_BRIDGE_ISSUER` 在场 —— 见上一段([ref] ① 撤回;加回来 = 翻案,要新裁定)。
|
|
47
|
-
* · ❌ `
|
|
47
|
+
* · ❌ `webAdmin`(含 `worker` 名)/ auth-bridge 的 center 回退 —— fleet 管理轴。初版(车LT)收过
|
|
48
48
|
* `managed-worker` 臂,实测两个反例后撤回:`run-local.ts` 强设 `REQUIRE_PRINCIPAL=false` 的本机 CLI 在一个
|
|
49
|
-
* 带 registry 键的共享 `.env` 上拒启;本仓自己的 `test/config-coverage-blocks.test.ts`
|
|
49
|
+
* 带 registry 键的共享 `.env` 上拒启;本仓自己的 `test/config-coverage-blocks.test.ts` webAdmin 两格当场红。
|
|
50
50
|
* · ❌ `operatorPrincipals` 非空 —— **真假阳**:`IMAGE_BAKES_ENABLED` 那条既有不变量
|
|
51
51
|
* (`config-invariants.ts` 的 `bake-operator-principals`)**强制**开烤门的部署把它填非空。
|
|
52
52
|
* · ❌ `SERVICE_AUTH_TOKENS` 条目数 —— 一台机器上同时给 cli 与 web-admin 发一只令牌是单用户常态。
|
package/dist/http/admission.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { APPROVAL_REACH, MCP_IMAGE_MAX_BASE64, isApprovalReach, isPermissionMode, isThinkingLevel, expandTiers } from "@sema-agent/core";
|
|
2
|
-
import {
|
|
2
|
+
import { isAtMentionable, matchCatalogModel, refusedCatalogEntry, selectableCatalog } from "../model-select.js";
|
|
3
3
|
import { modelUnavailableMessage } from "../model-entry-refusal.js";
|
|
4
4
|
import { HttpError } from "../security.js";
|
|
5
5
|
import { MAX_SETTINGS_OUTPUT_STYLE_CHARS, MAX_SETTINGS_ENV_VARS, MAX_SETTINGS_ENV_KEY_CHARS, MAX_SETTINGS_ENV_VALUE_CHARS, PERMISSION_MODE_WORDS, parseTaskSettings, settingsPermissionBucketIssue, skillListingBudgetFractionOk, skillListingMaxDescOk, stampEntryPermissionMode, taskHooksHonored, taskSettingsKeyIssue } from "../task-settings.js";
|
|
@@ -15,6 +15,7 @@ import { verifyRoundsFromBody } from "./verify-rounds.js";
|
|
|
15
15
|
import { skillCarriesRetiredManifest } from "./retired-skill-manifest.js";
|
|
16
16
|
import { resolveDevicePlacementIntent } from "./device-placement.js";
|
|
17
17
|
import { sendError, httpErrorCode } from "./send.js";
|
|
18
|
+
import { WEB_ADMIN_ENV } from "@sema-agent/settings-schema";
|
|
18
19
|
const APPROVAL_REACH_WORDS = APPROVAL_REACH.map((word) => JSON.stringify(word)).join(" / ");
|
|
19
20
|
export const MAX_SKILL_CONTENT_CHARS = 1_048_576;
|
|
20
21
|
export const MAX_SYSTEM_PROMPT_CHARS = 16_384;
|
|
@@ -51,8 +52,7 @@ export const SKILL_MANIFEST_RETIRED = "skill.manifest was retired in core 7.41.0
|
|
|
51
52
|
const MAX_IMAGES_PER_REQUEST = 20;
|
|
52
53
|
const MAX_IMAGE_BASE64_BYTES = MCP_IMAGE_MAX_BASE64;
|
|
53
54
|
function mentionableNames(config, catalog) {
|
|
54
|
-
|
|
55
|
-
return Object.keys(catalog).filter((n) => n !== "default" && isModelAllowlisted(n, catalog, allowlist, config.modelRefusals));
|
|
55
|
+
return Object.keys(catalog).filter((n) => n !== "default" && isAtMentionable(n, catalog, config.atMention, config.modelRefusals));
|
|
56
56
|
}
|
|
57
57
|
function refuseUnavailableModel(res, config, field, ref) {
|
|
58
58
|
const hit = refusedCatalogEntry(ref, config.modelRefusals);
|
|
@@ -377,7 +377,7 @@ export function createAdmission(ctx) {
|
|
|
377
377
|
const wantsSelfOrchestration = body.selfOrchestration === true
|
|
378
378
|
|| parseTaskSettings(body.settings).settings?.ultracode === true;
|
|
379
379
|
if (!admission.available && wantsSelfOrchestration) {
|
|
380
|
-
sendError(res, 501, "capability.self_orchestration_required",
|
|
380
|
+
sendError(res, 501, "capability.self_orchestration_required", `self-orchestration is enabled on this worker (SELF_ORCHESTRATION_ENABLED) but it is multi-tenant (REQUIRE_PRINCIPAL) and wires NO per-principal entitlement source, so the engine's allowWorkflows gate — which is tighten-only, meaning an absent resolver leaves it UNGATED — is fail-closed for every principal: no request can ever get the workflow engine here (GET /v1/capabilities reports workflows:false with workflowsGate.denial "entitlement_resolver_absent"). Wire a web-admin (${WEB_ADMIN_ENV.url} + token, not dry-run) to gate it per principal, or set SELF_ORCHESTRATION_ENABLED=false — the honest posture for a worker that cannot grant it. To submit this task without the workflow engine, drop selfOrchestration / settings.ultracode; ultracode's other half (the max thinking tier) is available as reasoningEffort: "max"`);
|
|
381
381
|
return null;
|
|
382
382
|
}
|
|
383
383
|
}
|