@sema-agent/server 7.67.0 → 7.69.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 (71) hide show
  1. package/USAGE.md +19 -2
  2. package/dist/adoption/plan.js +11 -0
  3. package/dist/approval-card.d.ts +26 -0
  4. package/dist/approval-card.js +11 -0
  5. package/dist/approval.js +5 -4
  6. package/dist/boot/config-center.d.ts +6 -7
  7. package/dist/boot/config-center.js +31 -8
  8. package/dist/boot/leader.js +1 -1
  9. package/dist/boot/resolve-spec.js +1 -1
  10. package/dist/boot/workflow-orchestration.d.ts +2 -0
  11. package/dist/boot/workflow-orchestration.js +10 -2
  12. package/dist/budget.js +1 -1
  13. package/dist/config-catalog.js +20 -1
  14. package/dist/config-center/apply-effective.d.ts +8 -1
  15. package/dist/config-center/apply-effective.js +23 -9
  16. package/dist/config-center/facade.d.ts +1 -1
  17. package/dist/config-center/facade.js +1 -1
  18. package/dist/config-center/read-face.d.ts +30 -1
  19. package/dist/config-center/read-face.js +33 -15
  20. package/dist/config-center/restart-signal.js +2 -1
  21. package/dist/config-center/types.d.ts +20 -5
  22. package/dist/config-provider.js +1 -0
  23. package/dist/config-types.d.ts +17 -2
  24. package/dist/config.d.ts +0 -21
  25. package/dist/config.js +19 -6
  26. package/dist/http/route-ctx.d.ts +44 -2
  27. package/dist/http/routes/approvals-assistant.js +1 -0
  28. package/dist/http/routes/capabilities.js +1 -0
  29. package/dist/http/routes/runs.js +1 -1
  30. package/dist/http/routes/tasks.js +1 -0
  31. package/dist/http/routes/workflows.js +15 -7
  32. package/dist/http/server.d.ts +15 -2
  33. package/dist/http/server.js +74 -45
  34. package/dist/leader/wire.d.ts +9 -2
  35. package/dist/leader/wire.js +6 -6
  36. package/dist/main.js +6 -5
  37. package/dist/mcp-tool-faces.js +11 -2
  38. package/dist/model-compat.d.ts +81 -0
  39. package/dist/model-compat.js +52 -0
  40. package/dist/observability/fail-open.d.ts +4 -0
  41. package/dist/observability/fail-open.js +4 -0
  42. package/dist/operator-ask.d.ts +46 -0
  43. package/dist/operator-ask.js +4 -0
  44. package/dist/orchestration/workflow-agent-session-index.d.ts +96 -0
  45. package/dist/orchestration/workflow-agent-session-index.js +146 -0
  46. package/dist/orchestration/workflow-journal-entry.d.ts +78 -0
  47. package/dist/orchestration/workflow-journal-entry.js +20 -0
  48. package/dist/orchestration/workflow-notify-journal.d.ts +43 -1
  49. package/dist/orchestration/workflow-notify-journal.js +43 -3
  50. package/dist/parked-decide.d.ts +115 -5
  51. package/dist/parked-decide.js +94 -26
  52. package/dist/plugins/pg-pool.js +8 -0
  53. package/dist/plugins/store-backend.d.ts +5 -0
  54. package/dist/plugins/store-backend.js +3 -1
  55. package/dist/plugins/tidb-pool.js +8 -0
  56. package/dist/plugins/workflow-journal-store-sql.js +10 -3
  57. package/dist/plugins/workflow-run-store-sql.d.ts +30 -0
  58. package/dist/plugins/workflow-run-store-sql.js +40 -0
  59. package/dist/router/route-orchestration.js +2 -1
  60. package/dist/run-local.js +1 -1
  61. package/dist/runs.d.ts +10 -1
  62. package/dist/runs.js +4 -1
  63. package/dist/runtime-governance.js +5 -4
  64. package/dist/task-mcp.d.ts +50 -6
  65. package/dist/task-mcp.js +71 -35
  66. package/dist/tool-approval.d.ts +20 -0
  67. package/dist/tool-approval.js +2 -1
  68. package/dist/trace/core-keyset-guard.d.ts +3 -3
  69. package/dist/trace/engine-notice-wire.d.ts +17 -1
  70. package/dist/trace/engine-notice-wire.js +7 -1
  71. package/package.json +4 -4
