@zhushanwen/pi-smart-context 0.1.4 → 0.2.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhushanwen/pi-smart-context",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"xyz-agent": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@zhushanwen/pi-extension-logger": "0.4.1",
|
|
40
|
-
"@zhushanwen/pi-llm-shared": "0.
|
|
40
|
+
"@zhushanwen/pi-llm-shared": "0.6.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@vitest/coverage-v8": "^4.1.9",
|
|
@@ -43,14 +43,17 @@ function makeEvent(overrides?: Partial<BeforeCompactLikeEvent["preparation"]>):
|
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
function makeCtx(): ExtensionContext {
|
|
46
|
+
function makeCtx(crossModel?: { provider: string; id: string } | null): ExtensionContext {
|
|
47
47
|
return {
|
|
48
48
|
model: { provider: "zai", id: "glm" },
|
|
49
49
|
getSystemPrompt: () => "sys",
|
|
50
50
|
sessionManager: { getSessionId: () => "s1", getSessionFile: () => "/tmp/s1.jsonl" },
|
|
51
51
|
modelRegistry: {
|
|
52
52
|
getApiKeyAndHeaders: async () => ({ ok: true, apiKey: "k" }),
|
|
53
|
-
|
|
53
|
+
// resolveRef 精确匹配:仅 (provider,id) 同时命中时返回模型(配合 hasConfiguredAuth 放行)
|
|
54
|
+
find: (provider: string, id: string) =>
|
|
55
|
+
crossModel && provider === crossModel.provider && id === crossModel.id ? crossModel : null,
|
|
56
|
+
hasConfiguredAuth: () => crossModel != null,
|
|
54
57
|
},
|
|
55
58
|
} as unknown as ExtensionContext;
|
|
56
59
|
}
|
|
@@ -84,11 +87,12 @@ describe("session_before_compact 接管 handler", () => {
|
|
|
84
87
|
expect(mockedCall).not.toHaveBeenCalled();
|
|
85
88
|
});
|
|
86
89
|
|
|
87
|
-
it("same-model 成功 → compaction 带 engine/mode 标记 + preamble + fileOps 清单 + transcript 指针", async () => {
|
|
90
|
+
it("same-model 成功 → compaction 带 engine/mode/model 标记 + preamble + fileOps 清单 + transcript 指针", async () => {
|
|
88
91
|
mockedCall.mockResolvedValue({ ok: true, text: "summary body", usage: { input: 1, output: 2 } });
|
|
89
92
|
const { handler } = makeHandler(normalizeSmartContextConfig({ compactModel: { type: "ref", ref: "" } }));
|
|
90
93
|
const decision = await handler(makeEvent(), makeCtx());
|
|
91
|
-
|
|
94
|
+
// details.model = `${ctx.model.provider}/${ctx.model.id}`(§3.3 ①,用量归属数据源)
|
|
95
|
+
expect(decision.compaction?.details).toEqual({ engine: "smart-context", mode: "same-model", model: "zai/glm" });
|
|
92
96
|
expect(decision.compaction?.summary).toContain("summary body");
|
|
93
97
|
// D13-9 preamble 在最前;D11-2 fileOps;D13-4 transcript
|
|
94
98
|
expect(decision.compaction?.summary.startsWith("This is an automatically generated checkpoint")).toBe(true);
|
|
@@ -115,6 +119,32 @@ describe("session_before_compact 接管 handler", () => {
|
|
|
115
119
|
expect(mockedNative).not.toHaveBeenCalled();
|
|
116
120
|
});
|
|
117
121
|
|
|
122
|
+
it("cross-model 成功 → details.model=compactModel 解析结果,native details 字段保留", async () => {
|
|
123
|
+
mockedNative.mockResolvedValue({
|
|
124
|
+
summary: "native checkpoint",
|
|
125
|
+
firstKeptEntryId: "kept-1",
|
|
126
|
+
tokensBefore: 500_000,
|
|
127
|
+
usage: {
|
|
128
|
+
input: 5, output: 6, cacheRead: 0, cacheWrite: 0, totalTokens: 11,
|
|
129
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
130
|
+
},
|
|
131
|
+
details: { nativeMarker: "keep" },
|
|
132
|
+
});
|
|
133
|
+
const { handler } = makeHandler(
|
|
134
|
+
normalizeSmartContextConfig({ compactModel: { type: "ref", ref: "xiaomi/mimo" } }),
|
|
135
|
+
);
|
|
136
|
+
const decision = await handler(makeEvent(), makeCtx({ provider: "xiaomi", id: "mimo" }));
|
|
137
|
+
// details.model = `${resolveModel(...).provider}/${id}`(§3.3 ①);native details 字段原样保留(spread 增量,不改变其他字段)
|
|
138
|
+
expect(decision.compaction?.details).toEqual({
|
|
139
|
+
engine: "smart-context",
|
|
140
|
+
mode: "cross-model",
|
|
141
|
+
model: "xiaomi/mimo",
|
|
142
|
+
nativeMarker: "keep",
|
|
143
|
+
});
|
|
144
|
+
// nativeCompact 收到的 model 就是解析结果(details.model 与实际执行模型同源)
|
|
145
|
+
expect(mockedNative.mock.calls[0][1]).toEqual({ provider: "xiaomi", id: "mimo" });
|
|
146
|
+
});
|
|
147
|
+
|
|
118
148
|
it("收缩校验失败(摘要 ≥ 被压段)→ 拒绝 + 同段记录不重试(D13-1)", async () => {
|
|
119
149
|
mockedCall.mockResolvedValue({ ok: true, text: "z".repeat(10_000) });
|
|
120
150
|
const { handler, state } = makeHandler(normalizeSmartContextConfig({}));
|
package/src/compact-handler.ts
CHANGED
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
* - same-model 模式:完整上下文 + 会话原 system prompt + tools + 末尾追加压缩指令(kv-cache 前缀命中)
|
|
7
7
|
* - cross-model 模式:直接调用包导出的 compact(preparation, 压缩Model, ...)(原生组装零复刻,R4 结论)
|
|
8
8
|
*
|
|
9
|
-
* 输出 CompactionResult.details 携带 {engine:"smart-context", mode} 标记(D1 entry 标记)。
|
|
9
|
+
* 输出 CompactionResult.details 携带 {engine:"smart-context", mode, model} 标记(D1 entry 标记)。
|
|
10
|
+
* model = `${model.provider}/${model.id}`(执行压缩的实际模型)——用量页 compaction 归属数据源
|
|
11
|
+
* (usage-page-fixes §3.3 ①);pi appendCompaction 对 details 逐字透传落盘(pi-semantics PS-28)。
|
|
10
12
|
*/
|
|
11
13
|
|
|
12
14
|
import { buildSessionContext, compact as nativeCompact, convertToLlm } from "@earendil-works/pi-coding-agent";
|
|
@@ -93,6 +95,8 @@ function warnLog(message: string, data?: unknown): void {
|
|
|
93
95
|
export interface SmartContextDetails {
|
|
94
96
|
engine: "smart-context";
|
|
95
97
|
mode: "same-model" | "cross-model";
|
|
98
|
+
/** 执行压缩的模型 `${provider}/${modelId}`(用量归属数据源,usage-page-fixes §3.3 ①)。 */
|
|
99
|
+
model: string;
|
|
96
100
|
}
|
|
97
101
|
|
|
98
102
|
/** sessionManager 上会话文件字段/方法的宽松形状(D13-4,消费侧可选链兜底)。 */
|
|
@@ -219,7 +223,11 @@ async function generateSameMode(
|
|
|
219
223
|
firstKeptEntryId: event.preparation.firstKeptEntryId,
|
|
220
224
|
tokensBefore: event.preparation.tokensBefore,
|
|
221
225
|
usage: result.usage as CompactionResult["usage"],
|
|
222
|
-
details: {
|
|
226
|
+
details: {
|
|
227
|
+
engine: "smart-context",
|
|
228
|
+
mode: "same-model",
|
|
229
|
+
model: `${model.provider}/${model.id}`,
|
|
230
|
+
} satisfies SmartContextDetails,
|
|
223
231
|
};
|
|
224
232
|
}
|
|
225
233
|
|
|
@@ -266,7 +274,12 @@ async function generateCrossMode(
|
|
|
266
274
|
// D13-2:原生 compact 内部对截断的处理沿用原生语义;此处补 engine 标记
|
|
267
275
|
return {
|
|
268
276
|
...result,
|
|
269
|
-
details: {
|
|
277
|
+
details: {
|
|
278
|
+
...(result.details as object | undefined),
|
|
279
|
+
engine: "smart-context",
|
|
280
|
+
mode: "cross-model",
|
|
281
|
+
model: `${model.provider}/${model.id}`,
|
|
282
|
+
} as SmartContextDetails,
|
|
270
283
|
};
|
|
271
284
|
}
|
|
272
285
|
|