@myassis/gateway 1.0.106 → 1.0.108

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.
@@ -100,7 +100,7 @@ exports.appConfig = {
100
100
  /** 摘要后保留的原始历史消息条数 */
101
101
  historyKeep: parseInt(process.env.HISTORY_KEEP || '4', 10),
102
102
  /** 保留完整输出的最近工具调用轮数 */
103
- toolPairKeep: parseInt(process.env.TOOL_PAIR_KEEP || '2', 10),
103
+ toolPairKeep: parseInt(process.env.TOOL_PAIR_KEEP || '4', 10),
104
104
  /** 极端裁剪时至少保留的工具调用轮数 */
105
105
  minToolPairKeep: 2,
106
106
  /** 单次请求上下文字符预算(LLMClient 硬上限为 200000,此处留出余量) */
@@ -121,7 +121,7 @@ exports.appConfig = {
121
121
  /** 模型上下文窗口的可用百分比(折算为字符预算,对齐 Codex 的 90%) */
122
122
  turnCompactTriggerPercent: parseInt(process.env.TURN_COMPACT_TRIGGER_PERCENT || '90', 10),
123
123
  /** 轮内压缩时保留原文的最近工具调用轮数 */
124
- turnCompactKeepPairs: parseInt(process.env.TURN_COMPACT_KEEP_PAIRS || '2', 10),
124
+ turnCompactKeepPairs: parseInt(process.env.TURN_COMPACT_KEEP_PAIRS || '4', 10),
125
125
  /** 单轮请求内最多做几次轮内压缩,防止摘要模型被反复调用 */
126
126
  maxInTurnCompactions: parseInt(process.env.MAX_IN_TURN_COMPACTIONS || '4', 10),
127
127
  /** 模型瞬时故障(空回复 / 超时 / 网络抖动)的自动重试次数 */
@@ -200,6 +200,9 @@ function clipPair(messages, pair, limit, sessionId) {
200
200
  // 以避免在「未真正裁剪」时产生无提示可引用的孤儿存档。
201
201
  if (Array.isArray(head.tool_calls)) {
202
202
  for (const tc of head.tool_calls) {
203
+ const tcName = tc?.toolName || tc?.function?.name;
204
+ if (tcName === 'updatePlan')
205
+ continue;
203
206
  tc.input = clipJsonArguments(tc.input, limit);
204
207
  if (tc.function) {
205
208
  tc.function.arguments = clipJsonArguments(tc.function.arguments, limit);
@@ -210,6 +213,8 @@ function clipPair(messages, pair, limit, sessionId) {
210
213
  const msg = messages[i];
211
214
  if (!msg || typeof msg.content !== 'string')
212
215
  continue;
216
+ if (msg.tool_call_name === 'updatePlan')
217
+ continue; // plan state must stay intact
213
218
  const original = msg.content;
214
219
  if (original.length <= limit)
215
220
  continue; // 仅当真正被截断才归档 + 提示
@@ -319,6 +324,9 @@ function skeletonizePair(messages, pair, sessionId) {
319
324
  toolName: tc?.toolName || tc?.function?.name || 'unknown',
320
325
  });
321
326
  }
327
+ const tcName = tc?.toolName || tc?.function?.name;
328
+ if (tcName === 'updatePlan')
329
+ continue;
322
330
  tc.input = skeletonArguments(tc.input);
323
331
  if (tc.function) {
324
332
  tc.function.arguments = skeletonArguments(tc.function.arguments);
@@ -329,6 +337,8 @@ function skeletonizePair(messages, pair, sessionId) {
329
337
  const msg = messages[i];
330
338
  if (!msg)
331
339
  continue;
340
+ if (msg.tool_call_name === 'updatePlan')
341
+ continue;
332
342
  const original = typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content ?? '');
333
343
  // 骨架化总是有损,但仅在原文较长时值得归档 + 提示
334
344
  if (original.length <= SKELETON_OUTPUT_LIMIT) {
@@ -898,6 +898,7 @@ class Session {
898
898
  }
899
899
  }
900
900
  systemPrompt = await (0, systemPrompt_js_1.getSystemPromptAsync)(agent, systemPrompt);
901
+ systemPrompt += '\n【防重复规则】1.不要重复执行已经成功完成的工具调用。若工具结果被截断(标记为内容过长已截断或完整结果请调阅detailTool),必须先用detailTool获取完整内容,切勿重新执行原工具。2.完成阶段性目标后(如编辑验证通过、提交代码后)直接总结结果回复用户,不要重新检查已解决的问题。';
901
902
  if (messages.some(x => x.role === 'system')) {
902
903
  messages = messages.map(m => m.role == 'system' ? { ...m, content: systemPrompt + '\n以下为之前对话内容摘要:\n' + m.content } : m);
903
904
  }
@@ -1397,6 +1398,11 @@ class Session {
1397
1398
  };
1398
1399
  messages.push(toolResultMessage);
1399
1400
  }
1401
+ // 每轮注入简短计划状态,防止上下文裁剪导致模型丢失计划而重新创建
1402
+ if (this.plan.length > 0 && !this.isPlanCompleted()) {
1403
+ const planStatus = this.plan.map((s, i) => (i + 1) + '.' + s.step + '[' + s.status + ']').join('; ');
1404
+ messages.push({ role: 'user', content: '[计划状态] ' + planStatus, attachments: [] });
1405
+ }
1400
1406
  // 计划模式:模型常常只在开头和结尾调用 updatePlan,中间过程不同步进度。
1401
1407
  // 这里在已有计划且连续多轮未同步时,主动注入一条提醒,迫使模型推进计划状态。
1402
1408
  const reminder = this.buildPlanReminder(roundsSincePlanUpdate, forceFinalize);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myassis/gateway",
3
- "version": "1.0.106",
3
+ "version": "1.0.108",
4
4
  "description": "我的助手 Gateway Service - 本地 AI 网关服务,支持认证、WebSocket 实时通信和任务调度",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -1,64 +1,64 @@
1
- #!/usr/bin/env node
2
- // pkg-build-win.js - Windows pkg build using PKG_CACHE_PATH
3
- // Points to ~/.pkg-cache which contains the correct v3.6 patched binary (40.6 MB, hash matches)
4
- 'use strict';
5
- const { spawn } = require('child_process');
6
- const path = require('path');
7
- const os = require('os');
8
- const fs = require('fs');
9
-
10
- const TARGET = process.argv[2] || 'node18-win-x64';
11
- const OUTPUT = process.argv[3] || 'myassis-gateway-win.exe';
12
-
13
- const CACHE_DIR = path.join(os.homedir(), '.pkg-cache');
14
- const PKG_BIN = path.resolve(__dirname, '../node_modules/@yao-pkg/pkg/lib-es5/bin.js');
15
-
16
- function log(msg) { console.error('[pkg-build] ' + msg); }
17
-
18
- /** 根据 target (如 node24-win-x64) 在缓存目录中找到匹配的二进制 */
19
- function findCachedBinary(target) {
20
- const m = target.match(/^node(\d+)-(.+)$/);
21
- if (!m) return null;
22
- const [, major, plat] = m;
23
- const v36dir = path.join(CACHE_DIR, 'v3.6');
24
- if (!fs.existsSync(v36dir)) return null;
25
- const candidates = fs.readdirSync(v36dir)
26
- .filter(f => new RegExp(`^fetched-v${major}\\.\\d+\\.\\d+-${plat}$`).test(f))
27
- .sort()
28
- .reverse();
29
- return candidates.length > 0 ? path.join(v36dir, candidates[0]) : null;
30
- }
31
-
32
- async function main() {
33
- log(`Building for ${TARGET}`);
34
- log(`Output: ${OUTPUT}`);
35
-
36
- // Verify cached binary exists (dynamically match by target)
37
- const cachedBinary = findCachedBinary(TARGET);
38
- if (!cachedBinary) {
39
- log(`ERROR: No cached binary found for target ${TARGET} in ${CACHE_DIR}`);
40
- log(`Please run: node node_modules/@yao-pkg/pkg/lib-es5/bin.js --targets ${TARGET} first`);
41
- process.exit(1);
42
- }
43
- const size = (fs.statSync(cachedBinary).size / 1024 / 1024).toFixed(1);
44
- log(`Using cached binary: ${cachedBinary} (${size} MB)`);
45
-
46
- // Use PKG_CACHE_PATH so pkg-fetch finds the correct v3.6 binary by hash
47
- const env = { ...process.env };
48
- delete env.PKG_NODE_PATH; // MUST NOT use PKG_NODE_PATH - it bypasses placeholders check
49
- env.PKG_CACHE_PATH = CACHE_DIR;
50
- log(`PKG_CACHE_PATH=${CACHE_DIR}`);
51
-
52
- log('Starting pkg...');
53
- return new Promise((resolve) => {
54
- const child = spawn(process.execPath, [PKG_BIN, '.', '--targets', TARGET, '--output', OUTPUT], {
55
- cwd: path.resolve(__dirname, '..'),
56
- env,
57
- stdio: 'inherit'
58
- });
59
- child.on('exit', (code) => process.exit(code || 0));
60
- child.on('error', (e) => { log('Spawn error: ' + e.message); process.exit(1); });
61
- });
62
- }
63
-
64
- main().catch(e => { console.error('[pkg-build] Fatal:', e.message); process.exit(1); });
1
+ #!/usr/bin/env node
2
+ // pkg-build-win.js - Windows pkg build using PKG_CACHE_PATH
3
+ // Points to ~/.pkg-cache which contains the correct v3.6 patched binary (40.6 MB, hash matches)
4
+ 'use strict';
5
+ const { spawn } = require('child_process');
6
+ const path = require('path');
7
+ const os = require('os');
8
+ const fs = require('fs');
9
+
10
+ const TARGET = process.argv[2] || 'node18-win-x64';
11
+ const OUTPUT = process.argv[3] || 'myassis-gateway-win.exe';
12
+
13
+ const CACHE_DIR = path.join(os.homedir(), '.pkg-cache');
14
+ const PKG_BIN = path.resolve(__dirname, '../node_modules/@yao-pkg/pkg/lib-es5/bin.js');
15
+
16
+ function log(msg) { console.error('[pkg-build] ' + msg); }
17
+
18
+ /** 根据 target (如 node24-win-x64) 在缓存目录中找到匹配的二进制 */
19
+ function findCachedBinary(target) {
20
+ const m = target.match(/^node(\d+)-(.+)$/);
21
+ if (!m) return null;
22
+ const [, major, plat] = m;
23
+ const v36dir = path.join(CACHE_DIR, 'v3.6');
24
+ if (!fs.existsSync(v36dir)) return null;
25
+ const candidates = fs.readdirSync(v36dir)
26
+ .filter(f => new RegExp(`^fetched-v${major}\\.\\d+\\.\\d+-${plat}$`).test(f))
27
+ .sort()
28
+ .reverse();
29
+ return candidates.length > 0 ? path.join(v36dir, candidates[0]) : null;
30
+ }
31
+
32
+ async function main() {
33
+ log(`Building for ${TARGET}`);
34
+ log(`Output: ${OUTPUT}`);
35
+
36
+ // Verify cached binary exists (dynamically match by target)
37
+ const cachedBinary = findCachedBinary(TARGET);
38
+ if (!cachedBinary) {
39
+ log(`ERROR: No cached binary found for target ${TARGET} in ${CACHE_DIR}`);
40
+ log(`Please run: node node_modules/@yao-pkg/pkg/lib-es5/bin.js --targets ${TARGET} first`);
41
+ process.exit(1);
42
+ }
43
+ const size = (fs.statSync(cachedBinary).size / 1024 / 1024).toFixed(1);
44
+ log(`Using cached binary: ${cachedBinary} (${size} MB)`);
45
+
46
+ // Use PKG_CACHE_PATH so pkg-fetch finds the correct v3.6 binary by hash
47
+ const env = { ...process.env };
48
+ delete env.PKG_NODE_PATH; // MUST NOT use PKG_NODE_PATH - it bypasses placeholders check
49
+ env.PKG_CACHE_PATH = CACHE_DIR;
50
+ log(`PKG_CACHE_PATH=${CACHE_DIR}`);
51
+
52
+ log('Starting pkg...');
53
+ return new Promise((resolve) => {
54
+ const child = spawn(process.execPath, [PKG_BIN, '.', '--targets', TARGET, '--output', OUTPUT], {
55
+ cwd: path.resolve(__dirname, '..'),
56
+ env,
57
+ stdio: 'inherit'
58
+ });
59
+ child.on('exit', (code) => process.exit(code || 0));
60
+ child.on('error', (e) => { log('Spawn error: ' + e.message); process.exit(1); });
61
+ });
62
+ }
63
+
64
+ main().catch(e => { console.error('[pkg-build] Fatal:', e.message); process.exit(1); });
@@ -1 +0,0 @@
1
- ok