@vibe-forge/client 0.11.2 → 0.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/dist/assets/{arc-De_WjPJ3.js → arc-h39NrT24.js} +1 -1
  2. package/dist/assets/{blockDiagram-c4efeb88-C4aR2zTE.js → blockDiagram-c4efeb88-CaDg46I6.js} +1 -1
  3. package/dist/assets/{c4Diagram-c83219d4-BZH3rq_m.js → c4Diagram-c83219d4-CDqjcF9U.js} +1 -1
  4. package/dist/assets/channel-CBULQbJz.js +1 -0
  5. package/dist/assets/{classDiagram-beda092f-BzJgBrIK.js → classDiagram-beda092f-BDnZm8nO.js} +1 -1
  6. package/dist/assets/{classDiagram-v2-2358418a-5ZtXcnT3.js → classDiagram-v2-2358418a-BUi85KJW.js} +1 -1
  7. package/dist/assets/clone-dkS7LczW.js +1 -0
  8. package/dist/assets/{createText-1719965b-DUVvEtmR.js → createText-1719965b-Ca5dEwfo.js} +1 -1
  9. package/dist/assets/{cssMode-GoTNjuXX.js → cssMode-Ysz7NfYo.js} +1 -1
  10. package/dist/assets/{edges-96097737-Dd7m4Cvs.js → edges-96097737-CdSKqxZt.js} +1 -1
  11. package/dist/assets/{erDiagram-0228fc6a-DxqFlG_f.js → erDiagram-0228fc6a-B-veAUv_.js} +1 -1
  12. package/dist/assets/{flowDb-c6c81e3f-DU0C5kCI.js → flowDb-c6c81e3f-DD8Cx7_9.js} +1 -1
  13. package/dist/assets/{flowDiagram-50d868cf-Di1uDa_X.js → flowDiagram-50d868cf-9f-_x1ET.js} +1 -1
  14. package/dist/assets/flowDiagram-v2-4f6560a1-1miffU4x.js +1 -0
  15. package/dist/assets/{flowchart-elk-definition-6af322e1-CwG8aty5.js → flowchart-elk-definition-6af322e1-5RhpQM4M.js} +1 -1
  16. package/dist/assets/{freemarker2-j39cqTlI.js → freemarker2-SgMdIXw4.js} +1 -1
  17. package/dist/assets/{ganttDiagram-a2739b55-baO_lzL-.js → ganttDiagram-a2739b55-DnxNghZA.js} +1 -1
  18. package/dist/assets/{gitGraphDiagram-82fe8481-COoHjYMf.js → gitGraphDiagram-82fe8481-CBvS3Tf9.js} +1 -1
  19. package/dist/assets/{graph-KxESr4M5.js → graph-CkHF299-.js} +1 -1
  20. package/dist/assets/{handlebars-BgjdZO8G.js → handlebars-C57IyLUe.js} +1 -1
  21. package/dist/assets/{html-Ba7tYObe.js → html-YsDy5wvW.js} +1 -1
  22. package/dist/assets/{htmlMode-Bztvbig1.js → htmlMode-7o_VDODD.js} +1 -1
  23. package/dist/assets/{index-5325376f-BMTAx2mL.js → index-5325376f-BzOVQPu-.js} +1 -1
  24. package/dist/assets/{index-Pm_kLJvG.js → index-BHFpctk6.js} +320 -319
  25. package/dist/assets/index-D_XqxIvp.css +32 -0
  26. package/dist/assets/{infoDiagram-8eee0895-CC74qbHY.js → infoDiagram-8eee0895-DJ-UI1h4.js} +1 -1
  27. package/dist/assets/{javascript-C1e1cllX.js → javascript-BHQ9NEZr.js} +1 -1
  28. package/dist/assets/{journeyDiagram-c64418c1-C4MyOdE6.js → journeyDiagram-c64418c1-DwfykcG9.js} +1 -1
  29. package/dist/assets/{jsonMode-BC98AlvF.js → jsonMode-3QjftkMM.js} +1 -1
  30. package/dist/assets/{layout-CxAyTlr7.js → layout-CbViRb_b.js} +1 -1
  31. package/dist/assets/{line-DhaUfI71.js → line-DBdBvv9D.js} +1 -1
  32. package/dist/assets/{linear-MYukzldK.js → linear-BDAfhcjn.js} +1 -1
  33. package/dist/assets/{liquid-DahfJEYl.js → liquid-B0cPPzIR.js} +1 -1
  34. package/dist/assets/{lspLanguageFeatures-BWDJcswW.js → lspLanguageFeatures-IOxbobOz.js} +1 -1
  35. package/dist/assets/{mdx-BELlF_FD.js → mdx-Dma_RA8P.js} +1 -1
  36. package/dist/assets/{mermaid.core-BrQnSGSY.js → mermaid.core-Cvn8Go4x.js} +4 -4
  37. package/dist/assets/{mindmap-definition-8da855dc-B0FoxTiy.js → mindmap-definition-8da855dc-DEnYq0Lc.js} +1 -1
  38. package/dist/assets/{pieDiagram-a8764435-Ddr2cjSL.js → pieDiagram-a8764435-ZC4j8sHU.js} +1 -1
  39. package/dist/assets/{python--C9if_AD.js → python-Be0WX4q5.js} +1 -1
  40. package/dist/assets/{quadrantDiagram-1e28029f-BlEs7Mrl.js → quadrantDiagram-1e28029f-DUaqHlIB.js} +1 -1
  41. package/dist/assets/{razor-B9U9JxKn.js → razor-Tjhny-uT.js} +1 -1
  42. package/dist/assets/{requirementDiagram-08caed73-kEFOAu2v.js → requirementDiagram-08caed73-DjSal3es.js} +1 -1
  43. package/dist/assets/{sankeyDiagram-a04cb91d-BBghez8I.js → sankeyDiagram-a04cb91d-BMDXMrMz.js} +1 -1
  44. package/dist/assets/{sequenceDiagram-c5b8d532-CJqgzdUE.js → sequenceDiagram-c5b8d532-CQl9YUlH.js} +1 -1
  45. package/dist/assets/{stateDiagram-1ecb1508-BER4XEI6.js → stateDiagram-1ecb1508-DG7mU9jD.js} +1 -1
  46. package/dist/assets/{stateDiagram-v2-c2b004d7-EBV2vSks.js → stateDiagram-v2-c2b004d7-DTbR_azy.js} +1 -1
  47. package/dist/assets/{styles-b4e223ce-k0eswZsE.js → styles-b4e223ce-C9aS3zb8.js} +1 -1
  48. package/dist/assets/{styles-ca3715f6-Ckr7GA-0.js → styles-ca3715f6-Bh3keVTZ.js} +1 -1
  49. package/dist/assets/{styles-d45a18b0-C1bpSwV3.js → styles-d45a18b0-BDcLLa65.js} +1 -1
  50. package/dist/assets/{svgDrawCommon-b86b1483-CDtKpGvy.js → svgDrawCommon-b86b1483-B9H5ZS_9.js} +1 -1
  51. package/dist/assets/{timeline-definition-faaaa080-BeGR-vua.js → timeline-definition-faaaa080-DCMYCBhK.js} +1 -1
  52. package/dist/assets/{tsMode-D_gJXIy3.js → tsMode-DVqLsn98.js} +1 -1
  53. package/dist/assets/{typescript-BoKcNXkN.js → typescript-wMVyXw7G.js} +1 -1
  54. package/dist/assets/{xml-DZvURlJ-.js → xml-w0gzmn0c.js} +1 -1
  55. package/dist/assets/{xychartDiagram-f5964ef8-DxfeLuYV.js → xychartDiagram-f5964ef8-CdxyD3K5.js} +1 -1
  56. package/dist/assets/{yaml-CTC8PAGY.js → yaml-C29TL1ed.js} +1 -1
  57. package/dist/index.html +2 -2
  58. package/package.json +4 -4
  59. package/src/api/sessions.ts +70 -1
  60. package/src/api/types.ts +2 -1
  61. package/src/api.ts +5 -0
  62. package/src/components/chat/AGENTS.md +14 -2
  63. package/src/components/chat/ChatComposerCard.scss +73 -0
  64. package/src/components/chat/ChatComposerCard.tsx +59 -0
  65. package/src/components/chat/ChatHeader.tsx +3 -1
  66. package/src/components/chat/ChatHistoryView.tsx +215 -49
  67. package/src/components/chat/CurrentTodoList.scss +210 -200
  68. package/src/components/chat/CurrentTodoList.tsx +116 -48
  69. package/src/components/chat/QueuedMessagesCard.scss +195 -0
  70. package/src/components/chat/QueuedMessagesCard.tsx +170 -0
  71. package/src/components/chat/sender/@components/adapter-select/AdapterSelectControl.scss +8 -0
  72. package/src/components/chat/sender/@components/sender-attachments/SenderAttachments.scss +152 -28
  73. package/src/components/chat/sender/@components/sender-attachments/SenderAttachments.tsx +95 -23
  74. package/src/components/chat/sender/@components/sender-body/SenderBody.tsx +7 -0
  75. package/src/components/chat/sender/@components/sender-interaction-panel/SenderInteractionPanel.scss +161 -45
  76. package/src/components/chat/sender/@components/sender-interaction-panel/SenderInteractionPanel.tsx +310 -71
  77. package/src/components/chat/sender/@components/sender-monaco-editor/SenderMonacoEditor.tsx +18 -0
  78. package/src/components/chat/sender/@components/sender-monaco-editor/use-sender-monaco-editor.ts +86 -9
  79. package/src/components/chat/sender/@components/sender-submit-action/SenderSubmitAction.scss +98 -1
  80. package/src/components/chat/sender/@components/sender-submit-action/SenderSubmitAction.tsx +137 -17
  81. package/src/components/chat/sender/@components/sender-toolbar/SenderToolbar.tsx +12 -6
  82. package/src/components/chat/sender/@core/build-sender-controller-result.ts +6 -0
  83. package/src/components/chat/sender/@core/build-sender-toolbar.ts +25 -2
  84. package/src/components/chat/sender/@core/create-sender-toolbar-handlers.ts +9 -2
  85. package/src/components/chat/sender/@core/interaction-request.ts +2 -2
  86. package/src/components/chat/sender/@core/sender-toolbar-bindings.ts +28 -4
  87. package/src/components/chat/sender/@hooks/use-sender-controller.ts +56 -11
  88. package/src/components/chat/sender/@hooks/use-sender-keydown.ts +64 -0
  89. package/src/components/chat/sender/@hooks/use-sender-shortcuts.ts +16 -1
  90. package/src/components/chat/sender/@hooks/use-sender-submit.ts +16 -8
  91. package/src/components/chat/sender/@types/sender-props.ts +19 -3
  92. package/src/components/chat/sender/@types/sender-toolbar-types.ts +12 -1
  93. package/src/components/chat/sender/Sender.scss +3 -0
  94. package/src/components/chat/sender/Sender.tsx +2 -12
  95. package/src/hooks/chat/session-view-cache.ts +4 -1
  96. package/src/hooks/chat/use-chat-adapter.ts +5 -1
  97. package/src/hooks/chat/use-chat-model-adapter-selection.tsx +5 -1
  98. package/src/hooks/chat/use-chat-session-actions.ts +99 -4
  99. package/src/hooks/chat/use-chat-session-messages.ts +20 -1
  100. package/src/hooks/chat/use-chat-session.ts +2 -0
  101. package/src/main.tsx +8 -0
  102. package/src/resources/locales/en.json +32 -1
  103. package/src/resources/locales/zh.json +32 -1
  104. package/src/routes/ChatRoute.scss +45 -1
  105. package/src/routes/ChatRoute.tsx +3 -0
  106. package/dist/assets/channel-BvERb8WU.js +0 -1
  107. package/dist/assets/clone-B9_0v-6Y.js +0 -1
  108. package/dist/assets/flowDiagram-v2-4f6560a1-LpS8Kb00.js +0 -1
  109. package/dist/assets/index-C1oh0w9H.css +0 -32
  110. package/src/components/chat/ThinkingStatus.scss +0 -70
  111. package/src/components/chat/ThinkingStatus.tsx +0 -13
