# I need help using assitant in python (required\_action infinite loop)

**URL:** <https://community.openai.com/t/i-need-help-using-assitant-in-python-required-action-infinite-loop/486969>\
**Category:** API\
**Tags:** python, assistants-api\
**Created:** [November 9, 2023, 7:44am UTC](https://community.openai.com/t/i-need-help-using-assitant-in-python-required-action-infinite-loop/486969 "2023-11-09T07:44:17Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![inachomsky](https://sea2.discourse-cdn.com/openai1/user_avatar/community.openai.com/inachomsky/32/236428_2.png) [@inachomsky](https://community.openai.com/u/inachomsky)\
**Post date:** [November 9, 2023, 7:44am UTC](https://community.openai.com/t/i-need-help-using-assitant-in-python-required-action-infinite-loop/486969/1 "2023-11-09T07:44:17Z")

</div>

I have created a assistant using the openai ui and i have tested it in playground, and works perfect, its a assistant with a single function and a single input message that returns a json with some data transformed by chatgpt.  
Im not clear where check in the documentation the steps to make it in python:

This are my python lines:

```auto
    thread = openai.beta.threads.create()
    message = openai.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="Use custom instructions and return JSON using this text: " + custom_text
    )

    run = openai.beta.threads.runs.create(
            thread_id=thread.id,
            assistant_id="my assistant key created in the openai webside")
    while run.status != 'completed':
        print(run.status)
        run = openai.beta.threads.runs.retrieve(
            thread_id=thread.id,
            run_id=run.id
        )
        try:
            messages = openai.beta.threads.messages.list(
                thread_id=thread.id
            )
            print(messages)
        except:
            continue
    return messages

```

The thread run starts on queue, but the next state is required\_action and never change, if i print the messsage i can see the custom\_text added in the content.  
requires\_action  
SyncCursorPage[ThreadMessage](data= info about the message content)  
Y need execute that text using the assistant function, but i don’t know how.

---

<div class="post-metadata">

**Author:** ![nayan96](https://sea2.discourse-cdn.com/openai1/user_avatar/community.openai.com/nayan96/32/243469_2.png) [@nayan96](https://community.openai.com/u/nayan96)\
**Post date:** [November 10, 2023, 12:45pm UTC](https://community.openai.com/t/i-need-help-using-assitant-in-python-required-action-infinite-loop/486969/2 "2023-11-10T12:45:11Z")

</div>

Run changes to `required_action` state when assistant calls a function. Here is snippet from OpenAI docs.

> When using the **Function calling** tool, the Run will move to a `required_action` state once the model determines the names and arguments of the functions to be called. You must then run those functions and [submit the outputs](https://platform.openai.com/docs/api-reference/runs/submitToolOutputs) before the run proceeds. If the outputs are not provided before the `expires_at` timestamp passes (roughly 10 mins past creation), the run will move to an expired status.

So you need to process the function and call `submit_outputs` for run to proceed. It will remain at `required_action` state till you process it or the run expires(roughly 10 mins after the state has been changed to `required_action`)

Also run can fail, cancel or expire. You need to exit the loop when that happens.

Here is more info on the [run lifecycle.](https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps)

---

<div class="post-metadata">

**Author:** ![geteff](https://sea2.discourse-cdn.com/openai1/user_avatar/community.openai.com/geteff/32/229071_2.png) [@geteff](https://community.openai.com/u/geteff)\
**Post date:** [November 16, 2023, 4:08pm UTC](https://community.openai.com/t/i-need-help-using-assitant-in-python-required-action-infinite-loop/486969/4 "2023-11-16T16:08:24Z")

</div>

Hi. I have been struggling with similar issues. Can you help me by showing your complete code? I am very new to coding. I am trying to use the assistant api to loop through data with a single retrieval function and single input message at a time. To run every questions as input in an excel sequentially. Thank you!

---

<div class="post-metadata">

**Author:** ![inachomsky](https://sea2.discourse-cdn.com/openai1/user_avatar/community.openai.com/inachomsky/32/236428_2.png) [@inachomsky](https://community.openai.com/u/inachomsky)\
**Post date:** [November 17, 2023, 11:46am UTC](https://community.openai.com/t/i-need-help-using-assitant-in-python-required-action-infinite-loop/486969/5 "2023-11-17T11:46:57Z")

</div>

Yes i finally have a code that is not the best but works

```auto
def myfuction():
    thread = openai.beta.threads.create()
    message = openai.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="Explaining what do"
    )
    running=True
    run = openai.beta.threads.runs.create(
            thread_id=thread.id,
            assistant_id="My assistant ID")
    count=0

    tool_outputs = []
    while run.status != 'completed':
        run = openai.beta.threads.runs.retrieve(
                thread_id=thread.id,
                run_id=run.id
                )
        messages = openai.beta.threads.messages.list(
                thread_id=thread.id
                )
        #print(run)
        #print(messages)
        if run.status == "requires_action" and count==0:
            tool_call_id = None
            try:
                for message in run.messages:
#this part is so ugly and take me time to make it work, i didnt find it in the doc, its to execute the function
                    if "tool_call_id" in message.content:
                        tool_call_id = message.content.split("tool_call_id: ")[1].split()[0]
                        print(tool_call_id)
                        break

                if tool_call_id:
                    count=1
                    print(tool_call_id)
                    # Sent action
                    run = openai.beta.threads.runs.submit_tool_outputs(
                        thread_id=thread.id,
                        run_id=run.id,
                        tool_outputs=[
                            {
                                "tool_call_id": tool_call_id
                            }
                        ]
                    )

        if run.required_action and run.required_action.submit_tool_outputs and run.required_action.submit_tool_outputs.tool_calls:
            for tool_call in run.required_action.submit_tool_outputs.tool_calls:
                tool_call_id = tool_call.id
                arguments = json.loads(tool_call.function.arguments)
                response = arguments # arguments is the response
                print(response)
                tool_outputs.append({
                    "tool_call_id": tool_call_id,
                    "outputs": {"response": response}
                })
                return response

        print(run.status)
        run = openai.beta.threads.runs.retrieve(
            thread_id=thread.id,
            run_id=run.id
        )
        if run.status =="succeeded":
#Actual code never enter here
            messages = openai.beta.threads.messages.list(
                thread_id=thread.id
            )
            return messages
        elif run.status == "cancelled" or run.status == "failed":
            raise "thread cancelled"
        elif run.status == "in_progress":
            #wait for next iteration
            import time
            time.sleep(5)
    return None

```

and i call response = myFunction to use it.

---

<div class="post-metadata">

**Author:** ![geteff](https://sea2.discourse-cdn.com/openai1/user_avatar/community.openai.com/geteff/32/229071_2.png) [@geteff](https://community.openai.com/u/geteff)\
**Post date:** [November 17, 2023, 12:02pm UTC](https://community.openai.com/t/i-need-help-using-assitant-in-python-required-action-infinite-loop/486969/6 "2023-11-17T12:02:18Z")

</div>

This is great! Thanks! I have been working on it with similar thoughts.

---

<div class="post-metadata">

**Author:** ![nayan96](https://sea2.discourse-cdn.com/openai1/user_avatar/community.openai.com/nayan96/32/243469_2.png) [@nayan96](https://community.openai.com/u/nayan96)\
**Post date:** [November 17, 2023, 6:24pm UTC](https://community.openai.com/t/i-need-help-using-assitant-in-python-required-action-infinite-loop/486969/7 "2023-11-17T18:24:32Z")

</div>

```auto
> if run.status =="succeeded":
> #Actual code never enter here

```

“Succeeded” is not a valid state. When it is successful you will have receive “completed” state. One way to manage this is do while(true) and inside handle all the possible states for the “run.status”.

Using switch case will make it simpler to read.

Make sure to break for default case, your code will be stuck in infinite loop if you fail to handle any case or if API is updated to return any state not mentioned in documents.

---

<div class="post-metadata">

**Author:** ![jlvanhulst](https://sea2.discourse-cdn.com/openai1/user_avatar/community.openai.com/jlvanhulst/32/195305_2.png) [@jlvanhulst](https://community.openai.com/u/jlvanhulst)\
**Post date:** [November 17, 2023, 10:35pm UTC](https://community.openai.com/t/i-need-help-using-assitant-in-python-required-action-infinite-loop/486969/8 "2023-11-17T22:35:15Z")

</div>

Here’s my take it on it - that can handle all kinds of functions easily.

> **[Playing with the new OpenAI Assistant and function calling in Python](https://medium.com/@jl_28165/playing-with-the-new-openai-assistant-and-function-calling-in-python-2a4ddf27a208)**
>
> I just updated our VicBot AI Assistant to support the new Assistant Structure that OpenAI released in Beta last week. I love it!

---

<div class="post-metadata">

**Author:** ![inachomsky](https://sea2.discourse-cdn.com/openai1/user_avatar/community.openai.com/inachomsky/32/236428_2.png) [@inachomsky](https://community.openai.com/u/inachomsky)\
**Post date:** [November 18, 2023, 4:22am UTC](https://community.openai.com/t/i-need-help-using-assitant-in-python-required-action-infinite-loop/486969/9 "2023-11-18T04:22:32Z")

</div>

I did a litte refactor, could be helpfully for somebody:

```auto

def handle_requires_action(run, thread):
    #this is uggly for me but i didnt understand very well how get the function_call, and why is needed do it from the messages, but works for now and i dont want lost time and credits in more attempts
    tool_call_id = None
    try:
        for message in run.messages:
            if "tool_call_id" in message.content:
                tool_call_id = message.content.split("tool_call_id: ")[1].split()[0]
                print(tool_call_id)
                break

        if tool_call_id:
            print(tool_call_id)
            #this call the function of the assistent in the active threat with "action_required" and move their status to "in_progress"
            run = openai.beta.threads.runs.submit_tool_outputs(
                thread_id=thread.id,
                run_id=run.id,
                tool_outputs=[
                    {
                        "tool_call_id": tool_call_id
                    }
                ]
            )
    except Exception as e:
        print(e)

def handle_succeeded(run, thread):
#never called in my case
    messages = openai.beta.threads.messages.list(
        thread_id=thread.id
    )
    #print(run)
    #print(messages)
    return messages

def handle_cancelled_or_failed(run, thread):
    raise "thread cancelled"

def handle_in_progress(run, thread):
    time.sleep(5)

def get_json_from_article_new(article): 
    openai.api_key = openaikey
    thread = openai.beta.threads.create()
    openai.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="describe action, not sure if this is really required"
    )

    run = openai.beta.threads.runs.create(
            thread_id=thread.id,
            assistant_id="Assistant id")
    tool_outputs = []

    status_handlers = {
        "requires_action": handle_requires_action,
        "succeeded": handle_succeeded,
        "cancelled": handle_cancelled_or_failed,
        "failed": handle_cancelled_or_failed,
        "expired": handle_cancelled_or_failed,
        "in_progress": handle_in_progress,
        "queued": handle_in_progress
    }

    while run.status != 'completed':
        run = openai.beta.threads.runs.retrieve(thread_id=thread.id, run_id=run.id)
        print(run.status)

        if run.required_action and run.required_action.submit_tool_outputs and run.required_action.submit_tool_outputs.tool_calls:
            #Here i recovery the response that i need, and the function ends.
            #Enter when the "in_progress" finish and go back to the state required_action but in the messages comes the response.
            for tool_call in run.required_action.submit_tool_outputs.tool_calls:
                tool_call_id = tool_call.id
                arguments = json.loads(tool_call.function.arguments)
                response = arguments
                tool_outputs.append({
                    "tool_call_id": tool_call_id,
                    "outputs": {"response": response}
                })
                #return the result
                return response

        elif run.status in status_handlers:
            status_handlers[run.status](run, thread)
        else:
            print(f"Unhandled status: {run.status}")
            raise Exception("Unhandled status")
            break
    return None

```

---

<div class="post-metadata">

**Author:** ![jaytomsheek](https://avatars.discourse-cdn.com/v4/letter/j/90ced4/32.png) [@jaytomsheek](https://community.openai.com/u/jaytomsheek)\
**Post date:** [November 22, 2023, 12:15pm UTC](https://community.openai.com/t/i-need-help-using-assitant-in-python-required-action-infinite-loop/486969/10 "2023-11-22T12:15:22Z")

</div>

@inachomsky thank you for starting this thread.

I use JS and struggled to get the tool call id as well, and I found a possible solution. As @jlvanhulst pointed oput in his blog, “tool\_calls is a list!” I decided not to implemet his solution because 1. its in python and I use JS, 2. I am only calling one function anyway, so it is a bit overkill for me.

Anyway, tool\_calls is a list, so I just need the ID of the first item, so for me in JS language as follows:

```auto
const retrieveRun = await openai.beta.threads.runs.retrieve(
    threadId,
    runId
  );

const toolCalls = retrieveRun.required_action.submit_tool_outputs.tool_calls;

const run = await openai.beta.threads.runs.submitToolOutputs(
        threadId,
        runId,
        {
          tool_outputs: [
            {
              tool_call_id: toolCalls[0].id,
              output: "true",
            },
          ],
        }
        );

```

Why the output is true, don’t ask me, it just worked inside the Asssistant Playground.

Let me know if this helped.

---

<div class="post-metadata">

**Author:** ![jlvanhulst](https://sea2.discourse-cdn.com/openai1/user_avatar/community.openai.com/jlvanhulst/32/195305_2.png) [@jlvanhulst](https://community.openai.com/u/jlvanhulst)\
**Post date:** [December 2, 2023, 7:35pm UTC](https://community.openai.com/t/i-need-help-using-assitant-in-python-required-action-infinite-loop/486969/11 "2023-12-02T19:35:13Z")

</div>

I worked on a new version as well - now fully async version running on Django/Celery

> **[Building a scalable OpenAI Assistant Processor in Django with Celery](https://medium.com/@jl_28165/building-a-scalable-openai-assistant-processor-in-django-with-celery-a61a1af722e0)**
>
> Two weeks ago I wrote about my first experiments with the new OpenAI Assistants. At that point I had created a basic implementation inside…

---

<div class="post-metadata">

**Author:** ![TheBreak247](https://avatars.discourse-cdn.com/v4/letter/t/ac91a4/32.png) [@TheBreak247](https://community.openai.com/u/TheBreak247)\
**Post date:** [January 10, 2024, 10:57pm UTC](https://community.openai.com/t/i-need-help-using-assitant-in-python-required-action-infinite-loop/486969/12 "2024-01-10T22:57:58Z")

</div>

Why on earth do they make it so hard to use the assistance API? Seems to me the entire point is to use tools, so why the assistant does not handle passing arguments between the thread and the tools is beyond me. llama library does, but I have found the performance is severely degraded.

---

<div class="post-metadata">

**Author:** ![dorottya.hatscher](https://avatars.discourse-cdn.com/v4/letter/d/ba9def/32.png) [@dorottya.hatscher](https://community.openai.com/u/dorottya.hatscher)\
**Post date:** [January 19, 2024, 1:43pm UTC](https://community.openai.com/t/i-need-help-using-assitant-in-python-required-action-infinite-loop/486969/13 "2024-01-19T13:43:10Z")

</div>

thanks for JS code… I’ve tried it but is says “Cannot read properties of undefined (reading ‘submit\_tool\_outputs’)”

Here’s my node:

```auto

import OpenAI from 'openai';
export default async function retrieveOpenAIRun({
    thread_id,
    run_id,
    apiKey
}) {
    const openai = new OpenAI({
    apiKey
    });
  //const run = await openai.beta.threads.runs.retrieve(thread_id, run_id);
    
  const toolCalls = retrieveOpenAIRun.required_action.submit_tool_outputs.tool_calls;
  
  const run = await openai.beta.threads.runs.submitToolOutputs(
        thread_id,
        run_id,
        {
          tool_outputs: [
            {
              tool_call_id: toolCalls[0].id,
              output: "true",
            },
          ],
        }
        );
  
  return run;
}

```

---

<div class="post-metadata">

**Author:** ![avigiova](https://sea2.discourse-cdn.com/openai1/user_avatar/community.openai.com/avigiova/32/511341_2.png) [@avigiova](https://community.openai.com/u/avigiova)\
**Post date:** [January 3, 2025, 10:21am UTC](https://community.openai.com/t/i-need-help-using-assitant-in-python-required-action-infinite-loop/486969/14 "2025-01-03T10:21:29Z")

</div>

I have solved it like this:

````auto
const run = await this.openai.beta.threads.runs.create(thread, {
      assistant_id: assistant.id,
      stream: true,
    });
    for await (const event of run) {
      if (event.event === 'thread.run.requires_action') {
        const action =
          event.data.required_action.submit_tool_outputs.tool_calls[0];
        await this.openai.beta.threads.runs.submitToolOutputs(
          thread,
          event.data.id,
          {
            tool_outputs: [
              {
                tool_call_id: action.id,
                output: 'true',
              },
            ],
          },
        );
      }
    }```
````
