@sema-agent/server 7.107.0 → 7.109.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.
Files changed (101) hide show
  1. package/MIGRATION.md +72 -1
  2. package/USAGE.md +51 -25
  3. package/dist/approval-ask-audit-store.d.ts +62 -4
  4. package/dist/approval-ask-audit-store.js +67 -11
  5. package/dist/approval-ask-machine.d.ts +9 -25
  6. package/dist/approval-ask-machine.js +5 -2
  7. package/dist/approval-card.d.ts +32 -3
  8. package/dist/approval-card.js +29 -2
  9. package/dist/approval.js +16 -13
  10. package/dist/bench/s1/live-deps.d.ts +4 -5
  11. package/dist/bench/s1/live-deps.js +9 -10
  12. package/dist/boot/coordinators.d.ts +4 -0
  13. package/dist/boot/coordinators.js +3 -2
  14. package/dist/boot/leader.js +0 -2
  15. package/dist/boot/resolve-spec.d.ts +1 -1
  16. package/dist/boot/resolve-spec.js +3 -8
  17. package/dist/boot/shutdown.d.ts +8 -0
  18. package/dist/boot/shutdown.js +31 -8
  19. package/dist/boot/stage-06-runners.d.ts +1 -0
  20. package/dist/boot/stage-06-runners.js +6 -3
  21. package/dist/boot/stage-07-capability-layer.d.ts +1 -0
  22. package/dist/boot/stage-08-reapers.d.ts +1 -0
  23. package/dist/boot/stage-09-leader.d.ts +1 -0
  24. package/dist/boot/stage-10-http-server.d.ts +1 -0
  25. package/dist/boot/stage-10-http-server.js +3 -1
  26. package/dist/brain.js +2 -1
  27. package/dist/capabilities/scenarios.d.ts +3 -2
  28. package/dist/config-catalog.js +1 -3
  29. package/dist/config-center/apply-effective.js +2 -0
  30. package/dist/config-center/types.d.ts +7 -0
  31. package/dist/config-provider.js +1 -0
  32. package/dist/config-types.d.ts +2 -9
  33. package/dist/config.js +2 -5
  34. package/dist/deployment-governance.js +2 -1
  35. package/dist/fleet-client.d.ts +10 -2
  36. package/dist/fleet-client.js +14 -8
  37. package/dist/http/admission.js +8 -2
  38. package/dist/http/memory-compliance-failure-reply.d.ts +41 -0
  39. package/dist/http/memory-compliance-failure-reply.js +73 -0
  40. package/dist/http/memory-store-refusal-reply.d.ts +2 -2
  41. package/dist/http/resume-legs.js +3 -2
  42. package/dist/http/route-ctx.d.ts +3 -3
  43. package/dist/http/routes/capabilities.js +1 -0
  44. package/dist/http/routes/diagnostics.js +2 -0
  45. package/dist/http/routes/memory-compliance.js +2 -34
  46. package/dist/http/routes/memory-origin.d.ts +1 -1
  47. package/dist/http/routes/sessions.js +3 -11
  48. package/dist/http/routes/side-query.js +7 -2
  49. package/dist/http/routes/tasks.js +2 -1
  50. package/dist/http/server.d.ts +2 -2
  51. package/dist/http/wire-types.d.ts +8 -0
  52. package/dist/leader/diffup.d.ts +53 -0
  53. package/dist/leader/diffup.js +95 -1
  54. package/dist/leader/leader.d.ts +0 -6
  55. package/dist/leader/leader.js +1 -1
  56. package/dist/leader/repair-wire.js +1 -1
  57. package/dist/leader/wire.d.ts +3 -10
  58. package/dist/leader/wire.js +39 -13
  59. package/dist/memory-store-refusal.d.ts +2 -1
  60. package/dist/model-entry-headers.d.ts +41 -0
  61. package/dist/model-entry-headers.js +61 -0
  62. package/dist/model-entry-refusal.d.ts +6 -0
  63. package/dist/model-entry-refusal.js +4 -0
  64. package/dist/model-reach-scope.d.ts +55 -0
  65. package/dist/model-reach-scope.js +16 -0
  66. package/dist/model-unreachable-notice.d.ts +38 -0
  67. package/dist/model-unreachable-notice.js +72 -0
  68. package/dist/observability/fail-open.d.ts +5 -5
  69. package/dist/observability/fail-open.js +5 -5
  70. package/dist/observability/run-terminal.d.ts +2 -1
  71. package/dist/outbound-dispatcher.d.ts +69 -0
  72. package/dist/outbound-dispatcher.js +123 -3
  73. package/dist/plugins/approval-ask-store-file.d.ts +2 -1
  74. package/dist/plugins/approval-ask-store-file.js +3 -0
  75. package/dist/plugins/approval-ask-store-memory.d.ts +2 -1
  76. package/dist/plugins/approval-ask-store-memory.js +7 -1
  77. package/dist/plugins/approval-ask-store-sql.d.ts +18 -0
  78. package/dist/plugins/approval-ask-store-sql.js +7 -0
  79. package/dist/plugins/park-commit-watch.d.ts +48 -0
  80. package/dist/plugins/park-commit-watch.js +87 -0
  81. package/dist/request-key-closure.js +1 -1
  82. package/dist/router/route-orchestration.js +7 -2
  83. package/dist/run-local.js +2 -3
  84. package/dist/runs.js +3 -2
  85. package/dist/runtime-governance.d.ts +3 -3
  86. package/dist/runtime-governance.js +3 -2
  87. package/dist/task-settings.js +4 -2
  88. package/dist/tool-approval.d.ts +99 -15
  89. package/dist/tool-approval.js +75 -10
  90. package/dist/tool-rule-names.d.ts +25 -0
  91. package/dist/tool-rule-names.js +5 -0
  92. package/dist/trace/core-keyset-guard.d.ts +14 -2
  93. package/dist/trace/engine-notice-wire.d.ts +3 -1
  94. package/dist/trace/engine-notice-wire.js +2 -0
  95. package/dist/trace/project.d.ts +3 -1
  96. package/dist/trace/project.js +2 -3
  97. package/dist/trace/self-minted-wire.d.ts +71 -0
  98. package/dist/trace/self-minted-wire.js +28 -0
  99. package/dist/unattended-permission-mode.d.ts +54 -93
  100. package/dist/unattended-permission-mode.js +8 -61
  101. package/package.json +3 -3
