@sema-agent/server 7.71.0 → 7.73.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.
- package/README.md +1 -1
- package/USAGE.md +12 -1
- package/dist/approval-card.d.ts +16 -17
- package/dist/approval-card.js +0 -9
- package/dist/boot/config-center.d.ts +6 -1
- package/dist/boot/config-center.js +3 -1
- package/dist/boot/memory-boundary.d.ts +27 -5
- package/dist/boot/memory-boundary.js +6 -6
- package/dist/boot/memory-consolidation.js +2 -1
- package/dist/boot/runner-deps.d.ts +32 -16
- package/dist/boot/runner-deps.js +3 -1
- package/dist/boot/stores.js +6 -4
- package/dist/boot/unpriced-ceiling-verdict.d.ts +15 -0
- package/dist/boot/unpriced-ceiling-verdict.js +39 -0
- package/dist/brain.js +2 -9
- package/dist/budget.d.ts +21 -2
- package/dist/budget.js +3 -3
- package/dist/capabilities/tool-defer.d.ts +18 -12
- package/dist/config-catalog.js +12 -12
- package/dist/config-center/apply-effective.js +2 -4
- package/dist/config-center/facade.d.ts +1 -1
- package/dist/config-center/restart-signal.js +2 -2
- package/dist/config-center/skills-mcp.js +15 -0
- package/dist/config-types.d.ts +83 -23
- package/dist/config-types.js +19 -1
- package/dist/config.d.ts +58 -0
- package/dist/config.js +76 -22
- package/dist/http/active-run-conflict.d.ts +3 -2
- package/dist/http/durable-run-leg.d.ts +64 -0
- package/dist/http/durable-run-leg.js +63 -0
- package/dist/http/route-ctx.d.ts +14 -0
- package/dist/http/route-ctx.js +3 -0
- package/dist/http/routes/approvals-assistant.js +3 -3
- package/dist/http/routes/capabilities.js +2 -2
- package/dist/http/routes/runs.js +23 -68
- package/dist/http/routes/workflows.js +1 -0
- package/dist/http/server.js +70 -24
- package/dist/main.js +4 -1
- package/dist/memory-bundle-engine.d.ts +4 -3
- package/dist/memory-bundle-engine.js +2 -1
- package/dist/memory-incident-sink.d.ts +37 -0
- package/dist/memory-incident-sink.js +13 -0
- package/dist/memory-operator-faces.d.ts +9 -3
- package/dist/memory-operator-faces.js +4 -3
- package/dist/memory-scope.d.ts +37 -1
- package/dist/memory-scope.js +12 -2
- package/dist/observability/fail-open.d.ts +1 -1
- package/dist/observability/fail-open.js +1 -1
- package/dist/observability/metrics.js +1 -1
- package/dist/observability/tool-trace.d.ts +18 -1
- package/dist/observability/tool-trace.js +4 -3
- package/dist/parked-decide.js +3 -2
- package/dist/plugins/e2b-orphan-reclaim.d.ts +4 -4
- package/dist/plugins/e2b-orphan-reclaim.js +18 -20
- package/dist/plugins/file-run-store.js +1 -0
- package/dist/plugins/memory-run-store.js +1 -0
- package/dist/plugins/run-store-sql.d.ts +5 -2
- package/dist/plugins/run-store-sql.js +5 -3
- package/dist/plugins/store-contracts.d.ts +41 -0
- package/dist/plugins/store-contracts.js +3 -2
- package/dist/run-cancel-context.js +1 -1
- package/dist/run-local.js +19 -8
- package/dist/runs.d.ts +16 -2
- package/dist/runs.js +2 -1
- package/dist/runtime-caps-resolver.js +5 -3
- package/dist/spec-fields.d.ts +4 -2
- package/dist/task-a2a.js +3 -2
- package/dist/task-mcp.js +3 -2
- package/dist/tool-approval.d.ts +26 -21
- package/dist/tool-approval.js +2 -2
- package/dist/trace/core-keyset-guard.d.ts +17 -5
- package/dist/trace/project.d.ts +55 -0
- package/dist/trace/project.js +45 -3
- package/dist/usage-analytics.d.ts +20 -2
- package/dist/usage-analytics.js +9 -1
- package/dist/wire-name-bound.d.ts +14 -0
- package/dist/wire-name-bound.js +13 -0
- package/package.json +2 -2
package/dist/runs.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defaultTaskRegistry, type CascadeConfig, type CheckpointToken, type Runner, type SubagentSteerHandle, type TaskResult, type TaskSpec, type TaskStream, type TerminalCause } from "@sema-agent/core";
|
|
1
|
+
import { defaultTaskRegistry, type CascadeConfig, type CheckpointToken, type RunInternals, type Runner, type SubagentSteerHandle, type TaskResult, type TaskSpec, type TaskStream, type TerminalCause } from "@sema-agent/core";
|
|
2
2
|
import type { SendUserFileEmitter } from "./capabilities/send-user-file-tool.js";
|
|
3
3
|
import type { RunStore } from "./plugins/store-backend.js";
|
|
4
4
|
import type { Metrics } from "./observability/metrics.js";
|
|
@@ -282,7 +282,21 @@ pendingEngineNotices?: readonly {
|
|
|
282
282
|
message: string;
|
|
283
283
|
detail?: Record<string, unknown>;
|
|
284
284
|
sessionId?: unknown;
|
|
285
|
-
}[]
|
|
285
|
+
}[],
|
|
286
|
+
/**
|
|
287
|
+
* 🔴 **S-218:部署方铸的 TRUSTED run internals**(今天唯一成员 `workflowParkedResume`)。
|
|
288
|
+
*
|
|
289
|
+
* 它**不是** `TaskSpec` 字段、不是工具参数、不进请求体 —— 模型永远不能自己决定一次审批。铸点只有
|
|
290
|
+
* 一个:`/decide` 的 workflow 第三条车道(判据属主 = `parked-decide.ts` 的 `planWorkflowParkedDecide`
|
|
291
|
+
* 顶注 + `http/durable-run-leg.ts` 的 `TrustedRunInternals`)。本腿只负责把它摊进**下面那只**共享
|
|
292
|
+
* 供给座席,core 的 `prepareTask` 据它给 Workflow 工具挂 `parkedResume` dep。
|
|
293
|
+
*
|
|
294
|
+
* 位置在座席对象的**最后**:座席里那几位(onActivity/onForwardEvent/onTaskNotification/onSubagentSpawn)
|
|
295
|
+
* 是本腿自己的执行面供给,调用方无权覆盖它们 —— 真要撞名,撞的也只能是本腿自己新加的位,而那时
|
|
296
|
+
* `TrustedRunInternals` 的白名单会在编译期先红一次(它只开部署方可以决定的那一格)。
|
|
297
|
+
* 缺席 ⇒ 座席与本位存在之前逐字相同。
|
|
298
|
+
*/
|
|
299
|
+
trustedInternals?: Pick<RunInternals, "workflowParkedResume">): Promise<void>;
|
|
286
300
|
/** How often a running instance refreshes its run's updated_at (liveness, independent of events).
|
|
287
301
|
* Must stay strictly below `runStaleSec` (asserted at startup AND on every hot config candidate) or the
|
|
288
302
|
* reaper would race live runs. [ref]:数值的单源是 `config-invariants.ts`(那条不变量的属主),两个消费面
|
package/dist/runs.js
CHANGED
|
@@ -160,7 +160,7 @@ export function evictIfConflict(runner, sessionId, result) {
|
|
|
160
160
|
runner.sessions.evict?.(sessionId);
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
|
-
export async function runInBackground(runner, spec, runStore, taskId, metrics, principal, verify, cascade, instrumentDegenerate, planCacheProbe, persistThinking = false, inflight, preemptable, steerable, modelUsage, elicitation, elicitOwner, captureTurnAnchor, fleetPublisher, captureUserMessageAnchor, question, workflowCompletionInbox, subagentSteer, completionDiagLog, sendUserFile, promptManifests, approval, parkCheckpointReader, pendingEngineNotices) {
|
|
163
|
+
export async function runInBackground(runner, spec, runStore, taskId, metrics, principal, verify, cascade, instrumentDegenerate, planCacheProbe, persistThinking = false, inflight, preemptable, steerable, modelUsage, elicitation, elicitOwner, captureTurnAnchor, fleetPublisher, captureUserMessageAnchor, question, workflowCompletionInbox, subagentSteer, completionDiagLog, sendUserFile, promptManifests, approval, parkCheckpointReader, pendingEngineNotices, trustedInternals) {
|
|
164
164
|
const startedAt = Date.now();
|
|
165
165
|
metrics?.addGauge("runs_active", 1);
|
|
166
166
|
fleetPublisher?.onStart();
|
|
@@ -311,6 +311,7 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
311
311
|
},
|
|
312
312
|
}
|
|
313
313
|
: {}),
|
|
314
|
+
...(trustedInternals ?? {}),
|
|
314
315
|
};
|
|
315
316
|
const statusSeat = {
|
|
316
317
|
onStatusEvent: (e) => {
|
|
@@ -45,6 +45,8 @@ export function toCoreRuntimeCaps(ent) {
|
|
|
45
45
|
caps.allowObservers = ent.allowObservers;
|
|
46
46
|
if (typeof autoMode === "boolean")
|
|
47
47
|
caps.autoMode = autoMode;
|
|
48
|
+
if (caps.autoMode === false)
|
|
49
|
+
caps.autoModeDenySource = "org";
|
|
48
50
|
if (typeof ent.allowMemoryOptOut === "boolean")
|
|
49
51
|
caps.allowMemoryOptOut = ent.allowMemoryOptOut;
|
|
50
52
|
return Object.keys(caps).length ? caps : undefined;
|
|
@@ -142,7 +144,7 @@ export function createPrincipalEntitlementsClient(opts) {
|
|
|
142
144
|
catch {
|
|
143
145
|
e = new Error("center fetch failed with an unstringifiable rejection reason");
|
|
144
146
|
}
|
|
145
|
-
const entry = { caps: { allowWorkflows: false, allowFork: false, autoMode: false }, expiresAt: now() + denyTtlMs };
|
|
147
|
+
const entry = { caps: { allowWorkflows: false, allowFork: false, autoMode: false, autoModeDenySource: "org" }, expiresAt: now() + denyTtlMs };
|
|
146
148
|
if (!recordDeny)
|
|
147
149
|
readMintedDeny.add(entry);
|
|
148
150
|
putCache(principal, entry);
|
|
@@ -231,7 +233,7 @@ export function applyLocalAutoModeDeny(base, deny) {
|
|
|
231
233
|
if (!deny)
|
|
232
234
|
return base;
|
|
233
235
|
if (base === undefined)
|
|
234
|
-
return () => ({ autoMode: false });
|
|
235
|
-
return async (principal) => ({ ...(await base(principal)), autoMode: false });
|
|
236
|
+
return () => ({ autoMode: false, autoModeDenySource: "local" });
|
|
237
|
+
return async (principal) => ({ ...(await base(principal)), autoMode: false, autoModeDenySource: "local" });
|
|
236
238
|
}
|
|
237
239
|
//# sourceMappingURL=runtime-caps-resolver.js.map
|
package/dist/spec-fields.d.ts
CHANGED
|
@@ -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
|
|
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;
|
package/dist/task-a2a.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { resolveComplianceDenies
|
|
1
|
+
import { resolveComplianceDenies } from "@sema-agent/core";
|
|
2
|
+
import { isUsableWireName } from "./wire-name-bound.js";
|
|
2
3
|
import { HttpError } from "./security.js";
|
|
3
4
|
export const MAX_REQUEST_A2A_PEERS = 32;
|
|
4
5
|
export function a2aInjectionHonored(config) {
|
|
@@ -19,7 +20,7 @@ function normalizeA2aPeer(e) {
|
|
|
19
20
|
if (!e || typeof e !== "object")
|
|
20
21
|
return null;
|
|
21
22
|
const o = e;
|
|
22
|
-
if (
|
|
23
|
+
if (!isUsableWireName(o.name))
|
|
23
24
|
return null;
|
|
24
25
|
if (typeof o.url !== "string" || !HTTP_URL_RE.test(o.url))
|
|
25
26
|
return null;
|
package/dist/task-mcp.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { mcpInjectionDroppedNotice, resolveComplianceDenies
|
|
1
|
+
import { mcpInjectionDroppedNotice, resolveComplianceDenies } from "@sema-agent/core";
|
|
2
|
+
import { isUsableWireName } from "./wire-name-bound.js";
|
|
2
3
|
import { HttpError } from "./security.js";
|
|
3
4
|
import { CONTENT_ORIGIN_WORDS, describeBadContentOrigin, isContentOriginWord } from "./mcp-content-origin.js";
|
|
4
5
|
import { readMcpSourceLabel } from "./mcp-source-label.js";
|
|
@@ -26,7 +27,7 @@ function normalizeServer(e, noteBadOrigin) {
|
|
|
26
27
|
if (!e || typeof e !== "object")
|
|
27
28
|
return bad("entry");
|
|
28
29
|
const o = e;
|
|
29
|
-
if (
|
|
30
|
+
if (!isUsableWireName(o.name))
|
|
30
31
|
return bad("name");
|
|
31
32
|
const t = o.transport;
|
|
32
33
|
if (!t || typeof t !== "object")
|
package/dist/tool-approval.d.ts
CHANGED
|
@@ -126,11 +126,16 @@ export interface ToolApprovalFrame {
|
|
|
126
126
|
requiresRealApproval?: true;
|
|
127
127
|
/**
|
|
128
128
|
* **S-125③/[ref]**(core 7.5.0;**ADDITIVE**,`"tool_approval"` only)—— 这只 ask 的**出身**:
|
|
129
|
-
* 谁提的这一问,一个 core 闭集词(`ASK_ORIGINS` **11 员**,core 7.
|
|
130
|
-
*
|
|
129
|
+
* 谁提的这一问,一个 core 闭集词(`ASK_ORIGINS` **11 员**,core 7.14.0 现值:content_question /
|
|
130
|
+
* ancestor_marked / org_unavailable / org_rule / rule_store_unavailable / hook / ask_rule /
|
|
131
131
|
* denial_limit_fallback / shell_gate_tighten / safety_tighten / policy)。引擎在门上盖章(core d.ts:
|
|
132
132
|
* 「engine-stamped at the gate, never a policy's claim」),`AskRequest.origin` 逐字透传。
|
|
133
133
|
*
|
|
134
|
+
* ⚠️ **core 7.14.0 [ref] C2 BREAKING**:`unresolvable` → `ancestor_marked`,**无别名**。server 侧零形变
|
|
135
|
+
* (本键一直是 `string` 逐字透传),但**消费端的 switch 要改词**;7.14.0 之前 park 下来、行上存着
|
|
136
|
+
* `unresolvable` 的老记录,在 core 每一道 `isAskOrigin` 筛上自此都是非成员(投影处不回显 ⇒ 本键缺席),
|
|
137
|
+
* 而那一行的 `org` 事实不受影响。
|
|
138
|
+
*
|
|
134
139
|
* 🔴 **echo-only,零消费**:自动车道的资格判据全在 core(`classifierMayAnswer` 的闭表),server
|
|
135
140
|
* **不许**据本键自铸第二张资格表 —— 那是同一语义面两个写者(源头修复纪律),与
|
|
136
141
|
* `denialLimitFallback` 顶注那条「不据 autoDenyAfterMs 自铸第二只定时器」同一条禁令。
|
|
@@ -144,26 +149,26 @@ export interface ToolApprovalFrame {
|
|
|
144
149
|
*/
|
|
145
150
|
origin?: string;
|
|
146
151
|
/**
|
|
147
|
-
* **
|
|
148
|
-
*
|
|
149
|
-
* (`
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
* 🔴
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
* 🔴 **不枚举词表**(值形是 `
|
|
158
|
-
* core
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
152
|
+
* **[ref] C3**(core 7.14.0;**ADDITIVE**,`"tool_approval"` only)—— `origin: "rule_store_unavailable"`
|
|
153
|
+
* 的**机制判别位**:持久规则车道这一次**读不下来的是哪一半**。core 闭二词
|
|
154
|
+
* (`RULE_STORE_UNREADABLE_KINDS`):`"store"` = 接上的规则店读不了(读失败 / 超时);`"call"` = 店读到了,
|
|
155
|
+
* 但**这条命令**按人的 deny/ask 行读不出来(收紧 lexer 的 `unreadable`:展开里含规则词、引号没闭、语法
|
|
156
|
+
* 错——具体那句在 `message` 里)。`AskRequest.ruleStoreUnreadable` 逐字透传。
|
|
157
|
+
*
|
|
158
|
+
* 🔴 **在场 ⇔ `origin === "rule_store_unavailable"`**(core 顶注逐字)。两词对审批人是两件事:`store`
|
|
159
|
+
* 指向「去看规则店 / 网络」,`call` 指向「这条命令的写法让规则判不了」——一个 origin 词对这两件事同形。
|
|
160
|
+
* 缺席 = 车道把店和这条命令都读通了,**或**本部署没接规则车道;消费端禁把缺席读成对规则店健康的断言。
|
|
161
|
+
*
|
|
162
|
+
* 🔴 **不枚举词表**(值形是 `string` 而不是本仓自铸的联合):词表单一属主在 core
|
|
163
|
+
* (`isRuleStoreUnreadable` 是它的成员判),抄一份会把 core 加的新词吞成缺席 —— 与 {@link origin} 逐字同规。
|
|
164
|
+
*
|
|
165
|
+
* 🔴 **echo-only,零消费**:策略自声明的值在 core 的**唯一**盖章点就被抹掉了,server 不重算、不再筛第二遍,
|
|
166
|
+
* 更不许据本键自铸第二张车道资格表 —— 同 `origin` / `denialLimitFallback` 两条顶注的同一条禁令。
|
|
167
|
+
*
|
|
168
|
+
* ⚰️ 本键的前任 `classifierUnavailable`(S-185 / [ref])随 core 7.14.0 [ref] **整族退役**:引擎那份事实改骑
|
|
169
|
+
* `GateDisposition.denied.cause`(`tool_end.gate` / `permissionDenied.gate`),ask 面自此没有这一位。
|
|
163
170
|
*/
|
|
164
|
-
|
|
165
|
-
cause: string;
|
|
166
|
-
};
|
|
171
|
+
ruleStoreUnreadable?: string;
|
|
167
172
|
/**
|
|
168
173
|
* **E-14**([ref]② Trojan Source 族;**ADDITIVE**,`"tool_approval"` only)—— 这只 ask 的**工具输入**
|
|
169
174
|
* (`AskRequest.args`)里含 bidi 控制符(LRM/RLM、嵌入/覆写、隔离符;字符类属主 `text-bidi.ts`)。
|
package/dist/tool-approval.js
CHANGED
|
@@ -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,
|
|
11
|
+
import { ApprovalCardEnvelopeSchema, MAX_RULE_OFFERS, buildApprovalCard, buildApprovalCardEnvelope, buildApprovalRequestFrame, buildRevokeFrame, readDenialLimitFallback, 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,7 +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
|
-
...(
|
|
847
|
+
...(typeof req.ruleStoreUnreadable === "string" && req.ruleStoreUnreadable.length > 0 ? { ruleStoreUnreadable: req.ruleStoreUnreadable } : {}),
|
|
848
848
|
...((c) => (c !== undefined ? { probeCause: c } : {}))(readProbeCause(req)),
|
|
849
849
|
...((c) => (c !== undefined ? { ruleEvidence: c } : {}))(readRuleEvidence(req)),
|
|
850
850
|
...(bounded.omitted ? { argsOmitted: true } : { args: bounded.args }),
|
|
@@ -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, 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):本仓「词表闭集,未处置成员=编译红」的钉法只许有**一个**形 ——
|
|
@@ -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" | "
|
|
46
|
+
type AskProjected = "toolName" | "toolCallId" | "args" | "message" | "sourceTaskId" | "fromSubagent" | "sourceAgentName" | "delegation" | "ruleOffers" | "ruleOffersAbsence" | "persistedRuleShadowed" | "probeCause" | "ruleEvidence" | "requiresRealApproval" | "denialLimitFallback" | "origin" | "ruleStoreUnreadable";
|
|
47
47
|
type AskExcluded = "preview" | "principal" | "riskAxes" | "boundInputHash" | "isDelegatedChild" | "probeReason" | "hasBidiControls" | "previewWithheld" | "execCwd";
|
|
48
48
|
type _GuardAsk = AssertAllKeysHandled<Exclude<keyof AskRequest, AskProjected | AskExcluded>>;
|
|
49
49
|
type _GuardAskReverse = AssertAllKeysHandled<Exclude<AskProjected | AskExcluded, keyof AskRequest>>;
|
|
@@ -103,7 +103,7 @@ type _GuardWiringRulesReverse = AssertAllKeysHandled<Exclude<WiringRulesHandled,
|
|
|
103
103
|
type WiringModelGateHandled = "class" | "removed" | "restore";
|
|
104
104
|
type _GuardWiringModelGate = AssertAllKeysHandled<Exclude<keyof WiringSection<"modelGate">, WiringModelGateHandled>>;
|
|
105
105
|
type _GuardWiringModelGateReverse = AssertAllKeysHandled<Exclude<WiringModelGateHandled, keyof WiringSection<"modelGate">>>;
|
|
106
|
-
type WiringAutoModeHandled = "armed" | "reason";
|
|
106
|
+
type WiringAutoModeHandled = "armed" | "reason" | "deniedSource";
|
|
107
107
|
type _GuardWiringAutoMode = AssertAllKeysHandled<Exclude<keyof WiringSection<"autoMode">, WiringAutoModeHandled>>;
|
|
108
108
|
type _GuardWiringAutoModeReverse = AssertAllKeysHandled<Exclude<WiringAutoModeHandled, keyof WiringSection<"autoMode">>>;
|
|
109
109
|
type WiringGovernanceHandled = "audience" | "lockedConfig" | "compliance" | "memoryAdmission" | "retention";
|
|
@@ -117,7 +117,7 @@ type _GuardPermissionTraceReverse = AssertAllKeysHandled<Exclude<PermissionTrace
|
|
|
117
117
|
/** `T` 非 `never` 时收敛到 `never`(空集 ⇒ 残留 `"EMPTY"` ⇒ tsc 红)。 */
|
|
118
118
|
type AssertNonEmpty<T> = [T] extends [never] ? "EMPTY" : never;
|
|
119
119
|
type _GuardPermissionTraceNonEmpty = AssertAllKeysHandled<AssertNonEmpty<PermissionTraceKind>>;
|
|
120
|
-
type SummaryProjected = "sessionId" | "scope" | "createdAt" | "gateKind" | "severity" | "spentMicroUsd" | "deadline" | "hasBidiControls" | "requiresRealApproval" | "denialLimitFallback" | "origin" | "
|
|
120
|
+
type SummaryProjected = "sessionId" | "scope" | "createdAt" | "gateKind" | "severity" | "spentMicroUsd" | "deadline" | "hasBidiControls" | "requiresRealApproval" | "denialLimitFallback" | "origin" | "ruleStoreUnreadable";
|
|
121
121
|
type SummaryExcluded = "token" | "toolInput" | "toolName" | "toolCallId" | "preview" | "principal" | "sourceTaskId" | "contentKind" | "restoreMode" | "checkpointId" | "previewWithheld";
|
|
122
122
|
type _GuardInboxSummary = AssertAllKeysHandled<Exclude<keyof CheckpointSummary, SummaryProjected | SummaryExcluded>>;
|
|
123
123
|
type _GuardInboxSummaryReverse = AssertAllKeysHandled<Exclude<SummaryProjected | SummaryExcluded, keyof CheckpointSummary>>;
|
|
@@ -138,12 +138,20 @@ type SettlementWhoKeys = Settlement["who"] extends infer W ? (W extends object ?
|
|
|
138
138
|
type GateOutcomeProjected = "disposition" | "settlement" | "origin";
|
|
139
139
|
type _GuardGateOutcome = AssertAllKeysHandled<Exclude<keyof GateOutcome, GateOutcomeProjected>>;
|
|
140
140
|
type _GuardGateOutcomeReverse = AssertAllKeysHandled<Exclude<GateOutcomeProjected, keyof GateOutcome>>;
|
|
141
|
+
type GateDispositionKeys = GateDisposition extends infer D ? (D extends object ? keyof D : never) : never;
|
|
142
|
+
type GateDispositionProjected = "kind" | "deniedBy" | "cause";
|
|
143
|
+
type _GuardGateDisposition = AssertAllKeysHandled<Exclude<GateDispositionKeys, GateDispositionProjected>>;
|
|
144
|
+
type _GuardGateDispositionReverse = AssertAllKeysHandled<Exclude<GateDispositionProjected, GateDispositionKeys>>;
|
|
141
145
|
type SettlementProjected = "kind" | "who" | "when" | "note";
|
|
142
146
|
type _GuardSettlement = AssertAllKeysHandled<Exclude<SettlementKeys, SettlementProjected>>;
|
|
143
147
|
type _GuardSettlementReverse = AssertAllKeysHandled<Exclude<SettlementProjected, SettlementKeys>>;
|
|
144
148
|
type SettlementWhoProjected = "party" | "approver" | "window";
|
|
145
149
|
type _GuardSettlementWho = AssertAllKeysHandled<Exclude<SettlementWhoKeys, SettlementWhoProjected>>;
|
|
146
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>>;
|
|
147
155
|
export type CoreKeysetGuards = [
|
|
148
156
|
_GuardNotification,
|
|
149
157
|
_GuardNotificationReverse,
|
|
@@ -208,10 +216,14 @@ export type CoreKeysetGuards = [
|
|
|
208
216
|
_GuardPausedCauseReverse,
|
|
209
217
|
_GuardGateOutcome,
|
|
210
218
|
_GuardGateOutcomeReverse,
|
|
219
|
+
_GuardGateDisposition,
|
|
220
|
+
_GuardGateDispositionReverse,
|
|
211
221
|
_GuardSettlement,
|
|
212
222
|
_GuardSettlementReverse,
|
|
213
223
|
_GuardSettlementWho,
|
|
214
|
-
_GuardSettlementWhoReverse
|
|
224
|
+
_GuardSettlementWhoReverse,
|
|
225
|
+
_GuardWorkflowRun,
|
|
226
|
+
_GuardWorkflowRunReverse
|
|
215
227
|
];
|
|
216
228
|
export {};
|
|
217
229
|
//# sourceMappingURL=core-keyset-guard.d.ts.map
|
package/dist/trace/project.d.ts
CHANGED
|
@@ -119,7 +119,62 @@ 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;
|
|
138
|
+
/**
|
|
139
|
+
* 🔴 **耐久行的**门记录读口(7.72.0;`screenedGate` 的读腿孪生)—— 先把本仓自己写过的**旧拼法**读成它
|
|
140
|
+
* 今天的名字({@link RETIRED_ASK_ORIGIN_SPELLINGS}),再走与写腿**同一只**筛子。
|
|
141
|
+
*
|
|
142
|
+
* 为什么读腿要多这一步而写腿不要:读到的字节可能是**本仓上一个版本**写下的(账本回放、park 行的
|
|
143
|
+
* `resolvedOutcome`),而 core 7.14.0 [ref] C2 把 `ASK_ORIGINS` 的一个词改了名 —— 不认旧拼法,那些行就整条
|
|
144
|
+
* withhold,连 `disposition` / `settlement`(谁拒的、人怎么结的)一起在回放面上消失。写腿面对的则是**当下**
|
|
145
|
+
* 引擎铸的记录,它铸不出退役词,所以那里出现退役词 = producer 契约漂了 = 要 report + withhold 的事。
|
|
146
|
+
*
|
|
147
|
+
* 不改原对象(调用方与账本共享引用):归一时换一只信封,原记录一个字节不动。
|
|
148
|
+
*/
|
|
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;
|
|
123
178
|
/** The durable `tool_end` payload (shared by both append sites). E1: the model-facing `output` is UNTRUSTED RAW
|
|
124
179
|
* from core (file/shell/API bodies) — core only SIZE-bounds it (`truncated`), REDACTION is ours (same contract as
|
|
125
180
|
* `tool_start.args`); never re-fed to a model. E2: identity. Absent `output` ⇒ the tool produced no content body.
|
package/dist/trace/project.js
CHANGED
|
@@ -86,7 +86,19 @@ export function toolStartEventData(ev) {
|
|
|
86
86
|
return { toolCallId: ev.toolCallId, toolName: ev.toolName, ...(ev.label !== undefined ? { label: ev.label } : {}), args: redactDeep(ev.args), ...identityFields(ev) };
|
|
87
87
|
}
|
|
88
88
|
const SETTLEMENT_NOTE_MAX = 500;
|
|
89
|
+
const RETIRED_ASK_ORIGIN_SPELLINGS = {
|
|
90
|
+
unresolvable: "ancestor_marked",
|
|
91
|
+
};
|
|
89
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) {
|
|
90
102
|
if (v === null || typeof v !== "object")
|
|
91
103
|
return undefined;
|
|
92
104
|
const g = v;
|
|
@@ -96,6 +108,7 @@ export function screenedGate(v) {
|
|
|
96
108
|
return undefined;
|
|
97
109
|
}
|
|
98
110
|
const shapeDefect = (d.kind === "denied" && typeof d.deniedBy !== "string" && "disposition.deniedBy is not a string") ||
|
|
111
|
+
(d.kind === "denied" && d.cause !== undefined && typeof d.cause !== "string" && "disposition.cause is not a string") ||
|
|
99
112
|
(g.settlement !== undefined && (g.settlement === null || typeof g.settlement !== "object") && "settlement is not an object") ||
|
|
100
113
|
(g.settlement !== undefined && g.settlement !== null && typeof g.settlement.kind !== "string" && "settlement.kind is not a string") ||
|
|
101
114
|
(g.origin !== undefined && typeof g.origin !== "string" && "origin is not a string") ||
|
|
@@ -115,11 +128,37 @@ export function screenedGate(v) {
|
|
|
115
128
|
return undefined;
|
|
116
129
|
}
|
|
117
130
|
return {
|
|
118
|
-
disposition: d.kind === "denied"
|
|
131
|
+
disposition: d.kind === "denied"
|
|
132
|
+
? { kind: "denied", deniedBy: d.deniedBy, ...(d.cause === undefined ? {} : { cause: d.cause }) }
|
|
133
|
+
: { kind: "allowed" },
|
|
119
134
|
...(settlement === undefined ? {} : { settlement }),
|
|
120
135
|
...(g.origin === undefined ? {} : { origin: g.origin }),
|
|
121
136
|
};
|
|
122
137
|
}
|
|
138
|
+
export function screenedStoredGate(v) {
|
|
139
|
+
if (v === null || typeof v !== "object")
|
|
140
|
+
return undefined;
|
|
141
|
+
const g = v;
|
|
142
|
+
const renamed = typeof g.origin === "string" ? RETIRED_ASK_ORIGIN_SPELLINGS[g.origin] : undefined;
|
|
143
|
+
return screenedGate(renamed === undefined ? g : { ...g, origin: renamed });
|
|
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
|
+
}
|
|
123
162
|
const SETTLEMENT_PARTIES = new Set(["person", "engine", "host", "none"]);
|
|
124
163
|
function projectSettlement(st) {
|
|
125
164
|
const whoV = st.who;
|
|
@@ -329,7 +368,10 @@ export function wiringManifestEventData(ev) {
|
|
|
329
368
|
const reason = str(autoIn.reason);
|
|
330
369
|
if (armed === undefined || reason === undefined)
|
|
331
370
|
return undefined;
|
|
332
|
-
|
|
371
|
+
if (armed !== (reason === "armed"))
|
|
372
|
+
return undefined;
|
|
373
|
+
const deniedSource = str(autoIn.deniedSource);
|
|
374
|
+
return { armed, reason, ...(deniedSource === undefined ? {} : { deniedSource }) };
|
|
333
375
|
})();
|
|
334
376
|
const toolsIn = m.tools;
|
|
335
377
|
const tools = toolsIn === undefined ? undefined : Value.Check(ToolRoster, toolsIn) ? toolsIn : (recordFailOpen("server.trace.tool-roster-malformed", "wiring_manifest.tools did not fit core ToolRoster"), undefined);
|
|
@@ -514,7 +556,7 @@ export function toolCallFieldsOf(d) {
|
|
|
514
556
|
};
|
|
515
557
|
}
|
|
516
558
|
export function toolResultFieldsOf(d) {
|
|
517
|
-
const gate = d.gate === undefined ? undefined :
|
|
559
|
+
const gate = d.gate === undefined ? undefined : screenedStoredGate(d.gate);
|
|
518
560
|
return {
|
|
519
561
|
callId: String(d.toolCallId ?? ""),
|
|
520
562
|
...(typeof d.label === "string" ? { label: d.label } : {}),
|
|
@@ -26,6 +26,11 @@ export interface UsageRow {
|
|
|
26
26
|
stats?: {
|
|
27
27
|
tokens?: number;
|
|
28
28
|
modelUsage?: Record<string, UsageModelEntry>;
|
|
29
|
+
/** core 7.14.0 [ref] C-b(`TaskResult.stats.usageMissing`):这一行的用量数字是**下界**不是测量值
|
|
30
|
+
* —— 至少有一轮模型没报用量,或整条结果是宿主/编排车道自铸的(一个模型轮都没跑过)。
|
|
31
|
+
* `true` 或缺席,**永不 `false`**;缺席 ⇔ 每轮都报了用量。fold 侧翻成既有的
|
|
32
|
+
* {@link UsageTotals.estimated}(见 `foldRow`),**不开第二条不精确轴**。 */
|
|
33
|
+
usageMissing?: true;
|
|
29
34
|
};
|
|
30
35
|
}
|
|
31
36
|
/**
|
|
@@ -57,17 +62,30 @@ export interface UsageTotals {
|
|
|
57
62
|
* ②有 per-model echo 行**缺数值键**(该键按 0 计入,总量偏低;成本键缺席时尤其:少算 ≠ 免费);
|
|
58
63
|
* ③(S10/V2-⑤)有行的 {@link UsageModelEntry.usageBasis} 缺席或非本读端认识的分量制——存量行某族
|
|
59
64
|
* 历史上把 cache 计入 inputTokens,tokensIn 求和会**双算**,口径不可分辨。
|
|
60
|
-
*
|
|
65
|
+
* ④(7.72.0 / core 7.14.0 [ref] C-b)有行自陈 `stats.usageMissing` —— 那一行的数字是**下界**:至少一轮
|
|
66
|
+
* 模型没报用量,或整条结果是宿主自铸的零结果(取消打断 / 零执行的治理拒绝)。`tokens: 0` 在那种行上读作
|
|
67
|
+
* 「未知」而不是「免费」。
|
|
68
|
+
* 四者都只表达「别把这个总数当精确值」,消费端一视同仁。 */
|
|
61
69
|
estimated: boolean;
|
|
62
70
|
}
|
|
63
71
|
/** GET /v1/usage/summary — 窗内总量。 */
|
|
64
72
|
export declare function usageSummary(rows: UsageRow[]): UsageTotals;
|
|
65
73
|
export type UsageMetric = "tasks" | "tokensIn" | "tokensOut" | "costUsd";
|
|
66
74
|
export type UsageGranularity = "hour" | "day";
|
|
67
|
-
/**
|
|
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
|
+
*/
|
|
68
85
|
export declare function usageSeries(rows: UsageRow[], metric: UsageMetric, granularity: UsageGranularity): Array<{
|
|
69
86
|
t: string;
|
|
70
87
|
v: number;
|
|
88
|
+
estimated: boolean;
|
|
71
89
|
}>;
|
|
72
90
|
export type UsageDimension = "principal" | "model";
|
|
73
91
|
/** GET /v1/usage/breakdown — 按维度分桶。dimension=model 时按 per-model echo 展开(一行可贡献多个 model 桶;
|
package/dist/usage-analytics.js
CHANGED
|
@@ -17,8 +17,13 @@ function foldModelEntry(t, d) {
|
|
|
17
17
|
if (d.usageBasis !== "uncached-components-v1")
|
|
18
18
|
t.estimated = true;
|
|
19
19
|
}
|
|
20
|
+
function markRowLowerBound(t, row) {
|
|
21
|
+
if (row.stats?.usageMissing === true)
|
|
22
|
+
t.estimated = true;
|
|
23
|
+
}
|
|
20
24
|
function foldRow(t, row) {
|
|
21
25
|
t.tasks += 1;
|
|
26
|
+
markRowLowerBound(t, row);
|
|
22
27
|
const mu = row.stats?.modelUsage;
|
|
23
28
|
if (mu && Object.keys(mu).length > 0) {
|
|
24
29
|
for (const d of Object.values(mu))
|
|
@@ -49,7 +54,7 @@ export function usageSeries(rows, metric, granularity) {
|
|
|
49
54
|
}
|
|
50
55
|
return [...buckets.entries()]
|
|
51
56
|
.sort((a, b) => a[0] - b[0])
|
|
52
|
-
.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 }));
|
|
53
58
|
}
|
|
54
59
|
export function usageBreakdown(rows, dimension) {
|
|
55
60
|
const buckets = new Map();
|
|
@@ -70,6 +75,7 @@ export function usageBreakdown(rows, dimension) {
|
|
|
70
75
|
const t = bucket(model);
|
|
71
76
|
t.tasks += 1;
|
|
72
77
|
foldModelEntry(t, d);
|
|
78
|
+
markRowLowerBound(t, r);
|
|
73
79
|
}
|
|
74
80
|
}
|
|
75
81
|
else {
|
|
@@ -92,6 +98,8 @@ export function projectUsageStats(result) {
|
|
|
92
98
|
const mu = stats.modelUsage;
|
|
93
99
|
if (mu && typeof mu === "object" && !Array.isArray(mu))
|
|
94
100
|
out.modelUsage = mu;
|
|
101
|
+
if (stats.usageMissing === true)
|
|
102
|
+
out.usageMissing = true;
|
|
95
103
|
return out;
|
|
96
104
|
}
|
|
97
105
|
catch {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 这个申报名能用吗 —— 四个收口共用的**那一只**谓词。
|
|
3
|
+
*
|
|
4
|
+
* 严判:非串、空串、超 `TOOL_WIRE_NAME_MAX_CHARS` 一律不可用。本层不做截断/规范化 —— 截短一个名字
|
|
5
|
+
* 就是**换一个身份**(core 自己 7.13.0 起正是为此把截断改成拒),而被换掉身份的那台 server 上挂的
|
|
6
|
+
* allowTools / toolFaces 收窄声明会一起对不上号。
|
|
7
|
+
*/
|
|
8
|
+
export declare function isUsableWireName(v: unknown): v is string;
|
|
9
|
+
/**
|
|
10
|
+
* 坏名的**可打印**摘要(进 warn 元数据)——中和 + 截长,绝不把任意长度的申报串原样回显进日志。
|
|
11
|
+
* 长度如实带上:运维要的是「我那个名字长了多少」,不是一屏乱码。
|
|
12
|
+
*/
|
|
13
|
+
export declare function describeBadWireName(v: unknown): string;
|
|
14
|
+
//# sourceMappingURL=wire-name-bound.d.ts.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { TOOL_WIRE_NAME_MAX_CHARS } from "@sema-agent/core";
|
|
2
|
+
export function isUsableWireName(v) {
|
|
3
|
+
return typeof v === "string" && v.length > 0 && v.length <= TOOL_WIRE_NAME_MAX_CHARS;
|
|
4
|
+
}
|
|
5
|
+
export function describeBadWireName(v) {
|
|
6
|
+
if (typeof v !== "string")
|
|
7
|
+
return v === null ? "null" : Array.isArray(v) ? "array" : typeof v;
|
|
8
|
+
if (v.length === 0)
|
|
9
|
+
return "empty";
|
|
10
|
+
const head = v.length > 32 ? `${JSON.stringify(v.slice(0, 32))}…` : JSON.stringify(v);
|
|
11
|
+
return `${head} (${v.length} chars > ${TOOL_WIRE_NAME_MAX_CHARS})`;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=wire-name-bound.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.73.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": "7.
|
|
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",
|