@@ -196,5 +196,126 @@ describe("Task Tool History Handling", () => {
196196 content : '{"setting": "value"}' ,
197197 } )
198198 } )
199+
200+ describe ( "environment details deduplication" , ( ) => {
201+ it ( "should filter out existing environment_details blocks before adding new ones" , ( ) => {
202+ // Simulate user content that already contains environment details from a previous session
203+ const userContentWithOldEnvDetails = [
204+ {
205+ type : "text" as const ,
206+ text : "Some user message" ,
207+ } ,
208+ {
209+ type : "text" as const ,
210+ text : "<environment_details>\n# Old Environment Details\nCurrent time: 2024-01-01\n</environment_details>" ,
211+ } ,
212+ ]
213+
214+ // Filter out existing environment_details blocks using the same logic as Task.ts
215+ const contentWithoutEnvDetails = userContentWithOldEnvDetails . filter ( ( block ) => {
216+ if ( block . type === "text" && typeof block . text === "string" ) {
217+ // Check if this text block is a complete environment_details block
218+ const isEnvironmentDetailsBlock =
219+ block . text . trim ( ) . startsWith ( "<environment_details>" ) &&
220+ block . text . trim ( ) . endsWith ( "</environment_details>" )
221+ return ! isEnvironmentDetailsBlock
222+ }
223+ return true
224+ } )
225+
226+ // Verify old environment details were removed
227+ expect ( contentWithoutEnvDetails ) . toHaveLength ( 1 )
228+ expect ( contentWithoutEnvDetails [ 0 ] . text ) . toBe ( "Some user message" )
229+
230+ // Simulate adding fresh environment details
231+ const newEnvironmentDetails =
232+ "<environment_details>\n# Fresh Environment Details\nCurrent time: 2024-01-02\n</environment_details>"
233+ const finalUserContent = [
234+ ...contentWithoutEnvDetails ,
235+ { type : "text" as const , text : newEnvironmentDetails } ,
236+ ]
237+
238+ // Verify we have exactly one environment_details block (the new one)
239+ const envDetailsBlocks = finalUserContent . filter ( ( block ) => {
240+ if ( block . type === "text" && typeof block . text === "string" ) {
241+ return (
242+ block . text . trim ( ) . startsWith ( "<environment_details>" ) &&
243+ block . text . trim ( ) . endsWith ( "</environment_details>" )
244+ )
245+ }
246+ return false
247+ } )
248+ expect ( envDetailsBlocks ) . toHaveLength ( 1 )
249+ expect ( envDetailsBlocks [ 0 ] . text ) . toContain ( "2024-01-02" )
250+ expect ( envDetailsBlocks [ 0 ] . text ) . not . toContain ( "2024-01-01" )
251+ } )
252+
253+ it ( "should not filter out text that mentions environment_details tags in content" , ( ) => {
254+ // User content that mentions the tags but isn't an environment_details block
255+ const userContent = [
256+ {
257+ type : "text" as const ,
258+ text : "Let me explain how <environment_details> work in this system" ,
259+ } ,
260+ {
261+ type : "text" as const ,
262+ text : "The closing tag is </environment_details>" ,
263+ } ,
264+ {
265+ type : "text" as const ,
266+ text : "Regular message" ,
267+ } ,
268+ ]
269+
270+ // Filter using the same logic as Task.ts
271+ const contentWithoutEnvDetails = userContent . filter ( ( block ) => {
272+ if ( block . type === "text" && typeof block . text === "string" ) {
273+ const isEnvironmentDetailsBlock =
274+ block . text . trim ( ) . startsWith ( "<environment_details>" ) &&
275+ block . text . trim ( ) . endsWith ( "</environment_details>" )
276+ return ! isEnvironmentDetailsBlock
277+ }
278+ return true
279+ } )
280+
281+ // All blocks should be preserved since none are complete environment_details blocks
282+ expect ( contentWithoutEnvDetails ) . toHaveLength ( 3 )
283+ expect ( contentWithoutEnvDetails ) . toEqual ( userContent )
284+ } )
285+
286+ it ( "should not filter out regular text blocks" , ( ) => {
287+ // User content with various blocks but no environment details
288+ const userContent = [
289+ {
290+ type : "text" as const ,
291+ text : "Regular message" ,
292+ } ,
293+ {
294+ type : "text" as const ,
295+ text : "Another message with <task> tags" ,
296+ } ,
297+ {
298+ type : "tool_result" as const ,
299+ tool_use_id : "tool_123" ,
300+ content : "Tool result" ,
301+ } ,
302+ ]
303+
304+ // Filter using the same logic as Task.ts
305+ const contentWithoutEnvDetails = userContent . filter ( ( block ) => {
306+ if ( block . type === "text" && typeof block . text === "string" ) {
307+ const isEnvironmentDetailsBlock =
308+ block . text . trim ( ) . startsWith ( "<environment_details>" ) &&
309+ block . text . trim ( ) . endsWith ( "</environment_details>" )
310+ return ! isEnvironmentDetailsBlock
311+ }
312+ return true
313+ } )
314+
315+ // All blocks should be preserved
316+ expect ( contentWithoutEnvDetails ) . toHaveLength ( 3 )
317+ expect ( contentWithoutEnvDetails ) . toEqual ( userContent )
318+ } )
319+ } )
199320 } )
200321} )
0 commit comments