Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chat: feature to cancel active runs #1404

Merged
merged 1 commit into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 33 additions & 10 deletions MAVProxy/modules/mavproxy_chat/chat_openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def __init__(self, mpstate, status_cb=None, wait_for_command_ack_fn=None):
self.client = None
self.assistant = None
self.assistant_thread = None
self.latest_run = None

# check connection to OpenAI assistant and connect if necessary
# returns True if connection is good, False if not
Expand Down Expand Up @@ -99,6 +100,25 @@ def set_api_key(self, api_key_str):
self.assistant = None
self.assistant_thread = None

# cancel the active run
def cancel_run(self):
# check the active thread and run
if (self.assistant_thread and self.latest_run is not None):
run_status = self.latest_run.status
if (run_status != "completed" and run_status != "cancelled" and
run_status != "cancelling"):
Comment on lines +108 to +109
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (run_status != "completed" and run_status != "cancelled" and
run_status != "cancelling"):
if run_status not in ["completed", "cancelled", "cancelling"]:


# cancel the active run
self.client.beta.threads.runs.cancel(
thread_id=self.assistant_thread.id,
run_id=self.run.id
)
else:
if (self.latest_run.status == "completed"):
print("Chat is completed, cannot be cancelled")
elif (self.latest_run.status == "cancelled"):
print("Chat is cancelled")

# send text to assistant
def send_to_assistant(self, text):
# get lock
Expand Down Expand Up @@ -132,7 +152,7 @@ def send_to_assistant(self, text):
time.sleep(0.1)

# retrieve the run
latest_run = self.client.beta.threads.runs.retrieve(
self.latest_run = self.client.beta.threads.runs.retrieve(
thread_id=self.assistant_thread.id,
run_id=self.run.id
)
Expand All @@ -141,22 +161,22 @@ def send_to_assistant(self, text):
failure_message = None

# check run status
if latest_run.status in ["queued", "in_progress", "cancelling"]:
if self.latest_run.status in ["queued", "in_progress", "cancelling"]:
run_done = False
elif latest_run.status in ["cancelled", "completed", "expired"]:
elif self.latest_run.status in ["cancelled", "completed", "expired"]:
run_done = True
elif latest_run.status in ["failed"]:
failure_message = latest_run.last_error.message
elif self.latest_run.status in ["failed"]:
failure_message = self.latest_run.last_error.message
run_done = True
elif latest_run.status in ["requires_action"]:
self.handle_function_call(latest_run)
elif self.latest_run.status in ["requires_action"]:
self.handle_function_call(self.latest_run)
run_done = False
else:
print("chat: unrecognised run status" + latest_run.status)
print("chat: unrecognised run status" + self.latest_run.status)
run_done = True

# send status to status callback
status_message = latest_run.status
status_message = self.latest_run.status
if failure_message is not None:
status_message = status_message + ": " + failure_message
self.send_status(status_message)
Expand All @@ -165,7 +185,10 @@ def send_to_assistant(self, text):
reply_messages = self.client.beta.threads.messages.list(self.assistant_thread.id,
order="asc",
after=input_message.id)
if reply_messages is None:

if (self.latest_run.status == "cancelled"):
return "cancelled successfully"
elif reply_messages is None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a blocker but the "elif" could be just an "if" because of the return one line higher

return "chat: failed to retrieve messages"

# concatenate all messages into a single reply skipping the first which is our question
Expand Down
14 changes: 14 additions & 0 deletions MAVProxy/modules/mavproxy_chat/chat_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ def __init__(self, mpstate, wait_for_command_ack_fn):
self.frame.Bind(wx.EVT_BUTTON, self.send_button_click, self.send_button)
self.horiz_sizer.Add(self.send_button, proportion=0, flag=wx.ALIGN_TOP | wx.ALL, border=5)

# add a cancel button
self.cancel_button = wx.Button(self.frame, id=-1, label="cancel", size=(75, 25))
self.frame.Bind(wx.EVT_BUTTON, self.cancel_button_click , self.cancel_button)
self.horiz_sizer.Add(self.cancel_button, proportion=0, flag=wx.ALIGN_TOP | wx.ALL, border=5)
wx.CallAfter(self.cancel_button.Disable)

# set size hints and add sizer to frame
self.vert_sizer.Add(self.text_reply, proportion=1, flag=wx.EXPAND, border=5)
self.vert_sizer.Add(self.text_status, proportion=0, flag=wx.EXPAND, border=5)
Expand Down Expand Up @@ -139,6 +145,10 @@ def record_button_click_execute(self, event):
self.set_status_text("sending text to assistasnt")
self.send_text_to_assistant()

# cancel button clicked
def cancel_button_click(self, event):
self.chat_openai.cancel_run()

# send button clicked
def send_button_click(self, event):
self.text_input_change(event)
Expand All @@ -161,6 +171,8 @@ def send_text_to_assistant(self):
focus = self.text_input

# disable buttons and text input to stop multiple inputs (can't be done from a thread or must use CallAfter)
# enable the cancel button to cancel the current run
wx.CallAfter(self.cancel_button.Enable)
wx.CallAfter(self.record_button.Disable)
wx.CallAfter(self.text_input.Disable)
wx.CallAfter(self.send_button.Disable)
Expand All @@ -181,6 +193,8 @@ def send_text_to_assistant(self):
wx.CallAfter(self.text_reply.AppendText, reply + "\n\n")

# reenable buttons and text input (can't be done from a thread or must use CallAfter)
# disable the cancel button
wx.CallAfter(self.cancel_button.Disable)
wx.CallAfter(self.record_button.Enable)
wx.CallAfter(self.text_input.Enable)
wx.CallAfter(self.send_button.Enable)
Expand Down