@zhushanwen/pi-smart-context 0.3.0 → 0.3.2

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
@@ -8,15 +8,23 @@
8
8
  - **双模式生成接管**(`session_before_compact`,覆盖工具 / `/compact` / 内建 auto 三条路径):
9
9
  - same-model:完整原始上下文 + 会话原 system prompt + tools + 末尾追加压缩指令——前缀缓存全命中,成本≈增量指令+输出,且模型看全量上下文(质量上限最高)
10
10
  - cross-model:调用 pi 原生 `compact()` 仅换模型与凭证——split-turn / fileOps / previousSummary 原生组装
11
- - **3 档阈值提醒**(默认 200K/400K/600K):`agent_settled` 越档检查,每档一次、多档合并、压缩后重置,followUp 投递;措辞是数据投递不是指令
11
+ - **3 档阈值提醒**(默认 400K/500K/600K):`agent_settled` 越档检查,每档一次、多档合并、压缩后重置,followUp 投递;措辞是数据投递不是指令
12
12
  - **排除模型**(精准 `provider/modelId` 匹配):工具拒绝 + 不提醒 + 回落 pi 原生生成;切换跨界时注入一条可用性通知,downshift(切小窗模型将触线)时建议先压缩
13
13
  - **健壮性**:摘要收缩校验、max-tokens 截断 fail-closed、接管失败 3 次熔断、transcript 回查指针、压缩后最近文件内容重注入(≤5 文件/50K)、多轮压缩降智提示
14
14
  - **subagent 进程**自动静默(`PI_SUBAGENT_ROOT_SESSION_ID` 标记)
15
15
 
16
- ## 配置
16
+ ## 行为门控
17
+
18
+ | 状态 | 工具 execute | 阈值提醒 | 压缩生成接管 |
19
+ |---|---|---|---|
20
+ | enabled,模型未排除 | 放行(低于最低档阈值时拒绝并返回用量建议) | 生效 | 生效(按双模式判定) |
21
+ | enabled,模型命中排除列表 | 拒绝(返回原因) | 跳过 | 跳过(回落 pi 原生生成) |
22
+ | enabled=false | 拒绝("可在设置页开启") | 跳过 | 跳过(回落 pi 原生) |
23
+ | compactModel 未配置/无效 | 放行(same-model 不依赖该配置) | 生效 | same-model 生效;cross-model 回退当前模型,压缩不失败 |
24
+ | 模型切换跨界(model_select) | 常驻不变 | 注入一条可用性变化通知(仅跨界时) | 按新模型即时重判 |
17
25
 
18
- `<agentDir>/config/smart-context-ext-config.json`(读时热加载)。schema 与示例见 `skills/smart-context-ext-config/SKILL.md`。xyz-agent 桌面端在设置页(系统 → 智能上下文压缩)可视化配置。
26
+ 行为正确性由 execute / handler 现场校验兜底,每次事件回调重新读配置(热加载,改完下一 turn 生效,无需重启)。
19
27
 
20
- ## 设计文档
28
+ ## 配置
21
29
 
22
- `docs/extensions/smart-context/design.md`(xyz-agent 仓库)——决策依据、探针记录、验收场景。
30
+ `<agentDir>/config/smart-context-ext-config.json`(读时热加载)。schema 与示例见 `skills/smart-context-ext-config/SKILL.md`。taiji 桌面端在设置页(系统 → 智能上下文压缩)可视化配置。
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@zhushanwen/pi-smart-context",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "type": "module",
5
5
  "main": "index.ts",
