feat(coding-agent): add fork position and duplicate session option (#3431)

This commit is contained in:
Armin Ronacher
2026-04-20 14:13:34 +02:00
committed by GitHub
parent ebc60aa825
commit 23569e304b
10 changed files with 128 additions and 39 deletions

View File

@@ -1451,9 +1451,9 @@ export class InteractiveMode {
return this.handleFatalRuntimeError("Failed to create session", error);
}
},
fork: async (entryId) => {
fork: async (entryId, options) => {
try {
const result = await this.runtimeHost.fork(entryId);
const result = await this.runtimeHost.fork(entryId, options);
if (!result.cancelled) {
await this.handleRuntimeSessionChange();
this.renderCurrentSessionState();
@@ -3970,6 +3970,7 @@ export class InteractiveMode {
}
private showUserMessageSelector(): void {
const duplicateSessionOptionId = "__duplicate_session__";
const userMessages = this.session.getUserMessagesForForking();
if (userMessages.length === 0) {
@@ -3977,26 +3978,49 @@ export class InteractiveMode {
return;
}
const selectableEntries = [
...userMessages.map((m) => ({ id: m.entryId, text: m.text })),
{ id: duplicateSessionOptionId, text: "Duplicate session" },
];
const initialSelectedId = userMessages[userMessages.length - 1]?.entryId;
this.showSelector((done) => {
const selector = new UserMessageSelectorComponent(
userMessages.map((m) => ({ id: m.entryId, text: m.text })),
selectableEntries,
async (entryId) => {
const result = await this.runtimeHost.fork(entryId);
if (result.cancelled) {
try {
let result: { cancelled: boolean; selectedText?: string };
if (entryId === duplicateSessionOptionId) {
const leafId = this.sessionManager.getLeafId();
if (!leafId) {
throw new Error("Cannot duplicate session: no current entry selected");
}
result = await this.runtimeHost.fork(leafId, { position: "at" });
} else {
result = await this.runtimeHost.fork(entryId);
}
if (result.cancelled) {
done();
this.ui.requestRender();
return;
}
await this.handleRuntimeSessionChange();
this.renderCurrentSessionState();
this.editor.setText(result.selectedText ?? "");
done();
this.ui.requestRender();
return;
this.showStatus("Branched to new session");
} catch (error: unknown) {
done();
this.showError(error instanceof Error ? error.message : String(error));
}
await this.handleRuntimeSessionChange();
this.renderCurrentSessionState();
this.editor.setText(result.selectedText ?? "");
done();
this.showStatus("Branched to new session");
},
() => {
done();
this.ui.requestRender();
},
initialSelectedId,
);
return { component: selector, focus: selector.getMessageList() };
});