@sema-agent/server 7.1.0 → 7.3.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 (76) hide show
  1. package/README.md +3 -1
  2. package/README.zh-CN.md +1 -1
  3. package/USAGE.md +6 -1
  4. package/dist/approval-ask-machine.d.ts +39 -0
  5. package/dist/approval-ask-machine.js +101 -0
  6. package/dist/approval-card.d.ts +244 -0
  7. package/dist/approval-card.js +237 -0
  8. package/dist/approval-deny-reasons.d.ts +56 -0
  9. package/dist/approval-deny-reasons.js +54 -0
  10. package/dist/approval-reconciler.d.ts +167 -0
  11. package/dist/approval-reconciler.js +307 -0
  12. package/dist/boot/coordinators.d.ts +1 -0
  13. package/dist/boot/coordinators.js +36 -3
  14. package/dist/boot/lexical-path-env.d.ts +14 -0
  15. package/dist/boot/lexical-path-env.js +116 -0
  16. package/dist/boot/org-memory.d.ts +8 -5
  17. package/dist/boot/org-memory.js +23 -12
  18. package/dist/boot/reapers.d.ts +34 -0
  19. package/dist/boot/reapers.js +198 -23
  20. package/dist/boot/resolve-spec.d.ts +16 -1
  21. package/dist/boot/resolve-spec.js +104 -46
  22. package/dist/config-center/facade.d.ts +1 -1
  23. package/dist/config-center/facade.js +1 -1
  24. package/dist/config-center/http-client.d.ts +19 -0
  25. package/dist/config-center/http-client.js +81 -32
  26. package/dist/config-types.d.ts +76 -7
  27. package/dist/config.d.ts +1 -0
  28. package/dist/config.js +134 -4
  29. package/dist/elicitation.d.ts +4 -0
  30. package/dist/elicitation.js +2 -2
  31. package/dist/http/routes/capabilities.js +18 -2
  32. package/dist/http/routes/runs.d.ts +1 -0
  33. package/dist/http/routes/runs.js +548 -16
  34. package/dist/http/routes/tasks.js +190 -12
  35. package/dist/http/server.d.ts +1 -1
  36. package/dist/http/server.js +124 -8
  37. package/dist/http/sse-log.d.ts +51 -0
  38. package/dist/http/sse-log.js +64 -0
  39. package/dist/http/wire-types.d.ts +20 -5
  40. package/dist/leader/wire.js +4 -0
  41. package/dist/main.js +7 -4
  42. package/dist/org-memory-admission.d.ts +2 -1
  43. package/dist/org-memory-admission.js +10 -4
  44. package/dist/parked-decide.js +5 -2
  45. package/dist/plugins/approval-ask-store-memory.d.ts +38 -0
  46. package/dist/plugins/approval-ask-store-memory.js +299 -0
  47. package/dist/plugins/approval-ask-store-sql.d.ts +341 -0
  48. package/dist/plugins/approval-ask-store-sql.js +705 -0
  49. package/dist/plugins/background-agent-store-sql.js +20 -1
  50. package/dist/plugins/checkpoint-store-sql.d.ts +84 -9
  51. package/dist/plugins/checkpoint-store-sql.js +297 -16
  52. package/dist/plugins/local-checkpoint-store.d.ts +6 -5
  53. package/dist/plugins/local-checkpoint-store.js +4 -0
  54. package/dist/plugins/pg-pool.js +11 -0
  55. package/dist/plugins/store-backend.d.ts +18 -0
  56. package/dist/plugins/store-backend.js +10 -0
  57. package/dist/plugins/tidb-pool.js +27 -4
  58. package/dist/question.d.ts +18 -3
  59. package/dist/question.js +20 -6
  60. package/dist/runs.d.ts +16 -1
  61. package/dist/runs.js +61 -3
  62. package/dist/runtime-caps-resolver.d.ts +7 -1
  63. package/dist/runtime-caps-resolver.js +65 -3
  64. package/dist/runtime-governance.d.ts +11 -4
  65. package/dist/runtime-governance.js +16 -5
  66. package/dist/spec-fields.d.ts +4 -0
  67. package/dist/spec-fields.js +6 -0
  68. package/dist/task-settings.d.ts +35 -15
  69. package/dist/task-settings.js +19 -5
  70. package/dist/tool-approval.d.ts +296 -3
  71. package/dist/tool-approval.js +1066 -50
  72. package/dist/trace/core-keyset-guard.d.ts +2 -2
  73. package/dist/trace/ledger-sink.js +14 -1
  74. package/dist/trace/project.d.ts +55 -0
  75. package/dist/trace/project.js +135 -0
  76. package/package.json +4 -3
