fix(coding-agent): stabilize edit diff previews closes #3134

This commit is contained in:
Mario Zechner
2026-04-15 23:08:23 +02:00
parent ae6d493fcb
commit f7cd613ee4
6 changed files with 332 additions and 35 deletions

View File

@@ -12,6 +12,7 @@ export interface ToolExecutionOptions {
export class ToolExecutionComponent extends Container {
private contentBox: Box;
private contentText: Text;
private selfRenderContainer: Container;
private callRendererComponent?: Component;
private resultRendererComponent?: Component;
private rendererState: any = {};
@@ -58,13 +59,15 @@ export class ToolExecutionComponent extends Container {
this.addChild(new Spacer(1));
// Always create both. contentBox is used for tools with renderer-based call/result composition.
// Always create all shell variants. contentBox is used for default renderer-based composition.
// selfRenderContainer is used when the tool renders its own framing.
// contentText is reserved for generic fallback rendering when no tool definition exists.
this.contentBox = new Box(1, 1, (text: string) => theme.bg("toolPendingBg", text));
this.contentText = new Text("", 1, 1, (text: string) => theme.bg("toolPendingBg", text));
this.selfRenderContainer = new Container();
if (this.hasRendererDefinition()) {
this.addChild(this.contentBox);
this.addChild(this.getRenderShell() === "self" ? this.selfRenderContainer : this.contentBox);
} else {
this.addChild(this.contentText);
}
@@ -96,6 +99,16 @@ export class ToolExecutionComponent extends Container {
return this.builtInToolDefinition !== undefined || this.toolDefinition !== undefined;
}
private getRenderShell(): "default" | "self" {
if (!this.builtInToolDefinition) {
return this.toolDefinition?.renderShell ?? "default";
}
if (!this.toolDefinition) {
return this.builtInToolDefinition.renderShell ?? "default";
}
return this.toolDefinition.renderShell ?? this.builtInToolDefinition.renderShell ?? "default";
}
private getRenderContext(lastComponent: Component | undefined): ToolRenderContext {
return {
args: this.args,
@@ -214,22 +227,25 @@ export class ToolExecutionComponent extends Container {
let hasContent = false;
this.hideComponent = false;
if (this.hasRendererDefinition()) {
this.contentBox.setBgFn(bgFn);
this.contentBox.clear();
const renderContainer = this.getRenderShell() === "self" ? this.selfRenderContainer : this.contentBox;
if (renderContainer instanceof Box) {
renderContainer.setBgFn(bgFn);
}
renderContainer.clear();
const callRenderer = this.getCallRenderer();
if (!callRenderer) {
this.contentBox.addChild(this.createCallFallback());
renderContainer.addChild(this.createCallFallback());
hasContent = true;
} else {
try {
const component = callRenderer(this.args, theme, this.getRenderContext(this.callRendererComponent));
this.callRendererComponent = component;
this.contentBox.addChild(component);
renderContainer.addChild(component);
hasContent = true;
} catch {
this.callRendererComponent = undefined;
this.contentBox.addChild(this.createCallFallback());
renderContainer.addChild(this.createCallFallback());
hasContent = true;
}
}
@@ -239,7 +255,7 @@ export class ToolExecutionComponent extends Container {
if (!resultRenderer) {
const component = this.createResultFallback();
if (component) {
this.contentBox.addChild(component);
renderContainer.addChild(component);
hasContent = true;
}
} else {
@@ -251,13 +267,13 @@ export class ToolExecutionComponent extends Container {
this.getRenderContext(this.resultRendererComponent),
);
this.resultRendererComponent = component;
this.contentBox.addChild(component);
renderContainer.addChild(component);
hasContent = true;
} catch {
this.resultRendererComponent = undefined;
const component = this.createResultFallback();
if (component) {
this.contentBox.addChild(component);
renderContainer.addChild(component);
hasContent = true;
}
}