Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ multi-line editor; slash-command, unified `@` workspace/Plugin references and
session events; `/mode`, `/model`, `/resume`, `/plugins` and other upstream
slash commands; searchable model and reasoning-effort selectors, plus MCP and
workflow panels; status-bar-only Shift+Tab mode cycling
(`build` → `edit` → `guarded` → `yolo`), independent `/plan` toggling with an input-border indicator, Ctrl+N model and empty-prompt Tab effort
cycling; structured session-goal status in the right side of the turn footer;
(`build` → `edit` → `guarded` → `yolo`), independent `/plan` toggling with an input-border indicator, Ctrl+N model and Ctrl+T effort
cycling (Tab also cycles effort on an empty prompt); structured session-goal status in the right side of the turn footer;
animated active-turn timer with a static `ZCODE_TUI_REDUCED_MOTION=1`
fallback; responsive context-remaining and session-token metrics.

Expand Down
4 changes: 4 additions & 0 deletions packages/zcode-tui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1542,6 +1542,10 @@ class ZCodeTui {
void this.switchModel();
return { consume: true };
}
if (matchesKey(data, "ctrl+t")) {
void this.switchEffort();
return { consume: true };
}
if (matchesKey(data, "tab")
&& (this.turnAbortController || this.inputQueue.paused)
&& Boolean(this.editor.getText().trim())
Expand Down
7 changes: 7 additions & 0 deletions test/tui/fixtures/input-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ let history = [
{ role: "user", messageId: "question-1", content: "Original question" },
{ role: "agent", messageId: "answer-1", content: "Original answer" }
];
let effort = "low";
await runTui({
initialModel: "scenario/model", workspaceDirectory: process.cwd(),
initialThoughtLevel: effort,
effortOptions: [{ id: "low", label: "Low" }, { id: "high", label: "High" }],
loadSessionTranscript: async () => history,
readClipboardImage: async () => ({ dataUrl: "data:image/png;base64,aW1hZ2U=", mediaType: "image/png" }),
submitPrompt: async (input) => {
Expand All @@ -19,6 +22,10 @@ await runTui({
history = [];
return { response: "Rewound", resetSessionProjection: true, restoredMessages: [] };
}
if (String(input).startsWith("/effort ")) {
effort = String(input).slice("/effort ".length);
return { response: `Reasoning effort switched to ${effort}.`, thoughtLevel: effort };
}
return { response: `Sent: ${String(input)}` };
}
});
20 changes: 20 additions & 0 deletions test/tui/input-actions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,23 @@ test("fragmented terminal palette replies do not enter the draft or trigger inpu
await session.sendAndWait(" tail\r", "unaltered draft submitted", /Sent: retained draft tail/u);
await session.exit();
}, 20_000);

test("Ctrl+T cycles reasoning effort without clearing a typed prompt", async () => {
await using workspace = await ScenarioWorkspace.create({ prefix: "zcode-effort-shortcut-" });
await using session = TerminalSession.start({
command: [process.execPath, join(import.meta.dir, "fixtures/input-actions.ts")],
workspace
});
await session.waitForScreen("ready", /Original answer/u);
session.send("Draft question");
await session.waitForScreen("draft typed", /Draft question/u);
session.send("\x14");
await session.waitForScreen("effort raised", /⚡ high/u);
await session.waitForScreen("draft preserved after effort raised", /Draft question/u);
session.send("\x14");
await session.waitForScreen("effort lowered", /⚡ low/u);
await session.waitForScreen("draft preserved after effort lowered", /Draft question/u);
await session.assertScreenExcludes("effort shortcut does not submit the draft", /Sent: Draft question/u);
await session.sendAndWait("\r", "draft submitted", /Sent: Draft question/u);
await session.exit();
}, 20_000);
Loading