Skip to content

Support AI SDK 5 #93

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 52 commits into
base: main
Choose a base branch
from
Open

Support AI SDK 5 #93

wants to merge 52 commits into from

Conversation

ianmacartney
Copy link
Contributor

Fixes #79


By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Copy link

pkg-pr-new bot commented Jul 29, 2025

Open in StackBlitz

npm i https://pkg.pr.new/get-convex/agent/@convex-dev/agent@93
npm i https://pkg.pr.new/get-convex/agent/@convex-dev/agent-playground@93

commit: 997ca66

@ianmacartney ianmacartney mentioned this pull request Jul 29, 2025
@ethan-huo
Copy link

agent-playground@93 did not compile output dist?

@defrex
Copy link

defrex commented Aug 3, 2025

Been trying this out, and I'm running into an issue where the tool-call and tool-result parts are being split up across multiple messages, which is causing an issue when converting the db data to UIMessages.

This causes toUIMessages to warn: "Tool result without preceding tool call.. adding anyways ".

That warning might be ignorable, but the tool rendering I had working great with ai v5 is now broken as well. It renders an in-progress call, then a complete call with no input data from the next message.

Screenshot 2025-08-03 at 12 34 06 PM
  const { results: messages, isLoading } = useThreadMessages(
    api.agents.queries.listMessages,
    !threadId ? 'skip' : { threadId },
    { initialNumItems: 10, stream: true },
  )

  const uiMessages = useMemo(
    () => toUIMessages(messages) as UIMessage[],
    [messages],
  )
  console.log({ messages, uiMessages })
{
    "messages": [
        {
            "_creationTime": 1754237891580.9077,
            "_id": "ks73axqgdwqm2wjt6b7p05erpd7mzm9c",
            "agentName": "Default Agent",
            "message": {
                "content": "what is northwind?",
                "role": "user"
            },
            "order": 0,
            "status": "success",
            "stepOrder": 0,
            "text": "what is northwind?",
            "threadId": "m570ksgh0n7b880mcwcndaf7j57mzfw5",
            "tool": false,
            "userId": "user_30KIz0FtwR3NYeF1mCbz8xCzBYS",
            "streaming": false
        },
        {
            "_creationTime": 1754237893818.0708,
            "_id": "ks72dxex748mfbbdaamvf1eg517myq17",
            "agentName": "Default Agent",
            "finishReason": "tool-calls",
            "message": {
                "content": [
                    {
                        "text": "Let me get the detailed information about the Northwind database for you.",
                        "type": "text"
                    },
                    {
                        "args": {
                            "dataSourceId": "js77sg17kf8wp6t9m459w9be157meqaj"
                        },
                        "toolCallId": "toolu_01WDyAEZkVRCZF91wb8j15ah",
                        "toolName": "get_data_source_documentation",
                        "type": "tool-call"
                    }
                ],
                "role": "assistant"
            },
            "model": "claude-sonnet-4-20250514",
            "order": 0,
            "provider": "anthropic.messages",
            "providerMetadata": { },
            "reasoningDetails": [],
            "status": "success",
            "stepOrder": 1,
            "text": "Let me get the detailed information about the Northwind database for you.",
            "threadId": "m570ksgh0n7b880mcwcndaf7j57mzfw5",
            "tool": true,
            "usage": { },
            "userId": "user_30KIz0FtwR3NYeF1mCbz8xCzBYS",
            "warnings": [],
            "streaming": false
        },
        {
            "_creationTime": 1754237893818.071,
            "_id": "ks753xrf056md6yj5wjqmd1zjn7mze63",
            "agentName": "Default Agent",
            "message": {
                "content": [
                    {
                        "result": {
                            "type": "json",
                            "value": {
                                "data": {
                                    "description": "[...etc]",
                                    "title": "Northwind",
                                    "type": "postgres"
                                },
                                "success": true
                            }
                        },
                        "toolCallId": "toolu_01WDyAEZkVRCZF91wb8j15ah",
                        "toolName": "get_data_source_documentation",
                        "type": "tool-result"
                    }
                ],
                "role": "tool"
            },
            "order": 0,
            "sources": [],
            "status": "success",
            "stepOrder": 2,
            "threadId": "m570ksgh0n7b880mcwcndaf7j57mzfw5",
            "tool": true,
            "userId": "user_30KIz0FtwR3NYeF1mCbz8xCzBYS",
            "streaming": false
        }
    ],
    "uiMessages": [
        {
            "id": "ks73axqgdwqm2wjt6b7p05erpd7mzm9c",
            "createdAt": "2025-08-03T16:18:11.580Z",
            "order": 0,
            "stepOrder": 0,
            "status": "success",
            "key": "m570ksgh0n7b880mcwcndaf7j57mzfw5-0-0",
            "text": "what is northwind?",
            "role": "user",
            "parts": [
                {
                    "type": "text",
                    "text": "what is northwind?"
                }
            ]
        },
        {
            "id": "ks753xrf056md6yj5wjqmd1zjn7mze63",
            "createdAt": "2025-08-03T16:18:13.818Z",
            "order": 0,
            "stepOrder": 1,
            "status": "success",
            "key": "m570ksgh0n7b880mcwcndaf7j57mzfw5-0-1",
            "text": "Let me get the detailed information about the Northwind database for you.",
            "role": "assistant",
            "agentName": "Default Agent",
            "parts": [
                {
                    "state": "done",
                    "providerMetadata": { },
                    "type": "text",
                    "text": "Let me get the detailed information about the Northwind database for you."
                },
                {
                    "type": "step-start"
                },
                {
                    "type": "tool-call",
                    "input": {
                        "dataSourceId": "js77sg17kf8wp6t9m459w9be157meqaj"
                    },
                    "toolCallId": "toolu_01WDyAEZkVRCZF91wb8j15ah",
                    "toolName": "get_data_source_documentation",
                    "state": "input-available",
                    "callProviderMetadata": { }
                },
                {
                    "type": "tool-get_data_source_documentation",
                    "toolCallId": "toolu_01WDyAEZkVRCZF91wb8j15ah",
                    "state": "output-available",
                    "output": {
                        "type": "json",
                        "value": {
                            "data": {
                                "description": "[...etc]",
                                "documentation": "[...etc]",
                                "title": "Northwind",
                                "type": "postgres"
                            },
                            "success": true
                        }
                    }
                }
            ]
        }
    ]
}

