@zhushanwen/pi-smart-context 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
  - cross-model:调用 pi 原生 `compact()` 仅换模型与凭证——split-turn / fileOps / previousSummary 原生组装
11
11
  - **3 档阈值提醒**(默认 400K/500K/600K):`agent_settled` 越档检查,每档一次、多档合并、压缩后重置,nextTurn 投递(随下一次 prompt 注入,不自起 run);已提醒档位经 `pi.appendEntry` 落在 session entries(`smart-context:fired`),reload / 进程重启后从 entries 重建,同一档不会重复提醒;措辞是数据投递不是指令
12
12
  - **排除模型**(精准 `provider/modelId` 匹配):工具拒绝 + 不提醒 + 回落 pi 原生生成;切换跨界时注入一条可用性通知,downshift(切小窗模型将触线)时建议先压缩
13
- - **通知车道**:压缩结果 / 阈值提醒 / 模型切换四类通知统一走 nextTurn(custom role 随下次 prompt 注入,不自起 run)——工具压缩掐断的 turn 由 taiji runtime 在 `compaction_end` 判定后经投递内核追加续跑投递(详情见仓库设计文档 delivery-ownership-kernel)
13
+ - **通知车道**:压缩结果 / 阈值提醒 / 模型切换四类通知统一走 nextTurn(custom role 随下次 prompt 注入,不自起 run)——工具压缩掐断的 turn 由 taiji runtime 在 `compaction_end` 判定后经投递内核追加续跑投递
14
14
  - **健壮性**:摘要收缩校验、max-tokens 截断 fail-closed、接管失败 3 次熔断(本 session 内停止接管)、transcript 回查指针、压缩后最近文件内容重注入(≤5 文件/50K)、多轮压缩降智提示(累计压缩 ≥2 次后附加)
15
15
  - **subagent 进程**自动静默(`TAIJI_AGENT_SUBAGENT` 标记)
16
16
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhushanwen/pi-smart-context",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "type": "module",
5
5
  "main": "index.ts",
6
6
  "taiji": {
@@ -36,10 +36,10 @@
36
36
  "pi-package"
37
37
  ],
38
38
  "dependencies": {
39
- "@zhushanwen/extension-protocol": "0.21.0",
39
+ "@zhushanwen/extension-protocol": "0.23.0",
40
40
  "@zhushanwen/pi-ext-guards": "0.5.0",
41
41
  "@zhushanwen/pi-extension-logger": "0.6.2",
42
- "@zhushanwen/pi-llm-shared": "0.11.3"
42
+ "@zhushanwen/pi-llm-shared": "0.12.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@vitest/coverage-v8": "^4.1.9",
@@ -5,7 +5,7 @@
5
5
  // wrapper(() => isCtxStale())——registerCompactContextTool 在 factory 体同步执行,简写
6
6
  // 属性 { isCtxStale } 会把该行时刻的初始 () => false 快照进 deps 对象,session_start
7
7
  // handler 内的重新赋值不回写已构造对象 → compact onComplete/onError(E1 实锤崩溃点)
8
- // 守卫的前置代际检查恒不生效,stale 分诊 100% 退化为 PS-30 文案兜底。
8
+ // 检查的前置代际检查恒不生效,stale 分诊 100% 退化为 PS-30 文案兜底。
9
9
  //
10
10
  // 可区分快照 vs live 的唯一拓扑是 factory 重跑(生产主路径:pi 每次 session 替换
11
11
  // newSession/fork/switchSession 都重跑 factory 函数体,loader.ts extensionCache 只缓存
@@ -31,7 +31,7 @@ describe("pi SDK 契约(compact 接管路径依赖的导出形状)", () => {
31
31
  ];
32
32
  const ctx = buildSessionContext(entries as never);
33
33
  expect(Array.isArray(ctx.messages)).toBe(true);
34
- // compaction entry 投影为一条消息 + 保留段消息(旧摘要在前缀中,D12 same-mode 前提)
34
+ // compaction entry 派生为一条消息 + 保留段消息(旧摘要在前缀中,D12 same-mode 前提)
35
35
  expect(ctx.messages.length).toBeGreaterThanOrEqual(2);
36
36
  });
37
37
 
@@ -83,7 +83,7 @@ interface SessionManagerSessionFileLike {
83
83
  }
84
84
 
85
85
  /**
86
- * sessionManager 会话文件访问形状的运行时守卫(D13-4):
86
+ * sessionManager 会话文件访问形状的运行时检查(D13-4):
87
87
  * 只收窄到对象(字段存在性/类型由消费侧可选链 + ?? 兜底,与原语义一致)。
88
88
  */
