@@ -5,6 +5,7 @@ import * as fs from "fs";
55import * as os from "os" ;
66import * as path from "path" ;
77import { GitFileHistory } from "../common/file-history" ;
8+ import { clearSessionState } from "../common/state" ;
89import { type SessionMessage } from "../session" ;
910import { SessionManager } from "../session" ;
1011
@@ -1257,6 +1258,75 @@ test("replySession /continue runs trailing pending tool calls before requesting
12571258 ) ;
12581259} ) ;
12591260
1261+ test ( "replySession rebuilds snippet state from persisted read history before editing" , async ( ) => {
1262+ const workspace = createTempDir ( "deepcode-rebuild-snippet-workspace-" ) ;
1263+ const home = createTempDir ( "deepcode-rebuild-snippet-home-" ) ;
1264+ setHomeDir ( home ) ;
1265+
1266+ const filePath = path . join ( workspace , "note.txt" ) ;
1267+ fs . writeFileSync ( filePath , "alpha\nbeta\n" , "utf8" ) ;
1268+
1269+ const responses = [
1270+ createToolCallResponse (
1271+ [
1272+ {
1273+ id : "call-edit" ,
1274+ type : "function" ,
1275+ function : {
1276+ name : "edit" ,
1277+ arguments : JSON . stringify ( {
1278+ snippet_id : "full_file_5" ,
1279+ file_path : filePath ,
1280+ old_string : "beta" ,
1281+ new_string : "gamma" ,
1282+ } ) ,
1283+ } ,
1284+ } ,
1285+ ] ,
1286+ { prompt_tokens : 1 , completion_tokens : 1 , total_tokens : 2 }
1287+ ) ,
1288+ createChatResponse ( "done" , { prompt_tokens : 1 , completion_tokens : 1 , total_tokens : 2 } ) ,
1289+ ] ;
1290+ const manager = createMockedClientSessionManager ( workspace , responses ) ;
1291+ const originalActivateSession = manager . activateSession . bind ( manager ) ;
1292+ ( manager as any ) . activateSession = async ( ) => { } ;
1293+
1294+ const sessionId = await manager . createSession ( { text : "first prompt" } ) ;
1295+ const readToolMessage = ( manager as any ) . buildToolMessage (
1296+ sessionId ,
1297+ "call-read" ,
1298+ JSON . stringify ( {
1299+ ok : true ,
1300+ name : "read" ,
1301+ output : " 1\talpha\n 2\tbeta\n" ,
1302+ metadata : {
1303+ snippet : {
1304+ id : "full_file_5" ,
1305+ filePath,
1306+ startLine : 1 ,
1307+ endLine : 3 ,
1308+ } ,
1309+ } ,
1310+ } ) ,
1311+ { name : "read" , arguments : JSON . stringify ( { file_path : filePath } ) }
1312+ ) as SessionMessage ;
1313+ ( manager as any ) . appendSessionMessage ( sessionId , readToolMessage ) ;
1314+
1315+ clearSessionState ( sessionId ) ;
1316+ ( manager as any ) . activateSession = originalActivateSession ;
1317+
1318+ await manager . replySession ( sessionId , { text : "change beta" } ) ;
1319+
1320+ assert . equal ( fs . readFileSync ( filePath , "utf8" ) , "alpha\ngamma\n" ) ;
1321+ const editToolMessage = manager . listSessionMessages ( sessionId ) . find ( ( message ) => {
1322+ const params = message . messageParams as { tool_call_id ?: string } | null ;
1323+ return message . role === "tool" && params ?. tool_call_id === "call-edit" ;
1324+ } ) ;
1325+ assert . ok ( editToolMessage ) ;
1326+ assert . match ( editToolMessage . content ?? "" , / " o k " : t r u e | " o k " : t r u e / ) ;
1327+ assert . doesNotMatch ( editToolMessage . content ?? "" , / U n k n o w n s n i p p e t _ i d / ) ;
1328+ } ) ;
1329+
12601330test ( "activateSession pauses for permission when a tool call requires ask" , async ( ) => {
12611331 const workspace = createTempDir ( "deepcode-permission-ask-workspace-" ) ;
12621332 const home = createTempDir ( "deepcode-permission-ask-home-" ) ;
@@ -2712,6 +2782,13 @@ function createChatResponse(content: string, usage: Record<string, unknown>): un
27122782 } ;
27132783}
27142784
2785+ function createToolCallResponse ( toolCalls : unknown [ ] , usage : Record < string , unknown > ) : unknown {
2786+ return {
2787+ choices : [ { message : { content : "" , tool_calls : toolCalls } } ] ,
2788+ usage,
2789+ } ;
2790+ }
2791+
27152792function buildTestMessage (
27162793 id : string ,
27172794 sessionId : string ,
0 commit comments