@ianmacartney
Copy link
Contributor Author

@defrex does it work now?

@defrex
Copy link

defrex commented Aug 4, 2025

Hm, not quite. The number of messages seems correct, but I'm getting the same "Tool result without preceding tool call.. adding anyway" warning in console and the tool-call is still split into two parts.

  {
      "type": "tool-call",
      "toolCallId": "toolu_01WDyAEZkVRCZF91wb8j15ah",
      "state": "input-available",
      "input": {
          "dataSourceId": "js77sg17kf8wp6t9m459w9be157meqaj"
      },
      "toolName": "get_data_source_documentation",
  },
  {
      "type": "tool-get_data_source_documentation",
      "toolCallId": "toolu_01WDyAEZkVRCZF91wb8j15ah",
      "state": "output-available",
      "output": {
          "type": "json",
          "value": {
              "data": {
                  "description": "[...etc]",
                  "documentation": "[...etc]",
                  "title": "Northwind",
                  "type": "postgres"
              },
              "success": true
          }
      }
  }

I believe in ai sdk v5 they should be combined into

  {
      "type": "tool-get_data_source_documentation",
      "toolCallId": "toolu_01WDyAEZkVRCZF91wb8j15ah",
      "state": "output-available",
      "input": {
          "dataSourceId": "js77sg17kf8wp6t9m459w9be157meqaj"
      },
      "output": {
          "type": "json",
          "value": {
              "data": {
                  "description": "[...etc]",
                  "documentation": "[...etc]",
                  "title": "Northwind",
                  "type": "postgres"
              },
              "success": true
          }
      }
  },

That is, the tool-call should result in a single part that updates it's state and serves different data at different points.

The type for state is "input-streaming" | "input-available" | "output-available" | "output-error"

@defrex
Copy link

defrex commented Aug 4, 2025

I did some experimenting locally and put up a PR that gets this working: #104

ianmacartney and others added 8 commits August 4, 2025 15:52
Update a single `tool-[toolName]` part in `toUIMessages`
- Updated UIMessage type to accept METADATA, DATA_PARTS, and TOOLS generics
- Made toUIMessages function generic with the same type parameters
- Added proper type annotations for tool parts and message arrays
- Fixed tool UI part type constraints
- Add @ai-sdk/provider-utils to peerDependencies in package.json
- Update src/mapping.ts with related functionality changes
- Generate pnpm-lock.yaml for new dependency
@ethan-huo
Copy link

@ianmacartney I have a PR that replaces the Node API — could you review it? npm isn't responding on my machine, so I can't update the lockfile

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.

Support AI SDK v5
3 participants