@sema-agent/server 7.72.0 → 7.73.1

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 (48) hide show
  1. package/README.md +1 -1
  2. package/USAGE.md +10 -0
  3. package/dist/boot/config-center.d.ts +6 -1
  4. package/dist/boot/config-center.js +3 -1
  5. package/dist/boot/memory-boundary.d.ts +27 -5
  6. package/dist/boot/memory-boundary.js +6 -6
  7. package/dist/boot/memory-consolidation.js +2 -1
  8. package/dist/boot/runner-deps.js +3 -1
  9. package/dist/boot/stores.js +6 -4
  10. package/dist/boot/unpriced-ceiling-verdict.d.ts +15 -0
  11. package/dist/boot/unpriced-ceiling-verdict.js +39 -0
  12. package/dist/budget.d.ts +10 -2
  13. package/dist/budget.js +2 -2
  14. package/dist/capabilities/tool-defer.d.ts +18 -12
  15. package/dist/config-types.d.ts +15 -7
  16. package/dist/config.d.ts +28 -12
  17. package/dist/config.js +26 -9
  18. package/dist/http/active-run-conflict.d.ts +3 -2
  19. package/dist/http/routes/runs.js +13 -10
  20. package/dist/http/server.js +15 -7
  21. package/dist/main.js +5 -5
  22. package/dist/memory-bundle-engine.d.ts +4 -3
  23. package/dist/memory-bundle-engine.js +2 -1
  24. package/dist/memory-incident-sink.d.ts +37 -0
  25. package/dist/memory-incident-sink.js +13 -0
  26. package/dist/memory-operator-faces.d.ts +9 -3
  27. package/dist/memory-operator-faces.js +4 -3
  28. package/dist/memory-scope.d.ts +37 -1
  29. package/dist/memory-scope.js +12 -2
  30. package/dist/observability/fail-open.d.ts +1 -1
  31. package/dist/observability/fail-open.js +1 -1
  32. package/dist/plugins/approval-ask-store-memory.js +3 -1
  33. package/dist/plugins/approval-ask-store-sql.d.ts +5 -0
  34. package/dist/plugins/approval-ask-store-sql.js +7 -0
  35. package/dist/plugins/file-run-store.js +1 -0
  36. package/dist/plugins/memory-run-store.js +1 -0
  37. package/dist/plugins/run-store-sql.d.ts +5 -2
  38. package/dist/plugins/run-store-sql.js +5 -3
  39. package/dist/plugins/store-contracts.d.ts +14 -0
  40. package/dist/run-local.js +15 -7
  41. package/dist/spec-fields.d.ts +4 -2
  42. package/dist/tool-approval.js +1 -1
  43. package/dist/trace/core-keyset-guard.d.ts +8 -2
  44. package/dist/trace/project.d.ts +43 -0
  45. package/dist/trace/project.js +26 -0
  46. package/dist/usage-analytics.d.ts +11 -1
  47. package/dist/usage-analytics.js +1 -1
  48. package/package.json +2 -2
