@sema-agent/server 7.123.0 → 7.124.1
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 +138 -0
- package/README.md +2 -2
- package/README.zh-CN.md +2 -2
- package/USAGE.md +53 -51
- 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.js +1 -1
- 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 +1 -1
- 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} +38 -22
- 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 +15 -15
- 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 +26 -6
- package/dist/config-lkg.js +43 -14
- package/dist/config-provider.d.ts +23 -19
- package/dist/config-provider.js +24 -26
- package/dist/config-types.d.ts +52 -51
- package/dist/config.d.ts +9 -46
- package/dist/config.js +33 -92
- 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 +8 -8
- 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 +7 -7
- package/dist/fleet-client.js +5 -4
- 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 +2 -2
- package/dist/http/durable-run-leg.js +2 -1
- package/dist/http/health-self-report.d.ts +4 -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 +5 -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 +1 -1
- 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.js +3 -2
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/key-resolver.d.ts +1 -1
- package/dist/leader/wire.d.ts +2 -2
- 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 +3 -3
- package/dist/model-entry-refusal.js +4 -4
- package/dist/model-provider.d.ts +2 -2
- package/dist/model-route-endpoint.d.ts +1 -1
- 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/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 +26 -2
- package/dist/plugins/scheduler-support.d.ts +26 -7
- package/dist/plugins/scheduler-support.js +96 -53
- 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/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/run-local.js +6 -3
- package/dist/runtime-caps-resolver.d.ts +4 -4
- package/dist/runtime-caps-resolver.js +2 -2
- package/dist/runtime-governance.d.ts +5 -5
- 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-titler.d.ts +0 -11
- package/dist/session-titler.js +3 -5
- package/dist/shared-memory-scope-authorizer.d.ts +4 -4
- package/dist/task-a2a.d.ts +1 -1
- 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 +17 -15
- package/dist/trace/self-minted-wire.d.ts +134 -3
- package/dist/trace/self-minted-wire.js +46 -9
- 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 +100 -119
- 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 +12 -12
- 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/{config-center → web-admin-client}/read-warnings.d.ts +23 -16
- package/dist/{config-center → web-admin-client}/read-warnings.js +33 -23
- 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 +12 -39
- package/package.json +2 -2
- package/skills/find-skills.md +2 -2
- 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
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
|
}
|
|
@@ -77,6 +77,7 @@ export declare function buildCheckpointCtx(fields: {
|
|
|
77
77
|
body: TaskRequestBody;
|
|
78
78
|
memoryScope?: string | undefined;
|
|
79
79
|
unattendedLeg?: true;
|
|
80
|
+
writerVersion: string;
|
|
80
81
|
}): CheckpointCtx;
|
|
81
82
|
/**
|
|
82
83
|
* 模式词的**第二个写者** —— `plan_review` 的批准 / 编辑把这条 run 的体词从 `plan` 写成批准的档(`resume-legs.ts` `drivePlanReview`,调用点只有那一处;
|
|
@@ -130,10 +131,14 @@ export declare function allowListReadingRefusal(era: AllowListReadingEra): {
|
|
|
130
131
|
retriable: true;
|
|
131
132
|
};
|
|
132
133
|
};
|
|
133
|
-
/**
|
|
134
|
+
/**
|
|
135
|
+
* 一条停驻行的持久化体在本版上**不能**重放时,是哪一条规则拒的(闭集;加一条 ⇒ {@link storedBodyReplayAnswer} 的 switch 编译红)。
|
|
136
|
+
* 答 `checkpoint.unsupported_version` 的两臂随带这一行的写者版本(续跑上下文的 `writerVersion`,缺席 = 本版之前写下的行)—— 那一码的两版本键由它铸({@link buildCheckpointVersionKeys})。
|
|
137
|
+
*/
|
|
134
138
|
export type StoredBodyReplayRefusal = {
|
|
135
139
|
readonly kind: "allow_list_reading";
|
|
136
140
|
readonly era: AllowListReadingEra;
|
|
141
|
+
readonly writerVersion?: string;
|
|
137
142
|
} | {
|
|
138
143
|
readonly kind: "skill_deny_inert";
|
|
139
144
|
readonly entry: SkillDenyInertEntry;
|
|
@@ -141,7 +146,18 @@ export type StoredBodyReplayRefusal = {
|
|
|
141
146
|
readonly kind: "permission_mode_reading";
|
|
142
147
|
readonly stored: PermissionMode | undefined;
|
|
143
148
|
readonly floor: PermissionMode;
|
|
149
|
+
readonly writerVersion?: string;
|
|
144
150
|
};
|
|
151
|
+
/**
|
|
152
|
+
* 🔴 **`checkpoint.unsupported_version` 的 409 体上两个版本键 —— 唯一铸法;本码每一个铸点同一条律**(core 原码镜像 = `resume-legs.ts` 的 catch 臂;本服务自铸的两只拒
|
|
153
|
+
* = {@link storedBodyReplayAnswer} 的 allow 读法 / 模式词读法两臂):续跑上下文带写者版本 ⇒ `{ writerVersion, readerVersion }`;不带(本版之前写下的行)⇒ `{}`,不编值。
|
|
154
|
+
* 两值相等也照带 —— 那是事实(不是版本问题,出路照码与报文);写者比读者新才是「回到写它的那一版去决」。`readerVersion` 由调用方传本进程的服务版本
|
|
155
|
+
* (本模块零值依赖,不自取)。纯数据。
|
|
156
|
+
*/
|
|
157
|
+
export declare function buildCheckpointVersionKeys(writerVersion: string | undefined, readerVersion: string): {
|
|
158
|
+
writerVersion: string;
|
|
159
|
+
readerVersion: string;
|
|
160
|
+
} | Record<string, never>;
|
|
145
161
|
/** 续跑家族交回的拒答复形(`{ status, body }`,由 `sendResumeOutcome` / 各路由发送;`body` 至少 `error` + `errorCode`)。 */
|
|
146
162
|
export interface ResumeRefusalAnswer {
|
|
147
163
|
readonly status: number;
|
|
@@ -169,8 +185,9 @@ export declare function storedBodyReplayLogFields(refusal: StoredBodyReplayRefus
|
|
|
169
185
|
note: string;
|
|
170
186
|
};
|
|
171
187
|
/**
|
|
172
|
-
* `stored-body-replay.ts` `storedBodyReplayRefusal` 的答复:每条规则一只既有铸点(allow 记号 ⇒ {@link allowListReadingRefusal}
|
|
188
|
+
* `stored-body-replay.ts` `storedBodyReplayRefusal` 的答复:每条规则一只既有铸点(allow 记号 ⇒ {@link allowListReadingRefusal};模式词记号 ⇒ {@link permissionModeReadingRefusal};
|
|
189
|
+
* 这两只答 `checkpoint.unsupported_version`,体按那一码的键律补两版本键,`readerVersion` = 调用方传的本进程服务版本;技能拒侧 ⇒ {@link resumeBlockedByPolicyAnswer},与提交腿的 400
|
|
173
190
|
* `request.field_invalid` 同码同句 —— 体上只有这一个问题时;存量体同时还踩中 `resolveSpec` 更早的拒〔三桶超帽 / 托管姿态〕时,提交侧答更早那条、续跑侧答本句,两边都是拒,指路不同)。
|
|
174
191
|
*/
|
|
175
|
-
export declare function storedBodyReplayAnswer(refusal: StoredBodyReplayRefusal): ResumeRefusalAnswer;
|
|
192
|
+
export declare function storedBodyReplayAnswer(refusal: StoredBodyReplayRefusal, readerVersion: string): ResumeRefusalAnswer;
|
|
176
193
|
//# sourceMappingURL=checkpoint-ctx.d.ts.map
|
|
@@ -14,6 +14,7 @@ export function bodyCarriesAllowList(body) {
|
|
|
14
14
|
export function buildCheckpointCtx(fields) {
|
|
15
15
|
return {
|
|
16
16
|
body: fields.body,
|
|
17
|
+
writerVersion: fields.writerVersion,
|
|
17
18
|
...(fields.memoryScope !== undefined ? { memoryScope: fields.memoryScope } : {}),
|
|
18
19
|
...(fields.unattendedLeg === true ? { unattendedLeg: true } : {}),
|
|
19
20
|
...(bodyCarriesAllowList(fields.body) ? { permissionsAllowReading: "allow_layer" } : {}),
|
|
@@ -73,6 +74,9 @@ export function allowListReadingRefusal(era) {
|
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
}
|
|
77
|
+
export function buildCheckpointVersionKeys(writerVersion, readerVersion) {
|
|
78
|
+
return writerVersion !== undefined ? { writerVersion, readerVersion } : {};
|
|
79
|
+
}
|
|
76
80
|
export function resumeBlockedByPolicyAnswer(message, blockedBy, extra) {
|
|
77
81
|
return {
|
|
78
82
|
status: 409,
|
|
@@ -93,14 +97,18 @@ export function storedBodyReplayLogFields(refusal) {
|
|
|
93
97
|
}
|
|
94
98
|
}
|
|
95
99
|
}
|
|
96
|
-
export function storedBodyReplayAnswer(refusal) {
|
|
100
|
+
export function storedBodyReplayAnswer(refusal, readerVersion) {
|
|
97
101
|
switch (refusal.kind) {
|
|
98
|
-
case "allow_list_reading":
|
|
99
|
-
|
|
102
|
+
case "allow_list_reading": {
|
|
103
|
+
const answer = allowListReadingRefusal(refusal.era);
|
|
104
|
+
return { status: answer.status, body: { ...answer.body, ...buildCheckpointVersionKeys(refusal.writerVersion, readerVersion) } };
|
|
105
|
+
}
|
|
100
106
|
case "skill_deny_inert":
|
|
101
107
|
return resumeBlockedByPolicyAnswer(refusal.entry.message, "request.field_invalid");
|
|
102
|
-
case "permission_mode_reading":
|
|
103
|
-
|
|
108
|
+
case "permission_mode_reading": {
|
|
109
|
+
const answer = permissionModeReadingRefusal();
|
|
110
|
+
return { status: answer.status, body: { ...answer.body, ...buildCheckpointVersionKeys(refusal.writerVersion, readerVersion) } };
|
|
111
|
+
}
|
|
104
112
|
default: {
|
|
105
113
|
const unhandled = refusal;
|
|
106
114
|
throw new Error(`stored-body replay refusal ${JSON.stringify(unhandled)} has no answer`);
|
package/dist/http/dispatch.js
CHANGED
|
@@ -208,11 +208,11 @@ export function createDispatch(ctx) {
|
|
|
208
208
|
res.end(deps.metrics.render());
|
|
209
209
|
return;
|
|
210
210
|
}
|
|
211
|
-
if (deps.
|
|
211
|
+
if (deps.webAdminJwtVerifier) {
|
|
212
212
|
const authz = req.headers.authorization ?? "";
|
|
213
213
|
const rawBearer = /^Bearer\s/i.test(authz) ? authz.replace(/^Bearer\s+/i, "") : "";
|
|
214
214
|
if (rawBearer && looksLikeJwt(rawBearer)) {
|
|
215
|
-
const v = await deps.
|
|
215
|
+
const v = await deps.webAdminJwtVerifier.verify(rawBearer);
|
|
216
216
|
if (v.ok) {
|
|
217
217
|
setSsoPrincipal(req, v.identity.principal);
|
|
218
218
|
req.headers[deps.config.principalHeader.toLowerCase()] = v.identity.principal;
|
|
@@ -9,6 +9,7 @@ import { commitSessionInheritEnv } from "./session-inherit-env.js";
|
|
|
9
9
|
import { clearTurnActivity, readTurnActivityMs } from "../turn-activity.js";
|
|
10
10
|
import { recordResourceWindow } from "../resource-window.js";
|
|
11
11
|
import { buildCheckpointCtx } from "./checkpoint-ctx.js";
|
|
12
|
+
import { serviceVersion } from "../service-version.js";
|
|
12
13
|
export async function mintAndDriveDurableRun(ctx, runStore, args) {
|
|
13
14
|
const { deps } = ctx;
|
|
14
15
|
const { inflightRuns, preemptableRuns, steerableRuns } = ctx.registry;
|
|
@@ -32,7 +33,7 @@ export async function mintAndDriveDurableRun(ctx, runStore, args) {
|
|
|
32
33
|
return { status: placementReject.status, body: devicePlacementErrorBody(placementReject) };
|
|
33
34
|
commitSessionInheritEnv(deps, args.prepared.spec.sessionId, args.prepared.body);
|
|
34
35
|
if (deps.checkpointStore) {
|
|
35
|
-
await deps.checkpointStore.putCtx(sessionId, buildCheckpointCtx({ body: args.prepared.body, memoryScope: args.prepared.auth?.memoryScope }));
|
|
36
|
+
await deps.checkpointStore.putCtx(sessionId, buildCheckpointCtx({ body: args.prepared.body, memoryScope: args.prepared.auth?.memoryScope, writerVersion: serviceVersion() }));
|
|
36
37
|
}
|
|
37
38
|
const anchorOwner = args.prepared.auth?.principal ?? null;
|
|
38
39
|
const getLeafId = deps.sessionStorage?.getLeafId?.bind(deps.sessionStorage);
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
* · `auth.required` = 全局凭据门的武装谓词(`hasServiceAuth`,由 `dispatch.ts` 交进来 —— 门与本位读同一次求值的同一只函数);
|
|
8
8
|
* · `auth.kinds` = {@link IDENTITY_SOURCES}(`verifiedIdentitySource` 的回值闭集)里,这台部署的装配**能**回的那几个词:
|
|
9
9
|
* `service_token` ⇐ 全局门武装(`systemFor` 只在配了 service token 时回得出值)· `sso` ⇐ 鉴权桥装了(入口预认证只在
|
|
10
|
-
* `
|
|
10
|
+
* `webAdminJwtVerifier` 在场时挂身份)· `direct_door_jwt` ⇐ 直连门开着(`verifiedIdentitySource` 那一臂的第一个合取项);
|
|
11
11
|
* · `auth.identityAttach` = kinds 里有没有**带调用方身份**的一类({@link carriesCallerIdentity},穷举):`service_token` 认的是系统
|
|
12
12
|
* (`systemFor` 回系统名或 null),不是人;
|
|
13
13
|
* · `operator` = 能力事实 `operatorLane`(operator 面族的 501 门读的同一只;名单本身不上 wire);
|
|
14
14
|
* · `center.issuer` = 鉴权桥 issuer 的唯一取值 `authBridgeIssuerOf`(装配 `boot/stage-09-leader.ts` 与 caps `centerWiring.issuer` 同读);
|
|
15
|
-
* · `center.webBaseUrl` = 运维旋钮 `
|
|
15
|
+
* · `center.webBaseUrl` = 运维旋钮 `SEMA_WEB_ADMIN_WEB_URL`(`config.webAdmin.webBaseUrl`,接了中心才挂;起服时已判成固定基址);
|
|
16
16
|
* · `center.sessionsVisible` = 中心的 web 面能不能列出本引擎的会话 —— 四件接线事实全在才可能:中心车道配齐(`centerLaneConfigured`,
|
|
17
17
|
* 租约 / 用量 / 公告同一只谓词)∧ 公告地址在(配置席 `fleetAdvertiseAddress`:web 面只拨中心登记过的实例地址)∧ 鉴权桥在(web 面带的是
|
|
18
18
|
* 中心铸的中继令牌,不带 service token)∧ 会话枚举面在(事实 `sessionList`,web 面中继 `GET /v1/sessions`);缺任一 ⇒ `false`。
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* ## 无鉴权面
|
|
23
23
|
* `/health` 排在凭据门之前、缺省全网卡监听:本模块只出闭集词、布尔与运维要发布的 URL。两只 URL 值都过 display-safe 律
|
|
24
24
|
* (`buildDisplaySafeUrl`,所有展示面 URL 的同一个铸点):userinfo 落地、query 值成记号、尾斜杠折掉 —— issuer 的来源
|
|
25
|
-
* (`AUTH_BRIDGE_ISSUER` / `
|
|
25
|
+
* (`AUTH_BRIDGE_ISSUER` / `SEMA_WEB_ADMIN_URL`)起服时不判凭据形,这一道是它上无鉴权面的唯一闸。令牌、名单、worker 名、凭证一概不上。
|
|
26
26
|
* 同一张面上本模块之外还有一个**调用方自取**的串(如实,7.123.0 起;`model` / `dataRoot` / `version` 等其余非闭集的名是部署自己的事实,不是调用方放进来的):排空中的动作号 `engineSignal.draining.actionId`(`fleet/engine-signal.ts` 铸,契约 §0.4)——
|
|
27
27
|
* 引擎自起的排空是引擎的闭集词,经排空口(operator-only)进的排空是调用方自取的幂等键**原样**(契约包今天只要求非空串,推荐 `manual:<uuid>`),
|
|
28
28
|
* 所以那一键不是闭集词:调用方不要往里放秘密或人名。
|
|
@@ -59,5 +59,5 @@ export interface HealthSelfReport {
|
|
|
59
59
|
* 三键的**唯一铸点**(`build*`:纯数据)。`credentialGateArmed` 由 `dispatch.ts` 交进来 —— 它是全局凭据门自己的那一句
|
|
60
60
|
* (`hasServiceAuth`),本模块不另求一遍(另求就是第二个写者)。
|
|
61
61
|
*/
|
|
62
|
-
export declare function buildHealthSelfReport(deps: Pick<FlatServiceDeps, "config" | "
|
|
62
|
+
export declare function buildHealthSelfReport(deps: Pick<FlatServiceDeps, "config" | "webAdminJwtVerifier" | "sessionStorage" | "runStore">, credentialGateArmed: boolean): HealthSelfReport;
|
|
63
63
|
//# sourceMappingURL=health-self-report.d.ts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { IDENTITY_SOURCES } from "./principal-gate.js";
|
|
2
2
|
import { operatorLane, sessionList } from "../capability-facts.js";
|
|
3
3
|
import { authBridgeIssuerOf } from "../auth-bridge.js";
|
|
4
|
-
import { centerLaneConfigured } from "../
|
|
4
|
+
import { centerLaneConfigured } from "../web-admin-client/center-request.js";
|
|
5
5
|
import { buildDisplaySafeUrl } from "../trace/redact.js";
|
|
6
6
|
export const IDENTITY_ATTACH_WORDS = ["available", "unavailable"];
|
|
7
7
|
export const OPERATOR_PRESENCE_WORDS = ["present", "absent"];
|
|
@@ -35,10 +35,10 @@ function identitySourceWired(kind, a) {
|
|
|
35
35
|
}
|
|
36
36
|
export function buildHealthSelfReport(deps, credentialGateArmed) {
|
|
37
37
|
const { config } = deps;
|
|
38
|
-
const bridgeWired = deps.
|
|
38
|
+
const bridgeWired = deps.webAdminJwtVerifier !== undefined;
|
|
39
39
|
const kinds = IDENTITY_SOURCES.filter((k) => identitySourceWired(k, { credentialGateArmed, bridgeWired, directDoorActive: config.directDoorActive }));
|
|
40
40
|
const issuer = authBridgeIssuerOf(config)?.issuer;
|
|
41
|
-
const webBaseUrl = config.
|
|
41
|
+
const webBaseUrl = config.webAdmin?.webBaseUrl;
|
|
42
42
|
const sessionsVisible = centerLaneConfigured(config) && config.fleetAdvertiseAddress !== undefined && bridgeWired && sessionList(deps).available ? (config.requirePrincipal ? true : "unknown") : false;
|
|
43
43
|
return {
|
|
44
44
|
auth: { required: credentialGateArmed, kinds, identityAttach: kinds.some(carriesCallerIdentity) ? "available" : "unavailable" },
|
|
@@ -14,7 +14,7 @@ import type { WiringManifestReceipt } from "./wire-types.js";
|
|
|
14
14
|
* map grows past a threshold (no O(n) scan on the hot path). Single-threaded event-loop semantics: each HTTP
|
|
15
15
|
* request is its own task, so there is no get→set race within a tick.
|
|
16
16
|
*
|
|
17
|
-
* (Caller context: the
|
|
17
|
+
* (Caller context: the web-admin review gateway mints/echoes the Idempotency-Key and routes a given key to
|
|
18
18
|
* the same worker, so this PER-POD cache is the worker-side backstop against a retried submission re-running —
|
|
19
19
|
* and re-billing. Cross-pod / cross-restart exactly-once needs store-backing; the durable async /v1/runs path
|
|
20
20
|
* is the alternative for long tasks.)
|
|
@@ -23,10 +23,11 @@ import type { RunRegistry, RouteHelpers, RouteLegs } from "./route-ctx.js";
|
|
|
23
23
|
import type { createRequestGuards } from "./request-guards.js";
|
|
24
24
|
import type { FlatServiceDeps } from "./server.js";
|
|
25
25
|
/**
|
|
26
|
-
* {@link CHECKPOINT_ERROR_DISPOSITION}
|
|
27
|
-
*
|
|
26
|
+
* 🔴 **一次 `CheckpointError` 拒的处置 —— 唯一读口**:{@link CHECKPOINT_ERROR_DISPOSITION} 的读法(doctrine 在那张表头)。resume 腿的 catch 臂只调它一次,
|
|
27
|
+
* 行的落点与 wire 的 `retriable` 都读这一个结果。纯函数,钉直接调。运行期遇到表外的码(装树 core 比本二进制多一个码的版本偏斜 —— 型面上拼不出来)
|
|
28
|
+
* ⇒ `"terminal"`:与 `by_reason` 认不得的词同一条 fail-closed 方向(不宽容默认成可重试),也与修前手列串的缺省逐字相同。
|
|
28
29
|
*/
|
|
29
|
-
export declare function
|
|
30
|
+
export declare function resumeRefusalDisposition(e: CheckpointError): "cancelled" | "retriable" | "terminal";
|
|
30
31
|
export declare function createResumeLegs(ctx: {
|
|
31
32
|
deps: FlatServiceDeps;
|
|
32
33
|
runnerFor: FlatServiceDeps["runnerFor"];
|
package/dist/http/resume-legs.js
CHANGED
|
@@ -17,12 +17,15 @@ import { fleetRunPublisher, fleetRunLabels, fleetRunResiduals, isFleetAgentTermi
|
|
|
17
17
|
import { defaultSubagentTailBus } from "../fleet/subagent-tail-bus.js";
|
|
18
18
|
import { APPROVAL_GATE_KINDS, createApprovalCardEmitter, isApprovalGateKind, parkRowStandingAnswerFacts, resolveApprovalLeg, resolveStreamApprovalGate, standingAnswerDurablyRecordable } from "../tool-approval.js";
|
|
19
19
|
import { buildCheckpointAnchorHash } from "../approval-ask-audit-store.js";
|
|
20
|
+
import { APPROVAL_ENDING_CAUSES } from "../approval-deny-reasons.js";
|
|
21
|
+
import { serviceVersion } from "../service-version.js";
|
|
20
22
|
import { TERMINAL_PARK_GATE_KINDS } from "../plugins/checkpoint-store-sql.js";
|
|
21
23
|
import { withPrincipal } from "../observability/principal-context.js";
|
|
22
24
|
import { withModelReachScope } from "../model-reach-scope.js";
|
|
23
25
|
import { createInstructionSelectionLeg } from "../instruction-selection.js";
|
|
24
26
|
import { modelTextEventData, turnEndEventData, contextUsageEventData, toolStartEventData, toolEndEventData, taskProgressEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, workspaceChangedEventData, wiringManifestEventData, toolRosterDeltaEventData, toolDisclosureEventData, humanInputEventData, appendModelUsageDelta, appendPromptManifest, attachModelUsage } from "../trace/project.js";
|
|
25
27
|
import { redactSecrets } from "../trace/redact.js";
|
|
28
|
+
import { buildRunObjectivePreview } from "../user-authored-text.js";
|
|
26
29
|
import { createLedgerSink, createSerialLedgerAppend } from "../trace/ledger-sink.js";
|
|
27
30
|
import { registerEngineNoticeLeg } from "../trace/engine-notice-wire.js";
|
|
28
31
|
import { reasoningDeltaBytes, reasoningSegmentEventId } from "../trace/model-segment.js";
|
|
@@ -43,7 +46,7 @@ import { commitSessionInheritEnv } from "./session-inherit-env.js";
|
|
|
43
46
|
import { ASK_USER_QUESTION_TOOL_NAME } from "../approval-content-kind.js";
|
|
44
47
|
import { deploymentListAsks } from "../approval.js";
|
|
45
48
|
import { readResumeCtx, resumeCtxCorruptAnswer } from "./resume-ctx-read.js";
|
|
46
|
-
import { resumeBlockedByPolicyAnswer, storedBodyReplayAnswer, storedBodyReplayLogFields, withPermissionModeRewritten } from "./checkpoint-ctx.js";
|
|
49
|
+
import { buildCheckpointVersionKeys, resumeBlockedByPolicyAnswer, storedBodyReplayAnswer, storedBodyReplayLogFields, withPermissionModeRewritten } from "./checkpoint-ctx.js";
|
|
47
50
|
import { storedBodyReplayRefusal } from "./stored-body-replay.js";
|
|
48
51
|
import { httpErrorCode } from "./send.js";
|
|
49
52
|
function isCheckpointReopenedFailure(r) {
|
|
@@ -108,7 +111,7 @@ const CHECKPOINT_ERROR_DISPOSITION = {
|
|
|
108
111
|
"steering.invalid_content": "terminal",
|
|
109
112
|
"steering.queue_full": "terminal",
|
|
110
113
|
};
|
|
111
|
-
export function
|
|
114
|
+
export function resumeRefusalDisposition(e) {
|
|
112
115
|
const word = Object.hasOwn(CHECKPOINT_ERROR_DISPOSITION, e.code) ? CHECKPOINT_ERROR_DISPOSITION[e.code] : undefined;
|
|
113
116
|
switch (word) {
|
|
114
117
|
case "cancelled":
|
|
@@ -135,14 +138,26 @@ const CHECKPOINT_ERROR_FIELD_ROLE = {
|
|
|
135
138
|
taskConfig: "config",
|
|
136
139
|
inheritedGate: "config",
|
|
137
140
|
};
|
|
138
|
-
const
|
|
139
|
-
binding:
|
|
140
|
-
answer:
|
|
141
|
-
outcome_cell:
|
|
142
|
-
regrant:
|
|
143
|
-
config:
|
|
141
|
+
const FIELD_ROLE_CAUSE = {
|
|
142
|
+
binding: APPROVAL_ENDING_CAUSES.BINDING_CHANGED,
|
|
143
|
+
answer: APPROVAL_ENDING_CAUSES.ANSWER_INVALID,
|
|
144
|
+
outcome_cell: APPROVAL_ENDING_CAUSES.OUTCOME_CELL_INVALID,
|
|
145
|
+
regrant: APPROVAL_ENDING_CAUSES.OUTCOME_CELL_INVALID,
|
|
146
|
+
config: undefined,
|
|
144
147
|
};
|
|
145
|
-
const
|
|
148
|
+
const WIRE_CODE_OF_DECISION_REFUSAL = {
|
|
149
|
+
[APPROVAL_ENDING_CAUSES.BINDING_CHANGED]: "approval_binding_mismatch",
|
|
150
|
+
[APPROVAL_ENDING_CAUSES.ANSWER_INVALID]: "resume_outcome_invalid",
|
|
151
|
+
[APPROVAL_ENDING_CAUSES.OUTCOME_CELL_INVALID]: "resume_outcome_invalid",
|
|
152
|
+
};
|
|
153
|
+
const UNCLASSIFIED_INVALID_OUTCOME_CODE = WIRE_CODE_OF_DECISION_REFUSAL[APPROVAL_ENDING_CAUSES.BINDING_CHANGED];
|
|
154
|
+
function decisionRefusalCauseOf(e, gate) {
|
|
155
|
+
if (gate !== "policy_ask")
|
|
156
|
+
return APPROVAL_ENDING_CAUSES.OUTCOME_CELL_INVALID;
|
|
157
|
+
const field = e.detail?.field;
|
|
158
|
+
const role = field !== undefined && Object.hasOwn(CHECKPOINT_ERROR_FIELD_ROLE, field) ? CHECKPOINT_ERROR_FIELD_ROLE[field] : undefined;
|
|
159
|
+
return role === undefined ? undefined : FIELD_ROLE_CAUSE[role];
|
|
160
|
+
}
|
|
146
161
|
function notResumableAnswer() {
|
|
147
162
|
return { status: 409, body: { error: "run is not in a resumable (suspended) state (already resumed, decided, or expired)", errorCode: "conflict.not_resumable" } };
|
|
148
163
|
}
|
|
@@ -420,7 +435,7 @@ export function createResumeLegs(ctx) {
|
|
|
420
435
|
};
|
|
421
436
|
const refuseStoredBodyReplay = (sessionId, refusal) => {
|
|
422
437
|
deps.logger?.warn?.("resume_refused_stored_body", { sessionId, ...storedBodyReplayLogFields(refusal) });
|
|
423
|
-
return storedBodyReplayAnswer(refusal);
|
|
438
|
+
return storedBodyReplayAnswer(refusal, serviceVersion());
|
|
424
439
|
};
|
|
425
440
|
const resolveResumeSpecOrBlocked = async (ctx, req, auth) => {
|
|
426
441
|
const replay = storedBodyReplayRefusal(ctx, deps.config.autonomy);
|
|
@@ -460,7 +475,7 @@ export function createResumeLegs(ctx) {
|
|
|
460
475
|
async function driveResumeLeg(args, onAccepted) {
|
|
461
476
|
const resumeLegStartedAt = Date.now();
|
|
462
477
|
const { runner: legRunner, token, sessionId, principal, fleetScope, taskConfig, resumeObjective, outcome, verifyRounds, resumeCtx } = args;
|
|
463
|
-
const commitResumeCtx = () => deps.checkpointStore.putCtx(resumeCtx.sessionId, resumeCtx.ctx).catch((e) => {
|
|
478
|
+
const commitResumeCtx = () => deps.checkpointStore.putCtx(resumeCtx.sessionId, { ...resumeCtx.ctx, writerVersion: serviceVersion() }).catch((e) => {
|
|
464
479
|
deps.metrics?.inc("resume_ctx_not_persisted_total");
|
|
465
480
|
deps.logger?.warn?.("resume_ctx_not_persisted", { sessionId: resumeCtx.sessionId, gate: outcome.gate, error: errorText(e), note: "this continuation runs with the body it was given; the durable rebuild input still holds the PREVIOUS body, so the NEXT continuation of this session rebuilds from that one (never wider than this leg's)" });
|
|
466
481
|
});
|
|
@@ -494,7 +509,7 @@ export function createResumeLegs(ctx) {
|
|
|
494
509
|
const freshId = uuidv7();
|
|
495
510
|
const created = await deps.runStore.createRun(freshId, sessionId, principal ?? null, deps.instanceId ?? "default", {
|
|
496
511
|
source: args.mintFreshRun.source,
|
|
497
|
-
objectivePreview: resumeObjective
|
|
512
|
+
objectivePreview: buildRunObjectivePreview(resumeObjective ?? ""),
|
|
498
513
|
});
|
|
499
514
|
if (!created.ok) {
|
|
500
515
|
return { status: 409, body: await buildActiveRunConflict({ runStore: deps.runStore, checkpointStore: deps.checkpointStore, governance: deps.config, runStaleSec: deps.config.runStaleSec, turnActivity: readTurnActivityMs }, sessionId, created.activeTaskId) };
|
|
@@ -969,7 +984,8 @@ export function createResumeLegs(ctx) {
|
|
|
969
984
|
}
|
|
970
985
|
catch (e) {
|
|
971
986
|
if (e instanceof CheckpointError) {
|
|
972
|
-
const
|
|
987
|
+
const refusalCause = e.code === "checkpoint.invalid_outcome" ? decisionRefusalCauseOf(e, outcome.gate) : undefined;
|
|
988
|
+
const disposition = resumeRefusalDisposition(e);
|
|
973
989
|
if (disposition === "cancelled") {
|
|
974
990
|
const cs2 = deps.checkpointStore;
|
|
975
991
|
if (cs2) {
|
|
@@ -1020,16 +1036,13 @@ export function createResumeLegs(ctx) {
|
|
|
1020
1036
|
body: {
|
|
1021
1037
|
...(taskId !== undefined ? { taskId } : {}),
|
|
1022
1038
|
error: e.message,
|
|
1023
|
-
errorCode: e.code === "checkpoint.invalid_outcome"
|
|
1024
|
-
? (outcome.gate === "policy_ask" && !NON_BINDING_INVALID_OUTCOME_FIELDS.has(String(e.detail?.field ?? ""))
|
|
1025
|
-
? "approval_binding_mismatch"
|
|
1026
|
-
: "resume_outcome_invalid")
|
|
1027
|
-
: e.code,
|
|
1039
|
+
errorCode: e.code === "checkpoint.invalid_outcome" ? (refusalCause !== undefined ? WIRE_CODE_OF_DECISION_REFUSAL[refusalCause] : UNCLASSIFIED_INVALID_OUTCOME_CODE) : e.code,
|
|
1028
1040
|
...(e.detail?.field ? { field: e.detail.field } : {}),
|
|
1029
1041
|
...((e.code === "resume.usage_window_exhausted" || e.code === "resume.preflight_rejected") && typeof e.detail?.retryAfterMs === "number" && Number.isFinite(e.detail.retryAfterMs) && e.detail.retryAfterMs > 0
|
|
1030
1042
|
? { retryAfterSec: Math.max(1, Math.ceil(e.detail.retryAfterMs / 1000)) }
|
|
1031
1043
|
: {}),
|
|
1032
1044
|
...(retriable ? { retriable: true } : {}),
|
|
1045
|
+
...(e.code === "checkpoint.unsupported_version" ? buildCheckpointVersionKeys(resumeCtx.ctx.writerVersion, serviceVersion()) : {}),
|
|
1033
1046
|
},
|
|
1034
1047
|
};
|
|
1035
1048
|
}
|
package/dist/http/route-ctx.d.ts
CHANGED
|
@@ -176,6 +176,14 @@ export interface CheckpointCtx {
|
|
|
176
176
|
* 不改词的续跑腿写回传原 ctx ⇒ 记号随行。
|
|
177
177
|
*/
|
|
178
178
|
permissionModeReading?: import("./checkpoint-ctx.js").PermissionModeReading;
|
|
179
|
+
/**
|
|
180
|
+
* 🔴 S-1365 —— **写这份上下文的服务版本**(`package.json` 的 `version`),**服务端写、不来自请求体**(与 {@link unattendedLeg} 同为 `body` 的兄弟键)。
|
|
181
|
+
* 写点两个:`buildCheckpointCtx`(每一次新的持久化写)与续跑腿的写回({@link DriveResumeArgs.resumeCtx} 的唯一写点,CAS 赢点盖本进程的版本 —— 接下来写下一张停车行的就是它)。
|
|
182
|
+
* 读者:`checkpoint.unsupported_version` 的 409 体 —— 原样带出 `writerVersion`,与本引擎的 `readerVersion` 并列(运维据此知道该回哪一版去决);
|
|
183
|
+
* 两键唯一铸法 `checkpoint-ctx.ts` `buildCheckpointVersionKeys`,本码每个铸点同调。它是**上下文**,不是拒因:成因与码都不读它。
|
|
184
|
+
* 缺席 = 本版之前写下的行(不回填):那一码的体不带两键,如实不猜。不是一次性迁移 —— 这一格是常设的事实位,没有删除条件。
|
|
185
|
+
*/
|
|
186
|
+
writerVersion?: string;
|
|
179
187
|
}
|
|
180
188
|
/** B4①(命名化):`driveResumeIntoRunLog` 的入参形(resume 家族共用)——原为 9 成员内联匿名对象。 */
|
|
181
189
|
export interface DriveResumeArgs {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* 身份 → 授权 →(本口无 body,无验型步)。
|
|
8
8
|
*
|
|
9
9
|
* 🔴 语义 = **触发一次既有的 refresh 拍**,不是「再实现一遍拉取」:实现面是
|
|
10
|
-
* `
|
|
10
|
+
* `webAdmin.refreshNow()`,它与 60s cadence 共用同一只 join 形拍(在飞则 join,绝不并发双拍)。
|
|
11
11
|
* 回执里的两个世代号取自**同一本**世代账(`/health` 的三键同源)—— 两面各算一次迟早会各说各话。
|
|
12
12
|
*
|
|
13
13
|
* 🔴 没有配置管道(纯 env 形)⇒ 诚实 409 指路,**不吞成 200**:一个「triggered:true 但什么都没发生」的
|
|
@@ -24,7 +24,7 @@ export async function handleAdminConfigRefresh(req, res, match, ctx) {
|
|
|
24
24
|
const trigger = deps.configRefreshNow;
|
|
25
25
|
const outcome = trigger ? await trigger() : "not-wired";
|
|
26
26
|
if (outcome === "failed") {
|
|
27
|
-
sendError(res, 502, "internal.config_refresh_failed", "the config refresh tick failed (source unreachable / unreadable / apply error) — the live config is unchanged; see the worker's
|
|
27
|
+
sendError(res, 502, "internal.config_refresh_failed", "the config refresh tick failed (source unreachable / unreadable / apply error) — the live config is unchanged; see the worker's web_admin_refresh_failed log line for the cause");
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
30
|
if (outcome === "not-wired") {
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* 进入排空经 `drainState.enter`(收尾链装的唯一入口)。
|
|
7
7
|
* · 门序 = operator 面的既有口径(`routes/retention-ops.ts` 逐字):身份 → 授权 → 验型;billable=false,**刻意不吃排空 503**
|
|
8
8
|
* (排空中的重放必须能拿到 `already_draining` 回执,吃了就自锁)。
|
|
9
|
-
* · 判序:体坏 ⇒ 400 `request.field_invalid`(零状态变化)→ 没有收尾链(嵌入宿主 / 测试夹具)⇒ 501 `capability.drain_state_required`
|
|
9
|
+
* · 判序:体坏(含动作号不是标识符形 —— settings-schema 11 `DRAIN_ACTION_ID`)⇒ 400 `request.field_invalid`(零状态变化)→ 没有收尾链(嵌入宿主 / 测试夹具)⇒ 501 `capability.drain_state_required`
|
|
10
10
|
* → 身份不符 ⇒ 409 `conflict.fleet_identity`(零状态变化;拒句点名不符的字段,不回显值)→ 入口:已在排空 / 硬停已在进行 ⇒ 200 回执
|
|
11
11
|
* (这一发的期限不会被采用);这一发会进入排空而 `deadlineAt` 离进入那一拍超过 `FLEET_LEASE_OUTAGE_MAX_MS`(`config.fleetLeaseOutageMaxMs`,
|
|
12
12
|
* 本口随入参声明的准入上界,`fleet/drain-entry.ts` 规则 2)⇒ 入口答拒、本口 400 `request.field_invalid`(零状态变化;拒句点名字段、上界的
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { readDrainRequest } from "@sema-agent/settings-schema/fleet";
|
|
1
|
+
import { DRAIN_ACTION_ID, readDrainRequest } from "@sema-agent/settings-schema/fleet";
|
|
2
2
|
import { sendJson, sendError } from "../send.js";
|
|
3
3
|
import { gatedPrincipal, explicitOperatorOk, sendOperatorPrincipalsRequired, sendPrincipalRefusal } from "../principal-gate.js";
|
|
4
4
|
import * as facts from "../../capability-facts.js";
|
|
5
5
|
import { fleetScopeOf } from "../../config-types.js";
|
|
6
6
|
import { drainIdentityMismatches } from "../../fleet/drain-entry.js";
|
|
7
7
|
import { assertNever } from "../route-ctx.js";
|
|
8
|
+
import { WEB_ADMIN_ENV } from "@sema-agent/settings-schema";
|
|
8
9
|
export const ADMIN_DRAIN_PATH = "/v1/admin/drain";
|
|
9
10
|
const OPERATOR_ONLY_MESSAGE = "drain declaration is operator-only: the caller principal is not in OPERATOR_PRINCIPALS";
|
|
10
11
|
export async function handleAdminDrain(req, res, match, ctx) {
|
|
@@ -26,7 +27,7 @@ export async function handleAdminDrain(req, res, match, ctx) {
|
|
|
26
27
|
}
|
|
27
28
|
const request = readDrainRequest(await ctx.helpers.readJson(req));
|
|
28
29
|
if (request === undefined) {
|
|
29
|
-
sendError(res, 400, "request.field_invalid",
|
|
30
|
+
sendError(res, 400, "request.field_invalid", `the drain request must be { actionId, worker, deadlineAt, scope?, expectedGeneration?, instanceId?, term? }: actionId an idempotency key in identifier form (${DRAIN_ACTION_ID.source} — it is republished on GET /health, so no spaces or free text), worker this engine's worker name, deadlineAt epoch milliseconds, expectedGeneration a canonical decimal string ("7") — nothing was changed`);
|
|
30
31
|
return;
|
|
31
32
|
}
|
|
32
33
|
const enter = deps.drainState?.enter;
|
|
@@ -34,9 +35,9 @@ export async function handleAdminDrain(req, res, match, ctx) {
|
|
|
34
35
|
sendError(res, 501, "capability.drain_state_required", "this deployment has no drain entry wired (embedded in another process?) — there is no drain for this request to enter");
|
|
35
36
|
return;
|
|
36
37
|
}
|
|
37
|
-
const mismatched = drainIdentityMismatches(request, { scope: deps.config.fleetScope, worker: deps.config.
|
|
38
|
+
const mismatched = drainIdentityMismatches(request, { scope: deps.config.fleetScope, worker: deps.config.webAdmin?.worker, generation: deps.config.fleetGeneration, instanceId: deps.instanceId });
|
|
38
39
|
if (mismatched.length > 0) {
|
|
39
|
-
sendError(res, 409, "conflict.fleet_identity", `the drain request names a different instance than this engine (mismatched: ${mismatched.join(", ")}) — nothing was changed; compare with this engine's GET /health (worker comes from
|
|
40
|
+
sendError(res, 409, "conflict.fleet_identity", `the drain request names a different instance than this engine (mismatched: ${mismatched.join(", ")}) — nothing was changed; compare with this engine's GET /health (worker comes from ${WEB_ADMIN_ENV.worker}, generation from FLEET_GENERATION, scope from FLEET_SCOPE — unset, and a request without scope, mean "${fleetScopeOf(undefined)}")`);
|
|
40
41
|
return;
|
|
41
42
|
}
|
|
42
43
|
const answer = enter({ actionId: request.actionId, deadlineAt: request.deadlineAt, deadlineBoundMs: deps.config.fleetLeaseOutageMaxMs });
|
|
@@ -11,7 +11,7 @@ import { PLAN_APPROVE_PERMISSION_MODES_AFTER, isPlanApprovePermissionModeAfter,
|
|
|
11
11
|
import { MAX_APPROVAL_NONCE_CHARS } from "../../plugins/approval-nonce-store.js";
|
|
12
12
|
import { redactedPreview, redactSecrets } from "../../trace/redact.js";
|
|
13
13
|
import { redactRiskDescriptor } from "../../observability/run-terminal.js";
|
|
14
|
-
import {
|
|
14
|
+
import { buildRunName } from "../../fleet/fleet-bus.js";
|
|
15
15
|
import { sleep } from "../sse-log.js";
|
|
16
16
|
import { bindSseLifecycle } from "../sse-lifecycle.js";
|
|
17
17
|
import { sendJson, sendError, sseHeaders, SSE_MAX_STREAM_MS, SSE_HEARTBEAT_IDLE_MS } from "../send.js";
|
|
@@ -384,12 +384,12 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
384
384
|
.map((r) => {
|
|
385
385
|
const s = byGate.get(r.sessionId);
|
|
386
386
|
const gate = s ? { kind: s.gateKind, severity: s.severity ?? null, spentMicroUsd: s.spentMicroUsd ?? null, deadline: s.deadline ?? null } : null;
|
|
387
|
-
const preview = r.objectivePreview
|
|
388
|
-
const label = preview
|
|
387
|
+
const preview = r.objectivePreview ?? undefined;
|
|
388
|
+
const label = preview === undefined ? undefined : buildRunName(preview);
|
|
389
389
|
return {
|
|
390
390
|
taskId: r.taskId, sessionId: r.sessionId, status: r.status, needsAttention: !!gate, gate,
|
|
391
391
|
...(label !== undefined ? { name: label } : {}),
|
|
392
|
-
...(preview !== undefined && label !== preview ? { description: preview } : {}),
|
|
392
|
+
...(preview !== undefined && preview.trim() !== "" && label !== preview ? { description: preview } : {}),
|
|
393
393
|
createdAt: r.createdAt, updatedAt: r.updatedAt,
|
|
394
394
|
};
|
|
395
395
|
})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PERMISSION_MODES, expandTiers, reasoningEffortLevelsOf, routePairingStatus } from "@sema-agent/core";
|
|
2
|
-
import { modelImageInput,
|
|
3
|
-
import { buildDroppedEntriesWire } from "../../
|
|
2
|
+
import { modelImageInput, isAtMentionable, selectableCatalog } from "../../model-select.js";
|
|
3
|
+
import { buildDroppedEntriesWire } from "../../web-admin-client/read-warnings.js";
|
|
4
4
|
import { modelKeyPoisonOf, resolveModelApiKey } from "../../key-resolver.js";
|
|
5
5
|
import { projectSealedKeyCapability } from "../../sealed-key.js";
|
|
6
6
|
import { cwdHonored, deviceCwdHonored } from "../../task-cwd.js";
|
|
@@ -10,7 +10,7 @@ import { autonomyKeepsOpenWriteFace, autonomyModeFloor } from "../../runtime-gov
|
|
|
10
10
|
import { DEVICE_PROTOCOL_VERSION, DEVICE_WS_PATH } from "../../device-ws-protocol.js";
|
|
11
11
|
import { a2aInjectionHonored } from "../../task-a2a.js";
|
|
12
12
|
import { buildEmptyMcpProbeFace, buildMcpInjectionRefusal, buildMcpProbeCacheKey, buildMcpProbeInflightRefusal, buildMcpProbeRateKey, buildMcpProbeRateRefusal, createMcpProbeLocal, buildMcpProbeDeclarationRefusal, buildMcpProbeIncompleteRefusal, McpProbeIncomplete, MCP_PROBE_HTTP_STATUS, MCP_PROBE_MAX_INFLIGHT, MCP_PROBE_VERDICT_TIMEOUT_MS, createMcpProbeWalk, readMcpProbeBody, } from "../../capabilities/mcp-probe.js";
|
|
13
|
-
import { mcpForScenario } from "../../
|
|
13
|
+
import { mcpForScenario } from "../../web-admin-client/facade.js";
|
|
14
14
|
import { sendJson, sendError } from "../send.js";
|
|
15
15
|
import { assertNever } from "../route-ctx.js";
|
|
16
16
|
import { fileHistoryCaptureOf } from "../../file-history-capture.js";
|
|
@@ -237,7 +237,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
237
237
|
}
|
|
238
238
|
case "models": {
|
|
239
239
|
const atCatalog = selectableCatalog(deps.config.models, deps.config.tiers, deps.config.modelRefusals);
|
|
240
|
-
const
|
|
240
|
+
const atMention = deps.config.atMention;
|
|
241
241
|
const models = Object.entries(deps.config.models)
|
|
242
242
|
.filter(([name]) => name !== "default")
|
|
243
243
|
.map(([name, m]) => ({
|
|
@@ -250,7 +250,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
250
250
|
...(m.maxTokens ? { maxOutputTokens: m.maxTokens } : {}),
|
|
251
251
|
...((levels) => (levels !== undefined ? { supportedEffortLevels: [...levels] } : {}))(reasoningEffortLevelsOf(m)),
|
|
252
252
|
...(m.compat !== undefined ? { compat: m.compat } : {}),
|
|
253
|
-
...(
|
|
253
|
+
...(atMention.mode !== "all" ? { atMentionable: isAtMentionable(name, atCatalog, atMention, deps.config.modelRefusals) } : {}),
|
|
254
254
|
routePairing: routePairingOf(deps, name, m),
|
|
255
255
|
}));
|
|
256
256
|
const nonAlias = Object.entries(deps.config.models).filter(([n]) => n !== "default");
|
|
@@ -3,7 +3,7 @@ import { sendJson, sendError } from "../send.js";
|
|
|
3
3
|
import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal, sendOperatorPrincipalsRequired } from "../principal-gate.js";
|
|
4
4
|
import { assertNever } from "../route-ctx.js";
|
|
5
5
|
import * as facts from "../../capability-facts.js";
|
|
6
|
-
import {
|
|
6
|
+
import { configKnobTable } from "../../config.js";
|
|
7
7
|
import { buildConfigCatalog } from "../../config-catalog.js";
|
|
8
8
|
export const CONFIG_CATALOG_PATH = "/v1/config/catalog";
|
|
9
9
|
const OPERATOR_ONLY_MESSAGE = "the config catalog is operator-only: the caller principal is not in OPERATOR_PRINCIPALS";
|
|
@@ -40,8 +40,7 @@ export async function handleConfigCatalog(req, res, match, ctx) {
|
|
|
40
40
|
boot: { ...(deps.memoryConsolidationValve !== undefined ? { memoryConsolidationValve: deps.memoryConsolidationValve } : {}) },
|
|
41
41
|
knobs: configKnobTable(),
|
|
42
42
|
centerDomains: DOMAINS,
|
|
43
|
-
centerManagedKeys: deps.
|
|
44
|
-
retired: buildRetiredEnvWire(),
|
|
43
|
+
centerManagedKeys: deps.webAdminManagedKeys?.(),
|
|
45
44
|
}));
|
|
46
45
|
return;
|
|
47
46
|
}
|
|
@@ -14,7 +14,7 @@ export function buildServerWiringGates(input) {
|
|
|
14
14
|
backend: input.backend,
|
|
15
15
|
parkFacility: input.checkpointStore !== undefined,
|
|
16
16
|
});
|
|
17
|
-
const noCenterArm = (knob) => `this knob has no
|
|
17
|
+
const noCenterArm = (knob) => `this knob has no web-admin arm on this deployment — it is set by ${knob} on this machine, or derived from the deployment posture`;
|
|
18
18
|
return {
|
|
19
19
|
streamApproval: gate.active ? "active" : gate.reason,
|
|
20
20
|
durableApproval: buildPostureKnobReading(input.durableApproval, {
|