@@ -8,7 +8,7 @@ import { approvalPayloadFingerprint } from "./plugins/approval-payload-fingerpri
8
8
  import { createLogger } from "./observability/logger.js";
9
9
  import { recordFailOpen } from "./observability/fail-open.js";
10
10
  import { deriveAskId, deriveAskScopedBatchId, deriveBatchId, MAX_DECISION_NOTE_CHARS } from "./approval-ask-machine.js";
11
- import { ApprovalCardEnvelopeSchema, MAX_RULE_OFFERS, buildApprovalCard, buildApprovalCardEnvelope, buildApprovalRequestFrame, buildRevokeFrame, readDenialLimitFallback, readProbeCause, readReadRootCandidate, readRuleEvidence, readRuleOffersAbsence, readRuleOffersAbsenceSeat, readParkRowTrueSeat, readClosedWordSeat, RuleOfferRawSchema, backfillLegacyBatchMemberKind, screenUncoveredDetailSeat, } from "./approval-card.js";
11
+ import { ApprovalCardEnvelopeSchema, MAX_RULE_OFFERS, buildApprovalCard, buildApprovalCardEnvelope, buildApprovalRequestFrame, buildRevokeFrame, readDenialLimitFallback, readProbeCause, readReadRootCandidate, readRuleEvidence, readRuleOffersAbsence, readRuleOffersAbsenceSeat, readParkRowTrueSeat, readAskClassPair, readClosedWordSeat, RuleOfferRawSchema, backfillLegacyBatchMemberKind, screenUncoveredDetailSeat, } from "./approval-card.js";
12
12
  import { MAX_SETTLED_BY_CHARS, POLICY_REFUSAL_DECISION, projectAskTerminalClaimTruth, settledByFitsColumn } from "./plugins/approval-ask-store-sql.js";
13
13
  import { settleByPolicy } from "./approval-policy-settlement.js";
14
14
  import { governanceAskMarksFor, runWithGovernanceAskScope } from "./governance-ask-marks.js";
@@ -26,6 +26,8 @@ const SUSPENDED_POLL_MAX_PER_TICK = 64;
26
26
  const SUSPENDED_POLL_BUDGET_MS = 5_000;
27
27
  const EDITED_DECISION_MARK_CAP_MS = 10_000;
28
28
  const DEFAULT_WINDOW_MARGIN_MS = 10_000;
29
+ const SHUTDOWN_DRAIN_POLL_MS = 50;
30
+ const SHUTDOWN_BEFORE_PARK = "shutdown_before_park";
29
31
  const MAX_ALLOW_SESSIONS = 4096;
30
32
  const DEFAULT_ADMIT_MAX_PER_TASK = 32;
31
33
  const DEFAULT_ADMIT_MAX_PER_OWNER = 256;