@@ -96,7 +96,8 @@ export declare function taskAgentsSpecFragment(raw: unknown, requirePrincipal: b
96
96
  export declare function retainBackgroundProcessesFromBody(raw: unknown, requirePrincipal: boolean | undefined, warn: (event: string, fields: Record<string, unknown>) => void): true | undefined;
97
97
  /** [ref]② — body.{excludeTools,deferTools} → `TaskSpec.{excludeTools,deferTools}`(core 1.314 工具面
98
98
  * 控制批)。语义:excludeTools=roster 真卸载(schema 字节不上 wire,manifest 如实收窄);deferTools=
99
- * [ref] 延迟披露(占位上 wire,ToolSearch 激活 materialize)。两位 tighten-only(core 继承不变量:
99
+ * [ref] 延迟披露(占位上 wire,ToolSearch 激活 materialize;**core 7.15.0 [ref] 起它是唯一不受那道
100
+ * 10% 阈值门的延迟来源** —— 按字面恒延迟、不计量,引擎自选的候选集才受门)。两位 tighten-only(core 继承不变量:
100
101
  * union 进全部子 spawn 路径),per-run 工具面收窄无跨租户面 ⇒ 无租户门(interactiveTools 同姿势)。
101
102
  * DEFENSIVE(resume 重放不过 HTTP 400 门):非数组 ⇒ undefined;项非非空字符串 ⇒ 逐项 DROP;空数组 ⇒
102
103
  * undefined(不挂键=core 缺省,byte-compat)。HTTP 门另有 fail-loud 400(提交面邻居姿势)。 */
@@ -109,7 +110,8 @@ export declare function toolNameListFromBody(raw: unknown): string[] | undefined
109
110
  * **呈现**轴,它与 `deferMode` / `deferTools` 的延迟披露轴**无耦合** —— 上一行提 deferTools 只是在借它
110
111
  * 的「无租户门」姿势作类比。「引擎缺省 simple」这句本身在 core 5.40.0 上仍逐字为真
111
112
  * (`core/types.d.ts:133`:default "simple"),本批亲验未变。
112
- * 真正的 defer 轴对表(core 5.40.0 起 `deferMode:"auto"` 不再 sweep 内建)记在
113
+ * 真正的 defer 轴对表(core 5.40.0 起 `deferMode:"auto"` 不再 sweep 内建;7.15.0 起它不再是第二道门,
114
+ * 只是把候选集拓宽后走同一道阈值门)记在
113
115
  * `src/capabilities/tool-defer.ts` 的头注 —— 别把两根轴的结论写到一处。
114
116
  * DEFENSIVE(resume 重放不过 HTTP 400 门):非法值 ⇒ undefined;提交面另有 fail-loud 400(邻居姿势)。 */
115
117
  export declare function promptProfileFromBody(raw: unknown): "simple" | "classic" | undefined;
@@ -852,7 +852,7 @@ export class ToolApprovalCoordinator {
852
852
  };
853
853
  const windowBudgetMs = reachability === "unreached" ? this.unreachedTtlMs : this.ttlMs;
854
854
  const effectiveWindowMs = effectiveAskWindowMs(windowBudgetMs, this.windowMarginMs, origin.legDeadlineMonotonic, performance.now());
855
- const expiresAtMs = Date.now() + effectiveWindowMs;
855
+ const expiresAtMs = Math.ceil(Date.now() + effectiveWindowMs);
856
856
  let askId;
857
857
  let batchId;
858
858
  const card = this.askStore ? buildApprovalCard(frame, req, req.requiresRealApproval === true) : undefined;
@@ -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, TaskEvent, TraceEvent, MailboxMessage, MailboxAppendMessage, TaskSpec, TaskResult, WiringManifest, GateOutcome, GateDisposition, Settlement, PausedCause } from "@sema-agent/core";
20
+ import type { TaskNotificationPayload, SemaProvenance, BackgroundChildEvent, RosterEntry, AskRequest, CheckpointSummary, TaskEvent, TraceEvent, MailboxMessage, MailboxAppendMessage, TaskSpec, TaskResult, WiringManifest, GateOutcome, GateDisposition, Settlement, PausedCause, WorkflowRun } from "@sema-agent/core";
21
21
  import type { ToolApprovalFrame } from "../tool-approval.js";
