@sema-agent/server 7.57.0 → 7.59.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 +2 -0
- package/dist/approval-card.d.ts +47 -0
- package/dist/approval-card.js +18 -0
- package/dist/boot/parked-revive-gate.d.ts +3 -0
- package/dist/boot/parked-revive-gate.js +2 -2
- package/dist/boot/resolve-spec.js +1 -1
- package/dist/boot/runner-deps.d.ts +2 -2
- package/dist/boot/runner-deps.js +4 -0
- package/dist/boot/stores.js +15 -8
- package/dist/config-catalog.d.ts +0 -29
- package/dist/config-catalog.js +3 -0
- package/dist/config-center/http-client.js +7 -11
- package/dist/config-center/read-warnings.d.ts +20 -0
- package/dist/config-center/read-warnings.js +36 -0
- package/dist/config-provider.d.ts +3 -0
- package/dist/config-provider.js +4 -8
- package/dist/config-types.d.ts +12 -2
- package/dist/config.js +13 -2
- package/dist/cross-session-settings.d.ts +70 -0
- package/dist/cross-session-settings.js +37 -0
- package/dist/deployment-governance.d.ts +30 -1
- package/dist/deployment-governance.js +11 -5
- package/dist/hooks/hook-runner.js +8 -8
- package/dist/main.js +1 -0
- package/dist/memory-scope.d.ts +20 -0
- package/dist/memory-scope.js +9 -1
- package/dist/observability/metrics.js +1 -1
- package/dist/observability/run-terminal-log.d.ts +4 -0
- package/dist/observability/run-terminal-log.js +15 -1
- package/dist/plugins/device-store-sql.d.ts +30 -6
- package/dist/plugins/device-store-sql.js +23 -4
- package/dist/plugins/file-history-store-sql.d.ts +5 -0
- package/dist/plugins/file-history-store-sql.js +7 -7
- package/dist/plugins/image-bake-store-sql.js +1 -1
- package/dist/plugins/mailbox-store-sql.d.ts +33 -11
- package/dist/plugins/mailbox-store-sql.js +74 -12
- package/dist/plugins/retention-lane-store-sql.d.ts +8 -4
- package/dist/plugins/retention-lane-store-sql.js +1 -1
- package/dist/plugins/retention-store-sql.d.ts +7 -3
- package/dist/plugins/retention-store-sql.js +2 -2
- package/dist/plugins/task-list-store-sql.d.ts +2 -2
- package/dist/plugins/task-list-store-sql.js +1 -1
- package/dist/plugins/usage-window-store-sql.d.ts +5 -3
- package/dist/plugins/usage-window-store-sql.js +1 -5
- package/dist/run-local.d.ts +2 -1
- package/dist/run-local.js +3 -3
- package/dist/runs.d.ts +13 -0
- package/dist/runs.js +2 -0
- package/dist/task-settings.d.ts +13 -3
- package/dist/task-settings.js +1 -1
- package/dist/tool-approval.d.ts +23 -1
- package/dist/tool-approval.js +6 -1
- package/dist/trace/core-keyset-guard.d.ts +7 -8
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +5 -0
- package/dist/trace/project.d.ts +45 -3
- package/dist/trace/project.js +23 -0
- package/dist/trace/redact.js +7 -3
- package/dist/trace/sema-provenance.d.ts +15 -0
- package/dist/trace/sema-provenance.js +3 -0
- package/package.json +3 -3
package/USAGE.md
CHANGED
|
@@ -1285,6 +1285,8 @@ armed ⟺ 本次请求 permissionMode 是 "auto" ∧ 本部署装配了分类
|
|
|
1285
1285
|
| 旋钮 | 缺省 | 语义 |
|
|
1286
1286
|
|---|---|---|
|
|
1287
1287
|
| `PERMISSIONS_DISABLE_AUTO_MODE` | `false`(opt-in) | CC/center/settings 键名 `permissions.disableAutoMode` 的 **env 腿**(config catalog 登记 center 键名 `permissions.disableAutoMode`,settings-schema 现无 `permissions` 域 ⇒ 目录行 `domainExists:false`):**tighten-only** 棘轮 —— `true` ⇒ 本部署每个 principal 的 `caps.autoMode` 折成 `false`(center 授予 `true` **翻不回**);未设 ⇒ 不动 caps。布尔词表(`true/false/1/0/yes/no/on/off`),词表外的值**拒启**(安全轴旋钮不许静默回默认)。目录行见 `GET /v1/config/catalog`(approval 域,security 轴) |
|
|
1288
|
+
| `CROSS_SESSION_INBOUND` | 未设 | 跨终端会话设计线:CC settings 键名 `crossSessionInbound` 的**部署/组织层**(引擎层形的 `managed` 层,CC `policySettings` 对位)—— 本部署对**入站跨会话消息**的治理三态:`accept` 投递 / `hold` 停在收件会话的待审队列(模型看不见、不能据此行动)/ `refuse` 本部署整体退出这条车道。🔴 **未设 ≠ `accept`**:未设 = 这一层不表态,由其余层与引擎的 mode-parity 判定决定。词表外的值**拒启**。⚠️ **生效前提**:引擎的 peer 目录席(`RunnerDeps.peerDirectory`)在场——本版**未接**该席,故本旋钮今天「就位待命」不生效(目录席到货那天零改动即生效);目录行见 `GET /v1/config/catalog`(approval 域,security 轴) |
|
|
1289
|
+
| `CROSS_SESSION_DIALOG_EXPIRY` | 未设(⇒ 引擎缺省 `5m`) | 同族:CC settings 键名 `dialogExpiry` 的部署层 —— 被 hold 的跨会话消息等待人审多久后按**安全缺省**结算(过期丢弃,**带回执**告知发送方,不静默吞)。词表 `60s`/`5m`/`10m`/`never`(`never` = 不设期限);未设 ⇒ 本仓**不铸键**,由引擎落它自己的缺省(不复制上游缺省值)。词表外拒启。⚠️ 生效前提同上。另注:CC 的同名键还有第二个消费面(转发到远端客户端的审批对话框停靠时长),本旋钮**今天不驱动**那一面 |
|
|
1288
1290
|
|
|
1289
1291
|
**自查读面**(`GET /v1/capabilities.permissionModeAuto`,壳的 `sema doctor permissions` 消费;下例第一行是
|
|
1290
1292
|
`intentArming:true`(与带新武装式的 core 同批提货后)的读数——server 7.57 × core 7.2.0 上无 center 的本地部署答
|
package/dist/approval-card.d.ts
CHANGED
|
@@ -309,6 +309,34 @@ export type RuleOffersAbsence = z.infer<typeof RuleOffersAbsenceSchema>;
|
|
|
309
309
|
* 形不合/缺席 ⇒ 不铸键(缺席不是断言 —— 它同时覆盖「有 offers」与结构性无车道的门,core 契约逐字)。
|
|
310
310
|
*/
|
|
311
311
|
export declare function readRuleOffersAbsence(req: unknown): RuleOffersAbsence | undefined;
|
|
312
|
+
/** S-114(core 7.4.0 [ref])—— 回落卡的计数与窗。`limit` 是**闭二词**(core d.ts 逐字),两个计数是
|
|
313
|
+
* 非负整数,`autoDenyAfterMs` 是 core 契约里的 `0..2147483647` 非负整数(`0` = 本卡不武装窗:部署把
|
|
314
|
+
* 旋钮关了,或 TOTAL 档的卡按 [ref]① 恒 0 等人)。四成员**全必填**——core 的 `DenialLimitFallback` 上
|
|
315
|
+
* 没有一个可选位,所以「少一位」不是老 core 而是坏值,整键不铸(与 `readRuleEvidence` 的恰一不变量
|
|
316
|
+
* 同款判据:形不合 ⇒ 丢整键,绝不半铸一张让人误读计数的卡)。 */
|
|
317
|
+
declare const DenialLimitFallbackSchema: z.ZodObject<{
|
|
318
|
+
consecutive: z.ZodNumber;
|
|
319
|
+
total: z.ZodNumber;
|
|
320
|
+
limit: z.ZodEnum<{
|
|
321
|
+
total: "total";
|
|
322
|
+
consecutive: "consecutive";
|
|
323
|
+
}>;
|
|
324
|
+
autoDenyAfterMs: z.ZodNumber;
|
|
325
|
+
}, z.core.$strict>;
|
|
326
|
+
export type DenialLimitFallback = z.infer<typeof DenialLimitFallbackSchema>;
|
|
327
|
+
/**
|
|
328
|
+
* `AskRequest.denialLimitFallback`(core 7.4.0 [ref])的**边界窄读** —— 活卡帧与 `card_json` 的唯一铸造点
|
|
329
|
+
* (与 {@link readRuleOffersAbsence} / {@link readProbeCause} 同款分工),两面结构性同值。
|
|
330
|
+
*
|
|
331
|
+
* 四成员皆 core 铸的机器数/闭词(非内容族)⇒ **零 redact**;`.strict()` 让 core 将来加成员时本读面当场
|
|
332
|
+
* 判假、整键不铸 —— 与 `_GuardAsk` 的差集门是同一件事的两端(编译期点名 + 运行期 fail-closed),新成员
|
|
333
|
+
* 必须由人处置过才上 wire。缺席/形不合 ⇒ 不铸键(**缺席不是断言**:绝大多数 ask 根本不是回落卡)。
|
|
334
|
+
*
|
|
335
|
+
* 🔴 **echo-only**:server 不读它做任何裁决,120s 窗的执行归 core 的 resolveAsk(引擎自有 deadline,
|
|
336
|
+
* `settledBy:"timeout"` + `autoDenied:true` 由 core 盖章)。据 `autoDenyAfterMs` 在本仓自铸第二只定时器
|
|
337
|
+
* = 同一语义面两个写者(源头修复纪律),明令禁止。
|
|
338
|
+
*/
|
|
339
|
+
export declare function readDenialLimitFallback(req: unknown): DenialLimitFallback | undefined;
|
|
312
340
|
/**
|
|
313
341
|
* [ref] §3.1 的**中性投影**——呈卡面看到的全部内容,与 wire 面的既有 `ToolApprovalFrame` 解耦。
|
|
314
342
|
*
|
|
@@ -379,6 +407,15 @@ export declare const ApprovalCardSchema: z.ZodObject<{
|
|
|
379
407
|
lane_cannot_speak: "lane_cannot_speak";
|
|
380
408
|
shadowed: "shadowed";
|
|
381
409
|
}>>;
|
|
410
|
+
denialLimitFallback: z.ZodOptional<z.ZodObject<{
|
|
411
|
+
consecutive: z.ZodNumber;
|
|
412
|
+
total: z.ZodNumber;
|
|
413
|
+
limit: z.ZodEnum<{
|
|
414
|
+
total: "total";
|
|
415
|
+
consecutive: "consecutive";
|
|
416
|
+
}>;
|
|
417
|
+
autoDenyAfterMs: z.ZodNumber;
|
|
418
|
+
}, z.core.$strict>>;
|
|
382
419
|
probeCause: z.ZodOptional<z.ZodObject<{
|
|
383
420
|
code: z.ZodString;
|
|
384
421
|
roots: z.ZodObject<{
|
|
@@ -478,6 +515,15 @@ export declare const ApprovalCardEnvelopeSchema: z.ZodObject<{
|
|
|
478
515
|
lane_cannot_speak: "lane_cannot_speak";
|
|
479
516
|
shadowed: "shadowed";
|
|
480
517
|
}>>;
|
|
518
|
+
denialLimitFallback: z.ZodOptional<z.ZodObject<{
|
|
519
|
+
consecutive: z.ZodNumber;
|
|
520
|
+
total: z.ZodNumber;
|
|
521
|
+
limit: z.ZodEnum<{
|
|
522
|
+
total: "total";
|
|
523
|
+
consecutive: "consecutive";
|
|
524
|
+
}>;
|
|
525
|
+
autoDenyAfterMs: z.ZodNumber;
|
|
526
|
+
}, z.core.$strict>>;
|
|
481
527
|
probeCause: z.ZodOptional<z.ZodObject<{
|
|
482
528
|
code: z.ZodString;
|
|
483
529
|
roots: z.ZodObject<{
|
|
@@ -694,4 +740,5 @@ export declare function buildApprovalPreambleSseFrames(frames: readonly Approval
|
|
|
694
740
|
event: string;
|
|
695
741
|
data: unknown;
|
|
696
742
|
}>;
|
|
743
|
+
export {};
|
|
697
744
|
//# sourceMappingURL=approval-card.d.ts.map
|
package/dist/approval-card.js
CHANGED
|
@@ -226,6 +226,21 @@ export function readRuleOffersAbsence(req) {
|
|
|
226
226
|
const parsed = RuleOffersAbsenceEnvelopeSchema.safeParse(req);
|
|
227
227
|
return parsed.success ? parsed.data.ruleOffersAbsence : undefined;
|
|
228
228
|
}
|
|
229
|
+
const DenialLimitFallbackSchema = z
|
|
230
|
+
.object({
|
|
231
|
+
consecutive: z.number().int().nonnegative(),
|
|
232
|
+
total: z.number().int().nonnegative(),
|
|
233
|
+
limit: z.enum(["consecutive", "total"]),
|
|
234
|
+
autoDenyAfterMs: z.number().int().nonnegative().max(2147483647),
|
|
235
|
+
})
|
|
236
|
+
.strict();
|
|
237
|
+
const _denialLimitFallbackConformance = [true, true];
|
|
238
|
+
void _denialLimitFallbackConformance;
|
|
239
|
+
const DenialLimitFallbackEnvelopeSchema = z.object({ denialLimitFallback: DenialLimitFallbackSchema.optional() });
|
|
240
|
+
export function readDenialLimitFallback(req) {
|
|
241
|
+
const parsed = DenialLimitFallbackEnvelopeSchema.safeParse(req);
|
|
242
|
+
return parsed.success ? parsed.data.denialLimitFallback : undefined;
|
|
243
|
+
}
|
|
229
244
|
export const ApprovalCardSchema = z
|
|
230
245
|
.object({
|
|
231
246
|
toolName: z.string().max(MAX_IDENT),
|
|
@@ -245,6 +260,7 @@ export const ApprovalCardSchema = z
|
|
|
245
260
|
persistedRuleShadowed: z.string().max(MAX_RULE_TEXT_CHARS).optional(),
|
|
246
261
|
ruleOffers: z.array(RuleOfferSchema).max(MAX_RULE_OFFERS).optional(),
|
|
247
262
|
ruleOffersAbsence: RuleOffersAbsenceSchema.optional(),
|
|
263
|
+
denialLimitFallback: DenialLimitFallbackSchema.optional(),
|
|
248
264
|
probeCause: ProbeCauseSchema.optional(),
|
|
249
265
|
ruleEvidence: RuleEvidenceSchema.optional(),
|
|
250
266
|
fromSubagent: z.literal(true).optional(),
|
|
@@ -286,6 +302,7 @@ export function buildApprovalCard(source, req, requiresRealApproval) {
|
|
|
286
302
|
const probeCause = readProbeCause(req);
|
|
287
303
|
const ruleEvidence = readRuleEvidence(req);
|
|
288
304
|
const ruleOffersAbsence = readRuleOffersAbsence(req);
|
|
305
|
+
const denialLimitFallback = readDenialLimitFallback(req);
|
|
289
306
|
const toolCallId = clip(source.toolCallId, MAX_IDENT);
|
|
290
307
|
const sourceTaskId = clip(source.sourceTaskId, MAX_IDENT);
|
|
291
308
|
const sourceAgentName = clip(source.sourceAgentName, MAX_AGENT_NAME);
|
|
@@ -307,6 +324,7 @@ export function buildApprovalCard(source, req, requiresRealApproval) {
|
|
|
307
324
|
...(ruleEvidence !== undefined ? { ruleEvidence } : {}),
|
|
308
325
|
...(source.ruleOffers !== undefined && source.ruleOffers.length > 0 ? { ruleOffers: source.ruleOffers.map(copyRuleOffer) } : {}),
|
|
309
326
|
...(ruleOffersAbsence !== undefined ? { ruleOffersAbsence } : {}),
|
|
327
|
+
...(denialLimitFallback !== undefined ? { denialLimitFallback } : {}),
|
|
310
328
|
...(source.fromSubagent === true ? { fromSubagent: true } : {}),
|
|
311
329
|
...(sourceTaskId !== undefined ? { sourceTaskId } : {}),
|
|
312
330
|
...(sourceAgentName !== undefined ? { sourceAgentName } : {}),
|
|
@@ -71,6 +71,9 @@ export interface ParkedReviveGateDeps {
|
|
|
71
71
|
};
|
|
72
72
|
/** host 腿 cwd 占位的落地根(main.ts 的 `localRoot`;`config.localDataRoot` 优先)。 */
|
|
73
73
|
readonly localRoot: string;
|
|
74
|
+
/** S-133:守卫集 `dataRoot` = boot 已铸的引擎记忆根(`memoryEngine.root`,boot/stores.ts 单一写者),不在本腿重推导
|
|
75
|
+
* (重推导 = 第二个写者,7.59.0 重扫 codex 轮抓到 HTTP 腿 fallback 与 stores 不同源正是这一形)。`undefined` = 引擎未接。 */
|
|
76
|
+
readonly memoryEngineRoot: string | undefined;
|
|
74
77
|
/** 沙箱 lane 的真 env 登记簿。缺省 = 进程内唯一那只(工厂装饰器写的同一个);测试注入自建实例。 */
|
|
75
78
|
readonly slots?: SandboxPathEnvSlots;
|
|
76
79
|
}
|
|
@@ -10,7 +10,7 @@ function hostGateCwd(config, localRoot) {
|
|
|
10
10
|
return join(config.localDataRoot ?? localRoot, "parked-revive-unrooted");
|
|
11
11
|
}
|
|
12
12
|
export function createParkedReviveInheritedGate(deps) {
|
|
13
|
-
const { config, question, approvalExemptionStore, logger, localRoot, approverSeat } = deps;
|
|
13
|
+
const { config, question, approvalExemptionStore, logger, localRoot, approverSeat, memoryEngineRoot } = deps;
|
|
14
14
|
const slots = deps.slots ?? sandboxPathEnvSlots;
|
|
15
15
|
return async (row, identity) => {
|
|
16
16
|
const metadata = await chainMetadataOf(deps, row, identity);
|
|
@@ -33,7 +33,7 @@ export function createParkedReviveInheritedGate(deps) {
|
|
|
33
33
|
}
|
|
34
34
|
: {}),
|
|
35
35
|
});
|
|
36
|
-
const governed = applyRuntimeGovernance({ objective: "", toolPolicy: baseline }, createDeploymentGovernanceInputs(config, pathAdjudication));
|
|
36
|
+
const governed = applyRuntimeGovernance({ objective: "", toolPolicy: baseline }, createDeploymentGovernanceInputs(config, pathAdjudication, { engineDataRoot: memoryEngineRoot }));
|
|
37
37
|
return {
|
|
38
38
|
parentConstraints: [
|
|
39
39
|
{
|
|
@@ -425,7 +425,7 @@ export function createResolveSpec(ctx) {
|
|
|
425
425
|
logger: { warn: (event, fields) => logger.warn(event, { ...(fields ?? {}), lane: config.remoteExec?.provider }) },
|
|
426
426
|
}),
|
|
427
427
|
};
|
|
428
|
-
const governedBase = applyRuntimeGovernance(spec, createDeploymentGovernanceInputs(config, pathAdjudication));
|
|
428
|
+
const governedBase = applyRuntimeGovernance(spec, createDeploymentGovernanceInputs(config, pathAdjudication, { engineDataRoot: memoryEngine?.root }));
|
|
429
429
|
let governed = governedBase;
|
|
430
430
|
let effectiveSettings = effMode ? withPermissionMode(parsedSettings.settings, effMode) : parsedSettings.settings;
|
|
431
431
|
if (appendLessPack && effectiveSettings?.outputStyle) {
|
|
@@ -154,7 +154,7 @@ export interface RunnerDepsCtx {
|
|
|
154
154
|
}
|
|
155
155
|
/** [ref] A10 留档发现②:main runner `RunnerDeps` 与 main.ts subRunner 字面量之间此前手工重复
|
|
156
156
|
* 的 ~15 个键,类型标注见 {@link createSharedRunnerDeps} 头注。 */
|
|
157
|
-
export type SharedRunnerDeps = Pick<RunnerDeps, "brain" | "readFace" | "readDenyPatterns" | "readDenyBuiltinTiers" | "readDenyBuiltinExclude" | "memoryDelegationEvidence" | "memoryProvenance" | "memoryCapturePolicy" | "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">;
|
|
157
|
+
export type SharedRunnerDeps = Pick<RunnerDeps, "brain" | "readFace" | "readDenyPatterns" | "readDenyBuiltinTiers" | "readDenyBuiltinExclude" | "memoryDelegationEvidence" | "memoryProvenance" | "memoryCapturePolicy" | "delegationEntryCaps" | "crossSessionInbound" | "crossSessionDialogExpiry" | "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">;
|
|
158
158
|
/**
|
|
159
159
|
* [ref] A10 留档发现②(review 2026-07-29,[ref]§三族A 同源修补的延续):main runner 的
|
|
160
160
|
* `RunnerDeps` 字面量(下方 `createRunnerDeps`)与 `main.ts` 里 subRunner 的 `new Runner({...})`
|
|
@@ -260,7 +260,7 @@ export declare function createEngineNoticeSeat(logger: {
|
|
|
260
260
|
* 「键为 undefined」与「键缺席」对引擎逐字等价)。**不复制引擎缺省**(`roots`/`static-face`/`carry`/`open`/
|
|
261
261
|
* CC parity 20/200 一个都不抄):上游改缺省之日起本仓不会成为第二份真源。
|
|
262
262
|
*/
|
|
263
|
-
export type DeploymentPostureSeats = Pick<RunnerDeps, "readFace" | "readDenyPatterns" | "readDenyBuiltinTiers" | "readDenyBuiltinExclude" | "memoryDelegationEvidence" | "memoryProvenance" | "memoryCapturePolicy" | "delegationEntryCaps">;
|
|
263
|
+
export type DeploymentPostureSeats = Pick<RunnerDeps, "readFace" | "readDenyPatterns" | "readDenyBuiltinTiers" | "readDenyBuiltinExclude" | "memoryDelegationEvidence" | "memoryProvenance" | "memoryCapturePolicy" | "delegationEntryCaps" | "crossSessionInbound" | "crossSessionDialogExpiry">;
|
|
264
264
|
export declare function buildDeploymentPostureSeats(config: Pick<ServiceConfig, keyof DeploymentPostureSeats>): DeploymentPostureSeats;
|
|
265
265
|
export declare function createSharedRunnerDeps(ctx: SharedRunnerDepsCtx): SharedRunnerDeps;
|
|
266
266
|
export declare function createRunnerDeps(ctx: RunnerDepsCtx): RunnerDeps;
|
package/dist/boot/runner-deps.js
CHANGED
|
@@ -10,6 +10,7 @@ import { defaultEngineNoticeRouter } from "../trace/engine-notice-wire.js";
|
|
|
10
10
|
import { WorkflowNotifyGate } from "../orchestration/workflow-notify-journal.js";
|
|
11
11
|
import { makeLoadProjectMemory, makeProbeInstructionSources } from "../project-memory.js";
|
|
12
12
|
import { workflowModelAllowlistFor } from "../task-workflow.js";
|
|
13
|
+
import { buildCrossSessionInboundLayers, crossSessionDialogExpiryOf } from "../cross-session-settings.js";
|
|
13
14
|
export function createRunnerDepsOnAsk(toolApproval) {
|
|
14
15
|
if (!toolApproval)
|
|
15
16
|
return undefined;
|
|
@@ -33,6 +34,7 @@ export function createEngineNoticeSeat(logger, router = defaultEngineNoticeRoute
|
|
|
33
34
|
return warn ? { onNotice: createEngineNoticeForwarder({ warn }, router) } : {};
|
|
34
35
|
}
|
|
35
36
|
export function buildDeploymentPostureSeats(config) {
|
|
37
|
+
const crossSessionLayers = buildCrossSessionInboundLayers(config);
|
|
36
38
|
const seats = {
|
|
37
39
|
readFace: config.readFace ? config.readFace : undefined,
|
|
38
40
|
readDenyPatterns: config.readDenyPatterns ? config.readDenyPatterns : undefined,
|
|
@@ -42,6 +44,8 @@ export function buildDeploymentPostureSeats(config) {
|
|
|
42
44
|
memoryProvenance: config.memoryProvenance ?? undefined,
|
|
43
45
|
memoryCapturePolicy: config.memoryCapturePolicy ?? undefined,
|
|
44
46
|
delegationEntryCaps: config.delegationEntryCaps ?? undefined,
|
|
47
|
+
crossSessionInbound: Object.keys(crossSessionLayers).length > 0 ? crossSessionLayers : undefined,
|
|
48
|
+
crossSessionDialogExpiry: crossSessionDialogExpiryOf(config),
|
|
45
49
|
};
|
|
46
50
|
return seats;
|
|
47
51
|
}
|
package/dist/boot/stores.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
|
-
import { FileBackgroundAgentStore, FileMailboxStore, FileRosterStore, FileUsageWindowStore, InMemoryUsageWindowStore } from "@sema-agent/core";
|
|
2
|
+
import { FileBackgroundAgentStore, FileMailboxStore, FileRosterStore, FileUsageWindowStore, InMemoryUsageWindowStore, mailboxCrossProcessMountVerdict } from "@sema-agent/core";
|
|
3
3
|
import { createMemorySyncRunner, createMemorySyncTransport } from "../memory-sync-client.js";
|
|
4
4
|
import { memoryEmbedderFor } from "../plugins/memory-embedder.js";
|
|
5
5
|
import { ensurePgMemoryEmbedderMetaSchema, reconcileEmbedderFingerprint } from "../plugins/memory-embedder-fingerprint.js";
|
|
@@ -20,7 +20,7 @@ import { ensurePgTaskListSchema, ensureTiDBTaskListSchema } from "../plugins/tas
|
|
|
20
20
|
import { assertDeviceAuditRebindEventSchema, ensurePgDeviceSchema, ensureTiDBDeviceSchema } from "../plugins/device-store-sql.js";
|
|
21
21
|
import { mysqlDriver, pgDriver } from "../plugins/sql-driver.js";
|
|
22
22
|
import { assertCloudSnapshotBlobPosture, openStoreBackendWithFallback } from "../plugins/store-backend.js";
|
|
23
|
-
import { buildMemoryRemoteLaneWarn, memoryEngineBackendFor, memoryEngineRemoteLanePosture } from "../memory-scope.js";
|
|
23
|
+
import { buildMemoryRemoteLaneWarn, memoryEngineBackendFor, memoryEngineRemoteLanePosture, memoryEngineRootFor } from "../memory-scope.js";
|
|
24
24
|
import { assertToolResultProvenanceSchema } from "../plugins/tool-result-store-sql.js";
|
|
25
25
|
import { assertPermissionRuleApprovalSchema, assertPermissionRuleTicketSchema } from "../plugins/permission-rule-store-sql.js";
|
|
26
26
|
import { assertApprovalAskRuleMaterialSchema } from "../plugins/approval-ask-store-sql.js";
|
|
@@ -168,7 +168,7 @@ export async function openStores(ctx) {
|
|
|
168
168
|
...(embedder !== undefined ? { embedder } : {}),
|
|
169
169
|
});
|
|
170
170
|
vectorMode = pgMem.vectorMode;
|
|
171
|
-
memoryEngine = { backend: pgMem, root:
|
|
171
|
+
memoryEngine = { backend: pgMem, root: memoryEngineRootFor(config, localRoot) };
|
|
172
172
|
}
|
|
173
173
|
else {
|
|
174
174
|
const pool = backend?.mysqlPool();
|
|
@@ -180,7 +180,7 @@ export async function openStores(ctx) {
|
|
|
180
180
|
memorySyncCursors = new TiDBMemorySyncStore(pool);
|
|
181
181
|
const tidbMem = new TiDBMemoryEngineBackend(pool, { history: countedHistorySink(new TiDBMemoryHistoryStore(pool)) });
|
|
182
182
|
vectorMode = tidbMem.vectorMode;
|
|
183
|
-
memoryEngine = { backend: tidbMem, root:
|
|
183
|
+
memoryEngine = { backend: tidbMem, root: memoryEngineRootFor(config, localRoot) };
|
|
184
184
|
}
|
|
185
185
|
logger.info("memory_engine_enabled", {
|
|
186
186
|
enabled: true,
|
|
@@ -299,19 +299,26 @@ export async function openStores(ctx) {
|
|
|
299
299
|
const pgPool = backend?.pgPool?.();
|
|
300
300
|
if (pgPool) {
|
|
301
301
|
await ensurePgMailboxSchema(async (text, params) => pgPool.query(text, params));
|
|
302
|
-
mailboxStore = new PgMailboxStore(pgPool);
|
|
302
|
+
mailboxStore = new PgMailboxStore(pgPool, logger);
|
|
303
303
|
}
|
|
304
304
|
else if (mysqlPool) {
|
|
305
305
|
await ensureTiDBMailboxSchema(mysqlPool);
|
|
306
|
-
mailboxStore = new TiDBMailboxStore(mysqlPool);
|
|
306
|
+
mailboxStore = new TiDBMailboxStore(mysqlPool, logger);
|
|
307
307
|
}
|
|
308
308
|
else if (backend?.kind === "local") {
|
|
309
309
|
mailboxStore = new FileMailboxStore(config.localDataRoot ?? localRoot, {
|
|
310
310
|
onCorruptRead: (info) => logger.warn("mailbox_corrupt_read", { path: info.path, reason: info.reason }),
|
|
311
311
|
});
|
|
312
312
|
}
|
|
313
|
-
if (mailboxStore)
|
|
314
|
-
|
|
313
|
+
if (mailboxStore) {
|
|
314
|
+
const laneVerdict = mailboxCrossProcessMountVerdict(mailboxStore);
|
|
315
|
+
logger.info("mailbox_store_enabled", {
|
|
316
|
+
backend: pgPool ? "pg" : mysqlPool ? "tidb" : "file",
|
|
317
|
+
crossProcessSafe: mailboxStore.crossProcessSafe,
|
|
318
|
+
peerLaneMountable: laneVerdict.ok,
|
|
319
|
+
...(laneVerdict.ok ? {} : { peerLaneRefusal: laneVerdict.code }),
|
|
320
|
+
});
|
|
321
|
+
}
|
|
315
322
|
}
|
|
316
323
|
let usageWindowStore;
|
|
317
324
|
if (config.usageWindows) {
|
package/dist/config-catalog.d.ts
CHANGED
|
@@ -1,32 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DESIGN-278 §5 S2([ref])—— 配置目录本体:`GET /v1/config/catalog` 的数据层。
|
|
3
|
-
*
|
|
4
|
-
* ## 形
|
|
5
|
-
* 目录 = **逐 env 键**一行(分母 = 全 `src/` 生产运行时的 env 读取点;完备性由
|
|
6
|
-
* `test/config-catalog.test.ts` 的 D1 双向 AST 对账门执法 —— 多一行是幽灵键、少一行是漏登记,两个方向
|
|
7
|
-
* 都当场红)。每行静态登记 `{域、类型、一句话语义、staticDefault?/derivedDefaultNote?、危险轴、center
|
|
8
|
-
* 联接(domain/path/优先序/时机)}`,运行期由 {@link buildConfigCatalog} 补上**本进程实算**的
|
|
9
|
-
* `{envHeld、effectiveLane、effectiveValue、center.managedNow/effectiveNow/domainExists}`。
|
|
10
|
-
*
|
|
11
|
-
* ## 词表纪律([ref]:闭集,未知词=编译红)
|
|
12
|
-
* · 类型 {@link CATALOG_VALUE_TYPES} / 时机 {@link CATALOG_TIMINGS} / 危险轴 {@link CATALOG_DANGER_AXES}
|
|
13
|
-
* 全是 `as const` 闭集;restart 片集 {@link CATALOG_RESTART_SLICES} 用 `Record<RestartSlice, true>`
|
|
14
|
-
* 锁步 —— core/config-center 的片集变了,这里不改就 tsc 红。
|
|
15
|
-
* · 域 = `ServiceConfigGroups` 的九组键(类型锁步,不自铸第二份分组)。
|
|
16
|
-
*
|
|
17
|
-
* ## secret 纪律(设计稿 §0.5 补偿条款)
|
|
18
|
-
* `secret` 类值**永不出本模块**(只回 `{present}`);`opaque` 类(策略 JSON/公钥表/证书)回
|
|
19
|
-
* `{present, length}`;`url` 类剥 userinfo(config 实算腿与 env 原文腿同裁)。机器钉 =
|
|
20
|
-
* test/config-catalog.test.ts 的响应体 canary 扫描格 + 名字启发式兜底格。
|
|
21
|
-
*
|
|
22
|
-
* ## 生效时机模型(设计稿 §3:标注是「键 × 写入通道」的属性)
|
|
23
|
-
* env 腿恒 `deploy`(env 在运行期不可变;retired/无消费键标 `inert`);center 腿按域:limits 热
|
|
24
|
-
* (costQuotaWindowSec 除外 —— 显式 deferred,铸因 `cost-quota-window`)、governance 热二件、
|
|
25
|
-
* approvalRequire 走 `runtime-gates` 重启片、readFace 族 `read-face` 片且 **env-wins**(⚪ 成因 a)、
|
|
26
|
-
* models 面 **本进程实算**(tier 表在场 ⇒ restart/models-tiers,tier-less ⇒ hot)。
|
|
27
|
-
* readFace 在 settings-schema 现行 DOMAINS 里**没有域**(R-15:暂不开)⇒ `domainExists:false`,
|
|
28
|
-
* writeLanes 不含 center(⚪ 成因 b 的诚实呈现)。
|
|
29
|
-
*/
|
|
30
1
|
import type { ServiceConfig, ServiceConfigGroups } from "./config-types.js";
|
|
31
2
|
import type { ConfigKnobRecord } from "./config.js";
|
|
32
3
|
import type { RestartSlice } from "./config-center/restart-signal.js";
|
package/dist/config-catalog.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CROSS_SESSION_INBOUND_SETTINGS, CROSS_SESSION_DIALOG_EXPIRY_VALUES } from "@sema-agent/core";
|
|
1
2
|
export const CATALOG_VALUE_TYPES = ["boolean", "number", "string", "enum", "csv", "json", "path", "url", "secret", "opaque"];
|
|
2
3
|
export const CATALOG_TIMINGS = ["hot", "restart", "deploy", "inert"];
|
|
3
4
|
export const CATALOG_DANGER_AXES = ["security", "billing", "data"];
|
|
@@ -84,6 +85,8 @@ export const CONFIG_CATALOG = [
|
|
|
84
85
|
r("CONFIG_REQUIRE_ROSTER", "integrations", "boolean", "远程 registry 非 dryRun 时布防 ready 门:roster 未落地 ⇒ 计费提交 503 + /health ready:false(严格 'true')", { staticDefault: "false" }),
|
|
85
86
|
r("CORS_ORIGIN", "auth", "csv", "CORS 白名单(单值 v1 兼容回显;多值按请求 Origin 匹配 + Vary;未设=无 CORS 面)", { danger: SEC, configKey: "corsOrigins" }),
|
|
86
87
|
r("COST_QUOTA_WINDOW_SEC", "limitsHttp", "number", "per-principal 成本配额窗长(秒);SQL 腿窗长进桶主键 ⇒ center 腿显式 deferred(重启生效)", { staticDefault: "86400", danger: BILL, configKey: "costQuotaWindowSec", center: cLimits("costQuotaWindowSec", { timing: "restart", restartReason: "cost-quota-window" }) }),
|
|
88
|
+
r("CROSS_SESSION_DIALOG_EXPIRY", "approval", "enum", "held 跨会话消息等待人审的期限(CC settings 键名 dialogExpiry;未设=不铸键,引擎自落缺省 5m;词表外拒启)", { danger: SEC, enumValues: [...CROSS_SESSION_DIALOG_EXPIRY_VALUES], configKey: "crossSessionDialogExpiry", derivedDefaultNote: "缺席 ⇒ 不铸键,core 自缺省 5m", resolve: (c) => c.crossSessionDialogExpiry ?? null }),
|
|
89
|
+
r("CROSS_SESSION_INBOUND", "approval", "enum", "入站跨会话消息的部署/组织层治理(CC settings 键名 crossSessionInbound 的 managed 层;未设=本层不表态≠accept;词表外拒启)", { danger: SEC, enumValues: [...CROSS_SESSION_INBOUND_SETTINGS], configKey: "crossSessionInbound", derivedDefaultNote: "缺席 ⇒ managed 层不设,由其余层与 mode-parity 决定", resolve: (c) => c.crossSessionInbound ?? null }),
|
|
87
90
|
r("DB_BACKEND", "store", "enum", "store 后端引擎选择(mysql 兼容/pg/本机文件店/纯内存)", { enumValues: ["mysql", "pg", "local", "memory"], danger: DATA, derivedDefaultNote: "裸 boot ⇒ local(多租户裸 boot ⇒ memory + notice);有 SQL 信号 ⇒ mysql", configKey: "dbBackend", resolve: (c) => c.dbBackend }),
|
|
88
91
|
r("DB_QUERY_TIMEOUT_MS", "store", "number", "per-query DB 超时(ms;坏值回默认姿态+warn,绝不 NaN 进 driver)", { derivedDefaultNote: "缺席 ⇒ 池级不设/计数族 30s(按引擎)", configKey: "dbQueryTimeoutMs" }),
|
|
89
92
|
r("DEFAULT_SCENARIO", "integrations", "string", "出厂缺省场景(编码产品出厂态;通用中性 persona 用 default 显式选回)", { staticDefault: "code", configKey: "defaultScenario" }),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { readEffectiveWire, PrincipalCapsWire } from "@sema-agent/settings-schema";
|
|
3
3
|
import { centerPromptsFromEffective } from "../prompts-domain-validate.js";
|
|
4
|
+
import { foldEffectiveReadWarning } from "./read-warnings.js";
|
|
4
5
|
export async function fetchEffective(baseUrl, token, etag, fetchImpl = fetch, worker) {
|
|
5
6
|
const scheme = new URL(baseUrl).protocol;
|
|
6
7
|
if (scheme !== "http:" && scheme !== "https:")
|
|
@@ -21,17 +22,12 @@ export async function fetchEffective(baseUrl, token, etag, fetchImpl = fetch, wo
|
|
|
21
22
|
delete wire.prompts;
|
|
22
23
|
else
|
|
23
24
|
wire.prompts = centerPrompts;
|
|
24
|
-
const domainErrors =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
? { domain: w.domain, error: `unknown keys carried to consumer (spelling?): ${w.keys.join(", ")}`.slice(0, 600) }
|
|
31
|
-
: w.kind === "unread-config-file"
|
|
32
|
-
? { domain: w.domain ?? "config.d", error: `unread config file ${w.file} (${w.why})`.slice(0, 600) }
|
|
33
|
-
: undefined)
|
|
34
|
-
.filter((r) => r !== undefined);
|
|
25
|
+
const domainErrors = [];
|
|
26
|
+
for (const w of warnings) {
|
|
27
|
+
const f = foldEffectiveReadWarning(w);
|
|
28
|
+
if (f !== null)
|
|
29
|
+
domainErrors.push(f);
|
|
30
|
+
}
|
|
35
31
|
const effective = wire;
|
|
36
32
|
return { effective, etag: res.headers.get("etag") ?? undefined, ...(domainErrors.length > 0 ? { domainErrors } : {}) };
|
|
37
33
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `EffectiveReadWarning` → 候选门口径的**单点**折叠(本地腿 `config-provider.ts` 与远程腿 `http-client.ts` 共用;
|
|
3
|
+
* 两腿各抄一份映射正是漂移的成因——远程腿曾漏掉一次改动,版本超前的 center 多一个字段就整份远程 refresh 整拒)。
|
|
4
|
+
*
|
|
5
|
+
* **律只有一条:未知键 = 候选门错误,零特例。** 「别的写者按契约放的扩展键」(壳写在 models 条目上的 `sema*`)
|
|
6
|
+
* 不是本函数要分辨的事——那由 settings-schema 的 `EXTENSION_NAMESPACES` 在**声明处**说清(登记的键既不点名也不计数,
|
|
7
|
+
* 1.5.0 起);到了这里的每一个键都是「写了没生效」的拼错或越界,与 domain-defaulted 同级。此前本仓在下游按 kind/
|
|
8
|
+
* 按域/按键路径闭集/按 64 满额四层猜意图,每层都被下一轮复审打穿——意图只能在声明处说,消费方不猜。
|
|
9
|
+
*
|
|
10
|
+
* 截断:schema 的键列表有界(64),超界带 `truncatedFrom`(真实总数)——文案如实带上,消费方永远不把有界列表当穷举。
|
|
11
|
+
* 词表是闭集:`switch` 穷举 `kind`,schema 加新 kind 这里编译红,不会静默漏臂。
|
|
12
|
+
*/
|
|
13
|
+
import type { EffectiveReadWarning } from "@sema-agent/settings-schema";
|
|
14
|
+
export type FoldedReadWarning = {
|
|
15
|
+
readonly domain: string;
|
|
16
|
+
readonly error: string;
|
|
17
|
+
};
|
|
18
|
+
/** null = 不入诊断面(`hosts-grandfathered`:值已被收编接受,与本地店同口径)。 */
|
|
19
|
+
export declare function foldEffectiveReadWarning(w: EffectiveReadWarning): FoldedReadWarning | null;
|
|
20
|
+
//# sourceMappingURL=read-warnings.d.ts.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const MAX_ERROR_CHARS = 600;
|
|
2
|
+
const cap = (s) => s.slice(0, MAX_ERROR_CHARS);
|
|
3
|
+
const keyList = (prefix, keys, truncatedFrom) => {
|
|
4
|
+
const total = truncatedFrom ?? keys.length;
|
|
5
|
+
const budget = MAX_ERROR_CHARS - prefix.length;
|
|
6
|
+
const shown = [];
|
|
7
|
+
let used = 0;
|
|
8
|
+
const suffixFor = (n) => (n < total ? ` (+${total - n} more, list truncated)` : "");
|
|
9
|
+
for (const k of keys) {
|
|
10
|
+
const piece = (shown.length > 0 ? ", " : "") + k;
|
|
11
|
+
if (used + piece.length + suffixFor(shown.length + 1).length > budget)
|
|
12
|
+
break;
|
|
13
|
+
shown.push(k);
|
|
14
|
+
used += piece.length;
|
|
15
|
+
}
|
|
16
|
+
return `${prefix}${shown.join(", ")}${suffixFor(shown.length)}`;
|
|
17
|
+
};
|
|
18
|
+
export function foldEffectiveReadWarning(w) {
|
|
19
|
+
switch (w.kind) {
|
|
20
|
+
case "hosts-grandfathered":
|
|
21
|
+
return null;
|
|
22
|
+
case "domain-defaulted":
|
|
23
|
+
return { domain: w.domain, error: cap(w.error instanceof Error ? w.error.message : String(w.error)) };
|
|
24
|
+
case "unknown-keys-dropped":
|
|
25
|
+
return { domain: w.domain, error: keyList("unknown keys dropped by domain schema: ", w.keys, w.truncatedFrom) };
|
|
26
|
+
case "unknown-keys-carried":
|
|
27
|
+
return { domain: w.domain, error: keyList("unknown keys carried to consumer (spelling?): ", w.keys, w.truncatedFrom) };
|
|
28
|
+
case "unread-config-file":
|
|
29
|
+
return { domain: w.domain ?? "config.d", error: cap(`unread config file ${w.file} (${w.why})`) };
|
|
30
|
+
default: {
|
|
31
|
+
const never = w;
|
|
32
|
+
throw new Error(`unhandled EffectiveReadWarning kind: ${JSON.stringify(never)}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=read-warnings.js.map
|
|
@@ -7,6 +7,9 @@ import { fetchEffective as remoteFetchEffective, fetchSkillContent as remoteFetc
|
|
|
7
7
|
* 连坐全包回落 env——坏域按该域 schema default 落+错误单列,好域照常生效;caller(main.ts)对每条打
|
|
8
8
|
* per-domain warn 点名坏域。gate 域(governance/rosters/…)坏文件 tolerant 仍 throw(READ 容错不放宽
|
|
9
9
|
* gate fail-loud,registry-core 半场精化)——那条路走既有的整包 catch。 */
|
|
10
|
+
/** 壳写在 `config.d/models.json` 条目上的装饰键(`sema*`)自 settings-schema 1.5.0 起是**声明过的扩展命名空间**
|
|
11
|
+
* (`EXTENSION_NAMESPACES`):schema 照旧 strip、但不再报「未知键」,所以本函数收到的每一个未知键都是拼错/越界 ⇒ 候选门错误。
|
|
12
|
+
* 此前把这类键当「通知」放行的整套下游机制(域豁免/键路径闭集/满额特判/单独的通知面)已全部撤回——意图在声明处说,消费方不猜。 */
|
|
10
13
|
export type FetchEffectiveResult = {
|
|
11
14
|
effective: EffectiveConfig;
|
|
12
15
|
etag?: string;
|
package/dist/config-provider.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHmac, randomBytes } from "node:crypto";
|
|
2
|
+
import { foldEffectiveReadWarning } from "./config-center/read-warnings.js";
|
|
2
3
|
import { FileConfigStore } from "@sema-agent/settings-schema/node";
|
|
3
4
|
import { findSkillContent, skillContentHash, refIntegrityIssues, siblingResolver, } from "@sema-agent/settings-schema";
|
|
4
5
|
import { redactSecrets } from "./trace/redact.js";
|
|
@@ -62,14 +63,9 @@ export class LocalConfigProvider {
|
|
|
62
63
|
const store = this.#injectedStore ??
|
|
63
64
|
new FileConfigStore(this.root, {
|
|
64
65
|
onWarning: (w) => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
parseWarnings.push({ domain: w.domain, error: `unknown keys dropped by domain schema: ${w.keys.join(", ")}` });
|
|
69
|
-
else if (w.kind === "unknown-keys-carried")
|
|
70
|
-
parseWarnings.push({ domain: w.domain, error: `unknown keys carried to consumer (spelling?): ${w.keys.join(", ")}` });
|
|
71
|
-
else if (w.kind === "unread-config-file")
|
|
72
|
-
parseWarnings.push({ domain: w.domain ?? "config.d", error: `unread config file ${w.file} (${w.why})` });
|
|
66
|
+
const f = foldEffectiveReadWarning(w);
|
|
67
|
+
if (f !== null)
|
|
68
|
+
parseWarnings.push(f);
|
|
73
69
|
},
|
|
74
70
|
});
|
|
75
71
|
const { effective: eff, domainErrors } = await store.getEffective({ tolerant: true });
|
package/dist/config-types.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* compiling unchanged. All imports below are top-level `import type` (erased — never a load edge,
|
|
7
7
|
* see test/module-cycle-gate.test.ts header on verbatimModuleSyntax). */
|
|
8
8
|
import type { SealedKeyPoison } from "./sealed-key.js";
|
|
9
|
-
import type { A2aServerSpec, CompliancePosture, FileHistoryRetentionPolicy, LockedKey, McpServerSpec, Model, ModelRoles, RetentionPolicy } from "@sema-agent/core";
|
|
9
|
+
import type { A2aServerSpec, CompliancePosture, CrossSessionDialogExpiry, CrossSessionInboundSetting, FileHistoryRetentionPolicy, LockedKey, McpServerSpec, Model, ModelRoles, RetentionPolicy } from "@sema-agent/core";
|
|
10
10
|
import type { ApprovalHmacKey, PrincipalJwtKey } from "./auth-keys.js";
|
|
11
11
|
import type { ElicitationThrottle } from "./elicitation.js";
|
|
12
12
|
import type { QuestionThrottle } from "./question.js";
|
|
@@ -1299,6 +1299,16 @@ export interface ServiceConfigFlat {
|
|
|
1299
1299
|
* 「缺席=不阻」⇒ 壳发 `permissionMode:"auto"` 即武装)。词表外的值 boot 拒启(安全轴旋钮不许静默回默认)。
|
|
1300
1300
|
* 合成点 = `boot/runtime-caps.ts` 最外层(applyLocalAutoModeDeny);读面 = `/v1/capabilities.permissionModeAuto`。 */
|
|
1301
1301
|
permissionsDisableAutoMode: boolean;
|
|
1302
|
+
/** S-111([ref] §4.4)—— CC `settings.crossSessionInbound` 的**部署/组织层**(引擎层形的 `managed` 层,
|
|
1303
|
+
* CC `policySettings` 对位):本部署对入站跨会话消息的治理三态。`accept` 投递 / `hold` 停在收件会话的待审
|
|
1304
|
+
* 队列 / `refuse` 整体退出车道。**未设 = 本层不设**(不是 accept):引擎读作「managed 层未表态」,由其余层
|
|
1305
|
+
* 与 mode-parity 决定。词表外的值 boot 拒启(保护型旋钮不许静默回默认)。
|
|
1306
|
+
* ⚠️ 供层点 = `cross-session-settings.ts`,生效前提 = 引擎的 peer 目录席在场(座缺席 ⇒ 整条车道不挂)。 */
|
|
1307
|
+
crossSessionInbound?: CrossSessionInboundSetting;
|
|
1308
|
+
/** S-111 —— CC `settings.dialogExpiry` 的部署层:held 跨会话消息等待人审多久后按安全缺省结算(带回执过期,
|
|
1309
|
+
* 不静默吞)。`"never"` = 不设期限。**未设 ⇒ 不铸键**,由引擎落它自己的缺省(`"5m"`)——本仓不复制上游
|
|
1310
|
+
* 缺省值。词表外 boot 拒启。⚠️ CC 同名键还有第二个消费面(远端审批对话框停靠时长),本旋钮今天不驱动它。 */
|
|
1311
|
+
crossSessionDialogExpiry?: CrossSessionDialogExpiry;
|
|
1302
1312
|
/** [ref]④ defer face (EXPERIMENTAL, default OFF): mark the default scenario's LONG-TAIL first-party tools
|
|
1303
1313
|
* (today = SelectEnvironment only) `defer:true` (core tool-disclosure: the model sees a placeholder until it
|
|
1304
1314
|
* ToolSearch-loads the schema). Assessment says the win is marginal for us (spec.tools total ≈4.2k tokens, of
|
|
@@ -1628,7 +1638,7 @@ export type ServiceStoreConfig = Pick<ServiceConfigFlat, "sessionBackend" | "ses
|
|
|
1628
1638
|
export type ServiceModelPlaneConfig = Pick<ServiceConfigFlat, "gatewayBaseUrl" | "gatewayApiKey" | "gatewayFallbackUrls" | "gatewayMaxRetries" | "anthropic" | "resilience" | "model" | "models" | "modelApiKeyEnv" | "modelApiKeys" | "modelQuotaWeights" | "tiers" | "projects" | "roles" | "atModelAllowlist" | "cascadeLadder" | "degrade">;
|
|
1629
1639
|
/** 组:approval(审批 / HITL 门)。`directDoorActive` 无 env 解析腿(装配层三域合取的产物),但语义上
|
|
1630
1640
|
* 就是本组的门状态,故进组;`parseApprovalDomain` 的返回类型相应是 `Omit<…, "directDoorActive">`。 */
|
|
1631
|
-
export type ServiceApprovalConfig = Pick<ServiceConfigFlat, "approvalRequire" | "approvalDeny" | "approvalTimeoutSec" | "approvalAutoBudget" | "approvalNeverAuto" | "approvalHmacKeys" | "durableApproval" | "directApprovalDoor" | "directDoorActive" | "resourceSuspend" | "resourceSuspendTtlSec" | "resourceSuspendTotalTokens" | "resourceSuspendTotalBudgetUsd" | "resourceSuspendMaxSlices" | "askQuestionEnabled" | "questionThrottle" | "toolApprovalEnabled" | "permissionRulesEnabled" | "permissionRulesEnabledExplicit" | "streamAskWindowMarginMs" | "streamApproval" | "unattendedApprovalPolicy" | "mcpElicitation" | "sensitiveWritePatterns" | "manualModeShellGate" | "permissionsDisableAutoMode">;
|
|
1641
|
+
export type ServiceApprovalConfig = Pick<ServiceConfigFlat, "approvalRequire" | "approvalDeny" | "approvalTimeoutSec" | "approvalAutoBudget" | "approvalNeverAuto" | "approvalHmacKeys" | "durableApproval" | "directApprovalDoor" | "directDoorActive" | "resourceSuspend" | "resourceSuspendTtlSec" | "resourceSuspendTotalTokens" | "resourceSuspendTotalBudgetUsd" | "resourceSuspendMaxSlices" | "askQuestionEnabled" | "questionThrottle" | "toolApprovalEnabled" | "permissionRulesEnabled" | "permissionRulesEnabledExplicit" | "streamAskWindowMarginMs" | "streamApproval" | "unattendedApprovalPolicy" | "mcpElicitation" | "sensitiveWritePatterns" | "manualModeShellGate" | "permissionsDisableAutoMode" | "crossSessionInbound" | "crossSessionDialogExpiry">;
|
|
1632
1642
|
/** 组:memory(记忆面 + TOC 同步腿)。 */
|
|
1633
1643
|
export type ServiceMemoryConfig = Pick<ServiceConfigFlat, "memoryEngineEnabled" | "memoryEngineDir" | "memoryEngineRemoteLaneAllowed" | "memoryEngineBackend" | "memoryScope" | "memoryPersistenceCapable" | "memorySync" | "memoryEmbedder" | "memoryOrgAdmissionMode" | "memoryDelegationEvidence" | "memoryProvenance" | "memoryCapturePolicy" | "memoryConsolidationDriver" | "memoryOrgDirectoryJson" | "memoryOrgGrantTtlMs" | "memoryOrgUnavailableBackoffMs" | "projectMemoryEnabled" | "syncImportLeaseStaleSec">;
|
|
1634
1644
|
/** 组:auth(鉴权 / 身份 / 治理棒)。`commandPolicy` 只有 sema-registry 腿(无 env 标量形),故 env 解析
|
package/dist/config.js
CHANGED
|
@@ -2,7 +2,7 @@ import { readFileSync } from "node:fs";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { BUILTIN_COMPLIANCE_DENIES, COMPLIANCE_CAPABILITIES, compileReadDeny, resolveReadDenyBuiltins, CODE_AGENT_PROMPT, formatUserScope, PROTOCOL_TABLE, protocolOf, RECOMMENDED_SENSITIVE_PATTERNS, RETIRED_TOOL_NAMES, resolveFileHistoryRetention, resolveLockedKeys, validatePermissionRules } from "@sema-agent/core";
|
|
5
|
+
import { BUILTIN_COMPLIANCE_DENIES, COMPLIANCE_CAPABILITIES, CROSS_SESSION_INBOUND_SETTINGS, CROSS_SESSION_DIALOG_EXPIRY_VALUES, compileReadDeny, resolveReadDenyBuiltins, CODE_AGENT_PROMPT, formatUserScope, PROTOCOL_TABLE, protocolOf, RECOMMENDED_SENSITIVE_PATTERNS, RETIRED_TOOL_NAMES, resolveFileHistoryRetention, resolveLockedKeys, validatePermissionRules } from "@sema-agent/core";
|
|
6
6
|
import { ROSTER_PRIMARY_ROLES, ROSTER_CHEAP_ROLES } from "@sema-agent/settings-schema";
|
|
7
7
|
import { parseApprovalHmacKeys, parsePrincipalJwks } from "./auth-keys.js";
|
|
8
8
|
import { DEFAULT_ELICITATION_THROTTLE } from "./elicitation.js";
|
|
@@ -420,6 +420,15 @@ function enumEnv(name, fallback, allowed) {
|
|
|
420
420
|
throw new Error(`env ${name}="${v}" must be one of: ${allowed.join(", ")}`);
|
|
421
421
|
return v;
|
|
422
422
|
}
|
|
423
|
+
function optionalEnumKey(key, envName, raw, allowed) {
|
|
424
|
+
if (raw === undefined || raw === "")
|
|
425
|
+
return {};
|
|
426
|
+
if (!allowed.includes(raw)) {
|
|
427
|
+
throw new Error(`env ${envName}="${raw.slice(0, 120)}" must be one of: ${allowed.join(", ")} — or leave it UNSET to say nothing on this layer. ` +
|
|
428
|
+
`Refusing to boot rather than reading a misspelled value as "unset": that runs the deployment with NO policy on this axis while the operator believes one is configured`);
|
|
429
|
+
}
|
|
430
|
+
return { [key]: raw };
|
|
431
|
+
}
|
|
423
432
|
function headerNameEnv(name, fallback) {
|
|
424
433
|
const v = env(name, fallback);
|
|
425
434
|
if (!/^[A-Za-z0-9_-]+$/.test(v))
|
|
@@ -980,6 +989,8 @@ function parseApprovalDomain(ctx) {
|
|
|
980
989
|
`Refusing to boot rather than treating a misspelled value as "unset": that silently ran the deployment with NO shell gate while the operator believed one was configured`);
|
|
981
990
|
})(process.env.MANUAL_MODE_SHELL_GATE),
|
|
982
991
|
permissionsDisableAutoMode: boolEnv("PERMISSIONS_DISABLE_AUTO_MODE", false),
|
|
992
|
+
...optionalEnumKey("crossSessionInbound", "CROSS_SESSION_INBOUND", process.env.CROSS_SESSION_INBOUND, CROSS_SESSION_INBOUND_SETTINGS),
|
|
993
|
+
...optionalEnumKey("crossSessionDialogExpiry", "CROSS_SESSION_DIALOG_EXPIRY", process.env.CROSS_SESSION_DIALOG_EXPIRY, CROSS_SESSION_DIALOG_EXPIRY_VALUES),
|
|
983
994
|
mcpElicitation: {
|
|
984
995
|
enabled: boolEnv("MCP_ELICITATION_ENABLED", false),
|
|
985
996
|
throttle: {
|
|
@@ -1792,7 +1803,7 @@ const APPROVAL_GROUP_KEYS = [
|
|
|
1792
1803
|
"approvalRequire", "approvalDeny", "approvalTimeoutSec", "approvalAutoBudget", "approvalNeverAuto",
|
|
1793
1804
|
"approvalHmacKeys", "durableApproval", "directApprovalDoor", "directDoorActive", "resourceSuspend",
|
|
1794
1805
|
"resourceSuspendTtlSec", "resourceSuspendTotalTokens", "resourceSuspendTotalBudgetUsd", "resourceSuspendMaxSlices", "askQuestionEnabled", "questionThrottle", "toolApprovalEnabled", "permissionRulesEnabled", "permissionRulesEnabledExplicit", "streamAskWindowMarginMs", "streamApproval", "unattendedApprovalPolicy", "mcpElicitation",
|
|
1795
|
-
"sensitiveWritePatterns", "manualModeShellGate", "permissionsDisableAutoMode",
|
|
1806
|
+
"sensitiveWritePatterns", "manualModeShellGate", "permissionsDisableAutoMode", "crossSessionInbound", "crossSessionDialogExpiry",
|
|
1796
1807
|
];
|
|
1797
1808
|
const MEMORY_GROUP_KEYS = [
|
|
1798
1809
|
"memoryEngineEnabled", "memoryEngineDir", "memoryEngineRemoteLaneAllowed", "memoryEngineBackend", "memoryScope",
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S-111 件③ —— 跨会话入站治理的**三层供给**([ref] §4.4)。
|
|
3
|
+
*
|
|
4
|
+
* 分工(单一属主):**判定归引擎**(`resolveCrossSessionInboundSetting` 的层次收紧 + `judgeCrossSessionInbound`
|
|
5
|
+
* 的 mode-parity 与 hold 因由,全在 core 的纯函数里);**本仓只供层**。本文件不判、不折、不比较秩——
|
|
6
|
+
* 它只回答一个问题:「managed / user / repo 这三层,本部署各自的值从哪里来?」
|
|
7
|
+
*
|
|
8
|
+
* ## 三层来源(逐层如实,缺席也点名)
|
|
9
|
+
*
|
|
10
|
+
* | 层 | 引擎语义(CC 对位) | 本仓的源 | 今日状态 |
|
|
11
|
+
* |---|---|---|---|
|
|
12
|
+
* | `managed` | `policySettings`(组织/部署强制层) | `CROSS_SESSION_INBOUND` 部署旋钮 | **已接线** |
|
|
13
|
+
* | `user` | `userSettings`/`flagSettings`(用户自己的层) | `body.settings.crossSessionInbound` | **缺席**,见下 |
|
|
14
|
+
* | `repo` | `localSettings`/`projectSettings`(仓库层) | 本服务没有项目层 settings 源 | **缺席** |
|
|
15
|
+
*
|
|
16
|
+
* ### `user` 层为什么今天缺席(诚实面,不是遗漏)
|
|
17
|
+
*
|
|
18
|
+
* 引擎的座位 `RunnerDeps.crossSessionInbound` 是**部署级**的(一个 Runner 单例,getter 无会话上下文),
|
|
19
|
+
* 而 `crossSessionInbound` 在 CC 里是**每会话**的 settings 值。本服务是「一个 Runner × 多会话」的宿主:
|
|
20
|
+
* 把某一次提交的 `body.settings.crossSessionInbound` 塞进部署级座位,等于让 A 会话的设置去治理 B 会话的
|
|
21
|
+
* 排水——比不接线更糟,且是静默的。可选的补法只有两条,都不在本件射程内:
|
|
22
|
+
* (a) 引擎开一个**每任务**座(形如既有的 `TaskSpec.autoModeRequested` 意图座)——上游诉求,已留档;
|
|
23
|
+
* (b) 本仓用 per-run 异步上下文托住层,并保证**每一条** run 腿都建立该上下文——漏一条腿 =
|
|
24
|
+
* 用户设的 `refuse` 静默失效 = 安全轴 fail-open,不许半接。
|
|
25
|
+
* 在 (a)/(b) 落地之前,提交面对这两个键**明拒**(`TASK_SETTINGS_UNSUPPORTED_KEYS`,400 体 `unsupportedKeys`
|
|
26
|
+
* 逐字列名),而不是「受理但不执行」——在保护型配置上那是静默的假安全;宽容层(RESUME 重放)结构上不读它们。
|
|
27
|
+
*
|
|
28
|
+
* ### 另一件如实:整条车道今日未挂
|
|
29
|
+
*
|
|
30
|
+
* 两个座位在引擎侧都**以 `RunnerDeps.peerDirectory` 在场为前提**(座缺席 ⇒ 跨会话车道整条不挂,
|
|
31
|
+
* 每个面与 pre-385 构建逐字节相同)。本仓的 peer 目录席位是另一件欠账,故本文件铸出的层今天是
|
|
32
|
+
* **就位待命**而非生效中。这不改变供层的正确性:目录席到货那天零改动即生效。
|
|
33
|
+
*/
|
|
34
|
+
import type { CrossSessionDialogExpiry, CrossSessionInboundSetting, CrossSessionInboundSettingLayers } from "@sema-agent/core";
|
|
35
|
+
/** 引擎层形的层名 —— 从 core 的类型上取,**引擎加一层 = 本文件编译错**(下面两处闭集都锁在这个联合上)。 */
|
|
36
|
+
export type CrossSessionInboundLayerName = keyof CrossSessionInboundSettingLayers;
|
|
37
|
+
/** 层名的运行时闭集(与类型同源:表的键即闭集,表不全 = 编译错)。 */
|
|
38
|
+
export declare const CROSS_SESSION_INBOUND_LAYER_NAMES: readonly ["managed", "user", "repo"];
|
|
39
|
+
export interface CrossSessionInboundLayerSource {
|
|
40
|
+
/** 这一层的值在本仓从哪里来(缺席的层写清「为什么没有源」,不留空)。 */
|
|
41
|
+
readonly source: string;
|
|
42
|
+
/** 今天真的接线了吗。`false` = 本仓恒不铸这一层的键(引擎读作「该层未设」)。 */
|
|
43
|
+
readonly wired: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* **三层来源登记表** —— 头注那张表的机器可读形,同时是 {@link buildCrossSessionInboundLayers} 的驱动表。
|
|
47
|
+
* 一处改、两处同步:把某层翻 `wired: true` 而不给取值臂,构造时**响亮抛**(见下),不会静默铸空层。
|
|
48
|
+
*/
|
|
49
|
+
export declare const CROSS_SESSION_INBOUND_LAYER_SOURCES: Record<CrossSessionInboundLayerName, CrossSessionInboundLayerSource>;
|
|
50
|
+
/** 本文件读的部署配置切片(与 `ServiceConfig` 的两个可选键同名同形)。 */
|
|
51
|
+
export interface CrossSessionSettingsConfig {
|
|
52
|
+
crossSessionInbound?: CrossSessionInboundSetting;
|
|
53
|
+
crossSessionDialogExpiry?: CrossSessionDialogExpiry;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 按 {@link CROSS_SESSION_INBOUND_LAYER_SOURCES} 铸引擎层形。
|
|
57
|
+
*
|
|
58
|
+
* 纯数据出参(`build*` 命名律);未接线的层**恒不铸键** —— 引擎把缺席读作「该层未设」,与铸一个
|
|
59
|
+
* `undefined` 值不同(后者会让层次解析多走一趟无谓的读)。
|
|
60
|
+
*/
|
|
61
|
+
export declare function buildCrossSessionInboundLayers(cfg: CrossSessionSettingsConfig): CrossSessionInboundSettingLayers;
|
|
62
|
+
/**
|
|
63
|
+
* 部署级 `dialogExpiry`(held 跨会话消息等待人审的期限)。未设 ⇒ **不铸键**,由引擎落它自己的缺省
|
|
64
|
+
* (`CROSS_SESSION_DIALOG_EXPIRY_DEFAULT` = `"5m"`)—— 本仓不复制上游缺省值,免得两处各写一个数。
|
|
65
|
+
*
|
|
66
|
+
* ⚠️ 同名 CC 键还有**第二个**消费面(转发到远端客户端的审批对话框停靠时长)。本函数只答跨会话这一面;
|
|
67
|
+
* 停靠面的接线是另一件,今天两者不共享这一个旋钮,发布面如实说明。
|
|
68
|
+
*/
|
|
69
|
+
export declare function crossSessionDialogExpiryOf(cfg: CrossSessionSettingsConfig): CrossSessionDialogExpiry | undefined;
|
|
70
|
+
//# sourceMappingURL=cross-session-settings.d.ts.map
|