@te-river/opencode-team-mode 1.8.1 → 1.8.3
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 +47 -38
- package/README.zh-CN.md +47 -36
- package/dist/host/v2-prune.d.ts +81 -1
- package/dist/host/v2-prune.d.ts.map +1 -1
- package/dist/host/v2-prune.js +303 -18
- package/dist/host/v2-prune.js.map +1 -1
- package/dist/host/v2-retry.d.ts +14 -4
- package/dist/host/v2-retry.d.ts.map +1 -1
- package/dist/host/v2-retry.js +22 -10
- package/dist/host/v2-retry.js.map +1 -1
- package/dist/host/v2-session.d.ts +8 -0
- package/dist/host/v2-session.d.ts.map +1 -1
- package/dist/host/v2-session.js +18 -5
- package/dist/host/v2-session.js.map +1 -1
- package/dist/host/v2-state.d.ts +165 -0
- package/dist/host/v2-state.d.ts.map +1 -0
- package/dist/host/v2-state.js +448 -0
- package/dist/host/v2-state.js.map +1 -0
- package/dist/host/v2-tail.d.ts +98 -0
- package/dist/host/v2-tail.d.ts.map +1 -0
- package/dist/host/v2-tail.js +191 -0
- package/dist/host/v2-tail.js.map +1 -0
- package/dist/host/v2-types.d.ts +2 -0
- package/dist/host/v2-types.d.ts.map +1 -1
- package/dist/host/v2-usage.d.ts +72 -2
- package/dist/host/v2-usage.d.ts.map +1 -1
- package/dist/host/v2-usage.js +142 -9
- package/dist/host/v2-usage.js.map +1 -1
- package/dist/host/v2.d.ts.map +1 -1
- package/dist/host/v2.js +187 -3
- package/dist/host/v2.js.map +1 -1
- package/dist/prompts/lead.d.ts +1 -1
- package/dist/prompts/lead.d.ts.map +1 -1
- package/dist/prompts/lead.js +12 -0
- package/dist/prompts/lead.js.map +1 -1
- package/dist/prompts/shared.d.ts +1 -1
- package/dist/prompts/shared.d.ts.map +1 -1
- package/dist/prompts/shared.js +5 -0
- package/dist/prompts/shared.js.map +1 -1
- package/dist/tm/config-layers.d.ts.map +1 -1
- package/dist/tm/config-layers.js +4 -0
- package/dist/tm/config-layers.js.map +1 -1
- package/dist/tm/config.d.ts +8 -0
- package/dist/tm/config.d.ts.map +1 -1
- package/dist/tm/config.js.map +1 -1
- package/dist/tm/pipelines.d.ts +9 -0
- package/dist/tm/pipelines.d.ts.map +1 -1
- package/dist/tm/pipelines.js +1 -1
- package/dist/tm/pipelines.js.map +1 -1
- package/dist/tm/stats.d.ts +11 -0
- package/dist/tm/stats.d.ts.map +1 -1
- package/dist/tm/stats.js +34 -1
- package/dist/tm/stats.js.map +1 -1
- package/docs/v2-port-notes.md +7 -3
- package/package.json +1 -1
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 任务状态卡 — the LEAD's request-side JIT state injection.
|
|
3
|
+
*
|
|
4
|
+
* The lead is the one role that has to hold the whole picture: which ledger
|
|
5
|
+
* items are in flight, which are blocked, which child is still running, and
|
|
6
|
+
* where the board is. Every one of those lives SOMEWHERE (host storage, the
|
|
7
|
+
* child registry, the request layer's own note) but none of them rides the
|
|
8
|
+
* request, so the model re-derives them by calling `tm_ledger` / `tm_join`
|
|
9
|
+
* again — a round per look. This layer renders the state into ONE system
|
|
10
|
+
* entry of ≤300 tokens, on the same `session.hook("context")` seam the request
|
|
11
|
+
* layer already owns.
|
|
12
|
+
*
|
|
13
|
+
* The rules that make it safe:
|
|
14
|
+
*
|
|
15
|
+
* - **Only the lead, only our sessions.** A child session's agent is also one
|
|
16
|
+
* of ours, so gating on scope alone would hand the card to a specialist; the
|
|
17
|
+
* lead is the only role that holds the list. The scope gate is asked the
|
|
18
|
+
* same way `v2-session.ts` asks it, and a foreign/unknown session is left
|
|
19
|
+
* byte-exact (Team-scope isolation, #22).
|
|
20
|
+
* - **One entry, replaced in place.** The card carries a `hash:` of its own
|
|
21
|
+
* body as a VISIBLE marker; the gate itself compares BYTES (`prev === card`),
|
|
22
|
+
* so "nothing changed" can never be claimed for two cards that merely share a
|
|
23
|
+
* hash line. The same bytes mean NOTHING is written, different bytes rewrite
|
|
24
|
+
* the SAME array slot (length and position do not move), and no marker entry
|
|
25
|
+
* means one `push`. A host that replays the hook in-process therefore cannot
|
|
26
|
+
* grow the card into a wall.
|
|
27
|
+
* - **Empty state is not a card.** No open/doing/blocked ledger item and no
|
|
28
|
+
* running child = the entry is omitted entirely, because an empty box costs
|
|
29
|
+
* tokens and says nothing.
|
|
30
|
+
* - **The window reading is its OWN entry** (`[Team 窗口占用]`), not a card line:
|
|
31
|
+
* `窗口:<bucket>% · 模型 <id>` with the percent rounded to the NEAREST 5%
|
|
32
|
+
* multiple (42% → 40%), so a percent that jitters by a point or two does not
|
|
33
|
+
* rewrite the request. The card's render and its byte gate never reference
|
|
34
|
+
* it; an unreadable window (no usage, no catalog entry, a throwing read)
|
|
35
|
+
* removes the entry rather than rendering a fabricated 0%.
|
|
36
|
+
* - **A failed read says so, once per session.** A storage read that throws
|
|
37
|
+
* injects nothing and writes one `state_skipped` trajectory row; a repeated
|
|
38
|
+
* failure for the same session does not become a line per request.
|
|
39
|
+
* - **Never throws into the hook.** A failure here allows the request through
|
|
40
|
+
* and is counted, because a missing card is a missing extra.
|
|
41
|
+
* - **The budget is paid for by trimming, not by lying.** The counts are the
|
|
42
|
+
* real totals; the rendered list is trimmed from the OLDEST item until the
|
|
43
|
+
* card fits `STATE_CARD_MAX_TOKENS`. Token cost reuses `estimateTokens`
|
|
44
|
+
* from `src/tm/config.ts` (CJK-aware) so the number here and the number the
|
|
45
|
+
* offloader uses can never disagree.
|
|
46
|
+
*/
|
|
47
|
+
import { estimateTokens, shorten } from "../tm/config.js";
|
|
48
|
+
import { normalizeAgentName } from "../identity.js";
|
|
49
|
+
import { cacheStatsOf, createUsagePercent } from "./v2-usage.js";
|
|
50
|
+
/** 卡片标记:`event.system` 里以它开头的条目就是状态卡(唯一一条)。 */
|
|
51
|
+
export const STATE_CARD_MARKER = "[Team 状态卡]";
|
|
52
|
+
/** 窗口占用条目的标记——它是**独立条目**,不参与状态卡的渲染与 hash 门控。 */
|
|
53
|
+
export const WINDOW_MARKER = "[Team 窗口占用]";
|
|
54
|
+
/** 窗口占用的分桶步长:最近 5% 的整数倍(42% → 40%)。 */
|
|
55
|
+
export const WINDOW_BUCKET_STEP = 5;
|
|
56
|
+
/** 卡片 token 上限。 超过就按「最旧账本项」开始裁剪。 */
|
|
57
|
+
export const STATE_CARD_MAX_TOKENS = 300;
|
|
58
|
+
/** 每条账本项渲染的字符上限。 */
|
|
59
|
+
export const STATE_CARD_ITEM_CHARS = 60;
|
|
60
|
+
/** 看板根的字符上限(超长工作区路径不该吃满预算)。 */
|
|
61
|
+
export const STATE_CARD_BOARD_CHARS = 120;
|
|
62
|
+
/** 运行中的子代理:登记时的 `state` 只有 running / idle / error 三种。 */
|
|
63
|
+
const RUNNING_STATE = "running";
|
|
64
|
+
/** 两个 32 位 FNV-1a 拼成 16 位 hex — 确定性、跨平台、不依赖 BigInt 目标。 */
|
|
65
|
+
function fnv32(text, seed) {
|
|
66
|
+
let h = seed >>> 0;
|
|
67
|
+
for (let i = 0; i < text.length; i++) {
|
|
68
|
+
h ^= text.charCodeAt(i);
|
|
69
|
+
h = Math.imul(h, 16777619) >>> 0;
|
|
70
|
+
}
|
|
71
|
+
return h >>> 0;
|
|
72
|
+
}
|
|
73
|
+
/** 16 位 hex 的状态指纹。 */
|
|
74
|
+
export function stateCardHash(body) {
|
|
75
|
+
const a = fnv32(body, 0x811c9dc5);
|
|
76
|
+
const b = fnv32(body, 0x9e3779b9);
|
|
77
|
+
return a.toString(16).padStart(8, "0") + b.toString(16).padStart(8, "0");
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 窗口占用的分桶:最近 5% 的整数倍。 分桶是为了让「同一个档位」在两次请求之间
|
|
81
|
+
* 逐字节相等——百分比每次都可能抖一两位,而「窗口还剩多少」这个判断不需要那么细。
|
|
82
|
+
*/
|
|
83
|
+
export function windowBucket(percent) {
|
|
84
|
+
const p = Number.isFinite(percent) ? Math.max(0, percent) : 0;
|
|
85
|
+
return Math.round(p / WINDOW_BUCKET_STEP) * WINDOW_BUCKET_STEP;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 窗口占用条目。 它是**独立**的一条 system 条目(自己的 marker、自己的 hash),
|
|
89
|
+
* 状态卡的渲染与字节门控完全不引用它——两件事各自可靠。
|
|
90
|
+
*/
|
|
91
|
+
export function renderWindowEntry(bucket, model) {
|
|
92
|
+
const body = `窗口:${bucket}% · 模型 ${model}`;
|
|
93
|
+
return `${WINDOW_MARKER}\nhash:${stateCardHash(body)}\n${body}`;
|
|
94
|
+
}
|
|
95
|
+
/** 计数来自完整账本(真值),渲染列表才允许被裁剪——两件事不能混。 */
|
|
96
|
+
function countsOf(items) {
|
|
97
|
+
const c = { doing: 0, blocked: 0, todo: 0 };
|
|
98
|
+
for (const it of items) {
|
|
99
|
+
if (it.status === "doing")
|
|
100
|
+
c.doing++;
|
|
101
|
+
else if (it.status === "blocked")
|
|
102
|
+
c.blocked++;
|
|
103
|
+
else if (it.status === "open")
|
|
104
|
+
c.todo++;
|
|
105
|
+
}
|
|
106
|
+
return c;
|
|
107
|
+
}
|
|
108
|
+
/** 卡片里列出的项:done 的项已经收口,占位置不提供信息。 */
|
|
109
|
+
function openish(items) {
|
|
110
|
+
return items.filter((it) => it.status !== "done");
|
|
111
|
+
}
|
|
112
|
+
function itemLine(it) {
|
|
113
|
+
const tail = it.status === "blocked" ? "(等批准)" : "";
|
|
114
|
+
return `#${it.id} [${it.status}] ${shorten(it.text, STATE_CARD_ITEM_CHARS)}${tail}`;
|
|
115
|
+
}
|
|
116
|
+
function childLine(c) {
|
|
117
|
+
// `ses_` + 6 = the id shape the lead can copy into tm_join without paging.
|
|
118
|
+
return `${String(c.sessionID ?? "").slice(0, 10)} ${c.agent}`;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* 运行中且属于这个会话的子代理。 m5:没有 sessionID 就不知道它们属于谁——
|
|
122
|
+
* 那时返回空数组(整行省略),而不是把别的会话的运行中子代理列进这张卡。
|
|
123
|
+
*/
|
|
124
|
+
function runningChildren(input) {
|
|
125
|
+
const sid = String(input.sessionID ?? "");
|
|
126
|
+
if (!sid)
|
|
127
|
+
return [];
|
|
128
|
+
return (input.children ?? []).filter(
|
|
129
|
+
// R5:`hostChildren()` 的 parentSessionID 是必填,所以这里不做「没写父会话就当作
|
|
130
|
+
// 全部」的宽容 —— 那等于把别人的子代理往这张卡上贴。fail closed。
|
|
131
|
+
(c) => c && String(c.state ?? "") === RUNNING_STATE && c.parentSessionID === sid);
|
|
132
|
+
}
|
|
133
|
+
/** children 行:`shown` 是预算允许列出的条数,括号里的计数始终是真实总数。 */
|
|
134
|
+
function childrenLine(runs, shown) {
|
|
135
|
+
if (!runs.length)
|
|
136
|
+
return "";
|
|
137
|
+
if (shown <= 0)
|
|
138
|
+
return `运行子代理(${runs.length}):列表因预算省略`;
|
|
139
|
+
const tail = shown < runs.length ? `,仅列前 ${shown}` : "";
|
|
140
|
+
return `运行子代理(${runs.length}${tail}):${runs.slice(0, shown).map(childLine).join("、")}`;
|
|
141
|
+
}
|
|
142
|
+
function renderBody(input, rendered, withPrune, childrenShown) {
|
|
143
|
+
const all = openish(input.ledger?.items ?? []);
|
|
144
|
+
const counts = countsOf(input.ledger?.items ?? []);
|
|
145
|
+
const lines = [];
|
|
146
|
+
if (all.length) {
|
|
147
|
+
lines.push(`账本(进行 ${counts.doing} / 阻塞 ${counts.blocked} / 待办 ${counts.todo}):`);
|
|
148
|
+
}
|
|
149
|
+
for (const it of rendered)
|
|
150
|
+
lines.push(itemLine(it));
|
|
151
|
+
const childText = childrenLine(runningChildren(input), childrenShown);
|
|
152
|
+
if (childText)
|
|
153
|
+
lines.push(childText);
|
|
154
|
+
lines.push(`看板:${shorten(input.boardRoot, STATE_CARD_BOARD_CHARS)}`);
|
|
155
|
+
const pruneDelta = Math.max(0, Math.floor(Number(input.pruneDelta ?? 0)) || 0);
|
|
156
|
+
if (withPrune && pruneDelta > 0)
|
|
157
|
+
lines.push(`上轮修剪:${pruneDelta} 条消息已卸载(tm_fetch 可取回)`);
|
|
158
|
+
return lines.join("\n");
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* 渲染一张卡片,或返回 null(空状态 = 不注入)。 纯函数:同样的状态必然
|
|
162
|
+
* 产出逐字节相同的文本,这是字节门控能成立的前提。
|
|
163
|
+
*/
|
|
164
|
+
export function renderStateCard(input) {
|
|
165
|
+
const items = openish(input.ledger?.items ?? []);
|
|
166
|
+
const runs = runningChildren(input);
|
|
167
|
+
if (!items.length && !runs.length)
|
|
168
|
+
return null;
|
|
169
|
+
// 预算不够时的让位顺序,两者都不许说谎:
|
|
170
|
+
// ① 账本项从最旧一项开始裁(账本是追加序);
|
|
171
|
+
// ② `上轮修剪` 整行让位;
|
|
172
|
+
// ③ children 行从尾部删,但计数保留(`运行子代理(N,仅列前 K)`)。
|
|
173
|
+
let rendered = items.slice();
|
|
174
|
+
let withPrune = true;
|
|
175
|
+
let childrenShown = runs.length;
|
|
176
|
+
let card = assemble(input, rendered, withPrune, childrenShown);
|
|
177
|
+
while (estimateTokens(card) > STATE_CARD_MAX_TOKENS && rendered.length > 0) {
|
|
178
|
+
rendered = rendered.slice(1);
|
|
179
|
+
card = assemble(input, rendered, withPrune, childrenShown);
|
|
180
|
+
}
|
|
181
|
+
if (estimateTokens(card) > STATE_CARD_MAX_TOKENS && withPrune) {
|
|
182
|
+
// 让位顺序就是上面那三步:账本项(最旧先,上一个 while)→ `上轮修剪` 行(这里)
|
|
183
|
+
// → children 列表长度(下一个 while,计数保留)。绝不为凑预算先动 children。
|
|
184
|
+
// 最坏情况 ≈150 token:`看板:` ≤120 字符(shorten 上限)+ children 只留计数行,
|
|
185
|
+
// 两项叠加仍远低于 300 的上限。
|
|
186
|
+
withPrune = false;
|
|
187
|
+
card = assemble(input, rendered, withPrune, childrenShown);
|
|
188
|
+
}
|
|
189
|
+
while (estimateTokens(card) > STATE_CARD_MAX_TOKENS && childrenShown > 0) {
|
|
190
|
+
childrenShown--;
|
|
191
|
+
card = assemble(input, rendered, withPrune, childrenShown);
|
|
192
|
+
}
|
|
193
|
+
return card;
|
|
194
|
+
}
|
|
195
|
+
function assemble(input, rendered, withPrune, childrenShown) {
|
|
196
|
+
const body = renderBody(input, rendered, withPrune, childrenShown);
|
|
197
|
+
return `${STATE_CARD_MARKER}\nhash:${stateCardHash(body)}\n${body}`;
|
|
198
|
+
}
|
|
199
|
+
function cardTextOf(part) {
|
|
200
|
+
const text = part?.text;
|
|
201
|
+
return typeof text === "string" ? text : "";
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* 只有「marker + 16 位 hex 的 hash 行」才算我们的卡片。 n9:早先的
|
|
205
|
+
* `startsWith(STATE_CARD_MARKER)` 会认领一条恰好以 marker 开头、其实是别人写的
|
|
206
|
+
* 条目,然后把它整条覆盖掉。
|
|
207
|
+
*/
|
|
208
|
+
const CARD_HEAD_RE = /^\[Team 状态卡\]\nhash:[0-9a-f]{16}/;
|
|
209
|
+
function isMarkerEntry(part) {
|
|
210
|
+
return CARD_HEAD_RE.test(cardTextOf(part));
|
|
211
|
+
}
|
|
212
|
+
/** 窗口条目的认领规则与状态卡同构:marker + 16 位 hex,缺一不可。 */
|
|
213
|
+
const WINDOW_HEAD_RE = /^\[Team 窗口占用\]\nhash:[0-9a-f]{16}/;
|
|
214
|
+
function isWindowEntry(part) {
|
|
215
|
+
return WINDOW_HEAD_RE.test(cardTextOf(part));
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* 注册到 `session.hook("context")` 的状态卡层。 依赖全部注入,所以测试可以
|
|
219
|
+
* 用一个内存账本驱动它,而生产路径用的是 `tm_ledger` 的那个 store 实例。
|
|
220
|
+
*/
|
|
221
|
+
export async function applyV2StateCard(ctx, input) {
|
|
222
|
+
const report = {
|
|
223
|
+
enabled: input.enabled !== false,
|
|
224
|
+
injected: 0,
|
|
225
|
+
replaced: 0,
|
|
226
|
+
unchanged: 0,
|
|
227
|
+
empty: 0,
|
|
228
|
+
cleared: 0,
|
|
229
|
+
skipped: 0,
|
|
230
|
+
agentSkipped: 0,
|
|
231
|
+
foreignSkipped: 0,
|
|
232
|
+
threw: 0,
|
|
233
|
+
windowInjected: 0,
|
|
234
|
+
windowUnchanged: 0,
|
|
235
|
+
windowCleared: 0,
|
|
236
|
+
windowAbsent: 0,
|
|
237
|
+
lastWhy: "",
|
|
238
|
+
};
|
|
239
|
+
const registrations = [];
|
|
240
|
+
const session = ctx.session;
|
|
241
|
+
// `stateCard: "off"` must be byte-identical to the build before this layer
|
|
242
|
+
// existed, and "did not register" is the only way to be sure of that.
|
|
243
|
+
if (!report.enabled)
|
|
244
|
+
return { registrations, report };
|
|
245
|
+
if (!session || typeof session.hook !== "function")
|
|
246
|
+
return { registrations, report };
|
|
247
|
+
const usageOf = input.usageOf ?? createUsagePercent(ctx);
|
|
248
|
+
const emit = (row) => {
|
|
249
|
+
try {
|
|
250
|
+
input.onEvent?.(row);
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
253
|
+
/* 轨迹是附加物,不能成为请求失败的理由 */
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
/** 每会话只记一次失败——否则一个坏 store 会按请求刷屏。 */
|
|
257
|
+
const skippedLogged = new Set();
|
|
258
|
+
/** 上一张卡片看到的累计修剪条数,用来算「上轮」的差量。 */
|
|
259
|
+
const pruneSeen = new Map();
|
|
260
|
+
registrations.push(await session.hook("context", async (event) => {
|
|
261
|
+
try {
|
|
262
|
+
// The lead is the only role that holds the list; a child session's agent
|
|
263
|
+
// is one of ours too, so scope alone would hand it the card.
|
|
264
|
+
if (normalizeAgentName(String(event?.agent ?? "")) !== "team") {
|
|
265
|
+
report.agentSkipped++;
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
// #22: a session we do not own is left byte-exact.
|
|
269
|
+
if (input.scope && input.scope.count(input.scope.decide(event)) !== "ours") {
|
|
270
|
+
report.foreignSkipped++;
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
// 尾层模式(`dynamicTail: "on"`):状态卡与窗口条目写进请求末尾的
|
|
274
|
+
// 滞留区,system 一个字节都不碰——前缀缓存靠的就是它稳定。
|
|
275
|
+
const onTail = input.sink !== undefined;
|
|
276
|
+
if (!onTail && !Array.isArray(event?.system))
|
|
277
|
+
return;
|
|
278
|
+
const sessionID = String(event.sessionID ?? "");
|
|
279
|
+
// ---- 窗口占用:独立条目,状态卡的渲染与 hash 门控一个字节都不碰 ----
|
|
280
|
+
// 读不到窗口/用量 = 「不可得」,不是 0%:整条不显示,已存在的那条摘掉。
|
|
281
|
+
// 读取抛错与「读不到」同处理——两种情况我们都没拿到数字,区分只对日志有用,
|
|
282
|
+
// 而这里连日志都不该成为请求失败的理由。
|
|
283
|
+
let windowReading = null;
|
|
284
|
+
try {
|
|
285
|
+
windowReading = await usageOf(sessionID, event.messages);
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
windowReading = null;
|
|
289
|
+
}
|
|
290
|
+
// ---- 缓存命中:每请求一行轨迹,就发在这一次读数上(不新增第二次 usage 读取)----
|
|
291
|
+
// 读不到 usage 就一行都不写:「没读到」落盘后会被当成「0 命中」,那正是这行要防的。
|
|
292
|
+
// `step_id` 覆盖 v2.ts 包装里的默认值(它在 `...row` 之前),这一行因此按自己的
|
|
293
|
+
// 口径被 tm_stats 汇总,而不是混进 v2-state 的观测行。
|
|
294
|
+
if (windowReading) {
|
|
295
|
+
const cache = cacheStatsOf(windowReading);
|
|
296
|
+
emit({
|
|
297
|
+
step_id: "v2-cache",
|
|
298
|
+
event: "cache",
|
|
299
|
+
// `hit` 是本行的规范字段名,`read` 是同一数值的可读别名(汇总两种拼写都认)。
|
|
300
|
+
hit: cache.read,
|
|
301
|
+
read: cache.read,
|
|
302
|
+
write: cache.write,
|
|
303
|
+
input: cache.input,
|
|
304
|
+
rate: cache.hitRate === null ? null : Number(cache.hitRate.toFixed(2)),
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
{
|
|
308
|
+
if (onTail) {
|
|
309
|
+
if (!windowReading) {
|
|
310
|
+
// 读不到 = 没有这一节;上一条尾巴已经由尾层剥离,这里无需再摘。
|
|
311
|
+
report.windowAbsent++;
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
const entry = renderWindowEntry(windowBucket(windowReading.percent), `${windowReading.model.providerID}/${windowReading.model.id}`);
|
|
315
|
+
// 同一请求内重放(宿主会重放 hook):同串就不再写,计 unchanged。
|
|
316
|
+
if (input.sink?.peek(sessionID, "window") === entry) {
|
|
317
|
+
report.windowUnchanged++;
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
input.sink?.set(sessionID, "window", entry);
|
|
321
|
+
report.windowInjected++;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
const at = event.system.findIndex(isWindowEntry);
|
|
327
|
+
if (!windowReading) {
|
|
328
|
+
if (at >= 0) {
|
|
329
|
+
event.system.splice(at, 1);
|
|
330
|
+
report.windowCleared++;
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
report.windowAbsent++;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
const entry = renderWindowEntry(windowBucket(windowReading.percent), `${windowReading.model.providerID}/${windowReading.model.id}`);
|
|
338
|
+
if (at < 0) {
|
|
339
|
+
event.system.push({ type: "text", text: entry });
|
|
340
|
+
report.windowInjected++;
|
|
341
|
+
}
|
|
342
|
+
else if (cardTextOf(event.system[at]) === entry) {
|
|
343
|
+
// 分桶与模型都没变 ⇒ 一个字节都没写(和卡片同一条纪律)。
|
|
344
|
+
report.windowUnchanged++;
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
;
|
|
348
|
+
event.system[at].text = entry;
|
|
349
|
+
report.windowInjected++;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
let ledger = null;
|
|
355
|
+
try {
|
|
356
|
+
ledger = await input.loadLedger(sessionID);
|
|
357
|
+
}
|
|
358
|
+
catch (err) {
|
|
359
|
+
report.skipped++;
|
|
360
|
+
report.lastWhy = String(err?.message ?? err).slice(0, 120);
|
|
361
|
+
if (!skippedLogged.has(sessionID)) {
|
|
362
|
+
skippedLogged.add(sessionID);
|
|
363
|
+
emit({ event: "state_skipped", why: report.lastWhy, session: sessionID ? "known" : "absent" });
|
|
364
|
+
}
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
let pruneDelta;
|
|
368
|
+
let pruneNow;
|
|
369
|
+
if (input.pruneCount) {
|
|
370
|
+
try {
|
|
371
|
+
pruneNow = Math.max(0, Math.floor(Number(input.pruneCount()) || 0));
|
|
372
|
+
const before = pruneSeen.get(sessionID) ?? 0;
|
|
373
|
+
pruneDelta = Math.max(0, pruneNow - before);
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
/* 没有修剪数据 = 这一行整行省略 */
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
const card = renderStateCard({
|
|
380
|
+
ledger,
|
|
381
|
+
children: input.children(),
|
|
382
|
+
boardRoot: input.boardRoot,
|
|
383
|
+
pruneDelta,
|
|
384
|
+
sessionID,
|
|
385
|
+
});
|
|
386
|
+
if (onTail) {
|
|
387
|
+
if (!card) {
|
|
388
|
+
// 没有卡片 = 这一节不出现;上一条尾巴由尾层剥离,旧卡不会留在请求里。
|
|
389
|
+
report.empty++;
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
if (input.sink?.peek(sessionID, "state") === card) {
|
|
393
|
+
// 同一请求内重放:一个字节都不再写。
|
|
394
|
+
report.unchanged++;
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
input.sink?.set(sessionID, "state", card);
|
|
398
|
+
report.injected++;
|
|
399
|
+
if (pruneNow !== undefined)
|
|
400
|
+
pruneSeen.set(sessionID, pruneNow);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
if (!card) {
|
|
404
|
+
// R2:宿主会跨请求保留 `event.system`,账本清空后旧卡仍挂着就是高估形态
|
|
405
|
+
// (卡上还写着「进行 1 / 运行子代理 1」)。状态为空 = 把我们的条目摘掉;
|
|
406
|
+
// `empty` 只计「本来就没有卡」的那一刻。
|
|
407
|
+
const staleAt = event.system.findIndex(isMarkerEntry);
|
|
408
|
+
if (staleAt >= 0) {
|
|
409
|
+
event.system.splice(staleAt, 1);
|
|
410
|
+
report.cleared++;
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
report.empty++;
|
|
414
|
+
}
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
const at = event.system.findIndex(isMarkerEntry);
|
|
418
|
+
// m4: `pruneSeen` advances ONLY after the card actually lands. Advancing
|
|
419
|
+
// before rendering swallowed the delta whenever the render was dropped
|
|
420
|
+
// (empty state, or a budget cut that removed the very line carrying it) —
|
|
421
|
+
// the next card then read "上轮 = 0" for work that really happened.
|
|
422
|
+
if (at < 0) {
|
|
423
|
+
event.system.push({ type: "text", text: card });
|
|
424
|
+
report.injected++;
|
|
425
|
+
if (pruneNow !== undefined)
|
|
426
|
+
pruneSeen.set(sessionID, pruneNow);
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
const prev = cardTextOf(event.system[at]);
|
|
430
|
+
// n9 字节门控:整串相等才算「没变」。 hash 行只是给人看的标记,拿它当
|
|
431
|
+
// 比较键会让两条内容不同的卡片在 hash 相同(或被截断)时被判成没变。
|
|
432
|
+
if (prev === card) {
|
|
433
|
+
report.unchanged++;
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
const slot = event.system[at];
|
|
437
|
+
slot.text = card;
|
|
438
|
+
report.replaced++;
|
|
439
|
+
if (pruneNow !== undefined)
|
|
440
|
+
pruneSeen.set(sessionID, pruneNow);
|
|
441
|
+
}
|
|
442
|
+
catch {
|
|
443
|
+
report.threw++;
|
|
444
|
+
}
|
|
445
|
+
}));
|
|
446
|
+
return { registrations, report };
|
|
447
|
+
}
|
|
448
|
+
//# sourceMappingURL=v2-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v2-state.js","sourceRoot":"","sources":["../../src/host/v2-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAEzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAqD,MAAM,eAAe,CAAA;AAKnH,+CAA+C;AAC/C,MAAM,CAAC,MAAM,iBAAiB,GAAG,YAAY,CAAA;AAC7C,gDAAgD;AAChD,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAAA;AAC1C,uCAAuC;AACvC,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAA;AACnC,qCAAqC;AACrC,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAA;AACxC,oBAAoB;AACpB,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,CAAA;AACvC,+BAA+B;AAC/B,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAA;AAsFzC,yDAAyD;AACzD,MAAM,aAAa,GAAG,SAAS,CAAA;AAE/B,0DAA0D;AAC1D,SAAS,KAAK,CAAC,IAAY,EAAE,IAAY;IACvC,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,CAAA;IAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;QACvB,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;IAClC,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,CAAA;AAChB,CAAC;AAED,sBAAsB;AACtB,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;IACjC,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;IACjC,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;AAC1E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAC7D,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,kBAAkB,CAAC,GAAG,kBAAkB,CAAA;AAChE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc,EAAE,KAAa;IAC7D,MAAM,IAAI,GAAG,MAAM,MAAM,UAAU,KAAK,EAAE,CAAA;IAC1C,OAAO,GAAG,aAAa,UAAU,aAAa,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAA;AACjE,CAAC;AAQD,uCAAuC;AACvC,SAAS,QAAQ,CAAC,KAAmB;IACnC,MAAM,CAAC,GAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAA;IACzD,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,EAAE,CAAC,MAAM,KAAK,OAAO;YAAE,CAAC,CAAC,KAAK,EAAE,CAAA;aAC/B,IAAI,EAAE,CAAC,MAAM,KAAK,SAAS;YAAE,CAAC,CAAC,OAAO,EAAE,CAAA;aACxC,IAAI,EAAE,CAAC,MAAM,KAAK,MAAM;YAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IACzC,CAAC;IACD,OAAO,CAAC,CAAA;AACV,CAAC;AAED,oCAAoC;AACpC,SAAS,OAAO,CAAC,KAAmB;IAClC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,KAAK,MAAM,CAAC,CAAA;AACnD,CAAC;AAED,SAAS,QAAQ,CAAC,EAAc;IAC9B,MAAM,IAAI,GAAG,EAAE,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAA;IACnD,OAAO,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,MAAM,KAAK,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,qBAAqB,CAAC,GAAG,IAAI,EAAE,CAAA;AACrF,CAAC;AAED,SAAS,SAAS,CAAC,CAAiB;IAClC,2EAA2E;IAC3E,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAA;AAC/D,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,KAA2B;IAClD,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC,CAAA;IACzC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAA;IACnB,OAAO,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,MAAM;IAClC,4DAA4D;IAC5D,0CAA0C;IAC1C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,KAAK,aAAa,IAAI,CAAC,CAAC,eAAe,KAAK,GAAG,CACjF,CAAA;AACH,CAAC;AAED,mDAAmD;AACnD,SAAS,YAAY,CAAC,IAAsB,EAAE,KAAa;IACzD,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAA;IAC3B,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,SAAS,IAAI,CAAC,MAAM,WAAW,CAAA;IACtD,MAAM,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IACvD,OAAO,SAAS,IAAI,CAAC,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAA;AACxF,CAAC;AAED,SAAS,UAAU,CACjB,KAA2B,EAC3B,QAAsB,EACtB,SAAkB,EAClB,aAAqB;IAErB,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,CAAA;IAC9C,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,CAAA;IAClD,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,KAAK,SAAS,MAAM,CAAC,OAAO,SAAS,MAAM,CAAC,IAAI,IAAI,CAAC,CAAA;IAClF,CAAC;IACD,KAAK,MAAM,EAAE,IAAI,QAAQ;QAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAA;IACnD,MAAM,SAAS,GAAG,YAAY,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,CAAA;IACrE,IAAI,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IACpC,KAAK,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,sBAAsB,CAAC,EAAE,CAAC,CAAA;IACpE,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;IAC9E,IAAI,SAAS,IAAI,UAAU,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,UAAU,uBAAuB,CAAC,CAAA;IACtF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,KAA2B;IACzD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,CAAA;IAChD,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,CAAC,CAAA;IACnC,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IAC9C,sBAAsB;IACtB,2BAA2B;IAC3B,mBAAmB;IACnB,8CAA8C;IAC9C,IAAI,QAAQ,GAAG,KAAK,CAAC,KAAK,EAAE,CAAA;IAC5B,IAAI,SAAS,GAAG,IAAI,CAAA;IACpB,IAAI,aAAa,GAAG,IAAI,CAAC,MAAM,CAAA;IAC/B,IAAI,IAAI,GAAG,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,CAAC,CAAA;IAC9D,OAAO,cAAc,CAAC,IAAI,CAAC,GAAG,qBAAqB,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3E,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QAC5B,IAAI,GAAG,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,CAAC,CAAA;IAC5D,CAAC;IACD,IAAI,cAAc,CAAC,IAAI,CAAC,GAAG,qBAAqB,IAAI,SAAS,EAAE,CAAC;QAC9D,+CAA+C;QAC/C,qDAAqD;QACrD,6DAA6D;QAC7D,oBAAoB;QACpB,SAAS,GAAG,KAAK,CAAA;QACjB,IAAI,GAAG,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,CAAC,CAAA;IAC5D,CAAC;IACD,OAAO,cAAc,CAAC,IAAI,CAAC,GAAG,qBAAqB,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;QACzE,aAAa,EAAE,CAAA;QACf,IAAI,GAAG,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,CAAC,CAAA;IAC5D,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAS,QAAQ,CACf,KAA2B,EAC3B,QAAsB,EACtB,SAAkB,EAClB,aAAqB;IAErB,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,CAAC,CAAA;IAClE,OAAO,GAAG,iBAAiB,UAAU,aAAa,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAA;AACrE,CAAC;AAED,SAAS,UAAU,CAAC,IAAa;IAC/B,MAAM,IAAI,GAAI,IAA2B,EAAE,IAAI,CAAA;IAC/C,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAA;AAC7C,CAAC;AAED;;;;GAIG;AACH,MAAM,YAAY,GAAG,kCAAkC,CAAA;AAEvD,SAAS,aAAa,CAAC,IAAa;IAClC,OAAO,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAA;AAC5C,CAAC;AAED,8CAA8C;AAC9C,MAAM,cAAc,GAAG,mCAAmC,CAAA;AAE1D,SAAS,aAAa,CAAC,IAAa;IAClC,OAAO,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAA;AAC9C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAc,EAAE,KAAqB;IAC1E,MAAM,MAAM,GAAoB;QAC9B,OAAO,EAAE,KAAK,CAAC,OAAO,KAAK,KAAK;QAChC,QAAQ,EAAE,CAAC;QACX,QAAQ,EAAE,CAAC;QACX,SAAS,EAAE,CAAC;QACZ,KAAK,EAAE,CAAC;QACR,OAAO,EAAE,CAAC;QACV,OAAO,EAAE,CAAC;QACV,YAAY,EAAE,CAAC;QACf,cAAc,EAAE,CAAC;QACjB,KAAK,EAAE,CAAC;QACR,cAAc,EAAE,CAAC;QACjB,eAAe,EAAE,CAAC;QAClB,aAAa,EAAE,CAAC;QAChB,YAAY,EAAE,CAAC;QACf,OAAO,EAAE,EAAE;KACZ,CAAA;IACD,MAAM,aAAa,GAAqB,EAAE,CAAA;IAC1C,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAA;IAC3B,2EAA2E;IAC3E,sEAAsE;IACtE,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,CAAA;IACrD,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,CAAC,IAAI,KAAK,UAAU;QAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,CAAA;IAEpF,MAAM,OAAO,GAAuB,KAAK,CAAC,OAAO,IAAI,kBAAkB,CAAC,GAAG,CAAC,CAAA;IAE5E,MAAM,IAAI,GAAG,CAAC,GAA4B,EAAQ,EAAE;QAClD,IAAI,CAAC;YACH,KAAK,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAA;QACtB,CAAC;QAAC,MAAM,CAAC;YACP,wBAAwB;QAC1B,CAAC;IACH,CAAC,CAAA;IACD,qCAAqC;IACrC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAA;IACvC,iCAAiC;IACjC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAA;IAE3C,aAAa,CAAC,IAAI,CAChB,MAAM,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,KAAuB,EAAE,EAAE;QAC9D,IAAI,CAAC;YACH,yEAAyE;YACzE,6DAA6D;YAC7D,IAAI,kBAAkB,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC;gBAC9D,MAAM,CAAC,YAAY,EAAE,CAAA;gBACrB,OAAM;YACR,CAAC;YACD,mDAAmD;YACnD,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC;gBAC3E,MAAM,CAAC,cAAc,EAAE,CAAA;gBACvB,OAAM;YACR,CAAC;YACD,4CAA4C;YAC5C,mCAAmC;YACnC,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,KAAK,SAAS,CAAA;YACvC,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC;gBAAE,OAAM;YACpD,MAAM,SAAS,GAAG,MAAM,CAAE,KAAiC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAA;YAC5E,6CAA6C;YAC7C,yCAAyC;YACzC,wCAAwC;YACxC,sBAAsB;YACtB,IAAI,aAAa,GAA+B,IAAI,CAAA;YACpD,IAAI,CAAC;gBACH,aAAa,GAAG,MAAM,OAAO,CAAC,SAAS,EAAG,KAAgC,CAAC,QAAQ,CAAC,CAAA;YACtF,CAAC;YAAC,MAAM,CAAC;gBACP,aAAa,GAAG,IAAI,CAAA;YACtB,CAAC;YACD,mDAAmD;YACnD,gDAAgD;YAChD,uDAAuD;YACvD,uCAAuC;YACvC,IAAI,aAAa,EAAE,CAAC;gBAClB,MAAM,KAAK,GAAG,YAAY,CAAC,aAAa,CAAC,CAAA;gBACzC,IAAI,CAAC;oBACH,OAAO,EAAE,UAAU;oBACnB,KAAK,EAAE,OAAO;oBACd,+CAA+C;oBAC/C,GAAG,EAAE,KAAK,CAAC,IAAI;oBACf,IAAI,EAAE,KAAK,CAAC,IAAI;oBAChB,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,IAAI,EAAE,KAAK,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;iBACvE,CAAC,CAAA;YACJ,CAAC;YACD,CAAC;gBACC,IAAI,MAAM,EAAE,CAAC;oBACX,IAAI,CAAC,aAAa,EAAE,CAAC;wBACnB,mCAAmC;wBACnC,MAAM,CAAC,YAAY,EAAE,CAAA;oBACvB,CAAC;yBAAM,CAAC;wBACN,MAAM,KAAK,GAAG,iBAAiB,CAC7B,YAAY,CAAC,aAAa,CAAC,OAAO,CAAC,EACnC,GAAG,aAAa,CAAC,KAAK,CAAC,UAAU,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,EAAE,CAC9D,CAAA;wBACD,0CAA0C;wBAC1C,IAAI,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,KAAK,KAAK,EAAE,CAAC;4BACpD,MAAM,CAAC,eAAe,EAAE,CAAA;wBAC1B,CAAC;6BAAM,CAAC;4BACN,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAA;4BAC3C,MAAM,CAAC,cAAc,EAAE,CAAA;wBACzB,CAAC;oBACH,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,CAAA;oBAChD,IAAI,CAAC,aAAa,EAAE,CAAC;wBACnB,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;4BACZ,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;4BAC1B,MAAM,CAAC,aAAa,EAAE,CAAA;wBACxB,CAAC;6BAAM,CAAC;4BACN,MAAM,CAAC,YAAY,EAAE,CAAA;wBACvB,CAAC;oBACH,CAAC;yBAAM,CAAC;wBACN,MAAM,KAAK,GAAG,iBAAiB,CAC7B,YAAY,CAAC,aAAa,CAAC,OAAO,CAAC,EACnC,GAAG,aAAa,CAAC,KAAK,CAAC,UAAU,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,EAAE,CAC9D,CAAA;wBACD,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;4BACX,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;4BAChD,MAAM,CAAC,cAAc,EAAE,CAAA;wBACzB,CAAC;6BAAM,IAAI,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC;4BAClD,gCAAgC;4BAChC,MAAM,CAAC,eAAe,EAAE,CAAA;wBAC1B,CAAC;6BAAM,CAAC;4BACN,CAAC;4BAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAsB,CAAC,IAAI,GAAG,KAAK,CAAA;4BACpD,MAAM,CAAC,cAAc,EAAE,CAAA;wBACzB,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YACD,IAAI,MAAM,GAAkB,IAAI,CAAA;YAChC,IAAI,CAAC;gBACH,MAAM,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,CAAA;YAC5C,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,OAAO,EAAE,CAAA;gBAChB,MAAM,CAAC,OAAO,GAAG,MAAM,CAAE,GAAa,EAAE,OAAO,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;gBACrE,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;oBAClC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;oBAC5B,IAAI,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAA;gBAChG,CAAC;gBACD,OAAM;YACR,CAAC;YACD,IAAI,UAA8B,CAAA;YAClC,IAAI,QAA4B,CAAA;YAChC,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;gBACrB,IAAI,CAAC;oBACH,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;oBACnE,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;oBAC5C,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC,CAAA;gBAC7C,CAAC;gBAAC,MAAM,CAAC;oBACP,sBAAsB;gBACxB,CAAC;YACH,CAAC;YACD,MAAM,IAAI,GAAG,eAAe,CAAC;gBAC3B,MAAM;gBACN,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE;gBAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,UAAU;gBACV,SAAS;aACV,CAAC,CAAA;YACF,IAAI,MAAM,EAAE,CAAC;gBACX,IAAI,CAAC,IAAI,EAAE,CAAC;oBACV,sCAAsC;oBACtC,MAAM,CAAC,KAAK,EAAE,CAAA;oBACd,OAAM;gBACR,CAAC;gBACD,IAAI,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;oBAClD,oBAAoB;oBACpB,MAAM,CAAC,SAAS,EAAE,CAAA;oBAClB,OAAM;gBACR,CAAC;gBACD,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;gBACzC,MAAM,CAAC,QAAQ,EAAE,CAAA;gBACjB,IAAI,QAAQ,KAAK,SAAS;oBAAE,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;gBAC9D,OAAM;YACR,CAAC;YACD,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,8CAA8C;gBAC9C,2CAA2C;gBAC3C,0BAA0B;gBAC1B,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,CAAA;gBACrD,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;oBACjB,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;oBAC/B,MAAM,CAAC,OAAO,EAAE,CAAA;gBAClB,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,KAAK,EAAE,CAAA;gBAChB,CAAC;gBACD,OAAM;YACR,CAAC;YACD,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,CAAA;YAChD,0EAA0E;YAC1E,uEAAuE;YACvE,0EAA0E;YAC1E,kEAAkE;YAClE,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;gBACX,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;gBAC/C,MAAM,CAAC,QAAQ,EAAE,CAAA;gBACjB,IAAI,QAAQ,KAAK,SAAS;oBAAE,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;gBAC9D,OAAM;YACR,CAAC;YACD,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAA;YACzC,0CAA0C;YAC1C,uCAAuC;YACvC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBAClB,MAAM,CAAC,SAAS,EAAE,CAAA;gBAClB,OAAM;YACR,CAAC;YACD,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,EAAE,CAAqB,CAAA;YACjD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;YAChB,MAAM,CAAC,QAAQ,EAAE,CAAA;YACjB,IAAI,QAAQ,KAAK,SAAS;gBAAE,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;QAChE,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,CAAC,KAAK,EAAE,CAAA;QAChB,CAAC;IACH,CAAC,CAAC,CACH,CAAA;IAED,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,CAAA;AAClC,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 易变注入的请求尾部 (`dynamicTail`) — 把「每轮都可能变」的上下文搬到
|
|
3
|
+
* `event.messages` 的最后一条,而不是塞进 `event.system`。
|
|
4
|
+
*
|
|
5
|
+
* 为什么:system 前缀是 provider 前缀缓存最值钱的部分。状态卡每轮都变(账本
|
|
6
|
+
* 动一下、窗口 bucket 跳一格、重试指令出现/消失),它一改,system 里它之后的
|
|
7
|
+
* 每一个 token 都失去缓存命中——一份 ≤300 token 的卡片能让几万 token 的 system
|
|
8
|
+
* 前缀全部作废。把它挪到请求末尾的一条 user 消息,system 就保持逐字节稳定。
|
|
9
|
+
*
|
|
10
|
+
* 形状:
|
|
11
|
+
* - 生产者(状态卡 / 窗口 / 重试指令 / 拆分建议)`set(sid, key, text)` 写进
|
|
12
|
+
* 进程内 sink;每个 key 每会话只有一格(后者覆盖前者)。
|
|
13
|
+
* - 本层注册**最后**一个 `session.hook("context")`(在 prune 之后,所以它追加
|
|
14
|
+
* 的消息不会被同一请求的修剪看见):`take(sid)` 取出并清空,按
|
|
15
|
+
* state → window → retry → advice 的顺序渲染成**一条**消息:
|
|
16
|
+
* `{ id: "team-dynamic", role: "user", content: [{ type: "text", text }] }`。
|
|
17
|
+
* - 宿主会跨请求复用 `event.messages`,所以追加前先剥掉以 `[Team 动态上下文]`
|
|
18
|
+
* 开头的旧尾部——否则每轮多一条,最后挤掉真正的工作。
|
|
19
|
+
*
|
|
20
|
+
* `dynamicTail: "off"` 时本层根本不注册,四个生产者各自走原来的 `event.system`
|
|
21
|
+
* 路径,逐字节与改动前一致(这是回滚路径,也是套件里钉住的对照)。
|
|
22
|
+
*/
|
|
23
|
+
import type { TeamScope } from "./v2-scope.js";
|
|
24
|
+
import type { V2Context, V2Registration } from "./v2-types.js";
|
|
25
|
+
/** 尾部消息的标记:`event.messages` 里首段文本以它开头的那条就是我们的。 */
|
|
26
|
+
export declare const DYNAMIC_TAIL_MARKER = "[Team \u52A8\u6001\u4E0A\u4E0B\u6587]";
|
|
27
|
+
/** 一条尾部消息的 id——便于宿主/测试认出它,不是能力令牌。 */
|
|
28
|
+
export declare const DYNAMIC_TAIL_MESSAGE_ID = "team-dynamic";
|
|
29
|
+
/** 生产者可写的段。 顺序即渲染顺序,见 `DYNAMIC_SECTION_ORDER`。 */
|
|
30
|
+
export type DynamicSection = "state" | "window" | "retry" | "advice";
|
|
31
|
+
/**
|
|
32
|
+
* 渲染顺序是**声明**的,不是 Map 的插入顺序:四个生产者按各自 hook 的注册
|
|
33
|
+
* 顺序写入,若靠插入顺序,重排注册就会重排消息体(一条会被前缀缓存的内容)。
|
|
34
|
+
*/
|
|
35
|
+
export declare const DYNAMIC_SECTION_ORDER: readonly DynamicSection[];
|
|
36
|
+
export interface DynamicSink {
|
|
37
|
+
/** 记下一段易变上下文。空文本被忽略(没有内容就不占位)。 */
|
|
38
|
+
set(sessionID: string, key: DynamicSection, text: string): void;
|
|
39
|
+
/** 取出并清空该会话的全部段。没有内容时返回空 Map(不是 undefined)。 */
|
|
40
|
+
take(sessionID: string): Map<DynamicSection, string>;
|
|
41
|
+
/** 只读当前值(同一请求内 hook 被重放时的幂等判定);不清空。 */
|
|
42
|
+
peek(sessionID: string, key: DynamicSection): string | undefined;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 进程内 sink:`Map<sessionID, Map<key, text>>`。
|
|
46
|
+
*
|
|
47
|
+
* 不做 TTL:`take` 在每个请求的尾部层里清空自己,sink 的生命周期就是「两个
|
|
48
|
+
* hook 之间」——一个会话的残留最多活到它下一次组装请求,且只影响它自己。
|
|
49
|
+
*/
|
|
50
|
+
export declare function createDynamicSink(): DynamicSink;
|
|
51
|
+
/** 一条消息的首段文本(`content[]` 是 v2 的形状,`parts[]` 是旧形状;两者都认)。 */
|
|
52
|
+
export declare function firstTextOf(message: unknown): string;
|
|
53
|
+
/** 是我们上一轮追加的尾部消息吗?marker 前缀或我们铸造的 id,任一即可。 */
|
|
54
|
+
export declare function isDynamicTailMessage(message: unknown): boolean;
|
|
55
|
+
/** 渲染一条尾部消息的正文:首行 marker,每段前一行 `### <段名>`。 */
|
|
56
|
+
export declare function renderDynamicTail(sections: Map<DynamicSection, string>): string;
|
|
57
|
+
/** `dynamicTail: "off"`(以及旧的假值拼写)关闭;其余一律是默认的尾部注入。 */
|
|
58
|
+
export declare function resolveDynamicTailConfig(config?: {
|
|
59
|
+
dynamicTail?: string;
|
|
60
|
+
}): {
|
|
61
|
+
enabled: boolean;
|
|
62
|
+
};
|
|
63
|
+
export interface DynamicTailReport {
|
|
64
|
+
enabled: boolean;
|
|
65
|
+
/** 真的追加了一条尾部消息的请求数。 */
|
|
66
|
+
messages: number;
|
|
67
|
+
/** 这些尾部消息的字符数合计(与 `estimateTokens` 同一口径)。 */
|
|
68
|
+
bytes: number;
|
|
69
|
+
/** 被剥掉的旧尾部消息条数——大于 0 就是「宿主复用了消息数组」的证据。 */
|
|
70
|
+
stripped: number;
|
|
71
|
+
/** sink 为空的请求数(没有易变上下文,一个字节都没追加)。 */
|
|
72
|
+
empty: number;
|
|
73
|
+
/** 是 ours 但请求没带消息数组:sink 内容留着给下一次,不在这里丢。 */
|
|
74
|
+
noMessages: number;
|
|
75
|
+
/** scope 判定非 ours 的请求数(一个字节都不动)。 */
|
|
76
|
+
foreignSkipped: number;
|
|
77
|
+
/** hook 内部抛错(永不外溢,只计数)。 */
|
|
78
|
+
threw: number;
|
|
79
|
+
}
|
|
80
|
+
export interface DynamicTailInput {
|
|
81
|
+
scope?: TeamScope;
|
|
82
|
+
/** `dynamicTail: "off"` → 不注册该层(旧行为逐字节一致)。 */
|
|
83
|
+
enabled?: boolean;
|
|
84
|
+
sink: DynamicSink;
|
|
85
|
+
/** 每个真实注入一行轨迹(`step_id:"v2-tail"` 由人格侧提供)。 */
|
|
86
|
+
onEvent?: (row: Record<string, unknown>) => void;
|
|
87
|
+
}
|
|
88
|
+
export interface DynamicTailLayer {
|
|
89
|
+
registrations: V2Registration[];
|
|
90
|
+
report: DynamicTailReport;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* 注册请求尾部层。**必须是最后一个 `session.hook("context")`**:四个生产者都在
|
|
94
|
+
* 它之前写入 sink,prune 也在它之前看过消息数组,它负责把 sink 的内容收成一条
|
|
95
|
+
* 消息并在同一次请求里剥掉旧尾部。
|
|
96
|
+
*/
|
|
97
|
+
export declare function applyV2DynamicTail(ctx: V2Context, input: DynamicTailInput): Promise<DynamicTailLayer>;
|
|
98
|
+
//# sourceMappingURL=v2-tail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v2-tail.d.ts","sourceRoot":"","sources":["../../src/host/v2-tail.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAoB,MAAM,eAAe,CAAA;AAEhF,kDAAkD;AAClD,eAAO,MAAM,mBAAmB,0CAAiB,CAAA;AAEjD,qCAAqC;AACrC,eAAO,MAAM,uBAAuB,iBAAiB,CAAA;AAErD,kDAAkD;AAClD,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAA;AAEpE;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,SAAS,cAAc,EAA2C,CAAA;AAStG,MAAM,WAAW,WAAW;IAC1B,kCAAkC;IAClC,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/D,+CAA+C;IAC/C,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,GAAG,CAAC,cAAc,EAAE,MAAM,CAAC,CAAA;IACpD,uCAAuC;IACvC,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,cAAc,GAAG,MAAM,GAAG,SAAS,CAAA;CACjE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,WAAW,CA2B/C;AAED,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAUpD;AAED,8CAA8C;AAC9C,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAI9D;AAED,8CAA8C;AAC9C,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,GAAG,CAAC,cAAc,EAAE,MAAM,CAAC,GAAG,MAAM,CAS/E;AAKD,qDAAqD;AACrD,wBAAgB,wBAAwB,CACtC,MAAM,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAoB,GACjD;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAEtB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAA;IACb,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAA;IAChB,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAA;IACb,4CAA4C;IAC5C,UAAU,EAAE,MAAM,CAAA;IAClB,oCAAoC;IACpC,cAAc,EAAE,MAAM,CAAA;IACtB,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,IAAI,EAAE,WAAW,CAAA;IACjB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;CACjD;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,cAAc,EAAE,CAAA;IAC/B,MAAM,EAAE,iBAAiB,CAAA;CAC1B;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAoE3G"}
|