Is there a way to gracefully stop the chat?

When I stop the chat and submit a new message, I get errors like this":

‘‘fc_689b494b97b88196beca7f5359fc59bb0e21d6210d7020ab’ of type ‘function_call’ was provided without its required ‘reasoning’ item: ‘rs_689b49479dd48196bd47a3d1ffcadd930e21d6210d7020ab’."

To workaround, we have to use this conditional spaghetti like so, wondering if there a better way to do this.

function pruneProblematicParts(messages: UIMessage): UIMessage {

if (!Array.isArray(messages)) return messages;

const isIncompleteToolInput = (part: unknown): boolean => {

const p = part as { type?: string; state?: string };

if (typeof p?.type !== ‘string’) return false;

const isToolType = p.type === ‘dynamic-tool’ || p.type.startsWith(‘tool-’);

return isToolType && p.state === ‘input-streaming’;

};

const isReasoningPart = (part: unknown): boolean => {

return (part as { type?: string }).type === ‘reasoning’;

};

return messages

.map((*message*) => {

if (message.role !== ‘assistant’) return message;

// Drop incomplete tool input parts and any reasoning parts (reasoning is ephemeral and

// can be orphaned when a stream is stopped mid-flight)

const filteredParts = message.parts

    .filter((*part*, *index*, *arr*) => {

if (isIncompleteToolInput(part)) return false;

// Only drop reasoning parts that are trailing (no following item)

if (isReasoningPart(part)) {

const isLast = index === arr.length - 1;

return !isLast;

      }

return true;

    })

// Strip provider-specific metadata that can create invalid provider item dependencies

    .map((*part*) => {

// eslint-disable-next-line @typescript-eslint*/no-explicit-any*

const p: any = part as any;

if (p && typeof p === ‘object’) {

if (‘callProviderMetadata’ in p) {

// Remove function_call ids linking to missing reasoning items

delete p.callProviderMetadata;

        }

if (‘providerMetadata’ in p) {

// Remove message/item ids to avoid strict item ordering requirements on resend

delete p.providerMetadata;

        }

      }

return p as typeof part;

    });

// If no parts remain, drop the message entirely to avoid empty assistant messages

if (filteredParts.length === 0) {

return { …message, parts: } as UIMessage; // will be filtered out in the next step

  }

return { …message, parts: filteredParts } as UIMessage;

})

.filter((*m*) => !(*m*.role === 'assistant' && *m*.parts.length === 0));

}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.