mocode-ai 0.1.6 → 0.1.7

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.
@@ -9,8 +9,7 @@ import { chat, planChatTools, } from '../llm/index.js';
9
9
  import { executeTool } from '../tools/registry.js';
10
10
  import { PLAN_DISABLED_TOOLS } from '../tools/constants.js';
11
11
  import { getAgentMode, setAgentMode } from './mode.js';
12
- import { maybeCompact, contextState } from '../session/index.js';
13
- import { optimizeToolResult } from '../context/index.js';
12
+ import { maybeCompact, capToolResultForHistory, contextState, } from '../session/index.js';
14
13
  import { config } from '../config/index.js';
15
14
  import { jailResolve } from '../sandbox/index.js';
16
15
  /** 解析工具 arguments JSON;非法或空返 null(调用方据此降级到普通 preview)。 */
@@ -68,16 +67,12 @@ function readDiffContext(tc, parsed) {
68
67
  }
69
68
  return { preWriteOld: null, editStartLine: 1 };
70
69
  }
71
- /** 回灌 tool 结果到 history:经 Context Optimization Pipeline 编码(tree/search/log/...)后裁到单条上限。
72
- * tool_call_id 与 assistant.tool_calls 按序配对。未注册 encoder 时回落 capToolResultForHistory(零行为变化)。
73
- * TUI 渲染(hooks.onToolResult)用原始 output,与此解耦——屏上看全量,LLM 看编码后紧凑版。 */
70
+ /** 回灌 tool 结果到 history(裁到单条上限);tool_call_id assistant.tool_calls 按序配对。 */
74
71
  function pushToolResult(history, tc, output) {
75
72
  history.push({
76
73
  role: 'tool',
77
74
  tool_call_id: tc.id,
78
- // optimizeToolResult:classifier encoder → encode(保不变量压缩)→ capToolResultForHistory 兜底。
79
- // tc.arguments 透传给 encoder(上下文感知编码,如 read_file 的 offset/limit)。永不抛错。
80
- content: optimizeToolResult(tc.name, output, tc.arguments),
75
+ content: capToolResultForHistory(tc.name, output),
81
76
  });
82
77
  }
83
78
  /**
@@ -85,7 +80,7 @@ function pushToolResult(history, tc, output) {
85
80
  * 流式调 LLM(经 hooks.onText 实时渲染)→ 有 tool_calls 就分组执行并回灌
86
81
  * → 否则流式正文即最终回复。history 在调用间持久,由调用方持有。
87
82
  * 步前经 session/maybeCompact 自动压缩(接近窗口上限时三层压缩);
88
- * 工具结果进 history 前经 Context Optimization Pipeline(optimizeToolResult:类型化编码 + 长度裁剪)。
83
+ * 工具结果进 history 前经 capToolResultForHistory 裁到单条上限。
89
84
  *
90
85
  * 中断语义:signal 经 executeTool(name, args, signal) 串进工具;run_command/web_fetch 等 abort 即时杀
91
86
  * (树杀子进程 / 取消 fetch),循环顶 if(signal.aborted) 兜底还原。不会留下未配对的 tool_call_id。
@@ -122,7 +122,6 @@ export const config = {
122
122
  compactThreshold: Number(process.env.COMPACT_THRESHOLD) || 0.85,
123
123
  includeUsage: process.env.LLM_STREAM_USAGE !== 'false',
124
124
  autoCompact: process.env.AUTO_COMPACT !== 'false',
125
- contextOptimize: process.env.MOCODE_CONTEXT_OPTIMIZE !== 'false',
126
125
  autoReflect: process.env.AUTO_REFLECT !== 'false',
127
126
  reflectEveryN: Number(process.env.REFLECT_EVERY_N) || 5,
128
127
  maxSteps: Number(process.env.MAX_STEPS) || 200,
@@ -19,7 +19,14 @@ export const editFileTool = {
19
19
  const newStr = String(args.new_string);
20
20
  const full = resolve(path);
21
21
  const data = await readFile(full, 'utf8');
22
- const count = data.split(oldStr).length - 1;
22
+ // 行尾归一化:read_file split(/\r?\n/) 输出纯 LF,LLM 据此构造的 old_string/new_string
23
+ // 也是 LF;但本工具原样读文件(CRLF 保留),直接精确匹配会在 CRLF 文件上必败(文件 \r\n 对不上
24
+ // old_string 的 \n)。故匹配/计数在归一化(LF)文本上做,写回时按文件原始行尾风格还原,
25
+ // 不把 CRLF 文件悄悄换成 LF(只含 LF 的纯 LF 文件 norm===data,行为完全不变)。
26
+ const norm = data.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
27
+ const normOld = oldStr.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
28
+ const normNew = newStr.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
29
+ const count = norm.split(normOld).length - 1;
23
30
  if (count === 0) {
24
31
  return `错误:在 ${path} 中未找到 old_string。请先 read_file 确认实际内容。`;
25
32
  }
@@ -27,8 +34,10 @@ export const editFileTool = {
27
34
  return `错误:old_string 在 ${path} 中出现 ${count} 次,不唯一。请加入更多上下文使其唯一。`;
28
35
  }
29
36
  // 用函数形式替换,避免 new_string 里的 $ 被当特殊模式
30
- const updated = data.replace(oldStr, () => newStr);
31
- await writeFile(full, updated, 'utf8');
37
+ const updated = norm.replace(normOld, () => normNew);
38
+ // 检测原始行尾风格,写回时还原(存在 \r\n 即视为 CRLF 文件;纯 LF 文件保持 LF)
39
+ const out = data.includes('\r\n') ? updated.replace(/\n/g, '\r\n') : updated;
40
+ await writeFile(full, out, 'utf8');
32
41
  return `已在 ${path} 中完成 1 处替换。`;
33
42
  },
34
43
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mocode-ai",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "终端编码 agent:LLM + tool-call 循环 + 流式输出(含思考)+ 16 个工具,接任意 OpenAI 兼容后端。",
5
5
  "type": "module",
6
6
  "bin": {