Skip to content

Commit 74fc9a0

Browse files
committed
feat(web): add steer-now buttons for queued messages
Add explicit steer actions to the web UI's queued-message list: a per-row button that injects a single queued message into the running turn, and a queue-header button that steers the whole queue (TUI Ctrl+S parity). Also fix Ctrl+S steering not triggering when CapsLock is on, and count web-initiated steers in the input_steer telemetry event by moving the tracking call to the shared steer path. Closes #2270
1 parent ceaa969 commit 74fc9a0

16 files changed

Lines changed: 1292 additions & 101 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@moonshot-ai/kimi-code": patch
3+
---
4+
5+
web: Fix Ctrl+S steering not triggering when CapsLock is on.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@moonshot-ai/kimi-code": patch
3+
---
4+
5+
web: Add "Steer now" buttons to the queued-message list to inject queued messages into the running turn — one message at a time or the whole queue from the queue header. Click the bolt button next to a queued message to steer it.

.changeset/web-steer-telemetry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@moonshot-ai/kimi-code": patch
3+
---
4+
5+
web: Count steered messages sent from the web UI in usage telemetry, the same way steers from the TUI are counted.

apps/kimi-web/src/App.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,7 @@ function openPr(url: string): void {
837837
@interrupt="client.abortCurrentPrompt()"
838838
@unqueue="handleUnqueue"
839839
@edit-queued="handleEditQueued"
840+
@steer-queued="client.steerQueuedPrompt($event)"
840841
@reorder-queue="handleReorderQueue"
841842
@set-permission="client.setPermission($event)"
842843
@set-thinking="client.setThinking($event)"

apps/kimi-web/src/components/chat/ChatPane.vue

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import AttachmentChip from './AttachmentChip.vue';
1515
import MoonSpinner from '../ui/MoonSpinner.vue';
1616
import Spinner from '../ui/Spinner.vue';
1717
import Icon from '../ui/Icon.vue';
18+
import Button from '../ui/Button.vue';
1819
import Tooltip from '../ui/Tooltip.vue';
1920
import { useConfirmDialog } from '../../composables/useConfirmDialog';
2021
import { copyTextToClipboard } from '../../lib/clipboard';
@@ -213,6 +214,11 @@ const emit = defineEmits<{
213214
unqueue: [index: number];
214215
/** Load a queued message back into the composer for editing (and dequeue it). */
215216
editQueued: [index: number];
217+
/** Steer the whole queue into the running turn now (like Ctrl+S, but the
218+
* live composer draft stays behind). */
219+
steerQueue: [];
220+
/** Steer one queued message (by index) into the running turn now. */
221+
steerQueued: [index: number];
216222
/** Drag-to-reorder a queued message within the active session's queue. */
217223
reorderQueue: [payload: { from: number; to: number }];
218224
}>();
@@ -689,6 +695,16 @@ function isStreamingRenderBlock(turn: ChatTurn, block: { sourceIndex: number }):
689695
{{ t('composer.queueLabel') }} · <b>{{ queued.length }}</b>
690696
</span>
691697
<span class="q-hint">{{ t('composer.queueAutoDrain') }}</span>
698+
<Button
699+
variant="ghost"
700+
size="sm"
701+
:title="t('composer.queueSteerTitle')"
702+
:aria-label="t('composer.queueSteerTitle')"
703+
@click.stop="emit('steerQueue')"
704+
>
705+
<Icon name="bolt" size="sm" />
706+
{{ t('composer.queueSteerNow') }}
707+
</Button>
692708
</div>
693709
<div
694710
v-for="(item, qi) in queued"
@@ -743,6 +759,16 @@ function isStreamingRenderBlock(turn: ChatTurn, block: { sourceIndex: number }):
743759
</div>
744760
<span v-if="qi === 0" class="q-tag q-tag-next">{{ t('composer.queueNext') }}</span>
745761
<span v-else class="q-tag q-tag-idx">#{{ qi + 1 }}</span>
762+
<Button
763+
variant="ghost"
764+
size="sm"
765+
:title="t('composer.queueSteerOneTitle')"
766+
:aria-label="t('composer.queueSteerOneTitle')"
767+
@click.stop="emit('steerQueued', qi)"
768+
>
769+
<Icon name="bolt" size="sm" />
770+
{{ t('composer.queueSteerNow') }}
771+
</Button>
746772
<button
747773
type="button"
748774
class="q-rm"

apps/kimi-web/src/components/chat/Composer.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -491,8 +491,9 @@ function handleKeydown(e: KeyboardEvent): void {
491491
}
492492
}
493493
494-
// Ctrl+S / Cmd+S — steer into the running turn (TUI parity)
495-
if (e.key === 's' && (e.ctrlKey || e.metaKey) && !e.shiftKey && !e.altKey) {
494+
// Ctrl+S / Cmd+S — steer into the running turn (TUI parity). toLowerCase so
495+
// CapsLock (key: 'S') doesn't defeat the match, same as the sidebar's Ctrl+K.
496+
if (e.key.toLowerCase() === 's' && (e.ctrlKey || e.metaKey) && !e.shiftKey && !e.altKey) {
496497
if (props.running) {
497498
e.preventDefault();
498499
handleSteer();

apps/kimi-web/src/components/chat/ConversationPane.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ const emit = defineEmits<{
108108
interrupt: [];
109109
unqueue: [index: number];
110110
editQueued: [index: number];
111+
steerQueued: [index: number];
111112
reorderQueue: [payload: { from: number; to: number }];
112113
setPermission: [mode: PermissionMode];
113114
setThinking: [level: ThinkingLevel];
@@ -1436,6 +1437,8 @@ defineExpose({ loadComposerForEdit, focusComposer });
14361437
@unqueue="emit('unqueue', $event)"
14371438
@edit-queued="handleEditQueued"
14381439
@reorder-queue="handleReorderQueue"
1440+
@steer-queue="emit('steer', { text: '', attachments: [] })"
1441+
@steer-queued="emit('steerQueued', $event)"
14391442
/>
14401443
</template>
14411444
</div>

0 commit comments

Comments
 (0)