package/dist/task-mcp.js CHANGED
@@ -1,9 +1,10 @@
1
- import { resolveComplianceDenies } from "@sema-agent/core";
1
+ import { mcpInjectionDroppedNotice, resolveComplianceDenies } from "@sema-agent/core";
2
2
  import { HttpError } from "./security.js";
3
3
  import { CONTENT_ORIGIN_WORDS, describeBadContentOrigin, isContentOriginWord } from "./mcp-content-origin.js";
4
4
  import { readMcpSourceLabel } from "./mcp-source-label.js";
5
5
  import { readMcpToolFaces } from "./mcp-tool-faces.js";
6
6
  export const MAX_REQUEST_MCP_SERVERS = 32;
7
+ export const MAX_REQUEST_MCP_DROP_NAMES = MAX_REQUEST_MCP_SERVERS;
7
8
  export function mcpInjectionHonored(config) {
8
9
  if (config.lockedConfigKeys?.includes("mcp") === true)
9
10
  return false;
@@ -14,20 +15,27 @@ export function mcpInjectionHonored(config) {
14
15
  function isStringRecord(v) {
15
16
  return !!v && typeof v === "object" && !Array.isArray(v) && Object.values(v).every((x) => typeof x === "string");
16
17
  }
18
+ const bad = (field) => ({ ok: false, field });
19
+ const MALFORMED_NAME = "<malformed>";
20
+ function declaredName(e) {
21
+ return e && typeof e === "object" && typeof e.name === "string" && e.name !== ""
22
+ ? String(e.name)
23
+ : MALFORMED_NAME;
24
+ }
17
25
  function normalizeServer(e, noteBadOrigin) {
18
26
  if (!e || typeof e !== "object")
19
- return null;
27
+ return bad("entry");
20
28
  const o = e;
21
29
  if (typeof o.name !== "string" || o.name.length === 0 || o.name.length > 128)
22
- return null;
30
+ return bad("name");
23
31
  const t = o.transport;
24
32
  if (!t || typeof t !== "object")
25
- return null;
33
+ return bad("transport");
26
34
  const tr = t;
27
35
  let transport;
28
36
  if (tr.kind === "stdio") {
29
37
  if (typeof tr.command !== "string" || tr.command.length === 0)
30
- return null;
38
+ return bad("transport.command");
31
39
  transport = {
32
40
  kind: "stdio",
33
41
  command: tr.command,
@@ -37,7 +45,7 @@ function normalizeServer(e, noteBadOrigin) {
37
45
  }
38
46
  else if (tr.kind === "http") {
39
47
  if (typeof tr.url !== "string" || !/^https?:\/\//i.test(tr.url))
40
- return null;
48
+ return bad("transport.url");
41
49
  transport = {
42
50
  kind: "http",
43
51
  url: tr.url,
@@ -46,12 +54,12 @@ function normalizeServer(e, noteBadOrigin) {
46
54
  };
47
55
  }
48
56
  else {
49
- return null;
57
+ return bad("transport.kind");
50
58
  }
51
59
  const spec = { name: o.name, transport };
52
60
  if (o.allowTools !== undefined) {
53
61
  if (!Array.isArray(o.allowTools) || !o.allowTools.every((a) => typeof a === "string"))
54
- return null;
62
+ return bad("allowTools");
55
63
  spec.allowTools = o.allowTools;
56
64
  }
57
65
  if (typeof o.elicitation === "boolean")
@@ -82,29 +90,32 @@ function normalizeServer(e, noteBadOrigin) {
82
90
  Object.assign(spec, readMcpSourceLabel(spec.name, o.source));
83
91
  const faces = readMcpToolFaces(o.toolFaces);
84
92
  if (!faces.ok)
85
- return null;
93
+ return bad("toolFaces");
86
94
  if (faces.faces !== undefined)
87
95
  spec.toolFaces = faces.faces;
88
- return spec;
96
+ return { ok: true, spec };
89
97
  }
90
98
  export function validateRequestMcp(raw) {
91
99
  if (raw === undefined || raw === null)
92
- return { ok: [], dropped: [], badContentOrigin: [] };
100
+ return validateRequestMcpEntries([]);
93
101
  if (!Array.isArray(raw))
94
102
  return null;
103
+ return validateRequestMcpEntries(raw);
104
+ }
105
+ function validateRequestMcpEntries(raw) {
95
106
  const ok = [];
96
107
  const dropped = [];
97
108
  const badContentOrigin = [];
98
109
  for (const e of raw.slice(0, MAX_REQUEST_MCP_SERVERS)) {
99
110
  const v = normalizeServer(e, (server, value) => badContentOrigin.push({ server, value: describeBadContentOrigin(value) }));
100
- if (v)
101
- ok.push(v);
111
+ if (v.ok)
112
+ ok.push(v.spec);
102
113
  else
103
- dropped.push(e && typeof e === "object" && typeof e.name === "string" ? String(e.name) : "<malformed>");
114
+ dropped.push({ server: declaredName(e), reason: "malformed_entry", field: v.field });
104
115
  }
105
- if (raw.length > MAX_REQUEST_MCP_SERVERS)
106
- dropped.push(`(+${raw.length - MAX_REQUEST_MCP_SERVERS} over cap of ${MAX_REQUEST_MCP_SERVERS})`);
107
- return { ok, dropped, badContentOrigin };
116
+ for (const e of raw.slice(MAX_REQUEST_MCP_SERVERS, MAX_REQUEST_MCP_SERVERS + MAX_REQUEST_MCP_DROP_NAMES))
117
+ dropped.push({ server: declaredName(e), reason: "over_cap" });
118
+ return { ok, dropped, droppedTotal: Math.max(0, raw.length - ok.length), badContentOrigin };
108
119
  }
109
120
  export function assertRequestMcpUnlocked(bodyMcp, lockedKeys) {
110
121
  if (!lockedKeys.has("mcp"))
@@ -140,21 +151,33 @@ export function mergeRequestMcp(baseline, gated, reservedNames) {
140
151
  const add = gated.filter((s) => !closed.has(s.name));
141
152
  return add.length === 0 ? baseline : [...(baseline ?? []), ...add];
142
153
  }
143
- export function resolveRequestMcp(baseline, bodyMcp, config, logger) {
154
+ export function resolveRequestMcp(baseline, bodyMcp, config, logger, notice) {
144
155
  if (bodyMcp === undefined || bodyMcp === null)
145
156
  return baseline;
146
- const honored = mcpInjectionHonored(config);
147
- if (!honored) {
148
- logger?.warn("mcp_injection_ignored", { reason: "gate_closed (per-request MCP honored only on single-user host lane)" });
149
- return baseline;
150
- }
151
- const v = validateRequestMcp(bodyMcp);
152
- if (v === null) {
157
+ const { mcp, drops } = classifyRequestMcp(baseline, bodyMcp, config, logger);
158
+ mintInjectionDropNotices(drops, notice);
159
+ return mcp;
160
+ }
161
+ function classifyRequestMcp(baseline, bodyMcp, config, logger) {
162
+ if (bodyMcp !== undefined && bodyMcp !== null && !Array.isArray(bodyMcp)) {
153
163
  logger?.warn("mcp_injection_ignored", { reason: "mcpServers not an array" });
154
- return baseline;
164
+ return { mcp: baseline, drops: [] };
155
165
  }
156
- if (v.dropped.length > 0)
157
- logger?.warn("mcp_injection_dropped", { dropped: v.dropped });
166
+ const entries = Array.isArray(bodyMcp) ? bodyMcp : [];
167
+ const outcome = mcpInjectionHonored(config) ? classifyHonored(baseline, entries, config, logger) : classifyGateClosed(baseline, entries);
168
+ if (outcome.drops.length > 0)
169
+ logger?.warn("mcp_injection_dropped", { dropped: outcome.drops, droppedTotal: outcome.droppedTotal });
170
+ return { mcp: outcome.mcp, drops: outcome.drops };
171
+ }
172
+ function classifyGateClosed(baseline, entries) {
173
+ return {
174
+ mcp: baseline,
175
+ drops: entries.slice(0, MAX_REQUEST_MCP_DROP_NAMES).map((e) => ({ server: declaredName(e), reason: "gate_closed" })),
176
+ droppedTotal: entries.length,
177
+ };
178
+ }
179
+ function classifyHonored(baseline, entries, config, logger) {
180
+ const v = validateRequestMcpEntries(entries);
158
181
  if (v.badContentOrigin.length > 0) {
159
182
  logger?.warn("mcp_content_class_dropped", {
160
183
  entries: v.badContentOrigin,
@@ -165,13 +188,26 @@ export function resolveRequestMcp(baseline, bodyMcp, config, logger) {
165
188
  const reservedNames = config.mcpServers?.reservedNames ?? [];
166
189
  const closed = deploymentClosedMcpNames(baseline, reservedNames);
167
190
  const blocked = v.ok.filter((s) => closed.has(s.name)).map((s) => s.name);
168
- if (blocked.length > 0) {
169
- logger?.warn("mcp_injection_dropped", {
170
- reason: "name_reserved_by_deployment",
171
- dropped: blocked,
172
- note: "these names are declared by the deployment (center/config) — mounted or skipped, a caller can neither shadow nor refill them; rename the request-side server",
173
- });
191
+ return {
192
+ mcp: mergeRequestMcp(baseline, v.ok, reservedNames),
193
+ drops: [...v.dropped, ...blocked.map((server) => ({ server, reason: "name_reserved_by_deployment" }))],
194
+ droppedTotal: v.droppedTotal + blocked.length,
195
+ };
196
+ }
197
+ function mintInjectionDropNotices(drops, notice) {
198
+ if (notice === undefined || drops.length === 0)
199
+ return;
200
+ const sessionId = notice.sessionId;
201
+ if (typeof sessionId !== "string" || sessionId.length === 0)
202
+ return;
203
+ const said = new Set();
204
+ for (const d of drops) {
205
+ if (d.server !== MALFORMED_NAME) {
206
+ if (said.has(d.server))
207
+ continue;
208
+ said.add(d.server);
209
+ }
210
+ notice.emit(mcpInjectionDroppedNotice({ sessionId, server: d.server, reason: d.reason, ...(d.field !== undefined ? { field: d.field } : {}) }));
174
211
  }
175
- return mergeRequestMcp(baseline, v.ok, reservedNames);
176
212
  }
177
213
  //# sourceMappingURL=task-mcp.js.map
@@ -143,6 +143,26 @@ export interface ToolApprovalFrame {
143
143
  * ask」,治理策略产的与普通策略产的在这一个词上同形 ⇒ 顶替不了(逐字论证见 `governance-ask-marks.ts` 顶注)。
144
144
  */
145
145
  origin?: string;
146
+ /**
147
+ * **S-185 / [ref]**(core 7.10.0;**ADDITIVE**,`"tool_approval"` only)—— 这一问**为什么**到了人手上:
148
+ * auto 档的分类器被咨询过、而它**跑不了**。`cause` = core 的闭三词
149
+ * (`AUTO_MODE_UNAVAILABLE_CAUSES` = `error` / `timeout` / `breaker_open`),`AskRequest.classifierUnavailable`
150
+ * 逐字透传。
151
+ *
152
+ * 🔴 **缺席 ≠「分类器好着呢」**:缺席同时覆盖三形 —— 分类器答上了 / 这只 ask 没资格走分类器
153
+ * (`classifierMayAnswer` 的闭表)/ 本部署压根没接分类器。消费端**禁**把缺席读成对分类器健康的断言。
154
+ * 另注:`parse_error`(分类器跑了但答得出格)**不盖这一位** —— 那是另一句话,core 顶注逐字。
155
+ *
156
+ * 🔴 **不枚举词表**(值形是 `{cause: string}` 而不是本仓自铸的联合):词表单一属主在 core,抄一份会把
157
+ * core 加的新词吞成缺席。窄读只判「对象 ∧ `cause` 非空串 ∧ 无多余成员」(`readClassifierUnavailable`,
158
+ * 帧与卡的**唯一**铸造点 ⇒ 两面结构性同值)。
159
+ *
160
+ * 🔴 **echo-only,零消费**:熔断/超时的处置全在 core 的分类器站,server 不许据本键自铸第二套回落判据
161
+ * —— 同 `origin` / `denialLimitFallback` 两条顶注的同一条禁令(同一语义面两个写者)。
162
+ */
163
+ classifierUnavailable?: {
164
+ cause: string;
165
+ };
146
166
  /**
147
167
  * **E-14**([ref]② Trojan Source 族;**ADDITIVE**,`"tool_approval"` only)—— 这只 ask 的**工具输入**
148
168
  * (`AskRequest.args`)里含 bidi 控制符(LRM/RLM、嵌入/覆写、隔离符;字符类属主 `text-bidi.ts`)。
@@ -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, deriveBatchId, MAX_DECISION_NOTE_CHARS } from "./approval-ask-machine.js";
11
- import { ApprovalCardEnvelopeSchema, MAX_RULE_OFFERS, buildApprovalCard, buildApprovalCardEnvelope, buildApprovalRequestFrame, buildRevokeFrame, readDenialLimitFallback, readProbeCause, readRuleEvidence, readRuleOffersAbsence, RuleOfferRawSchema, backfillLegacyBatchMemberKind, screenUncoveredDetailSeat, } from "./approval-card.js";
11
+ import { ApprovalCardEnvelopeSchema, MAX_RULE_OFFERS, buildApprovalCard, buildApprovalCardEnvelope, buildApprovalRequestFrame, buildRevokeFrame, readDenialLimitFallback, readClassifierUnavailable, readProbeCause, readRuleEvidence, readRuleOffersAbsence, RuleOfferRawSchema, backfillLegacyBatchMemberKind, screenUncoveredDetailSeat, } from "./approval-card.js";
12
12
  import { projectAskTerminalClaimTruth } from "./plugins/approval-ask-store-sql.js";
13
13
  import { governanceAskMarksFor, runWithGovernanceAskScope } from "./governance-ask-marks.js";
14
14
  const defaultLogger = createLogger();
@@ -844,6 +844,7 @@ export class ToolApprovalCoordinator {
844
844
  ...(ruleLaneMaterial !== undefined ? { ruleOffers: ruleLaneMaterial.offers } : {}),
845
845
  ...((a) => (a !== undefined ? { ruleOffersAbsence: a } : {}))(readRuleOffersAbsence(req)),
846
846
  ...((f) => (f !== undefined ? { denialLimitFallback: f } : {}))(readDenialLimitFallback(req)),
847
+ ...((c) => (c !== undefined ? { classifierUnavailable: c } : {}))(readClassifierUnavailable(req)),
847
848
  ...((c) => (c !== undefined ? { probeCause: c } : {}))(readProbeCause(req)),
848
849
  ...((c) => (c !== undefined ? { ruleEvidence: c } : {}))(readRuleEvidence(req)),
849
850
  ...(bounded.omitted ? { argsOmitted: true } : { args: bounded.args }),
@@ -28,7 +28,7 @@ type BgNotifExcluded = "kind" | "sessionScoped" | "owner" | "scope" | "descripti
28
28
  type _GuardBgNotif = AssertAllKeysHandled<Exclude<keyof BackgroundChildEvent, BgNotifProjected | BgNotifExcluded>>;
29
29
  type RosterProjected = "name" | "agentId" | "sessionId" | "toolUseId" | "owner" | "scope" | "sessionScoped" | "rootSessionId" | "model" | "modelFallback" | "createdAt";
30
30
  type _GuardRoster = AssertAllKeysHandled<Exclude<keyof RosterEntry, RosterProjected>>;
31
- type AskProjected = "toolName" | "toolCallId" | "args" | "message" | "sourceTaskId" | "fromSubagent" | "sourceAgentName" | "delegation" | "ruleOffers" | "ruleOffersAbsence" | "persistedRuleShadowed" | "probeCause" | "ruleEvidence" | "requiresRealApproval" | "denialLimitFallback" | "origin";
31
+ type AskProjected = "toolName" | "toolCallId" | "args" | "message" | "sourceTaskId" | "fromSubagent" | "sourceAgentName" | "delegation" | "ruleOffers" | "ruleOffersAbsence" | "persistedRuleShadowed" | "probeCause" | "ruleEvidence" | "requiresRealApproval" | "denialLimitFallback" | "origin" | "classifierUnavailable";
32
32
  type AskExcluded = "preview" | "principal" | "riskAxes" | "boundInputHash" | "isDelegatedChild" | "probeReason" | "hasBidiControls" | "previewWithheld" | "execCwd";
33
33
  type _GuardAsk = AssertAllKeysHandled<Exclude<keyof AskRequest, AskProjected | AskExcluded>>;
34
34
  type TaskEventHandled = "text_delta" | "reasoning_delta" | "tool_start" | "tool_end" | "turn_end" | "compacted" | "diagnostics" | "message_committed" | "status" | "task_notification" | "task_progress" | "steering_injected" | "workspace_changed" | "done" | "context_usage" | "compaction_outcome" | "human_input" | "wiring_manifest" | "text_end" | "tool_roster_delta";
@@ -38,14 +38,14 @@ type _GuardMailbox = AssertAllKeysHandled<Exclude<keyof MailboxMessage, MailboxP
38
38
  type MailboxAppendProjected = "from" | "content" | "sentAt" | "hopChain" | "peerMeta";
39
39
  type _GuardMailboxAppend = AssertAllKeysHandled<Exclude<keyof MailboxAppendMessage, MailboxAppendProjected>>;
40
40
  type PermissionTraceKind = Extract<TraceEvent["kind"], `permission.${string}`>;
41
- type PermissionTraceProjected = "permission.persisted_rule_allowed" | "permission.rule_store_unreadable";
41
+ type PermissionTraceProjected = "permission.persisted_rule_allowed" | "permission.rule_store_unreadable" | "permission.read_only_allowed";
42
42
  type PermissionTraceDropped = "permission.sandbox_admitted" | "permission.rule_sync_resurrected" | "permission.rule_sync_dropped" | "permission.org_snapshot_unavailable";
43
43
  type _GuardPermissionTrace = AssertAllKeysHandled<Exclude<PermissionTraceKind, PermissionTraceProjected | PermissionTraceDropped>>;
44
44
  type _GuardPermissionTraceReverse = AssertAllKeysHandled<Exclude<PermissionTraceProjected | PermissionTraceDropped, PermissionTraceKind>>;
45
45
  /** `T` 非 `never` 时收敛到 `never`(空集 ⇒ 残留 `"EMPTY"` ⇒ tsc 红)。 */
46
46
  type AssertNonEmpty<T> = [T] extends [never] ? "EMPTY" : never;
47
47
  type _GuardPermissionTraceNonEmpty = AssertAllKeysHandled<AssertNonEmpty<PermissionTraceKind>>;
48
- type SummaryProjected = "sessionId" | "scope" | "createdAt" | "gateKind" | "severity" | "spentMicroUsd" | "deadline" | "hasBidiControls" | "requiresRealApproval" | "denialLimitFallback" | "origin";
48
+ type SummaryProjected = "sessionId" | "scope" | "createdAt" | "gateKind" | "severity" | "spentMicroUsd" | "deadline" | "hasBidiControls" | "requiresRealApproval" | "denialLimitFallback" | "origin" | "classifierUnavailable";
49
49
  type SummaryExcluded = "token" | "toolInput" | "toolName" | "toolCallId" | "preview" | "principal" | "sourceTaskId" | "contentKind" | "restoreMode" | "checkpointId" | "previewWithheld";
50
50
  type _GuardInboxSummary = AssertAllKeysHandled<Exclude<keyof CheckpointSummary, SummaryProjected | SummaryExcluded>>;
51
51
  type TaskSpecWired = "objective" | "principal" | "images" | "sessionId" | "requireExistingSession" | "oneShot" | "clientContext" | "resumeAt" | "resumeAtMode" | "model" | "compactionModel" | "thinking" | "systemPrompt" | "appendSystemPrompt" | "promptProvider" | "memory" | "suggestNextPrompts" | "restoreFiles" | "acceptPartialRestore" | "rewindFilesTo" | "tools" | "excludeTools" | "deferTools" | "toolMaterializeStrategy" | "promptProfile" | "toolPolicy" | "onAsk" | "onQuestion" | "hooks" | "durableApproval" | "resourceSuspend" | "resilience" | "finalVerification" | "checkpointStore" | "handsReadOnly" | "memoryPersistenceCapable" | "additionalDirectories" | "additionalReadDirectories" | "enablePlanMode" | "interactiveTools" | "enableFork" | "shellGate" | "mcp" | "a2a" | "skills" | "backgroundScope" | "envFacts" | "limits" | "configOverrides" | "forwardSubagentEvents" | "retainSubagentSessions" | "retainBackgroundProcesses" | "outputSchema" | "outputRetries" | "compaction" | "attachments" | "selfOrchestration" | "getApiKeyAndHeaders" | "interactionPosture" | "agents" | "taskId" | "signal" | "preemptSignal" | "modelRole" | "enableBlockedReport" | "maxSuspends" | "autoModeRequested";
@@ -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"];
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"];
20
20
  export type EngineNoticeWireCode = (typeof ENGINE_NOTICE_WIRE_CODES)[number];
21
21
  /** 白名单谓词(单点):路由与门都读这一个,不许第二处手抄码串。 */
22
22
  export declare function isEngineNoticeWireCode(code: string): code is EngineNoticeWireCode;
@@ -136,5 +136,21 @@ export declare function registerEngineNoticeLeg(opts: {
136
136
  live?: EngineNoticeWireSink;
137
137
  durable?: EngineNoticeWireSink;
138
138
  router?: EngineNoticeRouter;
139
+ /**
140
+ * L-167 —— **腿开张之前**就已经铸好的通告(装配期 `resolveSpec` 的产物,经
141
+ * `PreparedTaskSubmission.engineNotices` 递过来)。注册完口**立刻**经同一只 {@link EngineNoticeRouter.route}
142
+ * 投出:白名单、归属键、消毒、隔离四件判据一个都不绕,**不是**第二条投递机制 —— 只是把 `route()` 挪到
143
+ * 「这条会话已经有口在听」的那一拍。
144
+ *
145
+ * 🔴 为什么不让铸点自己 `route()`:装配(`prepareSpec`)跑在本函数**之前**,那一刻这条会话一只口都没有,
146
+ * `route()` 恒返 0 —— 一条结构上永远投不出去的用户面披露,就是本仓 `task.user_steer_undrained` 陈腐明拒
147
+ * 那一族的病。缺席/空数组 ⇒ 一个字节不投(既有腿逐字不变)。
148
+ */
149
+ pending?: readonly {
150
+ code: string;
151
+ message: string;
152
+ detail?: Record<string, unknown>;
153
+ sessionId?: unknown;
154
+ }[];
139
155
  }): () => void;
140
156
  //# sourceMappingURL=engine-notice-wire.d.ts.map
@@ -20,6 +20,8 @@ export const ENGINE_NOTICE_WIRE_CODES = [
20
20
  "peer.held_settled",
21
21
  "peer.idle_subscription",
22
22
  "classifier.denial_limit",
23
+ "mcp.injection_dropped",
24
+ "delegation.ask_unresolvable",
23
25
  ];
24
26
  const WIRE_CODES = new Set(ENGINE_NOTICE_WIRE_CODES);
25
27
  export function isEngineNoticeWireCode(code) {
@@ -150,6 +152,10 @@ export function registerEngineNoticeLeg(opts) {
150
152
  const sinks = [...(live ? [live] : []), ...(durable ? [durable] : [])];
151
153
  if (sinks.length === 0)
152
154
  return () => undefined;
153
- return (opts.router ?? defaultEngineNoticeRouter).registerLeg(sessionId, sinks);
155
+ const router = opts.router ?? defaultEngineNoticeRouter;
156
+ const unregister = router.registerLeg(sessionId, sinks);
157
+ for (const notice of opts.pending ?? [])
158
+ router.route(notice);
159
+ return unregister;
154
160
  }
155
161
  //# sourceMappingURL=engine-notice-wire.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/server",
3
- "version": "7.67.0",
3
+ "version": "7.69.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,8 +54,8 @@
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": "7.9.0",
58
- "@sema-agent/settings-schema": "1.9.0",
57
+ "@sema-agent/core": "7.11.2",
58
+ "@sema-agent/settings-schema": "1.10.0",
59
59
  "e2b": "^2.28.0",
60
60
  "libsodium-wrappers": "^0.8.4",
61
61
  "mysql2": "^3.22.4",
@@ -69,7 +69,7 @@
69
69
  "sharp": "^0.35.3"
70
70
  },
71
71
  "devDependencies": {
72
- "@sema-agent/sdk": "8.6.0",
72
+ "@sema-agent/sdk": "8.8.0",
73
73
  "@types/libsodium-wrappers": "^0.7.14",
74
74
  "@types/node": "22.10.2",
75
75
  "@types/pg": "^8.20.0",