From a7c37da713f35333c8aba6460f73888a41b18f7b Mon Sep 17 00:00:00 2001 From: hunteraraujo Date: Wed, 6 Sep 2023 11:41:23 -0700 Subject: [PATCH 1/9] Make input and additionalInput optional in StepRequestBody Updated the StepRequestBody class to allow both 'input' and 'additionalInput' to be optional. Added logic in toJson() method to return an empty JSON object if both fields are null. --- frontend/lib/models/step_request_body.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/lib/models/step_request_body.dart b/frontend/lib/models/step_request_body.dart index 6f8fb7cb..23e7521f 100644 --- a/frontend/lib/models/step_request_body.dart +++ b/frontend/lib/models/step_request_body.dart @@ -1,10 +1,13 @@ class StepRequestBody { - final String input; + final String? input; final Map? additionalInput; StepRequestBody({required this.input, this.additionalInput}); Map toJson() { + if (input == null && additionalInput == null) { + return {}; + } return {'input': input, 'additional_input': additionalInput}; } } From 5cd1abab945a6bd581787eb9b27c039734d6f6b5 Mon Sep 17 00:00:00 2001 From: hunteraraujo Date: Wed, 6 Sep 2023 11:42:45 -0700 Subject: [PATCH 2/9] Implement Continuous Mode in ChatViewModel Added a new state variable `_isContinuousMode` to the ChatViewModel to track whether the chat is in continuous mode or not. This state is toggled via a setter and triggers UI updates through `notifyListeners()`. Enhanced the `sendChatMessage` method to automatically send a null message if continuous mode is active, triggering the next step in the chat. --- frontend/lib/viewmodels/chat_viewmodel.dart | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/frontend/lib/viewmodels/chat_viewmodel.dart b/frontend/lib/viewmodels/chat_viewmodel.dart index 5c8fb3ca..baf8e654 100644 --- a/frontend/lib/viewmodels/chat_viewmodel.dart +++ b/frontend/lib/viewmodels/chat_viewmodel.dart @@ -10,6 +10,14 @@ class ChatViewModel with ChangeNotifier { List _chats = []; String? _currentTaskId; + bool _isContinuousMode = false; + + bool get isContinuousMode => _isContinuousMode; + set isContinuousMode(bool value) { + _isContinuousMode = value; + notifyListeners(); + } + ChatViewModel(this._chatService); /// Returns the current list of chats. @@ -95,7 +103,7 @@ class ChatViewModel with ChangeNotifier { } /// Sends a chat message for a specific task. - void sendChatMessage(String message) async { + void sendChatMessage(String? message) async { if (_currentTaskId == null) { print("Error: Task ID is not set."); return; @@ -136,6 +144,10 @@ class ChatViewModel with ChangeNotifier { // Notify UI of the new chats notifyListeners(); + if (_isContinuousMode) { + sendChatMessage(null); + } + print("Chats added for task ID: $_currentTaskId"); } catch (error) { // TODO: Bubble up errors to UI From d80053e8dc7a91340e0a97bca04c4e006443c2d2 Mon Sep 17 00:00:00 2001 From: hunteraraujo Date: Wed, 6 Sep 2023 11:46:03 -0700 Subject: [PATCH 3/9] Refactor ChatInputField to Support Continuous Mode - Added a new boolean state `isContinuousMode` to the `ChatInputField` widget to handle the continuous mode feature. - Introduced a new callback function `onContinuousModePressed` to manage the state of the continuous mode from an external source. - Conditionally rendered the send button based on the `isContinuousMode` state. - Enhanced the UI by adding a button to toggle between continuous mode and single message mode, which triggers the `onContinuousModePressed` callback. --- frontend/lib/views/chat/chat_input_field.dart | 45 ++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/frontend/lib/views/chat/chat_input_field.dart b/frontend/lib/views/chat/chat_input_field.dart index 560e9069..e6fcca1c 100644 --- a/frontend/lib/views/chat/chat_input_field.dart +++ b/frontend/lib/views/chat/chat_input_field.dart @@ -3,10 +3,14 @@ import 'package:flutter/material.dart'; class ChatInputField extends StatefulWidget { // Callback to be triggered when the send button is pressed final Function(String) onSendPressed; + final Function() onContinuousModePressed; + final bool isContinuousMode; const ChatInputField({ Key? key, required this.onSendPressed, + required this.onContinuousModePressed, + this.isContinuousMode = false, }) : super(key: key); @override @@ -49,6 +53,8 @@ class _ChatInputFieldState extends State { // when the content exceeds its maximum height child: SingleChildScrollView( reverse: true, + // TODO: Deselect text field after user goes into continous mode + // TODO: Include tool tip to explain clicking text field will end continuous mode child: TextField( controller: _controller, // Allowing the TextField to expand vertically and accommodate multiple lines @@ -56,16 +62,35 @@ class _ChatInputFieldState extends State { decoration: InputDecoration( hintText: 'Type a message...', border: InputBorder.none, - suffixIcon: IconButton( - splashRadius: 0.1, - icon: const Icon(Icons.send), - onPressed: () { - // TODO: We allow empty messages? - if (_controller.text.isNotEmpty) { - widget.onSendPressed(_controller.text); - _controller.clear(); - } - }, + suffixIcon: Row( + mainAxisSize: MainAxisSize.min, // Set to minimum space + children: [ + if (!widget.isContinuousMode) + // TODO: Include tool tip to explain single message sending + IconButton( + splashRadius: 0.1, + icon: const Icon(Icons.send), + onPressed: () { + widget.onSendPressed(_controller.text); + _controller.clear(); + }, + ), + // TODO: Include tool tip to explain continuous mode + // TODO: Include pop up to explain continuous mode reprecussions + IconButton( + splashRadius: 0.1, + icon: Icon(widget.isContinuousMode + ? Icons.pause + : Icons.fast_forward), + onPressed: () { + if (!widget.isContinuousMode) { + widget.onSendPressed(_controller.text); + _controller.clear(); + } + widget.onContinuousModePressed(); + }, + ) + ], ), ), ), From d3b4b50a5c80d06f89dfa70dcea87cfc62913f39 Mon Sep 17 00:00:00 2001 From: hunteraraujo Date: Wed, 6 Sep 2023 11:46:43 -0700 Subject: [PATCH 4/9] Update parameters for ChatInputField to support continuous mode --- frontend/lib/views/chat/chat_view.dart | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/frontend/lib/views/chat/chat_view.dart b/frontend/lib/views/chat/chat_view.dart index d3a5bfdb..565ff285 100644 --- a/frontend/lib/views/chat/chat_view.dart +++ b/frontend/lib/views/chat/chat_view.dart @@ -56,13 +56,20 @@ class _ChatViewState extends State { child: ChatInputField( onSendPressed: (message) async { if (widget.viewModel.currentTaskId != null) { - widget.viewModel.sendChatMessage(message); + widget.viewModel + .sendChatMessage((message == "") ? null : message); } else { String newTaskId = await taskViewModel.createTask(message); widget.viewModel.setCurrentTaskId(newTaskId); - widget.viewModel.sendChatMessage(message); + widget.viewModel + .sendChatMessage((message == "") ? null : message); } }, + onContinuousModePressed: () { + widget.viewModel.isContinuousMode = + !widget.viewModel.isContinuousMode; + }, + isContinuousMode: widget.viewModel.isContinuousMode, ), ), ], From 4e499c5bac7031d8a189df26cba5a837d207bd80 Mon Sep 17 00:00:00 2001 From: hunteraraujo Date: Wed, 6 Sep 2023 11:56:45 -0700 Subject: [PATCH 5/9] Deselect text field after user goes into continuous mode --- frontend/lib/views/chat/chat_input_field.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/lib/views/chat/chat_input_field.dart b/frontend/lib/views/chat/chat_input_field.dart index e6fcca1c..e516799b 100644 --- a/frontend/lib/views/chat/chat_input_field.dart +++ b/frontend/lib/views/chat/chat_input_field.dart @@ -20,6 +20,7 @@ class ChatInputField extends StatefulWidget { class _ChatInputFieldState extends State { // Controller for the TextField to manage its content final TextEditingController _controller = TextEditingController(); + final FocusNode _focusNode = FocusNode(); @override Widget build(BuildContext context) { @@ -53,10 +54,10 @@ class _ChatInputFieldState extends State { // when the content exceeds its maximum height child: SingleChildScrollView( reverse: true, - // TODO: Deselect text field after user goes into continous mode // TODO: Include tool tip to explain clicking text field will end continuous mode child: TextField( controller: _controller, + focusNode: _focusNode, // Allowing the TextField to expand vertically and accommodate multiple lines maxLines: null, decoration: InputDecoration( @@ -86,6 +87,7 @@ class _ChatInputFieldState extends State { if (!widget.isContinuousMode) { widget.onSendPressed(_controller.text); _controller.clear(); + _focusNode.unfocus(); } widget.onContinuousModePressed(); }, From 2e62c517e216836ccf8d4aef38bec61d43902ff5 Mon Sep 17 00:00:00 2001 From: hunteraraujo Date: Wed, 6 Sep 2023 12:04:52 -0700 Subject: [PATCH 6/9] Include tooltips for single message + continuous mode --- frontend/lib/views/chat/chat_input_field.dart | 46 +++++++++++-------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/frontend/lib/views/chat/chat_input_field.dart b/frontend/lib/views/chat/chat_input_field.dart index e516799b..19bf72f0 100644 --- a/frontend/lib/views/chat/chat_input_field.dart +++ b/frontend/lib/views/chat/chat_input_field.dart @@ -67,30 +67,36 @@ class _ChatInputFieldState extends State { mainAxisSize: MainAxisSize.min, // Set to minimum space children: [ if (!widget.isContinuousMode) - // TODO: Include tool tip to explain single message sending - IconButton( + Tooltip( + message: 'Send a single message', + child: IconButton( + splashRadius: 0.1, + icon: const Icon(Icons.send), + onPressed: () { + widget.onSendPressed(_controller.text); + _controller.clear(); + }, + ), + ), + // TODO: Include pop up to explain continuous mode reprecussions + Tooltip( + message: widget.isContinuousMode + ? '' + : 'Enable continuous mode', + child: IconButton( splashRadius: 0.1, - icon: const Icon(Icons.send), + icon: Icon(widget.isContinuousMode + ? Icons.pause + : Icons.fast_forward), onPressed: () { - widget.onSendPressed(_controller.text); - _controller.clear(); + if (!widget.isContinuousMode) { + widget.onSendPressed(_controller.text); + _controller.clear(); + _focusNode.unfocus(); + } + widget.onContinuousModePressed(); }, ), - // TODO: Include tool tip to explain continuous mode - // TODO: Include pop up to explain continuous mode reprecussions - IconButton( - splashRadius: 0.1, - icon: Icon(widget.isContinuousMode - ? Icons.pause - : Icons.fast_forward), - onPressed: () { - if (!widget.isContinuousMode) { - widget.onSendPressed(_controller.text); - _controller.clear(); - _focusNode.unfocus(); - } - widget.onContinuousModePressed(); - }, ) ], ), From 27e9868aa50ee718698be87ee39fb4829f5a5706 Mon Sep 17 00:00:00 2001 From: hunteraraujo Date: Wed, 6 Sep 2023 12:10:57 -0700 Subject: [PATCH 7/9] End continuous mode when clicking text field --- frontend/lib/views/chat/chat_input_field.dart | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/frontend/lib/views/chat/chat_input_field.dart b/frontend/lib/views/chat/chat_input_field.dart index 19bf72f0..4901408a 100644 --- a/frontend/lib/views/chat/chat_input_field.dart +++ b/frontend/lib/views/chat/chat_input_field.dart @@ -22,6 +22,22 @@ class _ChatInputFieldState extends State { final TextEditingController _controller = TextEditingController(); final FocusNode _focusNode = FocusNode(); + @override + void initState() { + super.initState(); + _focusNode.addListener(() { + if (_focusNode.hasFocus && widget.isContinuousMode) { + widget.onContinuousModePressed(); + } + }); + } + + @override + void dispose() { + _focusNode.dispose(); // Dispose of the FocusNode when you're done. + super.dispose(); + } + @override Widget build(BuildContext context) { // Using LayoutBuilder to provide the current constraints of the widget, @@ -54,7 +70,6 @@ class _ChatInputFieldState extends State { // when the content exceeds its maximum height child: SingleChildScrollView( reverse: true, - // TODO: Include tool tip to explain clicking text field will end continuous mode child: TextField( controller: _controller, focusNode: _focusNode, From a8023c259876dc68b37d486ba8208f39c59f388d Mon Sep 17 00:00:00 2001 From: hunteraraujo Date: Wed, 6 Sep 2023 12:15:57 -0700 Subject: [PATCH 8/9] Fix empty user chats --- frontend/lib/viewmodels/chat_viewmodel.dart | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/frontend/lib/viewmodels/chat_viewmodel.dart b/frontend/lib/viewmodels/chat_viewmodel.dart index baf8e654..f85c9d5e 100644 --- a/frontend/lib/viewmodels/chat_viewmodel.dart +++ b/frontend/lib/viewmodels/chat_viewmodel.dart @@ -120,13 +120,17 @@ class ChatViewModel with ChangeNotifier { Step executedStep = Step.fromMap(executedStepResponse); // Create a Chat object for the user message - final userChat = Chat( - id: executedStep.stepId, - taskId: executedStep.taskId, - message: executedStep.input, - timestamp: DateTime.now(), - messageType: MessageType.user, - ); + if (executedStep.input.isNotEmpty) { + final userChat = Chat( + id: executedStep.stepId, + taskId: executedStep.taskId, + message: executedStep.input, + timestamp: DateTime.now(), + messageType: MessageType.user, + ); + + _chats.add(userChat); + } // Create a Chat object for the agent message final agentChat = Chat( @@ -137,8 +141,6 @@ class ChatViewModel with ChangeNotifier { messageType: MessageType.agent, jsonResponse: executedStepResponse); - // Add the user and agent chats to the list - _chats.add(userChat); _chats.add(agentChat); // Notify UI of the new chats From a933f117fb5b127df863cbc966f991106417958a Mon Sep 17 00:00:00 2001 From: hunteraraujo Date: Wed, 6 Sep 2023 12:21:30 -0700 Subject: [PATCH 9/9] Add the ability to deselect a task --- frontend/lib/viewmodels/task_viewmodel.dart | 7 +++++++ frontend/lib/views/task/task_view.dart | 1 + 2 files changed, 8 insertions(+) diff --git a/frontend/lib/viewmodels/task_viewmodel.dart b/frontend/lib/viewmodels/task_viewmodel.dart index 4b9517b9..5423c181 100644 --- a/frontend/lib/viewmodels/task_viewmodel.dart +++ b/frontend/lib/viewmodels/task_viewmodel.dart @@ -73,4 +73,11 @@ class TaskViewModel with ChangeNotifier { throw ArgumentError(errorMessage); } } + + /// Deselects the currently selected task. + void deselectTask() { + _selectedTask = null; + print("Deselected the current task."); + notifyListeners(); // Notify listeners to rebuild UI + } } diff --git a/frontend/lib/views/task/task_view.dart b/frontend/lib/views/task/task_view.dart index f681f536..73d64b48 100644 --- a/frontend/lib/views/task/task_view.dart +++ b/frontend/lib/views/task/task_view.dart @@ -46,6 +46,7 @@ class _TaskViewState extends State { final chatViewModel = Provider.of(context, listen: false); chatViewModel.clearCurrentTaskAndChats(); + widget.viewModel.deselectTask(); print( 'New Task button pressed, cleared current task ID and chats'); },