Assistant Function call / run completes but no new message generated in thread

So I have an Assistant I’ve built that uses a function to link the users name and email to a session (session is linked to threads, not important for the question). Once it links that it creates a “user_id” and outputs that the user was saved successfully.

const handleToolCalls = async (toolCalls, sessionId) => {
    const toolOutputs = [];

    for (const call of toolCalls) {
        if (call.function?.name === "save-update-user") {
            const args = JSON.parse(call.function.arguments);
            // Include sessionId when calling saveOrUpdateUserInfo
            const userId = await saveOrUpdateUserInfo({ ...args, sessionId });

            toolOutputs.push({
                tool_call_id: call.id,
                output: `User ${userId} saved/updated`
            });
        }
        // Handle other function calls as needed
    }

    return toolOutputs;
};

Once that happens it gets submitted to the run and then when I get the complete status I look at the messages in the thread.

const run = await openai.beta.threads.runs.create(threadId, { assistant_id: config.assistantId });

// Poll for run completion
        let runStatus;
        do {
            await new Promise(resolve => setTimeout(resolve, 2000));
            const updatedRun = await openai.beta.threads.runs.retrieve(threadId, run.id);
            runStatus = updatedRun.status;

            if (runStatus === 'requires_action' && updatedRun.required_action?.type === "submit_tool_outputs") {
                const toolOutputs = await handleToolCalls(updatedRun.required_action.submit_tool_outputs.tool_calls, sessionId);
            
                // Submit tool outputs to complete the run
                await openai.beta.threads.runs.submitToolOutputs(threadId, run.id, { tool_outputs: toolOutputs });
            }
        } while (runStatus !== 'completed' && runStatus !== 'requires_action');

        const threadMessages = await openai.beta.threads.messages.list(threadId);

        console.log("Thread Messages: ", threadMessages);

        const sortedMessages = threadMessages.data.sort((a, b) => b.created_at - a.created_at);
        const latestAssistantMessage = sortedMessages.filter(message => message.role === 'assistant')[0];

        // Log assistant's response
        if (latestAssistantMessage && latestAssistantMessage.content) {
            await logChatMessage(sessionId, latestAssistantMessage.content, 'assistant');
        }

        return latestAssistantMessage;

The issue I’m running into is that even after the run is marked as complete, there’s no new assistant message in the thread, it finds the previous one.

Just a hunch, not tried your code yet, but can you edit the output into stringified JSON? like this:

toolOutputs.push({
                tool_call_id: call.id,
                output: JSON.stringify({ status: 'success', message: `User ${userId} saved/updated` })
            });

Same result, unfortunately.

maybe your while condition will also terminate when requires_action is triggered. so you probably did not reach completed. you should continue the run after submitting the tool output.

That did it! Thank you.

In case it helps anyone:

// Poll for run completion
        let runStatus;
        do {
            await new Promise(resolve => setTimeout(resolve, 2000));
            const updatedRun = await openai.beta.threads.runs.retrieve(threadId, run.id);
            runStatus = updatedRun.status;

            if (runStatus === 'requires_action' && updatedRun.required_action?.type === "submit_tool_outputs") {
                const toolOutputs = await handleToolCalls(updatedRun.required_action.submit_tool_outputs.tool_calls, sessionId);
            
                // Submit tool outputs to complete the run
                await openai.beta.threads.runs.submitToolOutputs(threadId, run.id, { tool_outputs: toolOutputs });

                // re-fetch the run status after submitting tool outputs
                const recheckedRun = await openai.beta.threads.runs.retrieve(threadId, run.id);
                runStatus = recheckedRun.status;
            }
        } while (runStatus !== 'completed');