22
22
  /** 编译期断言:T 必须收敛到 never(有残余键 = tsc 红)。
23
23
  * 🔴 **导出**([ref] U1/U2):本仓「词表闭集,未处置成员=编译红」的钉法只许有**一个**形 ——
@@ -148,6 +148,10 @@ type _GuardSettlementReverse = AssertAllKeysHandled<Exclude<SettlementProjected,
148
148
  type SettlementWhoProjected = "party" | "approver" | "window";
149
149
  type _GuardSettlementWho = AssertAllKeysHandled<Exclude<SettlementWhoKeys, SettlementWhoProjected>>;
150
150
  type _GuardSettlementWhoReverse = AssertAllKeysHandled<Exclude<SettlementWhoProjected, SettlementWhoKeys>>;
151
+ type WorkflowRunForwarded = "id" | "scope" | "status" | "startedAt" | "endedAt" | "createdAt" | "rev" | "name" | "description" | "result" | "error" | "errorCode" | "agentFailures" | "stats" | "phases" | "agents" | "groups";
152
+ type WorkflowRunStripped = "sourceTaskId" | "originatingSessionId" | "effectiveArgs" | "budgetOvershoot" | "timeoutInterruption" | "resultFull" | "completionId" | "resume" | "journalSkips";
153
+ type _GuardWorkflowRun = AssertAllKeysHandled<Exclude<keyof WorkflowRun, WorkflowRunForwarded | WorkflowRunStripped>>;
154
+ type _GuardWorkflowRunReverse = AssertAllKeysHandled<Exclude<WorkflowRunForwarded | WorkflowRunStripped, keyof WorkflowRun>>;
151
155
  export type CoreKeysetGuards = [
152
156
  _GuardNotification,
153
157
  _GuardNotificationReverse,
@@ -217,7 +221,9 @@ export type CoreKeysetGuards = [
217
221
  _GuardSettlement,
218
222
  _GuardSettlementReverse,
219
223
  _GuardSettlementWho,
220
- _GuardSettlementWhoReverse
224
+ _GuardSettlementWhoReverse,
225
+ _GuardWorkflowRun,
226
+ _GuardWorkflowRunReverse
221
227
  ];
222
228
  export {};
223
229
  //# sourceMappingURL=core-keyset-guard.d.ts.map
@@ -119,6 +119,21 @@ export declare function toolStartEventData(ev: {
119
119
  eventId?: string;
120
120
  parentToolCallId?: string;
121
121
  }): Record<string, unknown>;
122
+ /**
123
+ * 🔴 **筛子是一只总函数**(S-239,codex 对抗复审 r1 [medium] 亲核复现后修)—— 上面纪律②许诺的
124
+ * 「坏形 ⇒ report + withhold,**不抛**」此前是靠**逐条枚举**坏形兑现的,枚举不到的那些照样抛:
125
+ * `projectSettlement` 对 `note` / `who.approver` 先 `redactSecrets` 再截断,而 `redactSecrets` 在 ≥2^23
126
+ * 的单段上爆回溯栈(`RangeError`,S-102/S-106 登记的既有上界,见 `redact.ts` 该行顶注),两条叶各能抛一次。
127
+ *
128
+ * 抛出去的代价按腿算,而且一条比一条重:写腿落账那处的 `.catch` 看不到**同步**投影期的异常;读腿上它
129
+ * 直接逃出 `formatEvent` / 投影函数 —— 账本裸回放腿的那一次会当场断流(那一行不上帧、游标不前进、后面的
130
+ * `done` 永远到不了、重连恒复现同一处),而 `gate-outcome-defective` 那一格还不涨。
131
+ *
132
+ * ⇒ 兑现方式从「枚举」换成**结构**:任何逃出投影的异常同走既有的那一口 report + withhold。规则因此变少
133
+ * (不是「守住已知的 N 种坏形」而是「坏字节一律 withhold」),上面那几道具名形门留着只为**诊断串更准**。
134
+ * ⛔ **刻意不动**「先脱敏后截断」的次序:截断在前会把跨界的密钥切成半截明文留在输出里,而且它只治
135
+ * `note` 一条叶(`approver` 同病)—— 那是给一个类打两个特判,正是本仓要消掉的形。
136
+ */
122
137
  export declare function screenedGate(v: unknown): GateOutcome | undefined;
123
138
  /**
124
139
  * 🔴 **耐久行的**门记录读口(7.72.0;`screenedGate` 的读腿孪生)—— 先把本仓自己写过的**旧拼法**读成它
@@ -132,6 +147,34 @@ export declare function screenedGate(v: unknown): GateOutcome | undefined;
132
147
  * 不改原对象(调用方与账本共享引用):归一时换一只信封,原记录一个字节不动。
133
148
  */
134
149
  export declare function screenedStoredGate(v: unknown): GateOutcome | undefined;