@@ -40,10 +40,20 @@
40
40
  color: var(--primary-color, #6366f1);
41
41
  border-color: var(--primary-color, #6366f1);
42
42
  }
43
- &.thinking {
43
+ &.stop {
44
44
  color: #fff;
45
45
  border-color: #dc2626;
46
46
  background: linear-gradient(180deg, #ef4444, #dc2626);
47
+
48
+ &:hover {
49
+ color: #fff;
50
+ border-color: #dc2626;
51
+ background: linear-gradient(180deg, #ef4444, #dc2626);
52
+ }
53
+
54
+ .material-symbols-rounded {
55
+ transform: none;
56
+ }
47
57
  }
48
58
  &.disabled {
49
59
  color: #9ca3af;
@@ -51,4 +61,91 @@
51
61
  border-color: var(--border-color);
52
62
  opacity: .72;
53
63
  }
64
+
65
+ &.blocked {
66
+ cursor: not-allowed;
67
+
68
+ &:hover {
69
+ color: #9ca3af;
70
+ border-color: var(--border-color);
71
+ background: color-mix(
72
+ in srgb,
73
+ var(--bg-color, #fff) 92%,
74
+ var(--sub-bg-color, #f3f4f6) 8%
75
+ );
76
+ }
77
+
78
+ .material-symbols-rounded {
79
+ transform: none;
80
+ }
81
+ }
82
+ }
83
+
84
+ .chat-confirm-btn.ant-btn {
85
+ height: var(--sender-control-height);
86
+ padding: 0 10px;
87
+ border-radius: var(--sender-control-radius);
88
+ border-color: var(--border-color);
89
+ background: var(--bg-color, #fff);
90
+ box-shadow: none;
91
+ display: inline-flex;
92
+ align-items: center;
93
+ gap: 4px;
94
+ font-size: 12px;
95
+ font-weight: 500;
96
+
97
+ .material-symbols-rounded {
98
+ font-size: 15px;
99
+ line-height: 1;
100
+ }
101
+
102
+ &:hover,
103
+ &:focus {
104
+ border-color: color-mix(
105
+ in srgb,
106
+ var(--primary-color, #2563eb) 38%,
107
+ var(--border-color) 62%
108
+ );
109
+ color: var(--text-color, #1f2937);
110
+ background: color-mix(
111
+ in srgb,
112
+ var(--bg-color, #fff) 90%,
113
+ var(--sub-bg-color, #eff6ff) 10%
114
+ );
115
+ }
116
+ }
117
+
118
+ .sender-send-tooltip {
119
+ display: flex;
120
+ flex-direction: column;
121
+ gap: 6px;
122
+ }
123
+
124
+ .sender-send-tooltip__row {
125
+ display: flex;
126
+ align-items: center;
127
+ gap: 8px;
128
+ }
129
+
130
+ .sender-send-tooltip__label {
131
+ min-width: 0;
132
+ color: inherit;
133
+ font-size: inherit;
134
+ line-height: 1.4;
135
+ }
136
+
137
+ .sender-send-tooltip-popover {
138
+ pointer-events: none;
139
+
140
+ .ant-tooltip-inner {
141
+ padding: 8px 10px !important;
142
+ }
143
+
144
+ .shortcut-display {
145
+ background: rgba(255, 255, 255, .12);
146
+ border-color: rgba(255, 255, 255, .16);
147
+ color: rgba(255, 255, 255, .92);
148
+ box-shadow: none;
149
+ flex: 0 0 auto;
150
+ }
54
151
  }
@@ -1,9 +1,11 @@
1
1
  import '../sender-toolbar/SenderSelectShared.scss'
2
2
  import './SenderSubmitAction.scss'
3
3
 
4
- import { Button } from 'antd'
4
+ import type { SessionQueuedMessageMode } from '@vibe-forge/core'
5
+ import { Button, Tooltip } from 'antd'
5
6
  import { useTranslation } from 'react-i18next'
6
7
 
8
+ import { ShortcutDisplay } from '#~/components/ShortcutDisplay'
7
9
  import { ShortcutTooltip } from '#~/components/ShortcutTooltip'
8
10
 
9
11
  export function SenderSubmitAction({
@@ -11,29 +13,51 @@ export function SenderSubmitAction({
11
13
  submitLoading,
12
14
  submitLabel,
13
15
  hasComposerContent,
14
- hasSendText,
15
16
  modelUnavailable,
17
+ sendBlocked,
18
+ sendBlockedTooltip,
19
+ showConfirmInteractionAction,
20
+ confirmInteractionLabel,
16
21
  isThinking,
17
22
  resolvedSendShortcut,
23
+ queueSteerShortcut,
24
+ queueNextShortcut,
18
25
  isMac,
19
26
  onCancel,
27
+ onConfirmInteractionAction,
20
28
  onSend,
21
- onInterrupt
29
+ onStop
22
30
  }: {
23
31
  isInlineEdit: boolean
24
32
  submitLoading: boolean
25
33
  submitLabel?: string
26
34
  hasComposerContent: boolean
27
- hasSendText: boolean
28
35
  modelUnavailable: boolean
36
+ sendBlocked: boolean
37
+ sendBlockedTooltip?: string
38
+ showConfirmInteractionAction: boolean
39
+ confirmInteractionLabel?: string
29
40
  isThinking: boolean
30
41
  resolvedSendShortcut: string
42
+ queueSteerShortcut?: string
43
+ queueNextShortcut?: string
31
44
  isMac: boolean
32
45
  onCancel?: () => void
33
- onSend: () => void
34
- onInterrupt: () => void
46
+ onConfirmInteractionAction?: () => void
47
+ onSend: (mode?: SessionQueuedMessageMode) => void
48
+ onStop?: () => void
35
49
  }) {
36
50
  const { t } = useTranslation()
51
+ const showStopAction = isThinking && !hasComposerContent
52
+ const isSendDisabled = !showStopAction && (modelUnavailable || sendBlocked)
53
+ const handleSendClick = () => onSend()
54
+ const buttonClasses = [
55
+ 'chat-send-btn',
56
+ hasComposerContent && !isSendDisabled ? 'active' : '',
57
+ showStopAction ? 'stop' : '',
58
+ isSendDisabled ? 'disabled' : '',
59
+ sendBlocked ? 'blocked' : ''
60
+ ].filter(Boolean).join(' ')
37
61
 
38
62
  if (isInlineEdit) {
39
63
  return (
@@ -49,7 +73,7 @@ export function SenderSubmitAction({
49
73
  size='small'
50
74
  loading={submitLoading}
51
75
  disabled={!hasComposerContent}
52
- onClick={onSend}
76
+ onClick={handleSendClick}
53
77
  >
54
78
  {submitLabel ?? t('chat.send')}
55
79
  </Button>
@@ -57,23 +81,119 @@ export function SenderSubmitAction({
57
81
  )
58
82
  }
59
83
 
84
+ if (isThinking) {
85
+ if (showStopAction) {
86
+ return (
87
+ <Tooltip
88
+ title={
89
+ <div className='sender-send-tooltip'>
90
+ <div className='sender-send-tooltip__row'>
91
+ <span className='sender-send-tooltip__label'>{t('chat.queue.stopShortcutTooltip')}</span>
92
+ <ShortcutDisplay shortcut='esc' isMac={isMac} />
93
+ </div>
94
+ </div>
95
+ }
96
+ placement='top'
97
+ classNames={{ root: 'sender-send-tooltip-popover' }}
98
+ trigger={['hover']}
99
+ mouseEnterDelay={.3}
100
+ mouseLeaveDelay={.08}
101
+ arrow={false}
102
+ >
103
+ <div className='sender-control-tooltip-target'>
104
+ <div className={buttonClasses} onClick={onStop}>
105
+ <span className='material-symbols-rounded'>stop_circle</span>
106
+ </div>
107
+ </div>
108
+ </Tooltip>
109
+ )
110
+ }
111
+
112
+ return (
113
+ <Tooltip
114
+ title={
115
+ <div className='sender-send-tooltip'>
116
+ <div className='sender-send-tooltip__row'>
117
+ <span className='sender-send-tooltip__label'>{t('chat.queue.steerShortcutTooltip')}</span>
118
+ <ShortcutDisplay shortcut={queueSteerShortcut} isMac={isMac} />
119
+ </div>
120
+ <div className='sender-send-tooltip__row'>
121
+ <span className='sender-send-tooltip__label'>{t('chat.queue.nextShortcutTooltip')}</span>
122
+ <ShortcutDisplay shortcut={queueNextShortcut} isMac={isMac} />
123
+ </div>
124
+ </div>
125
+ }
126
+ placement='top'
127
+ classNames={{ root: 'sender-send-tooltip-popover' }}
128
+ trigger={['hover']}
129
+ mouseEnterDelay={.3}
130
+ mouseLeaveDelay={.08}
131
+ arrow={false}
132
+ >
133
+ <div className='sender-control-tooltip-target'>
134
+ <div className={buttonClasses} onClick={isSendDisabled ? undefined : handleSendClick}>
135
+ <span className='material-symbols-rounded'>send</span>
136
+ </div>
137
+ </div>
138
+ </Tooltip>
139
+ )
140
+ }
141
+
142
+ if (sendBlocked) {
143
+ return (
144
+ <>
145
+ <Tooltip
146
+ title={sendBlockedTooltip}
147
+ placement='top'
148
+ classNames={{ root: 'sender-send-tooltip-popover' }}
149
+ trigger={['hover']}
150
+ mouseEnterDelay={.3}
151
+ mouseLeaveDelay={.08}
152
+ arrow={false}
153
+ >
154
+ <div className='sender-control-tooltip-target'>
155
+ <div className={buttonClasses} onClick={handleSendClick}>
156
+ <span className='material-symbols-rounded'>send</span>
157
+ </div>
158
+ </div>
159
+ </Tooltip>
160
+
161
+ {showConfirmInteractionAction && onConfirmInteractionAction != null && (
162
+ <Tooltip
163
+ title={t('chat.permissionConfirmOptionTooltip')}
164
+ placement='top'
165
+ classNames={{ root: 'sender-send-tooltip-popover' }}
166
+ trigger={['hover']}
167
+ mouseEnterDelay={.3}
168
+ mouseLeaveDelay={.08}
169
+ arrow={false}
170
+ >
171
+ <Button
172
+ autoInsertSpace={false}
173
+ size='small'
174
+ type='default'
175
+ className='chat-confirm-btn'
176
+ onClick={onConfirmInteractionAction}
177
+ >
178
+ <span className='material-symbols-rounded'>task_alt</span>
179
+ <span>{confirmInteractionLabel ?? t('chat.permissionConfirmOption')}</span>
180
+ </Button>
181
+ </Tooltip>
182
+ )}
183
+ </>
184
+ )
185
+ }
186
+
60
187
  return (
61
188
  <ShortcutTooltip
62
189
  shortcut={resolvedSendShortcut}
63
190
  isMac={isMac}
64
191
  title={t('chat.sendShortcutTooltip')}
65
192
  targetClassName='sender-control-tooltip-target'
66
- enabled={!isThinking}
193
+ enabled
67
194
  >
68
- <div
69
- className={`chat-send-btn ${hasSendText && !modelUnavailable ? 'active' : ''} ${isThinking ? 'thinking' : ''} ${
70
- modelUnavailable ? 'disabled' : ''
71
- }`.trim()}
72
- onClick={modelUnavailable ? undefined : (isThinking ? onInterrupt : onSend)}
73
- >
74
- <span className='material-symbols-rounded'>
75
- {isThinking ? 'stop_circle' : 'send'}
76
- </span>
195
+ <div className={buttonClasses} onClick={isSendDisabled ? undefined : handleSendClick}>
196
+ <span className='material-symbols-rounded'>send</span>
77
197
  </div>
78
198
  </ShortcutTooltip>
79
199
  )
@@ -36,6 +36,10 @@ export function SenderToolbar({
36
36
  />
37
37
 
38
38
  <div className='toolbar-left'>
39
+ {!state.isInlineEdit && (
40
+ <AdapterSelectControl state={state} data={data} handlers={handlers} />
41
+ )}
42
+
39
43
  <ReferenceActionsControl
40
44
  state={state}
41
45
  data={data}
@@ -63,23 +67,25 @@ export function SenderToolbar({
63
67
  </div>
64
68
 
65
69
  <div className={`toolbar-right ${state.isInlineEdit ? 'toolbar-right--inline-edit' : ''}`.trim()}>
66
- {!state.isInlineEdit && (
67
- <AdapterSelectControl state={state} data={data} handlers={handlers} />
68
- )}
69
-
70
70
  <SenderSubmitAction
71
71
  isInlineEdit={state.isInlineEdit}
72
72
  submitLoading={state.submitLoading}
73
73
  submitLabel={data.submitLabel}
74
74
  hasComposerContent={state.hasComposerContent}
75
- hasSendText={state.hasSendText}
76
75
  modelUnavailable={state.modelUnavailable}
76
+ sendBlocked={state.sendBlocked}
77
+ sendBlockedTooltip={state.sendBlockedTooltip}
78
+ showConfirmInteractionAction={state.showConfirmInteractionAction}
79
+ confirmInteractionLabel={data.confirmInteractionLabel}
77
80
  isThinking={state.isThinking}
78
81
  resolvedSendShortcut={state.resolvedSendShortcut}
82
+ queueSteerShortcut={data.composerControlShortcuts.queueSteer}
83
+ queueNextShortcut={data.composerControlShortcuts.queueNext}
79
84
  isMac={state.isMac}
80
85
  onCancel={handlers.onCancel}
86
+ onConfirmInteractionAction={handlers.onConfirmInteractionOption}
81
87
  onSend={handlers.onSend}
82
- onInterrupt={handlers.onInterrupt}
88
+ onStop={handlers.onInterrupt}
83
89
  />
84
90
  </div>
85
91
  </div>
@@ -60,6 +60,8 @@ export const buildSenderControllerResult = ({
60
60
  modelUnavailable,
61
61
  permissionContext,
62
62
  placeholder,
63
+ secondarySendShortcut,
64
+ onSecondarySendShortcut,
63
65
  editorRef,
64
66
  toolbar
65
67
  }: {
@@ -80,6 +82,8 @@ export const buildSenderControllerResult = ({
80
82
  reasons?: string[]
81
83
  }
82
84
  placeholder: string
85
+ secondarySendShortcut?: string
86
+ onSecondarySendShortcut?: () => void
83
87
  editorRef: MutableRefObject<SenderEditorHandle | null>
84
88
  toolbar: SenderControllerToolbar
85
89
  }) => ({
@@ -100,6 +104,8 @@ export const buildSenderControllerResult = ({
100
104
  interactionResponse,
101
105
  modelUnavailable,
102
106
  placeholder,
107
+ secondarySendShortcut,
108
+ onSecondarySendShortcut,
103
109
  onInputChange: completion.handleInputChange,
104
110
  onCursorChange: completion.handleCursorChange,
105
111
  onCancelContextPicker: () => {
@@ -17,10 +17,16 @@ export const buildSenderToolbar = ({
17
17
  isInlineEdit,
18
18
  isMac,
19
19
  isThinking,
20
+ sendBlocked,
21
+ sendBlockedTooltip,
22
+ showConfirmInteractionAction,
23
+ confirmInteractionLabel,
24
+ onConfirmInteractionOption,
20
25
  message,
21
26
  props,
22
27
  refs,
23
28
  referenceActions,
29
+ queuedMessageShortcuts,
24
30
  resolvedSendShortcut,
25
31
  selectOverlays,
26
32
  supportsEffort,
@@ -31,14 +37,22 @@ export const buildSenderToolbar = ({
31
37
  handleImageUpload: () => void
32
38
  handleOpenContextPicker: () => void
33
39
  }
34
- callbacks: { onSend: () => void }
40
+ callbacks: { onSend: (mode?: 'steer' | 'next') => void }
35
41
  composer: { input: string; pendingImageCount: number; pendingFileCount: number }
36
- composerControlShortcuts: SenderToolbarData['composerControlShortcuts']
42
+ composerControlShortcuts: Pick<
43
+ SenderToolbarData['composerControlShortcuts'],
44
+ 'switchEffort' | 'switchModel' | 'switchPermissionMode'
45
+ >
37
46
  focusRestore: { queueEditorFocusRestore: () => void }
38
47
  isBusy: boolean
39
48
  isInlineEdit: boolean
40
49
  isMac: boolean
41
50
  isThinking: boolean
51
+ sendBlocked: boolean
52
+ sendBlockedTooltip?: string
53
+ showConfirmInteractionAction: boolean
54
+ confirmInteractionLabel?: string
55
+ onConfirmInteractionOption?: () => void
42
56
  message: { warning: (content: ReactNode) => unknown }
43
57
  props: SenderProps
44
58
  refs: {
@@ -57,6 +71,7 @@ export const buildSenderToolbar = ({
57
71
  referenceMenuNavigation: SenderToolbarRefs['referenceMenuNavigation']
58
72
  permissionMenuNavigation: SenderToolbarRefs['permissionMenuNavigation']
59
73
  }
74
+ queuedMessageShortcuts: Pick<SenderToolbarData['composerControlShortcuts'], 'queueNext' | 'queueSteer'>
60
75
  resolvedSendShortcut: string
61
76
  selectOverlays: {
62
77
  showModelSelect: boolean
@@ -82,7 +97,9 @@ export const buildSenderToolbar = ({
82
97
  onModelChange: props.onModelChange,
83
98
  onToggleRecommendedModel: props.onToggleRecommendedModel,
84
99
  onPermissionModeChange: props.onPermissionModeChange,
100
+ onQueueModeChange: props.onQueueModeChange,
85
101
  onCancel: props.onCancel,
102
+ onConfirmInteractionOption,
86
103
  onSend: callbacks.onSend
87
104
  },
88
105
  composer,
@@ -95,6 +112,8 @@ export const buildSenderToolbar = ({
95
112
  modelSearchOptions: props.modelSearchOptions,
96
113
  permissionMode: props.permissionMode ?? 'default',
97
114
  permissionModeOptions: props.permissionModeOptions ?? [],
115
+ queueMode: props.queueMode ?? 'steer',
116
+ queuedMessageShortcuts,
98
117
  recommendedModelOptions: props.recommendedModelOptions,
99
118
  servicePreviewModelOptions: props.servicePreviewModelOptions,
100
119
  resolvedSendShortcut,
@@ -110,10 +129,14 @@ export const buildSenderToolbar = ({
110
129
  isInlineEdit,
111
130
  isMac,
112
131
  isThinking,
132
+ sendBlocked,
133
+ sendBlockedTooltip,
134
+ showConfirmInteractionAction,
113
135
  modelUnavailable: props.modelUnavailable,
114
136
  referenceActions,
115
137
  refs,
116
138
  selectOverlays,
139
+ confirmInteractionLabel,
117
140
  submitLabel: props.submitLabel,
118
141
  submitLoading: props.submitLoading === true,
119
142
  supportsEffort
@@ -3,6 +3,7 @@ import type { ReactNode } from 'react'
3
3
  import type { ChatEffort } from '#~/hooks/chat/use-chat-effort'
4
4
  import type { ModelSelectOption } from '#~/hooks/chat/use-chat-model-adapter-selection'
5
5
  import type { PermissionMode } from '#~/hooks/chat/use-chat-permission-mode'
6
+ import type { SessionQueuedMessageMode } from '@vibe-forge/core'
6
7
 
7
8
  import type { SenderToolbarHandlers } from '../@types/sender-toolbar-types'
8
9
 
@@ -19,7 +20,9 @@ export const createSenderToolbarHandlers = ({
19
20
  onModelChange,
20
21
  onToggleRecommendedModel,
21
22
  onPermissionModeChange,
23
+ onQueueModeChange,
22
24
  onCancel,
25
+ onConfirmInteractionOption,
23
26
  onSend,
24
27
  referenceActions,
25
28
  selectOverlays,
@@ -41,8 +44,10 @@ export const createSenderToolbarHandlers = ({
41
44
  onModelChange?: (model: string) => void
42
45
  onToggleRecommendedModel?: (option: ModelSelectOption) => void | Promise<void>
43
46
  onPermissionModeChange?: (mode: PermissionMode) => void
47
+ onQueueModeChange?: (mode: SessionQueuedMessageMode) => void
44
48
  onCancel?: () => void
45
- onSend: () => void
49
+ onConfirmInteractionOption?: () => void
50
+ onSend: (mode?: SessionQueuedMessageMode) => void
46
51
  referenceActions: {
47
52
  setShowReferenceActions: (nextOpen: boolean) => void
48
53
  setShowPermissionActions: (nextOpen: boolean) => void
@@ -108,8 +113,10 @@ export const createSenderToolbarHandlers = ({
108
113
  onToggleRecommendedModel,
109
114
  onEffortChange,
110
115
  onAdapterChange,
116
+ onQueueModeChange,
111
117
  onSend,
112
118
  onInterrupt,
113
- onCancel
119
+ onCancel,
120
+ onConfirmInteractionOption
114
121
  } satisfies SenderToolbarHandlers
115
122
  }
@@ -1,5 +1,5 @@
1
1
  import type { AskUserQuestionParams } from '@vibe-forge/core'
2
2
 
3
3
  export const shouldHideSenderForInteraction = (
4
- interactionRequest: { id: string; payload: AskUserQuestionParams } | null | undefined
5
- ) => interactionRequest?.payload.kind === 'permission'
4
+ _interactionRequest: { id: string; payload: AskUserQuestionParams } | null | undefined
5
+ ) => false
@@ -1,5 +1,7 @@
1
1
  import type { ReactNode } from 'react'
2
2
 
3
+ import type { SessionQueuedMessageMode } from '@vibe-forge/core'
4
+
3
5
  import type { ChatEffort } from '#~/hooks/chat/use-chat-effort'
4
6
  import type { ModelSelectMenuGroup, ModelSelectOption } from '#~/hooks/chat/use-chat-model-adapter-selection'
5
7
  import type { PermissionMode } from '#~/hooks/chat/use-chat-permission-mode'
@@ -33,8 +35,10 @@ export const createSenderToolbarBindings = ({
33
35
  onModelChange?: (model: string) => void
34
36
  onToggleRecommendedModel?: (option: ModelSelectOption) => void | Promise<void>
35
37
  onPermissionModeChange?: (mode: PermissionMode) => void
38
+ onQueueModeChange?: (mode: SessionQueuedMessageMode) => void
36
39
  onCancel?: () => void
37
- onSend: () => void
40
+ onConfirmInteractionOption?: () => void
41
+ onSend: (mode?: SessionQueuedMessageMode) => void
38
42
  }
39
43
  composer: { input: string; pendingImageCount: number; pendingFileCount: number }
40
44
  resources: { message: { warning: (content: ReactNode) => unknown }; t: (key: string) => string }
@@ -46,6 +50,8 @@ export const createSenderToolbarBindings = ({
46
50
  modelSearchOptions?: ModelSelectOption[]
47
51
  permissionMode: PermissionMode
48
52
  permissionModeOptions: SenderToolbarData['permissionModeOptions']
53
+ queueMode: SessionQueuedMessageMode
54
+ queuedMessageShortcuts: Pick<SenderToolbarData['composerControlShortcuts'], 'queueNext' | 'queueSteer'>
49
55
  recommendedModelOptions?: ModelSelectOption[]
50
56
  servicePreviewModelOptions?: ModelSelectOption[]
51
57
  resolvedSendShortcut: string
@@ -56,11 +62,17 @@ export const createSenderToolbarBindings = ({
56
62
  ui: {
57
63
  adapterLocked: boolean
58
64
  canOpenReferenceActions: boolean
59
- composerControlShortcuts: SenderToolbarData['composerControlShortcuts']
65
+ composerControlShortcuts: Pick<
66
+ SenderToolbarData['composerControlShortcuts'],
67
+ 'switchEffort' | 'switchModel' | 'switchPermissionMode'
68
+ >
60
69
  focusRestore: { queueEditorFocusRestore: () => void }
61
70
  isInlineEdit: boolean
62
71
  isMac: boolean
63
72
  isThinking: boolean
73
+ sendBlocked: boolean
74
+ sendBlockedTooltip?: string
75
+ showConfirmInteractionAction: boolean
64
76
  modelUnavailable?: boolean
65
77
  referenceActions: {
66
78
  showReferenceActions: boolean
@@ -85,6 +97,7 @@ export const createSenderToolbarBindings = ({
85
97
  openEffortSelector: () => boolean
86
98
  }
87
99
  submitLabel?: string
100
+ confirmInteractionLabel?: string
88
101
  submitLoading: boolean
89
102
  supportsEffort: boolean
90
103
  }
@@ -93,6 +106,9 @@ export const createSenderToolbarBindings = ({
93
106
  isInlineEdit: ui.isInlineEdit,
94
107
  isThinking: ui.isThinking,
95
108
  modelUnavailable: Boolean(ui.modelUnavailable),
109
+ sendBlocked: ui.sendBlocked,
110
+ sendBlockedTooltip: ui.sendBlockedTooltip,
111
+ showConfirmInteractionAction: ui.showConfirmInteractionAction,
96
112
  adapterLocked: ui.adapterLocked,
97
113
  submitLoading: ui.submitLoading,
98
114
  supportsEffort: ui.supportsEffort,
@@ -108,6 +124,8 @@ export const createSenderToolbarBindings = ({
108
124
  selectedAdapter: selection.selectedAdapter,
109
125
  isMac: ui.isMac,
110
126
  resolvedSendShortcut: selection.resolvedSendShortcut,
127
+ queueMode: selection.queueMode,
128
+ showQueueModeControl: ui.isThinking && !ui.isInlineEdit,
111
129
  hasComposerContent: composer.input.trim() !== '' || composer.pendingImageCount > 0 || composer.pendingFileCount > 0,
112
130
  hasSendText: composer.input.trim() !== ''
113
131
  }
@@ -121,8 +139,12 @@ export const createSenderToolbarBindings = ({
121
139
  effortOptions: selection.effortOptions,
122
140
  permissionModeOptions: selection.permissionModeOptions,
123
141
  adapterOptions: selection.adapterOptions,
124
- composerControlShortcuts: ui.composerControlShortcuts,
125
- submitLabel: ui.submitLabel
142
+ composerControlShortcuts: {
143
+ ...ui.composerControlShortcuts,
144
+ ...selection.queuedMessageShortcuts
145
+ },
146
+ submitLabel: ui.submitLabel,
147
+ confirmInteractionLabel: ui.confirmInteractionLabel
126
148
  }
127
149
 
128
150
  const toolbarRefs: SenderToolbarRefs = {
@@ -144,7 +166,9 @@ export const createSenderToolbarBindings = ({
144
166
  onModelChange: callbacks.onModelChange,
145
167
  onToggleRecommendedModel: callbacks.onToggleRecommendedModel,
146
168
  onPermissionModeChange: callbacks.onPermissionModeChange,
169
+ onQueueModeChange: callbacks.onQueueModeChange,
147
170
  onCancel: callbacks.onCancel,
171
+ onConfirmInteractionOption: callbacks.onConfirmInteractionOption,
148
172
  onSend: callbacks.onSend,
149
173
  referenceActions: ui.referenceActions,
150
174
  selectOverlays: ui.selectOverlays,