@sema-agent/server 7.144.0 → 7.145.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/MIGRATION.md +129 -0
- package/README.md +3 -0
- package/README.zh-CN.md +1 -0
- package/USAGE.md +16 -8
- package/dist/audit.d.ts +2 -21
- package/dist/audit.js +0 -9
- package/dist/boot/session-faces.d.ts +1 -1
- package/dist/boot/session-faces.js +3 -3
- package/dist/boot/stage-09-leader.d.ts +1 -1
- package/dist/boot/stage-10-http-server.d.ts +1 -1
- package/dist/boot/stage-10-http-server.js +2 -2
- package/dist/config-d-migration.d.ts +3 -2
- package/dist/fleet/fleet-bus.d.ts +13 -3
- package/dist/fleet/fleet-bus.js +17 -3
- package/dist/http/admission.js +2 -1
- package/dist/http/checkpoint-ctx.d.ts +1 -0
- package/dist/http/checkpoint-ctx.js +1 -0
- package/dist/http/durable-run-leg.js +7 -6
- package/dist/http/resume-legs.js +5 -3
- package/dist/http/route-ctx.d.ts +15 -0
- package/dist/http/routes/approvals-assistant.d.ts +20 -1
- package/dist/http/routes/approvals-assistant.js +27 -6
- package/dist/http/routes/rules.d.ts +1 -1
- package/dist/http/routes/rules.js +5 -2
- package/dist/http/routes/session-sync.js +12 -0
- package/dist/http/routes/tasks.js +12 -9
- package/dist/http/run-meta.d.ts +14 -7
- package/dist/http/run-meta.js +5 -2
- package/dist/http/server.d.ts +13 -5
- package/dist/http/server.js +3 -0
- package/dist/http/submit-ctx.d.ts +12 -0
- package/dist/http/submit-ctx.js +23 -0
- package/dist/observability/fail-open.d.ts +15 -3
- package/dist/observability/fail-open.js +15 -3
- package/dist/plugins/approval-ask-store-file.d.ts +16 -2
- package/dist/plugins/approval-ask-store-file.js +21 -1
- package/dist/plugins/approval-ask-store-memory.d.ts +8 -2
- package/dist/plugins/approval-ask-store-memory.js +11 -8
- package/dist/plugins/caching-session-store.d.ts +3 -0
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +29 -11
- package/dist/plugins/checkpoint-store-sql.js +38 -16
- package/dist/plugins/file-run-store.d.ts +13 -1
- package/dist/plugins/file-run-store.js +11 -1
- package/dist/plugins/local-checkpoint-store.d.ts +14 -3
- package/dist/plugins/local-checkpoint-store.js +23 -5
- package/dist/plugins/local-session-store.d.ts +52 -16
- package/dist/plugins/local-session-store.js +47 -14
- package/dist/plugins/memory-run-store.d.ts +2 -0
- package/dist/plugins/memory-run-store.js +6 -0
- package/dist/plugins/one-time-migrations.js +2 -2
- package/dist/plugins/run-store-sql.d.ts +4 -0
- package/dist/plugins/run-store-sql.js +3 -0
- package/dist/plugins/session-store.d.ts +1 -1
- package/dist/prompt-screen.d.ts +21 -0
- package/dist/prompt-screen.js +8 -0
- package/dist/rules-consent.d.ts +63 -51
- package/dist/rules-consent.js +6 -10
- package/dist/run-acceptance.d.ts +40 -10
- package/dist/run-acceptance.js +38 -5
- package/dist/runs.js +1 -1
- package/dist/security.d.ts +10 -3
- package/dist/session-agent.d.ts +39 -0
- package/dist/session-agent.js +16 -0
- package/dist/session-error-wire.d.ts +4 -4
- package/dist/trace/model-segment.d.ts +3 -2
- package/dist/trace/model-segment.js +16 -8
- package/dist/trace/redact.d.ts +66 -2
- package/dist/trace/redact.js +220 -101
- package/dist/trace/self-minted-wire.d.ts +73 -1
- package/dist/trace/self-minted-wire.js +27 -0
- package/package.json +2 -2
- package/wire-changes/server@7.145.0.json +146 -0
package/dist/rules-consent.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type DirectWritableRuleBehavior, type RemovalLiveness } from "./permission-rule-vocab.js";
|
|
2
|
-
import { type RuleOwner, type ImportPreview, type
|
|
2
|
+
import { type RuleOwner, type ImportPreview, type ImportedSettingsLayer, type PersistedRule, type RuleBehavior, type RuleCandidate, type EffectivePermissionRule, type RemoveResult, type RuleWriteCommitted, type EditedRuleTextPrecheck, type RuleScope, type RuleOffer } from "@sema-agent/core";
|
|
3
3
|
import type { DurableRulePartitionProvider, PermissionRuleStoreProvider, RuleApprovalRecordStore } from "@sema-agent/core";
|
|
4
4
|
import { type RuleImportTicket, type RuleTicketPurpose, type RuleTicketReclaimResult, type RuleTicketRedeemResult, type RuleTicketSnapshot } from "./plugins/permission-rule-store-sql.js";
|
|
5
5
|
/**
|
|
@@ -142,11 +142,12 @@ export declare const MAX_LOCAL_IMPORT_BYTES: number;
|
|
|
142
142
|
* 救回来",而不是等下一次 prepare。运维旋钮暂不开(没有部署形要求它可调)。
|
|
143
143
|
*/
|
|
144
144
|
export declare const LOCAL_IMPORT_CLAIM_LEASE_MS = 60000;
|
|
145
|
-
/** 一条规则的 wire 身份键(**态** + 规则文本 + {@link serializeRuleScope} 的判别式串)
|
|
146
|
-
* (预览 / 兑付回执)用**同一把键**,客户端拿它把两张表 join
|
|
145
|
+
/** 一条规则的 wire 身份键(**态** + 规则文本 + {@link serializeRuleScope} 的判别式串)。local-import 的两个面
|
|
146
|
+
* (预览 / 兑付回执)用**同一把键**,客户端拿它把两张表 join 起来;cc-import 的兑付回执也是这一把(两只 redeem 口
|
|
147
|
+
* 同一张回执,见 {@link ImportOutcome}),scope 串与 `GET /v1/rules` 列举行逐字同形,对账直接按它比。
|
|
147
148
|
* 🔴 `behavior` 自 7.67.0 起是这把键的一格(core 7.9.0 [ref]:规则的身份是三元组)—— 少了它,同文本
|
|
148
149
|
* 同作用域的 deny 与 allow 两行会被本口判成 `duplicate_row`,而它们是两条不同的规则。 */
|
|
149
|
-
export interface
|
|
150
|
+
export interface ImportRuleKey {
|
|
150
151
|
behavior: RuleBehavior;
|
|
151
152
|
rule: string;
|
|
152
153
|
scope: string;
|
|
@@ -189,65 +190,75 @@ export type LocalImportRefusalCode =
|
|
|
189
190
|
/** 过了本层全部判据,却没能成为引擎的候选(= 本仓与 core 的判据分了家)。**响亮**而不是静默丢:
|
|
190
191
|
* 它意味着两侧的规则语法判据漂了,那是要人去看的事。 */
|
|
191
192
|
| "not_importable";
|
|
192
|
-
/**
|
|
193
|
-
*
|
|
194
|
-
* 🔴
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
* `
|
|
201
|
-
* `admitted:false + LocalImportRefusalCode`
|
|
202
|
-
*
|
|
203
|
-
|
|
204
|
-
export type LocalImportMemberOutcome =
|
|
193
|
+
/** 兑付回执的**成员级终态**(闭集,机读;`detail` 是给人看的那一半)。两只 redeem 口(cc-import / local-import)同一张表。
|
|
194
|
+
*
|
|
195
|
+
* 🔴 **引擎的成员拒一律落 `indeterminate`,本仓不铸 `refused`**:core 的 `RedeemedBatchMember` 拒绝臂只带一个**自由文本**
|
|
196
|
+
* `reason`,而它装的东西两类都有 —— 裁定(引擎 7.62.0 对旧导入记录里从 `/` 写起的全局规则答 `unsupported.layer_root:`;
|
|
197
|
+
* 批里的收紧没落、同批放行被扣下的 `withheld:`)与店侧成因(读不出店 / 写面抛 / OCC 用尽 —— 写面抛时那一条**可能已经落了**)。
|
|
198
|
+
* 按串去猜「这是裁定还是瞬时」正是本仓明令禁止的自造判读,所以一律 `indeterminate`(安全方向:不谎报落了,也不担保没落),
|
|
199
|
+
* `detail` 原样带引擎的话 —— 人读得到出路(例:那句 `unsupported.layer_root:` 自己说「重新 prepare,这一条会披露在 skipped」)。
|
|
200
|
+
* `refused` 留在词表里是给**带类型的**判别位到货那一天(引擎给拒绝臂一个机读的「裁定 / 瞬时」位之后,裁定那一类落 `refused`):
|
|
201
|
+
* 它进了**落盘回执的边界 schema**(`ImportOutcomeSchema`;`redeemed_outcome` 列回读同一张词表),滚动升级窗里先升的进程写下的
|
|
202
|
+
* `refused`,后升的进程读得回。⚠️ 预览面**不用**这个词:那一面的拒绝形是 `admitted:false + LocalImportRefusalCode`
|
|
203
|
+
* ({@link LocalImportPreviewMember}),两面词表**不同**。 */
|
|
204
|
+
export type ImportMemberOutcome =
|
|
205
205
|
/** 这一次真的写进店里了。 */
|
|
206
206
|
"persisted"
|
|
207
207
|
/** 等价规则**已经在店**(引擎的 `deduped`)—— 同意早就生效,这次什么都不用做。 */
|
|
208
208
|
| "no-op"
|
|
209
|
-
/**
|
|
210
|
-
* LocalImportRefusalCode,兑付面见上方登记恒折 indeterminate;留词只为旧行回读)。 */
|
|
209
|
+
/** 这条被拒了、确知没落(留给带类型判别位的词位,本版不铸 —— 见上)。 */
|
|
211
210
|
| "refused"
|
|
212
|
-
/**
|
|
213
|
-
*
|
|
211
|
+
/** **不知道落没落**:引擎在这一条上答了拒,而拒因只有自由文本。如实编,禁猜(猜"成了"会谎报一次没发生的授权,
|
|
212
|
+
* 猜"没成"会让人以为可以盲目重来,而重来可能撞上一条其实已经存在的规则 —— 对账读 `GET /v1/rules`,重来走一次新的导入,幂等)。 */
|
|
214
213
|
| "indeterminate";
|
|
215
|
-
/** `indeterminate` 的成因(
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
|
|
214
|
+
/** `indeterminate` 的成因(闭集,一词)。
|
|
215
|
+
* 「兑付走本身没走完」**不是**一个成员终态:那一形没有完整成员表,兑付不落定(放回认领、503 `state.rule_import_retry`,
|
|
216
|
+
* 同一张票重走交出完整表)—— 所以没有第二个词。 */
|
|
217
|
+
export type ImportIndeterminateCode =
|
|
218
|
+
/** 引擎在这一条上答了拒(`RedeemedBatchMember` 的 `refused` 臂),而拒因只有自由文本 ⇒ 落不了裁定,如实说"不知道"。 */
|
|
219
|
+
"store_refused";
|
|
221
220
|
/** prepare 面的一行。判别式联合:被收下的行**没有**拒因字段可读,被拒的行**必然**带拒因 ——
|
|
222
221
|
* 「admitted 却带 reason」这种矛盾态在类型上不可表达。
|
|
223
222
|
* 收下的**收紧**(deny / ask)在 prepare 当场经直写接缝落店,行带它的结局 `outcome`(`persisted` = 这次写了 / `no-op` = 等价规则已在店);
|
|
224
223
|
* 收下的**放行**没有 `outcome` —— 它的结局在 redeem 回执里(放行要同意,收紧不等同意;见 `prepareLocalImport`)。 */
|
|
225
224
|
export type LocalImportPreviewMember = {
|
|
226
|
-
key:
|
|
225
|
+
key: ImportRuleKey;
|
|
227
226
|
admitted: true;
|
|
228
227
|
} | {
|
|
229
|
-
key:
|
|
228
|
+
key: ImportRuleKey;
|
|
230
229
|
admitted: true;
|
|
231
230
|
outcome: LocalImportTighteningOutcome;
|
|
232
231
|
} | {
|
|
233
|
-
key:
|
|
232
|
+
key: ImportRuleKey;
|
|
234
233
|
admitted: false;
|
|
235
234
|
reason: LocalImportRefusalCode;
|
|
236
235
|
detail: string;
|
|
237
236
|
};
|
|
238
237
|
/** 一条收紧在 prepare 当场落店的结局(与兑付回执的 `persisted` / `no-op` 同词同义;直写接缝 `addPersistedRule` 的 `added` / `no-op`)。 */
|
|
239
238
|
export type LocalImportTighteningOutcome = "persisted" | "no-op";
|
|
240
|
-
/**
|
|
241
|
-
export interface
|
|
242
|
-
key:
|
|
243
|
-
outcome:
|
|
244
|
-
reason?:
|
|
239
|
+
/** 兑付回执的一行(两只 redeem 口同形;唯一铸点 {@link buildImportOutcomeMembers})。 */
|
|
240
|
+
export interface ImportOutcomeMember {
|
|
241
|
+
key: ImportRuleKey;
|
|
242
|
+
outcome: ImportMemberOutcome;
|
|
243
|
+
reason?: ImportIndeterminateCode;
|
|
245
244
|
detail?: string;
|
|
246
245
|
}
|
|
247
|
-
/**
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
246
|
+
/**
|
|
247
|
+
* 一次兑付的回执整只 —— **两只 redeem 口同一张**(cc-import / local-import 的 200 体都是 `{ members, rev }`,路由同一个铸点),
|
|
248
|
+
* local-import 另把它**逐字**写进票行 `redeemed_outcome`(回放同源:回放答的就是它)。
|
|
249
|
+
*
|
|
250
|
+
* 🔴 **落定律(一条,两口同读)**:兑付走完、拿到引擎的**完整成员表** ⇒ 这次兑付落定,回执逐成员交出(引擎的成员拒落
|
|
251
|
+
* `indeterminate`,见 {@link ImportMemberOutcome}),票不放回、不答 503:cc-import 一次性用掉、答 200 回执;local-import 把回执
|
|
252
|
+
* 落进票行(SETTLED)后答 200 —— 落定这一跳答不成(落定写抛 / 认领被租约接管而新持有者还没落定)⇒ 照旧答 409
|
|
253
|
+
* `conflict.rule_import_in_flight`,同票再来读到的是权威的那一份回执(那一跳不改成员结局,只决定哪一份是权威)。**没有**完整
|
|
254
|
+
* 成员表(引擎在走之前整批拒 / 走到一半抛 / confirm 输给并发写者 / 店在走之前抛)⇒ 不落定:放回认领、503
|
|
255
|
+
* `state.rule_import_retry`,同一张票重来就是重走一遍 —— 兑付按引擎的设计幂等(记录里的 dot 台账),重走交出完整表,
|
|
256
|
+
* 被打断的那一走已落的成员读 `no-op`。成员拒**不**按票自动重试:一条永久被拒的成员(旧记录里的 `unsupported.layer_root`)
|
|
257
|
+
* 若走重试臂,客户端会 503 到票过期、临期放不回 ⇒ 404,已落成员不撤、被拒成员永不落 —— 7.144.0 及更早 cc-import 口就是这一形。
|
|
258
|
+
*/
|
|
259
|
+
export interface ImportOutcome {
|
|
260
|
+
members: readonly ImportOutcomeMember[];
|
|
261
|
+
/** 这只桶在兑付结束时的 OCC 版本。 */
|
|
251
262
|
rev: number;
|
|
252
263
|
}
|
|
253
264
|
/** A7 prepare 的产物。第二臂(`ticket` 整键缺席)= **零可导入行** —— 与 cc-import 的「预览无票」臂
|
|
@@ -288,7 +299,7 @@ export type LocalImportRedeemed =
|
|
|
288
299
|
/** `replayed` = 这份终局不是本次走出来的,是从票行里逐字读回来的(⑥ 丢响应重试那条路)。 */
|
|
289
300
|
{
|
|
290
301
|
ok: true;
|
|
291
|
-
outcome:
|
|
302
|
+
outcome: ImportOutcome;
|
|
292
303
|
replayed: boolean;
|
|
293
304
|
}
|
|
294
305
|
/** 五类票拒(不存在 / 别人的 / 错车道 / 过期 / 已用过而无从回放)—— wire 面同形 404。 */
|
|
@@ -329,18 +340,19 @@ export type RuleImportPrepared = {
|
|
|
329
340
|
reason: "too-many-candidates";
|
|
330
341
|
candidates: number;
|
|
331
342
|
};
|
|
332
|
-
/** 导入 redeem 的结果。wire 口径写死(端点=http/routes/rules.ts)
|
|
333
|
-
*
|
|
334
|
-
*
|
|
335
|
-
* `state.rule_ticket_unreadable
|
|
336
|
-
|
|
343
|
+
/** 导入 redeem 的结果。wire 口径写死(端点=http/routes/rules.ts):成功 ⇒ 200 回执 `{ members, rev }`(与 local-import 口
|
|
344
|
+
* 同一张、同一个铸点;落定律见 {@link ImportOutcome});票拒五类(自造 / 别人的 / 错车道 / 过期 / 已用过)与裁定性拒绝
|
|
345
|
+
* (record-unusable / payload-mismatch)同形 404(零存在性 oracle,顶注 ①);`retryable === true` ⇒ 503
|
|
346
|
+
* `state.rule_import_retry`;`state-unreadable` ⇒ 503 `state.rule_ticket_unreadable`。分类保留只为服务端日志/诊断与
|
|
347
|
+
* 上述三分支的判据。 */
|
|
348
|
+
export type RuleImportRedeemed =
|
|
349
|
+
/** 兑付走完、拿到完整成员表 ⇒ 落定(成员里有引擎拒的也在这一臂,那几行 `indeterminate`)。 */
|
|
350
|
+
{
|
|
337
351
|
ok: true;
|
|
338
|
-
|
|
339
|
-
members: readonly RedeemedBatchMember[];
|
|
340
|
-
rev: number;
|
|
341
|
-
};
|
|
352
|
+
outcome: ImportOutcome;
|
|
342
353
|
}
|
|
343
|
-
/** `retryable` =
|
|
354
|
+
/** `retryable` = 这次失败**没有裁定任何事**、也**没有完整成员表**(store 抛错 / CAS 冲突 / 引擎走之前整批拒 / 走到一半抛),
|
|
355
|
+
* 认领已放回,属主原样重试即重走。
|
|
344
356
|
* 它与裁定性拒绝(载荷被改写、记录不存在)分家是承重的:把两者塌成一格,一次数据库抖动就会被
|
|
345
357
|
* 客户端读成「这张票永远不能用了」。⚠️ wire 面**不再**折 404:`retryable === true` ⇒ 503
|
|
346
358
|
* `state.rule_import_retry` + Retry-After(http/routes/rules.ts;走到这一步的调用方已赢下 principal
|
|
@@ -620,7 +632,7 @@ export type RuleBucketRef = string | RuleOwner;
|
|
|
620
632
|
*
|
|
621
633
|
* 🔴 三臂**刻意不塌成布尔**:「落了」「早就有了」「不知道落没落」对调用方是三种不同的处置,而把第三种
|
|
622
634
|
* 折进前两种里的任一边都是编一个结论(猜"成了"会谎报一次没发生的写,猜"没成"会让人以为可以重来)。
|
|
623
|
-
* 与导入面的成员级四态({@link
|
|
635
|
+
* 与导入面的成员级四态({@link ImportMemberOutcome})同一条纪律,词更少是因为本口只有一行。
|
|
624
636
|
*/
|
|
625
637
|
export type RuleWritten =
|
|
626
638
|
/** `persisted` = 这一次**真的往店里写了**;`no-op` = 这条身份**此前就站在店里**,本次调用**一个字都没写**
|
package/dist/rules-consent.js
CHANGED
|
@@ -15,13 +15,13 @@ export const MAX_LOCAL_IMPORT_BYTES = 256 * 1024;
|
|
|
15
15
|
export const LOCAL_IMPORT_CLAIM_LEASE_MS = 60_000;
|
|
16
16
|
const LOCAL_IMPORT_CLAIM_WAIT_MS = RULE_IMPORT_RETRY_AFTER_SEC * 1000;
|
|
17
17
|
const LOCAL_IMPORT_CLAIM_POLL_MS = 25;
|
|
18
|
-
const
|
|
18
|
+
const ImportOutcomeSchema = z
|
|
19
19
|
.object({
|
|
20
20
|
members: z.array(z
|
|
21
21
|
.object({
|
|
22
22
|
key: z.object({ behavior: z.preprocess((v) => readRowBehavior(v) ?? v, z.enum(RULE_BEHAVIORS)), rule: z.string().min(1), scope: z.string().min(1) }).strict(),
|
|
23
23
|
outcome: z.enum(["persisted", "no-op", "refused", "indeterminate"]),
|
|
24
|
-
reason: z.
|
|
24
|
+
reason: z.literal("store_refused").optional(),
|
|
25
25
|
detail: z.string().optional(),
|
|
26
26
|
})
|
|
27
27
|
.strict()),
|
|
@@ -241,7 +241,7 @@ function buildLocalImportLayers(candidates) {
|
|
|
241
241
|
return root === "" ? { layer: "userSettings", path: LOCAL_IMPORT_LAYER_PATH, readFile } : { layer: "projectSettings", path: `${LOCAL_IMPORT_LAYER_PATH}:${root}`, root, readFile };
|
|
242
242
|
});
|
|
243
243
|
}
|
|
244
|
-
function
|
|
244
|
+
function buildImportOutcomeMembers(members) {
|
|
245
245
|
return members.map((m) => {
|
|
246
246
|
const key = { behavior: m.behavior, rule: m.rule, scope: serializeRuleScope(m.scope) };
|
|
247
247
|
switch (m.status) {
|
|
@@ -449,11 +449,7 @@ export function createRuleConsentLane(stores, opts) {
|
|
|
449
449
|
if ("status" in result) {
|
|
450
450
|
return await indeterminate(result.reason);
|
|
451
451
|
}
|
|
452
|
-
|
|
453
|
-
if (refused.length > 0) {
|
|
454
|
-
return await indeterminate(`partial import: ${refused.length} member(s) refused (${refused.map((x) => x.reason).join("; ")})`);
|
|
455
|
-
}
|
|
456
|
-
return { ok: true, result };
|
|
452
|
+
return { ok: true, outcome: { members: buildImportOutcomeMembers(result.members), rev: result.rev } };
|
|
457
453
|
}
|
|
458
454
|
catch (err) {
|
|
459
455
|
return await indeterminate(err instanceof Error ? err.message : String(err));
|
|
@@ -535,7 +531,7 @@ export function createRuleConsentLane(stores, opts) {
|
|
|
535
531
|
},
|
|
536
532
|
async redeemLocalImport(principal, ticket) {
|
|
537
533
|
const readSettled = (raw) => {
|
|
538
|
-
const parsed =
|
|
534
|
+
const parsed = ImportOutcomeSchema.safeParse(raw);
|
|
539
535
|
if (!parsed.success) {
|
|
540
536
|
throw new Error(`the settled outcome recorded on this import ticket does not carry a readable shape: ${parsed.error.message}`);
|
|
541
537
|
}
|
|
@@ -609,7 +605,7 @@ export function createRuleConsentLane(stores, opts) {
|
|
|
609
605
|
if ("status" in result) {
|
|
610
606
|
return await transient(result.reason);
|
|
611
607
|
}
|
|
612
|
-
members =
|
|
608
|
+
members = buildImportOutcomeMembers(result.members);
|
|
613
609
|
rev = result.rev;
|
|
614
610
|
}
|
|
615
611
|
catch (err) {
|
package/dist/run-acceptance.d.ts
CHANGED
|
@@ -1,27 +1,44 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* **一次提交的「受理」与「交付」读法** —— 标题器只在引擎**受理**这条 run 之后起;本服务存 / 转这条 run 的目标的每一张面只取引擎**交付**的那一份
|
|
3
|
+
* (一条律,唯一属主 = 本文件)。
|
|
3
4
|
*
|
|
4
5
|
* ## 受理是哪一刻
|
|
5
6
|
* 引擎把这次提交的 objective 收进会话的那一帧:`human_input{ carrier: "objective", delivery: "applied" }`。它是第一次模型调用
|
|
6
7
|
* 之前的最后一帧;在它之前引擎能拒的一切 —— prepare 门(`config.tool_face_control` / `config.user_invoked_skill_unknown` /
|
|
7
|
-
* `config.memory_capture_unsupported` …)、第一回合前的内联图片准入(`config.image_invalid`)、部署的
|
|
8
|
-
*
|
|
8
|
+
* `config.memory_capture_unsupported` …)、第一回合前的内联图片准入(`config.image_invalid`)、部署的 prompt 屏(`prompt.submit` 丢弃 / 抛错、
|
|
9
|
+
* `classic.UserPromptSubmit` 拦截)、开跑前的预算 / 墙钟 —— 都还没让这次输入进会话。`wiring_manifest` 不是受理:它在 prepare 通过时就出了,图片准入与提示拦截
|
|
9
10
|
* 都在它之后(core `run-identity-wiring.js` 推 wiring_manifest,`run-leg.js` 才做图片准入、推 human_input、调模型)。
|
|
10
11
|
*
|
|
11
12
|
* 只回结果、不交流的腿(verify / cascade:core 在自己里面排空每条腿的流,宿主手里没有流)看不到那一帧。它们的受理证据是结果本身:
|
|
12
|
-
* 结果里跑过 turn(`stats.turns > 0`)⇒ objective 进过会话、模型答过。**token
|
|
13
|
+
* 结果里跑过 turn(`stats.turns > 0`)⇒ objective 进过会话、模型答过。**token 不是证据**:被屏拦下的 objective 不进会话,
|
|
13
14
|
* 而同一条 run 的收尾压缩可以在已有历史的会话上花 token(turns 0、tokens > 0)—— 按 token 判会把被拦下的输入送去起名。
|
|
14
15
|
* 两种证据说的是同一件事,本文件把它们收成一只闩:先到的那一个算数,只算一次。
|
|
15
16
|
*
|
|
17
|
+
* ## 交付的是哪一份(律:本服务的目标副本 = 引擎交付的那一份,屏判完之前一个字节都不存)
|
|
18
|
+
* prompt 屏(`prompt-screen.ts` 判这条腿有没有)可以改写或拦下目标:模型与会话转录只见屏后文本,调用方的原话没送达。本服务存 / 转目标的面 ——
|
|
19
|
+
* run 行预览(`objectivePreview`:`GET /v1/tasks` / 收件箱 `objective` / 运维任务视图 / 会话列表 / fleet 行名同读)、续跑输入(checkpoint ctx 体里的
|
|
20
|
+
* `objective`)、标题器取材 —— 于是只读本座交出的那一份,不读请求体:
|
|
21
|
+
* · **腿上没有屏** ⇒ 交付的就是请求原文,提交那一刻就知道({@link RunAcceptance.objectiveAtSubmit} 在场):各面在提交时照写,与没有屏这回事之前逐字同;
|
|
22
|
+
* · **腿上有屏** ⇒ 提交时什么都不写(`objectiveAtSubmit` 缺席:预览列 NULL、续跑输入标上 `promptScreened` 而 `objective` 留空、fleet 行不带名);屏判完、引擎交付时
|
|
23
|
+
* 本座把交付的那一份交给各面登记的补写口({@link RunAcceptance.onDelivered}:run 行预览、fleet 行名),持流的腿在那一帧上等补写落定再往下走。
|
|
24
|
+
* 续跑输入**不**登记补写口、一直留空,续跑腿的展示面只看它上面的标记(那一行在跑的时候还有别的写者,交付时整行重写会与它抢写;理由、代价、
|
|
25
|
+
* verify 形那份原文与留空的体记下的模型全文 `http/submit-ctx.ts`):
|
|
26
|
+
* - 受理帧不带 `rewrittenBy`(引擎:缺席 = 原样送达)⇒ 交付的 = 请求原文;
|
|
27
|
+
* - 受理帧带 `rewrittenBy`(屏改写过)⇒ 引擎今天不把屏后文本交给宿主 ⇒ **没有**可写的那一份:各面保持提交时的空,标题器不起。
|
|
28
|
+
* 引擎把屏后文本交给宿主之后,这一臂改读它 —— 读口换,律不变;
|
|
29
|
+
* - 没有受理帧(屏丢弃 / 抛错 / 受理前取消或失败)⇒ 没有交付,各面保持空;
|
|
30
|
+
* - 只回结果的腿:宿主看不到受理帧,也就分不出改写 ⇒ 有屏时没有可写的那一份(各面保持空、标题器不起);没屏时照提交时写好的。
|
|
31
|
+
* 不加第二份脱敏、不按内容猜:屏改没改由引擎的 `rewrittenBy` 说,不由本服务比字符串。
|
|
32
|
+
*
|
|
16
33
|
* ## 受理之后 / 之前
|
|
17
|
-
* · 受理 ⇒
|
|
34
|
+
* · 受理 ⇒ 有交付的那一份时标题器起一次(会话没有标题时它才真去生成;判据在标题器里,本文件不重复)。
|
|
18
35
|
* · 没受理就收场(零工作的拒、受理前取消 / 拦截)⇒ 标题器不起:被拒的输入不花一次模型调用,也不被送去起名。
|
|
19
36
|
* 这次提交在提交门铸下的会话行照旧留下(无标题、零消息),与此前同 —— 「提交没让引擎受理就收场」的会话去留是另一件事,不在本文件。
|
|
20
37
|
*
|
|
21
38
|
* ## 谁喂它
|
|
22
|
-
* 三条提交腿(同步 / 流式 / durable)各在两处喂同一只:持流的那一形把每一帧交给 {@link RunAcceptance.observe}
|
|
23
|
-
* {@link RunAcceptance.settle}
|
|
24
|
-
*
|
|
39
|
+
* 三条提交腿(同步 / 流式 / durable)各在两处喂同一只:持流的那一形把每一帧交给 {@link RunAcceptance.observe}(并等它交回的那一拍 —— 有补写时
|
|
40
|
+
* 补写落定才往下);终局落行之后调一次 {@link RunAcceptance.settle}。腿上不再有「什么时候起标题」「目标写哪一份」的判断,标题器与补写的唯一调用点是本文件的闩。
|
|
41
|
+
* 座由提交门在 `prepareSpec` 里随 spec 一起铸(`PreparedTaskSubmission.acceptance`);不经提交门的内部车道铸一只不带标题器的座,也就不起标题。
|
|
25
42
|
*
|
|
26
43
|
* ## 标题写成之后(`session_titled` 帧,契约 §4a-ttl)
|
|
27
44
|
* 标题器写成时把那一帧交回本座({@link RunAcceptanceDeps.sessionTitler} 的 `onTitled`);本座是这条 run 的流与标题器之间**唯一**的接缝:
|
|
@@ -45,21 +62,34 @@ export interface RunStreamSink {
|
|
|
45
62
|
}
|
|
46
63
|
export interface RunAcceptanceInput {
|
|
47
64
|
sessionId?: string;
|
|
65
|
+
/** 请求里的目标原文 —— 本座是它在受理之后唯一的读者(交付的那一份由它与引擎的交付帧定,见头注「交付的是哪一份」)。 */
|
|
48
66
|
objective: string;
|
|
67
|
+
/** 这条腿上有没有 prompt 屏(唯一读法 `prompt-screen.ts` 的 `promptScreenDeclared`;不经提交门的内部车道交自己负责的字,恒 `false`)。 */
|
|
68
|
+
screened: boolean;
|
|
49
69
|
/** 本 turn 真实驱动的模型 id(标题器与 turn 同链路)。 */
|
|
50
70
|
model?: string;
|
|
51
71
|
}
|
|
72
|
+
/** 登记补写口的那张面(fail-open 留痕里点名哪一面没补上)。闭集:加一张面 = 加一个词。 */
|
|
73
|
+
export type DeliveryFace = "run-preview" | "fleet-name";
|
|
52
74
|
export interface RunAcceptance {
|
|
53
|
-
/** 持流的腿逐帧调用(
|
|
75
|
+
/** 持流的腿逐帧调用(判哪一帧算受理、交付的是哪一份只在这里)。不抛;交回的那一拍在有补写时等补写落定(补写失败不抛,留痕),腿 await 它再往下。 */
|
|
54
76
|
observe(ev: {
|
|
55
77
|
type: string;
|
|
56
|
-
}): void
|
|
78
|
+
}): Promise<void>;
|
|
57
79
|
/** 终局落行之后:还没在流上见过受理帧、而结果里跑过 turn(只回结果的腿)⇒ 受理。只读 `stats.turns`。不抛、不等。 */
|
|
58
80
|
settle(result: {
|
|
59
81
|
readonly stats: {
|
|
60
82
|
readonly turns: number;
|
|
61
83
|
};
|
|
62
84
|
}): void;
|
|
85
|
+
/** 提交那一刻就知道的交付文本(腿上没有屏 ⇒ 请求原文);腿上有屏 ⇒ 缺席:各面提交时不写,交付时经 {@link onDelivered} 补。 */
|
|
86
|
+
readonly objectiveAtSubmit: string | undefined;
|
|
87
|
+
/**
|
|
88
|
+
* 一张面在提交时按 {@link objectiveAtSubmit} 写过之后,登记它的补写口:腿上有屏、引擎交付了可写的那一份时,本座以交付的文本调它一次
|
|
89
|
+
* (持流的腿在受理帧那一拍等它落定)。腿上没有屏 ⇒ 提交时已写完,永不调。补写抛错 ⇒ 不抛给腿(那张面保持提交时的空),留一次 F 类痕。
|
|
90
|
+
* 须在腿起跑之前登记(交付之后才登记的口当场补,不等)。
|
|
91
|
+
*/
|
|
92
|
+
onDelivered(face: DeliveryFace, fill: (objective: string) => Promise<void>): void;
|
|
63
93
|
/** 持活流的腿开流时挂上它的写口(一次提交至多一条活流;重挂以最后一次为准)。不挂 = 本次提交没有可写的流,标题写成的帧丢弃。 */
|
|
64
94
|
attachStream(sink: RunStreamSink): void;
|
|
65
95
|
}
|
package/dist/run-acceptance.js
CHANGED
|
@@ -1,35 +1,68 @@
|
|
|
1
|
+
import { recordFailOpen } from "./observability/fail-open.js";
|
|
2
|
+
import { seatText } from "./trace/exit-seat.js";
|
|
1
3
|
function isObjectiveApplied(ev) {
|
|
2
4
|
if (ev.type !== "human_input")
|
|
3
5
|
return false;
|
|
4
6
|
const h = ev;
|
|
5
7
|
return h.carrier === "objective" && h.delivery === "applied";
|
|
6
8
|
}
|
|
9
|
+
function rewrittenOnDelivery(ev) {
|
|
10
|
+
return ev.rewrittenBy !== undefined;
|
|
11
|
+
}
|
|
7
12
|
export function createRunAcceptance(deps, input) {
|
|
8
13
|
let accepted = false;
|
|
14
|
+
let delivered;
|
|
9
15
|
let terminalSeen = false;
|
|
10
16
|
let stream;
|
|
17
|
+
const fills = [];
|
|
11
18
|
const deliver = (frame) => {
|
|
12
19
|
if (stream === undefined || terminalSeen || !stream.reachable())
|
|
13
20
|
return;
|
|
14
21
|
stream.write(frame);
|
|
15
22
|
};
|
|
16
|
-
const
|
|
23
|
+
const runFill = async (face, fill, objective) => {
|
|
24
|
+
try {
|
|
25
|
+
await fill(objective);
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
recordFailOpen("server.objective-delivery.face-fill-failed", `face=${face} err=${seatText("operator-log-text", err instanceof Error ? err.message : String(err))}`);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const accept = (objective) => {
|
|
17
32
|
if (accepted)
|
|
18
|
-
return;
|
|
33
|
+
return Promise.resolve();
|
|
19
34
|
accepted = true;
|
|
35
|
+
delivered = objective;
|
|
36
|
+
if (objective === undefined)
|
|
37
|
+
return Promise.resolve();
|
|
20
38
|
if (input.sessionId)
|
|
21
|
-
deps.sessionTitler?.maybeTitle(input.sessionId,
|
|
39
|
+
deps.sessionTitler?.maybeTitle(input.sessionId, objective, input.model, deliver);
|
|
40
|
+
if (!input.screened)
|
|
41
|
+
return Promise.resolve();
|
|
42
|
+
return Promise.all(fills.map(({ face, fill }) => runFill(face, fill, objective))).then(() => undefined);
|
|
22
43
|
};
|
|
23
44
|
return {
|
|
45
|
+
objectiveAtSubmit: input.screened ? undefined : input.objective,
|
|
24
46
|
observe(ev) {
|
|
25
47
|
if (ev.type === "done")
|
|
26
48
|
terminalSeen = true;
|
|
27
49
|
if (!accepted && isObjectiveApplied(ev))
|
|
28
|
-
accept();
|
|
50
|
+
return accept(rewrittenOnDelivery(ev) ? undefined : input.objective);
|
|
51
|
+
return Promise.resolve();
|
|
29
52
|
},
|
|
30
53
|
settle(result) {
|
|
31
54
|
if (result.stats.turns > 0)
|
|
32
|
-
accept();
|
|
55
|
+
void accept(input.screened ? undefined : input.objective);
|
|
56
|
+
},
|
|
57
|
+
onDelivered(face, fill) {
|
|
58
|
+
if (!input.screened)
|
|
59
|
+
return;
|
|
60
|
+
if (accepted) {
|
|
61
|
+
if (delivered !== undefined)
|
|
62
|
+
void runFill(face, fill, delivered);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
fills.push({ face, fill });
|
|
33
66
|
},
|
|
34
67
|
attachStream(sink) {
|
|
35
68
|
stream = sink;
|
package/dist/runs.js
CHANGED
|
@@ -486,7 +486,7 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
486
486
|
}
|
|
487
487
|
fleetPublisher?.onEvent(ev);
|
|
488
488
|
await userInputLedger?.observeLegEvent(stream, ev);
|
|
489
|
-
acceptance?.observe(ev);
|
|
489
|
+
await acceptance?.observe(ev);
|
|
490
490
|
await workspaceRecorder?.observe(ev);
|
|
491
491
|
await flushPromptManifest();
|
|
492
492
|
switch (ev.type) {
|
package/dist/security.d.ts
CHANGED
|
@@ -113,9 +113,12 @@ export interface SessionCaller {
|
|
|
113
113
|
* 🔴 **会话行属主门上「无主行放行」臂的唯一判据**([ref] 读面律;会话面谓词 `sessionOwnerReadable`、fork / 删除 / 同步族的存量互认臂 {@link legacyUnownedSessionOk}、
|
|
114
114
|
* 审批豁免面、notify 面的无主臂都经它,不各写一份):
|
|
115
115
|
* · 无主的**普通**会话行 ⇒ 成立(各臂照它自己的其余条件);
|
|
116
|
-
* · 无主的 **placed** 行(委派子代:属主 =
|
|
116
|
+
* · 无主的 **placed** 行(委派子代:属主 = 引擎判的委派树属主,三只持久会话店建行那一笔原样记 `placement.owner`,`null` = 根匿名;`delegated-session-owner.ts` 头注)⇒ 只对 **fleet 调用方**成立({@link SessionCaller}:dev-open 部署上的任何调用方,
|
|
117
117
|
* 或出示了 service 凭据、不报主体的调用方 —— 只配 token 的单用户部署、BFF 的系统调用)。任何具名主体(含经 BFF 代发的)与没有 service 凭据的无身份调用方都不成立:
|
|
118
|
-
*
|
|
118
|
+
* 这一行要么属于一棵无身份调用方的树(引擎交的属主是 `null`),要么是属主从没被记下的行 —— 7.144.0 之前写下的存量(7.132.x 及更早建行不记属主;7.133.0–7.143.x 按本服务当年的推断写下,
|
|
119
|
+
* 推断那一刻来源还没有属主的仍无主;SQL 两店由一次性迁移 M23 在它的窗内回填),以及 local 文件店上 7.144.x 及更早建行两笔之间崩溃留下的行(7.145.0 起建行格先、存档后,不再新生)、
|
|
120
|
+
* 同一数据根上 run-local 腿经 core 店写下的 placed 存档(local 没有回填臂)
|
|
121
|
+
* —— 后者把它当公共行,就是把别人那棵树的子代转录交给拿到 id 的人。
|
|
119
122
|
* · 有主的行 ⇒ 不在本臂。
|
|
120
123
|
*/
|
|
121
124
|
export declare function ownerlessRowOpen(cell: SessionOwnerCell, caller: SessionCaller): boolean;
|
|
@@ -184,7 +187,7 @@ export type OwnerAwareSessionStore = SessionStore & {
|
|
|
184
187
|
register?: (sessionId: string, owner: string | null) => Promise<void>;
|
|
185
188
|
/** [ref] placed 分区的元组读口(店的既有读口,一行 PK 读;`undefined` = 普通会话或无此行)。店不交它 = 不实现 placement = 没有 placed 行(无 repo 的内存店)。两个读者:
|
|
186
189
|
* ① 会话面的属主门只在属主为 NULL 时读它一次(无主的 placed 行不是公共行,`http/principal-gate.ts` 的 `sessionOwnerCellOf`);
|
|
187
|
-
* ②
|
|
190
|
+
* ② `agent` 的唯一读口 `session-agent.ts` 的 `readSessionAgent`(会话视图体顶层、运维审批队列的停驻行同读):店没有这一面 ⇒ 键缺席,读面不凭别处另铸子代身份。 */
|
|
188
191
|
placementOf?: (sessionId: string) => Promise<SessionPlacementRecord | undefined>;
|
|
189
192
|
/** E16 — enumerate the caller's sessions (owner-filtered on the session store's OWN owner column).
|
|
190
193
|
* `includeUnowned` = [ref] 窄互认第二臂的**第三条件**(`owner IS NULL`)的 SQL 承载位:置真时
|
|
@@ -260,6 +263,10 @@ export type OwnerAwareSessionStore = SessionStore & {
|
|
|
260
263
|
* Phase-B route streams batches into (`appendBatch`) then commits (`commit`, the atomic swap) / aborts. The shadow
|
|
261
264
|
* rows have NO session_meta → invisible to wake until commit writes meta LAST = the sole commit point. */
|
|
262
265
|
beginImportStaging?: (realSessionId: string, token: string) => StagingHandle;
|
|
266
|
+
/** 带戳存档的早拒口(只有 local 店有这一形:更早的版本写下的属主戳留在引擎存档头上,一次性迁移改写不了的;SQL 孪生没有 ⇒ 不交这一口,调用方按「没有带戳存档」处置)。
|
|
267
|
+
* 只读、零写、不持锁;带戳 ⇒ 抛 `StampedSessionArchiveError`(`session-error-wire.ts` 映射 409 `conflict.session_archive_stamped`),没有存档 / 匿名存档 ⇒ 放行。
|
|
268
|
+
* 这是拒绝判对「这份存档带不带戳」的**唯一**读口(fork 的源与改日志的提交也问同一只);读者:会话同步导入第一阶段对按 id 分类出的 fork / stale(没带同意)的早拒。 */
|
|
269
|
+
assertArchiveAnonymous?: (sessionId: string) => Promise<void>;
|
|
263
270
|
/** 2c session-sync P1d-β (staged-row inspection) — read the rows STAGED under a `${realSessionId}#stg-${token}` id
|
|
264
271
|
* (NO session_meta probe — `exportEntries` returns null for an unregistered id), oldest-first. The import gate is now
|
|
265
272
|
* the per-line `StreamingImportValidator` (core 1.143.0) driven during the stream, so this is no longer the
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🔴 **一只会话在委派树里的位置 —— 一个来源、一只读口、一种 wire 写法**(`agent: { id?, parentSessionId?, rootSessionId? }`)。
|
|
3
|
+
*
|
|
4
|
+
* 来源只有一个:会话行上**存下来的委派元组**(core `SessionPlacementRecord`)—— 引擎在**后台**委派子代(带耐久 agent 行、店声明了委派分区)建会话那一笔交给店、
|
|
5
|
+
* 店原样记下,首写不可变。三只持久会话店都存:SQL 两孪生在 `session_meta` 的 `placement_*` 列(`plugins/session-placement.ts` 的 `placementFromRow`),
|
|
6
|
+
* local 后端(7.141.0 起)在会话存档行头(core 文件 repo)。读口是店的 `placementOf`(一行 PK 探针;店不交它 = 不存元组)。
|
|
7
|
+
*
|
|
8
|
+
* 读者(同一只读口 {@link readSessionAgent}、同一只投影 {@link sessionAgentOf},逐值同答):
|
|
9
|
+
* · 会话视图 `GET /v1/sessions/:id` 体顶层的 `agent`(视图读才付探针;探针抛 ⇒ 视图读响亮失败,`boot/session-faces.ts`);
|
|
10
|
+
* · 运维审批队列 `GET /v1/approvals` 的停驻行(`pending[]` 的 `checkpoint` 族)与 `/v1/approvals/stream` 的 `pending` 帧:行的身份就是它那只会话
|
|
11
|
+
* (决断口 `/v1/approvals/:sessionId/decide`),行上的 `agent` = 同一只会话在视图上的 `agent`;一行读不出 ⇒ 只这一行缺键、F 类兜底计数
|
|
12
|
+
* (`http/routes/approvals-assistant.ts`)。
|
|
13
|
+
* 不另立第二只读法:fleet 行 / 后台 agent 行上的同名事实是引擎别的记录,读面不拿它们回填或改写这里的答案。
|
|
14
|
+
*
|
|
15
|
+
* 投影律(不另铸):`id` = 元组的 `handle`(耐久 agent 行的 `a…` 键,与 fleet 行的 `id`、`GET /v1/agents/roster` 的 `handle` 同一个串);`parentSessionId` /
|
|
16
|
+
* `rootSessionId` = 元组的同名格(派它的会话 / 委派树的根会话);元组缺哪一格这里就缺哪一格;元组的 `scope`(租户键)/ `placedAt` / `kind` 不上 wire。
|
|
17
|
+
* 键在场 = 这是一只委派子代的会话(元组只存了 `kind` 时是 `{}`);键缺席 = 不是 placed 行(宿主会话、同步委派的子代、`subagent_type: "fork"` 的后台子代 ——
|
|
18
|
+
* 它的会话是父会话的一只普通分叉;`DB_BACKEND=local` 到 7.140.x 停驻时拷进宿主店的子代转录,那一份是普通会话行)、这台部署的店不存元组(无 repo 的内存店
|
|
19
|
+
* 〔`DB_BACKEND=memory`〕、嵌入方自建且不声明委派分区的店),或那一读没读成 —— 消费方一律读作「这台 server 没有说」,不读作「不是子代」。
|
|
20
|
+
*/
|
|
21
|
+
import type { SessionPlacementRecord } from "@sema-agent/core";
|
|
22
|
+
/** 一只会话在委派树里的位置(wire 键 `agent` 的值形)。 */
|
|
23
|
+
export interface SessionAgent {
|
|
24
|
+
id?: string;
|
|
25
|
+
parentSessionId?: string;
|
|
26
|
+
rootSessionId?: string;
|
|
27
|
+
}
|
|
28
|
+
/** 交委派元组读口的会话店面(本仓三只持久会话店与缓存包装层都交;内存店不交)。 */
|
|
29
|
+
export interface PlacementReadingSessionStore {
|
|
30
|
+
readonly placementOf?: (sessionId: string) => Promise<SessionPlacementRecord | undefined>;
|
|
31
|
+
}
|
|
32
|
+
/** {@link SessionAgent} 的唯一投影:店答出的委派元组 → `agent` 的值;`undefined`(普通会话 / 店没有这一面)⇒ 调用方不铸键。 */
|
|
33
|
+
export declare function sessionAgentOf(placement: SessionPlacementRecord | undefined): SessionAgent | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* `agent` 的**唯一读口**:店的 `placementOf` 一读 → {@link sessionAgentOf}。店不交 `placementOf` ⇒ `undefined`(这台部署不存元组,不探)。
|
|
36
|
+
* 探针抛 ⇒ 原样上抛 —— 读不出怎么说归读者(视图读响亮失败;队列只缺那一行的键并计数),本函数不替任何一面把故障说成「不是子代」。
|
|
37
|
+
*/
|
|
38
|
+
export declare function readSessionAgent(store: PlacementReadingSessionStore | undefined, sessionId: string): Promise<SessionAgent | undefined>;
|
|
39
|
+
//# sourceMappingURL=session-agent.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function sessionAgentOf(placement) {
|
|
2
|
+
if (placement === undefined)
|
|
3
|
+
return undefined;
|
|
4
|
+
return {
|
|
5
|
+
...(placement.handle !== undefined ? { id: placement.handle } : {}),
|
|
6
|
+
...(placement.parentSessionId !== undefined ? { parentSessionId: placement.parentSessionId } : {}),
|
|
7
|
+
...(placement.rootSessionId !== undefined ? { rootSessionId: placement.rootSessionId } : {}),
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export async function readSessionAgent(store, sessionId) {
|
|
11
|
+
const placementOf = store?.placementOf;
|
|
12
|
+
if (placementOf === undefined)
|
|
13
|
+
return undefined;
|
|
14
|
+
return sessionAgentOf(await placementOf.call(store, sessionId));
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=session-agent.js.map
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
* 由 {@link sessionErrorWireOf} 按**型**先认:两面同答 409 `conflict.session_archive_stamped` + 固定句 {@link STAMPED_SESSION_ARCHIVE_SENTENCE}(与上一句的属主变更拒同状态、不同码:
|
|
50
50
|
* 两件事的出路相反 —— 属主变更从第一阶段重来,带戳存档删掉会话再推 —— 机读方按码分支,不读句子)。
|
|
51
51
|
* open 面上它是 run 的写撞上真并发写,落成那条 run 的 `failed` 终局(`terminal.code: "conflict"`),提交腿不另作处置。
|
|
52
|
-
* 带戳存档的具名拒在提交里排在一切同步冲突判之前(`local-session-store.ts` 的 `
|
|
53
|
-
* 带戳存档的日志换不了,同步冲突的出路(带同意重来)
|
|
52
|
+
* 带戳存档的具名拒在提交里排在一切同步冲突判之前(`local-session-store.ts` 的 `assertArchiveAnonymous`,带戳判的唯一读口;fork 的源与第一阶段的早拒问的是同一只):改日志的推送的每一形(干净追加 / 载荷分叉 / fork / stale,带同意与否)都答它的这一句 ——
|
|
53
|
+
* 带戳存档的日志换不了,同步冲突的出路(带同意重来)无从谈起。第一阶段(`POST …/sync/import`)按 id 分类出 fork / stale 而没带同意时,通用冲突的出路同样是死路 ⇒ 路由先问这一口,带戳 ⇒ 第一阶段就答这一句(不等带同意的第二轮)。
|
|
54
54
|
* · `storage` / `unknown` —— 留白:故障类,通用 500 就是它们今天的应答。
|
|
55
55
|
*
|
|
56
56
|
* core 给闭集加一个词 ⇒ 下面的 `switch` 编译红,由人裁定它在两面上的答复,而不是让它静默落进某个恰好存在的臂
|
|
@@ -92,8 +92,8 @@ export declare const PLACED_SESSION_SENTENCE = "this session holds a delegated a
|
|
|
92
92
|
*/
|
|
93
93
|
export declare const STAGED_IMPORT_OWNER_CHANGED_SENTENCE = "session owner changed while the import streamed; nothing was imported \u2014 start the sync again";
|
|
94
94
|
/**
|
|
95
|
-
* local 店的具名拒(唯一铸点 `plugins/local-session-store.ts`):这只会话的引擎存档仍带更早版本写下的属主戳(一次性迁移 M33 改写不了它,或数据根跳过了带这次迁移的版本)
|
|
96
|
-
* ⇒ 不在它上面造新存档(fork),也不原地换它的日志(
|
|
95
|
+
* local 店的具名拒(唯一铸点 `plugins/local-session-store.ts` 的 `assertArchiveAnonymous`):这只会话的引擎存档仍带更早版本写下的属主戳(一次性迁移 M33 改写不了它,或数据根跳过了带这次迁移的版本)
|
|
96
|
+
* ⇒ 不在它上面造新存档(fork),也不原地换它的日志(改日志的推送,含第一阶段对 fork / stale 的早拒);零写。`SessionError.code` 是 core 闭集的 `conflict`;句子(给运维日志,点名会话 id)归本错,
|
|
97
97
|
* wire 上发自己的码 `conflict.session_archive_stamped` + 固定句 {@link STAMPED_SESSION_ARCHIVE_SENTENCE}(两面同一码同一句;映射 {@link sessionErrorWireOf}):
|
|
98
98
|
* 同一个 core 词 `conflict` 在 import 面上还有属主变更那一件事(出路相反),机读方要能按码把两件事分开。
|
|
99
99
|
*/
|
|
@@ -53,8 +53,9 @@ export type LiveModelTextFrame = (LiveEventIdentity & {
|
|
|
53
53
|
* 一块的原文只有一个定义({@link blockText}:它的 delta 字节;一个 delta 字节都没有、只有 `text_end` 的块 = 它的正文),活流段流与两条账本腿同读 ——
|
|
54
54
|
* 只有 `text_end` 的块照样进本段的流,由段末帧交付(不另出逐块帧),也照样进账本 `text` 行。
|
|
55
55
|
* 交付点上:① 这一块还押在窗里的字节按整段读法、**文本到此为止**交出(流式口的 `takeAll`;一帧不带 `eventId` 的 `text_delta`,紧贴段末帧之前);
|
|
56
|
-
* ② `text_end.content` = 引擎这一块的正文,**接在本段已喂入的前文之后**判(`textEndEventData(ev, 前文)`:与账本行同一只 `redactModelText
|
|
57
|
-
*
|
|
56
|
+
* ② `text_end.content` = 引擎这一块的正文,**接在本段已喂入的前文之后**判(`textEndEventData(ev, 前文)`:与账本行同一只 `redactModelText`;前文只作判定上下文;
|
|
57
|
+
* 前文与块界都是流式口自己的状态(`blockContext` / `blockBytes` / `endBlock`),登记册不另记 —— 流式口只留判定还需要的那一截前文(「扫描窗」,见 `trace/redact.ts` 流式口顶注),读法与带整段前文逐字节同);
|
|
58
|
+
* ③ 记下块界(`endBlock`)。⇒ 每块的逐块帧拼接 = 该块 `text_end.content`(引擎没修剪那一块时逐字节),各块依次拼接 = 账本 `text` 行(块界上到此为止的判定与整段判定不同时除外,见下)。
|
|
58
59
|
* 判定读不到交付点之后的字节,到此为止的判定可以与整段判定不同:一条凭据形恰横跨块界(交付那一截按到此为止判,读得出的半形出记号,后一块上横跨的那一条整枚换记号),
|
|
59
60
|
* 或交付时认作凭据、后文让它不再是(活流那一截是记号)—— 两种都是账本整段判,
|
|
60
61
|
* 段末核对对不上计一次 `server.live-text.hold-diverged` —— 这是交付点的定义,不是第二套规则(等后文 = 一段引子要扣到下一个结构帧,例如整份工具入参生成完)。
|