@myassis/gateway 1.0.98 → 1.0.100
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/dist/config/index.js
CHANGED
|
@@ -116,7 +116,10 @@ exports.appConfig = {
|
|
|
116
116
|
* 体积完全可能在轮内涨破预算。超过此阈值就在轮内先做摘要,
|
|
117
117
|
* 而不是等到裁剪到最重级别仍超限、把整轮请求打断。
|
|
118
118
|
*/
|
|
119
|
-
|
|
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
|
-
|
|
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
|
/** 按上限截断字符串,保留可读提示 */
|
package/dist/services/models.js
CHANGED
|
@@ -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 ||
|
|
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 ||
|
|
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,16 @@ 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
|
+
// 发给模型的字符预算:取配置上限与模型窗口(按百分比折算)的较小值,
|
|
933
|
+
// 避免对小窗口模型发出超限请求;大窗口模型则沿用 contextMaxChars。
|
|
934
|
+
const modelWindowChars = modelMaxTokens > 0
|
|
935
|
+
? Math.floor(modelMaxTokens * index_js_2.appConfig.turnCompactTriggerPercent / 100 * ContextBuilder_js_1.CHARS_PER_TOKEN)
|
|
936
|
+
: index_js_2.appConfig.turnCompactTriggerChars;
|
|
937
|
+
const effectiveContextMaxChars = Math.min(index_js_2.appConfig.contextMaxChars, modelWindowChars);
|
|
928
938
|
// 工具调用轮次计数,防止无限循环
|
|
929
939
|
let toolRound = 0;
|
|
930
940
|
// 达到工具轮上限后置位:强制模型停止调用工具、直接产出最终回复
|
|
@@ -1008,15 +1018,17 @@ class Session {
|
|
|
1008
1018
|
const callModel = async () => {
|
|
1009
1019
|
let transientRetries = 0;
|
|
1010
1020
|
while (true) {
|
|
1011
|
-
//
|
|
1012
|
-
//
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
}
|
|
1016
|
-
const built = (0, ContextBuilder_js_1.buildContext)(messages, messagesLength, index_js_2.appConfig.contextMaxChars, trimLevel);
|
|
1021
|
+
// 先做分级裁剪(只截断旧工具负载,保留最近 turnCompactKeepPairs 轮完整内容)。
|
|
1022
|
+
// 只有裁剪到当前级别后仍超出预算时,才做轮内摘要压缩;平时靠截断即可,
|
|
1023
|
+
// 避免工具调用一达到轮数就触发摘要。
|
|
1024
|
+
const built = (0, ContextBuilder_js_1.buildContext)(messages, messagesLength, effectiveContextMaxChars, trimLevel);
|
|
1017
1025
|
if (built.trimmed) {
|
|
1018
1026
|
logger.debug(`上下文裁剪: level=${built.level} chars=${built.chars}`);
|
|
1019
1027
|
}
|
|
1028
|
+
if (built.chars > effectiveContextMaxChars) {
|
|
1029
|
+
if (await compactInTurn())
|
|
1030
|
+
continue;
|
|
1031
|
+
}
|
|
1020
1032
|
// 收尾阶段不再下发工具定义:只要工具还在,模型大概率继续调用而不收尾
|
|
1021
1033
|
const llmClient = new LLMClient_js_1.LLMClient(models, built.messages, this.abortController.signal, forceFinalize ? [] : tools);
|
|
1022
1034
|
llmClient.setPreferredModel(this.selectModelId);
|