feat(web): steer queued messages into active turns

This commit is contained in:
kingwl
2026-07-30 03:17:54 +08:00
committed by imccyu
parent fff0172208
commit 955a12cca4
49 changed files with 508 additions and 147 deletions
@@ -89,8 +89,11 @@ export const zh = {
'queue.save': '保存排队消息',
'queue.cancelEdit': '取消编辑',
'queue.remove': '删除排队消息',
'queue.steer': '插话发送',
'queue.steer.unavailable': '仅运行中可插话发送',
'queue.editFailed': '编辑失败:这条消息可能已经开始发送。',
'queue.removeFailed': '删除失败:这条消息可能已经开始发送。',
'queue.steerFailed': '插话失败:当前回复已结束,或这条消息已经开始发送。',
'terminal.signal': '信号 {signal}',
'terminal.exitCode': '退出码 {code}',
'terminal.running': '运行中',
@@ -189,8 +192,11 @@ export const en = {
'queue.save': 'Save queued message',
'queue.cancelEdit': 'Cancel editing',
'queue.remove': 'Remove queued message',
'queue.steer': 'Steer queued message',
'queue.steer.unavailable': 'Steering is available only while the agent is running',
'queue.editFailed': 'Edit failed: this message may have already started sending.',
'queue.removeFailed': 'Removal failed: this message may have already started sending.',
'queue.steerFailed': 'Steering failed: the current response ended or this message already started sending.',
'terminal.signal': 'signal {signal}',
'terminal.exitCode': 'exit code {code}',
'terminal.running': 'Running',
@@ -9,7 +9,7 @@ import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots
import type { SessionId } from '@deepseek-ai/dsh-client-runtime/client'
import {
IconCheckOutline16, IconChevronDownOutline14, IconChevronUpOutline14,
IconCloseOutline16, IconEditOutline16, IconTrashOutline16,
IconCloseOutline16, IconEditOutline16, IconRightUpOutline16, IconTrashOutline16,
} from '@deepseek-ai/dsh-client-ui-primitives'
import type { QueueAction, QueueItemId } from '../contract/queue.ts'
import { NS } from '../locales.ts'
@@ -30,6 +30,7 @@ export type QueueDockProps = PropsRuntime<'conversation.input.dock'> & QueueDock
*/
export function QueueDock({ useSession, updateQueue, notify, t }: QueueDockProps) {
const queue = useSession(s => s.queue)
const running = useSession(s => s.running)
const [editing, setEditing] = useState<{ id: QueueItemId; text: string } | null>(null)
const [busy, setBusy] = useState<QueueItemId | null>(null)
const [collapsed, setCollapsed] = useState(true)
@@ -170,6 +171,22 @@ export function QueueDock({ useSession, updateQueue, notify, t }: QueueDockProps
>
<IconTrashOutline16 size={14} />
</button>
<button
type="button"
className={css.action}
aria-label={t('queue.steer')}
title={running ? t('queue.steer') : t('queue.steer.unavailable')}
disabled={busy !== null || !running}
onClick={() => {
void applyAction(
row.id,
{ kind: 'steer' },
t('queue.steerFailed'),
)
}}
>
<IconRightUpOutline16 size={14} />
</button>
</>
)}
</div>
@@ -31,9 +31,9 @@ export interface IConversation {
*/
send(text: string): Promise<void>
/**
* Apply one operation to a pending queue occurrence.
* Apply one edit, remove, or strict steer operation to a pending queue occurrence.
* @param itemId - agent-owned inbox occurrence identity.
* @param action - edit or remove operation.
* @param action - requested queue operation.
* @returns completion; business failures reject.
*/
updateQueue(itemId: QueueItemId, action: QueueAction): Promise<void>