This commit is contained in:
Connor Peet
2026-03-26 18:20:51 -07:00
parent da5fb11b3b
commit b0caf28f7e
5 changed files with 52 additions and 14 deletions

View File

@@ -172,7 +172,6 @@ export class AgentService extends Disposable implements IAgentService {
this._sessionToProvider.delete(session.toString());
}
this._stateManager.deleteSession(session.toString());
this._sessionDataService.deleteSessionData(session);
}
// ---- Protocol methods ---------------------------------------------------

View File

@@ -341,7 +341,6 @@ export class AgentSideEffects extends Disposable implements IProtocolSideEffectH
const agent = this._options.getAgent(session);
agent?.disposeSession(URI.parse(session)).catch(() => { });
this._stateManager.deleteSession(session);
this._options.sessionDataService.deleteSessionData(URI.parse(session));
}
async handleListSessions(): Promise<ISessionSummary[]> {

View File

@@ -45,12 +45,16 @@ export function parseSessionDbUri(raw: string): ISessionDbUriFields | undefined
if (!toolCallId || !filePath || (part !== 'before' && part !== 'after')) {
return undefined;
}
return {
sessionUri: decodeHex(parsed.authority).toString(),
toolCallId: decodeURIComponent(toolCallId),
filePath: decodeHex(filePath).toString(),
part
};
try {
return {
sessionUri: decodeHex(parsed.authority).toString(),
toolCallId: decodeURIComponent(toolCallId),
filePath: decodeHex(filePath).toString(),
part
};
} catch {
return undefined;
}
}
/**

View File

@@ -115,7 +115,7 @@ export async function mapSessionEvents(
list.push(r);
}
}
} catch {
} catch (_e) {
// Database may not exist yet for new sessions — that's fine
}
}

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import { IMarkdownString, MarkdownString } from '../../../../../../base/common/htmlContent.js';
import { generateUuid } from '../../../../../../base/common/uuid.js';
import { URI } from '../../../../../../base/common/uri.js';
import { ToolCallStatus, TurnState, ResponsePartKind, getToolFileEdits, getToolOutputText, type ICompletedToolCall, type IToolCallState, type ITurn } from '../../../../../../platform/agentHost/common/state/sessionState.js';
import { getToolKind, getToolLanguage } from '../../../../../../platform/agentHost/common/state/sessionReducers.js';
@@ -46,12 +45,20 @@ export function turnsToHistory(turns: readonly ITurn[], participantId: string):
switch (rp.kind) {
case ResponsePartKind.Markdown:
if (rp.content) {
parts.push({ kind: 'markdownContent', content: new MarkdownString(rp.content) });
parts.push({ kind: 'markdownContent', content: new MarkdownString(rp.content, { supportHtml: true }) });
}
break;
case ResponsePartKind.ToolCall:
parts.push(completedToolCallToSerialized(rp.toolCall as ICompletedToolCall));
case ResponsePartKind.ToolCall: {
const tc = rp.toolCall as ICompletedToolCall;
const fileEditParts = completedToolCallToEditParts(tc);
const serialized = completedToolCallToSerialized(tc);
if (fileEditParts.length > 0) {
serialized.presentation = ToolInvocationPresentation.Hidden;
}
parts.push(serialized);
parts.push(...fileEditParts);
break;
}
case ResponsePartKind.Reasoning:
if (rp.content) {
parts.push({ kind: 'thinking', value: rp.content });
@@ -122,6 +129,35 @@ function completedToolCallToSerialized(tc: ICompletedToolCall): IChatToolInvocat
};
}
/**
* Builds edit-structure progress parts for a completed tool call that
* produced file edits. Returns an empty array if the tool call has no edits.
* These parts replay the undo stops and code-block UI when restoring history.
*/
function completedToolCallToEditParts(tc: ICompletedToolCall): IChatProgress[] {
if (tc.status !== ToolCallStatus.Completed) {
return [];
}
const fileEdits = getToolFileEdits(tc);
if (fileEdits.length === 0) {
return [];
}
const filePath = getFilePathFromToolInput(tc);
if (!filePath) {
return [];
}
const fileUri = URI.file(filePath);
const parts: IChatProgress[] = [];
for (const _edit of fileEdits) {
parts.push({ kind: 'markdownContent', content: new MarkdownString('\n````\n') });
parts.push({ kind: 'codeblockUri', uri: fileUri, isEdit: true, undoStopId: tc.toolCallId });
parts.push({ kind: 'textEdit', uri: fileUri, edits: [], done: false, isExternalEdit: true });
parts.push({ kind: 'textEdit', uri: fileUri, edits: [], done: true, isExternalEdit: true });
parts.push({ kind: 'markdownContent', content: new MarkdownString('\n````\n') });
}
return parts;
}
/**
* Creates a live {@link ChatToolInvocation} from the protocol's tool-call
* state. Used during active turns to represent running tool calls in the UI.
@@ -278,7 +314,7 @@ function fileEditsToExternalEdits(tc: IToolCallState): IToolCallFileEdit[] {
resource: URI.file(filePath),
beforeContentUri: URI.parse(edit.beforeURI),
afterContentUri: URI.parse(edit.afterURI),
undoStopId: generateUuid(),
undoStopId: tc.toolCallId,
});
}
}