@@ -364,6 +366,10 @@ export class ToolApprovalCoordinator {
364
366
  parkedRedeem;
365
367
  askAudit;
366
368
  sessionGrants;
369
+ shutdownDraining = false;
370
+ asksInFlight = 0;
371
+ parkCommits;
372
+ parksAwaitingCommit = new Set();
367
373
  constructor(opts) {
368
374
  this.ruleConsent = opts?.ruleConsent;
369
375
  this.ruleScopeRootFor = opts?.ruleScopeRootFor;
@@ -381,6 +387,8 @@ export class ToolApprovalCoordinator {
381
387
  this.parkTombstonePerPrincipalMax = opts?.parkTombstonePerPrincipalMax ?? DEFAULT_PARK_TOMBSTONE_PER_PRINCIPAL_MAX;
382
388
  this.askAudit = opts?.askAudit;
383
389
  this.sessionGrants = opts?.sessionGrants;
390
+ this.parkCommits = opts?.parkCommits;
391
+ this.parkCommits?.onParkCommitted((calls) => this.noteParkCommitted(calls));
384
392
  }
385
393
  unattendedOutcome(site) {
386
394
  let outcome;
@@ -644,6 +652,34 @@ export class ToolApprovalCoordinator {
644
652
  }
645
653
  return n;
646
654
  }
655
+ async drainForShutdown(deadlineMs) {
656
+ this.shutdownDraining = true;
657
+ for (const e of [...this.pending.values()])
658
+ if (e.settledOutcome === undefined)
659
+ e.forceParkNow();
660
+ while ((this.asksInFlight > 0 || this.pending.size > 0 || this.streams.size > 0 || this.parksAwaitingCommit.size > 0) && Date.now() < deadlineMs) {
661
+ await new Promise((r) => setTimeout(r, SHUTDOWN_DRAIN_POLL_MS));
662
+ }
663
+ await this.parkCommits?.quiesce(deadlineMs);
664
+ this.askAudit?.noteLegsInterruptedByShutdown();
665
+ return { uncommittedParks: [...this.parksAwaitingCommit].map((p) => ({ approvalId: p.approvalId, taskId: p.taskId })) };
666
+ }
667
+ noteParkCommitted(calls) {
668
+ this.settleParksAwaitingCommit((p) => p.executingSessionId === calls.sessionId && calls.toolCallIds.includes(p.toolCallId), "park-committed");
669
+ }
670
+ settleParksAwaitingCommit(match, site) {
671
+ for (const p of [...this.parksAwaitingCommit]) {
672
+ if (!match(p))
673
+ continue;
674
+ this.parksAwaitingCommit.delete(p);
675
+ try {
676
+ this.askAudit?.recordSettle(p.settleRecord());
677
+ }
678
+ catch (err) {
679
+ recordFailOpen("server.approval-ask-audit.append-failed", `kind=settle site=${site} err=${err instanceof Error ? err.message : String(err)}`);
680
+ }
681
+ }
682
+ }
647
683
  admittedCount(taskId) {
648
684
  return this.admitByTask.get(taskId) ?? 0;
649
685
  }
@@ -740,14 +776,13 @@ export class ToolApprovalCoordinator {
740
776
  async sessionGrantUncontestedByRow(origin, req) {
741
777
  if (!this.askStore)
742
778
  return true;
743
- const sourceTaskId = req.sourceTaskId ?? origin.taskId;
744
- const askId = deriveAskId(sourceTaskId, origin.taskId, req.toolCallId, origin.legKey, req.delegation?.parentToolCallId);
779
+ const call = { taskId: origin.taskId, legKey: origin.legKey, toolCallId: req.toolCallId, sourceTaskId: req.sourceTaskId ?? origin.taskId };
745
780
  try {
746
- const row = await this.withStoreDeadline(this.askStore.getAsk(askId), "getAsk(session-grant-provenance)", DURABLE_CONVERGE_READ_TIMEOUT_MS);
747
- return row === null;
781
+ const rows = await this.withStoreDeadline(this.askStore.listByCall(call), "listByCall(session-grant-provenance)", DURABLE_CONVERGE_READ_TIMEOUT_MS);
782
+ return rows.length === 0;
748
783
  }
749
784
  catch (err) {
750
- this.noteStoreError(err, "getAsk(session-grant-provenance)");
785
+ this.noteStoreError(err, "listByCall(session-grant-provenance)");
751
786
  return false;
752
787
  }
753
788
  }
@@ -950,6 +985,7 @@ export class ToolApprovalCoordinator {
950
985
  if (p.targetCtxs?.has(ctx))
951
986
  p.onTargetGone?.(ctx);
952
987
  }
988
+ this.settleParksAwaitingCommit((p) => p.carrierLeg === ctx, "leg-closed");
953
989
  this.askAudit?.noteLegClosed(ctx.taskId);
954
990
  }
955
991
  }));
@@ -983,6 +1019,15 @@ export class ToolApprovalCoordinator {
983
1019
  };
984
1020
  };
