@myassis/gateway 1.0.98 → 1.0.99

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.
@@ -116,7 +116,10 @@ exports.appConfig = {
116
116
  * 体积完全可能在轮内涨破预算。超过此阈值就在轮内先做摘要,
117
117
  * 而不是等到裁剪到最重级别仍超限、把整轮请求打断。
118
118
  */
119
- turnCompactTriggerChars: parseInt(process.env.TURN_COMPACT_TRIGGER_CHARS || '144000', 10),
119
+ /** 模型 maxTokens 缺失时的轮内压缩兜底阈值(字符) */
120
+ turnCompactTriggerChars: parseInt(process.env.TURN_COMPACT_TRIGGER_CHARS || '1000000', 10),
121
+ /** 轮内压缩阈值占模型上下文窗口的百分比(对齐 Codex 的 90%) */
122
+ turnCompactTriggerPercent: parseInt(process.env.TURN_COMPACT_TRIGGER_PERCENT || '90', 10),
120
123
  /** 轮内压缩时保留原文的最近工具调用轮数 */
121
124
  turnCompactKeepPairs: parseInt(process.env.TURN_COMPACT_KEEP_PAIRS || '2', 10),
122
125
  /** 单轮请求内最多做几次轮内压缩,防止摘要模型被反复调用 */
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.nextTrimLevel = exports.planTurnCompaction = exports.buildContext = exports.estimateTokens = exports.estimateChars = exports.TrimLevel = void 0;
3
+ exports.nextTrimLevel = exports.planTurnCompaction = exports.buildContext = exports.estimateTokens = exports.estimateChars = exports.TrimLevel = exports.CHARS_PER_TOKEN = void 0;
4
4
  const shared_1 = require("@myassis/shared");
5
5
  const index_js_1 = require("../../config/index.js");
6
6
  const ToolLedger_js_1 = require("./ToolLedger.js");
@@ -14,7 +14,7 @@ const logger = (0, shared_1.getLogger)('ContextBuilder');
14
14
  * 关键约束:本模块只对 *投影副本* 做裁剪,绝不修改会话持久化数据。
15
15
  */
16
16
  /** 中英混合场景下的粗略 token 估算系数 */
17
- const CHARS_PER_TOKEN = 1.6;
17
+ exports.CHARS_PER_TOKEN = 1.6;
18
18
  /** 骨架化后单条工具结果保留的长度 */
19
19
  const SKELETON_OUTPUT_LIMIT = 120;
20
20
  /**
@@ -76,7 +76,7 @@ function estimateChars(messages) {
76
76
  exports.estimateChars = estimateChars;
77
77
  /** 估算 token 数(粗略) */
78
78
  function estimateTokens(messages) {
79
- return Math.ceil(estimateChars(messages) / CHARS_PER_TOKEN);
79
+ return Math.ceil(estimateChars(messages) / exports.CHARS_PER_TOKEN);
80
80
  }
81
81
  exports.estimateTokens = estimateTokens;
82
82
  /** 按上限截断字符串,保留可读提示 */
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.toSystemModel = exports.toModel = void 0;
3
+ exports.toSystemModel = exports.toModel = exports.DEFAULT_CONTEXT_WINDOW = void 0;
4
+ /** 未知模型的默认上下文窗口(对齐 Codex 的 fallback 272000 tokens) */
5
+ exports.DEFAULT_CONTEXT_WINDOW = 272000;
4
6
  function toModel(m) {
5
7
  return {
6
8
  id: String(m.id),
@@ -10,7 +12,7 @@ function toModel(m) {
10
12
  type: m.type || 'chat',
11
13
  description: m.description || '',
12
14
  capabilities: m.capabilities || [],
13
- maxTokens: m.maxTokens || 0,
15
+ maxTokens: m.maxTokens || exports.DEFAULT_CONTEXT_WINDOW,
14
16
  isActive: m.isActive,
15
17
  baseUrl: m.baseUrl,
16
18
  score: m.score || 0,
@@ -27,7 +29,7 @@ function toSystemModel(m) {
27
29
  type: m.type || 'chat',
28
30
  description: m.description || '',
29
31
  capabilities: m.capabilities || [],
30
- maxTokens: m.maxTokens || 0,
32
+ maxTokens: m.maxTokens || exports.DEFAULT_CONTEXT_WINDOW,
31
33
  isActive: 1,
32
34
  baseUrl: m.baseUrl,
33
35
  score: m.score || 0,
@@ -925,6 +925,13 @@ class Session {
925
925
  const models = this.useSystemMode
926
926
  ? (await dataService_js_1.modelsService.listSystem()).data.map(x => (0, models_js_1.toSystemModel)(x))
927
927
  : (await dataService_js_1.modelsService.list(token)).data.map(x => (0, models_js_1.toModel)(x));
928
+ // 轮内压缩阈值:优先按当前模型上下文窗口的百分比(对齐 Codex 的 90%),
929
+ // 模型未声明 maxTokens 时回退到固定字符阈值。
930
+ const activeModel = models.find(m => m.modelId === this.selectModelId || m.id === this.selectModelId) || models[0];
931
+ const modelMaxTokens = activeModel?.maxTokens || 0;
932
+ const turnCompactTokenThreshold = modelMaxTokens > 0
933
+ ? Math.floor(modelMaxTokens * index_js_2.appConfig.turnCompactTriggerPercent / 100)
934
+ : Math.floor(index_js_2.appConfig.turnCompactTriggerChars / ContextBuilder_js_1.CHARS_PER_TOKEN);
928
935
  // 工具调用轮次计数,防止无限循环
929
936
  let toolRound = 0;
930
937
  // 达到工具轮上限后置位:强制模型停止调用工具、直接产出最终回复
@@ -1010,7 +1017,7 @@ class Session {
1010
1017
  while (true) {
1011
1018
  // 预防式压缩:等到厂商报超限才处理已经太晚(那意味着一次废掉的请求,
1012
1019
  // 且部分厂商在超限时返回的是难以识别的 400),这里提前把体积降下来。
1013
- if ((0, ContextBuilder_js_1.estimateChars)(messages) > index_js_2.appConfig.turnCompactTriggerChars) {
1020
+ if ((0, ContextBuilder_js_1.estimateTokens)(messages) > turnCompactTokenThreshold) {
1014
1021
  await compactInTurn();
1015
1022
  }
1016
1023
  const built = (0, ContextBuilder_js_1.buildContext)(messages, messagesLength, index_js_2.appConfig.contextMaxChars, trimLevel);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myassis/gateway",
3
- "version": "1.0.98",
3
+ "version": "1.0.99",
4
4
  "description": "我的助手 Gateway Service - 本地 AI 网关服务,支持认证、WebSocket 实时通信和任务调度",
5
5
  "main": "dist/index.js",
6
6
  "bin": {