We encountered a random case with the Assistant api, where Run
object was returning a status of "requires_action"
and after submitting the tool output successfully it would return the status of "processing"
for a few seconds then again "requires_action"
with the exact same arguments
.
After run.create
, loop:
- Run status = processing
- Run status = requires_action
- Submit tool output (success)
- Run status = processing
- Repeats loop
Our processing code runs in a loop checking the Run status:
#class Assistant:
#...
def process(self, *, message=None):
"""
Processes the incoming message by creating a message in the thread, initiating a run, and handling the run's lifecycle.
This method takes a message, sends it to the thread, and manages the run created for this message. It handles different
run statuses. For runs requiring action, it processes necessary tool outputs. The method waits for the run to complete
and retrieves the final message from the thread.
Args:
message (str): The message to be processed.
Returns:
str: The content of the final message from the completed run.
"""
if not message:
raise ValueError("Message is required")
try:
thread = self.thread
print(f"[DEBUG][Assistant.process] Thread ID: {thread.id}")
new_message = client.beta.threads.messages.create(
thread_id=thread.id,
role="user",
content=[{ 'text': message, "type": 'text' }],
)
print(f"[DEBUG][Assistant.process] Created message with ID: {new_message.id} for Thread ID: {thread.id}")
except Exception as e:
print(f"[ERROR][Assistant.process] Failed to create message or run: {e}")
raise
run = client.beta.threads.runs.create(
thread_id=thread.id,
assistant_id=self.Assistant_id,
)
print(f"[DEBUG][Assistant.process] Created run with ID: {run.id} for Thread ID: {thread.id}") # type: ignore - SEE: https://platform.openai.com/docs/api-reference/runs/getRun
# The status of the run can be one of: queued, in_progress, requires_action, cancelling, cancelled, failed, completed, incomplete, or expired
while run.status in ["in_progress", "queued", "requires_action"]:
try:
print(f"[DEBUG][Assistant.process] Latest run status: {run.status}")
if run.status == "requires_action":
print(f"[DEBUG][Assistant.process] Run status is requires_action")
# if run.required_action.type == "submit_tool_outputs":
tool_call_outputs = handle_required_action(
run,
message,
thread_id=thread.id,
message_id=new_message.id
)
print(f"[DEBUG][Assistant.process] Complete tool call outputs: {tool_call_outputs}")
if tool_call_outputs and len(tool_call_outputs) > 0:
client.beta.threads.runs.submit_tool_outputs(
thread_id=thread.id,
run_id=run.id,
tool_outputs=tool_call_outputs
)
print(f"[DEBUG][Assistant.process] Submitted tool outputs to Run ID: {run.id}")
else:
print(f"[ERROR][Assistant.process] No tool call outputs!!")
print(f"[DEBUG][Assistant.process] ===== Waiting for next poll =====")
time.sleep(1) # Sleep to avoid hitting the API rate limit
run = client.beta.threads.runs.retrieve(run_id=run.id, thread_id=thread.id)
except Exception as e:
print(f"[ERROR][Assistant.process] Error during message retrieval or processing: {e}")
raise
if run.status == "completed":
messages = client.beta.threads.messages.list(thread_id=thread.id, run_id=run.id)
message = {
'role': messages.data[-1].role,
'content': messages.data[-1].content[0].text.value,
'id': messages.data[-1].id
}
return message
elif run.status == "failed":
raise ValueError(f"Run status is failed ({run.status}): {run.last_error}")
else:
raise ValueError(f"Run status is not completed ({run.status}): {run.last_error}")
This issue caused a large spike in the OpenAI api bill just from that single Run.
Any ideas how to fix this?
It has only happened once so far from hundreds of Runs.