77 transition: `transform ${agentTransitions.TRANSITION_DURATION}ms ease-in-out`
88 }"
99 >
10- <div
11- class =" w-full border rounded-lg pb-8"
12- :class =" agentStore.isAudioChatMode ? 'border-none mt-8' : 'border dark:bg-gray-700'"
13- >
10+ <SteerQueue />
11+ <!-- <SteerDebugPanel /> -->
12+ <div
13+ class =" w-full border rounded-lg flex flex-col"
14+ :class =" agentStore.isAudioChatMode ? 'border-none mt-8' : 'border dark:bg-gray-700'"
15+ >
1416 <textarea
1517 v-if =" !agentStore.isAudioChatMode"
1618 v-model =" agentStore.userMessageInput"
1719 ref =" textInput"
20+ rows =" 1"
1821 @input =" autoResize"
1922 :class =" [
20- 'min-h-12 px-4 pt-4 rounded-xl w-full resize-none overflow-hidden text-lightInputText dark:text-darkInputText rounded-md bg-transparent text-sm bg-gray-50 dark:bg-gray-700 dark:border-gray-600 focus:outline-none',
23+ 'h-8 px-4 py-3 border-b rounded-xl rounded-b-none w-full resize-none overflow-hidden text-lightInputText dark:text-darkInputText rounded-md bg-transparent text-sm bg-gray-50 dark:bg-gray-700 dark:border-gray-600 focus:outline-none',
2124 { '!text-base': coreStore.isIos }
2225 ]"
23- :placeholder =" agentStore.hasPendingToolApproval ? 'Approve or reject the pending action to continue' : agentStore.userMessagePlaceholder"
24- :disabled =" agentStore.isMessageInputBlocked"
26+ :placeholder =" placeholderText"
2527 @keydown.enter.exact.prevent =" sendMessage"
2628 />
29+ <div class =" flex items-center justify-between px-2 py-1" >
2730 <div
2831 v-if =" agentStore.availableModes.length > 1"
2932 ref =" modeMenu"
30- class =" absolute bottom-2 left-4 "
33+ class =" relative "
3134 >
3235 <button
3336 aria-label =" Select mode"
4649 :class =" isModeMenuOpen ? ' !rotate-180' : ' !rotate-0' "
4750 />
4851 </button >
49-
50- <div
51- v-if =" isModeMenuOpen"
52- class =" absolute bottom-full left-0 mb-2 min-w-40 overflow-hidden rounded-md border border-gray-200 bg-white shadow-lg dark:border-gray-600 dark:bg-gray-800"
53- >
54- <button
55- v-for =" mode in agentStore.availableModes"
56- :key =" mode.name"
57- class =" block w-full px-3 py-2 text-left text-sm text-lightInputText transition-colors duration-150 hover:bg-gray-100 dark:text-darkInputText dark:hover:bg-gray-700"
58- :class =" mode.name === agentStore.activeModeName ? 'bg-gray-100 dark:bg-gray-700' : ''"
59- type =" button"
60- @click =" selectMode(mode.name)"
52+ <Transition
53+ enter-active-class="transition ease-out duration-200"
54+ enter-from-class="opacity-0 scale-95"
55+ enter-to-class="opacity-100 scale-100"
56+ leave-active-class="transition ease-in duration-150"
57+ leave-from-class="opacity-100 scale-100"
58+ leave-to-class="opacity-0 scale-95"
59+ >
60+ <div
61+ v-if =" isModeMenuOpen"
62+ class =" absolute bottom-full left-0 mb-2 min-w-40 overflow-hidden rounded-md border border-gray-200 bg-white shadow-lg dark:border-gray-600 dark:bg-gray-800"
6163 >
62- {{ mode.name }}
63- </button >
64- </div >
64+ <button
65+ v-for =" mode in agentStore.availableModes"
66+ :key =" mode.name"
67+ class =" block w-full px-3 py-2 text-left text-sm text-lightInputText transition-colors duration-150 hover:bg-gray-100 dark:text-darkInputText dark:hover:bg-gray-700"
68+ :class =" mode.name === agentStore.activeModeName ? 'bg-gray-100 dark:bg-gray-700' : ''"
69+ type =" button"
70+ @click =" selectMode(mode.name)"
71+ >
72+ {{ mode.name }}
73+ </button >
74+ </div >
75+ </Transition >
6576 </div >
6677 <MicrophoneButton
6778 v-if =" props .meta .hasAudioAdapter "
6879 />
6980 <template v-if =" ! agentStore .isAudioChatMode " >
7081 <Button
7182 v-if =" ! agentStore .isResponseInProgress "
72- class="absolute right-4 bottom-2 !p-0 h-9 w-9 transition-opacity duration-200"
83+ class=" !p-0 h-7 w-7 transition-opacity duration-200"
7384 @click =" sendMessage "
74- :disabled =" ! agentStore .trimmedUserMessage || agentStore . isMessageInputBlocked "
85+ :disabled =" ! agentStore .trimmedUserMessage "
7586 >
7687 <IconArrowUpOutline
77- class="w-8 h-8 p-1
88+ class="w-6 h-6
7889 text-white"
7990 />
8091 </Button >
8192 <Button
8293 v-else
83- class="absolute right-4 bottom-2 !p-0 h-9 w-9 "
94+ class="right-4 bottom-2 !p-0 h-7 w-7 "
8495 @click =" stopCurrentRequest "
8596 >
8697 <div
87- class =" w-3 h-3 bg-white rounded-sm"
98+ class =" w-2.5 h-2.5 bg-white rounded-sm"
8899 />
89100 </Button >
90101 </template >
102+ </div >
91103 </div >
92104 </div >
93105</template >
94106
95107<script setup lang="ts">
96108import { IconArrowUpOutline , IconAngleDownOutline } from ' @iconify-prerendered/vue-flowbite' ;
97- import { useTemplateRef , onMounted , ref , onUnmounted } from ' vue' ;
109+ import { useTemplateRef , onMounted , ref , onUnmounted , watch , computed } from ' vue' ;
98110import { onClickOutside } from ' @vueuse/core'
99111import { useAgentStore } from ' ./composables/useAgentStore' ;
100112import { useAgentTransitions } from ' ./composables/useAgentTransitions' ;
101113import { Button } from ' @/afcl' ;
102114import { useCoreStore } from ' @/stores/core' ;
103115import { remToPx } from ' ./utils' ;
104116import MicrophoneButton from ' ./speech_recognition_frontend/MicrophoneButon.vue' ;
117+ import SteerQueue from ' ./SteerQueue.vue' ;
118+ import SteerDebugPanel from ' ./SteerDebugPanel.vue' ;
105119
106120const props = defineProps <{
107121 meta: {
@@ -124,13 +138,25 @@ const agentTransitions = useAgentTransitions();
124138const coreStore = useCoreStore ();
125139const isModeMenuOpen = ref (false );
126140
141+ const placeholderText = computed (() => {
142+ if (agentStore .isTurnActive ) {
143+ return ' Queue a follow-up — send after, or steer it…' ;
144+ }
145+ return agentStore .userMessagePlaceholder ;
146+ });
147+
127148onClickOutside (modeMenu as any , () => { isModeMenuOpen .value = false ; });
128149
129150onMounted (async () => {
130151 agentStore .setAvailableModes (props .meta .modes , props .meta .defaultModeName );
131152 agentStore .setCurrentGenerationModeFromLocalStorage ();
132153 agentStore .regisrerTextInput (textInput .value );
133154 textInput .value ?.focus ();
155+ autoResize ();
156+ });
157+
158+ watch (() => textInput .value ?.value , () => {
159+ autoResize ();
134160});
135161
136162function autoResize() {
@@ -161,7 +187,9 @@ function selectMode(modeName: string) {
161187async function sendMessage() {
162188 if (agentStore .isAudioChatMode ) return ;
163189 isModeMenuOpen .value = false ;
164- await agentStore .sendMessage ();
190+ // Routes to a steer (folded into the running turn) while generating, or a normal
191+ // new-turn send when idle.
192+ await agentStore .submitUserMessage ();
165193 autoResize ();
166194 props .conversationAreaRef ?.handleSendMessage ();
167195}
0 commit comments