@sema-agent/server 7.38.0 → 7.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/USAGE.md +9 -0
- package/deploy/sema-up/chart/values.yaml +2 -1
- package/dist/boot/config-center.d.ts +8 -0
- package/dist/boot/config-center.js +27 -0
- package/dist/boot/runner-deps.d.ts +7 -2
- package/dist/boot/runner-deps.js +6 -0
- package/dist/config-center/mcp-revocation.d.ts +57 -0
- package/dist/config-center/mcp-revocation.js +90 -0
- package/dist/config-center/restart-signal.d.ts +6 -0
- package/dist/config-center/restart-signal.js +25 -1
- package/dist/http/routes/diagnostics.js +2 -0
- package/dist/http/routes/sessions.js +3 -1
- package/dist/http/routes/workflows.js +3 -1
- package/dist/http/server.d.ts +10 -0
- package/dist/main.js +8 -1
- package/dist/question.d.ts +8 -0
- package/dist/question.js +5 -1
- package/dist/run-local.js +2 -0
- package/dist/trace/project.d.ts +3 -0
- package/dist/trace/project.js +12 -3
- package/package.json +2 -2
package/USAGE.md
CHANGED
|
@@ -424,6 +424,15 @@ READ_DENY_PATTERNS='[{"pattern":"**/secrets/**"},{"pattern":".ssh","caseSensitiv
|
|
|
424
424
|
⚠️ 本地 `config.d/` 车道今天**接不上**这一域(registry-core 的可移植域表里没有它),只有
|
|
425
425
|
`CONFIG_PROVIDER=remote` 的部署走得通。
|
|
426
426
|
|
|
427
|
+
- **MCP 撤销腿(7.39 起,core design/338)**:MCP 服务器 mount 仍是 restart-to-apply(新增/改址要
|
|
428
|
+
restart 才生效),但**从 enabled 集删除一个服务器即时生效**——refresh 拍收货后,被删服务器的
|
|
429
|
+
MCP 调用当场按 coded 拒绝 `mcp.server_revoked` 结算(known-not-executed,引擎每次派发前探询
|
|
430
|
+
台账,不缓存)。因此 `/health` 的 `restart.reasons` 对**纯删除向**不再报 `mcp`(签了就是为一个
|
|
431
|
+
已生效的变更滚动重启 fleet);删除+新增/改址混合拍照签。重新把服务器加回 enabled 集=解除撤销。
|
|
432
|
+
当前被撤名单可从 `GET /v1/diagnostics/wiring` 的 `mcpRevocations.revoked` 读(`null`=本进程无
|
|
433
|
+
配置管道);`GET /v1/sessions/:id/mcp` 面板与执行面同一台账(被撤服务器的工具不再展示)。
|
|
434
|
+
纯 env 配置的 `MCP_SERVERS` 部署无中心撤销语义,行为逐字不变。
|
|
435
|
+
|
|
427
436
|
**可选 — MCP 入站表单(elicitation,E23):默认关**
|
|
428
437
|
|
|
429
438
|
```bash
|
|
@@ -77,7 +77,8 @@ registry:
|
|
|
77
77
|
nodePort: 30300
|
|
78
78
|
storageSize: 2Gi
|
|
79
79
|
storageClass: "" # 空=集群默认 SC
|
|
80
|
-
|
|
80
|
+
# [4824] S10 P1:默认管理员名必须是中性值——个人标识串作生产默认值=内部标识外溢(cli 点名案)。
|
|
81
|
+
adminUser: admin
|
|
81
82
|
adminPassword: "" # REQUIRED(kube-up 注入)
|
|
82
83
|
sessionSecret: "" # REQUIRED
|
|
83
84
|
pullToken: "" # REQUIRED
|
|
@@ -55,6 +55,14 @@ export interface ConfigCenterRuntime {
|
|
|
55
55
|
}): void;
|
|
56
56
|
/** #131-2:停刷新环(hardShutdown 收尾链;幂等,未起环时 no-op)。 */
|
|
57
57
|
stopRefreshLoop(): void;
|
|
58
|
+
/** #324(core 5.50 design/338):mid-turn MCP 撤销台账读口,喂 `RunnerDeps.mcpRevocations` 席。
|
|
59
|
+
* **取走即声明接线**——调用本方法后,restart 信号的 mcp 片对纯删除向豁免(台账即时承接);
|
|
60
|
+
* 不取 ⇒ 旧 restart 语义逐字保留(fail-closed)。 */
|
|
61
|
+
takeMcpRevocations(): import("../config-center/mcp-revocation.js").McpRevocationLedger;
|
|
62
|
+
/** #324 诊断投影:当前被撤销的 MCP 服务器名单;纯 env 部署(无配置管道)= undefined(additive 纪律)。 */
|
|
63
|
+
mcpRevocationState(): {
|
|
64
|
+
revoked: string[];
|
|
65
|
+
} | undefined;
|
|
58
66
|
/** 晚绑取值:refresh 热应用会整个换引用(hook LLM / resolveSpec 每次现取)。 */
|
|
59
67
|
getKeyResolver(): ((model: ModelKeyRef) => Promise<{
|
|
60
68
|
apiKey: string;
|
|
@@ -47,6 +47,7 @@ import { createConfigProvider, raceBootFetch, BOOT_FETCH_DEFERRED } from "../con
|
|
|
47
47
|
import { createKeyResolver } from "../key-resolver.js";
|
|
48
48
|
import { ensureSealedKeyStore, reportExecutionPublicKey } from "../sealed-key.js";
|
|
49
49
|
import { applyEffective, applyCenterReadFace, mutateInPlace, logEffectiveDiff, applyCenterSkills, resolveMcpServers, resolveA2aPeers, restartReasons, modelPlaneChanged, planeHasActiveTiers, fetchPromptArtifact } from "../config-center/facade.js";
|
|
50
|
+
import { createMcpRevocationLedger, enabledMcpEntries } from "../config-center/mcp-revocation.js";
|
|
50
51
|
import { SHA256_HEX_RE } from "../digest-form.js";
|
|
51
52
|
import { createConfigApplyLedger } from "../config-center/apply-ledger.js"; // #322 世代账
|
|
52
53
|
export async function createConfigCenterRuntime(ctx) {
|
|
@@ -550,16 +551,31 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
550
551
|
// (MODEL_DEGRADE_TO / MODEL_DEGRADE_REACTIVE)开关,而它焊死的是 CENTER 目录里那条模型的路由面。读成
|
|
551
552
|
// 函数而非常量:`config.degrade` 今天由 env 独占(applyEffective 不写它),但若哪天中心接管这面,这里
|
|
552
553
|
// 自动跟着走,不会退化成 boot 期快照。车道关(默认)⇒ ctx 空 ⇒ 该片恒 null ⇒ 零行为变化。
|
|
554
|
+
// #324(core 5.50 design/338):mid-turn MCP 撤销台账。铸在这里(写路径归本 runtime:boot bake 铸
|
|
555
|
+
// baseline、refresh commit 喂 diff),读口经 `takeMcpRevocations()` 外借给 RunnerDeps 席。
|
|
556
|
+
// ⚠️ **取走即声明接线**:restart 豁免(纯删除向不签 mcp)只在 `mcpRevocationWired` 后生效——把豁免与
|
|
557
|
+
// 承接绑在同一动作上,main 若哪天删了接线行,豁免自动关回旧 restart 语义(fail-closed,#157;
|
|
558
|
+
// 反例=独立布尔,两处各写一遍必漂移,漂移方向正是「没人承接删除却不再签 restart」的静默 fail-open)。
|
|
559
|
+
const mcpRevocations = createMcpRevocationLedger((ev) => logger.info("mcp_revocation_ledger", { ...(ev.revoked.length > 0 ? { revoked: ev.revoked } : {}), ...(ev.restored.length > 0 ? { restored: ev.restored } : {}) }));
|
|
560
|
+
let mcpRevocationWired = false;
|
|
553
561
|
const restartCtx = () => ({
|
|
554
562
|
...(config.degrade?.reactive ? { reactiveDegradeTo: config.degrade.to } : {}),
|
|
555
563
|
// #A4:env 占住的 readFace 键(boot 期一次性事实,env 不会在进程内变)。
|
|
556
564
|
...(readFaceEnvHeld.length > 0 ? { readFaceEnvHeld } : {}),
|
|
565
|
+
// codex F2 双门:席被取走(wired)**且** boot bake 真铸过 baseline(mount 真身在案)才豁免——
|
|
566
|
+
// boot 超时/纯 env 形的 mount 不是中心集,撤销腿承接不了删除,豁免必须关死走旧 restart 语义。
|
|
567
|
+
...(mcpRevocationWired && mcpRevocations.hasBaseline() ? { mcpRevocationLive: true } : {}),
|
|
557
568
|
});
|
|
558
569
|
// #131-2:60s 刷新环的句柄提到 runtime 闭包层——stopRefreshLoop(hardShutdown 收尾链)要能清它。
|
|
559
570
|
let ccTimer;
|
|
560
571
|
return {
|
|
561
572
|
providerKind: configProvider?.kind,
|
|
562
573
|
promptSource,
|
|
574
|
+
takeMcpRevocations: () => {
|
|
575
|
+
mcpRevocationWired = true; // 取走即声明接线(见铸造点注)——restart 豁免从此拍起生效
|
|
576
|
+
return mcpRevocations;
|
|
577
|
+
},
|
|
578
|
+
mcpRevocationState: () => (configProvider ? mcpRevocations.view() : undefined), // 纯 env 形没有中心撤销语义 ⇒ 诚实缺席
|
|
563
579
|
getKeyResolver: () => keyResolver,
|
|
564
580
|
getCenterPrompts: () => centerPrompts,
|
|
565
581
|
modelReady: () => modelReadyState.ready,
|
|
@@ -696,6 +712,11 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
696
712
|
}
|
|
697
713
|
if (effective?.mcp)
|
|
698
714
|
config.mcpServers = resolveMcpServers(effective.mcp, logger);
|
|
715
|
+
// #324:撤销台账的 baseline 拍 = boot bake 的 enabled 条目表(mount 真身与台账「此前」同源单点;
|
|
716
|
+
// codex F1 修:带指纹,重加同名不同形不解除撤销)。域缺席/boot 超时 ⇒ null ⇒ 台账不铸 baseline
|
|
717
|
+
// (env 型 mcpServers 部署没有中心撤销语义)——此时 hasBaseline()=false,restart 豁免关死
|
|
718
|
+
// (codex F2 修:迟到 boot 采用的候选集≠mount 真身,**刻意不喂**,该形走旧 restart 语义收敛)。
|
|
719
|
+
mcpRevocations.applyEnabledEntries(enabledMcpEntries(effective?.mcp), { isBaseline: true });
|
|
699
720
|
// DESIGN-269 车1 件1:A2A peers ride the SAME restart-to-apply line as MCP (one center pull, one
|
|
700
721
|
// resolution, no hot swap). Absent `a2a` domain ⇒ the key is never written ⇒ the leg does not exist.
|
|
701
722
|
if (effective?.a2a)
|
|
@@ -903,6 +924,12 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
903
924
|
mutateInPlace(pricing, buildPricing(config.models)); // hot: cost/model changes; Runner reads this.deps.pricing live
|
|
904
925
|
keyResolver = createKeyResolver(config.modelApiKeyEnv, process.env, config.modelApiKeys); // hot: per-model key add/remove/change (env-ref + sealed)
|
|
905
926
|
limitSync?.sync(); // #322 批1:限额座与 config 成对换代(同一条「派生件紧贴 commit」纪律)
|
|
927
|
+
// #324:撤销台账拍(commit 接受即喂,与上面三件派生同族)。删除向由此**即时**生效
|
|
928
|
+
// (core 每次 MCP dispatch 前探 isRevoked)——design/338 要消的「撤销等 restart」窗。
|
|
929
|
+
// 放在 fullyApplied 判之前:mcp 域不在 limits 组,某组被整拒不构成扣住撤销的理由
|
|
930
|
+
// (撤销是收紧向,宁早不晚)。baseline 未铸(boot 超时形)时这一喂只推 seen 集,
|
|
931
|
+
// 恢复判据与 restart 豁免都被 hasBaseline 门关死(codex F2)。
|
|
932
|
+
mcpRevocations.applyEnabledEntries(enabledMcpEntries(r.effective.mcp));
|
|
906
933
|
applyLedger.applied(tickGen, r.effective.version);
|
|
907
934
|
if (planeDeferred) {
|
|
908
935
|
logger.warn("models_tiers_plane_deferred", { version: r.effective.version, note: "tier-frozen Runner: the changed model plane (models/roles/tiers/default) is NOT hot-applied — admission stays on the Runner's generation; restart applies the new plane (models-tiers restart signal rides /health)" });
|
|
@@ -92,6 +92,11 @@ export interface RunnerDepsCtx {
|
|
|
92
92
|
/** #154 车二:持久化权限规则店 provider(core `RunnerDeps.permissionRuleStore`)。缺席 ⇒ 引擎的
|
|
93
93
|
* `permissionRules.storeWired` 如实报 false、`AskRequest.ruleSuggestions` 不铸(诚实缺席)。 */
|
|
94
94
|
permissionRuleStore: RunnerDeps["permissionRuleStore"];
|
|
95
|
+
/** #324(core 5.50 design/338):mid-turn MCP 撤销台账席 —— core 每次 MCP dispatch 前同步探
|
|
96
|
+
* `isRevoked(serverName)`,被撤服务器的调用结算为 coded 拒绝 `mcp.server_revoked`(known-not-executed)。
|
|
97
|
+
* 来源=configCenter.takeMcpRevocations()(取走即声明接线,restart 豁免与承接绑同一动作)。
|
|
98
|
+
* 缺席=undefined=pre-338 语义(纯 env 部署无中心撤销面)。 */
|
|
99
|
+
mcpRevocations: RunnerDeps["mcpRevocations"];
|
|
95
100
|
/**
|
|
96
101
|
* 交接件⑤ —— commit 尾注的署名座(`RunnerDeps.hands.commitCoAuthor`)。
|
|
97
102
|
*
|
|
@@ -121,7 +126,7 @@ export interface RunnerDepsCtx {
|
|
|
121
126
|
}
|
|
122
127
|
/** design/158 A10 留档发现②:main runner `RunnerDeps` 与 main.ts subRunner 字面量之间此前手工重复
|
|
123
128
|
* 的 ~15 个键,类型标注见 {@link createSharedRunnerDeps} 头注。 */
|
|
124
|
-
export type SharedRunnerDeps = Pick<RunnerDeps, "brain" | "readFace" | "readDenyPatterns" | "readDenyBuiltinTiers" | "readDenyBuiltinExclude" | "memoryDelegationEvidence" | "memoryProvenance" | "delegationEntryCaps" | "models" | "roles" | "tiers" | "pricing" | "tracer" | "promptSource" | "executionEnvFactory" | "lspManager" | "backgroundAgentStore" | "mailboxStore" | "rosterStore" | "hooks" | "toolResultStore" | "hands" | "sessionPolicyStore" | "usageWindows" | "usageWindowStore" | "memoryScopeAdmission" | "deploymentMemoryScopes" | "sharedMemoryStores" | "compliancePostureResolver" | "lockedConfig" | "retentionPolicy" | "onNotice">;
|
|
129
|
+
export type SharedRunnerDeps = Pick<RunnerDeps, "brain" | "readFace" | "readDenyPatterns" | "readDenyBuiltinTiers" | "readDenyBuiltinExclude" | "memoryDelegationEvidence" | "memoryProvenance" | "delegationEntryCaps" | "models" | "roles" | "tiers" | "pricing" | "tracer" | "promptSource" | "executionEnvFactory" | "lspManager" | "backgroundAgentStore" | "mailboxStore" | "rosterStore" | "hooks" | "toolResultStore" | "hands" | "sessionPolicyStore" | "usageWindows" | "usageWindowStore" | "memoryScopeAdmission" | "deploymentMemoryScopes" | "sharedMemoryStores" | "compliancePostureResolver" | "lockedConfig" | "retentionPolicy" | "onNotice" | "mcpRevocations">;
|
|
125
130
|
/**
|
|
126
131
|
* design/158 A10 留档发现②(review 2026-07-29,[1543]§三族A 同源修补的延续):main runner 的
|
|
127
132
|
* `RunnerDeps` 字面量(下方 `createRunnerDeps`)与 `main.ts` 里 subRunner 的 `new Runner({...})`
|
|
@@ -150,7 +155,7 @@ export type SharedRunnerDeps = Pick<RunnerDeps, "brain" | "readFace" | "readDeny
|
|
|
150
155
|
* 属性,比再抽一层共享基座更强的同源保证),不重复收纳进这里。
|
|
151
156
|
*/
|
|
152
157
|
/** 基座真实消费的窄面(Pick)——subRunner 调用点(main.ts)只需凑这 13 个字段,不必造全量 ctx。 */
|
|
153
|
-
export type SharedRunnerDepsCtx = Pick<RunnerDepsCtx, "config" | "brain" | "pricing" | "tracer" | "promptSource" | "executionEnvFactory" | "lspManager" | "backgroundAgentStore" | "mailboxStore" | "rosterStore" | "deploymentHooks" | "toolResultStore" | "sessionPolicyStore" | "hands" | "usageWindowStore" | "orgMemoryAdmission" | "sharedMemoryStores" | "logger" | "governanceSeams">;
|
|
158
|
+
export type SharedRunnerDepsCtx = Pick<RunnerDepsCtx, "config" | "brain" | "pricing" | "tracer" | "promptSource" | "executionEnvFactory" | "lspManager" | "backgroundAgentStore" | "mailboxStore" | "rosterStore" | "deploymentHooks" | "toolResultStore" | "sessionPolicyStore" | "hands" | "usageWindowStore" | "orgMemoryAdmission" | "sharedMemoryStores" | "logger" | "governanceSeams" | "mcpRevocations">;
|
|
154
159
|
/**
|
|
155
160
|
* core `EngineNotice` → 结构化 `engine_notice` 行的**唯一**转发体(#240②)。
|
|
156
161
|
*
|
package/dist/boot/runner-deps.js
CHANGED
|
@@ -184,6 +184,12 @@ export function createSharedRunnerDeps(ctx) {
|
|
|
184
184
|
compliancePostureResolver: ctx.governanceSeams.compliancePostureResolver,
|
|
185
185
|
lockedConfig: ctx.governanceSeams.lockedConfig,
|
|
186
186
|
retentionPolicy: ctx.governanceSeams.retentionPolicy,
|
|
187
|
+
// #324(core 5.50 design/338):撤销台账席进**共享基座** —— core 每次 MCP dispatch 前探
|
|
188
|
+
// isRevoked,委托子代跑在另一只 Runner 上,漏挂 subRunner = 子代平面绕过撤销([1543]§三族A 形,
|
|
189
|
+
// 且这条轴的绕过方向是 fail-OPEN:被中心撤掉的服务器在子代腿继续可调)。leader lane 零 MCP mount
|
|
190
|
+
// (`src/leader/wire.ts` 无 MCP 面)⇒ 席不达 leader 结构性零影响(memoryDelegationEvidence 同款登记)。
|
|
191
|
+
// 缺席=undefined=pre-338 语义(纯 env 部署,restart-signal 的删除向豁免也不生效——同一动作绑定)。
|
|
192
|
+
mcpRevocations: ctx.mcpRevocations ? ctx.mcpRevocations : undefined,
|
|
187
193
|
};
|
|
188
194
|
return shared;
|
|
189
195
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #324(core 5.50 design/338 提货件)—— mid-turn MCP 撤销台账:`RunnerDeps.mcpRevocations` 席的宿主实现。
|
|
3
|
+
*
|
|
4
|
+
* 语义(与 core 契约对表,types.d.ts `RunnerDeps.mcpRevocations` 注):
|
|
5
|
+
* · 权威单点在宿主 —— core 每次 MCP dispatch 前**同步**探 `isRevoked(serverName)`,从不缓存答案。
|
|
6
|
+
* · 本台账记「中心**曾发布为 enabled、后从 enabled 集移除**」的服务器名。MCP mount 是 boot-baked
|
|
7
|
+
* (`resolveMcpServers` 只在启动期跑),所以**删除向**在 5.50 前只能等 restart 才生效——这正是
|
|
8
|
+
* design/338 要消的窗:治理面最要紧的动作(撤销一条对外通道)现在即时生效,restart 信号的
|
|
9
|
+
* 删除向豁免见 `restart-signal.ts` 的 mcp 特判(`mcpRevocationLive` 前提,fail-closed:席没接线
|
|
10
|
+
* 的部署保持旧的 restart 语义)。
|
|
11
|
+
* · **重现恢复是指纹判,不是名字判**(codex F1,confirmed):被撤的名字回到 enabled 集时,只有当
|
|
12
|
+
* 它的条目指纹与 **baseline(boot mount 真身)逐字相同**才解除撤销——重加同名**不同址/不同配置**
|
|
13
|
+
* 的条目,复活的会是 boot-frozen 的旧 mount(新配置要 restart 才装上),那是把已撤下的旧端点在
|
|
14
|
+
* restart 窗口内重新放行(fail-open)。指纹不匹配 ⇒ 名字保持 revoked 直到 restart 收敛。
|
|
15
|
+
* · **baseline 只由 boot bake 拍铸**(codex F2,confirmed):它必须是「实际 mount 的集合」——迟到
|
|
16
|
+
* boot 采用/refresh 拍的候选集都不是 mount 真身,不得铸 baseline。`hasBaseline()` 是 restart 豁免
|
|
17
|
+
* 的第二道门(boot 超时形:mount=env 集,中心撤销语义整个不适用,豁免必须关死走旧 restart 语义)。
|
|
18
|
+
* · **域缺席(null)不动**:中心停止发布 mcp 域 ≠ 逐服务器撤销指令(fingerprint 上 null↔非 null
|
|
19
|
+
* 自会签 restart);域在场但 `servers: []` 是明确的「清空」指令 ⇒ 全撤。
|
|
20
|
+
* · baseline 之后新增再删除的名字照 revoke(它从未 mount,isRevoked=true 无 mount 可拒=无害,
|
|
21
|
+
* fail-closed 向);这类名字重加时因无 baseline 指纹**不解除**——同样无害,restart 收敛。
|
|
22
|
+
*
|
|
23
|
+
* 纯内存、同步、无 I/O —— 每副本各自持有(mount 也是副本各自的,天然同界)。进程重启即清零:
|
|
24
|
+
* 重启后按新配置 mount,台账语义自洽。
|
|
25
|
+
*/
|
|
26
|
+
/** `RunnerDeps.mcpRevocations` 的结构超集(isRevoked 同签名,core 结构类型直接受用)。 */
|
|
27
|
+
export interface McpRevocationLedger {
|
|
28
|
+
/** core 每次 MCP dispatch 前同步探询;true = 该服务器已被中心从 enabled 集移除(或改形候 restart)。 */
|
|
29
|
+
isRevoked(serverName: string): boolean;
|
|
30
|
+
/** 配置拍喂当拍 ENABLED 服务器条目(name→指纹,插入序=发布序);`null` = mcp 域未发布(不动)。
|
|
31
|
+
* `isBaseline: true` 只允许 boot bake 拍传——铸 mount 真身;已铸后再传按普通拍处理(幂等防误用)。 */
|
|
32
|
+
applyEnabledEntries(entries: ReadonlyMap<string, string> | null, opts?: {
|
|
33
|
+
isBaseline?: boolean;
|
|
34
|
+
}): void;
|
|
35
|
+
/** true = boot bake 拍真铸过 baseline(mount 真身在案)。restart 豁免的第二道门:false 时豁免必须
|
|
36
|
+
* 关死(boot 超时/纯 env 形:中心集≠mount 集,撤销腿承接不了删除)。 */
|
|
37
|
+
hasBaseline(): boolean;
|
|
38
|
+
/** 诊断投影:当前被撤销名单(字典序)。 */
|
|
39
|
+
view(): {
|
|
40
|
+
revoked: string[];
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export declare function createMcpRevocationLedger(onChange?: (ev: {
|
|
44
|
+
revoked: string[];
|
|
45
|
+
restored: string[];
|
|
46
|
+
}) => void): McpRevocationLedger;
|
|
47
|
+
/** 一拍 EffectiveConfig 的 ENABLED MCP 服务器条目表(`resolveMcpServers` 同判据:`enabled !== false`;
|
|
48
|
+
* 值=整条目的 key 排序 JSON 指纹,Map 插入序=发布序);mcp 域缺席 ⇒ `null`(台账不动)。
|
|
49
|
+
* 指纹口径与 restart-signal 的 stableStringify 同精神(key 序归一),但**刻意独立实现**:两处指纹
|
|
50
|
+
* 只在各自域内自比,不跨域比对,无同源约束。 */
|
|
51
|
+
export declare function enabledMcpEntries(mcp: {
|
|
52
|
+
servers: Array<{
|
|
53
|
+
name: string;
|
|
54
|
+
enabled?: boolean;
|
|
55
|
+
}>;
|
|
56
|
+
} | undefined): ReadonlyMap<string, string> | null;
|
|
57
|
+
//# sourceMappingURL=mcp-revocation.d.ts.map
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #324(core 5.50 design/338 提货件)—— mid-turn MCP 撤销台账:`RunnerDeps.mcpRevocations` 席的宿主实现。
|
|
3
|
+
*
|
|
4
|
+
* 语义(与 core 契约对表,types.d.ts `RunnerDeps.mcpRevocations` 注):
|
|
5
|
+
* · 权威单点在宿主 —— core 每次 MCP dispatch 前**同步**探 `isRevoked(serverName)`,从不缓存答案。
|
|
6
|
+
* · 本台账记「中心**曾发布为 enabled、后从 enabled 集移除**」的服务器名。MCP mount 是 boot-baked
|
|
7
|
+
* (`resolveMcpServers` 只在启动期跑),所以**删除向**在 5.50 前只能等 restart 才生效——这正是
|
|
8
|
+
* design/338 要消的窗:治理面最要紧的动作(撤销一条对外通道)现在即时生效,restart 信号的
|
|
9
|
+
* 删除向豁免见 `restart-signal.ts` 的 mcp 特判(`mcpRevocationLive` 前提,fail-closed:席没接线
|
|
10
|
+
* 的部署保持旧的 restart 语义)。
|
|
11
|
+
* · **重现恢复是指纹判,不是名字判**(codex F1,confirmed):被撤的名字回到 enabled 集时,只有当
|
|
12
|
+
* 它的条目指纹与 **baseline(boot mount 真身)逐字相同**才解除撤销——重加同名**不同址/不同配置**
|
|
13
|
+
* 的条目,复活的会是 boot-frozen 的旧 mount(新配置要 restart 才装上),那是把已撤下的旧端点在
|
|
14
|
+
* restart 窗口内重新放行(fail-open)。指纹不匹配 ⇒ 名字保持 revoked 直到 restart 收敛。
|
|
15
|
+
* · **baseline 只由 boot bake 拍铸**(codex F2,confirmed):它必须是「实际 mount 的集合」——迟到
|
|
16
|
+
* boot 采用/refresh 拍的候选集都不是 mount 真身,不得铸 baseline。`hasBaseline()` 是 restart 豁免
|
|
17
|
+
* 的第二道门(boot 超时形:mount=env 集,中心撤销语义整个不适用,豁免必须关死走旧 restart 语义)。
|
|
18
|
+
* · **域缺席(null)不动**:中心停止发布 mcp 域 ≠ 逐服务器撤销指令(fingerprint 上 null↔非 null
|
|
19
|
+
* 自会签 restart);域在场但 `servers: []` 是明确的「清空」指令 ⇒ 全撤。
|
|
20
|
+
* · baseline 之后新增再删除的名字照 revoke(它从未 mount,isRevoked=true 无 mount 可拒=无害,
|
|
21
|
+
* fail-closed 向);这类名字重加时因无 baseline 指纹**不解除**——同样无害,restart 收敛。
|
|
22
|
+
*
|
|
23
|
+
* 纯内存、同步、无 I/O —— 每副本各自持有(mount 也是副本各自的,天然同界)。进程重启即清零:
|
|
24
|
+
* 重启后按新配置 mount,台账语义自洽。
|
|
25
|
+
*/
|
|
26
|
+
export function createMcpRevocationLedger(onChange) {
|
|
27
|
+
/** boot mount 真身(name→指纹);undefined = baseline 未铸(hasBaseline=false)。铸后不变。 */
|
|
28
|
+
let baseline;
|
|
29
|
+
let seen; // 上一拍 enabled 名集;undefined = 还没见过任何一拍
|
|
30
|
+
const revoked = new Set();
|
|
31
|
+
return {
|
|
32
|
+
isRevoked: (serverName) => revoked.has(serverName),
|
|
33
|
+
hasBaseline: () => baseline !== undefined,
|
|
34
|
+
applyEnabledEntries: (entries, opts) => {
|
|
35
|
+
if (entries === null)
|
|
36
|
+
return; // 域未发布 ≠ 撤销指令(成文见文件头)
|
|
37
|
+
if (opts?.isBaseline === true && baseline === undefined)
|
|
38
|
+
baseline = new Map(entries);
|
|
39
|
+
const restored = [];
|
|
40
|
+
for (const [n, fp] of entries) {
|
|
41
|
+
// codex F1:恢复=指纹判——只有回归到 baseline(mount 真身)的逐字同形才解除;
|
|
42
|
+
// 同名不同形(改址/改配置)保持 revoked,新配置候 restart 装上(fail-closed)。
|
|
43
|
+
if (revoked.has(n) && baseline?.get(n) === fp) {
|
|
44
|
+
revoked.delete(n);
|
|
45
|
+
restored.push(n);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const names = new Set(entries.keys());
|
|
49
|
+
const newlyRevoked = [];
|
|
50
|
+
if (seen !== undefined) {
|
|
51
|
+
for (const n of seen) {
|
|
52
|
+
if (!names.has(n) && !revoked.has(n)) {
|
|
53
|
+
revoked.add(n);
|
|
54
|
+
newlyRevoked.push(n);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
seen = names;
|
|
59
|
+
if (onChange && (newlyRevoked.length > 0 || restored.length > 0))
|
|
60
|
+
onChange({ revoked: newlyRevoked, restored });
|
|
61
|
+
},
|
|
62
|
+
view: () => ({ revoked: [...revoked].sort() }),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/** 一拍 EffectiveConfig 的 ENABLED MCP 服务器条目表(`resolveMcpServers` 同判据:`enabled !== false`;
|
|
66
|
+
* 值=整条目的 key 排序 JSON 指纹,Map 插入序=发布序);mcp 域缺席 ⇒ `null`(台账不动)。
|
|
67
|
+
* 指纹口径与 restart-signal 的 stableStringify 同精神(key 序归一),但**刻意独立实现**:两处指纹
|
|
68
|
+
* 只在各自域内自比,不跨域比对,无同源约束。 */
|
|
69
|
+
export function enabledMcpEntries(mcp) {
|
|
70
|
+
if (!mcp)
|
|
71
|
+
return null;
|
|
72
|
+
const out = new Map();
|
|
73
|
+
for (const s of mcp.servers) {
|
|
74
|
+
if (s.enabled !== false)
|
|
75
|
+
out.set(s.name, fingerprintOf(s));
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
function fingerprintOf(v) {
|
|
80
|
+
if (v === null || typeof v !== "object")
|
|
81
|
+
return JSON.stringify(v) ?? "null";
|
|
82
|
+
if (Array.isArray(v))
|
|
83
|
+
return `[${v.map(fingerprintOf).join(",")}]`;
|
|
84
|
+
const obj = v;
|
|
85
|
+
return `{${Object.keys(obj)
|
|
86
|
+
.sort()
|
|
87
|
+
.map((k) => `${JSON.stringify(k)}:${fingerprintOf(obj[k])}`)
|
|
88
|
+
.join(",")}}`;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=mcp-revocation.js.map
|
|
@@ -12,6 +12,12 @@ export interface RestartSliceCtx {
|
|
|
12
12
|
* 所以它们的变化不该产生 restart 理由 —— 否则 center 改一个本机用不上的键,整片 fleet 会为一次
|
|
13
13
|
* 对自己毫无影响的发布滚动重启一遍。缺席 = 没有 env 覆盖 ⇒ 整域都算数(与旧行为一致)。 */
|
|
14
14
|
readFaceEnvHeld?: readonly ("face" | "denyPatterns" | "denyBuiltinTiers" | "denyBuiltinExclude")[];
|
|
15
|
+
/** #324(core 5.50 design/338):撤销台账腿已接线(`RunnerDeps.mcpRevocations` 席在场且 refresh 拍在喂)。
|
|
16
|
+
* true ⇒ mcp 片的**纯删除向**(current 的 enabled 集是 boot 集的逐字子集)不再签 restart —— 删除已被
|
|
17
|
+
* 台账即时承接(core 每次 dispatch 前探 isRevoked),再签就是为一个已生效的变更滚动重启 fleet。
|
|
18
|
+
* 新增/改址/域整体出现或消失仍签(新 mount / 改址只能 restart 才生效)。缺席/false = 旧语义照签
|
|
19
|
+
* (fail-closed:没接席的部署里删除向没人承接,restart 是它唯一的生效路径)。 */
|
|
20
|
+
mcpRevocationLive?: boolean;
|
|
15
21
|
}
|
|
16
22
|
/** Structured restart signal an orchestrator consumes (GET /health → `restart`). Change-detected against the
|
|
17
23
|
* process's BOOT config, NOT presence — so it stays absent when nothing baked-at-boot changed (presence would
|
|
@@ -137,7 +137,31 @@ function restartSliceValue(eff, slice, ctx) {
|
|
|
137
137
|
* can auto rolling-restart on a non-empty result WITHOUT a restart loop, because the comparison is always
|
|
138
138
|
* against boot (a refresh that re-fires the same diff is idempotent, not a fresh trigger). */
|
|
139
139
|
export function restartReasons(boot, current, ctx) {
|
|
140
|
-
return RESTART_SLICES.filter((s) =>
|
|
140
|
+
return RESTART_SLICES.filter((s) => {
|
|
141
|
+
const b = restartSliceValue(boot, s, ctx);
|
|
142
|
+
const c = restartSliceValue(current, s, ctx);
|
|
143
|
+
if (stableStringify(b) === stableStringify(c))
|
|
144
|
+
return false;
|
|
145
|
+
// #324:撤销台账腿在场时,mcp 片的**纯删除向**不签 —— 删除已被台账即时承接(core 每次 dispatch 前
|
|
146
|
+
// 探 isRevoked),签了就是为一个已生效的变更滚动重启 fleet。判据=**保序严格子序列**(codex F3,
|
|
147
|
+
// confirmed:旧判据用 Set 成员测,[A,B]→[B,A] 纯重排两侧指纹不等、每条又都在 boot 集 ⇒ 被误豁免,
|
|
148
|
+
// 而服务器顺序是 mount 语义〔工具串接序〕,重排只能 restart 生效;删除+重排混合同理——存留条目的
|
|
149
|
+
// 相对顺序必须与 boot 逐字一致才是「纯删除」)。任何新增/改形/重排照签;域整体出现/消失(null↔数组)
|
|
150
|
+
// 不是删除向,保守照签。ctx 键缺席 = 席没接线 ⇒ 旧语义照签(fail-closed,#157)。
|
|
151
|
+
if (s === "mcp" && ctx?.mcpRevocationLive === true && Array.isArray(b) && Array.isArray(c) && c.length < b.length) {
|
|
152
|
+
const bootFps = b.map(stableStringify);
|
|
153
|
+
let bi = 0;
|
|
154
|
+
const pureRemoval = c.every((row) => {
|
|
155
|
+
const fp = stableStringify(row);
|
|
156
|
+
while (bi < bootFps.length && bootFps[bi] !== fp)
|
|
157
|
+
bi++;
|
|
158
|
+
return bi < bootFps.length ? (bi++, true) : false;
|
|
159
|
+
});
|
|
160
|
+
if (pureRemoval)
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
return true;
|
|
164
|
+
});
|
|
141
165
|
}
|
|
142
166
|
/** codex R10 (models-tiers 窗收口): TRUE when the MODEL PLANE (enabled models + active tier table + resolved
|
|
143
167
|
* default) of `next` differs from the last-APPLIED plane `prev`. Under a tier-frozen Runner (tiers non-empty at
|
|
@@ -166,6 +166,8 @@ async function handleDiagnosticsBody(req, res, url, ctx, miss) {
|
|
|
166
166
|
// 只有键名与判据文案,值从不进读面)。/health 那三键是同一份读数的窄投影,两面不可能各说各话。
|
|
167
167
|
// 缺席 ⇒ 显式 `null`(与 memoryPosture 同姿势:「这个进程说不出来」,不铸空壳)。
|
|
168
168
|
configApply: deps.configApplyState?.() ?? null,
|
|
169
|
+
// #324:mid-turn MCP 撤销名单(design/338)。null=本进程没有配置管道(说不出来),与上两键同姿势。
|
|
170
|
+
mcpRevocations: deps.mcpRevocationState?.() ?? null,
|
|
169
171
|
serverGates: buildServerWiringGates({
|
|
170
172
|
toolApprovalEnabled: deps.toolApproval !== undefined,
|
|
171
173
|
streamApprovalEnabled: deps.config.streamApproval?.enabled === true,
|
|
@@ -125,7 +125,9 @@ async function handleSessionsBody(req, res, url, ctx, miss) {
|
|
|
125
125
|
const panel = (async () => {
|
|
126
126
|
// Bound the connect/list so a hanging MCP server can't pin the request; dispose the late resolver if it
|
|
127
127
|
// eventually completes after the timeout (no connection leak). materializeMcpTools is fail-open per server.
|
|
128
|
-
|
|
128
|
+
// #324:第 6 参接撤销台账 —— 展示面与引擎执行面同一权威(被撤服务器不再进面板;core 契约:
|
|
129
|
+
// probe 抛错 fail-open + onProbeFailure 回调,这里缺席=沿 core 的 once-per-materialization notice)。
|
|
130
|
+
const matP = materializeMcpTools(specs, principal, undefined, undefined, undefined, deps.mcpRevocations);
|
|
129
131
|
let timer;
|
|
130
132
|
const mat = await Promise.race([matP.catch(() => null), new Promise((r) => { timer = setTimeout(() => r(null), MCP_MATERIALIZE_TIMEOUT_MS); })]);
|
|
131
133
|
if (timer)
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { getWorkflowRun, subscribeWorkflow, deriveAgentDisplayStatus, callKeyOrdinal } from "@sema-agent/core";
|
|
2
2
|
import { redactSteerIn, STEER_IN_MAX_CHARS, STEER_IN_MAX_REQUEST_CHARS } from "../../orchestration/workflow-agent-steer.js";
|
|
3
3
|
import { redactSecrets } from "../../trace/redact.js";
|
|
4
|
-
import { HEARTBEAT_MS } from "../../runs.js";
|
|
5
4
|
import { sendJson, sendError, sseHeaders } from "../send.js";
|
|
6
5
|
import { gatedPrincipal, explicitOperatorOk } from "../principal-gate.js";
|
|
7
6
|
const WORKFLOWS_RE = /^\/v1\/workflows(?:\/([^/]+)(\/stream|\/journal)?)?$/; // S8 self-orchestration runs: list / detail / live SSE
|
|
@@ -130,6 +129,9 @@ async function handleWorkflowsReadBody(req, res, url, ctx, miss) {
|
|
|
130
129
|
}
|
|
131
130
|
: {}),
|
|
132
131
|
...(r.stats ? { tokens: r.stats.tokens, turns: r.stats.turns } : {}),
|
|
132
|
+
// core 5.51 #210:status:"completed" 但停在人拒的唯一判别位——白名单不投它,journal 消费者
|
|
133
|
+
// 会把「用户拒了、在等指示」读成「自然跑完」(契约明写的误读形)。additive:自然结束不挂键。
|
|
134
|
+
...(r.haltedOnUserRejection === true ? { haltedOnUserRejection: true } : {}),
|
|
133
135
|
});
|
|
134
136
|
const js = deps.workflowJournalStore;
|
|
135
137
|
let projected;
|
package/dist/http/server.d.ts
CHANGED
|
@@ -463,6 +463,16 @@ export interface ServiceDeploymentDeps {
|
|
|
463
463
|
/** #322 追加件:`POST /v1/admin/config/refresh` 的实现面 —— 触发**一次既有**的 refresh 拍(在飞则 join)。
|
|
464
464
|
* 缺席 / 回 `"not-wired"` = 本部署没有配置管道 ⇒ 该口诚实 4xx(绝不吞成 200)。 */
|
|
465
465
|
configRefreshNow?: () => Promise<"triggered" | "not-wired" | "failed">;
|
|
466
|
+
/** #324(core 5.50 design/338):mid-turn MCP 撤销台账读口 —— GET /v1/sessions/:id/mcp 的展示面与
|
|
467
|
+
* 引擎执行面同一权威(被撤服务器的工具不再进面板)。缺席 = 无中心撤销面(pre-338 展示语义)。 */
|
|
468
|
+
mcpRevocations?: {
|
|
469
|
+
isRevoked(serverName: string): boolean;
|
|
470
|
+
};
|
|
471
|
+
/** #324 诊断投影:当前被撤销的 MCP 服务器名单(`GET /v1/diagnostics/wiring` 的 mcpRevocations 段)。
|
|
472
|
+
* 缺席/返回 undefined = 无配置管道 ⇒ 读面报 null(additive,不铸空壳)。 */
|
|
473
|
+
mcpRevocationState?: () => {
|
|
474
|
+
revoked: string[];
|
|
475
|
+
} | undefined;
|
|
466
476
|
/** codex R18 (models-tiers deferral): the persistent "deferred WITHOUT a next-boot handoff" state — set when a
|
|
467
477
|
* changed model plane could not hot-apply (tier-frozen Runner / tiered candidate) AND no restart-surviving LKG
|
|
468
478
|
* exists to justify forcing a restart. Surfaced on /health (`modelPlaneDeferred`) so the stuck-degraded state
|
package/dist/main.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFileSync
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { Runner, InMemoryToolResultStore, TtlSessionStore, uuidv7, defaultTaskRegistry, createAllowDenyPolicy, workflowsCapability, probeSearchBackend, describeStaticWiring } from "@sema-agent/core";
|
|
@@ -351,8 +351,12 @@ async function main() {
|
|
|
351
351
|
retentionExecutorWired: config.retentionSweep.intervalSec > 0 && retentionExecutor !== undefined && retentionLaneStore !== undefined,
|
|
352
352
|
});
|
|
353
353
|
// design/158 A10:RunnerDeps 装配段搬到 src/boot/runner-deps.ts(逐字;runStore 晚绑改取值,见该文件头注)。
|
|
354
|
+
// #324:撤销台账席取一次、两处(主 runnerDeps + subRunner 共享基座)同一引用。takeMcpRevocations 的
|
|
355
|
+
// 取走动作同时打开 restart-signal 的删除向豁免(承接与豁免绑定,见 config-center 的方法注)。
|
|
356
|
+
const mcpRevocations = configCenter.takeMcpRevocations();
|
|
354
357
|
const runnerDeps = createRunnerDeps({
|
|
355
358
|
hands: commitHands,
|
|
359
|
+
mcpRevocations,
|
|
356
360
|
config, logger, metrics, localRoot, promptSource: configCenter.promptSource, rosterStore, backgroundAgentStore, mailboxStore, usageWindowStore, brain,
|
|
357
361
|
pricing, tracer, outcomeSink, elicitation, question, toolApproval, sessionStore, memoryEngine,
|
|
358
362
|
memorySyncRunner, toolResultStore: runnerOffloadStore, sessionPolicyStore, runtimeCapsResolver, fileSnapshotStore,
|
|
@@ -529,6 +533,7 @@ async function main() {
|
|
|
529
533
|
config,
|
|
530
534
|
logger, // #240②:onNotice 席落共享基座 ⇒ 两 Runner 同源(EngineNotice→logger.warn)
|
|
531
535
|
hands: commitHands, // 交接件⑤:与主 runner 同一个值(基座保证同源)
|
|
536
|
+
mcpRevocations, // #324:与主 runner 同一台账实例(委托子代腿的 MCP 撤销同源生效)
|
|
532
537
|
brain,
|
|
533
538
|
pricing,
|
|
534
539
|
tracer,
|
|
@@ -1202,6 +1207,8 @@ async function main() {
|
|
|
1202
1207
|
restartState: () => configCenter.restartState(),
|
|
1203
1208
|
planeDeferredState: () => configCenter.planeDeferredState(), // codex R18: /health.modelPlaneDeferred (stuck-deferred plane, no handoff)
|
|
1204
1209
|
configApplyState: () => configCenter.configApplyState(), // #322 世代账:/health 三键 + 诊断 configApply 段(同一份读数)
|
|
1210
|
+
mcpRevocations, // #324:GET /v1/sessions/:id/mcp 展示面与引擎执行面同一台账
|
|
1211
|
+
mcpRevocationState: () => configCenter.mcpRevocationState(), // #324:诊断端点撤销名单投影
|
|
1205
1212
|
configRefreshNow: () => configCenter.refreshNow(), // #322 追加件:POST /v1/admin/config/refresh(触发既有拍,在飞则 join)
|
|
1206
1213
|
// shared drain state — SIGTERM flips `draining`, createServer assigns `inflight`, /health mirrors it.
|
|
1207
1214
|
drainState,
|
package/dist/question.d.ts
CHANGED
|
@@ -14,6 +14,14 @@ export interface QuestionFrame {
|
|
|
14
14
|
/** Server-signed emit timestamp (additive, [2805]§五→[2806]). Server-minted side-frame ⇒ no core-stream
|
|
15
15
|
* `eventId` to carry (absence is honest); this is the frame's own time coordinate. */
|
|
16
16
|
serverNowMs?: number;
|
|
17
|
+
/** "question" only ([4851]③, additive, the `tool_approval` window-trio precedent from #288): the
|
|
18
|
+
* coordinator's OWN answer window (`QUESTION_TTL_MS`, default 5min) — at expiry the ask releases
|
|
19
|
+
* UNAVAILABLE ("unanswered") and core adjudicates park-vs-continue. Minted from the SAME `ttlMs` the
|
|
20
|
+
* `setTimeout` below actually arms (single source; a shell countdown rendered from these can never
|
|
21
|
+
* disagree with the release). Relative + absolute + `serverNowMs` above = clock-skew-proof trio. */
|
|
22
|
+
expiresInMs?: number;
|
|
23
|
+
/** "question" only: `serverNowMs + expiresInMs` — absolute deadline on the server's clock. */
|
|
24
|
+
expiresAtMs?: number;
|
|
17
25
|
}
|
|
18
26
|
/** The per-run context `onQuestion` recovers via ALS. `emit` delivers a frame to the run's live stream; `abortSignal`
|
|
19
27
|
* (the run's own cancel signal) releases a question parked awaiting a human when the run aborts. */
|
package/dist/question.js
CHANGED
|
@@ -180,7 +180,11 @@ export class QuestionCoordinator {
|
|
|
180
180
|
// (the settlement is still pending there, so the emit is still fully awaited).
|
|
181
181
|
// The loser of the race keeps its own handlers — an emit that rejects AFTER the race must not surface as an
|
|
182
182
|
// unhandled rejection.
|
|
183
|
-
const emitted = (async () =>
|
|
183
|
+
const emitted = (async () => {
|
|
184
|
+
// [4851]③ 窗三键与上面 setTimeout 用同一个 ttlMs 铸(单源;壳倒计时永不与真释放口径分歧)。
|
|
185
|
+
const now = Date.now();
|
|
186
|
+
return ctx.emit({ type: "question", questionId: id, questions, serverNowMs: now, expiresInMs: this.throttle.ttlMs, expiresAtMs: now + this.throttle.ttlMs });
|
|
187
|
+
})()
|
|
184
188
|
.then(() => "ok", () => "failed");
|
|
185
189
|
const delivery = await Promise.race([emitted, answerP.then(() => "stalled")]);
|
|
186
190
|
if (delivery === "ok") {
|
package/dist/run-local.js
CHANGED
|
@@ -657,6 +657,8 @@ export async function runLocal(argv, deps = {}) {
|
|
|
657
657
|
usageWindowStore: config.usageWindows ? fileBackend.usageWindowStore : undefined,
|
|
658
658
|
orgMemoryAdmission,
|
|
659
659
|
sharedMemoryStores: undefined,
|
|
660
|
+
// #324:run-local 无 configCenter runtime = 无中心撤销面 ⇒ 席诚实缺席(pre-338 语义)。
|
|
661
|
+
mcpRevocations: undefined,
|
|
660
662
|
});
|
|
661
663
|
const runnerDeps = {
|
|
662
664
|
...sharedRunnerDeps,
|
package/dist/trace/project.d.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* each content event, additive / tolerate-absent.
|
|
14
14
|
*/
|
|
15
15
|
import type { ApprovalSettledBy, TaskResult } from "@sema-agent/core";
|
|
16
|
+
import { type AskDenyResolution } from "@sema-agent/core";
|
|
16
17
|
import type { RunEvent, RunRecord } from "../plugins/store-contracts.js";
|
|
17
18
|
import type { ModelUsageDelta, ModelUsageTracker, PromptManifestRecord } from "../budget.js";
|
|
18
19
|
import type { LedgerEventType } from "./ledger-events.js";
|
|
@@ -94,6 +95,7 @@ export type TraceBlock = {
|
|
|
94
95
|
structured?: unknown;
|
|
95
96
|
errorCode?: string;
|
|
96
97
|
settledBy?: ApprovalSettledBy;
|
|
98
|
+
resolution?: AskDenyResolution;
|
|
97
99
|
approver?: string;
|
|
98
100
|
eventId?: string;
|
|
99
101
|
parentToolCallId?: string;
|
|
@@ -137,6 +139,7 @@ export declare function toolEndEventData(ev: {
|
|
|
137
139
|
structured?: unknown;
|
|
138
140
|
errorCode?: string;
|
|
139
141
|
settledBy?: ApprovalSettledBy;
|
|
142
|
+
resolution?: AskDenyResolution;
|
|
140
143
|
approver?: string;
|
|
141
144
|
eventId?: string;
|
|
142
145
|
parentToolCallId?: string;
|
package/dist/trace/project.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
// 值导入(非 `import type`):`settledBy` 的闭集判据必须**复用 core
|
|
2
|
-
//
|
|
3
|
-
|
|
1
|
+
// 值导入(非 `import type`):`settledBy`/`resolution` 的闭集判据必须**复用 core 的谓词**——本仓抄
|
|
2
|
+
// 一份词表就是值拷贝漂移源(上游加员时两处静默不同步)。settledBy=core 5.18.1 #187;
|
|
3
|
+
// resolution 三席=core 5.52.0 根导出([4819] 应诺兑现,[4820] 预挂的闭集换装即此)。
|
|
4
|
+
import { isApprovalSettledBy, isAskDenyResolution } from "@sema-agent/core";
|
|
4
5
|
import { redactSecrets, redactDeep } from "./redact.js";
|
|
5
6
|
/** E8 (shell-host): drain the per-task model-usage accumulator into an append-only `model_usage` DELTA event.
|
|
6
7
|
* Shared by BOTH durable-write legs (runInBackground + the resume leg) so the persisted shape never drifts; the
|
|
@@ -176,6 +177,14 @@ export function toolEndEventData(ev) {
|
|
|
176
177
|
// 一律不铸键 —— 既不折 "human" 也不折 null,把「不知道」如实表达成「没有这个键」。
|
|
177
178
|
// 值是引擎铸的枚举短串、非用户内容 ⇒ 不脱敏。
|
|
178
179
|
...(isApprovalSettledBy(ev.settledBy) ? { settledBy: ev.settledBy } : {}),
|
|
180
|
+
// core 5.51.0 #127([4816] 提货单件①):`resolution` = ask 解析席**拒绝臂**的分类(九码闭集
|
|
181
|
+
// `AskDenyResolution`)——比 settledBy 更细(那个只说结算是什么种类,这个说拒绝走了哪条臂),
|
|
182
|
+
// 铸点在 resolveAsk 的组臂处、经引擎结算 sideband 逐字携带,**不可由 tool/policy 自declare**——
|
|
183
|
+
// core 契约逐字:「an out-of-vocabulary or self-declared word is dropped at the screens」,即
|
|
184
|
+
// **筛点单点在 core**。判据=闭集谓词 `isAskDenyResolution`(core 5.52.0 三席根导出到货,
|
|
185
|
+
// [4819]/[4820] 过渡形〔string 非空+≤64〕退役,单一属主纪律不抄词表)。
|
|
186
|
+
// 缺席不是语义(执行了的调用/policy 直拒/durable 腿都不带)。
|
|
187
|
+
...(isAskDenyResolution(ev.resolution) ? { resolution: ev.resolution } : {}),
|
|
179
188
|
// core 5.35.0 design/252 G-7(#263 提货批,[4022] G3):`approver` = 这次结算**是谁的**——审批通道
|
|
180
189
|
// 自报的结算方标识串,core `screenApproverAttribution` 筛形后逐字转录在 `settledBy` 旁,两键**合读**
|
|
181
190
|
// (`settledBy:"timeout"` + approver = 超时的那条队列名,不是拒绝的人)。与 settledBy 同族三条纪律:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.39.0",
|
|
4
4
|
"description": "Sema Server — the server/API implementation layer for Sema, wiring core, registry, model providers, and cloud agent execution. Built on @sema-agent/core.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"build:binary:run-local:darwin-arm64": "bun build --compile --target=bun-darwin-arm64 src/run-local.ts --outfile dist/run-local-darwin-arm64"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@sema-agent/core": "^5.
|
|
57
|
+
"@sema-agent/core": "^5.52.0",
|
|
58
58
|
"@sema-agent/registry-core": "^0.19.0",
|
|
59
59
|
"e2b": "^2.28.0",
|
|
60
60
|
"libsodium-wrappers": "^0.8.4",
|