@sema-agent/server 3.6.1 → 3.7.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.
- package/dist/budget.js +4 -4
- package/dist/fleet/fleet-bus.d.ts +1 -1
- package/dist/fleet/fleet-bus.js +11 -2
- package/dist/fleet-client.d.ts +6 -7
- package/dist/fleet-client.js +11 -11
- package/dist/hooks/branch-transcript.js +4 -1
- package/dist/trace/project.js +6 -0
- package/package.json +2 -2
package/dist/budget.js
CHANGED
|
@@ -167,10 +167,10 @@ export function createTracer(metrics, costQuota, modelUsage, fleetUsage, fleetLe
|
|
|
167
167
|
// 渲染成「未知」而非「免费」;第二级 = 行级缺席(本改动),沿账本→durable `model_usage`→
|
|
168
168
|
// `aggregateModelUsage`→`TaskStats.modelUsage` 回声→usage-analytics 的 `estimated` 标记,一路
|
|
169
169
|
// 保持缺席(聚合面的**未知传染**语义见 trace/project.ts)。
|
|
170
|
-
// ·
|
|
171
|
-
//
|
|
172
|
-
//
|
|
173
|
-
// center
|
|
170
|
+
// · fleet 批报腿(下面 fleetUsage)自 registry-core 0.11.0/[2103] 起**同样接住了**:wire 有
|
|
171
|
+
// 缺席位(UsageEntry.costMicroUsd optional),accumulator cell 级传染透传缺席,center 聚合面
|
|
172
|
+
// 「下界 + costUnknown」——两层语义与本处的关系见 fleet-client.ts 的旁注(3.7.0 前这里曾写
|
|
173
|
+
// 「wire 表达不了缺席、center 只见低估」,已被该车推翻;doc-rot 修 2026-07-30)。
|
|
174
174
|
// └──────────────────────────────────────────────────────────────────────────────────────────────┘
|
|
175
175
|
// E8 (shell-host): per-task × per-model usage for the `TaskStats.modelUsage` echo. `record` is a NO-OP unless
|
|
176
176
|
// e.taskId is a REGISTERED top-level run (the leak fence — sub-task/throwaway taskIds are never registered, so
|
|
@@ -109,7 +109,7 @@ export interface FleetTaskRow {
|
|
|
109
109
|
path: string;
|
|
110
110
|
edits: number;
|
|
111
111
|
}>;
|
|
112
|
-
/** [2070]①/[2080] 裁定(server 半场,3.
|
|
112
|
+
/** [2070]①/[2080] 裁定(server 半场,3.6.0):**产出这一行的车道**。
|
|
113
113
|
* - 缺席 = BCE 车道(`fleetBackgroundChildPublisher`)的 a\* 与 wa\* 真行,或顶层 run 行 —— 单源,常态。
|
|
114
114
|
* - `"run-leg"` = 由每腿的 `fleetRunPublisher` 从 `task_progress` tick 铸的**复合 id 行**
|
|
115
115
|
* (`${runId} ${childTaskId}`)。此形只在**没有 BCE 真行**的前台 delegation 上保留(同步腿委派的
|
package/dist/fleet/fleet-bus.js
CHANGED
|
@@ -157,7 +157,7 @@ export function fleetRunPublisher(bus, run) {
|
|
|
157
157
|
return typeof t === "number" ? t : undefined;
|
|
158
158
|
};
|
|
159
159
|
/**
|
|
160
|
-
* 🔴 [2070]①/[2080] 让位判据(run-leg 侧半场,server 3.
|
|
160
|
+
* 🔴 [2070]①/[2080] 让位判据(run-leg 侧半场,server 3.6.0)。
|
|
161
161
|
*
|
|
162
162
|
* 病灶(cli [2070]① 实测):本车道给**每一条**子代 tick 铸复合 id 行 `${runId} ${childTaskId}`,而
|
|
163
163
|
* BCE 车道(`fleetBackgroundChildPublisher`)对同一个 agent 已有 `a*`/`wa*` 稳定 handle 真行 ⇒ 同屏两行
|
|
@@ -318,6 +318,15 @@ export function fleetRunPublisher(bus, run) {
|
|
|
318
318
|
candidateCids.push(viaToolCall);
|
|
319
319
|
const liveCids = candidateCids.filter((c) => children.has(c));
|
|
320
320
|
const hadRow = liveCids.length > 0;
|
|
321
|
+
// 🔴 F1(2026-07-30 复审):无活行时先查 BCE claim——claim 在场 = 该 agent 的全部帧归 BCE 车道
|
|
322
|
+
// (run-leg 的 tick 臂已全程让位,children 恒空),终态臂同样让位:合成复合 id 瞬态终帧会让
|
|
323
|
+
// sourceLane 文档承诺废除的「同 agent 双 id 域帧」在终态那一拍回潮(且合成帧不带 sourceLane)。
|
|
324
|
+
// 返回 true=已被处理(BCE 车道自己发 a* 终帧);无 claim 的 bash 无 tick 形走下方原语义。
|
|
325
|
+
if (!hadRow) {
|
|
326
|
+
const claimed = [taskId, altId].some((t) => t !== undefined && bus.backgroundChildLaneRow(run.scope, t) !== undefined);
|
|
327
|
+
if (claimed)
|
|
328
|
+
return true;
|
|
329
|
+
}
|
|
321
330
|
// 都没活行 = bash 无 tick 形:按首候选合成瞬态终帧(建即离,诚实且无害)。
|
|
322
331
|
// [2070]③:合成帧**不铸 name** —— 这条「瞬态」帧会被壳的终态留存池渲 60s,顶上去的 a\* handle
|
|
323
332
|
// 在那 60s 里就是用户看到的名字。父链接/租户/会话三位照发(它们是归属事实,不是显示名)。
|
|
@@ -796,7 +805,7 @@ export function fleetBackgroundChildPublisher(bus, log) {
|
|
|
796
805
|
handleSpawn(e);
|
|
797
806
|
return;
|
|
798
807
|
}
|
|
799
|
-
const m = meta.get(e.taskId) ?? { sessionScoped: e.sessionScoped, tenantScope: "default", spawnedAt: Date.now() }; // scope domain map holds on the lazily-minted path too([1338]④ 首见起表)
|
|
808
|
+
const m = meta.get(e.taskId) ?? { sessionScoped: e.sessionScoped, tenantScope: e.scope ?? "default", spawnedAt: Date.now() }; // scope domain map holds on the lazily-minted path too([1338]④ 首见起表);F2(2026-07-30 复审):lazy-mint 曾硬编码 "default",scoped 部署下 claim 落错租户键 ⇒ 让位失效退回双生行
|
|
800
809
|
if (!meta.has(e.taskId)) {
|
|
801
810
|
remember(e.taskId, m); // tick/terminal without a seen spawn (restart/eviction edge) — row minted lazily
|
|
802
811
|
dlog("bg_child_event", { kind: `${e.kind}-lazy-mint`, taskId: e.taskId, sessionScoped: e.sessionScoped });
|
package/dist/fleet-client.d.ts
CHANGED
|
@@ -25,13 +25,12 @@ export declare class FleetUsageAccumulator {
|
|
|
25
25
|
private cells;
|
|
26
26
|
private runsSeen;
|
|
27
27
|
/**
|
|
28
|
-
* 🔴 RB-368
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* 在那之前,请**不要**把这个 `?? 0` 读成「已裁定未知=0」——裁定见 budget.ts 的 #59/RB-368 块。
|
|
28
|
+
* 🔴 RB-368(core 2.3.0;registry-core 0.11.0 收口,[2103]):`d.costMicroUsd` **可缺席 = 未知**
|
|
29
|
+
* (unpriced 部署,budget.ts 如实不带键)。wire 自 0.11.0 起有缺席位(UsageEntry.costMicroUsd
|
|
30
|
+
* optional)⇒ 本处**整键透传缺席**,不再折 0 低估。cell 级累加语义与 budget.ts ModelUsageTracker
|
|
31
|
+
* 同款=**传染**(同为单 producer 累加器:已知+未知=未知);center 聚合面的「下界 + costUnknown
|
|
32
|
+
* 标记」语义在 registry-core aggregateUsage(跨 worker 审计总账层,两层判据见 [2103])。
|
|
33
|
+
* 配额轴(weightedTokens)不受影响,仍逐笔精确。
|
|
35
34
|
*/
|
|
36
35
|
record(principal: string | undefined, model: string, taskId: string, d: {
|
|
37
36
|
inputTokens: number;
|
package/dist/fleet-client.js
CHANGED
|
@@ -25,13 +25,12 @@ export class FleetUsageAccumulator {
|
|
|
25
25
|
cells = new Map(); // key = principal <NUL> model
|
|
26
26
|
runsSeen = new Set(); // taskId per window → runs count (first brain.call of a run in this window)
|
|
27
27
|
/**
|
|
28
|
-
* 🔴 RB-368
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* 在那之前,请**不要**把这个 `?? 0` 读成「已裁定未知=0」——裁定见 budget.ts 的 #59/RB-368 块。
|
|
28
|
+
* 🔴 RB-368(core 2.3.0;registry-core 0.11.0 收口,[2103]):`d.costMicroUsd` **可缺席 = 未知**
|
|
29
|
+
* (unpriced 部署,budget.ts 如实不带键)。wire 自 0.11.0 起有缺席位(UsageEntry.costMicroUsd
|
|
30
|
+
* optional)⇒ 本处**整键透传缺席**,不再折 0 低估。cell 级累加语义与 budget.ts ModelUsageTracker
|
|
31
|
+
* 同款=**传染**(同为单 producer 累加器:已知+未知=未知);center 聚合面的「下界 + costUnknown
|
|
32
|
+
* 标记」语义在 registry-core aggregateUsage(跨 worker 审计总账层,两层判据见 [2103])。
|
|
33
|
+
* 配额轴(weightedTokens)不受影响,仍逐笔精确。
|
|
35
34
|
*/
|
|
36
35
|
record(principal, model, taskId, d) {
|
|
37
36
|
const p = principal ?? "__anonymous__"; // single-user turnkey: no principal — still meter, under a stable bucket
|
|
@@ -45,7 +44,8 @@ export class FleetUsageAccumulator {
|
|
|
45
44
|
if (cur) {
|
|
46
45
|
cur.inputTokens += d.inputTokens;
|
|
47
46
|
cur.outputTokens += d.outputTokens;
|
|
48
|
-
|
|
47
|
+
// 缺席=未知 ⇒ 传染(见上方旁注);两边都已知才相加
|
|
48
|
+
cur.costMicroUsd = cur.costMicroUsd === undefined || d.costMicroUsd === undefined ? undefined : cur.costMicroUsd + d.costMicroUsd;
|
|
49
49
|
cur.weightedTokens += d.weightedTokens ?? 0;
|
|
50
50
|
if (d.quotaWeightAtUse !== undefined)
|
|
51
51
|
cur.quotaWeightAtUse = d.quotaWeightAtUse; // 审计尾迹=最新倍率(窗口内基本恒定)
|
|
@@ -53,7 +53,7 @@ export class FleetUsageAccumulator {
|
|
|
53
53
|
cur.runs += 1;
|
|
54
54
|
}
|
|
55
55
|
else {
|
|
56
|
-
this.cells.set(key, { inputTokens: d.inputTokens, outputTokens: d.outputTokens, costMicroUsd: d.costMicroUsd
|
|
56
|
+
this.cells.set(key, { inputTokens: d.inputTokens, outputTokens: d.outputTokens, costMicroUsd: d.costMicroUsd, weightedTokens: d.weightedTokens ?? 0, quotaWeightAtUse: d.quotaWeightAtUse ?? 1, runs: firstOfRun ? 1 : 0 });
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
/** Drain the window into UsageReport entries and RESET. Empty window → []. */
|
|
@@ -61,7 +61,7 @@ export class FleetUsageAccumulator {
|
|
|
61
61
|
const out = [];
|
|
62
62
|
for (const [key, c] of this.cells) {
|
|
63
63
|
const sep = key.indexOf("\u0000");
|
|
64
|
-
out.push({ principal: key.slice(0, sep), model: key.slice(sep + 1), inputTokens: c.inputTokens, outputTokens: c.outputTokens, costMicroUsd: c.costMicroUsd, weightedTokens: c.weightedTokens, quotaWeightAtUse: c.quotaWeightAtUse, ...(c.runs > 0 ? { runs: c.runs } : {}) });
|
|
64
|
+
out.push({ principal: key.slice(0, sep), model: key.slice(sep + 1), inputTokens: c.inputTokens, outputTokens: c.outputTokens, ...(c.costMicroUsd !== undefined ? { costMicroUsd: c.costMicroUsd } : {}), weightedTokens: c.weightedTokens, quotaWeightAtUse: c.quotaWeightAtUse, ...(c.runs > 0 ? { runs: c.runs } : {}) });
|
|
65
65
|
}
|
|
66
66
|
this.cells.clear();
|
|
67
67
|
this.runsSeen.clear();
|
|
@@ -80,7 +80,7 @@ export class FleetUsageAccumulator {
|
|
|
80
80
|
if (cur) {
|
|
81
81
|
cur.inputTokens += e.inputTokens;
|
|
82
82
|
cur.outputTokens += e.outputTokens;
|
|
83
|
-
cur.costMicroUsd
|
|
83
|
+
cur.costMicroUsd = cur.costMicroUsd === undefined || e.costMicroUsd === undefined ? undefined : cur.costMicroUsd + e.costMicroUsd; // 回携未知同款传染
|
|
84
84
|
cur.weightedTokens += w;
|
|
85
85
|
if (qw !== undefined)
|
|
86
86
|
cur.quotaWeightAtUse = qw;
|
|
@@ -54,7 +54,10 @@ export const SKIPPED_ENTRY_TYPES = [
|
|
|
54
54
|
];
|
|
55
55
|
/** 单次评估送进模型的 transcript 字符上限。超出保留**尾部**(最近的对话对"条件是否已达成"更相关)。 */
|
|
56
56
|
export const BRANCH_TRANSCRIPT_MAX_CHARS = 60_000;
|
|
57
|
-
/** content(string | 片段数组)→ 可读文本。只取 text 片段;image/工具结果等非文本片段不进 transcript。
|
|
57
|
+
/** content(string | 片段数组)→ 可读文本。只取 text 片段;image/工具结果等非文本片段不进 transcript。
|
|
58
|
+
* 已登记的残余窄形(F5,2026-07-30 复审):core `toNormalizedTextBlock` 会把混进 content 的非法块
|
|
59
|
+
* 文本化成 `[normalized] {json}` 送模型,证据面这里丢弃 —— 模型可见/证据缺席方向的缺口,但触发
|
|
60
|
+
* 前提是非标准块混进 custom content(上游产生面不可达);若上游真出现该形,闭合钉/评估者误拦会先暴露。 */
|
|
58
61
|
function contentText(c) {
|
|
59
62
|
const parts = [];
|
|
60
63
|
if (typeof c === "string")
|
package/dist/trace/project.js
CHANGED
|
@@ -70,6 +70,12 @@ export function aggregateModelUsage(events) {
|
|
|
70
70
|
continue;
|
|
71
71
|
for (const [model, d] of Object.entries(usage)) {
|
|
72
72
|
any = true;
|
|
73
|
+
// F3(2026-07-30 复审):null/非对象行的守卫必须在任何取值**之前**——原来它排在 `d.inputTokens`
|
|
74
|
+
// 之后,对唯一能判别的形(null)先抛,守卫不可达;坏行按整行 0 折(#59 同口径),cost 记未知。
|
|
75
|
+
if (d === null || typeof d !== "object") {
|
|
76
|
+
costUnknown.add(model);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
73
79
|
const cur = total[model] ?? { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0, costMicroUsd: 0 };
|
|
74
80
|
cur.inputTokens += num(d.inputTokens);
|
|
75
81
|
cur.outputTokens += num(d.outputTokens);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.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
|
},
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@sema-agent/core": "^2.3.0",
|
|
57
|
-
"@sema-agent/registry-core": "^0.
|
|
57
|
+
"@sema-agent/registry-core": "^0.11.0",
|
|
58
58
|
"e2b": "^2.28.0",
|
|
59
59
|
"libsodium-wrappers": "^0.8.4",
|
|
60
60
|
"mysql2": "^3.22.4",
|