@@ -26,9 +26,9 @@ type _GuardBgNotif = AssertAllKeysHandled<Exclude<keyof BackgroundChildEvent, Bg
26
26
  type RosterProjected = "name" | "agentId" | "sessionId" | "toolUseId" | "owner" | "scope" | "sessionScoped" | "rootSessionId" | "model" | "modelFallback" | "createdAt";
27
27
  type _GuardRoster = AssertAllKeysHandled<Exclude<keyof RosterEntry, RosterProjected>>;
28
28
  type AskProjected = "toolName" | "toolCallId" | "args" | "message" | "sourceTaskId" | "fromSubagent" | "sourceAgentName" | "delegation";
29
- type AskExcluded = "preview" | "principal" | "requiresRealApproval";
29
+ type AskExcluded = "preview" | "principal" | "requiresRealApproval" | "riskAxes" | "boundInputHash";
30
30
  type _GuardAsk = AssertAllKeysHandled<Exclude<keyof AskRequest, AskProjected | AskExcluded>>;
31
- 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";
31
+ 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";
32
32
  type _GuardTaskEvent = AssertAllKeysHandled<Exclude<TaskEvent["type"], TaskEventHandled>>;
33
33
  export type CoreKeysetGuards = [_GuardNotification, _GuardBgNotif, _GuardRoster, _GuardAsk, _GuardTaskEvent];
34
34
  export {};
@@ -1,5 +1,5 @@
1
1
  import { redactSecrets } from "./redact.js";
2
- import { toolStartEventData, toolEndEventData, taskProgressEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, workspaceChangedEventData, turnEndEventData, contextUsageEventData } from "./project.js";
2
+ import { toolStartEventData, toolEndEventData, taskProgressEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, workspaceChangedEventData, wiringManifestEventData, humanInputEventData, turnEndEventData, contextUsageEventData } from "./project.js";
3
3
  import { NotifiedKeys, taskNotificationStreamKey } from "../orchestration/workflow-completion-inbox.js";
