Skip to content

Conversation

LJ5O
Copy link
Contributor

@LJ5O LJ5O commented Jun 3, 2025

Hi !
After some extensive debugging, I found the problem causing the error I encountered in #192 and was able to write a possible fix to it.

Description

In

return await streamText({
...chatProvider.chat(model),
maxSteps: 10,
messages,
headers,
tools: [
...await mcp(),
...await debug(),
, we are waiting for a streamText object, an answer from the LLM. This object is generated by the package @xsai/stream-text.

By looking at the code from this package, I can see the following :

const stepOne = async (options: StreamTextOptions): RecursivePromise<void> => {
    const step: StreamTextStep = {
      choices: [],
      finishReason: 'error',
      messages: structuredClone(options.messages),
      stepType: 'initial',
      toolCalls: [],
      toolResults: [],
    }

When instantiating a new streamText, messages are passed to structuredClone() function. Since messages is an object containing vue3 proxies somewhere, it fails ( Proxy object could not be cloned )

The solution I found is to use the function toRaw() provided by vue on every properties of messages using a convenient recursive function I added, toRawObject().
That way, structuredClone() can be used without any trouble.

Linked Issues

Fixes #192

Additional context

I think this is somewhat related to https://stackoverflow.com/questions/71075490/how-to-make-a-structuredclone-of-a-proxy-object

Before the fix :
Capture d’écran du 2025-06-03 14-25-56
After :
Capture d’écran du 2025-06-03 14-28-27

Sorry if my explanations are not very easy to understand, not very used to write PR yet, but I would be happy to discuss further about this PR if that could help !

After several debugging, it was found that streamText initialisation called the structuredClone() function on messages. The problem is that messages is an object containing vue3 proxies, that can not be cloned. My proposed fix is to remove those proxies before passing messages to streamText
Copy link

netlify bot commented Jun 3, 2025

Deploy Preview for airi-docs ready!

Name Link
🔨 Latest commit 36d0c80
🔍 Latest deploy log https://app.netlify.com/projects/airi-docs/deploys/683f249fc2eb1900081a984a
😎 Deploy Preview https://deploy-preview-193--airi-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link

netlify bot commented Jun 3, 2025

Deploy Preview for airi-vtuber ready!

Name Link
🔨 Latest commit 36d0c80
🔍 Latest deploy log https://app.netlify.com/projects/airi-vtuber/deploys/683f249fe335d9000863aefd
😎 Deploy Preview https://deploy-preview-193--airi-vtuber.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@LemonNekoGH
Copy link
Member

🤔 We have already called toRaw in chat store:

const newMessages = messages.value.slice(0, messages.value.length - 1).map((msg) => {
if (msg.role === 'assistant') {
const { slices: _, ...rest } = msg // exclude slices
return toRaw(rest)
}
return toRaw(msg)
})

LJ5O added 2 commits June 3, 2025 18:30
rest.tool_results is also a proxy that was not removed properly
@LJ5O
Copy link
Contributor Author

LJ5O commented Jun 3, 2025

Was it working on your side ? Maybe my setup is in cause 🤔

Well, I tried to run

      const newMessages = messages.value.slice(0, messages.value.length - 1).map((msg) => {
        if (msg.role === 'assistant') {
          const { slices: _, ...rest } = msg // exclude slices
          const a = toRaw(rest)
          return structuredClone(a) // FAILS HERE : Error sending message: DOMException: Proxy object could not be cloned.
        }
        const a = toRaw(msg)
        return structuredClone(a)
      })

Which didn't worked. toRaw() removes the Proxy only on the outer side of a given object, so maybe another one is hidden somewhere.

I played around, displaying the content of rest in the console, and found something interesting : rest.tool_results is also a Proxy, which is not removed by the first toRaw call. We have to call toRaw precisely on this property.

So, we just need to add the following :

        if (msg.role === 'assistant') {
          const { slices: _, ...rest } = msg // exclude slices
          rest.tool_results = toRaw(rest.tool_results) // ADDED FIX
          return toRaw(rest)

I'll also revert what I did previously, this single line is more efficient that looping through the whole object

@nekomeowww
Copy link
Member

Thanks for submitting the issue along with the fixes.

Let me take a look into this. Either toRaw and toValues will do the trick but I kind of unsure about which one fits and suits the best for this scenario.

Copy link
Member

@LemonNekoGH LemonNekoGH left a comment

Choose a reason for hiding this comment

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

LGTM, thanks, I really forgot to call toRaw for tool call results.

@nekomeowww
Copy link
Member

Oh ok.

Copy link
Member

@nekomeowww nekomeowww left a comment

Choose a reason for hiding this comment

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

Thanks.

@nekomeowww nekomeowww merged commit c29392c into moeru-ai:main Jun 4, 2025
11 checks passed
@LJ5O LJ5O deleted the fixProxyCloned branch June 4, 2025 06:44
@nekomeowww nekomeowww mentioned this pull request Jun 8, 2025
44 tasks
Disqort pushed a commit to Disqort/airi that referenced this pull request Aug 29, 2025
* Fix for proxy could not be cloned error

After several debugging, it was found that streamText initialisation called the structuredClone() function on messages. The problem is that messages is an object containing vue3 proxies, that can not be cloned. My proposed fix is to remove those proxies before passing messages to streamText

* Revert "Fix for proxy could not be cloned error"

This reverts commit 1575d30.

* Fix for proxy clone error

rest.tool_results is also a proxy that was not removed properly
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

"Proxy object could not be cloned." when sending more than 1 message
3 participants