@sema-agent/server 4.3.0 → 5.0.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/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +16 -16
- package/dist/approval-hmac.js +1 -1
- package/dist/approval.d.ts +17 -37
- package/dist/approval.js +26 -112
- package/dist/auth-bridge.d.ts +0 -1
- package/dist/auth-bridge.js +0 -1
- package/dist/auth-keys.d.ts +1 -1
- package/dist/auth-keys.js +1 -1
- package/dist/bench/s1/run-firm.js +1 -1
- package/dist/boot/config-center.d.ts +1 -1
- package/dist/boot/config-center.js +4 -3
- package/dist/boot/reapers.d.ts +1 -2
- package/dist/boot/reapers.js +4 -5
- package/dist/boot/resolve-spec.d.ts +1 -3
- package/dist/boot/resolve-spec.js +21 -35
- package/dist/boot/stores.js +1 -1
- package/dist/brain.js +3 -1
- package/dist/capabilities/center-prompts.d.ts +2 -3
- package/dist/capabilities/center-prompts.js +2 -3
- package/dist/capabilities/sandbox-file-send.d.ts +0 -2
- package/dist/capabilities/sandbox-file-send.js +2 -5
- package/dist/capabilities/scenarios.d.ts +2 -13
- package/dist/capabilities/scenarios.js +3 -22
- package/dist/capabilities/send-user-file-tool.js +3 -3
- package/dist/config-center/apply-effective.js +51 -13
- package/dist/config-center/types.d.ts +10 -3
- package/dist/config-provider.d.ts +1 -1
- package/dist/config-provider.js +6 -11
- package/dist/config-types.d.ts +15 -29
- package/dist/config.d.ts +28 -0
- package/dist/config.js +122 -68
- package/dist/fleet/fleet-bus.d.ts +1 -1
- package/dist/fleet/fleet-bus.js +25 -33
- package/dist/fleet-client.js +1 -1
- package/dist/http/active-run-conflict.d.ts +2 -0
- package/dist/http/active-run-conflict.js +1 -0
- package/dist/http/routes/approvals-assistant.d.ts +2 -1
- package/dist/http/routes/approvals-assistant.js +10 -96
- package/dist/http/routes/capabilities.js +6 -5
- package/dist/http/routes/fleet.js +7 -2
- package/dist/http/routes/images.js +10 -4
- package/dist/http/routes/runs.js +42 -65
- package/dist/http/routes/session-sync.d.ts +1 -1
- package/dist/http/routes/session-sync.js +2 -1
- package/dist/http/routes/tasks.js +7 -7
- package/dist/http/routes/trace-usage.js +1 -1
- package/dist/http/routes/workflows.js +3 -1
- package/dist/http/server.d.ts +1 -6
- package/dist/http/server.js +15 -10
- package/dist/http/verify-rounds.d.ts +2 -2
- package/dist/http/wire-types.d.ts +1 -1
- package/dist/images/bake-validate.d.ts +0 -22
- package/dist/images/bake-validate.js +0 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -5
- package/dist/main.js +9 -10
- package/dist/memory-scope.d.ts +1 -2
- package/dist/memory-scope.js +8 -4
- package/dist/orchestration/workflow-completion-inbox.d.ts +6 -4
- package/dist/orchestration/workflow-completion-inbox.js +6 -4
- package/dist/plugins/breaker-state-sql.d.ts +2 -3
- package/dist/plugins/file-run-store.d.ts +1 -1
- package/dist/plugins/file-run-store.js +1 -1
- package/dist/plugins/image-index-sql.d.ts +0 -1
- package/dist/plugins/image-index-sql.js +0 -1
- package/dist/plugins/local-checkpoint-store.d.ts +1 -1
- package/dist/plugins/local-checkpoint-store.js +1 -1
- package/dist/plugins/memory-engine-pg.js +2 -1
- package/dist/plugins/memory-engine-tidb.js +1 -1
- package/dist/plugins/memory-engine-vector-util.d.ts +2 -3
- package/dist/plugins/memory-engine-vector-util.js +2 -3
- package/dist/plugins/memory-run-store.d.ts +2 -2
- package/dist/plugins/memory-run-store.js +1 -1
- package/dist/plugins/memory-session-policy-store.d.ts +1 -1
- package/dist/plugins/memory-session-policy-store.js +1 -1
- package/dist/plugins/memory-sync-store-pg.js +1 -1
- package/dist/plugins/pg-pool.js +8 -10
- package/dist/plugins/pg-rate-limiter.d.ts +1 -4
- package/dist/plugins/pg-rate-limiter.js +0 -1
- package/dist/plugins/roster-store-sql.d.ts +1 -3
- package/dist/plugins/roster-store-sql.js +3 -5
- package/dist/plugins/store-backend.d.ts +7 -17
- package/dist/plugins/store-backend.js +14 -30
- package/dist/plugins/tidb-pool.js +6 -30
- package/dist/plugins/workflow-journal-store-sql.d.ts +1 -1
- package/dist/plugins/workflow-journal-store-sql.js +1 -1
- package/dist/principal-jwt.js +2 -2
- package/dist/prompts-domain-validate.d.ts +4 -3
- package/dist/prompts-domain-validate.js +7 -8
- package/dist/router/route-orchestration.js +3 -3
- package/dist/run-local.js +13 -10
- package/dist/runs.js +8 -6
- package/dist/runtime-caps-resolver.d.ts +3 -2
- package/dist/runtime-caps-resolver.js +4 -4
- package/dist/runtime-governance.d.ts +4 -7
- package/dist/runtime-governance.js +12 -17
- package/dist/sealed-key.d.ts +1 -1
- package/dist/sealed-key.js +1 -1
- package/dist/security.d.ts +0 -5
- package/dist/security.js +8 -12
- package/dist/session-sync.d.ts +0 -2
- package/dist/session-sync.js +10 -17
- package/dist/spec-fields.js +6 -6
- package/dist/task-settings.d.ts +0 -27
- package/dist/task-settings.js +42 -11
- package/dist/tool-approval.d.ts +3 -3
- package/dist/tool-approval.js +10 -10
- package/dist/trace/artifacts.d.ts +11 -0
- package/dist/trace/artifacts.js +8 -19
- package/dist/trace/ledger-sink.js +7 -1
- package/dist/trace/project.d.ts +17 -0
- package/dist/trace/project.js +58 -5
- package/package.json +3 -3
- package/dist/capabilities/oa-tools.d.ts +0 -15
- package/dist/capabilities/oa-tools.js +0 -54
- package/dist/plugins/approval-store-sql.d.ts +0 -116
- package/dist/plugins/approval-store-sql.js +0 -150
- package/dist/plugins/file-workflow-journal-store.d.ts +0 -12
- package/dist/plugins/file-workflow-journal-store.js +0 -12
- package/dist/plugins/pg-approval-store.d.ts +0 -9
- package/dist/plugins/pg-approval-store.js +0 -9
- package/dist/plugins/pg-breaker-state.d.ts +0 -8
- package/dist/plugins/pg-breaker-state.js +0 -8
- package/dist/plugins/pg-checkpoint-store.d.ts +0 -10
- package/dist/plugins/pg-checkpoint-store.js +0 -10
- package/dist/plugins/pg-file-snapshot-store.d.ts +0 -8
- package/dist/plugins/pg-file-snapshot-store.js +0 -8
- package/dist/plugins/pg-image-bake.d.ts +0 -12
- package/dist/plugins/pg-image-bake.js +0 -11
- package/dist/plugins/pg-image-index.d.ts +0 -12
- package/dist/plugins/pg-image-index.js +0 -11
- package/dist/plugins/pg-outcome-ledger.d.ts +0 -12
- package/dist/plugins/pg-outcome-ledger.js +0 -11
- package/dist/plugins/pg-resume-anchor-store.d.ts +0 -7
- package/dist/plugins/pg-resume-anchor-store.js +0 -7
- package/dist/plugins/pg-run-store.d.ts +0 -9
- package/dist/plugins/pg-run-store.js +0 -9
- package/dist/plugins/pg-session-policy-store.d.ts +0 -7
- package/dist/plugins/pg-session-policy-store.js +0 -7
- package/dist/plugins/pg-session-store.d.ts +0 -12
- package/dist/plugins/pg-session-store.js +0 -12
- package/dist/plugins/pg-tool-result-store.d.ts +0 -9
- package/dist/plugins/pg-tool-result-store.js +0 -9
- package/dist/plugins/pg-workflow-journal-store.d.ts +0 -9
- package/dist/plugins/pg-workflow-journal-store.js +0 -9
- package/dist/plugins/pg-workflow-run-store.d.ts +0 -9
- package/dist/plugins/pg-workflow-run-store.js +0 -9
- package/dist/plugins/tidb-approval-store.d.ts +0 -8
- package/dist/plugins/tidb-approval-store.js +0 -8
- package/dist/plugins/tidb-breaker-state.d.ts +0 -7
- package/dist/plugins/tidb-breaker-state.js +0 -7
- package/dist/plugins/tidb-checkpoint-store.d.ts +0 -9
- package/dist/plugins/tidb-checkpoint-store.js +0 -9
- package/dist/plugins/tidb-file-snapshot-store.d.ts +0 -8
- package/dist/plugins/tidb-file-snapshot-store.js +0 -8
- package/dist/plugins/tidb-image-bake.d.ts +0 -12
- package/dist/plugins/tidb-image-bake.js +0 -11
- package/dist/plugins/tidb-image-index.d.ts +0 -12
- package/dist/plugins/tidb-image-index.js +0 -11
- package/dist/plugins/tidb-outcome-ledger.d.ts +0 -12
- package/dist/plugins/tidb-outcome-ledger.js +0 -12
- package/dist/plugins/tidb-resume-anchor-store.d.ts +0 -7
- package/dist/plugins/tidb-resume-anchor-store.js +0 -7
- package/dist/plugins/tidb-run-store.d.ts +0 -10
- package/dist/plugins/tidb-run-store.js +0 -9
- package/dist/plugins/tidb-session-policy-store.d.ts +0 -7
- package/dist/plugins/tidb-session-policy-store.js +0 -7
- package/dist/plugins/tidb-tool-result-store.d.ts +0 -8
- package/dist/plugins/tidb-tool-result-store.js +0 -10
- package/dist/plugins/tidb-workflow-journal-store.d.ts +0 -9
- package/dist/plugins/tidb-workflow-journal-store.js +0 -9
- package/dist/plugins/tidb-workflow-run-store.d.ts +0 -10
- package/dist/plugins/tidb-workflow-run-store.js +0 -10
- package/dist/plugins/workflow-journal-limits.d.ts +0 -12
- package/dist/plugins/workflow-journal-limits.js +0 -12
package/dist/config.d.ts
CHANGED
|
@@ -116,6 +116,34 @@ export declare const hostExecSpoolEnabled: () => boolean;
|
|
|
116
116
|
* is REMOVED (a spread-inherited value from a bigger-window base model would mis-trigger a small window).
|
|
117
117
|
* Shared by the env lane (main + cheap models) and the center lane (sema-registry toModel). */
|
|
118
118
|
export declare function applyAutoCompactWindow(m: Model, explicit?: number): void;
|
|
119
|
+
/**
|
|
120
|
+
* 一条工具名**永不匹配任何现役工具**的三种拼法,及其修正指引。审批/权限名单是 server 侧 ToolPolicy 的
|
|
121
|
+
* RAW 逐字比对(canonicalToolName 折叠面已随 core 5.0.0 RB-476 退役),所以写错的名字不会报错、只会静默
|
|
122
|
+
* 不生效——对 deny/ask 名单而言这是**失守方向**(运维/客户端以为加了门,实际什么都没加)。
|
|
123
|
+
*
|
|
124
|
+
* 判据在此**单点成文**,三条腿共用(它们此前各自为政,拼法覆盖面不一致才是真缺口):
|
|
125
|
+
* ① env 腿(`APPROVAL_REQUIRE`/`DENY`/`NEVER_AUTO`,下方)—— boot 拒启;
|
|
126
|
+
* ② 中心下发腿(`runtime.approvalRequire`,config-center/apply-effective.ts)—— 域级拒绝+保前值+warn
|
|
127
|
+
* (常驻进程不 crash);
|
|
128
|
+
* ③ per-request 腿(`settings.permissions.{ask,deny}`,task-settings.ts)—— 该请求 422。
|
|
129
|
+
*
|
|
130
|
+
* 三种拼法:
|
|
131
|
+
* - 退役名(`bash`/`Task`/`KillShell`…):core `RETIRED_TOOL_NAMES` 静态表,指引=现役名。
|
|
132
|
+
* - pre-prefix 短名(`figma__x`):v4 自动加前缀的折叠面已删,实挂名恒带 `mcp__`,指引=补全前缀。
|
|
133
|
+
* - 不完整 MCP 名(`mcp__`、`mcp__figma`):前缀对但缺段——MCP 实挂名恒是 `mcp__<server>__<tool>` 三段形,
|
|
134
|
+
* 少一段同样永不匹配。旧判据「含 `__` 且 protocolOf 认不出」放过了这一族(前缀恰好认得出),从另一侧
|
|
135
|
+
* 漏出去,失守方向与 `figma__x` 完全相同。
|
|
136
|
+
*
|
|
137
|
+
* 已接受的权衡(与退役表墓碑同一条):部署自有工具真叫 `figma__x` 的极端形会被误拒——boot 期无 roster 可
|
|
138
|
+
* 豁免,且失败响亮、指引明确,好过静默失守。
|
|
139
|
+
*/
|
|
140
|
+
export interface UnmatchableToolName {
|
|
141
|
+
name: string;
|
|
142
|
+
guidance: string;
|
|
143
|
+
}
|
|
144
|
+
export declare function findUnmatchableToolNames(names: readonly string[]): UnmatchableToolName[];
|
|
145
|
+
/** {@link findUnmatchableToolNames} 的成句形——三条腿的文案同源(只有前缀/出口不同)。 */
|
|
146
|
+
export declare function formatUnmatchableToolNames(source: string, bad: readonly UnmatchableToolName[]): string;
|
|
119
147
|
/** 组名 → 该组取景的平铺键(introspection 面:测试用它钉「每个平铺键恰好被一组取景」)。 */
|
|
120
148
|
export declare const CONFIG_GROUP_KEYS: {
|
|
121
149
|
readonly [G in keyof ServiceConfigGroups]: readonly (keyof ServiceConfigFlat)[];
|
package/dist/config.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { CODE_AGENT_PROMPT, formatUserScope, isThinkingLevel, RECOMMENDED_SENSITIVE_PATTERNS } from "@sema-agent/core";
|
|
4
|
+
import { CODE_AGENT_PROMPT, formatUserScope, isThinkingLevel, protocolOf, RECOMMENDED_SENSITIVE_PATTERNS, RETIRED_TOOL_NAMES } from "@sema-agent/core";
|
|
5
5
|
import { ROSTER_PRIMARY_ROLES, ROSTER_CHEAP_ROLES } from "@sema-agent/registry-core";
|
|
6
6
|
import { parseApprovalHmacKeys, parsePrincipalJwks } from "./auth-keys.js"; // design/158 A4: the parser leaf — NOT security.js (base config layer must not value-import the 55KiB auth module)
|
|
7
7
|
import { DEFAULT_ELICITATION_THROTTLE } from "./elicitation.js";
|
|
@@ -60,16 +60,38 @@ function defaultSkillsDir() {
|
|
|
60
60
|
return "skills"; // import.meta 不可用的兜底(不应发生在 ESM 构建里)
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
63
|
+
const RETIRED_ENVS = [
|
|
64
|
+
["TIDB_HOST", "MYSQL_HOST", "renamed"], ["TIDB_PORT", "MYSQL_PORT", "renamed"], ["TIDB_USER", "MYSQL_USER", "renamed"],
|
|
65
|
+
["TIDB_PASSWORD", "MYSQL_PASSWORD", "renamed"], ["TIDB_DATABASE", "MYSQL_DATABASE", "renamed"], ["TIDB_POOL_SIZE", "MYSQL_POOL_SIZE", "renamed"],
|
|
66
|
+
["CONFIG_CENTER_URL", "SEMA_REGISTRY_URL", "renamed"], ["CONFIG_CENTER_TOKEN", "SEMA_REGISTRY_TOKEN", "renamed"],
|
|
67
|
+
["CONFIG_CENTER_DRY_RUN", "SEMA_REGISTRY_DRY_RUN", "renamed"], ["CONFIG_CENTER_WORKER", "SEMA_REGISTRY_WORKER", "renamed"],
|
|
68
|
+
["ANTHROPIC_BASEURL", "ANTHROPIC_BASE_URL", "renamed"],
|
|
69
|
+
["REGISTRY_ADMIN_TOKEN", "SEMA_REGISTRY_ADMIN_TOKEN", "renamed"], // [2373]B-1:墓碑族唯一漏网的双读(config-center.ts 发射点)
|
|
70
|
+
// [2354] OA 场景整体退役(clay 令 2026-08-01):配置本身作废,无替代名 ⇒ removed 族。
|
|
71
|
+
["OA_API_BASEURL", "the OA scenario was removed in 5.0.0", "removed"],
|
|
72
|
+
["OA_SERVICE_TOKEN", "the OA scenario was removed in 5.0.0", "removed"],
|
|
73
|
+
["OA_ISSUE_TOKEN", "the OA scenario was removed in 5.0.0", "removed"],
|
|
74
|
+
["OA_ISSUE_BASEURL", "the OA scenario was removed in 5.0.0", "removed"],
|
|
75
|
+
["OA_ISSUE_OWNER", "the OA scenario was removed in 5.0.0", "removed"],
|
|
76
|
+
["OA_ISSUE_REPO", "the OA scenario was removed in 5.0.0", "removed"],
|
|
77
|
+
["OA_ISSUE_LABELS", "the OA scenario was removed in 5.0.0", "removed"],
|
|
78
|
+
["APPROVAL_POLL_MS", "the OA poll-approval lane was removed in 5.0.0; the durable checkpoint lane is the only gate", "removed"],
|
|
79
|
+
];
|
|
80
|
+
function rejectRetiredEnvs() {
|
|
81
|
+
const hit = RETIRED_ENVS.filter(([o]) => process.env[o] !== undefined && process.env[o] !== "");
|
|
82
|
+
if (hit.length === 0)
|
|
83
|
+
return;
|
|
84
|
+
const renamed = hit.filter(([, , k]) => k === "renamed");
|
|
85
|
+
const removed = hit.filter(([, , k]) => k === "removed");
|
|
86
|
+
const parts = [];
|
|
87
|
+
if (renamed.length > 0) {
|
|
88
|
+
parts.push(`${renamed.map(([o, n]) => `${o} → use ${n}`).join("; ")} — rename the env key(s); the value semantics are unchanged`);
|
|
71
89
|
}
|
|
72
|
-
|
|
90
|
+
if (removed.length > 0) {
|
|
91
|
+
parts.push(`${removed.map(([o, n]) => `${o} (${n})`).join("; ")} — remove the env key(s): the capability itself was retired, ` +
|
|
92
|
+
`there is no replacement name and no rename that restores it`);
|
|
93
|
+
}
|
|
94
|
+
throw new Error(`retired env name(s) set ([2354] 兼容面全清,5.0.0 起拒启): ${parts.join(" | ")}.`);
|
|
73
95
|
}
|
|
74
96
|
/** Numeric env with validation: a non-numeric value FAILS at startup instead of silently becoming `NaN`
|
|
75
97
|
* (which e.g. slips past the `runStaleSec` liveness guard and silently disables the reaper). */
|
|
@@ -387,11 +409,11 @@ function parseStoreDomain(ctx) {
|
|
|
387
409
|
// 在场时,dbBackend 的旧默认 "mysql" 是**引擎选择器**(auto 探测/coords 构建都 key 它),默认切
|
|
388
410
|
// local 会把这些既有形错切到文件店(回归钉在 config-coverage)。
|
|
389
411
|
const sqlSignal = (!!process.env.SESSION_BACKEND && process.env.SESSION_BACKEND !== "memory") ||
|
|
390
|
-
!!(process.env.
|
|
412
|
+
!!(process.env.MYSQL_HOST || process.env.PG_HOST);
|
|
391
413
|
const bareBoot = !dbBackendSet && !sqlSignal;
|
|
392
414
|
const multiTenantBareBoot = bareBoot && requirePrincipal;
|
|
393
|
-
|
|
394
|
-
const dbBackend =
|
|
415
|
+
// [2354]:公名枚举不再收 "tidb"(enumEnv 对越集值自带拒启);内部逻辑不变。
|
|
416
|
+
const dbBackend = enumEnv("DB_BACKEND", bareBoot ? (multiTenantBareBoot ? "memory" : "local") : "mysql", ["mysql", "pg", "local", "memory"]);
|
|
395
417
|
if (multiTenantBareBoot) {
|
|
396
418
|
CONFIG_NOTICES.push({
|
|
397
419
|
event: "db_backend_default_memory_multi_tenant",
|
|
@@ -407,7 +429,7 @@ function parseStoreDomain(ctx) {
|
|
|
407
429
|
// backend); an UNSET DB_BACKEND keeps the memory default (no surprise DB requirement on a bare boot).
|
|
408
430
|
// `mysql` is accepted as an alias of the internal durable label `tidb` (see ServiceConfig.sessionBackend).
|
|
409
431
|
const sqlEngineExplicit = !!process.env.DB_BACKEND && dbBackend !== "local" && dbBackend !== "memory";
|
|
410
|
-
const sessionBackendRaw = enumEnv("SESSION_BACKEND", sqlEngineExplicit ? "mysql" : "memory", ["memory", "mysql", "
|
|
432
|
+
const sessionBackendRaw = enumEnv("SESSION_BACKEND", sqlEngineExplicit ? "mysql" : "memory", ["memory", "mysql", "auto"]); // [2354]:公名 "tidb" 退役
|
|
411
433
|
const sessionBackend = sessionBackendRaw === "mysql" ? "tidb" : sessionBackendRaw;
|
|
412
434
|
// P0.5 variant-2: the file-backed `local` backend's data root. Same tail as main.ts's `localRoot` and
|
|
413
435
|
// run-local.ts's `root` (CONFIG_LOCAL_DIR → AGENT_DATA_DIR → ~/.ai-agent), so the HTTP service + a run-local
|
|
@@ -421,7 +443,7 @@ function parseStoreDomain(ctx) {
|
|
|
421
443
|
// `auto` builds the DB coords only when a host is actually configured — otherwise it stays memory with no
|
|
422
444
|
// probe. (Explicit mysql always builds them so a missing host fails loudly.) `needsDb` is engine-agnostic;
|
|
423
445
|
// the connection coords are built for whichever engine `dbBackend` selects (MYSQL_* preferred, TIDB_* alias).
|
|
424
|
-
const dbHostSet = dbBackend === "pg" ? !!process.env.PG_HOST : !!
|
|
446
|
+
const dbHostSet = dbBackend === "pg" ? !!process.env.PG_HOST : !!process.env.MYSQL_HOST;
|
|
425
447
|
const needsTidb = sessionBackend === "tidb" || (sessionBackend === "auto" && dbHostSet);
|
|
426
448
|
const needsDb = needsTidb;
|
|
427
449
|
return {
|
|
@@ -433,14 +455,13 @@ function parseStoreDomain(ctx) {
|
|
|
433
455
|
localDataRoot,
|
|
434
456
|
tidb: needsDb && dbBackend === "mysql"
|
|
435
457
|
? {
|
|
436
|
-
host:
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
? Number(process.env.MYSQL_POOL_SIZE || process.env.TIDB_POOL_SIZE)
|
|
458
|
+
host: env("MYSQL_HOST"),
|
|
459
|
+
port: Number(env("MYSQL_PORT", "3306")),
|
|
460
|
+
user: env("MYSQL_USER"),
|
|
461
|
+
password: env("MYSQL_PASSWORD", ""),
|
|
462
|
+
database: env("MYSQL_DATABASE"),
|
|
463
|
+
connectionLimit: process.env.MYSQL_POOL_SIZE
|
|
464
|
+
? Number(process.env.MYSQL_POOL_SIZE)
|
|
444
465
|
: undefined,
|
|
445
466
|
}
|
|
446
467
|
: undefined,
|
|
@@ -528,7 +549,7 @@ function parseModelDomain() {
|
|
|
528
549
|
// credential alone does NOT infer (a bare ANTHROPIC_API_KEY historically only assembles the cloud route for
|
|
529
550
|
// registry-declared anthropic models); neither present ⇒ "gateway", byte-identical to before.
|
|
530
551
|
const explicitProvider = process.env.MODEL_PROVIDER; // env() semantics: "" = unset
|
|
531
|
-
const inferredAnthropicBaseUrl = firstSetEnv("
|
|
552
|
+
const inferredAnthropicBaseUrl = firstSetEnv("ANTHROPIC_BASE_URL"); // [2354]:无下划线非标名退役(墓碑)
|
|
532
553
|
const inferredAnthropicCred = firstSetEnv("ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN");
|
|
533
554
|
const provider = (() => {
|
|
534
555
|
if (explicitProvider !== undefined && explicitProvider !== "")
|
|
@@ -702,6 +723,11 @@ function parseModelDomain() {
|
|
|
702
723
|
? { model: cur, systemPrompt: CODE_AGENT_PROMPT }
|
|
703
724
|
: { ...cur, systemPrompt: CODE_AGENT_PROMPT };
|
|
704
725
|
}
|
|
726
|
+
// A2:词表验证**无条件**执行(此前它挂在下面 `MODEL_DEGRADE_TO ? {...}` 三元的真臂里,TO 缺席时
|
|
727
|
+
// parseDegradeOn 根本不可达 ⇒ 拼错词静默无效),而 USAGE.md 的「拼错词 boot 拒启,不静默忽略」是对
|
|
728
|
+
// MODEL_DEGRADE_ON 本身的无条件承诺:设了就验。TO 缺席 + ON 合法 ⇒ 照旧不装配 degrade(行为不变),
|
|
729
|
+
// 也不报错——ON 只是把那份已在的意图写下来,不是把 degrade 打开。
|
|
730
|
+
const degradeOn = parseDegradeOn(csv("MODEL_DEGRADE_ON"));
|
|
705
731
|
return {
|
|
706
732
|
gatewayBaseUrl,
|
|
707
733
|
gatewayApiKey: process.env.MODEL_API_KEY,
|
|
@@ -719,7 +745,7 @@ function parseModelDomain() {
|
|
|
719
745
|
? {
|
|
720
746
|
apiKey: firstSetEnv("ANTHROPIC_API_KEY"),
|
|
721
747
|
authToken: firstSetEnv("ANTHROPIC_AUTH_TOKEN"),
|
|
722
|
-
baseUrl: firstSetEnv("
|
|
748
|
+
baseUrl: firstSetEnv("ANTHROPIC_BASE_URL"),
|
|
723
749
|
version: process.env.ANTHROPIC_VERSION,
|
|
724
750
|
cacheBreakpoints: (process.env.ANTHROPIC_CACHE_BREAKPOINTS ?? "true") === "true",
|
|
725
751
|
...(process.env.ANTHROPIC_MAX_RETRIES ? { maxRetries: Number(env("ANTHROPIC_MAX_RETRIES", "2")) } : {}),
|
|
@@ -755,9 +781,10 @@ function parseModelDomain() {
|
|
|
755
781
|
to: env("MODEL_DEGRADE_TO"),
|
|
756
782
|
atCostFraction: Number(env("MODEL_DEGRADE_AT_COST_FRACTION", "0.7")),
|
|
757
783
|
reactive: boolEnv("MODEL_DEGRADE_REACTIVE", false),
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
784
|
+
// core 5.1.0([2390]②):词表=DegradeReason 全集;缺席时 core 默认含 server_error(默认门变宽),
|
|
785
|
+
// 本 env 是运维收窄/放宽的唯一旋钮。拼错词 boot 响亮拒——盲铸静默折无效成员是 TASK_TIMEOUT_SEC 同族病。
|
|
786
|
+
// (验词在上方无条件做掉了,见 A2 注;这里只是取用已验过的结果。)
|
|
787
|
+
downgradeOn: degradeOn,
|
|
761
788
|
// vision precheck (adversarial-review finding): the degrade TARGET is an external gateway
|
|
762
789
|
// model NOT in config.models, so resolveSpec's precheck (which only sees the picked model) can't see its
|
|
763
790
|
// vision capability — a vision-capable main + text-only degrade target would let images reach the text-only
|
|
@@ -771,6 +798,43 @@ function parseModelDomain() {
|
|
|
771
798
|
}
|
|
772
799
|
/** 域:approval(审批/HITL 门)—— 审批名单与预算、durable 面、直连门开关与钥、敏感写门、elicitation。
|
|
773
800
|
* 注:直连门的**激活**(directDoorActive)与 D-G §3 半开门不变量是跨域合取,留在装配层。 */
|
|
801
|
+
/** MODEL_DEGRADE_ON 词表=core `DegradeReason` 全集(集合用该类型铸=锁步:core 删词此处 tsc 红,加词这里
|
|
802
|
+
* 补一个词即可)。非法词 boot 响亮拒——盲铸静默折无效成员与 TASK_TIMEOUT_SEC 非法值折「无超时」同族。 */
|
|
803
|
+
const DEGRADE_ON_WORDS = new Set(["breaker_open", "rate_limit", "budget", "server_error", "last_resort"]);
|
|
804
|
+
function parseDegradeOn(words) {
|
|
805
|
+
if (words.length === 0)
|
|
806
|
+
return undefined;
|
|
807
|
+
const bad = words.filter((w) => !DEGRADE_ON_WORDS.has(w));
|
|
808
|
+
if (bad.length > 0) {
|
|
809
|
+
throw new Error(`MODEL_DEGRADE_ON has unknown trigger word(s): ${bad.join(", ")} (valid: ${[...DEGRADE_ON_WORDS].join(", ")})`);
|
|
810
|
+
}
|
|
811
|
+
return words;
|
|
812
|
+
}
|
|
813
|
+
export function findUnmatchableToolNames(names) {
|
|
814
|
+
const out = [];
|
|
815
|
+
for (const name of names) {
|
|
816
|
+
const retired = RETIRED_TOOL_NAMES.get(name);
|
|
817
|
+
if (retired !== undefined) {
|
|
818
|
+
out.push({ name, guidance: retired });
|
|
819
|
+
continue;
|
|
820
|
+
}
|
|
821
|
+
const ns = protocolOf(name);
|
|
822
|
+
if (ns === undefined) {
|
|
823
|
+
if (name.includes("__"))
|
|
824
|
+
out.push({ name, guidance: `pre-prefix MCP short form — the live name is mcp__${name}` });
|
|
825
|
+
continue;
|
|
826
|
+
}
|
|
827
|
+
if (ns.parse(name) === undefined) {
|
|
828
|
+
out.push({ name, guidance: `incomplete ${ns.id} name — the live form is ${ns.prefix}<server>__<tool>` });
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
return out;
|
|
832
|
+
}
|
|
833
|
+
/** {@link findUnmatchableToolNames} 的成句形——三条腿的文案同源(只有前缀/出口不同)。 */
|
|
834
|
+
export function formatUnmatchableToolNames(source, bad) {
|
|
835
|
+
return (`${source} names tool(s) that can never match a live tool (core 5.0.0 RB-476 — the alias/auto-prefix folds are gone): ` +
|
|
836
|
+
bad.map((b) => `${b.name} → ${b.guidance}`).join("; "));
|
|
837
|
+
}
|
|
774
838
|
function parseApprovalDomain(ctx) {
|
|
775
839
|
const { postureOn } = ctx; // 跨域入参②:posture 三态(single-user turnkey ⇒ HITL 面默认 ON)
|
|
776
840
|
// design/80 D-G: the direct-connect approval door anchors (all must be present to ACTIVATE; fail-closed).
|
|
@@ -778,15 +842,24 @@ function parseApprovalDomain(ctx) {
|
|
|
778
842
|
const dgHmacKeys = parseApprovalHmacKeys(process.env.APPROVAL_HMAC_KEYS);
|
|
779
843
|
// DURABLE_APPROVAL 既是本域字段,也是直连门的硬前置 —— 那条前置的理由与断言在装配层的跨域不变量段。
|
|
780
844
|
const durableApproval = boolEnv("DURABLE_APPROVAL", false);
|
|
845
|
+
// [2380] core 5.0.0 RB-476:approval 名单里「永不匹配」的名字**装配期拒启**(带修正指引)。core 自己的
|
|
846
|
+
// prepare 门(config.legacy_tool_name)在提交期才响——boot 期先拒,部署带失效名单不启动而不是首任务炸。
|
|
847
|
+
// 名单 RAW 直传(canonicalToolName 折叠面已随 core 退役,见 approval.ts);判据单点见
|
|
848
|
+
// {@link findUnmatchableToolNames}(env / 中心下发 / per-request 三腿共用同一条)。
|
|
849
|
+
const rejectUnmatchableToolNames = (envName, names) => {
|
|
850
|
+
const bad = findUnmatchableToolNames(names);
|
|
851
|
+
if (bad.length > 0)
|
|
852
|
+
throw new Error(formatUnmatchableToolNames(envName, bad));
|
|
853
|
+
return names;
|
|
854
|
+
};
|
|
781
855
|
return {
|
|
782
|
-
approvalRequire: csv("APPROVAL_REQUIRE"),
|
|
783
|
-
approvalDeny: csv("APPROVAL_DENY"),
|
|
784
|
-
approvalPollMs: Number(env("APPROVAL_POLL_MS", "1500")),
|
|
856
|
+
approvalRequire: rejectUnmatchableToolNames("APPROVAL_REQUIRE", csv("APPROVAL_REQUIRE")),
|
|
857
|
+
approvalDeny: rejectUnmatchableToolNames("APPROVAL_DENY", csv("APPROVAL_DENY")),
|
|
785
858
|
durableApproval,
|
|
786
859
|
resourceSuspend: boolEnv("RESOURCE_SUSPEND", false),
|
|
787
860
|
resourceSuspendTtlSec: Math.max(0, numEnv("RESOURCE_SUSPEND_TTL_SEC", "0")), // 0 ⇒ core default (30d)
|
|
788
861
|
approvalAutoBudget: Math.min(10000, Math.max(0, numEnv("APPROVAL_AUTO_BUDGET", "0"))), // clamp [0,10000]; 0 = off
|
|
789
|
-
approvalNeverAuto: csv("APPROVAL_NEVER_AUTO"),
|
|
862
|
+
approvalNeverAuto: rejectUnmatchableToolNames("APPROVAL_NEVER_AUTO", csv("APPROVAL_NEVER_AUTO")),
|
|
790
863
|
approvalHmacKeys: dgHmacKeys, // D-G: WIRED (see the field's JSDoc); empty ⇒ inactive, not unimplemented
|
|
791
864
|
directApprovalDoor,
|
|
792
865
|
// ③ sensitive-path write deny set: unset = core's recommended set; explicit value = full replacement
|
|
@@ -910,11 +983,10 @@ function parseAuthDomain(ctx) {
|
|
|
910
983
|
.map((s) => [s.slice(0, s.indexOf("=")).trim(), s.slice(s.indexOf("=") + 1).trim()])
|
|
911
984
|
.filter(([tok, sys]) => tok.length > 0 && sys.length > 0));
|
|
912
985
|
return {
|
|
913
|
-
//
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
bindHostSource: process.env.BIND_HOST ? "BIND_HOST" : process.env.HOST ? "HOST" : undefined,
|
|
986
|
+
// [2354]:HOST 读取臂已删(zsh 恒设 HOST=机器名,不可墓碑——静默不读;cli/桌面 [2053] 起已传
|
|
987
|
+
// BIND_HOST)。绑址唯一口=BIND_HOST;空串=未设。
|
|
988
|
+
bindHost: process.env.BIND_HOST || undefined,
|
|
989
|
+
bindHostSource: process.env.BIND_HOST ? "BIND_HOST" : undefined,
|
|
918
990
|
authToken: process.env.SERVICE_AUTH_TOKEN,
|
|
919
991
|
authTokens,
|
|
920
992
|
allowUnauthedWrites: boolEnv("ALLOW_UNAUTHED_WRITES", false),
|
|
@@ -1210,35 +1282,16 @@ function parseIntegrationsDomain() {
|
|
|
1210
1282
|
// 编码产品出厂态对标 CC 出厂态,通用域中性 persona 用 DEFAULT_SCENARIO=default 显式选回。
|
|
1211
1283
|
defaultScenario: env("DEFAULT_SCENARIO", "code"),
|
|
1212
1284
|
skillsDir: env("SKILLS_DIR", defaultSkillsDir()),
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
// 开 issue 工具:默认开到 OA 系统仓(AI-Only/oa-asset-system),写权限 token 走独立 env。
|
|
1216
|
-
oaIssue: process.env.OA_ISSUE_TOKEN
|
|
1217
|
-
? {
|
|
1218
|
-
// npm 卫生纪律:不再烤内网 git 主机缺省 — 开了 OA_ISSUE_TOKEN 就必须给 host(fail-loud)。
|
|
1219
|
-
baseUrl: (() => {
|
|
1220
|
-
const u = process.env.OA_ISSUE_BASEURL ?? process.env.GIT_API_BASEURL;
|
|
1221
|
-
if (!u)
|
|
1222
|
-
throw new Error("OA_ISSUE_TOKEN is set but no OA_ISSUE_BASEURL / GIT_API_BASEURL — the issue tool needs a git host");
|
|
1223
|
-
return u;
|
|
1224
|
-
})(),
|
|
1225
|
-
owner: env("OA_ISSUE_OWNER", "AI-Only"),
|
|
1226
|
-
repo: env("OA_ISSUE_REPO", "oa-asset-system"),
|
|
1227
|
-
token: env("OA_ISSUE_TOKEN"),
|
|
1228
|
-
defaultLabels: csv("OA_ISSUE_LABELS").map(Number).filter((n) => Number.isInteger(n)),
|
|
1229
|
-
}
|
|
1230
|
-
: undefined,
|
|
1285
|
+
// [2354] clay 令:OA 场景整体退役(oa-tools/oa 场景/OA 轮询审批车道随 5.0.0 全清)——
|
|
1286
|
+
// OA_* env 全族进 RETIRED_ENVS 墓碑(在场即拒启),此处零读取。
|
|
1231
1287
|
// sema-registry (control plane) URL/token/worker. The orchestrator renamed the worker-injected env from
|
|
1232
|
-
// CONFIG_CENTER_*
|
|
1233
|
-
|
|
1234
|
-
// fallback — and keep working after the orchestrator drops the legacy CONFIG_CENTER_* names. Pure config
|
|
1235
|
-
// plumbing: no API/auth/task-logic change.
|
|
1236
|
-
configCenter: (process.env.SEMA_REGISTRY_URL || process.env.CONFIG_CENTER_URL)
|
|
1288
|
+
// [2354]:CONFIG_CENTER_* 双读已删(墓碑在 rejectRetiredEnvs);SEMA_REGISTRY_* 唯一。
|
|
1289
|
+
configCenter: process.env.SEMA_REGISTRY_URL
|
|
1237
1290
|
? {
|
|
1238
|
-
baseUrl:
|
|
1239
|
-
token: process.env.SEMA_REGISTRY_TOKEN ||
|
|
1240
|
-
dryRun:
|
|
1241
|
-
worker: process.env.SEMA_REGISTRY_WORKER ||
|
|
1291
|
+
baseUrl: env("SEMA_REGISTRY_URL"),
|
|
1292
|
+
token: process.env.SEMA_REGISTRY_TOKEN || "",
|
|
1293
|
+
dryRun: process.env.SEMA_REGISTRY_DRY_RUN === "true",
|
|
1294
|
+
worker: process.env.SEMA_REGISTRY_WORKER || undefined,
|
|
1242
1295
|
}
|
|
1243
1296
|
: undefined,
|
|
1244
1297
|
configProvider: process.env.CONFIG_PROVIDER || undefined,
|
|
@@ -1254,7 +1307,7 @@ const MODEL_PLANE_GROUP_KEYS = [
|
|
|
1254
1307
|
"modelApiKeyEnv", "modelApiKeys", "modelQuotaWeights", "tiers", "projects", "roles", "cascadeLadder", "degrade",
|
|
1255
1308
|
];
|
|
1256
1309
|
const APPROVAL_GROUP_KEYS = [
|
|
1257
|
-
"approvalRequire", "approvalDeny", "
|
|
1310
|
+
"approvalRequire", "approvalDeny", "approvalTimeoutSec", "approvalAutoBudget", "approvalNeverAuto",
|
|
1258
1311
|
"approvalHmacKeys", "durableApproval", "directApprovalDoor", "directDoorActive", "resourceSuspend",
|
|
1259
1312
|
"resourceSuspendTtlSec", "askQuestionEnabled", "toolApprovalEnabled", "mcpElicitation", "sensitiveWritePatterns",
|
|
1260
1313
|
"manualModeShellGate",
|
|
@@ -1286,7 +1339,7 @@ const LIMITS_HTTP_GROUP_KEYS = [
|
|
|
1286
1339
|
const OBSERVABILITY_GROUP_KEYS = ["metricsToken", "traceToken", "toolTrace", "traceThinking", "logLevel", "otel"];
|
|
1287
1340
|
const INTEGRATIONS_GROUP_KEYS = [
|
|
1288
1341
|
"pluginsAllowHosts", "mcpServers", "configBootFetchBudgetMs", "gitApiBaseUrl", "gitApiToken", "defaultScenario",
|
|
1289
|
-
"skillsDir", "
|
|
1342
|
+
"skillsDir", "configCenter", "configProvider", "configLocalDir",
|
|
1290
1343
|
];
|
|
1291
1344
|
/** 组名 → 该组取景的平铺键(introspection 面:测试用它钉「每个平铺键恰好被一组取景」)。 */
|
|
1292
1345
|
export const CONFIG_GROUP_KEYS = {
|
|
@@ -1339,6 +1392,7 @@ export function attachConfigGroups(flat) {
|
|
|
1339
1392
|
return flat;
|
|
1340
1393
|
}
|
|
1341
1394
|
export function loadConfig() {
|
|
1395
|
+
rejectRetiredEnvs(); // [2354] 退役 env 墓碑:在场即拒启带新名指引
|
|
1342
1396
|
CONFIG_WARNINGS.length = 0; // repeated loadConfig() calls (test setup) must not accumulate stale warnings
|
|
1343
1397
|
CONFIG_NOTICES.length = 0;
|
|
1344
1398
|
CONFIG_KNOBS.clear(); // the polarity table describes THIS load, never a previous one's env
|
|
@@ -1379,8 +1433,8 @@ export function loadConfig() {
|
|
|
1379
1433
|
const { principalJwtPubkeys, principalJwtIss, principalJwtAud, operatorPrincipals: dgOperators, authTokens } = auth;
|
|
1380
1434
|
const { enabled: imageBakesEnabled, runnerPrincipal: bakeRunnerPrincipal } = orchestration.imageBakes;
|
|
1381
1435
|
// 🔴 the direct-door crypto gate lives ONLY in the durable (checkpointStore) /decide branch — so DURABLE_APPROVAL
|
|
1382
|
-
// is a HARD precondition. Without it, checkpointStore is undefined
|
|
1383
|
-
//
|
|
1436
|
+
// is a HARD precondition. Without it, checkpointStore is undefined and there is NO decide path at all
|
|
1437
|
+
// ([2354] A-5:legacy trusted-header /decide 车道已在 5.0.0 退役——本不变量从「防旁路」变成「防死门」,保留)。
|
|
1384
1438
|
const directDoorActive = directApprovalDoor && dgDurable && dgHmacKeys.length > 0 && principalJwtPubkeys.length > 0 && !!principalJwtIss && !!principalJwtAud;
|
|
1385
1439
|
// 🔴 boot invariant (D-G §3): a half-configured direct door is the WORST state (looks on, verifies nothing) — and
|
|
1386
1440
|
// an empty OPERATOR_PRINCIPALS makes isOperator() true-for-all (= cross-tenant escalation). Refuse to start.
|
|
@@ -54,7 +54,7 @@ export interface FleetTaskRow {
|
|
|
54
54
|
status: FleetTaskStatus;
|
|
55
55
|
/** core 1.367 δ([1514]/[1515]④):launch 时刻 epoch ms(revive 行=本 revive 周期 wake 时刻)——
|
|
56
56
|
* cli 的 elapsed 锚直出(比 server 端 elapsedMs 快照更稳,消费方自算不漂)。ADDITIVE / tolerate-absent
|
|
57
|
-
* (a* 车道 spawn
|
|
57
|
+
* (a* 车道 spawn 即带;诚实缺席——回落 server 收帧时刻的臂已随 [2354] 删,floor ^4.0.0 下 startedAt 恒在)。 */
|
|
58
58
|
startedAt?: number;
|
|
59
59
|
elapsedMs?: number;
|
|
60
60
|
tokens?: number;
|
package/dist/fleet/fleet-bus.js
CHANGED
|
@@ -21,7 +21,6 @@
|
|
|
21
21
|
* replica-local). A cross-replica fleet roll-up is a fleet-token-gated trace-API concern (separate), not this.
|
|
22
22
|
*/
|
|
23
23
|
import { EventEmitter } from "node:events";
|
|
24
|
-
import { canonicalToolName } from "@sema-agent/core";
|
|
25
24
|
import { redactSecrets } from "../trace/redact.js";
|
|
26
25
|
/**
|
|
27
26
|
* The process-local fleet aggregation bus. Holds the current active set + fans out deltas to SSE subscribers.
|
|
@@ -231,7 +230,9 @@ export function fleetRunPublisher(bus, run) {
|
|
|
231
230
|
// `totalInputTokens`,旧核帧(尚未升级到 3.0.0、该键缺席)回落 `inputTokens`(防御性:本引擎恒 ≥3.0.0
|
|
232
231
|
// 时两键并存;异常帧宁少算不 NaN)。Display-only(leader fleet 行的 token 数);billing(costMicroUsd)+
|
|
233
232
|
// context/compaction 走 totalTokens,不受影响;child 行走 task_progress.usage.totalTokens(上面的早退臂)。
|
|
234
|
-
|
|
233
|
+
// [2354] 兼容面全清:旧核帧回落臂(?? u.inputTokens)已删——floor ^4.0.0 下 totalInputTokens 恒在;
|
|
234
|
+
// 键缺席=越契约帧,按 0 计(宁少算不借异语义键充数)。
|
|
235
|
+
return (u.totalInputTokens ?? 0) + (u.outputTokens ?? 0);
|
|
235
236
|
};
|
|
236
237
|
return {
|
|
237
238
|
onStart() {
|
|
@@ -283,7 +284,7 @@ export function fleetRunPublisher(bus, run) {
|
|
|
283
284
|
// PascalCase double-belt (core 1.176): canonicalize so a legacy snake CONTROL verb (e.g. a
|
|
284
285
|
// pre-1.176 emit / a stray report_blocked) renders as its CC name (ReportBlocked) and the shell's PascalCase
|
|
285
286
|
// suppression Set still hides it — never re-leaking a control verb as fleet-row activity.
|
|
286
|
-
bus.publishTask({ id: run.runId, description:
|
|
287
|
+
bus.publishTask({ id: run.runId, description: ev.toolName }); // RAW(5.0.0):live 名恒 canonical
|
|
287
288
|
}
|
|
288
289
|
},
|
|
289
290
|
onForwardEvent(ev) {
|
|
@@ -595,9 +596,10 @@ export function fleetBackgroundChildPublisher(bus, log) {
|
|
|
595
596
|
...(inheritParent && tomb?.resolvedParentId !== undefined ? { resolvedParentId: tomb.resolvedParentId } : {}),
|
|
596
597
|
// session-scoped: registry owner IS the host sessionId (design/129 owner key); fork spawns also carry
|
|
597
598
|
// the child's uuid sessionId — that is the a*↔uuid cross-system anchor, NOT the host session, so it is not used here.
|
|
598
|
-
// [1522] LOW4
|
|
599
|
-
//
|
|
600
|
-
|
|
599
|
+
// [1522] LOW4 root-first。[2378]/[2380] RB-478 到货:三条 revive 发射腿全部无条件带
|
|
600
|
+
// `root ?? parent` 链 ⇒ `?? e.owner` 回落臂成纯死臂,删([2370] 补审时显式排除在全清宣称外
|
|
601
|
+
// 等的就是这一天)。rootSessionId 缺席=不打 host 标(over-filter 方向,durable drain 兜)。
|
|
602
|
+
...(e.sessionScoped && e.owner && e.rootSessionId ? { hostSessionId: e.rootSessionId } : {}),
|
|
601
603
|
// 🔴 scope DOMAIN mapping: core's registry scope is `ctx.principal ?? deployment scope` —
|
|
602
604
|
// UNDEFINED on a single-user no-principal deployment — while the service fleet domain keys the
|
|
603
605
|
// no-principal caller as "default" (`gatedPrincipal ?? "default"`, streamFleet's callerScope). Without
|
|
@@ -606,8 +608,9 @@ export function fleetBackgroundChildPublisher(bus, log) {
|
|
|
606
608
|
// a principal exists, so the map is exact.
|
|
607
609
|
tenantScope: e.scope ?? "default",
|
|
608
610
|
sessionScoped: e.sessionScoped,
|
|
609
|
-
//
|
|
610
|
-
|
|
611
|
+
// [2354] 兼容面全清:旧 core 帧「回落收帧时刻」臂已删——floor ^4.0.0 下 startedAt 恒在;
|
|
612
|
+
// 缺席=诚实不发(行键 optional,消费端本就容忍缺席)。
|
|
613
|
+
...(e.startedAt !== undefined ? { spawnedAt: e.startedAt } : {}),
|
|
611
614
|
...(e.rootSessionId ? { rootSessionId: e.rootSessionId } : {}),
|
|
612
615
|
...(e.parentToolCallId ? { parentToolCallId: e.parentToolCallId } : {}), // P1-2(core 1.432,12 发射点全带)
|
|
613
616
|
...(e.sessionId ? { aliasUuid: e.sessionId } : {}), // codex R4(M-B):uuid↔a* 别名(fork spawn 带 forkedId)
|
|
@@ -617,15 +620,9 @@ export function fleetBackgroundChildPublisher(bus, log) {
|
|
|
617
620
|
// core 帧的 parentSessionId(发起会话,1.350 声明字段——R2:无 runStore 的瞬态 sync 部署没有宿主
|
|
618
621
|
// fleet 行,行查 fallback 必空);②宿主行 sessionId 查表(同租户)兜底。
|
|
619
622
|
...(e.workflowRunId && !(e.sessionScoped && e.owner)
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
return { hostSessionId: e.rootSessionId };
|
|
624
|
-
if (e.parentSessionId)
|
|
625
|
-
return { hostSessionId: e.parentSessionId };
|
|
626
|
-
const host = e.parentTaskId ? bus.snapshot().tasks.find((r) => r.id === e.parentTaskId && r.scope === (e.scope ?? "default")) : undefined;
|
|
627
|
-
return host?.sessionId ? { hostSessionId: host.sessionId } : {};
|
|
628
|
-
})()
|
|
623
|
+
// [2378]/[2380] RB-478:wa* 三级回落(root→parentSessionId→行查表)收单级——core 三条发射腿
|
|
624
|
+
// 已无条件带 root 锚,后两级成死臂;缺席=不打标(over-filter,durable 兜),不再猜。
|
|
625
|
+
? (e.rootSessionId ? { hostSessionId: e.rootSessionId } : {})
|
|
629
626
|
: {}),
|
|
630
627
|
// [1493] cross-session isolation: a NON-session-scoped, non-wa* bg child (owner = the run taskId — the
|
|
631
628
|
// norm when backgroundScope!="session", i.e. every multi-tenant deployment, and any local path where the
|
|
@@ -654,18 +651,11 @@ export function fleetBackgroundChildPublisher(bus, log) {
|
|
|
654
651
|
// top-level/nested discriminator) on the spawn event — asked as a core seam follow-up ([1493]).
|
|
655
652
|
// core 1.367 δ:[1493] fable5-R1 注里请的 root fix **到货**——spawn 帧显式带 rootSessionId
|
|
656
653
|
// (固定点语义,嵌套孙代恒=root shell 会话),信任源直用;alias 反查臂降为旧 core 帧回落。
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
for (const pm of meta.values()) {
|
|
663
|
-
if (pm.aliasUuid === e.parentSessionId && (pm.tenantScope ?? "default") === childScope) {
|
|
664
|
-
return pm.hostSessionId ? { hostSessionId: pm.hostSessionId } : {}; // nested: inherit root (or stay untagged → Part B)
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
return { hostSessionId: e.parentSessionId }; // top-level: parentSessionId IS the shell root session
|
|
668
|
-
})()
|
|
654
|
+
// [2354] 兼容面全清:alias 反查臂(旧 core 帧无 rootSessionId 时经 meta 反查 parentSessionId)已删——
|
|
655
|
+
// floor ^4.0.0 下 spawn 帧恒带 rootSessionId(core 1.367 δ 固定点语义);缺席=不打 host 标,
|
|
656
|
+
// 失败方向仍是 over-filtering(durable inbox/stream-open drain 兜),永不 cross-delivery。
|
|
657
|
+
...(!(e.sessionScoped && e.owner) && !e.workflowRunId && e.rootSessionId
|
|
658
|
+
? { hostSessionId: e.rootSessionId }
|
|
669
659
|
: {}),
|
|
670
660
|
};
|
|
671
661
|
remember(e.taskId, m);
|
|
@@ -719,9 +709,9 @@ export function fleetBackgroundChildPublisher(bus, log) {
|
|
|
719
709
|
}
|
|
720
710
|
const tokens = sumUsage(e.usage);
|
|
721
711
|
const name = e.name ? redactSecrets(e.name) : undefined;
|
|
722
|
-
// [1364]③ K-7 换位:TYPE 列取 tick 帧的行级 `agentType`(core 1.350
|
|
723
|
-
//
|
|
724
|
-
const agentType = e.agentType ? redactSecrets(e.agentType) :
|
|
712
|
+
// [1364]③ K-7 换位:TYPE 列取 tick 帧的行级 `agentType`(core 1.350 定谳)。[2354] 兼容面全清:
|
|
713
|
+
// 「缺省回落 name」旧 core 兼容臂已删——floor ^4.0.0 下 agentType 恒在;缺席=诚实不发(行键 optional)。
|
|
714
|
+
const agentType = e.agentType ? redactSecrets(e.agentType) : undefined;
|
|
725
715
|
// The sink tick carries core's currentAction (its only attachment point today) —
|
|
726
716
|
// UNTRUSTED (tool argument head) → redact, same discipline as name. Additive; absent until a tool runs.
|
|
727
717
|
const currentAction = e.currentAction ? redactSecrets(e.currentAction) : undefined;
|
|
@@ -838,7 +828,9 @@ export function fleetBackgroundChildPublisher(bus, log) {
|
|
|
838
828
|
handleSpawn(e);
|
|
839
829
|
return;
|
|
840
830
|
}
|
|
841
|
-
|
|
831
|
+
// [2354] 补审 F2:lazy-mint 不再铸 spawnedAt: Date.now() 假锚(与 spawn 臂同口径——缺 launch 锚=
|
|
832
|
+
// 诚实缺席,行键 optional;tick/terminal 先到=restart/丢 spawn 边缘,收帧时刻不是 launch 时刻)。
|
|
833
|
+
const m = meta.get(e.taskId) ?? { sessionScoped: e.sessionScoped, tenantScope: e.scope ?? "default" }; // scope domain map holds on the lazily-minted path too([1338]④ 首见起表);F2(2026-07-30 复审):lazy-mint 曾硬编码 "default",scoped 部署下 claim 落错租户键 ⇒ 让位失效退回双生行
|
|
842
834
|
if (!meta.has(e.taskId)) {
|
|
843
835
|
remember(e.taskId, m); // tick/terminal without a seen spawn (restart/eviction edge) — row minted lazily
|
|
844
836
|
dlog("bg_child_event", { kind: `${e.kind}-lazy-mint`, taskId: e.taskId, sessionScoped: e.sessionScoped });
|
package/dist/fleet-client.js
CHANGED
|
@@ -190,7 +190,7 @@ export function startFleetClientFromEnv(cfg, opts) {
|
|
|
190
190
|
if (!cc?.baseUrl || !cc.token || !address)
|
|
191
191
|
return undefined;
|
|
192
192
|
if (!cc.worker) {
|
|
193
|
-
opts.logger?.warn("fleet_client_no_worker_scope", { note: "FLEET_ADVERTISE_ADDRESS set but
|
|
193
|
+
opts.logger?.warn("fleet_client_no_worker_scope", { note: "FLEET_ADVERTISE_ADDRESS set but SEMA_REGISTRY_WORKER missing — announce needs the worker (dispatch key); fleet client not started" });
|
|
194
194
|
return undefined;
|
|
195
195
|
}
|
|
196
196
|
return startFleetClient({ ...opts, center: { baseUrl: cc.baseUrl, token: cc.token, worker: cc.worker }, advertiseAddress: address });
|
|
@@ -38,6 +38,8 @@ export declare function resumeEntryForGate(kind: string, ids: {
|
|
|
38
38
|
*/
|
|
39
39
|
export interface ActiveRunConflictDoneResult {
|
|
40
40
|
status: "failed";
|
|
41
|
+
/** [2373]C-1:与 409 体同一机器码——流腿客户端凭它认拒绝,禁按 byte-frozen 文案匹配。 */
|
|
42
|
+
errorCode: "conflict.session_active_run";
|
|
41
43
|
errorMessage: string;
|
|
42
44
|
activeTaskId: string | null;
|
|
43
45
|
activeTaskStatus?: string;
|
|
@@ -36,6 +36,7 @@ export function resumeEntryForGate(kind, ids) {
|
|
|
36
36
|
export function toDoneFrameResult(body) {
|
|
37
37
|
return {
|
|
38
38
|
status: "failed",
|
|
39
|
+
errorCode: body.errorCode,
|
|
39
40
|
errorMessage: body.error,
|
|
40
41
|
activeTaskId: body.activeTaskId,
|
|
41
42
|
...(body.activeTaskStatus !== undefined ? { activeTaskStatus: body.activeTaskStatus } : {}),
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* 路由(前缀 `/v1/approvals` 与 `/v1/assistant`):
|
|
5
5
|
* · durable 腿(接了 checkpointStore 时优先):list / stream(SSE 原生推送)/ decide|answer / preempt /
|
|
6
6
|
* resume / plan_review;
|
|
7
|
-
* · legacy 腿(
|
|
7
|
+
* · legacy 腿(approvalStore 轮询车道)已于 5.0.0 整体退役([2354]/[2356] A-5)——无 checkpointStore 时
|
|
8
|
+
* `/v1/approvals` 落 404(诚实缺席),不再有 trusted-header 决裁面。
|
|
8
9
|
*
|
|
9
10
|
* 所有会**烧模型**的续跑都经 `ctx.legs.*`(resumeCheckpoint / resumePreempted / resumePlanReview)走 resume
|
|
10
11
|
* 家族的同一条腿:lease admission、markResuming CAS、写 run log、发 fleet 帧都在腿里,本域只做入站鉴权/形状门。
|