mocode-ai 1.2.7 → 1.2.9

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.
Files changed (129) hide show
  1. package/dist/agent/core.js +126 -43
  2. package/dist/config/index.js +31 -6
  3. package/dist/config/presets.js +36 -1
  4. package/dist/context/budget.js +5 -16
  5. package/dist/llm/index.js +42 -4
  6. package/dist/repl/index.js +57 -13
  7. package/dist/session/compact.js +329 -40
  8. package/dist/session/notes.js +63 -0
  9. package/dist/session/scheduler.js +5 -9
  10. package/dist/tools/constants.js +21 -0
  11. package/package.json +1 -1
  12. package/dist/__trace_manual_test__.js +0 -1
  13. package/dist/agent/core.d.ts +0 -112
  14. package/dist/agent/index.d.ts +0 -19
  15. package/dist/agent/mode.d.ts +0 -29
  16. package/dist/agent/retry-classifier.js +0 -64
  17. package/dist/agent/spawn.d.ts +0 -36
  18. package/dist/attachments/image.d.ts +0 -22
  19. package/dist/commands/config.d.ts +0 -8
  20. package/dist/commands/skill.js +0 -230
  21. package/dist/config/file.d.ts +0 -23
  22. package/dist/config/index.d.ts +0 -114
  23. package/dist/config/presets.d.ts +0 -57
  24. package/dist/context/budget.d.ts +0 -79
  25. package/dist/context/classifier.d.ts +0 -14
  26. package/dist/context/encoders/_util.d.ts +0 -11
  27. package/dist/context/encoders/code.d.ts +0 -2
  28. package/dist/context/encoders/doc.d.ts +0 -14
  29. package/dist/context/encoders/graph.d.ts +0 -11
  30. package/dist/context/encoders/graph.js +0 -81
  31. package/dist/context/encoders/index.d.ts +0 -2
  32. package/dist/context/encoders/log.d.ts +0 -2
  33. package/dist/context/encoders/log.js +0 -2
  34. package/dist/context/encoders/memory.d.ts +0 -2
  35. package/dist/context/encoders/passthrough.d.ts +0 -11
  36. package/dist/context/encoders/search.d.ts +0 -2
  37. package/dist/context/encoders/summary.d.ts +0 -12
  38. package/dist/context/encoders/table.d.ts +0 -2
  39. package/dist/context/encoders/tree.d.ts +0 -2
  40. package/dist/context/index.d.ts +0 -6
  41. package/dist/context/lifecycle.d.ts +0 -51
  42. package/dist/context/pipeline.d.ts +0 -9
  43. package/dist/context/registry.d.ts +0 -9
  44. package/dist/context/relevance.d.ts +0 -65
  45. package/dist/context/types.d.ts +0 -36
  46. package/dist/foo.js +0 -28
  47. package/dist/foo.test.js +0 -12
  48. package/dist/index.d.ts +0 -1
  49. package/dist/llm/capabilities.d.ts +0 -19
  50. package/dist/llm/index.d.ts +0 -111
  51. package/dist/memory/discover.d.ts +0 -15
  52. package/dist/memory/index.d.ts +0 -13
  53. package/dist/memory/reflect.d.ts +0 -34
  54. package/dist/memory/store.d.ts +0 -124
  55. package/dist/pet/bridge.d.ts +0 -73
  56. package/dist/pet/protocol.d.ts +0 -83
  57. package/dist/pet/state.d.ts +0 -28
  58. package/dist/plan/active.d.ts +0 -23
  59. package/dist/plan/active.js +0 -45
  60. package/dist/plan/index.d.ts +0 -13
  61. package/dist/plan/index.js +0 -33
  62. package/dist/plan/state.d.ts +0 -2
  63. package/dist/plan/state.js +0 -11
  64. package/dist/plan/store.d.ts +0 -78
  65. package/dist/plan/store.js +0 -429
  66. package/dist/project-skill/index.js +0 -95
  67. package/dist/project-skill/initializer.js +0 -178
  68. package/dist/project-snapshot/index.js +0 -85
  69. package/dist/project-snapshot/llm-snapshot.js +0 -150
  70. package/dist/project-snapshot/static-files.js +0 -87
  71. package/dist/repl/index.d.ts +0 -22
  72. package/dist/rollback/index.d.ts +0 -79
  73. package/dist/sandbox/command.d.ts +0 -3
  74. package/dist/sandbox/index.d.ts +0 -4
  75. package/dist/sandbox/jail.d.ts +0 -17
  76. package/dist/sandbox/policy.d.ts +0 -21
  77. package/dist/sandbox/root.d.ts +0 -5
  78. package/dist/session/compact.d.ts +0 -92
  79. package/dist/session/index.d.ts +0 -13
  80. package/dist/session/notes-plan.js +0 -41
  81. package/dist/session/persist.d.ts +0 -30
  82. package/dist/session/scheduler.d.ts +0 -53
  83. package/dist/skills/discover.d.ts +0 -33
  84. package/dist/skills/index.d.ts +0 -13
  85. package/dist/skills/skill-eval.js +0 -345
  86. package/dist/skills/skill-improve.js +0 -221
  87. package/dist/skills/stats.js +0 -102
  88. package/dist/tools/builtins/apply-patch.js +0 -174
  89. package/dist/tools/builtins/ask-human.d.ts +0 -9
  90. package/dist/tools/builtins/codegraph.d.ts +0 -2
  91. package/dist/tools/builtins/codegraph.js +0 -128
  92. package/dist/tools/builtins/edit-file.d.ts +0 -2
  93. package/dist/tools/builtins/glob.d.ts +0 -2
  94. package/dist/tools/builtins/grep.d.ts +0 -2
  95. package/dist/tools/builtins/index.d.ts +0 -2
  96. package/dist/tools/builtins/memory-forget.d.ts +0 -2
  97. package/dist/tools/builtins/memory-list.d.ts +0 -2
  98. package/dist/tools/builtins/memory-save.d.ts +0 -2
  99. package/dist/tools/builtins/memory-search.d.ts +0 -2
  100. package/dist/tools/builtins/memory-update.d.ts +0 -2
  101. package/dist/tools/builtins/project-skill-update.js +0 -102
  102. package/dist/tools/builtins/read-file.d.ts +0 -2
  103. package/dist/tools/builtins/run-command.d.ts +0 -2
  104. package/dist/tools/builtins/switch-mode.d.ts +0 -2
  105. package/dist/tools/builtins/switch-mode.js +0 -44
  106. package/dist/tools/builtins/task.d.ts +0 -2
  107. package/dist/tools/builtins/todolist.d.ts +0 -2
  108. package/dist/tools/builtins/todolist.js +0 -411
  109. package/dist/tools/builtins/use-skill.d.ts +0 -2
  110. package/dist/tools/builtins/web-fetch.d.ts +0 -2
  111. package/dist/tools/builtins/web-search.d.ts +0 -2
  112. package/dist/tools/builtins/write-file.d.ts +0 -2
  113. package/dist/tools/constants.d.ts +0 -52
  114. package/dist/tools/registry.d.ts +0 -18
  115. package/dist/tools/retry.js +0 -137
  116. package/dist/tools/types.d.ts +0 -42
  117. package/dist/ui/batch.d.ts +0 -67
  118. package/dist/ui/clipboard.d.ts +0 -9
  119. package/dist/ui/content.d.ts +0 -55
  120. package/dist/ui/diff.d.ts +0 -34
  121. package/dist/ui/intervention.d.ts +0 -46
  122. package/dist/ui/layout.d.ts +0 -225
  123. package/dist/ui/markdown.d.ts +0 -46
  124. package/dist/ui/mouse.d.ts +0 -29
  125. package/dist/ui/prompt.d.ts +0 -61
  126. package/dist/ui/render.d.ts +0 -60
  127. package/dist/ui/spinner.d.ts +0 -26
  128. package/dist/ui/theme.d.ts +0 -47
  129. package/dist/ui/thinking.js +0 -80