89
89
  function isSessionManagerSessionFileLike(sm: unknown): sm is SessionManagerSessionFileLike {
@@ -95,7 +95,7 @@ function isSessionManagerSessionFileLike(sm: unknown): sm is SessionManagerSessi
95
95
  * getSessionFile 若不可得则返回空串(指针省略,不失败)。
96
96
  */
97
97
  function getSessionFilePath(ctx: ExtensionContext): string {
98
- // 经 unknown 再守卫:sessionFile 是 sessionManager 的类型未暴露字段(宽于其声明)
98
+ // 经 unknown 再检查:sessionFile 是 sessionManager 的类型未暴露字段(宽于其声明)
99
99
  const sm: unknown = ctx.sessionManager;
100
100
  const accessor = isSessionManagerSessionFileLike(sm) ? sm : undefined;
101
101
  try {
package/src/index.ts CHANGED
@@ -150,7 +150,7 @@ export default function smartContextExtension(pi: ExtensionAPI): void {
150
150
  // isCtxStale 必须传 live 绑定 wrapper 而非简写属性:本行在 factory 体同步执行,简写
151
151
  // { isCtxStale } 会把此刻的初始 () => false 快照进 deps 对象,上方 session_start
152
152
  // handler 的重新赋值不回写已构造对象 → compact onComplete/onError(E1 实锤崩溃点)
153
- // 守卫的前置代际检查恒不生效。wrapper 每次调用读闭包当前绑定。
153
+ // 检查的前置代际检查恒不生效。wrapper 每次调用读闭包当前绑定。
154
154
  registerCompactContextTool(pi, { isCtxStale: () => isCtxStale() });
155
155
 
156
156
  // ── 阈值提醒(D3/D4):agent_settled 越档检查 + marker 持久化 + nextTurn 一次性投递 ──
@@ -184,7 +184,7 @@ export default function smartContextExtension(pi: ExtensionAPI): void {
184
184
  // 会在 agent 空闲后自起一个提醒 run,与用户消息同抢 prompt 跑道(故事 C 的三重放大器之一)。
185
185
  // 防循环:crossed 全部已标记 fired,marker 与提醒触发的 settled 不会重复发。
186
186
  // 事件回调内直接调用捕获的 pi——session 替换窗口可能 stale(crash-resilience D1
187
- // 普查接入点),守卫 stale 静默降级(不杀 pi 进程),非 stale 错误原样上抛。
187
+ // 普查接入点),检查 stale 静默降级(不杀 pi 进程),非 stale 错误原样上抛。
188
188
  guardStaleCtx(() => {
189
189
  sendSmartContextNotice(pi, message, "threshold-reminder");
190
190
  }, {
@@ -211,7 +211,7 @@ export default function smartContextExtension(pi: ExtensionAPI): void {
211
211
  debugLog(`switch notice: ${nowExcluded ? "unavailable" : "available"} (${modelId})`);
212
212
  // 状态通知(非紧急):triggerTurn:false 不唤醒轮次——LLM 在下一轮自然看到并自行
213
213
  // 调整(compact 工具 execute 有运行时门控校验兜底),不为通知烧一整轮全量上下文。
214
- // session 替换窗口可能 stale(D1 普查接入点)——守卫 stale 静默降级
214
+ // session 替换窗口可能 stale(D1 普查接入点)——检查 stale 静默降级
215
215
  guardStaleCtx(() => {
216
216
  sendSmartContextNotice(pi, notice, "model-switch");
217
217
  }, {
@@ -232,7 +232,7 @@ export default function smartContextExtension(pi: ExtensionAPI): void {
232
232
  if (downshift && isGatingActive(config, modelId)) {
233
233
  debugLog("downshift notice fired");
234
234
  // "建议"非紧急(同 S1 裁决):triggerTurn:false 不唤醒轮次,用户继续对话时
235
- // LLM 自行决策是否先压缩。session 替换窗口可能 stale(D1 普查接入点)——守卫 stale 静默降级
235
+ // LLM 自行决策是否先压缩。session 替换窗口可能 stale(D1 普查接入点)——检查 stale 静默降级
236
236
  guardStaleCtx(() => {
237
237
  sendSmartContextNotice(pi, downshift, "model-downshift");
238
238
  }, {
package/src/llm.ts CHANGED
@@ -17,7 +17,7 @@ import type { ExtensionContext, ToolInfo } from "@earendil-works/pi-coding-agent
17
17
  import { toErrorMessage } from "@zhushanwen/pi-ext-guards";
18
18
 
19
19
  /**
20
- * ToolInfo → pi-ai Tool 投影:三字段直取。parameters 是 typebox schema(主会话同源对象,
20
+ * ToolInfo → pi-ai Tool 派生视图:三字段直取。parameters 是 typebox schema(主会话同源对象,
21
21
  * 序列化后与主请求一致——缓存对齐的关键是不改造、原样透传)。
22
22
  */
23
23
  export function projectTools(toolInfos: readonly ToolInfo[]): LlmTool[] {
@@ -67,11 +67,11 @@ export interface SameModelCallOptions {
67
67
  systemPrompt: string;
68
68
  /** 完整上下文 messages + 末尾已追加的压缩指令 message。 */
69
69
  messages: Message[];
70
- /** 主会话工具投影(缓存对齐)。 */
70
+ /** 主会话工具派生视图(缓存对齐)。 */
71
71
  tools: LlmTool[];
72
72
  signal?: AbortSignal;
73
73
  sessionId?: string;
74
- /** 工具投影与 LLM 调用的依赖注入(单测 mock 点)。 */
74
+ /** 工具派生视图与 LLM 调用的依赖注入(单测 mock 点)。 */
75
75
  deps?: {
76
76
  getApiKeyAndHeaders?: (model: Model<never> | Model<string>) => Promise<{ ok: true; apiKey?: string; headers?: Record<string, string>; env?: Record<string, string> } | { ok: false; error: string }>;
77
77
  call?: (model: Model<never> | Model<string>, context: LlmContext, options: SimpleStreamOptions) => Promise<SimpleResponseLike>;
package/src/notices.ts CHANGED
@@ -9,12 +9,12 @@
9
9
  * `Agent is already processing` 拒绝。
10
10
  *
11
11
  * 语义定性(设计 D4「C-ext-19 合规定性」四类两分):
12
- * - 阈值提醒 / model_select 两条 = **提醒语义**(与 scheduler 2026-09-15 销账先例同类:
12
+ * - 阈值提醒 / model_select 两条 = **提醒语义**(与 scheduler 2026-09-15 逐条处理完毕先例同类:
13
13
  * 提醒不承载必须必达的结果);
14
14
  * - 压缩结果 onComplete / onError = **结果语义**,本改造是**存量域内改判而非新建
15
15
  * at-most-once 通道**:原 steer 通道即 at-most-once 且自起 run,nextTurn 化后必达性
16
- * (常驻至被消费)与运行面(不自起 run)同时持平或改善;账本化正向要求的完整迁移维持
17
- * pi-boundary-reliability 附录 B 挂账不变(设计 §1.3 Out)。
16
+ * (常驻至被消费)与运行侧(不自起 run)同时持平或改善;账本化正向要求的完整迁移维持
17
+ * pi-boundary-reliability 附录 B 挂着不处理不变(设计 §1.3 Out)。
18
18
  *
19
19
  * 已接受代价(设计 D4 四要素):阈值提醒不再于 agent 空闲时立即生效,改为随用户下一条消息
20
20
  * 注入——pi 内建 overflow/threshold 自动压缩兜底在场,无人在场时上下文可能持续增长。
package/src/tool.ts CHANGED
@@ -125,7 +125,7 @@ export function registerCompactContextTool(
125
125
  * G1 代际检测(crash-resilience D1):compact 是 fire-and-forget——onComplete/onError
126
126
  * 回调在压缩 LLM 调用期间异步触发,用户此间切换/重载 session 后回调持有的 pi 已
127
127
  * stale(E1 实锤崩溃点)。index.ts 注入模块级代数比对闭包,前置检查 + 错误分诊
128
- * 双保险;缺省时守卫退化为纯文案兜底分诊(PS-30 门禁守文案)。
128
+ * 双保险;缺省时检查退化为纯文案兜底分诊(PS-30 门禁守文案)。
129
129
  */
130
130
  isCtxStale?: () => boolean;
131
131
  },
@@ -192,8 +192,8 @@ export function registerCompactContextTool(
192
192
  // session/新建/重载高频触发)下 sendMessage 命中 stale ctx 同步抛错即
193
193
  // 杀死 pi 进程(pi 1.0.0 实装:dist/core/extensions/loader.js 的 assertActive
194
194
  // wrapper 对 stale 即 throw "no longer active",在 runtime 调用前同步 throw)。
195
- // 守卫 stale 静默降级(结果不投递,用户可重试 /compact),非
196
- // stale 错误原样上抛(守卫不吞真实 bug)。
195
+ // 检查 stale 静默降级(结果不投递,用户可重试 /compact),非
196
+ // stale 错误原样上抛(检查不吞真实 bug)。
197
197
  onComplete: (r: unknown) => {
198
198
  guardStaleCtx(() => {
199
199
  const result = toCompactionResultLike(r);
@@ -218,7 +218,7 @@ export function registerCompactContextTool(
218
218
  });
219
219
  },
220
220
  onError: (err: Error) => {
221
- // 压缩本身的失败信息先落日志(守卫体外——stale 降级时该观测保留)
221
+ // 压缩本身的失败信息先落日志(检查体外——stale 降级时该观测保留)
222
222
  debugLog(`compact_context error: ${err.message}`);
223
223
  guardStaleCtx(() => {
224
224
  sendSmartContextNotice(