4
4
  export function createLedgerSink(opts) {
5
5
  const keys = opts.notifiedKeys ?? new NotifiedKeys();
@@ -114,6 +114,19 @@ export function createLedgerSink(opts) {
114
114
  await flush();
115
115
  await append("workspace_changed", workspaceChangedEventData(ev));
116
116
  break;
117
+ case "wiring_manifest":
118
+ // 🔴 core 5.14.0 design/173:装配自证清单。账本行**同样**要剥 `governance` 段——durable 行可经
119
+ // `GET /v1/runs/:id/events` 重放给同一批租户订阅者,是与 sync 腿完全相同的泄露面,所以用**同一个**
120
+ // 构造器(两腿分头挑键就是下一次泄露的种子)。core 契约:no projection ⇒ do not disclose。
121
+ await flush();
122
+ await append("wiring_manifest", wiringManifestEventData(ev));
123
+ break;
124
+ case "human_input":
125
+ // core 5.14.0 design/171:人类输入生命周期账本(谁/经哪条载体/投递成没成)。落账是本臂的
126
+ // 正当用途——「这条 run 是谁喂的」正是事后对账要的历史事实;身份串的脱敏在共享构造器里。
127
+ await flush();
128
+ await append("human_input", humanInputEventData(ev));
129
+ break;
117
130
  case "task_progress":
118
131
  // core breakpoint⑤: a subagent's live progress tick → an INLINE "subagent working" card for the tailing
119
132
  // client (S2-a). Shared whitelist+redact builder (+ E2 identity for the exact concurrent-tick binding).
@@ -142,6 +142,7 @@ export declare function toolEndEventData(ev: {
142
142
  * exactly by them; the 1.72 whitelist dropped them, leaving a FIFO heuristic). */
143
143
  export declare function taskProgressEventData(ev: {
144
144
  taskId: string;
145
+ taskType?: string;
145
146
  parentTaskId?: string;
146
147
  name?: string;
147
148
  status?: string;
@@ -259,6 +260,60 @@ export declare function workspaceChangedEventData(ev: {
259
260
  eventId?: string;
260
261
  parentToolCallId?: string;
261
262
  }): Record<string, unknown>;
263
+ /**
264
+ * `wiring_manifest`(core 5.14.0 design/173 新 `TaskEvent` 臂)—— 每条腿(root/child/resume)在 prepare
265
+ * 时自证「我到底接了什么线」的清单帧。
266
+ *
267
+ * 🔴 **本构造器存在的唯一理由是剥掉 `governance` 段**。core 给该段盖了 `audience: "operator"` 并成文
268
+ * 了服务层义务:*a serving layer forwarding this event to a multi-tenant stream MUST project the governance
269
+ * section for operators only; **no projection ⇒ do not disclose***。我方的三条腿(sync SSE / durable 账本 /
270
+ * resume 账本)都是租户可读面,而 operator 投影是 #154 的独立大件——按 core 写死的失败方向,**没有投影
271
+ * 就不得披露**,所以本批先把整段剥掉止泄(此前 sync 腿的裸 catch-all 会把它连同 `lockedConfig` /
272
+ * `compliance` / `memoryAdmission` / `retention` 四个治理面在场位原样透传给任意订阅者)。
273
+ * 哪天 operator 投影落地,它是**另一个**构造器(按调用方身份分叉),不是往这里加键。
274
+ * ⚠️ 剥段还必须连**对该段取的哈希**一起剥:`configFingerprint` 同样不投影,理由见下方它那一行的旁注
275
+ * (无盐哈希 + 4 布尔 = 16 组合的谕示器,把「结构上藏起来」的段原样还原出来)。
276
+ *
277
+ * 其余段逐键挑(禁 `{...manifest}`:1.72 task_progress 教训——未来 core 加段必须由人显式处置,而不是
278
+ * 顺着 spread 裸上线,尤其当新段可能又是一个 audience 受限面时)。所有值都是引擎派生的闭枚举/布尔/
279
+ * 有限数/不透明摘要串,**非用户内容 ⇒ 不脱敏**;畸形值一律按缺席处理(不铸假值,与 compacted 同规)。
280
+ */
281
+ export declare function wiringManifestEventData(ev: {
282
+ manifest?: unknown;
283
+ eventId?: unknown;
284
+ parentToolCallId?: unknown;
285
+ }): Record<string, unknown>;
286
+ /**
287
+ * `human_input`(core 5.14.0 design/171 新 `TaskEvent` 臂)—— 「谁把什么喂进了这条 run」的生命周期账本
288
+ * 帧(objective / 实时 steer / nextTurn / parked-steer 续跑 / wake 五个载体共用一个投影点)。
289
+ *
290
+ * 信任划线(与 tool_approval 帧同族):
291
+ * · `inputId` / `sessionSeq` / `carrier` / `source` / `delivery` / `entryId` —— 引擎铸的标识与枚举值,
292
+ * **非用户内容** ⇒ verbatim。注意本帧**不带正文**(core 的臂里就没有 text 字段),所以没有内容脱敏面。
293
+ * · `issuer` 与 `actor.id` / `actor.issuer` —— 宿主从入口凭据派生的**身份串**,自由文本形(`slack:U123`
294
+ * 这类命名空间串里可以嵌任何东西)⇒ 过 `redactSecrets`,与 `sourceAgentName` 同待遇。
295
+ * · `actor.hostAsserted` —— 布尔,verbatim。**它是消费端唯一能判「这个署名可信吗」的位**(core 的
296
+ * `[from …]` 渲染就是靠它决定加不加 `(unverified)`),剥掉它比剥掉 id 更坏:剩下一个看不出真假的名字。
297
+ * · `principal` —— **刻意不投影**(与 ToolApprovalFrame 的 `principal` 同裁):帧本就经 owner-scoped 流
298
+ * 投递,租户身份不必再由帧自述。要它请先提消费需求,别顺手加。
299
+ *
300
+ * `actor` 逐键挑(禁 spread):core 已声明 `ActorAssertion` 是冻结三键形,但白名单的意义正是「core 加第
301
+ * 四键时由人处置」——身份对象上多出来的键裸上线是本文件反复登记的病族。
302
+ * 形参全可选 `unknown` 的理由同 {@link wiringManifestEventData}(两条 durable 腿手里只有 `{type:string}`)。
303
+ */
304
+ export declare function humanInputEventData(ev: {
305
+ inputId?: unknown;
306
+ sessionSeq?: unknown;
307
+ carrier?: unknown;
308
+ source?: unknown;
309
+ delivery?: unknown;
310
+ issuer?: unknown;
311
+ actor?: unknown;
312
+ principal?: unknown;
313
+ entryId?: unknown;
314
+ eventId?: unknown;
315
+ parentToolCallId?: unknown;
316
+ }): Record<string, unknown>;
262
317
  /** S4 (SILENT-FALLBACK P0-a): the durable `brain_status` observation row, shared by the bg + resume append
263
318
  * sites. core marks the live `status` frame EPHEMERAL (never replayed by core on resume) — this row is the
264
319
  * SERVICE's own observation record (why a turn stalled: rate_limited/retrying/reconnecting/circuit_open),
@@ -175,6 +175,12 @@ export function toolEndEventData(ev) {
175
175
  export function taskProgressEventData(ev) {
176
176
  return {
177
177
  taskId: ev.taskId,
178
+ // core 5.14.0([2854] 六车批②):委派种类判别键(core `DelegationTaskType` =
179
+ // "background_agent" | "workflow")—— 消费端据此路由一条 progress 帧,不必再从 id 形状猜。
180
+ // 形参取 `string` 而非闭枚举:该类型**没有**从 core 包根导出(亲验 index.d.ts 零命中,与发车帖
181
+ // 「新导出」的说法不符),抄一份闭集就是值拷贝漂移源;`stoppedBy` 先例同款——core 的开集串
182
+ // verbatim,消费端按契约容忍未知值。缺席=同步子代(无 fleet 行),缺席即不铸键。
183
+ ...(typeof ev.taskType === "string" && ev.taskType.length > 0 ? { taskType: ev.taskType } : {}),
178
184
  ...(ev.parentTaskId ? { parentTaskId: ev.parentTaskId } : {}),
179
185
  ...(ev.name ? { name: redactSecrets(ev.name) } : {}),
180
186
  // core [1414]#3 settle 终态 tick("completed"/"failed"——[1543]§三族B:此前被剥,消费方只见最后
@@ -333,6 +339,135 @@ export function workspaceChangedEventData(ev) {
333
339
  ...identityFields(ev),
334
340
  };
335
341
  }
342
+ /**
343
+ * `wiring_manifest`(core 5.14.0 design/173 新 `TaskEvent` 臂)—— 每条腿(root/child/resume)在 prepare
344
+ * 时自证「我到底接了什么线」的清单帧。
345
+ *
346
+ * 🔴 **本构造器存在的唯一理由是剥掉 `governance` 段**。core 给该段盖了 `audience: "operator"` 并成文
347
+ * 了服务层义务:*a serving layer forwarding this event to a multi-tenant stream MUST project the governance
348
+ * section for operators only; **no projection ⇒ do not disclose***。我方的三条腿(sync SSE / durable 账本 /
349
+ * resume 账本)都是租户可读面,而 operator 投影是 #154 的独立大件——按 core 写死的失败方向,**没有投影
350
+ * 就不得披露**,所以本批先把整段剥掉止泄(此前 sync 腿的裸 catch-all 会把它连同 `lockedConfig` /
351
+ * `compliance` / `memoryAdmission` / `retention` 四个治理面在场位原样透传给任意订阅者)。
352
+ * 哪天 operator 投影落地,它是**另一个**构造器(按调用方身份分叉),不是往这里加键。
353
+ * ⚠️ 剥段还必须连**对该段取的哈希**一起剥:`configFingerprint` 同样不投影,理由见下方它那一行的旁注
354
+ * (无盐哈希 + 4 布尔 = 16 组合的谕示器,把「结构上藏起来」的段原样还原出来)。
355
+ *
356
+ * 其余段逐键挑(禁 `{...manifest}`:1.72 task_progress 教训——未来 core 加段必须由人显式处置,而不是
357
+ * 顺着 spread 裸上线,尤其当新段可能又是一个 audience 受限面时)。所有值都是引擎派生的闭枚举/布尔/
358
+ * 有限数/不透明摘要串,**非用户内容 ⇒ 不脱敏**;畸形值一律按缺席处理(不铸假值,与 compacted 同规)。
359
+ */
360
+ export function wiringManifestEventData(ev) {
361
+ // 形参照 `compactionOutcomeEventData` / `contextUsageEventData` 先例:全可选 `unknown` + 内部逐层窄化。
362
+ // 两个理由,不是风格:①三条腿里有两条(ledger-sink.onEvent / resume switch)手里只有 `{type:string}`,
363
+ // 窄形参会逼出 `as unknown as` 双铸型(类型卫生棘轮门当场红);②窄化在这里做,账本回放/第三方 producer
364
+ // 送来的畸形段也走同一道门,而不是只保护 live 腿。
365
+ const str = (v) => (typeof v === "string" && v.length > 0 ? v : undefined);
366
+ const bool = (v) => (typeof v === "boolean" ? v : undefined);
367
+ const num = (v) => (typeof v === "number" && Number.isFinite(v) ? v : undefined);
368
+ /** 段读:非对象即缺席(不铸空段)。 */
369
+ const sec = (v) => (typeof v === "object" && v !== null && !Array.isArray(v) ? { ...v } : undefined);
370
+ const nonEmpty = (o) => (Object.keys(o).length > 0 ? o : undefined);
371
+ const m = sec(ev.manifest) ?? {};
372
+ const askIn = sec(m.ask) ?? {};
373
+ const questionIn = sec(m.question) ?? {};
374
+ const elicitIn = sec(m.elicit) ?? {};
375
+ const parkIn = sec(m.parkLane) ?? {};
376
+ const sessionIn = sec(m.session) ?? {};
377
+ const fleetIn = sec(m.fleet) ?? {};
378
+ const legIn = sec(m.leg) ?? {};
379
+ const interactionIn = sec(m.interaction) ?? {};
380
+ const ask = nonEmpty({
381
+ ...(str(askIn.form) !== undefined ? { form: askIn.form } : {}),
382
+ ...(str(askIn.provenance) !== undefined ? { provenance: askIn.provenance } : {}),
383
+ ...(str(askIn.effective) !== undefined ? { effective: askIn.effective } : {}),
384
+ });
385
+ const question = nonEmpty({
386
+ ...(str(questionIn.wired) !== undefined ? { wired: questionIn.wired } : {}),
387
+ ...(str(questionIn.provenance) !== undefined ? { provenance: questionIn.provenance } : {}),
388
+ // 组装谎言标(交互工具在场却没有投递面)——只在 core 真铸时带,缺席不折 false。
389
+ ...(questionIn.interactiveToolsWithoutDeliveryFace === true ? { interactiveToolsWithoutDeliveryFace: true } : {}),
390
+ });
391
+ const elicit = nonEmpty({
392
+ ...(bool(elicitIn.seamWired) !== undefined ? { seamWired: elicitIn.seamWired } : {}),
393
+ ...(num(elicitIn.serversOptedIn) !== undefined ? { serversOptedIn: elicitIn.serversOptedIn } : {}),
394
+ });
395
+ const parkLane = nonEmpty({
396
+ ...(bool(parkIn.capable) !== undefined ? { capable: parkIn.capable } : {}),
397
+ // `effective` 是三态(true / false / "unresolved")——布尔与字符串两支都得过。折成布尔会把
398
+ // 「还没定」谎报成「不能 park」,而那正是这个字段被造出来要区分的那一格。
399
+ ...(bool(parkIn.effective) !== undefined || str(parkIn.effective) !== undefined ? { effective: parkIn.effective } : {}),
400
+ ...(Array.isArray(parkIn.reasons) ? { reasons: parkIn.reasons.filter((r) => typeof r === "string") } : {}),
401
+ ...(str(parkIn.checkpointDurability) !== undefined ? { checkpointDurability: parkIn.checkpointDurability } : {}),
402
+ });
403
+ const fleet = nonEmpty({
404
+ ...(bool(fleetIn.backgroundAgentStore) !== undefined ? { backgroundAgentStore: fleetIn.backgroundAgentStore } : {}),
405
+ ...(bool(fleetIn.hostChildEventSink) !== undefined ? { hostChildEventSink: fleetIn.hostChildEventSink } : {}),
406
+ });
407
+ return {
408
+ ...(num(m.schemaVersion) !== undefined ? { schemaVersion: m.schemaVersion } : {}),
409
+ ...(str(legIn.kind) !== undefined ? { leg: { kind: legIn.kind } } : {}),
410
+ ...(ask !== undefined ? { ask } : {}),
411
+ ...(question !== undefined ? { question } : {}),
412
+ ...(str(interactionIn.posture) !== undefined ? { interaction: { posture: interactionIn.posture } } : {}),
413
+ ...(elicit !== undefined ? { elicit } : {}),
414
+ ...(parkLane !== undefined ? { parkLane } : {}),
415
+ ...(str(sessionIn.store) !== undefined ? { session: { store: sessionIn.store } } : {}),
416
+ ...(fleet !== undefined ? { fleet } : {}),
417
+ // governance —— **刻意不在此**(见头注:受众标 operator,无投影不披露)。
418
+ // configFingerprint —— **也刻意不在此**(codex 复审 2026-08-06 F1,验真后采纳)。剥掉一个段却把
419
+ // **对它取的哈希**发出去,等于没剥:core 的算法是
420
+ // `sha256(canonicalize(manifest 去掉 leg 与两个 provenance))` 取前 16 hex —— 无盐、输入里含整个
421
+ // governance 段,而 governance 只有 4 个布尔(audience 是常量)⇒ **16 种组合**。租户手里已经有其余
422
+ // 全部哈希输入(它们正是我们投影出去的那些段),把 16 种组合逐个拼进去重算一遍即可比中,
423
+ // lockedConfig / compliance / memoryAdmission / retention 四位当场还原。
424
+ // 「结构上藏起来、经哈希谕示器泄出去」仍然是泄出去,core 写死的失败方向(no projection ⇒ do not
425
+ // disclose)对侧信道一样适用。它的广告用途(判两条腿是不是同一套装配)在本仓与 SDK **今天零消费端**,
426
+ // 所以直接不发,而不是另铸一个「只对已投影字段取哈希」的服务端自造值(那是新 wire 语义,要跨仓对表)。
427
+ // 回补点:#154 的 operator 投影按调用方身份分叉,那条腿才带 core 的真 fingerprint。
428
+ ...identityFields(ev),
429
+ };
430
+ }
431
+ /**
432
+ * `human_input`(core 5.14.0 design/171 新 `TaskEvent` 臂)—— 「谁把什么喂进了这条 run」的生命周期账本
433
+ * 帧(objective / 实时 steer / nextTurn / parked-steer 续跑 / wake 五个载体共用一个投影点)。
434
+ *
435
+ * 信任划线(与 tool_approval 帧同族):
436
+ * · `inputId` / `sessionSeq` / `carrier` / `source` / `delivery` / `entryId` —— 引擎铸的标识与枚举值,
437
+ * **非用户内容** ⇒ verbatim。注意本帧**不带正文**(core 的臂里就没有 text 字段),所以没有内容脱敏面。
438
+ * · `issuer` 与 `actor.id` / `actor.issuer` —— 宿主从入口凭据派生的**身份串**,自由文本形(`slack:U123`
439
+ * 这类命名空间串里可以嵌任何东西)⇒ 过 `redactSecrets`,与 `sourceAgentName` 同待遇。
440
+ * · `actor.hostAsserted` —— 布尔,verbatim。**它是消费端唯一能判「这个署名可信吗」的位**(core 的
441
+ * `[from …]` 渲染就是靠它决定加不加 `(unverified)`),剥掉它比剥掉 id 更坏:剩下一个看不出真假的名字。
442
+ * · `principal` —— **刻意不投影**(与 ToolApprovalFrame 的 `principal` 同裁):帧本就经 owner-scoped 流
443
+ * 投递,租户身份不必再由帧自述。要它请先提消费需求,别顺手加。
444
+ *
445
+ * `actor` 逐键挑(禁 spread):core 已声明 `ActorAssertion` 是冻结三键形,但白名单的意义正是「core 加第
446
+ * 四键时由人处置」——身份对象上多出来的键裸上线是本文件反复登记的病族。
447
+ * 形参全可选 `unknown` 的理由同 {@link wiringManifestEventData}(两条 durable 腿手里只有 `{type:string}`)。
448
+ */
449
+ export function humanInputEventData(ev) {
450
+ const str = (v) => (typeof v === "string" && v.length > 0 ? v : undefined);
451
+ const a = typeof ev.actor === "object" && ev.actor !== null && !Array.isArray(ev.actor) ? { ...ev.actor } : {};
452
+ const actor = {
453
+ ...(str(a.id) !== undefined ? { id: redactSecrets(String(a.id)) } : {}),
454
+ ...(typeof a.hostAsserted === "boolean" ? { hostAsserted: a.hostAsserted } : {}),
455
+ ...(str(a.issuer) !== undefined ? { issuer: redactSecrets(String(a.issuer)) } : {}),
456
+ };
457
+ return {
458
+ // 缺键守卫同 compactionOutcomeEventData:无条件 String() 会把缺席铸成字面 "undefined" 落进 durable 行,
459
+ // 回放端读到一个看起来合法的 id/枚举值,比缺席更难发现。
460
+ ...(str(ev.inputId) !== undefined ? { inputId: ev.inputId } : {}),
461
+ ...(typeof ev.sessionSeq === "number" && Number.isFinite(ev.sessionSeq) ? { sessionSeq: ev.sessionSeq } : {}),
462
+ ...(str(ev.carrier) !== undefined ? { carrier: ev.carrier } : {}),
463
+ ...(str(ev.source) !== undefined ? { source: ev.source } : {}),
464
+ ...(str(ev.delivery) !== undefined ? { delivery: ev.delivery } : {}),
465
+ ...(str(ev.issuer) !== undefined ? { issuer: redactSecrets(String(ev.issuer)) } : {}),
466
+ ...(Object.keys(actor).length > 0 ? { actor } : {}),
467
+ ...(str(ev.entryId) !== undefined ? { entryId: ev.entryId } : {}),
468
+ ...identityFields(ev),
469
+ };
470
+ }
336
471
  /** S4 (SILENT-FALLBACK P0-a): the durable `brain_status` observation row, shared by the bg + resume append
337
472
  * sites. core marks the live `status` frame EPHEMERAL (never replayed by core on resume) — this row is the
338
473
  * SERVICE's own observation record (why a turn stalled: rate_limited/retrying/reconnecting/circuit_open),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/server",
3
- "version": "7.1.0",
3
+ "version": "7.3.0",
4
4
  "description": "Sema Server — the server/API implementation layer for Sema, wiring core, registry, model providers, and cloud agent execution. Built on @sema-agent/core.",
5
5
  "type": "module",
6
6
  "license": "BUSL-1.1",
@@ -54,7 +54,7 @@
54
54
  "build:binary:run-local:darwin-arm64": "bun build --compile --target=bun-darwin-arm64 src/run-local.ts --outfile dist/run-local-darwin-arm64"
55
55
  },
56
56
  "dependencies": {
57
- "@sema-agent/core": "^5.13.0",
57
+ "@sema-agent/core": "^5.14.0",
58
58
  "@sema-agent/registry-core": "^0.16.0",
59
59
  "e2b": "^2.28.0",
60
60
  "libsodium-wrappers": "^0.8.4",
@@ -62,7 +62,8 @@
62
62
  "pg": "^8.22.0",
63
63
  "ssh2": "^1.17.0",
64
64
  "typebox": "1.1.39",
65
- "ws": "^8.21.0"
65
+ "ws": "^8.21.0",
66
+ "zod": "^4.4.3"
66
67
  },
67
68
  "optionalDependencies": {
68
69
  "sharp": "^0.35.3"