@@ -15,6 +15,10 @@ import {
1515 cleanupAfterTruncation ,
1616 extractCommandBlocks ,
1717 injectSyntheticToolResults ,
18+ toolUseToText ,
19+ toolResultToText ,
20+ convertToolBlocksToText ,
21+ transformMessagesForCondensing ,
1822} from "../index"
1923
2024vi . mock ( "../../../api/transform/image-cleaning" , ( ) => ( {
@@ -1218,3 +1222,306 @@ describe("summarizeConversation with custom settings", () => {
12181222 )
12191223 } )
12201224} )
1225+
1226+ describe ( "toolUseToText" , ( ) => {
1227+ it ( "should convert tool_use block with object input to text" , ( ) => {
1228+ const block : Anthropic . Messages . ToolUseBlockParam = {
1229+ type : "tool_use" ,
1230+ id : "tool-123" ,
1231+ name : "read_file" ,
1232+ input : { path : "test.ts" , encoding : "utf-8" } ,
1233+ }
1234+
1235+ const result = toolUseToText ( block )
1236+
1237+ expect ( result ) . toBe ( "[Tool Use: read_file]\npath: test.ts\nencoding: utf-8" )
1238+ } )
1239+
1240+ it ( "should convert tool_use block with nested object input to text" , ( ) => {
1241+ const block : Anthropic . Messages . ToolUseBlockParam = {
1242+ type : "tool_use" ,
1243+ id : "tool-456" ,
1244+ name : "write_file" ,
1245+ input : {
1246+ path : "output.json" ,
1247+ content : { key : "value" , nested : { a : 1 } } ,
1248+ } ,
1249+ }
1250+
1251+ const result = toolUseToText ( block )
1252+
1253+ expect ( result ) . toContain ( "[Tool Use: write_file]" )
1254+ expect ( result ) . toContain ( "path: output.json" )
1255+ expect ( result ) . toContain ( "content:" )
1256+ expect ( result ) . toContain ( '"key"' )
1257+ expect ( result ) . toContain ( '"value"' )
1258+ } )
1259+
1260+ it ( "should convert tool_use block with string input to text" , ( ) => {
1261+ const block : Anthropic . Messages . ToolUseBlockParam = {
1262+ type : "tool_use" ,
1263+ id : "tool-789" ,
1264+ name : "execute_command" ,
1265+ input : "ls -la" as unknown as Record < string , unknown > ,
1266+ }
1267+
1268+ const result = toolUseToText ( block )
1269+
1270+ expect ( result ) . toBe ( "[Tool Use: execute_command]\nls -la" )
1271+ } )
1272+
1273+ it ( "should handle empty object input" , ( ) => {
1274+ const block : Anthropic . Messages . ToolUseBlockParam = {
1275+ type : "tool_use" ,
1276+ id : "tool-empty" ,
1277+ name : "some_tool" ,
1278+ input : { } ,
1279+ }
1280+
1281+ const result = toolUseToText ( block )
1282+
1283+ expect ( result ) . toBe ( "[Tool Use: some_tool]\n" )
1284+ } )
1285+ } )
1286+
1287+ describe ( "toolResultToText" , ( ) => {
1288+ it ( "should convert tool_result with string content to text" , ( ) => {
1289+ const block : Anthropic . Messages . ToolResultBlockParam = {
1290+ type : "tool_result" ,
1291+ tool_use_id : "tool-123" ,
1292+ content : "File contents here" ,
1293+ }
1294+
1295+ const result = toolResultToText ( block )
1296+
1297+ expect ( result ) . toBe ( "[Tool Result]\nFile contents here" )
1298+ } )
1299+
1300+ it ( "should convert tool_result with error flag to text" , ( ) => {
1301+ const block : Anthropic . Messages . ToolResultBlockParam = {
1302+ type : "tool_result" ,
1303+ tool_use_id : "tool-456" ,
1304+ content : "File not found" ,
1305+ is_error : true ,
1306+ }
1307+
1308+ const result = toolResultToText ( block )
1309+
1310+ expect ( result ) . toBe ( "[Tool Result (Error)]\nFile not found" )
1311+ } )
1312+
1313+ it ( "should convert tool_result with array content to text" , ( ) => {
1314+ const block : Anthropic . Messages . ToolResultBlockParam = {
1315+ type : "tool_result" ,
1316+ tool_use_id : "tool-789" ,
1317+ content : [
1318+ { type : "text" , text : "First line" } ,
1319+ { type : "text" , text : "Second line" } ,
1320+ ] ,
1321+ }
1322+
1323+ const result = toolResultToText ( block )
1324+
1325+ expect ( result ) . toBe ( "[Tool Result]\nFirst line\nSecond line" )
1326+ } )
1327+
1328+ it ( "should handle tool_result with image in array content" , ( ) => {
1329+ const block : Anthropic . Messages . ToolResultBlockParam = {
1330+ type : "tool_result" ,
1331+ tool_use_id : "tool-img" ,
1332+ content : [
1333+ { type : "text" , text : "Screenshot:" } ,
1334+ { type : "image" , source : { type : "base64" , media_type : "image/png" , data : "abc123" } } ,
1335+ ] ,
1336+ }
1337+
1338+ const result = toolResultToText ( block )
1339+
1340+ expect ( result ) . toBe ( "[Tool Result]\nScreenshot:\n[Image]" )
1341+ } )
1342+
1343+ it ( "should handle tool_result with no content" , ( ) => {
1344+ const block : Anthropic . Messages . ToolResultBlockParam = {
1345+ type : "tool_result" ,
1346+ tool_use_id : "tool-empty" ,
1347+ }
1348+
1349+ const result = toolResultToText ( block )
1350+
1351+ expect ( result ) . toBe ( "[Tool Result]" )
1352+ } )
1353+ } )
1354+
1355+ describe ( "convertToolBlocksToText" , ( ) => {
1356+ it ( "should return string content unchanged" , ( ) => {
1357+ const content = "Simple text content"
1358+
1359+ const result = convertToolBlocksToText ( content )
1360+
1361+ expect ( result ) . toBe ( "Simple text content" )
1362+ } )
1363+
1364+ it ( "should convert tool_use blocks to text blocks" , ( ) => {
1365+ const content : Anthropic . Messages . ContentBlockParam [ ] = [
1366+ {
1367+ type : "tool_use" ,
1368+ id : "tool-123" ,
1369+ name : "read_file" ,
1370+ input : { path : "test.ts" } ,
1371+ } ,
1372+ ]
1373+
1374+ const result = convertToolBlocksToText ( content )
1375+
1376+ expect ( Array . isArray ( result ) ) . toBe ( true )
1377+ expect ( ( result as Anthropic . Messages . ContentBlockParam [ ] ) [ 0 ] . type ) . toBe ( "text" )
1378+ expect ( ( result as Anthropic . Messages . TextBlockParam [ ] ) [ 0 ] . text ) . toContain ( "[Tool Use: read_file]" )
1379+ } )
1380+
1381+ it ( "should convert tool_result blocks to text blocks" , ( ) => {
1382+ const content : Anthropic . Messages . ContentBlockParam [ ] = [
1383+ {
1384+ type : "tool_result" ,
1385+ tool_use_id : "tool-123" ,
1386+ content : "File contents" ,
1387+ } ,
1388+ ]
1389+
1390+ const result = convertToolBlocksToText ( content )
1391+
1392+ expect ( Array . isArray ( result ) ) . toBe ( true )
1393+ expect ( ( result as Anthropic . Messages . ContentBlockParam [ ] ) [ 0 ] . type ) . toBe ( "text" )
1394+ expect ( ( result as Anthropic . Messages . TextBlockParam [ ] ) [ 0 ] . text ) . toContain ( "[Tool Result]" )
1395+ } )
1396+
1397+ it ( "should preserve non-tool blocks unchanged" , ( ) => {
1398+ const content : Anthropic . Messages . ContentBlockParam [ ] = [
1399+ { type : "text" , text : "Hello" } ,
1400+ {
1401+ type : "tool_use" ,
1402+ id : "tool-123" ,
1403+ name : "read_file" ,
1404+ input : { path : "test.ts" } ,
1405+ } ,
1406+ { type : "text" , text : "World" } ,
1407+ ]
1408+
1409+ const result = convertToolBlocksToText ( content )
1410+
1411+ expect ( Array . isArray ( result ) ) . toBe ( true )
1412+ const resultArray = result as Anthropic . Messages . ContentBlockParam [ ]
1413+ expect ( resultArray ) . toHaveLength ( 3 )
1414+ expect ( resultArray [ 0 ] ) . toEqual ( { type : "text" , text : "Hello" } )
1415+ expect ( resultArray [ 1 ] . type ) . toBe ( "text" )
1416+ expect ( ( resultArray [ 1 ] as Anthropic . Messages . TextBlockParam ) . text ) . toContain ( "[Tool Use: read_file]" )
1417+ expect ( resultArray [ 2 ] ) . toEqual ( { type : "text" , text : "World" } )
1418+ } )
1419+
1420+ it ( "should handle mixed content with multiple tool blocks" , ( ) => {
1421+ const content : Anthropic . Messages . ContentBlockParam [ ] = [
1422+ {
1423+ type : "tool_use" ,
1424+ id : "tool-1" ,
1425+ name : "read_file" ,
1426+ input : { path : "a.ts" } ,
1427+ } ,
1428+ {
1429+ type : "tool_result" ,
1430+ tool_use_id : "tool-1" ,
1431+ content : "contents of a.ts" ,
1432+ } ,
1433+ ]
1434+
1435+ const result = convertToolBlocksToText ( content )
1436+
1437+ expect ( Array . isArray ( result ) ) . toBe ( true )
1438+ const resultArray = result as Anthropic . Messages . ContentBlockParam [ ]
1439+ expect ( resultArray ) . toHaveLength ( 2 )
1440+ expect ( ( resultArray [ 0 ] as Anthropic . Messages . TextBlockParam ) . text ) . toContain ( "[Tool Use: read_file]" )
1441+ expect ( ( resultArray [ 1 ] as Anthropic . Messages . TextBlockParam ) . text ) . toContain ( "[Tool Result]" )
1442+ expect ( ( resultArray [ 1 ] as Anthropic . Messages . TextBlockParam ) . text ) . toContain ( "contents of a.ts" )
1443+ } )
1444+ } )
1445+
1446+ describe ( "transformMessagesForCondensing" , ( ) => {
1447+ it ( "should transform all messages with tool blocks to text" , ( ) => {
1448+ const messages = [
1449+ { role : "user" as const , content : "Hello" } ,
1450+ {
1451+ role : "assistant" as const ,
1452+ content : [
1453+ {
1454+ type : "tool_use" as const ,
1455+ id : "tool-1" ,
1456+ name : "read_file" ,
1457+ input : { path : "test.ts" } ,
1458+ } ,
1459+ ] ,
1460+ } ,
1461+ {
1462+ role : "user" as const ,
1463+ content : [
1464+ {
1465+ type : "tool_result" as const ,
1466+ tool_use_id : "tool-1" ,
1467+ content : "file contents" ,
1468+ } ,
1469+ ] ,
1470+ } ,
1471+ ]
1472+
1473+ const result = transformMessagesForCondensing ( messages )
1474+
1475+ expect ( result ) . toHaveLength ( 3 )
1476+ expect ( result [ 0 ] . content ) . toBe ( "Hello" )
1477+ expect ( Array . isArray ( result [ 1 ] . content ) ) . toBe ( true )
1478+ expect ( ( result [ 1 ] . content as any [ ] ) [ 0 ] . type ) . toBe ( "text" )
1479+ expect ( ( result [ 1 ] . content as any [ ] ) [ 0 ] . text ) . toContain ( "[Tool Use: read_file]" )
1480+ expect ( Array . isArray ( result [ 2 ] . content ) ) . toBe ( true )
1481+ expect ( ( result [ 2 ] . content as any [ ] ) [ 0 ] . type ) . toBe ( "text" )
1482+ expect ( ( result [ 2 ] . content as any [ ] ) [ 0 ] . text ) . toContain ( "[Tool Result]" )
1483+ } )
1484+
1485+ it ( "should preserve message role and other properties" , ( ) => {
1486+ const messages = [
1487+ {
1488+ role : "assistant" as const ,
1489+ content : [
1490+ {
1491+ type : "tool_use" as const ,
1492+ id : "tool-1" ,
1493+ name : "execute" ,
1494+ input : { cmd : "ls" } ,
1495+ } ,
1496+ ] ,
1497+ } ,
1498+ ]
1499+
1500+ const result = transformMessagesForCondensing ( messages )
1501+
1502+ expect ( result [ 0 ] . role ) . toBe ( "assistant" )
1503+ } )
1504+
1505+ it ( "should handle empty messages array" , ( ) => {
1506+ const result = transformMessagesForCondensing ( [ ] )
1507+
1508+ expect ( result ) . toEqual ( [ ] )
1509+ } )
1510+
1511+ it ( "should not mutate original messages" , ( ) => {
1512+ const originalContent = [
1513+ {
1514+ type : "tool_use" as const ,
1515+ id : "tool-1" ,
1516+ name : "read_file" ,
1517+ input : { path : "test.ts" } ,
1518+ } ,
1519+ ]
1520+ const messages = [ { role : "assistant" as const , content : originalContent } ]
1521+
1522+ transformMessagesForCondensing ( messages )
1523+
1524+ // Original should still have tool_use type
1525+ expect ( messages [ 0 ] . content [ 0 ] . type ) . toBe ( "tool_use" )
1526+ } )
1527+ } )
0 commit comments