6
- "xyz-agent": {
6
+ "taiji": {
7
7
  "role": "universal",
8
8
  "startupConfig": [
9
9
  {
@@ -15,8 +15,8 @@
15
15
  "ref": ""
16
16
  },
17
17
  "reminderThresholds": [
18
- 200000,
19
18
  400000,
19
+ 500000,
20
20
  600000
21
21
  ],
22
22
  "excludedModels": []
@@ -36,9 +36,9 @@
36
36
  "pi-package"
37
37
  ],
38
38
  "dependencies": {
39
- "@zhushanwen/pi-ext-guards": "0.3.0",
40
- "@zhushanwen/pi-extension-logger": "0.6.0",
41
- "@zhushanwen/pi-llm-shared": "0.7.0"
39
+ "@zhushanwen/pi-ext-guards": "0.4.1",
40
+ "@zhushanwen/pi-extension-logger": "0.6.1",
41
+ "@zhushanwen/pi-llm-shared": "0.8.1"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@vitest/coverage-v8": "^4.1.9",
@@ -15,7 +15,7 @@ description: "配置 @zhushanwen/pi-smart-context(智能上下文压缩:agen
15
15
 
16
16
  ## 配置文件
17
17
 
18
- 路径:`<agentDir>/config/smart-context-ext-config.json`(`<agentDir>` = `getAgentDir()`,默认 `~/.pi/agent`,xyz-agent 环境 `~/.xyz-agent/pi/agent`;`PI_CODING_AGENT_DIR` 可覆盖)。
18
+ 路径:`<agentDir>/config/smart-context-ext-config.json`(`<agentDir>` = `getAgentDir()`,默认 `~/.pi/agent`,taiji 环境 `~/.taiji/agent`;`PI_CODING_AGENT_DIR` 可覆盖)。
19
19
 
20
20
  ### Schema
21
21
 
@@ -23,7 +23,7 @@ description: "配置 @zhushanwen/pi-smart-context(智能上下文压缩:agen
23
23
  |---|---|---|---|
24
24
  | `enabled` | boolean | `true` | 总开关 |
25
25
  | `compactModel` | `{type:"ref", ref:string}` | `{type:"ref", ref:""}` | 压缩模型(完整 `provider/modelId`)。`ref` 为空 = 跟随当前会话模型(same-model 模式);等于当前模型同样进 same-model 模式 |
26
- | `reminderThresholds` | `number[]` | `[200000, 400000, 600000]` | 3 档提醒阈值(token 绝对数,升序) |
26
+ | `reminderThresholds` | `number[]` | `[400000, 500000, 600000]` | 3 档提醒阈值(token 绝对数,升序) |
27
27
  | `excludedModels` | `string[]` | `[]` | 排除模型列表,完整 `provider/modelId` 精准等值匹配(如 `"deepseek/deepseek-chat"`),不做前缀匹配 |
28
28
 
29
29
  ### 配置示例
@@ -32,7 +32,7 @@ description: "配置 @zhushanwen/pi-smart-context(智能上下文压缩:agen
32
32
  {
33
33
  "enabled": true,
34
34
  "compactModel": { "type": "ref", "ref": "xiaomi-token-plan-cn/mimo-v2.5" },
35
- "reminderThresholds": [200000, 400000, 600000],
35
+ "reminderThresholds": [400000, 500000, 600000],
36
36
  "excludedModels": ["deepseek/deepseek-chat"]
37
37
  }
38
38
  ```
@@ -52,5 +52,5 @@ description: "配置 @zhushanwen/pi-smart-context(智能上下文压缩:agen
52
52
  - 压缩回退当前模型:`compactModel.ref` 指向的模型不可用(无凭证/已删)——换可用模型或留空
53
53
  - 工具调用被拒「已禁用」/「已排除」:检查 `enabled` 与 `excludedModels`
54
54
  - 提醒未出现:`getContextUsage().tokens` 在压缩后首个响应前为 null,属正常(下轮恢复)
55
- - 连续接管失败 3 次后不再接管:本会话熔断保护,查看 `XYZ_AGENT_DEBUG=1` 日志定位失败原因
56
- - 调试:`XYZ_AGENT_DEBUG=1` 后看 `[smart-context]` 前缀日志(`~/.pi/agent/logs/`)
55
+ - 连续接管失败 3 次后不再接管:本会话熔断保护,查看 `TAIJI_AGENT_DEBUG=1` 日志定位失败原因
56
+ - 调试:`TAIJI_AGENT_DEBUG=1` 后看 `[smart-context]` 前缀日志(`~/.pi/agent/logs/`)
@@ -12,7 +12,6 @@ import {
12
12
  formatK,
13
13
  getCurrentModelId,
14
14
  isGatingActive,
15
- isSubagentProcess,
16
15
  isSummaryInflated,
17
16
  normalizeSmartContextConfig,
18
17
  pickMode,
@@ -23,7 +22,7 @@ describe("normalizeSmartContextConfig", () => {
23
22
  it("非对象输入回退默认值", () => {
24
23
  const c = normalizeSmartContextConfig(null);
25
24
  expect(c).toEqual(DEFAULT_SMART_CONTEXT_CONFIG);
26
- expect(c.reminderThresholds).toEqual([200_000, 400_000, 600_000]);
25
+ expect(c.reminderThresholds).toEqual([400_000, 500_000, 600_000]);
27
26
  });
28
27
 
29
28
  it("阈值过滤非正数并升序、截 3 档;空数组回退默认", () => {
@@ -31,7 +30,7 @@ describe("normalizeSmartContextConfig", () => {
31
30
  expect(c.reminderThresholds).toEqual([100_000, 200_000, 300_000]);
32
31
 
33
32
  const c2 = normalizeSmartContextConfig({ reminderThresholds: [] });
34
- expect(c2.reminderThresholds).toEqual([200_000, 400_000, 600_000]);
33
+ expect(c2.reminderThresholds).toEqual([400_000, 500_000, 600_000]);
35
34
  });
36
35
 
37
36
  it("excludedModels 只留含 / 的字符串条目并去重(精准匹配要求完整 provider/modelId)", () => {
@@ -173,9 +172,6 @@ describe("estimateShadowedTokens 口径契约(D2:与 pi estimateTokens 同
173
172
  });
174
173
  });
175
174
 
176
- describe("subagent 识别(R6)", () => {
177
- it("PI_SUBAGENT_ROOT_SESSION_ID 存在即 subagent", () => {
178
- expect(isSubagentProcess({ PI_SUBAGENT_ROOT_SESSION_ID: "s1" })).toBe(true);
179
- expect(isSubagentProcess({})).toBe(false);
180
- });
181
- });
175
+ // [HISTORICAL] subagent 识别(R6)用例已随本地实现删除移除——现行谓词收敛于
176
+ // ext-guards isSubagentProcess(ext-simplify-17 D4),三态与「宁缺勿污」钉值见
177
+ // extensions/shared/ext-guards/src/__tests__/predicates.test.ts。
@@ -1,5 +1,5 @@
1
1
  /**
2
- * startupConfig 声明守护测试:断言 package.json `xyz-agent.startupConfig` 声明的
2
+ * startupConfig 声明守护测试:断言 package.json `taiji.startupConfig` 声明的
3
3
  * content 与代码 DEFAULT_SMART_CONTEXT_CONFIG 常量深相等,防止两侧任一改动未同步(漂移)。
4
4
  * 机制:runtime 启动序列统一 ensure(extension-startup-config.ts),声明即首建内容。
5
5
  *
@@ -13,7 +13,7 @@ import { describe, expect, it } from "vitest";
13
13
 
14
14
  import { DEFAULT_SMART_CONTEXT_CONFIG } from "../pure.js";
15
15
 
16
- /** package.json `xyz-agent.startupConfig` 声明条目的最小形状(守护断言用)。 */
16
+ /** package.json `taiji.startupConfig` 声明条目的最小形状(守护断言用)。 */
17
17
  interface StartupConfigEntry {
18
18
  path: string;
19
19
  content: unknown;
@@ -21,11 +21,11 @@ interface StartupConfigEntry {
21
21
 
22
22
  const pkg = JSON.parse(
23
23
  readFileSync(join(fileURLToPath(import.meta.url), "../../../package.json"), "utf-8"),
24
- ) as { "xyz-agent"?: { startupConfig?: StartupConfigEntry[] } };
24
+ ) as { "taiji"?: { startupConfig?: StartupConfigEntry[] } };
25
25
 
26
26
  describe("startupConfig 声明守护", () => {
27
27
  it("声明 content 与代码 DEFAULT_SMART_CONTEXT_CONFIG 深相等", () => {
28
- const entry = pkg["xyz-agent"]?.startupConfig?.find(
28
+ const entry = pkg["taiji"]?.startupConfig?.find(
29
29
  (e: StartupConfigEntry) => e.path === "config/smart-context-ext-config.json",
30
30
  );
31
31
  expect(entry).toBeDefined();
@@ -38,7 +38,7 @@ function makePi(): { pi: ExtensionAPI & { sendUserMessage: ReturnType<typeof vi.
38
38
  function makeCtx(compactImpl?: (options: CompactOpts) => void): ExtensionContext {
39
39
  return {
40
40
  model: { provider: "zai", id: "glm" },
41
- getContextUsage: () => ({ tokens: 250_000, contextWindow: 1_000_000 }),
41
+ getContextUsage: () => ({ tokens: 450_000, contextWindow: 1_000_000 }),
42
42
  sessionManager: { getEntries: () => [] },
43
43
  compact: compactImpl ?? ((options: CompactOpts) => {
44
44
  options.onComplete({
@@ -14,6 +14,7 @@
14
14
  import { buildSessionContext, compact as nativeCompact, convertToLlm } from "@earendil-works/pi-coding-agent";
15
15
  import type { CompactionResult, SessionBeforeCompactEvent } from "@earendil-works/pi-coding-agent";
16
16
  import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
17
+ import { toErrorMessage } from "@zhushanwen/pi-ext-guards";
17
18
  import { createLogger } from "@zhushanwen/pi-extension-logger";
18
19
  import { resolveModel } from "@zhushanwen/pi-llm-shared";
19
20
  import { readFileSync } from "node:fs";
@@ -57,7 +58,7 @@ export function createTakeoverState(): TakeoverState {
57
58
  /** 统一 logger(@zhushanwen/pi-extension-logger:debug 文件日志 / warn 走 appendEntry 持久化)。 */
58
59
  const logger = createLogger("smart-context");
59
60
 
60
- /** 开发调试日志(XYZ_AGENT_DEBUG=1 时写文件,默认 no-op;logging-conventions 统一通道)。 */
61
+ /** 开发调试日志(TAIJI_AGENT_DEBUG=1 时写文件,默认 no-op;logging-conventions 统一通道)。 */
61
62
  export function debugLog(message: string): void {
62
63
  logger.debug(message);
63
64
  }
@@ -319,7 +320,7 @@ export function createBeforeCompactHandler(
319
320
  return { compaction: result };
320
321
  } catch (error) {
321
322
  state.failStreak += 1;
322
- warnLog("takeover error, falling back to native", { error: error instanceof Error ? error.message : String(error) });
323
+ warnLog("takeover error, falling back to native", { error: toErrorMessage(error) });
323
324
  return {}; // D7 回退
324
325
  }
325
326
  };
package/src/index.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * @zhushanwen/pi-smart-context 入口:事件接线 + 门控。
3
3
  *
4
- * 设计文档:docs/extensions/smart-context/design.md
5
4
  * - session_start:session 级闭包状态重建(规范 Session 隔离:fired 档位/熔断计数不跨 session)
6
5
  * - subagent 进程(R6):不注册工具、不提醒(宁缺勿污)
7
6
  * - session_before_compact:双模式接管(compact-handler)
@@ -11,7 +10,7 @@
11
10
  */
12
11
 
13
12
  import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
14
- import { guardStaleCtx, toErrorMessage } from "@zhushanwen/pi-ext-guards";
13
+ import { guardStaleCtx, isSubagentProcess, toErrorMessage } from "@zhushanwen/pi-ext-guards";
15
14
  import { setPiHandle } from "@zhushanwen/pi-extension-logger";
16
15
 
17
16
  import {
@@ -27,7 +26,6 @@ import {
27
26
  findCrossedThresholds,
28
27
  getCurrentModelId,
29
28
  isGatingActive,
30
- isSubagentProcess,
31
29
  loadSmartContextConfig,
32
30
  type EntryLike,
33
31
  } from "./pure.js";
@@ -63,7 +61,8 @@ export default function smartContextExtension(pi: ExtensionAPI): void {
63
61
  // 日志通道注入(extension-logger 两阶段初始化:工厂拿 pi → setPiHandle)
64
62
  setPiHandle(pi);
65
63
 
66
- // R6:subagent 子进程不注册工具、不提醒(PI_SUBAGENT_ROOT_SESSION_ID 标记)
64
+ // R6:subagent 子进程不注册工具、不提醒(宁缺勿污;TAIJI_AGENT_SUBAGENT 标记——
65
+ // ext-guards isSubagentProcess,ext-simplify-17 D4 重锚)
67
66
  if (isSubagentProcess()) {
68
67
  debugLog("subagent process detected, staying inert");
69
68
  return;
package/src/llm.ts CHANGED
@@ -14,6 +14,7 @@ import { completeSimple } from "@earendil-works/pi-ai/compat";
14
14
  import type { Context as LlmContext, SimpleStreamOptions } from "@earendil-works/pi-ai/compat";
15
15
  import type { Tool as LlmTool, Message, Model } from "@earendil-works/pi-ai";
16
16
  import type { ExtensionContext, ToolInfo } from "@earendil-works/pi-coding-agent";
17
+ import { toErrorMessage } from "@zhushanwen/pi-ext-guards";
17
18
 
18
19
  /**
19
20
  * ToolInfo → pi-ai Tool 投影:三字段直取。parameters 是 typebox schema(主会话同源对象,
@@ -127,6 +128,6 @@ export async function callSameModelCompaction(
127
128
  const text = resp.content.map(blockText).join("\n").trim();
128
129
  return { ok: true, text, usage: resp.usage, stopReason: resp.stopReason };
129
130
  } catch (error) {
130
- return { ok: false, error: error instanceof Error ? error.message : String(error) };
131
+ return { ok: false, error: toErrorMessage(error) };
131
132
  }
132
133
  }
package/src/pure.ts CHANGED
@@ -2,12 +2,12 @@
2
2
  * 纯函数层:配置 schema / 加载 / 门控判定 / 阈值检查 / 摘要后处理。
3
3
  *
4
4
  * 无副作用(fs 读取经 llm-shared loadConfig 的缓存封装),全部可单测。
5
- * 设计文档:docs/extensions/smart-context/design.md(D5 门控矩阵 / D6 阈值保护 / D8 配置 schema)。
6
5
  */
7
6
 
8
7
  import { estimateTokens } from "@earendil-works/pi-coding-agent";
8
+ import { isRecord } from "@zhushanwen/pi-ext-guards";
9
9
  import type { ModelSelector } from "@zhushanwen/pi-llm-shared";
10
- import { loadConfig } from "@zhushanwen/pi-llm-shared";
10
+ import { loadConfig, normalizeModelSelector } from "@zhushanwen/pi-llm-shared";
11
11
 
12
12
  // ──────────────────────── 配置 schema(D8) ────────────────────────
13
13
 
@@ -18,9 +18,9 @@ export const CHARS_PER_TOKEN_ESTIMATE = 4;
18
18
  /** 提醒阈值最大档数(3 档)。 */
19
19
  const MAX_THRESHOLD_TIERS = 3;
20
20
 
21
- /** 3 档提醒阈值默认值(token 绝对数):200K / 400K / 600K。 */
22
- const DEFAULT_REMINDER_THRESHOLD_TIER_1_TOKENS = 200_000;
23
- const DEFAULT_REMINDER_THRESHOLD_TIER_2_TOKENS = 400_000;
21
+ /** 3 档提醒阈值默认值(token 绝对数):400K / 500K / 600K。 */
22
+ const DEFAULT_REMINDER_THRESHOLD_TIER_1_TOKENS = 400_000;
23
+ const DEFAULT_REMINDER_THRESHOLD_TIER_2_TOKENS = 500_000;
24
24
  const DEFAULT_REMINDER_THRESHOLD_TIER_3_TOKENS = 600_000;
25
25
  const DEFAULT_REMINDER_THRESHOLDS: readonly number[] = [
26
26
  DEFAULT_REMINDER_THRESHOLD_TIER_1_TOKENS,
@@ -59,13 +59,8 @@ export function normalizeSmartContextConfig(raw: unknown): SmartContextConfig {
59
59
 
60
60
  const enabled = typeof r.enabled === "boolean" ? r.enabled : base.enabled;
61
61
 
62
- const rawModel = typeof r.compactModel === "object" && r.compactModel !== null
63
- ? (r.compactModel as Record<string, unknown>)
64
- : null;
65
62
  const compactModel: ModelSelector =
66
- rawModel?.type === "ref" && typeof rawModel.ref === "string"
67
- ? { type: "ref", ref: rawModel.ref }
68
- : { type: "ref", ref: "" };
63
+ normalizeModelSelector(r.compactModel) ?? { type: "ref", ref: "" };
69
64
 
70
65
  const rawThresholds = Array.isArray(r.reminderThresholds)
71
66
  ? r.reminderThresholds
@@ -249,16 +244,6 @@ export function buildReinjectSection(contents: ReadonlyArray<{ path: string; con
249
244
  return `\n\n<recently-read-files>\n${parts.join("\n\n")}\n</recently-read-files>`;
250
245
  }
251
246
 
252
- // ──────────────────────── subagent 识别(R6) ────────────────────────
253
-
254
- /**
255
- * subagent 子进程检测(D9/R6):subagent-core session-runner 无条件注入 PI_SUBAGENT_ROOT_SESSION_ID。
256
- * 命中 → 本进程不注册工具、不提醒(宁缺勿污)。
257
- */
258
- export function isSubagentProcess(env: NodeJS.ProcessEnv = process.env): boolean {
259
- return env.PI_SUBAGENT_ROOT_SESSION_ID !== undefined;
260
- }
261
-
262
247
  // ──────────────────────── session entries 统计(D13 纯函数) ────────────────────────
263
248
 
264
249
  /** sessionManager entries 的宽松形状(降智计数)。 */
@@ -271,11 +256,6 @@ export function countCompactions(entries: ReadonlyArray<EntryLike>): number {
271
256
  return entries.filter((e) => e.type === "compaction").length;
272
257
  }
273
258
 
274
- /** unknown 的对象收窄(Record 视图;字段消费再经 typeof / Array.isArray 收窄)。 */
275
- function isRecord(value: unknown): value is Record<string, unknown> {
276
- return typeof value === "object" && value !== null;
277
- }
278
-
279
259
  /**
280
260
  * 保留段已 Read 的文件集合(D13-11 去重:重注入跳过保留段已有的 Read 结果)。
281
261
  * 保留段 = branchEntries 中 firstKeptEntryId 之后的 message entries;从其 toolCall 参数提取 path。
package/src/tool.ts CHANGED
@@ -10,7 +10,7 @@
10
10
  */
11
11
 
12
12
  import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
13
- import { guardStaleCtx, toErrorMessage } from "@zhushanwen/pi-ext-guards";
13
+ import { guardStaleCtx, isRecord, toErrorMessage } from "@zhushanwen/pi-ext-guards";
14
14
  import { Type } from "typebox";
15
15
 
16
16
  import { debugLog } from "./compact-handler.js";
@@ -66,11 +66,6 @@ const TOOL_DESCRIPTION =
66
66
  "2) 后续工作不再依赖将被压缩的早期细节;3) 上下文已超过提醒阈值(你会收到 [smart-context 提示])。" +
67
67
  "若任一条件不满足,不要调用。";
68
68
 
69
- /** unknown 的对象收窄(Record 视图;字段消费再经 typeof 收窄)。 */
70
- function isRecord(value: unknown): value is Record<string, unknown> {
71
- return typeof value === "object" && value !== null;
72
- }
73
-
74
69
  /** CompactionResult → 宽松形状的 guard 转换(onComplete 回调参数消费,避免 cast)。 */
75
70
  function toCompactionResultLike(result: unknown): CompactionResultLike {
76
71
  const r: Record<string, unknown> = isRecord(result) ? result : {};
@@ -150,8 +145,8 @@ export function registerCompactContextTool(
150
145
  const config = loadSmartContextConfig();
151
146
  if (!gating.active) {
152
147
  const reason = config.enabled
153
- ? `当前模型 ${gating.modelId} 已配置为排除(smart-context excludedModels),压缩工具不可用。可在 xyz-agent 设置页或 smart-context-ext-config skill 中调整。`
154
- : `smart-context 已禁用。可在 xyz-agent 设置页开启,或经 smart-context-ext-config skill 修改配置。`;
148
+ ? `当前模型 ${gating.modelId} 已配置为排除(smart-context excludedModels),压缩工具不可用。可在 taiji 设置页或 smart-context-ext-config skill 中调整。`
149
+ : `smart-context 已禁用。可在 taiji 设置页开启,或经 smart-context-ext-config skill 修改配置。`;
155
150
  throw new Error(reason);
156
151
  }
157
152
 
@@ -190,7 +185,7 @@ export function registerCompactContextTool(
190
185
  : "未知";
191
186
  const showHint = compactionCount + 1 >= DEGRADATION_HINT_MIN_COMPACTIONS;
192
187
  const lines = [
193
- `[smart-context] 压缩完成。模式:${resultMode}${fellBack ? "(压缩模型不可用,已回退当前模型——请检查配置:xyz-agent 设置页或 smart-context-ext-config skill)" : ""}。`,
188
+ `[smart-context] 压缩完成。模式:${resultMode}${fellBack ? "(压缩模型不可用,已回退当前模型——请检查配置:taiji 设置页或 smart-context-ext-config skill)" : ""}。`,
194
189
  `压缩前 ${formatK(result.tokensBefore ?? 0)} tokens → 压缩后约 ${formatK(result.estimatedTokensAfter ?? 0)} tokens;摘要生成成本:${cost}。`,
195
190
  showHint ? buildDegradationHintLine() : "",
196
191
  ].filter((l) => l !== "");
package/vitest.config.ts CHANGED
@@ -1,9 +1,7 @@
1
- import { defineConfig } from "vitest/config";
1
+ import { taijiTestConfig } from "../../../test-guard/factory.ts"
2
2
 
3
- export default defineConfig({
3
+ export default taijiTestConfig({
4
4
  test: {
5
- reporters: ["default", "junit"],
6
- outputFile: { junit: "./test-results/vitest-junit.xml" },
7
5
  include: ["src/__tests__/**/*.test.ts"],
8
6
  },
9
7
  });