foliko 1.1.84 → 1.1.86

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.
@@ -549,7 +549,7 @@ class ChatUI {
549
549
  if (!this._lineBuffer) return;
550
550
 
551
551
  // 渲染剩余的 partial line(没有 \n 结尾的尾部文字)
552
- const rendered = this._lineBuffer//renderLine(this._lineBuffer, this._renderState, true);
552
+ const rendered = renderLine(this._lineBuffer, this._renderState, true);
553
553
  if (!this._currentBotMessage) {
554
554
  this._currentBotMessage = this.create_message(rendered, colored('● ', GREEN), true);
555
555
  } else {
@@ -94,42 +94,39 @@ function renderInline(text) {
94
94
  return result;
95
95
  }
96
96
 
97
+ function renderStreamThink(text) {
98
+ const GRAY = DIM;
99
+ const RESET = CLEAR;
100
+
101
+ let result = '';
102
+ let inThink = false;
103
+ let i = 0;
104
+
105
+ while (i < text.length) {
106
+ if (text.startsWith('<think>', i)) {
107
+ result += GRAY + '<think>';
108
+ inThink = true;
109
+ i += 7;
110
+ } else if (text.startsWith('</think>', i)) {
111
+ result += '</think>' + RESET;
112
+ inThink = false;
113
+ i += 8;
114
+ } else {
115
+ result += text[i];
116
+ i++;
117
+ }
118
+ }
119
+
120
+ return result;
121
+ }
122
+
97
123
  function renderThink(line, state = { inThink: false }, thinking) {
98
124
  // 处理只有开始标签的情况(line = "<think>" 这样单独一行)
99
125
  // 这种情况在流式输出时很常见
100
- if (line === '<think>' || line === '<think>\n') {
101
- state.inThink = true;
102
- return STYLES.think.prefix + line;
103
- }
104
-
105
126
  let result = line;
106
127
 
107
128
  // 匹配 <think>...</think> 以及可能的跨行情况
108
- result = result.replace(/<think>([\s\S]*?)<\/think>/g, (match, content) => {
109
- // 去掉 content 中的空行(保留最多一个换行)
110
- const compressed = content.replace(/\n+/g, '\n').replace(/^\n|\n$/g, '');
111
- const prefix = result.indexOf('<think>') > 0 ? '\n' : "";
112
- return prefix + STYLES.think.prefix + '<think>' + compressed + '</think>' + STYLES.think.suffix;
113
- });
114
-
115
- // 处理未闭合的 think 标签 - 更新状态
116
- if (result.includes('<think>') && !result.includes('</think>')) {
117
- state.inThink = true;
118
- }
119
- if (result.includes('</think>')) {
120
- state.inThink = false;
121
- // 如果只有 </think> 标签(没有开始标签)
122
- if (!result.includes('<think>')) {
123
- return STYLES.think.prefix + line + STYLES.think.suffix;
124
- }
125
- }
126
-
127
- // 处理未闭合的 think 标签(开始但没结束)
128
- if (state.inThink && !result.includes('<think>')) {
129
- // 去掉空行
130
- const compressed = result.replace(/\n+/g, '\n').replace(/^\n|\n$/g, '');
131
- result = STYLES.think.prefix + compressed + STYLES.think.suffix;
132
- }
129
+ result = renderStreamThink(line)
133
130
 
134
131
  return thinking ? result : renderInline(result);
135
132
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foliko",
3
- "version": "1.1.84",
3
+ "version": "1.1.86",
4
4
  "description": "简约的插件化 Agent 框架",
5
5
  "main": "src/index.js",
6
6
  "type": "commonjs",
@@ -95,11 +95,14 @@ class AgentChatHandler extends EventEmitter {
95
95
  model: this.model,
96
96
  maxContextTokens: config.maxContextTokens,
97
97
  keepRecentMessages: config.keepRecentMessages || 20,
98
+ compressionMessageThreshold: config.compressionMessageThreshold,
98
99
  enableSmartCompress: config.enableSmartCompress !== false,
99
100
  });
100
101
 
101
102
  // 上下文限制
102
103
  this._maxContextTokens = this._contextCompressor._maxContextTokens;
104
+ // 消息数量触发压缩的阈值(可配置,默认 100)
105
+ this._compressionMessageThreshold = this._contextCompressor._compressionMessageThreshold;
103
106
 
104
107
  // Token 计算缓存(避免每次请求重复计算)
105
108
  this._toolsTokensCache = null;
@@ -755,7 +758,7 @@ class AgentChatHandler extends EventEmitter {
755
758
 
756
759
  // logger.info(`BEFORE: messages=${messages.length}, tokens=${totalTokens}/${limit}`);
757
760
 
758
- if (totalTokens > limit || messages.length > 100) {
761
+ if (totalTokens > limit || messages.length > this._compressionMessageThreshold) {
759
762
  // logger.info(
760
763
  // `Context large (${messages.length} msgs, ${totalTokens}/${this._maxContextTokens} tokens), compressing...`
761
764
  // );
package/src/core/agent.js CHANGED
@@ -403,6 +403,7 @@ class Agent extends EventEmitter {
403
403
  // 上下文压缩配置
404
404
  maxContextTokens: this.config.maxContextTokens,
405
405
  compressionThreshold: this.config.compressionThreshold,
406
+ compressionMessageThreshold: this.config.compressionMessageThreshold,
406
407
  keepRecentMessages: this.config.keepRecentMessages,
407
408
  enableSmartCompress: this.config.enableSmartCompress,
408
409
  });
@@ -659,6 +659,8 @@ class ContextCompressor {
659
659
  this.model = config.model || 'deepseek-chat';
660
660
  this._maxContextTokens = config.maxContextTokens || this._getDefaultContextLimit();
661
661
  this._keepRecentMessages = config.keepRecentMessages || 20;
662
+ // 消息数量阈值:超过该数量即触发压缩(与 token 阈值并联触发)
663
+ this._compressionMessageThreshold = config.compressionMessageThreshold || 200;
662
664
  this._enableSmartCompress = config.enableSmartCompress !== false;
663
665
  this._compactionSettings = config.compactionSettings || DEFAULT_COMPACTION_SETTINGS;
664
666