@@ -1,114 +0,0 @@
1
- export interface Config {
2
- baseURL: string;
3
- apiKey: string;
4
- model: string;
5
- maxTokens?: number;
6
- systemPrompt: string;
7
- /** 模型上下文窗口(token)。须对齐真实模型窗口(GLM-4.6≈128k,DeepSeek-V3≈64k,Qwen 视版本)。 */
8
- contextWindowTokens: number;
9
- /** 自动压缩触发阈值(占窗口比例)。默认 0.85,保守偏早以吸收估算误差与下一步增长。 */
10
- compactThreshold: number;
11
- /** 流式请求里带 stream_options.include_usage 拿真实 usage。后端不认 stream_options 时关掉。 */
12
- includeUsage: boolean;
13
- /** 自动压缩总开关。关掉则只靠手动 /compact。 */
14
- autoCompact: boolean;
15
- /** Context Optimization Pipeline 总开关(工具结果进 LLM 前的类型化编码:tree/search/log/…)。
16
- * 关掉则工具结果原样进 LLM(仅长度裁剪),零行为变化。默认 true。 */
17
- contextOptimize: boolean;
18
- /** 相关性裁剪总开关(read_file 跨条裁剪:同 path 旧 read + 已被 mutation 覆写的旧 read
19
- * 自动替换为存根)。纯静态、不调 LLM;关掉则保留所有 read 结果(只受 capToolResultForHistory
20
- * 单条上限与 microcompact 旧区截短影响)。默认 true;
21
- * 设 MOCODE_CONTEXT_RELPRUNE=false 全局回退。 */
22
- contextRelprune: boolean;
23
- /** 观察者生命周期总开关(LIVE→REFERENCED→OBSOLETE→STUB 四态机;grep/glob/codegraph
24
- * producer ↔ read/edit/write consumer 引用追踪;孤立+老化非观察类工具自动 STUB;
25
- * 观察类工具永远只到 REFERENCED,不自动 STUB)。与 contextRelprune 并列,纯静态、不调 LLM。
26
- * 默认 true;设 MOCODE_LIFECYCLE=false 全局回退。 */
27
- contextLifecycle: boolean;
28
- /** Context Budget Scheduler 总开关(五区分账 + ROI 排序调度)。
29
- * 关掉则 agent 步前退化为 maybeCompact(history) 老路径(只看总占用 0.85 阈值),
30
- * 零行为变化。默认 true;设 MOCODE_BUDGET_SCHEDULER=false 全局回退。 */
31
- contextBudget: boolean;
32
- /** 后台反思 pass 总开关。关掉则只靠手动 /reflect + 机会主义 memory_update。 */
33
- autoReflect: boolean;
34
- /**
35
- * 记忆子系统总开关。关闭时:5 个 memory_* 工具不进工具表,buildSystemPrompt
36
- * 里的 Memory Index 段 + memory_* 工具使用说明整段不出现,plan 模式提示词里的
37
- * 工具名也跟着消失。运行时 /memory_switch 改;持久化 MEMORY_ENABLED。
38
- * 默认 false:新用户零侵入,想用记忆功能显式打开。
39
- */
40
- memoryEnabled: boolean;
41
- /** 每 N 个轮次触发一次后台反思 pass(与 agent 并发,不阻塞)。默认 5。 */
42
- reflectEveryN: number;
43
- /** 每轮 agent 循环最大步数(防无限循环)。默认 25。 */
44
- maxSteps: number;
45
- /** 子 agent(task 工具派生)默认步数上限。防子任务失控耗尽配额。默认 50。 */
46
- subAgentMaxSteps: number;
47
- /** 会话落盘目录(cwd 下)。 */
48
- sessionDir: string;
49
- /** AnySearch 联网搜索 API key(可选)。不配则走匿名免费额度(按 IP 限流)。 */
50
- searchApiKey?: string;
51
- /** 沙箱根目录(文件操作边界,可选)。未配则 startRepl 用 process.cwd() 兜底。优先级:--sandbox-root > 本项 > cwd。 */
52
- sandboxRoot?: string;
53
- /** AnySearch API base,默认官方端点。 */
54
- searchBaseUrl: string;
55
- /** 单张图片内联字节上限(base64 前的原始字节);超此大小拒绝并提示 TODO 走 URL 上传。默认 4MB。 */
56
- maxImageBytes?: number;
57
- /** 主题名(对应 src/ui/theme.ts 的 THEMES 表键)。默认 default;shell env MOCODE_THEME 覆盖文件。 */
58
- theme: string;
59
- /** MOCODE_THEME 是否由 shell 环境变量设置(非文件回填)。若是,/theme 写文件下次启动仍被 shell 盖。 */
60
- themeFromShell: boolean;
61
- /** 由 shell 环境变量设置的 LLM 键名列表(非文件回填)。若含某键,/model 写该键下次启动仍被 shell 盖。 */
62
- llmKeysFromShell: string[];
63
- }
64
- /**
65
- * 模型是否已配置(baseURL + apiKey 非空)。REPL 开场据此决定是否提示 /model。
66
- * 未配置时 config.model 仍回退 'gpt-4o-mini',但发消息会因 baseURL/apiKey 空而失败——由 runTurn catch 友好提示。
67
- */
68
- export declare function isModelConfigured(): boolean;
69
- /** 兼容旧名字:repl 的 buildSystemMessage 仍引 PLAN_MODE_SUFFIX(变量)。运行时按需现拼。 */
70
- export declare function buildBasePrompt(): string;
71
- /**
72
- * plan 模式追加到系统提示末尾的指令。
73
- * 历史曾是 `export const PLAN_MODE_SUFFIX`(顶层字面量);现改为按 isMemoryEnabled()
74
- * 动态拼:false 时不出现 memory_* 工具名,避免 LLM 想调不存在的工具。
75
- *
76
- * 注意:已改为 getter(每次访问现拼),让运行时切 /memory_switch 后立即生效。
77
- * 旧 import `PLAN_MODE_SUFFIX` 路径不变;repl 推荐改用 getPlanModeSuffix()(语义更清晰)。
78
- * 不能直接 `export const PLAN_MODE_SUFFIX = buildPlanModeSuffix()`:
79
- * 该表达式在模块初始化时立即求值,而 buildPlanModeSuffix 内部读 config,config 还未求值 → TDZ。
80
- */
81
- export declare function getPlanModeSuffix(): string;
82
- export declare const config: Config;
83
- /**
84
- * 运行时更新模型相关配置(/model 命令调)。
85
- * - 更新 config 对象字段(即时生效:chat() 读 config.model,reconfigureClient 读 config.baseURL/apiKey)。
86
- * - 同步 process.env(保持内存一致:其他读 process.env 的路径也拿到新值;且使新值在下次启动的
87
- * loadEnvFiles 中被视为"已设",不被文件回填覆盖——即"优先拿这里的")。
88
- * 持久化(写 ~/.mocode/config)由调用方走 writeConfigKeys,此处只管内存 + env。
89
- * 重建 OpenAI 客户端(baseURL/apiKey 是构造时固化的实例字段)由调用方走 reconfigureClient。
90
- */
91
- export declare function updateModelConfig(opts: {
92
- model?: string;
93
- baseURL?: string;
94
- apiKey?: string;
95
- contextWindowTokens?: number;
96
- }): void;
97
- /**
98
- * 记忆子系统总开关:单一来源。/memory_switch、/memory_status、buildSystemPrompt、
99
- * tools/builtins/index.ts、tools/constants.ts 的 plan-mode 列表都从这里查。
100
- * 默认 false(新用户零侵入)。
101
- */
102
- export declare function isMemoryEnabled(): boolean;
103
- /**
104
- * 切换记忆子系统开关(/memory_switch on|off 调)。
105
- * - 更新 config 单例字段(其它模块下次调 isMemoryEnabled() 即拿新值)。
106
- * - 同步 process.env.MEMORY_ENABLED(下次启动 loadEnvFiles 不被文件回填)。
107
- * 持久化(写 ~/.mocode/config 的 MEMORY_ENABLED 键)由调用方走 writeConfigKeys。
108
- *
109
- * 注:开关切换对当前会话的 tool list / 已拼好的 systemPrompt 不会自动重算 —
110
- * 工具表在 REPL 启动时构建,systemPrompt 在每轮 chat() 拼时按 isMemoryEnabled()
111
- * 现查现拼(关掉时该轮拼出来的 prompt 即不带 memory_* 段)。所以切换在「下一轮
112
- * agent 调用」起即时生效,本轮已发出的请求不会回滚。
113
- */
114
- export declare function updateMemoryConfig(enabled: boolean): void;
@@ -1,57 +0,0 @@
1
- /**
2
- * 多模型预设(`/model save <name>` 保存的命名配置)的纯 I/O 叶子。
3
- *
4
- * 存储:每个预设一个独立 JSON 文件 `~/.mocode/models/<name>.json`。
5
- * - 选用 per-file 而非单一 index.json:写不需要读-合并-写整本,天然原子(单文件 rename),
6
- * 符合 memory/store.ts 的惯例;并发写多个预设互不打架。
7
- * - 路径前缀与 CONFIG_PATH 共享 `~/.mocode/`,保证权限/位置一致。
8
- *
9
- * 不读 process.env、不触发 config 单例初始化——repl(/model 子命令)与 commands/config.ts
10
- * 之外的脚本都能安全 import。错误一律抛(写失败属异常路径,调用方决定怎么提示用户)。
11
- *
12
- * 命名约束:[a-zA-Z0-9_-]{1,32}。理由:
13
- * - 排除路径分隔符与 .. 防止越权写文件。
14
- * - 与 dotenv key 风格一致,便于未来扩展到同名 env override。
15
- * - 32 位上限防极长名撑爆文件名系统。
16
- */
17
- /** 预设目录:`~/.mocode/models/`(按需创建)。 */
18
- export declare const MODELS_DIR: string;
19
- /** 单个预设的内容:与 updateModelConfig 的可选字段对齐。 */
20
- export interface ModelPreset {
21
- name: string;
22
- baseURL: string;
23
- apiKey: string;
24
- model: string;
25
- contextWindow: number;
26
- }
27
- /** 名字是否合法(调用方复用,避免在多处重复同一正则)。 */
28
- export declare function isValidPresetName(name: string): boolean;
29
- /** 读单个预设;不存在抛错。 */
30
- export declare function getPreset(name: string): ModelPreset;
31
- /** 读单个预设;不存在返回 null(供列表/可选切换场景)。 */
32
- export declare function readPreset(name: string): ModelPreset | null;
33
- /** 写/覆盖一个预设(原子:写 tmp 再 rename)。 */
34
- export declare function savePreset(preset: ModelPreset): void;
35
- /** 删除一个预设;不存在返回 false,成功返回 true。 */
36
- export declare function deletePreset(name: string): boolean;
37
- /**
38
- * 重命名一个预设(原子:link+unlink,跨设备时退化为 copy+unlink)。
39
- * 用于 /model rename <old> <new>;不存在的旧名 / 已存在的新名返回 false,具体由调用方决定提示文案。
40
- */
41
- export declare function renamePreset(oldName: string, newName: string): boolean;
42
- /** 列出全部预设(按 name 升序);目录不存在返回空数组。 */
43
- export declare function listPresets(): ModelPreset[];
44
- /**
45
- * 把当前 config 的 LLM 四键(baseURL/apiKey/model/contextWindow)迁为命名预设。
46
- * 用于启动时一次性兜底老用户:加 /model 之前就已经在 ~/.mocode/config 写过的配置,
47
- * /model list 应该立刻能看到,而不是空。已有同名预设则不重复写。
48
- *
49
- * 返回新建的预设名;若未配置完整(baseURL/apiKey 缺失)或已有同名则返回 null。
50
- * 设计为幂等:重启调用一次也只会生效一次。
51
- */
52
- export declare function migrateCurrentToPreset(input: {
53
- baseURL: string;
54
- apiKey: string;
55
- model: string;
56
- contextWindow: number;
57
- }): string | null;
@@ -1,79 +0,0 @@
1
- import type { ChatMessage } from '../llm/index.js';
2
- /** 五区分账(占比对齐 CONTEXT_WINDOW)。顺序固定,便于遍历。 */
3
- export declare const BUDGET_LAYERS: readonly ["system", "history", "toolRecent", "toolOld", "summary", "reserve"];
4
- export type BudgetLayer = (typeof BUDGET_LAYERS)[number];
5
- /** 占比(总和 = 0.95,留 5% 给 Reserve)。对齐用户修正版:
6
- * Recent Tool 25%(原 40% 偏大,因 Hot 区不该被压)+ Old Tool 25% 同等 +
7
- * History 20% + System 15% + Summary 10%(平时 0 占用,触发后才用) */
8
- export declare const BUDGET_RATIO: Record<BudgetLayer, number>;
9
- /** Hot/Cold 划分:当前 step 起往前 HOT_TURN_WINDOW 个 user turn 之内的工具结果视为 Hot,
10
- * 之外的视为 Cold。0 = 全 Cold(等同老路径);越短 Hot 越小,压缩越激进。 */
11
- export declare const HOT_TURN_WINDOW = 4;
12
- /** 工具消息推入历史后,经过的「消费者 push 次数」即 age。
13
- * Cold 区内:age ≥ TOOL_OLD_AGE 的非观察类工具结果可被调度器就地 stub。
14
- * 默认 2 = 跨过 2 个消费者 push 仍未被消费,等同 lifecycle 的 DEFAULT_AGE_THRESHOLD。 */
15
- export declare const TOOL_OLD_AGE = 2;
16
- /** 从 history 末尾向前找最后一个 user 消息的索引;无 user 返 -1。 */
17
- export declare function lastUserIndex(history: ChatMessage[]): number;
18
- /** 从 idx 处向前数第 N 个 user turn 的边界 index(含该 user 之后的内容)。
19
- * 用于把 history 切成 Hot 区(tail 一段,endExclusive=history.length)与 Cold 区(0..endExclusive)。
20
- * 若 N 个 user 不足,Hot 区 = history.length(全保护);Cold 区空,无压缩目标。 */
21
- export declare function userTurnBoundary(history: ChatMessage[], window: number): number;
22
- /** 单区预算分配。绝对值 = ratio * window。 */
23
- export interface LayerBudget {
24
- actual: number;
25
- budget: number;
26
- overBudget: boolean;
27
- /** overBudget 比值 = max(0, actual - budget) / budget;无超 = 0。
28
- * 调度器用此值做 ROI 排序——溢出越多,优先处理。 */
29
- overRatio: number;
30
- }
31
- /** 一次评估的完整报告(供 agent/core.ts 决策)。 */
32
- export interface BudgetReport {
33
- step: number;
34
- total: number;
35
- window: number;
36
- layers: Record<BudgetLayer, LayerBudget>;
37
- /** 实际超预算的层(按 overRatio 降序,排前面先处理)。 */
38
- triggers: BudgetLayer[];
39
- /** 总占用超总阈(0.85*window)的兜底触发 — 单独字段,与 layers.triggers 分开。 */
40
- totalOver: boolean;
41
- /** Hot/Cold 边界:Cold 区 = [1, hotBoundary);Hot 区 = [hotBoundary, length)。
42
- * agent/core.ts 拿到后可对 Cold 区做就地 stub,Hot 区只 cap。 */
43
- hotBoundary: number;
44
- }
45
- /** 评估当前 history 的五区预算(纯函数,改不动 history)。
46
- * 传入 step 是当前所在 step 编号(agent 循环 step 变量),用于日志/调试。 */
47
- export declare function evaluateBudget(history: ChatMessage[], window: number, step?: number): BudgetReport;
48
- /** 调度器决策动作(纯数据,不动 history)。agent/core.ts 据此调用既有闸。 */
49
- export type ScheduleAction = {
50
- kind: 'warn';
51
- layer: BudgetLayer;
52
- reason: string;
53
- } | {
54
- /** 对 Cold 区(hotBoundary 之前)的 tool 消息按 ROI 做 L1→L2→L3 渐进压缩。
55
- * 注意:Hot 区永不发此 action——精细剔除由 lifecycle/pruner/drop_context 负责。 */
56
- kind: 'shrink_cold_tools';
57
- level: 1 | 2 | 3;
58
- } | {
59
- /** Hot 区只 cap(降单条上限),不 stub;aggressive = true 时调低阈值走更严的 cap。
60
- * 精细剔除(cap 不够时)由 lifecycle age stub 与 drop_context 工具兜底。 */
61
- kind: 'cap_hot_tools';
62
- aggressive: boolean;
63
- } | {
64
- kind: 'compact_history';
65
- focus?: string;
66
- };
67
- /** 根据 BudgetReport 生成调度动作(从轻到重,直至总占用回落到 0.85 以下)。
68
- * 规则:
69
- * - system 超 → warn(不压,配置问题不是内容问题)
70
- * - toolOld 超 → 先 L1(中截超大)→ L2(same-path 已有 relevance)→ L3(age stub,新增)
71
- * - toolRecent 超 → cap(只降低单条上限,不 stub)
72
- * - history 超 或 totalOver → compact_history(调 maybeCompact / compactHistory)
73
- * - summary 超 → 不动(摘要本身就压缩产物,删它等于丢历史,只能放任或扩 Recent 预算) */
74
- export declare function scheduleActions(report: BudgetReport): ScheduleAction[];
75
- /** 拍平成人类可读(供 /context 命令与 check-budget 脚本用)。 */
76
- export declare function formatReport(report: BudgetReport): string;
77
- /** 便捷:把 history 一把估成总 token 数(给 cap.js 等复用,避免重复实现)。
78
- * 注意:此处是粗估(只看 content 长度),不区分五区——只用于「系统层整体还剩多少」快查。 */
79
- export declare function quickEstimate(history: ChatMessage[]): number;
@@ -1,14 +0,0 @@
1
- import type { ContextKind } from './types.js';
2
- /**
3
- * 判定 ContextKind。
4
- * - 有 BY_NAME 强先验 → 用之(内置工具确定性强)。
5
- * - 否则形状启发(MCP / 未来工具)。
6
- * - 都不中 → passthrough(不动)。
7
- *
8
- * @param toolName 工具名
9
- * @param output 工具原始输出(形状启发用;有 BY_NAME 时不读)
10
- * @param _args 已解析参数(预留:未来 read_file 的 offset/limit 可影响 code 编码策略;Phase 1 不用)
11
- */
12
- export declare function classify(toolName: string, output: string, _args: Record<string, unknown> | null): ContextKind;
13
- /** 暴露 BY_NAME 副本供调试 / 未来 /context 展示(只读视图)。 */
14
- export declare function knownToolKinds(): Record<string, ContextKind>;
@@ -1,11 +0,0 @@
1
- /** 去 ANSI CSI 序列(颜色 / 光标 / 清屏等)。语义无损:颜色码不含信息。 */
2
- export declare function stripAnsi(s: string): string;
3
- /**
4
- * 折叠连续空行(只含空白字符的行)≥ threshold → 单个空行。
5
- * 用于 prose / source dump(web_fetch / use_skill / task / codegraph):HTML→文本与 markdown 常留多余空行,
6
- * 多空行与单空行语义等价,折叠无损。默认 threshold=3(只动真正过量的空行,常见 ≤2 空行不动)。
7
- *
8
- * 注意:用 `.trim() === ''` 判空——故 read_file 的 ` 2\t`(行号前缀 + tab,trim 后剩 `2`)不会被
9
- * 视作空行。read_file 的空行折叠见 code encoder(前缀感知)。
10
- */
11
- export declare function collapseBlankRuns(text: string, threshold?: number): string;
@@ -1,2 +0,0 @@
1
- import type { ContextEncoder } from '../types.js';
2
- export declare const codeEncoder: ContextEncoder;
@@ -1,14 +0,0 @@
1
- import type { ContextEncoder } from '../types.js';
2
- /**
3
- * Doc Encoder(web_fetch / use_skill):折叠连续空行(≥3 → 1)。
4
- *
5
- * 输入:
6
- * - web_fetch 的 `URL (HTTP ...)\n\n<body>`(HTML→文本,常留多余空行)。
7
- * - use_skill 的 `# Skill: name\n\n<body>`(SKILL.md 正文,frontmatter 已剥离)。
8
- * 输出:空行折叠;正文 / 指令逐字保留。
9
- *
10
- * 不变量:URL 前缀行 / Skill 标题行保留;正文文本逐字保留(仅折叠空行——markdown / HTML 多空行与
11
- * 单空行语义等价,无损)。use_skill 走放宽 cap(MAX_SKILL_RESULT)保指令完整——本 encoder 在 cap 前先
12
- * 折叠空行,减少被 cap 截断的风险。
13
- */
14
- export declare const docEncoder: ContextEncoder;
@@ -1,11 +0,0 @@
1
- import type { ContextEncoder } from '../types.js';
2
- /**
3
- * Graph Encoder(codegraph):去 ANSI + 折叠连续空行(≥3 → 1)。
4
- *
5
- * 输入:codegraph CLI 返回的 `[退出码 N]\n<源码 + 调用路径>`(可能含 ANSI 颜色、多余空行)。
6
- * 输出:去 ANSI + 空行折叠;结构(调用路径块、源码段)不动。
7
- *
8
- * 不变量:退出码行保留;源码与调用路径文本逐字保留(仅去颜色码 + 折叠空行);不删内容行。
9
- * 保守:不重构调用路径 / 不去重源码(codegraph CLI 输出格式未稳定,需先采样真实输出定不变量,留后续)。
10
- */
11
- export declare const graphEncoder: ContextEncoder;
@@ -1,81 +0,0 @@
1
- import { stripAnsi, collapseBlankRuns } from './_util.js';
2
- function isAgedCold(input) {
3
- return input.phase === 'sweep' && input.isCold === true && (input.age ?? 0) >= 2;
4
- }
5
- function normalizeBlock(block) {
6
- return block
7
- .replace(/\r\n/g, '\n')
8
- .split('\n')
9
- .map((line) => line.trimEnd())
10
- .join('\n')
11
- .trim();
12
- }
13
- function dedupeFencedBlocks(text) {
14
- const seen = new Set();
15
- let removed = 0;
16
- const result = text.replace(/```[^\n]*\n[\s\S]*?\n```/g, (block) => {
17
- const key = normalizeBlock(block);
18
- if (key.length < 120 || !seen.has(key)) {
19
- seen.add(key);
20
- return block;
21
- }
22
- removed++;
23
- return '… duplicate source block omitted (cold graph)';
24
- });
25
- return { text: result, removed };
26
- }
27
- function looksLikeSourceBlock(block) {
28
- const lines = block.split('\n');
29
- const sourceLines = lines.filter((line) => /^\s*\d+\t/.test(line) ||
30
- /^\s*(?:L)?\d+[:|]\s/.test(line) ||
31
- /^.*:\d+(?::\d+)?:\s/.test(line)).length;
32
- return block.length >= 120 && sourceLines >= 3;
33
- }
34
- function dedupeParagraphSourceBlocks(text) {
35
- const parts = text.split(/(\n{2,})/);
36
- const seen = new Set();
37
- let removed = 0;
38
- for (let i = 0; i < parts.length; i += 2) {
39
- const block = parts[i];
40
- if (!looksLikeSourceBlock(block))
41
- continue;
42
- const key = normalizeBlock(block);
43
- if (seen.has(key)) {
44
- parts[i] = '… duplicate source block omitted (cold graph)';
45
- removed++;
46
- }
47
- else {
48
- seen.add(key);
49
- }
50
- }
51
- return { text: parts.join(''), removed };
52
- }
53
- export const graphEncoder = {
54
- kind: 'graph',
55
- encode(input) {
56
- const stripped = stripAnsi(input.output);
57
- let text = stripped;
58
- let duplicates = 0;
59
- if (isAgedCold(input)) {
60
- const fenced = dedupeFencedBlocks(text);
61
- const paragraphs = dedupeParagraphSourceBlocks(fenced.text);
62
- text = paragraphs.text;
63
- duplicates = fenced.removed + paragraphs.removed;
64
- }
65
- text = collapseBlankRuns(text, 3);
66
- const notes = [
67
- /\x1b/.test(input.output) ? 'ANSI stripped' : '',
68
- text !== stripped && duplicates === 0 ? 'blank runs collapsed' : '',
69
- duplicates > 0 ? `${duplicates} duplicate source blocks omitted` : '',
70
- ].filter(Boolean);
71
- return {
72
- text,
73
- meta: {
74
- kind: 'graph',
75
- originalLen: input.output.length,
76
- encodedLen: text.length,
77
- note: notes.join(', ') || 'no change',
78
- },
79
- };
80
- },
81
- };
@@ -1,2 +0,0 @@
1
- import type { ContextEncoder } from '../types.js';
2
- export declare const builtinEncoders: ContextEncoder[];
@@ -1,2 +0,0 @@
1
- import type { ContextEncoder } from '../types.js';
2
- export declare const logEncoder: ContextEncoder;
@@ -1,2 +0,0 @@
1
- /** @deprecated 使用 commandEncoder;保留别名避免破坏已有直接导入。 */
2
- export { commandEncoder as logEncoder } from './command.js';
@@ -1,2 +0,0 @@
1
- import type { ContextEncoder } from '../types.js';
2
- export declare const memoryEncoder: ContextEncoder;
@@ -1,11 +0,0 @@
1
- import type { ContextEncoder } from '../types.js';
2
- /**
3
- * 兜底 encoder:identity,原样返回。
4
- * - classifier 未命中任何 kind(返回 'passthrough')时用。
5
- * - pipeline 总开关关闭(MOCODE_CONTEXT_OPTIMIZE=false)时,所有 kind 都走它 → 行为与改造前逐字节一致。
6
- * - Phase 1 阶段 registry 只注册它 → 全链路零行为变化。
7
- * - 任何 encoder 报错时,pipeline catch 后回落到它(传原 output)。
8
- *
9
- * 永不抛错:output 可能是任意字符串(含 ANSI / 多行 / 非法 UTF-8 片段),identity 直接返回,无解析风险。
10
- */
11
- export declare const passthroughEncoder: ContextEncoder;
@@ -1,2 +0,0 @@
1
- import type { ContextEncoder } from '../types.js';
2
- export declare const searchEncoder: ContextEncoder;
@@ -1,12 +0,0 @@
1
- import type { ContextEncoder } from '../types.js';
2
- /**
3
- * Summary Encoder(task):折叠连续空行(≥3 → 1)。
4
- *
5
- * 输入:task 工具返回的子 agent 最终摘要文本(已是摘要,可能含多余空行),可能带截断尾标
6
- * `…(子 agent 摘要已截断 N 字符)`。
7
- * 输出:空行折叠;摘要文本逐字保留。
8
- *
9
- * 不变量:摘要事实文本逐字保留(仅折叠空行);截断尾标保留。子 agent 摘要已是高密度文本,只做轻量去冗余,
10
- * 不再做进一步压缩(避免丢事实)。
11
- */
12
- export declare const summaryEncoder: ContextEncoder;
@@ -1,2 +0,0 @@
1
- import type { ContextEncoder } from '../types.js';
2
- export declare const tableEncoder: ContextEncoder;
@@ -1,2 +0,0 @@
1
- import type { ContextEncoder } from '../types.js';
2
- export declare const treeEncoder: ContextEncoder;
@@ -1,6 +0,0 @@
1
- export { optimizeToolResult } from './pipeline.js';
2
- export type { ContextKind, ContextEncoder, EncoderInput, EncoderOutput, } from './types.js';
3
- export { classify, knownToolKinds } from './classifier.js';
4
- export { registerEncoder, registerAll, getEncoder, registeredKinds, } from './registry.js';
5
- export { evaluateBudget, scheduleActions, formatReport, quickEstimate, userTurnBoundary, lastUserIndex, BUDGET_LAYERS, BUDGET_RATIO, HOT_TURN_WINDOW, TOOL_OLD_AGE, } from './budget.js';
6
- export type { BudgetLayer, LayerBudget, BudgetReport, ScheduleAction, } from './budget.js';
@@ -1,51 +0,0 @@
1
- import type { ChatMessage } from '../llm/index.js';
2
- /** 工具消息的观察者生命周期状态。 */
3
- export type LifeState = 'LIVE' | 'REFERENCED' | 'OBSOLETE' | 'STUB';
4
- /**
5
- * Observation Lifecycle Engine。
6
- * 每个 runAgentCore 实例持一个;pushToolResult 出口调 pushTool、mutation 分支调 pushMutation。
7
- * 内部 try/catch 兜底,对外永不抛错。
8
- */
9
- export declare class LifecycleEngine {
10
- private readonly ageThreshold;
11
- /** 工具消息 idx → 状态。 */
12
- private readonly states;
13
- /** 工具消息 idx → 被消费的次数(同一上游被多次消费也只算 REFERENCED,不计并发)。 */
14
- private readonly consumerCount;
15
- /** 工具消息 idx → 自 push 以来的「消费者 push」次数(用于老化判定)。
16
- * 每次 pushTool 触发,所有 LIVE 工具消息 age++。 */
17
- private readonly age;
18
- /** producer 路径 → 生产者工具消息 idx 列表(逆查用:某个 path 被消费时,反查上游 producer)。
19
- * 注意:不存 read_file,因为 read 自身就是消费者不充当 producer。 */
20
- private readonly producersByPath;
21
- /** 当前步序号(用于 age 老化:每次 pushTool 自增,对比 age 阈值)。 */
22
- private step;
23
- /** 最后 user 索引缓存(pushTool 时重算;pushMutation 时也重算,因为 mutation 可能跟 user 同行)。 */
24
- private lastUser;
25
- constructor(ageThreshold?: number);
26
- /** 新工具结果 push 进 history 时调;idx = history.length - 1。
27
- * mutation 工具(edit_file/write_file)的 push 跳过本轮的 autoStubOrphans(由调用方在
28
- * pushMutation 标完 read REFERENCED 之后再触发),避免刚被 mutation 消费的 read 被提前 STUB。 */
29
- pushTool(history: ChatMessage[], idx: number): void;
30
- /** mutation 工具(edit_file/write_file)push 后调。语义与 pushTool 一致,但额外标记「被 mutation 消费」的 read。
31
- * 注意:本层不直接 stub read(那是 Relevance Pruner 的职责);本层只更新状态图。
32
- * 注意:puhToolResult 出口已经登记过 mutation 本身,这里不再调 pushTool(避免 age 翻倍)。 */
33
- pushMutation(history: ChatMessage[], mutationIdx: number, path: string): void;
34
- /** 老化自动 STUB:扫描所有 LIVE(且非观察类)且 age ≥ 阈值且不在保护区的工具消息 → OBSOLETE → STUB。 */
35
- private autoStubOrphans;
36
- /** 实际替换 content 为存根。 */
37
- private stubOne;
38
- /** 找某条 tool 消息对应的 assistant.tool_calls.arguments。 */
39
- private findToolArgs;
40
- /** 拿某 idx 的当前状态;不在图里返 null。 */
41
- getState(idx: number): LifeState | null;
42
- /** 拿当前各状态计数。供 /context 显示「live=N, referenced=M, obsolete=K, stubbed=S」。 */
43
- stats(): {
44
- live: number;
45
- referenced: number;
46
- obsolete: number;
47
- stubbed: number;
48
- };
49
- }
50
- /** 默认单例工厂。runAgentCore 入口 new 一个,后续 pushTool / pushMutation 共享。 */
51
- export declare function createLifecycleEngine(ageThreshold?: number): LifecycleEngine;
@@ -1,9 +0,0 @@
1
- /**
2
- * 优化工具结果为进 LLM 的 tool 消息 content。
3
- *
4
- * @param name 工具名
5
- * @param output executeTool 的原始返回字符串
6
- * @param argsRaw 工具 arguments 原始 JSON 字符串(tc.arguments,可空;未传则 args=null)
7
- * @returns 进 history 的 content 字符串(永不抛错)
8
- */
9
- export declare function optimizeToolResult(name: string, output: string, argsRaw?: string): string;
@@ -1,9 +0,0 @@
1
- import type { ContextEncoder, ContextKind } from './types.js';
2
- /** 注册一个 encoder(后注册覆盖先注册,允许 MCP 覆盖默认)。返回 encoder 自身供链式。 */
3
- export declare function registerEncoder(enc: ContextEncoder): ContextEncoder;
4
- /** 批量注册(启动期 pipeline 调一次)。幂等:重复调忽略。 */
5
- export declare function registerAll(list: ContextEncoder[]): void;
6
- /** 取某 kind 的 encoder;未注册返 undefined(pipeline 回落 passthrough)。 */
7
- export declare function getEncoder(kind: ContextKind): ContextEncoder | undefined;
8
- /** 调试:列出已注册 kind。 */
9
- export declare function registeredKinds(): ContextKind[];
@@ -1,65 +0,0 @@
1
- import type { ChatMessage } from '../llm/index.js';
2
- /**
3
- * 维护「path → 该 path 所有 read_file tool 消息的 history index」映射。
4
- * - observePush:把刚 push 的 read_file tool 消息登记,并把同 path 的"更早" read 全部 stub。
5
- * - observeMutation:把该 mutation path 的"在 mutation 之前的" read 全部 stub。
6
- *
7
- * 设计:每个 agent 会话(每个 runAgentCore 实例)持有一个 pruner。会话结束/换 plan 时
8
- * 可新建;不持久化(history 重建时索引自然过期)。
9
- *
10
- * 零依赖:仅依赖 ChatMessage 形状;不 import llm / tools / agent。
11
- */
12
- export declare class RelevancePruner {
13
- /** path → [history index, ...] 按插入序;最新在末尾。 */
14
- private readonly readByPath;
15
- /** 把刚 push 的消息通知 pruner。
16
- * - 只处理 tool 消息(role==='tool')。
17
- * - 只关心 read_file:登记 + 反向 stub 同 path 旧 read。
18
- * - 非 read_file 的 tool 消息:无操作(本层只管 read_file)。
19
- * - 非 tool 消息(assistant / user / system):无操作。
20
- */
21
- observePush(history: ChatMessage[], msg: ChatMessage): void;
22
- /**
23
- * 把该 mutation path 的"在 mutation 之前的" read 全部 stub。
24
- * 通常用于 edit_file / write_file 工具:mutation 之后,之前的 read_file(p) 内容
25
- * 已失效(已不再是文件当前状态),模型后续若依赖旧 read 来 edit_file 会失败,但 edit_file
26
- * 的 old_string 来自模型记忆/后读,不依赖旧 read 结果文本。
27
- *
28
- * 调用时机:agent/core.ts 在 mutation 工具调用的 pushToolResult 之后立即调;
29
- * 此时 history 末尾就是 mutation 的 tool 消息,prior reads 指 < idx。
30
- */
31
- observeMutation(history: ChatMessage[], path: string): void;
32
- /**
33
- * 把 history 里 "path 同 + index < beforeIdx + 不在当前轮保护区" 的所有 read_file
34
- * tool 消息替换为存根(只改 .content,不动 id / 数组结构)。
35
- *
36
- * 实现:
37
- * - 用 readByPath[path] 直接拿到所有 index(已登记过),筛 < beforeIdx 的 stub。
38
- * - 同时扫一遍 [1, beforeIdx) 区间找未登记的(防御:索引可能漏登;不依赖索引也能 stub,
39
- * 保证正确性。索引只用于"避免重复扫全表"的优化)。
40
- * - protectedFrom = lastUserIndex(history):user 之后一律不动。
41
- * - 幂等:已是 STUB_PREFIX 的跳过。
42
- */
43
- private stubPriorReads;
44
- }
45
- /** 默认单例:每个 agent 循环一个。runAgentCore 入口 new 一个,后续 observe 共享。 */
46
- export declare function createRelevancePruner(): RelevancePruner;
47
- /**
48
- * 扫 history,统计被相关性裁剪 stub 的 read_file tool 消息(条数 + 原字节数)。
49
- * 供 /context 渲染统计行用(让用户直观看到「prune 帮了多少」)。
50
- * 永不抛错(对齐本模块契约);history 为空 / 无 stub 时返零值。
51
- *
52
- * 注意:stub 后只剩 stub 字符串(原 content 已丢失),故只能从 stub 字符串里 parse
53
- * 原字节数,误差 = stub 时记录的 content.length(精确);token 估算走 estimateTokens。
54
- */
55
- export declare function computePruneStats(history: ChatMessage[]): {
56
- stubbed: number;
57
- /** 原 content 总字节数(仅 stubbed 的)。 */
58
- originalChars: number;
59
- /** 反推原 token 数(粗略:estimateTokens(originalChars 字符))。 */
60
- originalTokens: number;
61
- /** 当前 stub 字符串总字节数。 */
62
- stubChars: number;
63
- /** 估算释放的 token 数(originalTokens - 当前 stub 占的 token)。 */
64
- freedTokens: number;
65
- };
@@ -1,36 +0,0 @@
1
- /** Context 的数据类型。classifier 据工具名 + 输出形状判定,选 encoder。 */
2
- export type ContextKind = 'tree' | 'search' | 'graph' | 'log' | 'code' | 'table' | 'memory' | 'doc' | 'status' | 'summary' | 'diff' | 'ast' | 'repo' | 'passthrough';
3
- /** encoder 的输入。pipeline 解析 argsRaw 后传入。 */
4
- export interface EncoderInput {
5
- /** 工具名(强先验信号)。 */
6
- toolName: string;
7
- /** 工具原始输出字符串(executeTool 的返回值,未经任何编码)。 */
8
- output: string;
9
- /** 已解析的工具参数;非法或空返 null。encoder 可据此做上下文感知编码(如 read_file 的 offset/limit)。 */
10
- args: Record<string, unknown> | null;
11
- /** 软目标字符数(来自 tools/constants.ts 的 cap 常量,按工具名取)。encoder 应尽量压到 budget 内,
12
- * 但最终长度裁剪仍由 pipeline 末尾的 capToolResultForHistory 兜底(保 head+标记+tail)。 */
13
- budget?: number;
14
- }
15
- /** encoder 的输出。 */
16
- export interface EncoderOutput {
17
- /** 编码后文本(喂给 LLM 的 tool 消息 content)。 */
18
- text: string;
19
- /** 编码元数据(调试 / 未来 /context 统计用;不影响喂给 LLM 的内容)。 */
20
- meta?: {
21
- kind: ContextKind;
22
- originalLen: number;
23
- encodedLen: number;
24
- /** 给调试者的备注(如"12 files · tree-encoded")。 */
25
- note?: string;
26
- };
27
- }
28
- /**
29
- * Encoder 统一接口:一类型一 encoder,纯函数,不抛错(失败由 pipeline 兜底)。
30
- * 扩展:在 encoders/ 加 xxx.ts 导出 ContextEncoder,在 encoders/index.ts 的 builtinEncoders 加一行。
31
- * 无需动 agent / llm / core。
32
- */
33
- export interface ContextEncoder {
34
- kind: ContextKind;
35
- encode(input: EncoderInput): EncoderOutput;
36
- }