@@ -13,6 +13,16 @@ import {
1313} from '../../../common/sessionParsing' ;
1414import { diffHeaders , diffNoAts , simpleDiff } from './fixtures/gitdiff/sessionParsing' ;
1515
16+ // Helper to construct a toolCall object
17+ function makeToolCall ( name : string , args : any ) : any {
18+ return {
19+ function : { name, arguments : JSON . stringify ( args ) } ,
20+ id : 'id_' + name + '_' + Math . random ( ) . toString ( 36 ) . slice ( 2 ) ,
21+ type : 'function' ,
22+ index : 0
23+ } ;
24+ }
25+
1626describe ( 'sessionParsing' , function ( ) {
1727 describe ( 'parseSessionLogs()' , function ( ) {
1828 it ( 'should parse valid session logs' , function ( ) {
@@ -206,6 +216,139 @@ another non-data line`;
206216 assert . strictEqual ( result . toolName , 'Read repository' ) ;
207217 assert . strictEqual ( result . invocationMessage , 'Read repository' ) ;
208218 } ) ;
219+
220+ it ( 'handles str_replace_editor view with diff-parsed content (empty file label -> repository)' , function ( ) {
221+ const diff = [
222+ 'diff --git a/src/file.ts b/src/file.ts' ,
223+ 'index 1111111..2222222 100644' ,
224+ '--- a/src/file.ts' ,
225+ '+++ b/src/file.ts' ,
226+ '@@ -1,2 +1,2 @@' ,
227+ '-old line' ,
228+ '+new line'
229+ ] . join ( '\n' ) ;
230+ const toolCall = makeToolCall ( 'str_replace_editor' , { command : 'view' , view_range : [ 1 , 10 ] } ) ;
231+ const result = parseToolCallDetails ( toolCall , diff ) ;
232+ assert . strictEqual ( result . toolName , 'Read repository' ) ;
233+ assert . strictEqual ( result . invocationMessage , 'Read repository' ) ;
234+ } ) ;
235+
236+ it ( 'handles str_replace_editor view with diff-parsed content (non-empty file label)' , function ( ) {
237+ const diff = [
238+ 'diff --git a/home/runner/work/repo/repo/src/deep/file.ts b/home/runner/work/repo/repo/src/deep/file.ts' ,
239+ 'index 1111111..2222222 100644' ,
240+ '--- a/home/runner/work/repo/repo/src/deep/file.ts' ,
241+ '+++ b/home/runner/work/repo/repo/src/deep/file.ts' ,
242+ '@@ -1,2 +1,2 @@' ,
243+ '-old line' ,
244+ '+new line'
245+ ] . join ( '\n' ) ;
246+ const toolCall = makeToolCall ( 'str_replace_editor' , { command : 'view' , view_range : [ 2 , 8 ] } ) ;
247+ const result = parseToolCallDetails ( toolCall , diff ) ;
248+ assert . strictEqual ( result . toolName , 'Read' ) ;
249+ assert . ok ( result . invocationMessage . includes ( 'src/deep/file.ts' ) ) ;
250+ assert . ok ( result . invocationMessage . includes ( 'lines 2 to 8' ) ) ;
251+ assert . ok ( result . toolSpecificData && 'command' in result . toolSpecificData ) ;
252+ } ) ;
253+
254+ it ( 'handles str_replace_editor view with path but unparsable diff content (no diff headers)' , function ( ) {
255+ const content = 'just some file content without diff headers' ;
256+ const toolCall = makeToolCall ( 'str_replace_editor' , { command : 'view' , path : '/home/runner/work/repo/repo/src/other.ts' } ) ;
257+ const result = parseToolCallDetails ( toolCall , content ) ;
258+ assert . strictEqual ( result . toolName , 'Read' ) ;
259+ assert . strictEqual ( result . invocationMessage , 'Read src/other.ts' ) ;
260+ } ) ;
261+
262+ it ( 'handles str_replace_editor view with undefined path (no label)' , function ( ) {
263+ const toolCall = makeToolCall ( 'str_replace_editor' , { command : 'view' } ) ;
264+ const result = parseToolCallDetails ( toolCall , 'plain content' ) ;
265+ assert . strictEqual ( result . toolName , 'Read repository' ) ;
266+ assert . strictEqual ( result . invocationMessage , 'Read repository' ) ;
267+ } ) ;
268+
269+ it ( 'handles str_replace_editor view with root repository path empty label branch' , function ( ) {
270+ const toolCall = makeToolCall ( 'str_replace_editor' , { command : 'view' , path : '/home/runner/work/repo/repo/' } ) ;
271+ const result = parseToolCallDetails ( toolCall , 'content' ) ;
272+ assert . strictEqual ( result . toolName , 'Read repository' ) ;
273+ } ) ;
274+
275+ it ( 'handles str_replace_editor edit with range' , function ( ) {
276+ const toolCall = makeToolCall ( 'str_replace_editor' , { command : 'edit' , path : '/home/runner/work/repo/repo/src/editMe.ts' , view_range : [ 5 , 15 ] } ) ;
277+ const result = parseToolCallDetails ( toolCall , '' ) ;
278+ assert . strictEqual ( result . toolName , 'Edit' ) ;
279+ assert . ok ( result . invocationMessage . includes ( 'lines 5 to 15' ) ) ;
280+ } ) ;
281+
282+ it ( 'handles str_replace (non-editor) path missing label fallback' , function ( ) {
283+ // Provide a path that toFileLabel will still shorten; assert structure
284+ const toolCall = makeToolCall ( 'str_replace' , { path : '/home/runner/work/repo/repo/src/x.ts' } ) ;
285+ const result = parseToolCallDetails ( toolCall , '' ) ;
286+ assert . strictEqual ( result . toolName , 'Edit' ) ;
287+ assert . strictEqual ( result . invocationMessage , 'Edit [](src/x.ts)' ) ;
288+ } ) ;
289+
290+ it ( 'handles create tool call' , function ( ) {
291+ const toolCall = makeToolCall ( 'create' , { path : '/home/runner/work/repo/repo/new/file.txt' } ) ;
292+ const result = parseToolCallDetails ( toolCall , '' ) ;
293+ assert . strictEqual ( result . toolName , 'Create' ) ;
294+ assert . strictEqual ( result . invocationMessage , 'Create [](new/file.txt)' ) ;
295+ } ) ;
296+
297+ it ( 'handles view tool call (non str_replace_editor) with range and root path giving repository label' , function ( ) {
298+ const toolCall = makeToolCall ( 'view' , { path : '/home/runner/work/repo/repo/' , view_range : [ 2 , 3 ] } ) ;
299+ const result = parseToolCallDetails ( toolCall , '' ) ;
300+ assert . strictEqual ( result . toolName , 'Read repository' ) ;
301+ assert . strictEqual ( result . invocationMessage , 'Read repository' ) ;
302+ } ) ;
303+
304+ it ( 'handles view tool call (non str_replace_editor) with file path and range' , function ( ) {
305+ const toolCall = makeToolCall ( 'view' , { path : '/home/runner/work/repo/repo/src/app.ts' , view_range : [ 3 , 7 ] } ) ;
306+ const result = parseToolCallDetails ( toolCall , '' ) ;
307+ assert . strictEqual ( result . toolName , 'Read' ) ;
308+ assert . ok ( result . invocationMessage . includes ( 'lines 3 to 7' ) ) ;
309+ } ) ;
310+
311+ it ( 'handles bash tool call without command (only content)' , function ( ) {
312+ const toolCall = makeToolCall ( 'bash' , { } ) ;
313+ const result = parseToolCallDetails ( toolCall , 'only output' ) ;
314+ assert . strictEqual ( result . toolName , 'Run Bash command' ) ;
315+ assert . strictEqual ( result . invocationMessage , 'only output' ) ;
316+ assert . ok ( ! result . toolSpecificData ) ; // no command so no toolSpecificData
317+ } ) ;
318+
319+ it ( 'handles read_bash tool call' , function ( ) {
320+ const toolCall = makeToolCall ( 'read_bash' , { } ) ;
321+ const result = parseToolCallDetails ( toolCall , 'ignored' ) ;
322+ assert . strictEqual ( result . toolName , 'read_bash' ) ;
323+ assert . strictEqual ( result . invocationMessage , 'Read logs from Bash session' ) ;
324+ } ) ;
325+
326+ it ( 'handles stop_bash tool call' , function ( ) {
327+ const toolCall = makeToolCall ( 'stop_bash' , { } ) ;
328+ const result = parseToolCallDetails ( toolCall , 'ignored' ) ;
329+ assert . strictEqual ( result . toolName , 'stop_bash' ) ;
330+ assert . strictEqual ( result . invocationMessage , 'Stop Bash session' ) ;
331+ } ) ;
332+
333+ it ( 'handles unknown tool call with empty content falling back to name' , function ( ) {
334+ const toolCall = makeToolCall ( 'mystery_tool' , { some : 'arg' } ) ;
335+ const result = parseToolCallDetails ( toolCall , '' ) ;
336+ assert . strictEqual ( result . toolName , 'mystery_tool' ) ;
337+ assert . strictEqual ( result . invocationMessage , 'mystery_tool' ) ;
338+ } ) ;
339+
340+ it ( 'gracefully handles invalid JSON arguments for non-view str_replace_editor (edit path undefined)' , function ( ) {
341+ const toolCall = {
342+ function : { name : 'str_replace_editor' , arguments : '{"command": "edit", invalid' } ,
343+ id : 'bad_json' ,
344+ type : 'function' ,
345+ index : 0
346+ } ;
347+ // Since JSON parse fails, args becomes {} and we are in else branch -> toolName Edit without file label
348+ const result = parseToolCallDetails ( toolCall as any , '' ) ;
349+ assert . strictEqual ( result . toolName , 'Edit' ) ;
350+ assert . strictEqual ( result . invocationMessage , 'Edit' ) ;
351+ } ) ;
209352 } ) ;
210353
211354 describe ( 'parseDiff()' , function ( ) {
0 commit comments