150
+ /**
151
+ * 🔴 **账本裸回放面的读腿一步**(S-239)—— `GET /v1/runs/:id/events`(`http/routes/runs.ts` 的
152
+ * `formatEvent`)对每一行走这一口,把行上的 `GateOutcome` 交给**同一只** {@link screenedStoredGate}。
153
+ *
154
+ * ## 它补的是哪一格
155
+ * 7.72.0 把耐久读边界收成一只筛子,但点名的读腿只有两条({@link toolResultFieldsOf} 的投影回放、
156
+ * `/decide` 幂等回放体)。**账本裸回放**是第三条,而它此前只过 `redactLedgerEventData` —— 那只函数
157
+ * 对 `tool_end` 型**逐字不动**(它管的是 `done.result` / `failed.errorMessage` / park 行三族)。
158
+ * 于是同一条账本行在本仓三张读面上有**两种**读法:
159
+ * · 本仓 7.64.0–7.71.0 自己写下的 `origin:"unresolvable"` —— 投影面读成今天的名字,裸回放面原样
160
+ * 透出一个 core 今天判**非成员**的词(消费端按闭集分派 ⇒ 落进它的 default 臂);
161
+ * · 第三方 producer / 坏世代写下的集外词与破不变量的记录 —— 投影面整条 withhold + 计数,裸回放面
162
+ * 直接上 wire,而 `gate-outcome-defective` 那一格不涨(运维看不见有 producer 在发坏记录)。
163
+ *
164
+ * ## 为什么是这一形(而不是在路由里加一只筛)
165
+ * 筛子仍然只有一只,归一表仍然只有一张 —— 本函数只是把**第三条读腿**接到它上面,规则因此从
166
+ * 「三条读腿里有两条筛」回到「凡耐久读腿上的 `GateOutcome` 一律过 `screenedStoredGate`,零例外」。
167
+ * 它按**型**分派而不是按调用点,所以将来第二个携带 `GateOutcome` 的账本型只需把
168
+ * {@link GATE_BEARING_LEDGER_EVENT_TYPE} 扩成词表,读腿一行都不用改。
169
+ *
170
+ * ## 与写腿的关系(别再走回头路)
171
+ * 写腿的对偶是 `redactLedgerEventData`(三孪生 store 的 `appendEvent` 落库前),它**不该**长出本函数
172
+ * 这一步:归一只认读腿,写腿保持严格(理由全文见 {@link RETIRED_ASK_ORIGIN_SPELLINGS} 的边界划清二)。
173
+ * 两只函数因此是「共用的脱敏汇点 + 读腿独有的筛」这一层关系,不是同一只函数的两种模式。
174
+ *
175
+ * 不改原对象(调用方与账本共享引用):有变更时换一只信封,原记录一个字节不动。
176
+ */
177
+ export declare function screenedStoredEventData(type: string, data: unknown): unknown;
135
178
  /** The durable `tool_end` payload (shared by both append sites). E1: the model-facing `output` is UNTRUSTED RAW
136
179
  * from core (file/shell/API bodies) — core only SIZE-bounds it (`truncated`), REDACTION is ours (same contract as
137
180
  * `tool_start.args`); never re-fed to a model. E2: identity. Absent `output` ⇒ the tool produced no content body.
@@ -90,6 +90,15 @@ const RETIRED_ASK_ORIGIN_SPELLINGS = {
90
90
  unresolvable: "ancestor_marked",
91
91
  };
92
92
  export function screenedGate(v) {
93
+ try {
94
+ return screenedGateOrThrow(v);
95
+ }
96
+ catch (e) {
97
+ recordFailOpen("server.trace.gate-outcome-defective", `projection threw: ${e instanceof Error ? `${e.name}: ${e.message}` : "non-Error throw"}`);
98
+ return undefined;
99
+ }
100
+ }
101
+ function screenedGateOrThrow(v) {
93
102
  if (v === null || typeof v !== "object")
94
103
  return undefined;
95
104
  const g = v;
@@ -133,6 +142,23 @@ export function screenedStoredGate(v) {
133
142
  const renamed = typeof g.origin === "string" ? RETIRED_ASK_ORIGIN_SPELLINGS[g.origin] : undefined;
134
143
  return screenedGate(renamed === undefined ? g : { ...g, origin: renamed });
135
144
  }
145
+ const GATE_BEARING_LEDGER_EVENT_TYPE = "tool_end";
146
+ export function screenedStoredEventData(type, data) {
147
+ if (type !== GATE_BEARING_LEDGER_EVENT_TYPE)
148
+ return data;
149
+ if (data === null || typeof data !== "object" || Array.isArray(data))
150
+ return data;
151
+ const d = data;
152
+ if (d.gate === undefined)
153
+ return data;
154
+ const gate = screenedStoredGate(d.gate);
155
+ if (gate === undefined) {
156
+ const withheld = { ...d };
157
+ delete withheld.gate;
158
+ return withheld;
159
+ }
160
+ return { ...d, gate };
161
+ }
136
162
  const SETTLEMENT_PARTIES = new Set(["person", "engine", "host", "none"]);
137
163
  function projectSettlement(st) {
138
164
  const whoV = st.who;
@@ -72,10 +72,20 @@ export interface UsageTotals {
72
72
  export declare function usageSummary(rows: UsageRow[]): UsageTotals;
73
73
  export type UsageMetric = "tasks" | "tokensIn" | "tokensOut" | "costUsd";
74
74
  export type UsageGranularity = "hour" | "day";
75
- /** GET /v1/usage/series — 时间序列(UTC 桶;空桶不发行,消费方按需补零)。 */
75
+ /**
76
+ * GET /v1/usage/series — 时间序列(UTC 桶;空桶不发行,消费方按需补零)。
77
+ *
78
+ * 🔴 **行带 `estimated`**(S-228):与 {@link usageSummary} / {@link usageBreakdown} **同轴同谓词** ——
79
+ * 三个读面的桶都是同一只 {@link UsageTotals},由同一条 {@link foldRow} 折出来,所以「这个数字不精确」
80
+ * 的四个来源(旧行 fallback / per-model echo 缺键 / 缺 `usageBasis` 的 legacy 口径 / 行自陈
81
+ * `usageMissing` 的下界)在三面上是**同一句话**。修前只有 series 的出口把这一位扔了:桶里塞进一条
82
+ * 「没量到」的行,折线与一段真的低消耗在 wire 上逐字同形 —— 而那两件事的处置相反。
83
+ * 不新开判据、不加第二条轴:出口多投一个已经算好的位。
84
+ */
76
85
  export declare function usageSeries(rows: UsageRow[], metric: UsageMetric, granularity: UsageGranularity): Array<{
77
86
  t: string;
78
87
  v: number;
88
+ estimated: boolean;
79
89
  }>;
80
90
  export type UsageDimension = "principal" | "model";
81
91
  /** GET /v1/usage/breakdown — 按维度分桶。dimension=model 时按 per-model echo 展开(一行可贡献多个 model 桶;
@@ -54,7 +54,7 @@ export function usageSeries(rows, metric, granularity) {
54
54
  }
55
55
  return [...buckets.entries()]
56
56
  .sort((a, b) => a[0] - b[0])
57
- .map(([b, t]) => ({ t: new Date(b).toISOString(), v: metric === "costUsd" ? round6(t.costUsd) : t[metric] }));
57
+ .map(([b, t]) => ({ t: new Date(b).toISOString(), v: metric === "costUsd" ? round6(t.costUsd) : t[metric], estimated: t.estimated }));
58
58
  }
59
59
  export function usageBreakdown(rows, dimension) {
60
60
  const buckets = new Map();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/server",
3
- "version": "7.72.0",
3
+ "version": "7.73.1",
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": "7.14.0",
57
+ "@sema-agent/core": "7.16.0",
58
58
  "@sema-agent/settings-schema": "1.10.0",
59
59
  "e2b": "^2.28.0",
60
60
  "libsodium-wrappers": "^0.8.4",