fix(tui): clear extension command image drafts
This commit is contained in:
@@ -752,24 +752,6 @@ export class InputController {
|
||||
}
|
||||
}
|
||||
|
||||
// Extension commands are local actions. Execute them before the normal
|
||||
// submission path creates an optimistic user message; otherwise a
|
||||
// consumed command remains rendered like a prompt sent to the model.
|
||||
const extensionCommandSpace = text.indexOf(" ");
|
||||
const isLocalExtensionCommand =
|
||||
text.startsWith("/") &&
|
||||
runner?.getCommand(extensionCommandSpace === -1 ? text.slice(1) : text.slice(1, extensionCommandSpace)) !==
|
||||
undefined;
|
||||
if (isLocalExtensionCommand) {
|
||||
this.ctx.editor.addToHistory(text);
|
||||
try {
|
||||
await this.ctx.session.prompt(text, { images: inputImages });
|
||||
} catch (error) {
|
||||
this.ctx.editor.setText(text);
|
||||
this.ctx.showError(error instanceof Error ? error.message : String(error));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle bash command (! for normal, !! for excluded from context)
|
||||
if (text.startsWith("!")) {
|
||||
@@ -820,6 +802,20 @@ export class InputController {
|
||||
this.ctx.queueCompactionMessage(text, "steer", images);
|
||||
return;
|
||||
}
|
||||
// Extension commands are local actions. Execute them before the normal
|
||||
// submission path creates an optimistic user message; otherwise a
|
||||
// consumed command remains rendered like a prompt sent to the model.
|
||||
if (this.#isLocalExtensionCommand(text)) {
|
||||
this.ctx.editor.clearDraft(text);
|
||||
try {
|
||||
await this.ctx.session.prompt(text, { images: inputImages });
|
||||
} catch (error) {
|
||||
this.ctx.editor.setText(text);
|
||||
this.ctx.showError(error instanceof Error ? error.message : String(error));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// If streaming, use prompt() with steer behavior
|
||||
// This handles extension commands (execute immediately), prompt template expansion, and queueing
|
||||
@@ -933,14 +929,18 @@ export class InputController {
|
||||
* Local extension commands are consumed before reaching the shared session
|
||||
* title gate and must not name the conversation.
|
||||
*/
|
||||
#maybeStartTitleGeneration(text: string): void {
|
||||
const runner = this.ctx.session.extensionRunner;
|
||||
#isLocalExtensionCommand(text: string): boolean {
|
||||
const extensionCommandSpace = text.indexOf(" ");
|
||||
const isLocalExtensionCommand =
|
||||
return (
|
||||
text.startsWith("/") &&
|
||||
runner?.getCommand(extensionCommandSpace === -1 ? text.slice(1) : text.slice(1, extensionCommandSpace)) !==
|
||||
undefined;
|
||||
if (isLocalExtensionCommand) {
|
||||
this.ctx.session.extensionRunner?.getCommand(
|
||||
extensionCommandSpace === -1 ? text.slice(1) : text.slice(1, extensionCommandSpace),
|
||||
) !== undefined
|
||||
);
|
||||
}
|
||||
|
||||
#maybeStartTitleGeneration(text: string): void {
|
||||
if (this.#isLocalExtensionCommand(text)) {
|
||||
return;
|
||||
}
|
||||
this.ctx.session.maybeStartTitleGeneration(text, () => {
|
||||
|
||||
@@ -120,7 +120,7 @@ describe("input controller — slash command history (#3148)", () => {
|
||||
expect(addToHistory).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("executes extension commands without rendering them as user prompts", async () => {
|
||||
it("executes extension commands without rendering them as user prompts or retaining image drafts", async () => {
|
||||
const { ctx, editor, addToHistory, onInputCallback, prompt } = makeCtx();
|
||||
Object.defineProperty(ctx.session, "extensionRunner", {
|
||||
value: {
|
||||
@@ -128,13 +128,18 @@ describe("input controller — slash command history (#3148)", () => {
|
||||
hasHandlers: () => false,
|
||||
},
|
||||
});
|
||||
const image: ImageContent = { type: "image", data: "image-data", mimeType: "image/png" };
|
||||
editor.pendingImages = [image];
|
||||
editor.pendingImageLinks = ["file:///draft.png"];
|
||||
controllerFor(ctx);
|
||||
|
||||
await editor.onSubmit?.("/id");
|
||||
|
||||
expect(prompt).toHaveBeenCalledWith("/id", { images: undefined });
|
||||
expect(prompt).toHaveBeenCalledWith("/id", { images: [image] });
|
||||
expect(addToHistory).toHaveBeenCalledWith("/id");
|
||||
expect(onInputCallback).not.toHaveBeenCalled();
|
||||
expect(editor.pendingImages).toEqual([]);
|
||||
expect(editor.pendingImageLinks).toEqual([]);
|
||||
});
|
||||
|
||||
it("routes /queue through the yield-only follow-up queue while streaming", async () => {
|
||||
|
||||
Reference in New Issue
Block a user