Skip to content

Commit ff9044b

Browse files
committed
make forking work
1 parent 8fe8366 commit ff9044b

3 files changed

Lines changed: 41 additions & 20 deletions

File tree

src/vs/platform/agentHost/node/agentService.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,10 +179,7 @@ export class AgentService extends Disposable implements IAgentService {
179179
const sourceState = this._stateManager.getSessionState(config.fork.session.toString());
180180
let sourceTurns: ITurn[] = [];
181181
if (sourceState) {
182-
const forkIdx = sourceState.turns.findIndex(t => t.id === config.fork!.turnId);
183-
if (forkIdx >= 0) {
184-
sourceTurns = sourceState.turns.slice(0, forkIdx + 1);
185-
}
182+
sourceTurns = sourceState.turns.slice(0, config.fork.turnIndex + 1);
186183
}
187184

188185
const summary: ISessionSummary = {

src/vs/platform/agentHost/node/copilot/copilotAgentForking.ts

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -310,24 +310,41 @@ export async function forkSessionInDb(
310310
[newSessionId, sourceSessionId, forkTurnIndex],
311311
);
312312

313-
// Copy search index entries for kept turns
314-
await dbRun(db,
315-
`INSERT INTO search_index (content, session_id, source_type, source_id)
316-
SELECT content, ?, source_type,
317-
REPLACE(source_id, ?, ?)
313+
// Copy search index entries for kept turns only.
314+
// source_id format is "<session_id>:turn:<turn_index>"; filter by
315+
// parsing the turn index so we don't leak content from later turns.
316+
await dbAll(db,
317+
`SELECT content, source_type, source_id
318318
FROM search_index
319-
WHERE session_id = ?
320-
AND source_type = 'turn'`,
321-
[newSessionId, sourceSessionId, newSessionId, sourceSessionId],
322-
);
319+
WHERE session_id = ? AND source_type = 'turn'`,
320+
[sourceSessionId],
321+
).then(async rows => {
322+
const prefix = `${sourceSessionId}:turn:`;
323+
for (const row of rows) {
324+
const sourceId = row.source_id as string;
325+
if (sourceId.startsWith(prefix)) {
326+
const turnIdx = parseInt(sourceId.substring(prefix.length), 10);
327+
if (!isNaN(turnIdx) && turnIdx <= forkTurnIndex) {
328+
const newSourceId = sourceId.replace(sourceSessionId, newSessionId);
329+
await dbRun(db,
330+
`INSERT INTO search_index (content, session_id, source_type, source_id)
331+
VALUES (?, ?, ?, ?)`,
332+
[row.content, newSessionId, row.source_type, newSourceId],
333+
);
334+
}
335+
}
336+
}
337+
});
323338

324-
// Copy checkpoints at or before the fork point
339+
// Copy checkpoints at or before the fork point.
340+
// checkpoint_number is 1-based and correlates to turns, so we keep
341+
// only those where checkpoint_number <= forkTurnIndex + 1.
325342
await dbRun(db,
326343
`INSERT INTO checkpoints (session_id, checkpoint_number, title, overview, history, work_done, technical_details, important_files, next_steps, created_at)
327344
SELECT ?, checkpoint_number, title, overview, history, work_done, technical_details, important_files, next_steps, created_at
328345
FROM checkpoints
329-
WHERE session_id = ?`,
330-
[newSessionId, sourceSessionId],
346+
WHERE session_id = ? AND checkpoint_number <= ?`,
347+
[newSessionId, sourceSessionId, forkTurnIndex + 1],
331348
);
332349

333350
await dbExec(db, 'COMMIT');

src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostSessionHandler.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,15 +1270,22 @@ export class AgentHostSessionHandler extends Disposable implements IChatSessionC
12701270
}
12711271

12721272
// Determine the turn index to fork at. If a specific request is
1273-
// provided, find its position in the protocol state's turn list.
1274-
// Otherwise fork the entire session.
1273+
// provided, fork BEFORE it (keeping turns up to the previous one).
1274+
// This matches the non-contributed path in ForkConversationAction
1275+
// which uses `requestIndex - 1`. If no request is provided, fork
1276+
// the entire session.
12751277
const protocolState = this._clientState.getSessionState(backendSession.toString());
12761278
let turnIndex: number | undefined;
12771279
if (request) {
1278-
turnIndex = protocolState?.turns.findIndex(t => t.id === request.id);
1279-
if (turnIndex === undefined || turnIndex < 0) {
1280+
const requestIdx = protocolState?.turns.findIndex(t => t.id === request.id);
1281+
if (requestIdx === undefined || requestIdx < 0) {
12801282
throw new Error(`Cannot fork: turn for request ${request.id} not found in protocol state`);
12811283
}
1284+
// Fork before this request — keep turns [0..requestIdx-1]
1285+
turnIndex = requestIdx - 1;
1286+
if (turnIndex < 0) {
1287+
throw new Error('Cannot fork: cannot fork before the first request');
1288+
}
12821289
} else if (protocolState && protocolState.turns.length > 0) {
12831290
turnIndex = protocolState.turns.length - 1;
12841291
}

0 commit comments

Comments
 (0)