@@ -24,25 +24,29 @@ describe("compaction infinite loop prevention", () => {
24
24
defaultCompletionOptions : {
25
25
maxTokens : 1000 ,
26
26
contextLength : 4000 ,
27
- }
27
+ } ,
28
28
} as ModelConfig ;
29
29
30
30
const mockLlmApi = { } as BaseLlmApi ;
31
31
32
32
it ( "should not loop infinitely when pruning doesn't reduce history size" , async ( ) => {
33
- const { countChatHistoryTokens, getModelContextLimit } = await import ( "./util/tokenizer.js" ) ;
33
+ const { countChatHistoryTokens, getModelContextLimit } = await import (
34
+ "./util/tokenizer.js"
35
+ ) ;
34
36
const mockStreamResponse = vi . mocked ( streamChatResponse ) ;
35
37
const mockCountTokens = vi . mocked ( countChatHistoryTokens ) ;
36
38
const mockGetContextLimit = vi . mocked ( getModelContextLimit ) ;
37
39
38
40
// Setup mocks
39
41
mockGetContextLimit . mockReturnValue ( 4000 ) ;
40
42
mockCountTokens . mockReturnValue ( 5000 ) ; // Always too big
41
- mockStreamResponse . mockImplementation ( async ( history , model , api , controller , callbacks ) => {
42
- callbacks ?. onContent ?.( "Summary" ) ;
43
- callbacks ?. onContentComplete ?.( ) ;
44
- return "Summary" ;
45
- } ) ;
43
+ mockStreamResponse . mockImplementation (
44
+ async ( history , model , api , controller , callbacks ) => {
45
+ callbacks ?. onContent ?.( "Summary" ) ;
46
+ callbacks ?. onContentComplete ?.( ) ;
47
+ return "Summary" ;
48
+ } ,
49
+ ) ;
46
50
47
51
// History that can't be pruned further (only system message)
48
52
const history : ChatCompletionMessageParam [ ] = [
@@ -51,26 +55,30 @@ describe("compaction infinite loop prevention", () => {
51
55
52
56
// This should not hang - it should break out of the loop
53
57
const result = await compactChatHistory ( history , mockModel , mockLlmApi ) ;
54
-
58
+
55
59
// Should complete successfully even though token count is still too high
56
60
expect ( result . compactedHistory ) . toBeDefined ( ) ;
57
61
expect ( mockCountTokens ) . toHaveBeenCalled ( ) ;
58
62
} ) ;
59
63
60
64
it ( "should not loop infinitely with history ending in assistant message" , async ( ) => {
61
- const { countChatHistoryTokens, getModelContextLimit } = await import ( "./util/tokenizer.js" ) ;
65
+ const { countChatHistoryTokens, getModelContextLimit } = await import (
66
+ "./util/tokenizer.js"
67
+ ) ;
62
68
const mockStreamResponse = vi . mocked ( streamChatResponse ) ;
63
69
const mockCountTokens = vi . mocked ( countChatHistoryTokens ) ;
64
70
const mockGetContextLimit = vi . mocked ( getModelContextLimit ) ;
65
71
66
72
// Setup mocks
67
73
mockGetContextLimit . mockReturnValue ( 4000 ) ;
68
74
mockCountTokens . mockReturnValue ( 5000 ) ; // Always too big
69
- mockStreamResponse . mockImplementation ( async ( history , model , api , controller , callbacks ) => {
70
- callbacks ?. onContent ?.( "Summary" ) ;
71
- callbacks ?. onContentComplete ?.( ) ;
72
- return "Summary" ;
73
- } ) ;
75
+ mockStreamResponse . mockImplementation (
76
+ async ( history , model , api , controller , callbacks ) => {
77
+ callbacks ?. onContent ?.( "Summary" ) ;
78
+ callbacks ?. onContentComplete ?.( ) ;
79
+ return "Summary" ;
80
+ } ,
81
+ ) ;
74
82
75
83
// History that ends with assistant - pruning won't change it
76
84
const history : ChatCompletionMessageParam [ ] = [
@@ -81,19 +89,21 @@ describe("compaction infinite loop prevention", () => {
81
89
82
90
// This should not hang
83
91
const result = await compactChatHistory ( history , mockModel , mockLlmApi ) ;
84
-
92
+
85
93
expect ( result . compactedHistory ) . toBeDefined ( ) ;
86
94
} ) ;
87
95
88
96
it ( "should successfully prune when pruning actually reduces size" , async ( ) => {
89
- const { countChatHistoryTokens, getModelContextLimit } = await import ( "./util/tokenizer.js" ) ;
97
+ const { countChatHistoryTokens, getModelContextLimit } = await import (
98
+ "./util/tokenizer.js"
99
+ ) ;
90
100
const mockStreamResponse = vi . mocked ( streamChatResponse ) ;
91
101
const mockCountTokens = vi . mocked ( countChatHistoryTokens ) ;
92
102
const mockGetContextLimit = vi . mocked ( getModelContextLimit ) ;
93
103
94
104
// Setup mocks
95
105
mockGetContextLimit . mockReturnValue ( 4000 ) ;
96
-
106
+
97
107
// Mock token counting to show reduction after pruning
98
108
let callCount = 0 ;
99
109
mockCountTokens . mockImplementation ( ( ) => {
@@ -102,12 +112,14 @@ describe("compaction infinite loop prevention", () => {
102
112
if ( callCount === 2 ) return 3000 ; // After pruning, fits
103
113
return 2000 ; // Subsequent calls
104
114
} ) ;
105
-
106
- mockStreamResponse . mockImplementation ( async ( history , model , api , controller , callbacks ) => {
107
- callbacks ?. onContent ?.( "Summary" ) ;
108
- callbacks ?. onContentComplete ?.( ) ;
109
- return "Summary" ;
110
- } ) ;
115
+
116
+ mockStreamResponse . mockImplementation (
117
+ async ( history , model , api , controller , callbacks ) => {
118
+ callbacks ?. onContent ?.( "Summary" ) ;
119
+ callbacks ?. onContentComplete ?.( ) ;
120
+ return "Summary" ;
121
+ } ,
122
+ ) ;
111
123
112
124
// History that can be successfully pruned
113
125
const history : ChatCompletionMessageParam [ ] = [
@@ -118,9 +130,9 @@ describe("compaction infinite loop prevention", () => {
118
130
] ;
119
131
120
132
const result = await compactChatHistory ( history , mockModel , mockLlmApi ) ;
121
-
133
+
122
134
expect ( result . compactedHistory ) . toBeDefined ( ) ;
123
135
// The function will call countTokens multiple times during the process
124
136
expect ( mockCountTokens ) . toHaveBeenCalled ( ) ;
125
137
} ) ;
126
- } ) ;
138
+ } ) ;
0 commit comments