foliko 1.1.83 → 1.1.84

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 = renderLine(this._lineBuffer, this._renderState, true);
552
+ const rendered = this._lineBuffer//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 {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foliko",
3
- "version": "1.1.83",
3
+ "version": "1.1.84",
4
4
  "description": "简约的插件化 Agent 框架",
5
5
  "main": "src/index.js",
6
6
  "type": "commonjs",
@@ -764,8 +764,11 @@ class ContextCompressor {
764
764
  content: summaryContent
765
765
  };
766
766
 
767
+ const combined = [...systemMessages, summary, ...recentMessages];
768
+ this._cleanupOrphanedToolResults(combined);
769
+
767
770
  messages.length = 0;
768
- messages.push(...systemMessages, summary, ...recentMessages);
771
+ messages.push(...combined);
769
772
 
770
773
  this._compressionCount++;
771
774
  const tokenCount = this._tokenCounter.countMessages(messages);
@@ -794,19 +797,81 @@ class ContextCompressor {
794
797
  content: summaryContent
795
798
  };
796
799
 
800
+ const combined = [...systemMessages, summary, ...recentMessages];
801
+ this._cleanupOrphanedToolResults(combined);
802
+
797
803
  messages.length = 0;
798
- messages.push(...systemMessages, summary, ...recentMessages);
804
+ messages.push(...combined);
799
805
 
800
806
  this._compressionCount++;
801
807
  if (messageStore.compressionState) {
802
808
  messageStore.compressionState.count++;
803
809
  messageStore.compressionState.lastCompressedAt = Date.now();
804
- messageStore.compressionState.lastTokenCount = this._tokenCounter.countMessages(messages);
810
+ messageStore.compressionState.lastTokenCount = this._tokenCounter.countMessages(combined);
805
811
  }
806
812
 
807
813
  logger.info(`Context simple compressed. Messages: ${messages.length}`);
808
814
  }
809
815
 
816
+ /**
817
+ * 清理孤立的 tool-result 消息(没有对应 tool-call 的)
818
+ * 压缩/裁剪后 recentMessages 可能切碎 tool-call/tool-result 配对,
819
+ * 必须就地清理,否则下游 API 会报 "tool result's tool id not found"
820
+ */
821
+ _cleanupOrphanedToolResults(messages) {
822
+ const validToolCallIds = new Set();
823
+ for (const msg of messages) {
824
+ if (msg.role !== 'assistant') continue;
825
+ if (Array.isArray(msg.content)) {
826
+ for (const item of msg.content) {
827
+ if ((item.type === 'tool-call' || item.type === 'tool-use') && item.toolCallId) {
828
+ validToolCallIds.add(item.toolCallId);
829
+ }
830
+ }
831
+ }
832
+ if (Array.isArray(msg.tool_calls)) {
833
+ for (const tc of msg.tool_calls) {
834
+ if (tc.id) validToolCallIds.add(tc.id);
835
+ }
836
+ }
837
+ }
838
+
839
+ let removedItems = 0;
840
+ let removedMsgs = 0;
841
+ for (const msg of messages) {
842
+ if (msg.role !== 'tool' || !Array.isArray(msg.content)) continue;
843
+ const originalLength = msg.content.length;
844
+ msg.content = msg.content.filter((item) => {
845
+ if (
846
+ item &&
847
+ (item.type === 'tool-result' || item.type === 'tool_result') &&
848
+ item.toolCallId &&
849
+ !validToolCallIds.has(item.toolCallId)
850
+ ) {
851
+ removedItems++;
852
+ return false;
853
+ }
854
+ return true;
855
+ });
856
+ if (msg.content.length === 0 && originalLength > 0) {
857
+ msg._orphaned = true;
858
+ }
859
+ }
860
+
861
+ for (let i = messages.length - 1; i >= 0; i--) {
862
+ if (messages[i]._orphaned) {
863
+ messages.splice(i, 1);
864
+ removedMsgs++;
865
+ }
866
+ }
867
+
868
+ if (removedItems > 0 || removedMsgs > 0) {
869
+ logger.debug(
870
+ `[ContextCompressor] cleanup: removed ${removedItems} orphaned tool-result items, ${removedMsgs} orphaned tool messages`
871
+ );
872
+ }
873
+ }
874
+
810
875
  async _summarizeMessages(messages) {
811
876
  if (!this.framework) {
812
877
  throw new Error('Framework not available');