985
1021
  async askBroadcast(origin, ctxs, req, signal) {
1022
+ this.asksInFlight++;
1023
+ try {
1024
+ return await this.askBroadcastCounted(origin, ctxs, req, signal);
1025
+ }
1026
+ finally {
1027
+ this.asksInFlight--;
1028
+ }
1029
+ }
1030
+ async askBroadcastCounted(origin, ctxs, req, signal) {
986
1031
  if (signal?.aborted)
987
1032
  return false;
988
1033
  const governanceForced = this.governanceForcedOf(origin, req);
@@ -1008,11 +1053,13 @@ export class ToolApprovalCoordinator {
1008
1053
  }
1009
1054
  const id = uuidv7();
1010
1055
  const child = isChildAsk(req);
1056
+ const carrierLeg = child ? undefined : aliveCtxs.find((c) => c.taskId === origin.taskId);
1011
1057
  const bounded = boundArgs(req.args);
1012
1058
  let effectiveGovernanceForced = governanceForced;
1013
1059
  let ruleLaneMaterial = this.buildRuleLaneMaterial(req, origin.owner, governanceForced, origin.sessionId);
1014
1060
  const mandateWord = readClosedWordSeat(req, "mandate");
1015
1061
  const originWord = typeof req.origin === "string" && req.origin.length > 0 ? req.origin : undefined;
1062
+ const askClassPair = readAskClassPair(req);
1016
1063
  const frame = {
1017
1064
  type: "tool_approval",
1018
1065
  approvalId: id,
@@ -1040,6 +1087,7 @@ export class ToolApprovalCoordinator {
1040
1087
  ...(req.mandated === true ? { mandated: true } : {}),
1041
1088
  ...(mandateWord !== undefined ? { mandate: mandateWord } : {}),
1042
1089
  ...(originWord !== undefined ? { origin: originWord } : {}),
1090
+ ...(askClassPair ?? {}),
1043
1091
  ...(typeof req.persistedRuleShadowed === "string" && req.persistedRuleShadowed !== ""
1044
1092
  ? { persistedRuleShadowed: redactSecrets(req.persistedRuleShadowed).slice(0, MAX_RULE_TEXT_CHARS) }
1045
1093
  : {}),
@@ -1091,7 +1139,7 @@ export class ToolApprovalCoordinator {
1091
1139
  const sourceTaskId = req.sourceTaskId ?? origin.taskId;
1092
1140
  const runId = origin.taskId;
1093
1141
  const legKey = origin.legKey;
1094
- askId = deriveAskId(sourceTaskId, runId, req.toolCallId, legKey, req.delegation?.parentToolCallId);
1142
+ askId = deriveAskId(sourceTaskId, runId, legKey, req);
1095
1143
  batchId = this.batchIdFor(askId, sourceTaskId, runId, legKey);
1096
1144
  try {
1097
1145
  const existingOrCreated = await this.withStoreDeadline(this.askStore.ensureAsk({
@@ -1282,13 +1330,28 @@ export class ToolApprovalCoordinator {
1282
1330
  releaseAdmission();
1283
1331
  if (selfEntry)
1284
1332
  selfEntry.settledOutcome = outcome;
1285
- this.askAudit?.recordSettle({
1333
+ const shutdownEnded = this.shutdownDraining && outcome === "expired";
1334
+ const settleRecord = () => ({
1286
1335
  approvalId: wireApprovalId,
1287
1336
  outcome,
1288
1337
  ...(windowRouteUnavailable ? { parkRouted: true } : {}),
1289
1338
  ...(hostSettledBy !== undefined ? { settledBy: hostSettledBy } : {}),
1339
+ ...(shutdownEnded ? { cause: SHUTDOWN_BEFORE_PARK } : {}),
1290
1340
  settledAtMs: Date.now(),
1291
1341
  });
1342
+ if (shutdownEnded && windowRouteUnavailable && this.unattendedRoutesToPark && this.parkCommits !== undefined) {
1343
+ this.parksAwaitingCommit.add({
1344
+ approvalId: wireApprovalId,
1345
+ taskId: origin.taskId,
1346
+ carrierLeg,
1347
+ executingSessionId: req.sourceTaskId,
1348
+ toolCallId: req.toolCallId,
1349
+ settleRecord,
1350
+ });
1351
+ }
1352
+ else {
1353
+ this.askAudit?.recordSettle(settleRecord());
1354
+ }
1292
1355
  resolveAllowed({ allowed, ...(allowed && updatedInput !== undefined ? { updatedInput } : {}), ...(allowed && readRootGrant !== undefined ? { readRootGrant } : {}) });
1293
1356
  };
1294
1357
  const broadcastClaimTruth = (read) => {
@@ -1471,7 +1534,7 @@ export class ToolApprovalCoordinator {
1471
1534
  if (done)
1472
1535
  return;
1473
1536
  if (!this.askStore || askId === undefined || batchId === undefined) {
1474
- settleParkRouteIfUnsettled();
1537
+ settleParkRouteIfUnsettled(undefined);
1475
1538
  return;
1476
1539
  }
1477
1540
  windowExpired(undefined);
@@ -1586,10 +1649,12 @@ export class ToolApprovalCoordinator {
1586
1649
  owner: origin.owner,
1587
1650
  toolName: req.toolName,
1588
1651
  toolCallId: req.toolCallId,
1589
- legTracked: !child && aliveCtxs.some((c) => c.taskId === origin.taskId),
1652
+ legTracked: carrierLeg !== undefined,
1590
1653
  expiresAtMs: persistedExpiresAtMs,
1591
1654
  mintedAtMs: Date.now(),
1592
1655
  });
1656
+ if (this.shutdownDraining)
1657
+ forceParkNow();
1593
1658
  const cardFrame = askId !== undefined && cardForFrame !== undefined
1594
1659
  ? buildApprovalRequestFrame({ askId, taskId: origin.taskId, approvalId: wireApprovalId, card: cardForFrame, expiresAtMs: persistedExpiresAtMs, nowMs: Date.now() })
1595
1660
  : undefined;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * S-919(安全轴,八病审计 SG H2-a)—— 本仓**收紧方向**按引擎工具名匹配的策略臂的**唯一**名字读法。
3
+ *
4
+ * ## 规则(一条,与 core 7.36.0 [ref] `NAME_READINGS` 同判)
5
+ * 一个调用可以答好几个名字:嵌入方工具声明别名(`MyShell{aliases:["Bash"]}`)后,模型按哪个名调它、它的 wire 名、
6
+ * 解到同一行的其余别名,都是这次调用的名字。core 把**收紧**方向的名单(`policy.nameLists` / `policy.shellToolsList` /
7
+ * `policy.durableQuestion` / `policy.sensitivePathGuardedByName`)读成 `any` —— 调用答得上的**任何**一个名字在名单里就算
8
+ * 命中;**授权 / 路由**方向的座(会话放行、审批卡分型、停车行)读 `wire`(`req.toolName`)。core 给宿主的读法端口是包根
9
+ * `ruleNamesOf(req)`(`dist/core/tool-name-readings.js`,亲读实现:`face.names` 含调用名时取它,否则只有调用名;拼写在先)。
10
+ *
11
+ * 本仓照此分两边:
12
+ * · **收紧臂**(`APPROVAL_DENY` / `APPROVAL_REQUIRE` / `APPROVAL_NEVER_AUTO`、commandPolicy 的 ask 表、治理 shell 标、
13
+ * durable 问题门、supervisor 危险门、workflow 问 / 拒)一律经本函数读全集;
14
+ * · **授权 / 路由臂**(会话豁免探针、会话放行键、审批卡分型、停车行的 AskUserQuestion 判别)读 `req.toolName`,不经这里 ——
15
+ * 用户对 `Bash` 说过的「本会话不再询问」不许替一只叫 `MyShell` 的工具放行(放宽臂不因别名放宽)。
16
+ *
17
+ * 修前(≤7.107.0)本仓自写的这些臂只比 `req.toolName`:模型按别名调嵌入方工具时,运维名单一个都不拦(core 同族策略判 deny、
18
+ * 本仓判 allow)。本仓自身不声明带别名的工具,所以只有经 `resolveSpec` 席挂别名工具的嵌入方走得到。
19
+ *
20
+ * 返回**命中的那个名字**(调用答得上的名字里第一个被规则够到的,拼写在先)—— 规则归因(`matchedAskRule`)写运维名单里的那个名,
21
+ * 不写一个名单里查不到的 wire 名;够不到 ⇒ `undefined`。判定式(精确集 / covering 规则)由调用方给,本函数只管「读哪些名字」。
22
+ */
23
+ import { type ToolCallRequest } from "@sema-agent/core";
24
+ export declare function heldRuleName(req: Pick<ToolCallRequest, "toolName" | "face">, holds: (name: string) => boolean): string | undefined;
25
+ //# sourceMappingURL=tool-rule-names.d.ts.map
@@ -0,0 +1,5 @@
1
+ import { ruleNamesOf } from "@sema-agent/core";
2
+ export function heldRuleName(req, holds) {
3
+ return ruleNamesOf(req).find(holds);
4
+ }
5
+ //# sourceMappingURL=tool-rule-names.js.map
@@ -17,7 +17,7 @@
17
17
  * ⑨⑩([ref],2026-08-31)把两个最大的 wire 面也纳入:TaskSpec 按「server 有无写点」记 Wired/Unwired,
18
18
  * TaskResult 按「转发/摘除」记 Forwarded/Stripped —— 谁改 resolve-spec.ts / runs.ts 的发射点谁同步本文件。
19
19
  */
20
- import type { TaskNotificationPayload, SemaProvenance, BackgroundChildEvent, RosterEntry, AskRequest, CheckpointSummary, PendingAction, TaskEvent, TraceEvent, MailboxMessage, MailboxAppendMessage, TaskSpec, TaskResult, WiringManifest, GateOutcome, GateDisposition, Settlement, PausedCause, WorkflowRun, ReadRootGrantCandidate, McpReconnectResult, McpServerStatus, NodeLspManagerOptions, RunnerDeps } from "@sema-agent/core";
20
+ import type { TaskNotificationPayload, SemaProvenance, BackgroundChildEvent, RosterEntry, AskRequest, CheckpointSummary, PendingAction, TaskEvent, TraceEvent, MailboxMessage, MailboxAppendMessage, TaskSpec, TaskResult, SideQueryResult, WiringManifest, GateOutcome, GateDisposition, Settlement, PausedCause, WorkflowRun, ReadRootGrantCandidate, McpReconnectResult, McpServerStatus, NodeLspManagerOptions, RunnerDeps } from "@sema-agent/core";
21
21
  import type { ToolApprovalFrame } from "../tool-approval.js";
22
22
  /** 编译期断言:T 必须收敛到 never(有残余键 = tsc 红)。
23
23
  * 🔴 **导出**([ref] U1/U2):本仓「词表闭集,未处置成员=编译红」的钉法只许有**一个**形 ——
@@ -43,7 +43,7 @@ type _GuardBgNotifReverse = AssertAllKeysHandled<Exclude<BgNotifProjected | BgNo
43
43
  type RosterProjected = "name" | "agentId" | "sessionId" | "toolUseId" | "owner" | "scope" | "sessionScoped" | "rootSessionId" | "model" | "modelFallback" | "createdAt";
44
44
  type _GuardRoster = AssertAllKeysHandled<Exclude<keyof RosterEntry, RosterProjected>>;
45
45
  type _GuardRosterReverse = AssertAllKeysHandled<Exclude<RosterProjected, keyof RosterEntry>>;
46
- type AskProjected = "toolName" | "toolCallId" | "args" | "message" | "sourceTaskId" | "fromSubagent" | "sourceAgentName" | "delegation" | "ruleOffers" | "ruleOffersAbsence" | "persistedRuleShadowed" | "probeCause" | "ruleEvidence" | "requiresRealApproval" | "denialLimitFallback" | "origin" | "readRootCandidate" | "mandated" | "mandate";
46
+ type AskProjected = "toolName" | "toolCallId" | "args" | "message" | "sourceTaskId" | "fromSubagent" | "sourceAgentName" | "delegation" | "ruleOffers" | "ruleOffersAbsence" | "persistedRuleShadowed" | "probeCause" | "ruleEvidence" | "requiresRealApproval" | "denialLimitFallback" | "origin" | "readRootCandidate" | "mandated" | "mandate" | "askClass" | "classes";
47
47
  type AskExcluded = "preview" | "principal" | "riskAxes" | "boundInputHash" | "isDelegatedChild" | "probeReason" | "hasBidiControls" | "previewWithheld" | "execCwd" | "authoredBy";
48
48
  type _GuardAsk = AssertAllKeysHandled<Exclude<keyof AskRequest, AskProjected | AskExcluded>>;
49
49
  type _GuardAskReverse = AssertAllKeysHandled<Exclude<AskProjected | AskExcluded, keyof AskRequest>>;
@@ -157,6 +157,14 @@ type PausedCauseForwarded = "kind" | "gate" | "checkpointId" | "restoreMode";
157
157
  type PausedCauseStripped = "token";
158
158
  type _GuardPausedCause = AssertAllKeysHandled<Exclude<keyof PausedCause, PausedCauseForwarded | PausedCauseStripped>>;
159
159
  type _GuardPausedCauseReverse = AssertAllKeysHandled<Exclude<PausedCauseForwarded | PausedCauseStripped, keyof PausedCause>>;
160
+ type SideQueryResultForwarded = "text" | "toolCalls" | "model" | "servedModel" | "degraded" | "responseModel" | "usage" | "usageMissing" | "stopReason" | "errorMessage";
161
+ type SideQueryResultStripped = never;
162
+ type _GuardSideQueryResult = AssertAllKeysHandled<Exclude<keyof SideQueryResult, SideQueryResultForwarded | SideQueryResultStripped>>;
163
+ type _GuardSideQueryResultReverse = AssertAllKeysHandled<Exclude<SideQueryResultForwarded | SideQueryResultStripped, keyof SideQueryResult>>;
164
+ type SideQueryToolCallForwarded = "id" | "wireId" | "name" | "args";
165
+ type SideQueryToolCallStripped = never;
166
+ type _GuardSideQueryToolCall = AssertAllKeysHandled<Exclude<keyof SideQueryResult["toolCalls"][number], SideQueryToolCallForwarded | SideQueryToolCallStripped>>;
167
+ type _GuardSideQueryToolCallReverse = AssertAllKeysHandled<Exclude<SideQueryToolCallForwarded | SideQueryToolCallStripped, keyof SideQueryResult["toolCalls"][number]>>;
160
168
  type SettlementKeys = Settlement extends infer S ? (S extends object ? keyof S : never) : never;
161
169
  type SettlementWhoKeys = Settlement["who"] extends infer W ? (W extends object ? keyof W : never) : never;
162
170
  type GateOutcomeProjected = "disposition" | "settlement" | "origin";
@@ -289,6 +297,10 @@ export type CoreKeysetGuards = [
289
297
  _GuardTaskResultReverse,
290
298
  _GuardPausedCause,
291
299
  _GuardPausedCauseReverse,
300
+ _GuardSideQueryResult,
301
+ _GuardSideQueryResultReverse,
302
+ _GuardSideQueryToolCall,
303
+ _GuardSideQueryToolCallReverse,
292
304
  _GuardGateOutcome,
293
305
  _GuardGateOutcomeReverse,
294
306
  _GuardGateDisposition,
@@ -16,7 +16,7 @@
16
16
  * 同文件 G1 e2e 的全码扇出夹具、以及契约文档附录 D.3 那张表(含**小节标题里的码数** —— 那道门本批
17
17
  * 刚立,立完就在下一次加码时自己咬住了)。
18
18
  */
19
- export declare const ENGINE_NOTICE_WIRE_CODES: readonly ["memory.session_polluted", "memory.harvest_quarantined", "memory.delegation_static_mark_waived", "memory.hold_opened", "memory.hold_released", "memory.hold_disposed", "task.turn_interrupted", "steering.parked_input_blocked", "task.user_steer_undrained", "task.user_followup_undrained", "memory.capture_opted_out", "memory.capture_optout_unpersisted", "task.halt_unconsumed", "task.late_approval", "config.durable_gate_unavailable", "peer.inbound_disposition", "peer.held_settled", "peer.idle_subscription", "classifier.denial_limit", "mcp.injection_dropped", "delegation.ask_unresolvable", "task.interrupt_unconsumed", "approval.read_root_granted", "approval.read_root_grant_rejected", "instructions.source_changed", "session.records_skipped", "classifier.unavailable", "config.permission_mode_unavailable", "permission.ask_released_by_mode", "permission.read_deny_unapplied", "permission.rule_store_unavailable"];
19
+ export declare const ENGINE_NOTICE_WIRE_CODES: readonly ["memory.session_polluted", "memory.harvest_quarantined", "memory.delegation_static_mark_waived", "memory.hold_opened", "memory.hold_released", "memory.hold_disposed", "task.turn_interrupted", "steering.parked_input_blocked", "task.user_steer_undrained", "task.user_followup_undrained", "memory.capture_opted_out", "memory.capture_optout_unpersisted", "task.halt_unconsumed", "task.late_approval", "config.durable_gate_unavailable", "peer.inbound_disposition", "peer.held_settled", "peer.idle_subscription", "classifier.denial_limit", "mcp.injection_dropped", "delegation.ask_unresolvable", "task.interrupt_unconsumed", "approval.read_root_granted", "approval.read_root_grant_rejected", "instructions.source_changed", "session.records_skipped", "server.model_unreachable", "classifier.unavailable", "config.permission_mode_unavailable", "permission.ask_released_by_mode", "permission.read_deny_unapplied", "permission.rule_store_unavailable"];
20
20
  export type EngineNoticeWireCode = (typeof ENGINE_NOTICE_WIRE_CODES)[number];
21
21
  /**
22
22
  * S-690 —— **本仓自铸**的通告码与它们的受众(码 / 铸点 / 受众三者的属主都是本仓)。
@@ -42,6 +42,8 @@ export declare const SERVER_NOTICE_AUDIENCE: {
42
42
  readonly "memory.layer_locked_legacy": "operator";
43
43
  /** S-612 —— 会话存档部分记录被跳过(唯一铸点 `src/session-records-skipped-notice.ts`);受众 user,理由见白名单键注。 */
44
44
  readonly "session.records_skipped": "user";
45
+ /** S-925 —— 模型调用因建连失败终态(唯一铸点 `src/model-unreachable-notice.ts`);受众 user,理由见白名单键注。 */
46
+ readonly "server.model_unreachable": "user";
45
47
  };
46
48
  export type ServerNoticeCode = keyof typeof SERVER_NOTICE_AUDIENCE;
47
49
  /** 该码是否本仓自铸(属主判据单点:门与投递面都读这一个)。 */
@@ -27,6 +27,7 @@ export const ENGINE_NOTICE_WIRE_CODES = [
27
27
  "approval.read_root_grant_rejected",
28
28
  "instructions.source_changed",
29
29
  "session.records_skipped",
30
+ "server.model_unreachable",
30
31
  "classifier.unavailable",
31
32
  "config.permission_mode_unavailable",
32
33
  "permission.ask_released_by_mode",
@@ -37,6 +38,7 @@ export const SERVER_NOTICE_AUDIENCE = {
37
38
  "instructions.source_changed": "user",
38
39
  "memory.layer_locked_legacy": "operator",
39
40
  "session.records_skipped": "user",
41
+ "server.model_unreachable": "user",
40
42
  };
41
43
  export function isServerNoticeCode(code) {
42
44
  return Object.hasOwn(SERVER_NOTICE_AUDIENCE, code);
@@ -298,7 +298,9 @@ export declare function toolEndEventData(ev: {
298
298
  * ## 信任划线
299
299
  * · `toolCallId` / `toolName` —— 调用 id(🔴 S-283 订正:出身是**服务商**在 tool_use / tool_calls 里给的,引擎缺席时自铸兜底、越界时折叠 ——
300
300
  * 此前写「引擎铸」不实)与名册里的工具名(与 `tool_start` 逐字同源)⇒ verbatim。调用 id 这一族的形状在**全部面的共同入口**一次施加 ——
301
- * core 7.36.0(#1207)brain 建调用那一行的准入(在形原样 / 越界单射折叠,原字节只在转录 `ToolCall.wireId`),逐帧面收到的恒是在形的引擎 id;
301
+ * core 7.36.0(#1207)brain 建调用那一行的准入(在形原样 / 越界单射折叠,原字节只在转录 `ToolCall.wireId`),一方 brain 新铸的调用在逐帧面上
302
+ * 恒是在形的引擎 id(残余两条 S-921:≤7.106.0 写下的存量行 resume 出来的帧是服务商原串逐字;宿主 Brain 不准入 KL-1207-a —— 详见
303
+ * run-terminal `admitProviderEcho` 顶注);
302
304
  * 本仓不设第二道闸(见 run-terminal `admitProviderEcho` 顶注;S-890 关)。
303
305
  * · `elapsedTimeSeconds` —— 引擎铸的整秒,单调、一 call 一个原点 ⇒ 有限数才铸键。
304
306
  * · `output` —— 🔴 **UNTRUSTED RAW**,core 逐字「exactly as `tool_end.output`: process output that may
@@ -1,5 +1,5 @@
1
1
  import { admitProviderEcho, redactErrorMessage, redactModelText } from "../observability/run-terminal.js";
2
- import { isAskClass, isAskOrigin, isPermissionMode, isPersistedRuleMandate, MCP_DELIVERY_VERDICTS, MCP_LIVENESS_STATES, screenGateOutcome, TEAM_ROLES, ToolRoster, ToolRosterDelta, WRITE_PROTECTION_TARGET_VIEWS } from "@sema-agent/core";
2
+ import { isAskClass, isAskOrigin, isModeReleaseReason, isPermissionMode, isPersistedRuleMandate, MCP_DELIVERY_VERDICTS, MCP_LIVENESS_STATES, screenGateOutcome, TEAM_ROLES, ToolRoster, ToolRosterDelta, WRITE_PROTECTION_TARGET_VIEWS } from "@sema-agent/core";
3
3
  import { Value } from "typebox/value";
4
4
  import { recordFailOpen } from "../observability/fail-open.js";
5
5
  import { redactSecrets, redactDeep } from "./redact.js";
@@ -126,11 +126,10 @@ function modeLedgerDefect(d) {
126
126
  return "disposition.released.origin is outside the closed set";
127
127
  if (o.mandate !== undefined && !isPersistedRuleMandate(o.mandate))
128
128
  return "disposition.released.mandate is outside the closed set";
129
- if (o.reason !== undefined && !(typeof o.reason === "string" && Object.hasOwn(RELEASE_REASON_WORDS, o.reason)))
129
+ if (o.reason !== undefined && !isModeReleaseReason(o.reason))
130
130
  return "disposition.released.reason is outside the closed set";
131
131
  return false;
132
132
  }
133
- const RELEASE_REASON_WORDS = { rule_unreadable: true };
134
133
  function screenedGateOrThrow(v) {
135
134
  if (v === null || typeof v !== "object") {
136
135
  if (v !== undefined)
@@ -0,0 +1,71 @@
1
+ /** 一个自铸 wire 值成员的登记。 */
2
+ export interface SelfMintedWireMember {
3
+ readonly attr: string | number;
4
+ readonly since: string;
5
+ }
6
+ export declare const SELF_MINTED_WIRE: {
7
+ /** [ref](7.55.0)起的终态成因注;S-929(7.108.0)+`shutdown_before_park`。 */
8
+ readonly crashConvergedCause: {
9
+ readonly at: "GET /v1/approvals crashConverged[].cause";
10
+ readonly members: {
11
+ crashed_before_park: {
12
+ attr: string;
13
+ since: string;
14
+ };
15
+ shutdown_before_park: {
16
+ attr: string;
17
+ since: string;
18
+ };
19
+ };
20
+ };
21
+ /**
22
+ * 会话所有者自助抹除面的**已分类拒** → HTTP 状态(S-930 起与 operator 面 `POST /v1/memory/erase` 同一只映射;`since` 记的是**本面**
23
+ * 自哪一版起这样答 —— 7.107.0 及以前本面只认前两只,其余落 500 `internal.error`)。
24
+ */
25
+ readonly sessionMemoryEraseStatus: {
26
+ readonly at: "POST /v1/sessions/:id/memory/erase(已分类拒 errorCode → HTTP 状态)";
27
+ readonly members: {
28
+ readonly "config.memory_erasure_request": {
29
+ readonly attr: 400;
30
+ readonly since: "7.52.0";
31
+ };
32
+ readonly "memory.target_outside_store": {
33
+ readonly attr: 409;
34
+ readonly since: "7.101.0";
35
+ };
36
+ readonly "memory.erasure_evidence_unavailable": {
37
+ readonly attr: 409;
38
+ readonly since: "7.108.0";
39
+ };
40
+ readonly "memory.erasure_selector_mismatch": {
41
+ readonly attr: 409;
42
+ readonly since: "7.108.0";
43
+ };
44
+ readonly "memory.erasure_census_incomplete": {
45
+ readonly attr: 409;
46
+ readonly since: "7.108.0";
47
+ };
48
+ readonly "internal.memory_control_plane_corrupt": {
49
+ readonly attr: 500;
50
+ readonly since: "7.108.0";
51
+ };
52
+ };
53
+ };
54
+ /** 本仓在出口对 core 值做的变换(值变、键不变)。 */
55
+ readonly wireValueRule: {
56
+ readonly at: "出口值变换(<端点>#<键> → 变换)";
57
+ readonly members: {
58
+ /** S-105(7.57.0):run 读面的终态错误文案脱敏(钉 test/run-failure-visibility.test.ts)。 */
59
+ readonly "GET /v1/runs/:id#result.errorMessage": {
60
+ readonly attr: "redactErrorMessage";
61
+ readonly since: "7.57.0";
62
+ };
63
+ /** S-922(7.108.0):side-query 200 体 `errorMessage` 与任务面同一只脱敏口(钉 test/side-query-provider-echo.test.ts)。 */
64
+ readonly "POST /v1/side-query#errorMessage": {
65
+ readonly attr: "redactErrorMessage";
66
+ readonly since: "7.108.0";
67
+ };
68
+ };
69
+ };
70
+ };
71
+ //# sourceMappingURL=self-minted-wire.d.ts.map
@@ -0,0 +1,28 @@
1
+ export const SELF_MINTED_WIRE = {
2
+ crashConvergedCause: {
3
+ at: "GET /v1/approvals crashConverged[].cause",
4
+ members: {
5
+ crashed_before_park: { attr: "-", since: "7.55.0" },
6
+ shutdown_before_park: { attr: "-", since: "7.108.0" },
7
+ },
8
+ },
9
+ sessionMemoryEraseStatus: {
10
+ at: "POST /v1/sessions/:id/memory/erase(已分类拒 errorCode → HTTP 状态)",
11
+ members: {
12
+ "config.memory_erasure_request": { attr: 400, since: "7.52.0" },
13
+ "memory.target_outside_store": { attr: 409, since: "7.101.0" },
14
+ "memory.erasure_evidence_unavailable": { attr: 409, since: "7.108.0" },
15
+ "memory.erasure_selector_mismatch": { attr: 409, since: "7.108.0" },
16
+ "memory.erasure_census_incomplete": { attr: 409, since: "7.108.0" },
17
+ "internal.memory_control_plane_corrupt": { attr: 500, since: "7.108.0" },
18
+ },
19
+ },
20
+ wireValueRule: {
21
+ at: "出口值变换(<端点>#<键> → 变换)",
22
+ members: {
23
+ "GET /v1/runs/:id#result.errorMessage": { attr: "redactErrorMessage", since: "7.57.0" },
24
+ "POST /v1/side-query#errorMessage": { attr: "redactErrorMessage", since: "7.108.0" },
25
+ },
26
+ },
27
+ };
28
+ //# sourceMappingURL=self-minted-wire.js.map