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
15 changes: 14 additions & 1 deletion apps/web/src/components/ChatView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8511,6 +8511,11 @@ export default function ChatView(props: ChatViewProps) {
setComposerDraftThreadContexts(composerDraftTarget, [...records]),
resetCursor: (options) => composerRef.current?.resetCursorState(options),
});
} else if (
submissionIntent === "background" &&
currentRouteThreadKeyRef.current === routeThreadKey
) {
handleNewThreadInActiveProject();
}
return;
}
Expand Down Expand Up @@ -8743,7 +8748,9 @@ export default function ChatView(props: ChatViewProps) {
}
beginLocalDispatch({
preparingWorktree: multipleModelSelections !== null || Boolean(baseBranchForWorktree),
submissionIntent,
// Only a draft has a background submission to hide behind its hero.
submissionIntent:
submissionIntent === "background" && !isLocalDraftThread ? "foreground" : submissionIntent,
});
setWorktreeSetupRef(
multipleModelSelections === null && baseBranchForWorktree
Expand Down Expand Up @@ -9316,6 +9323,12 @@ export default function ChatView(props: ChatViewProps) {
}),
);
}
} else if (
submissionIntent === "background" &&
currentRouteThreadKeyRef.current === routeThreadKey
) {
// An existing thread keeps running; open a fresh composer like a draft does.
handleNewThreadInActiveProject();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ export function buildKeybindingCommandOptions(
export function commandLabel(command: KeybindingCommand): string {
if (command === "composer.sendAlternate") return "Composer: Opposite Queue or Steer Action";
if (command === "composer.sendBackground") return "Composer: Start in Background";
if (command === "composer.sendAndNewThread") return "Composer: Send and Start New Thread";
if (command === "thread.steerQueuedMessage") return "Queue: Send First Queued Message as Steer";
if (command === "thread.editQueuedMessage") return "Queue: Edit Last Queued Message";
if (command === "thread.copyReference") return "Pull Request: Copy Link or Thread ID";
Expand Down
8 changes: 8 additions & 0 deletions apps/web/src/composer-logic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,14 @@ describe("composerSubmissionIntentForKey", () => {
event: { ...modEnter, altKey: true },
}),
).toBe("background");
expect(
composerSubmissionIntentForKey({
...input,
platform,
sendShortcut,
event: { ...modEnter, altKey: true },
}),
).toBe("background");
expect(
composerSubmissionIntentForKey({
...input,
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/composer-logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export function composerSubmissionIntentForKey(input: {
});
if (command === "composer.sendAlternate" && input.isRunning) return "alternate";
if (command === "composer.sendBackground" && input.isDraftThread) return "background";
if (command === "composer.sendAndNewThread" && !input.isDraftThread) return "background";
if (command !== null || event.key !== "Enter" || event.shiftKey || event.altKey) return null;
if (
composerRequiresModifier(input.sendShortcut, input.prompt ?? "") &&
Expand Down
11 changes: 6 additions & 5 deletions docs/user/keybindings.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ inserts a new line. This applies to the web and desktop composer at desktop widt

**Follow-up behavior** chooses Queue or Steer while the agent runs. Use
`mod+Enter` to do the opposite for one message, even when the send shortcut
requires a modifier. In a new thread, `mod+Alt+Enter` starts the thread in the
background and opens a fresh composer. Change either shortcut in
**Settings → Keybindings** under **Composer: Opposite Queue or Steer Action** or
**Composer: Start in Background**. These bindings take priority over the send
shortcut. Click the send button to use the configured follow-up behavior.
requires a modifier. `mod+Alt+Enter` sends, keeps that thread running in the
background, and opens a fresh new-thread composer. Change these
shortcuts in **Settings → Keybindings** under **Composer: Opposite Queue or
Steer Action**, **Composer: Start in Background**, or **Composer: Send and Start
New Thread**. These bindings take priority over the send shortcut. Click the
send button to use the configured follow-up behavior.

When an active turn has queued messages, `mod+Shift+Enter` sends the first as a
steer. Change it under **Queue: Send First Queued Message as Steer** in Keybindings.
Expand Down
1 change: 1 addition & 0 deletions packages/contracts/src/keybindings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export const STATIC_KEYBINDING_COMMANDS = [
"composer.stash",
"composer.sendAlternate",
"composer.sendBackground",
"composer.sendAndNewThread",
"composer.host",
"composer.effort",
"composer.mode",
Expand Down
5 changes: 5 additions & 0 deletions packages/shared/src/keybindings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ export const DEFAULT_KEYBINDINGS: ReadonlyArray<KeybindingRule> = [
command: "composer.sendBackground",
when: "composerFocus && draftThreadRoute",
},
{
key: "mod+alt+enter",
command: "composer.sendAndNewThread",
when: "composerFocus && !draftThreadRoute",
},
{ key: "mod+n", command: "chat.new", when: "!terminalFocus" },
{ key: "mod+shift+o", command: "chat.new", when: "!terminalFocus" },
{ key: "mod+shift+n", command: "chat.newLocal", when: "!terminalFocus" },
Expand Down
Loading