@@ -1249,6 +1249,102 @@ local function define_tests()
12491249 test .eq (full_content , " Hello" )
12501250 test .eq (# content_chunks , 1 )
12511251 end )
1252+
1253+ it (" should handle SSE events split across chunk boundaries" , function ()
1254+ local stream_chunks = {
1255+ ' event: message_start\n data: {"type":"message_start","message":{"usage":{"input_tokens":10,"output_tokens":0}}}\n\n ' ,
1256+ ' event: content_block_start\n data: {"type":"content_block_start","index":0,"content_block":{"type":"tool_use","id":"call_split","name":"run_script"}}\n\n ' ,
1257+ ' event: content_block_delta\n data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":"{\\ "scr"}}\n\n ' ..
1258+ ' event: content_block_del' ,
1259+ ' ta\n data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":"ipt\\ ": \\ "echo"}}\n\n ' ,
1260+ ' event: content_block_delta\n data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":" hello\\ "}"}}\n\n event: content_block_stop\n data: {"type":"content_block_stop","index":0}\n\n ' ,
1261+ ' event: message_delta\n data: {"type":"message_delta","delta":{"stop_reason":"tool_use"},"usage":{"output_tokens":8}}\n\n ' ,
1262+ ' event: message_stop\n data: {"type":"message_stop"}\n\n '
1263+ }
1264+
1265+ local mock_stream = {
1266+ chunks = stream_chunks ,
1267+ current = 0
1268+ }
1269+
1270+ setmetatable (mock_stream , {
1271+ __index = {
1272+ read = function (self )
1273+ self .current = self .current + 1
1274+ if self .current <= # self .chunks then
1275+ return self .chunks [self .current ]
1276+ end
1277+ return nil
1278+ end
1279+ }
1280+ })
1281+
1282+ local stream_response = {
1283+ stream = mock_stream ,
1284+ metadata = {}
1285+ }
1286+
1287+ local tool_calls = {}
1288+
1289+ local full_content , err , result = claude_client .process_stream (stream_response , {
1290+ on_tool_call = function (tool_call )
1291+ table.insert (tool_calls , tool_call )
1292+ end
1293+ })
1294+
1295+ test .is_nil (err )
1296+ test .eq (# tool_calls , 1 )
1297+ local tc = assert (tool_calls [1 ])
1298+ test .eq (tc .id , " call_split" )
1299+ test .eq (tc .name , " run_script" )
1300+ test .eq (tc .arguments .script , " echo hello" )
1301+ end )
1302+
1303+ it (" should handle chunk containing no complete events" , function ()
1304+ local stream_chunks = {
1305+ ' event: message_sta' ,
1306+ ' rt\n data: {"type":"message_start","message":{"usage":{"input_tokens":5,"output_tokens":0}}}\n\n ' ,
1307+ ' event: content_block_start\n data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}\n\n ' ,
1308+ ' event: content_block_delta\n data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"OK"}}\n\n ' ,
1309+ ' event: content_block_stop\n data: {"type":"content_block_stop","index":0}\n\n ' ,
1310+ ' event: message_delta\n data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"output_tokens":1}}\n\n ' ,
1311+ ' event: message_stop\n data: {"type":"message_stop"}\n\n '
1312+ }
1313+
1314+ local mock_stream = {
1315+ chunks = stream_chunks ,
1316+ current = 0
1317+ }
1318+
1319+ setmetatable (mock_stream , {
1320+ __index = {
1321+ read = function (self )
1322+ self .current = self .current + 1
1323+ if self .current <= # self .chunks then
1324+ return self .chunks [self .current ]
1325+ end
1326+ return nil
1327+ end
1328+ }
1329+ })
1330+
1331+ local stream_response = {
1332+ stream = mock_stream ,
1333+ metadata = {}
1334+ }
1335+
1336+ local content_chunks = {}
1337+
1338+ local full_content , err , result = claude_client .process_stream (stream_response , {
1339+ on_content = function (chunk )
1340+ table.insert (content_chunks , chunk )
1341+ end
1342+ })
1343+
1344+ test .is_nil (err )
1345+ test .eq (full_content , " OK" )
1346+ test .eq (# content_chunks , 1 )
1347+ end )
12521348 end )
12531349
12541350 describe (" Configuration Edge Cases" , function ()
0 commit comments