-
Notifications
You must be signed in to change notification settings - Fork 305
AI sdk v5 migration #391
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
Merged
Merged
AI sdk v5 migration #391
Changes from 35 commits
Commits
Show all changes
49 commits
Select commit
Hold shift + click to select a range
86aab9a
first draft of v5
whoiskatrin 5b8de15
fixed human in the loop
whoiskatrin f4adfed
Cleanup
whoiskatrin 204378d
another cleanup
whoiskatrin 2a73310
fix build
whoiskatrin 3fc2d36
another fix for formatting
whoiskatrin bed6298
fix dependency conflict
whoiskatrin 4000861
fix dependency conflict
whoiskatrin 6246767
another formatting fix
whoiskatrin 03eacb6
ai react issue fix
whoiskatrin c0d6e13
cleanup
whoiskatrin db1ddc6
Add pkg.pr.new workflow
whoiskatrin 48194ff
improve type safety and stream handling
whoiskatrin 7557c3c
minor fixes
whoiskatrin 862d1ca
fix observability event payload
whoiskatrin 69b9c61
fix biome lint issues
whoiskatrin b5c6777
fix: regenerate clean package-lock.json
whoiskatrin a60c03f
fix lint issues
whoiskatrin 2bc5aa8
fix changes from the main
whoiskatrin e006203
fix workflows
whoiskatrin ea89ac3
try ci again
whoiskatrin cf83355
fix a2a
whoiskatrin 9ec9a6c
update openai agents package
whoiskatrin b8a043d
fix minor issues
whoiskatrin ca376cb
add migration guide, changeset, small fixes for types
whoiskatrin 255d334
updated guide, added utils for migration, fixed types
whoiskatrin b06d9de
update packages
whoiskatrin 72df075
fix persistance and mcp tool calling
whoiskatrin ff9084e
migration cleanup
whoiskatrin ab31d57
fixed SSE raw output
whoiskatrin 20f858e
fix SSE output
whoiskatrin 1e5a792
fix streaming
whoiskatrin 1bfb39e
fix SSE format
whoiskatrin 6084d4a
fix for the chat format
whoiskatrin 30cbea2
fix for ReadableStreamDefaultController enqueue
whoiskatrin 7629f90
fix streaming
whoiskatrin fb6796d
fixes tool calls returning as raw SSE, streaming UI updates, and save…
whoiskatrin 5e272c8
fix data.error
whoiskatrin ec0ca29
fix for persistance and migration updates
whoiskatrin 0dfcc49
implement automatic tool resolution with human confirmation detection
whoiskatrin b94acf7
add automatic tool resolution and improve streaming response handling
whoiskatrin 066622c
persist complete assistant response after streaming finishes
whoiskatrin e09e8f2
fix: update text-delta property name from textDelta to delta in chat …
whoiskatrin 58459f0
allow custom message types
deathbyknowledge 8bdb1da
handle v5 sse errors
deathbyknowledge b90b33f
track and persist tool call states in chat messages
whoiskatrin 9501be1
types and docs amends
deathbyknowledge af697d9
add serverExecuted flag to skip confirmation UI for server-side tools
whoiskatrin 8527613
replace serverExecuted for toolsRequiringConfirmation
deathbyknowledge File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "agents": minor | ||
| --- | ||
|
|
||
| update to ai sdk v5 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,287 @@ | ||
| # Migration Guide: Upgrading to Agents SDK with AI SDK v5 | ||
|
|
||
| This guide helps you migrate your existing code to a new version of our SDK. The Agents SDK now uses AI SDK v5, which introduces several breaking changes and new features. | ||
whoiskatrin marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## Overview of Changes | ||
|
|
||
| ### 1. Message Format Changes | ||
|
|
||
| The most significant change is the message format. AI SDK v5 uses a new `UIMessage` format that replaces the older `Message` format. | ||
|
|
||
| #### Before (AI SDK v4): | ||
whoiskatrin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| ```typescript | ||
| import type { Message } from "ai"; | ||
|
|
||
| // Messages had a simple structure | ||
| const message: Message = { | ||
| id: "123", | ||
| role: "user", | ||
| content: "Hello, assistant!" | ||
| }; | ||
| ``` | ||
|
|
||
| #### After (AI SDK v5): | ||
|
|
||
| ```typescript | ||
| import type { UIMessage } from "ai"; | ||
|
|
||
| // Messages now use a parts-based structure | ||
| const message: UIMessage = { | ||
| id: "123", | ||
| role: "user", | ||
| // New: parts array replaces content property | ||
| parts: [ | ||
| { | ||
| type: "text", | ||
| text: "Hello, assistant!" | ||
| } | ||
| ] | ||
| }; | ||
| ``` | ||
|
|
||
| ### 2. Import Changes | ||
|
|
||
| Update your imports to use the new types and packages: | ||
|
|
||
| #### Before: | ||
|
|
||
| ```typescript | ||
| import type { Message, StreamTextOnFinishCallback } from "ai"; | ||
| import { useChat } from "ai/react"; | ||
| ``` | ||
|
|
||
| #### After: | ||
|
|
||
| ```typescript | ||
| import type { UIMessage as ChatMessage, StreamTextOnFinishCallback } from "ai"; | ||
| import { useChat } from "@ai-sdk/react"; | ||
| ``` | ||
|
|
||
| Note: Some imports moved to scoped packages like `@ai-sdk/react`, `@ai-sdk/ui-utils`, etc. | ||
|
|
||
| ### 3. AIChatAgent Changes | ||
|
|
||
| If you're extending `AIChatAgent`, the message handling has been updated: | ||
|
|
||
| #### Before: | ||
|
|
||
| ```typescript | ||
| class MyAgent extends AIChatAgent<Env> { | ||
| async onChatMessage( | ||
| onFinish: StreamTextOnFinishCallback<ToolSet>, | ||
| options?: { abortSignal: AbortSignal | undefined } | ||
| ): Promise<Response | undefined> { | ||
| // Your implementation | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| #### After: | ||
|
|
||
| ```typescript | ||
| class MyAgent extends AIChatAgent<Env> { | ||
| async onChatMessage( | ||
| onFinish: StreamTextOnFinishCallback<ToolSet>, | ||
| options?: { abortSignal: AbortSignal | undefined } | ||
| ): Promise<Response | undefined> { | ||
| // Same signature, but internally handles UIMessage format | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### 4. Tool Definitions | ||
|
|
||
| Tool definitions now use `inputSchema` instead of `parameters`: | ||
|
|
||
| #### Before: | ||
|
|
||
| ```typescript | ||
| const tools = { | ||
| weather: { | ||
| description: "Get weather information", | ||
| parameters: z.object({ | ||
| city: z.string() | ||
| }), | ||
| execute: async (args) => { | ||
| // Implementation | ||
| } | ||
| } | ||
| }; | ||
| ``` | ||
|
|
||
| #### After: | ||
|
|
||
| ```typescript | ||
| const tools = { | ||
| weather: { | ||
| description: "Get weather information", | ||
| inputSchema: z.object({ | ||
| // Changed from 'parameters' to 'inputSchema' | ||
| city: z.string() | ||
| }), | ||
| execute: async (args) => { | ||
| // Implementation | ||
| } | ||
| } | ||
| }; | ||
| ``` | ||
|
|
||
| ### 5. Streaming Response Changes | ||
|
|
||
| AI SDK v5 introduces a new streaming pattern with start/delta/end events: | ||
|
|
||
| #### Before (v4): | ||
|
|
||
| ```typescript | ||
| for await (const chunk of result.fullStream) { | ||
| if (chunk.type === "text-delta") { | ||
| process.stdout.write(chunk.textDelta); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| #### After (v5): | ||
|
|
||
| ```typescript | ||
| for await (const chunk of result.fullStream) { | ||
| switch (chunk.type) { | ||
| case "text-start": | ||
| // New: Called when text generation starts | ||
| break; | ||
| case "text-delta": | ||
| process.stdout.write(chunk.delta); // Note: 'delta' not 'textDelta' | ||
| break; | ||
| case "text-end": | ||
| // New: Called when text generation completes | ||
| break; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### 6. Message Persistence and Migration | ||
|
|
||
| The SDK automatically detects legacy message formats but **does NOT automatically rewrite your stored messages**. When old format messages are detected, you'll see a console warning: | ||
|
|
||
| ``` | ||
| 🔄 [AIChatAgent] Detected messages in legacy format (role/content). These will continue to work but consider migrating to the new message format for better compatibility with AI SDK v5 features. | ||
| To migrate: import { migrateMessagesToUIFormat } from '@cloudflare/agents' and call await this.persistMessages(migrateMessagesToUIFormat(this.messages)) | ||
| ``` | ||
|
|
||
| #### Important Notes: | ||
|
|
||
| - **No automatic rewriting**: The SDK reads and works with old format messages but doesn't modify your stored data | ||
| - **Backward compatibility**: Your existing messages will continue to work without migration | ||
| - **Manual migration**: You control when/if to migrate your data | ||
|
|
||
| #### How to migrate stored messages: | ||
|
|
||
| ```typescript | ||
| import { migrateMessagesToUIFormat } from "@cloudflare/agents"; | ||
|
|
||
| class MyAgent extends AIChatAgent<Env> { | ||
| async migrateStoredMessages() { | ||
| // Convert messages to new format | ||
| const migratedMessages = migrateMessagesToUIFormat(this.messages); | ||
|
|
||
| // Persist the migrated messages | ||
| await this.persistMessages(migratedMessages); | ||
|
|
||
| console.log("Messages migrated to UIMessage format"); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Step-by-Step Migration | ||
|
|
||
| ### Step 1: Update Dependencies | ||
|
|
||
| ```bash | ||
| npm update @cloudflare/agents ai | ||
| ``` | ||
|
|
||
| ### Step 2: Update Imports | ||
|
|
||
| Search and replace the following imports in your codebase: | ||
|
|
||
| - `import type { Message } from "ai"` → `import type { UIMessage } from "ai"` | ||
| - If you aliased Message as ChatMessage, you can now use: `import type { UIMessage as ChatMessage } from "ai"` | ||
|
|
||
| ### Step 3: Update Tool Definitions | ||
|
|
||
| Find all tool definitions and rename `parameters` to `inputSchema`: | ||
|
|
||
| ```typescript | ||
| // Find all occurrences of tool definitions | ||
| // Replace 'parameters:' with 'inputSchema:' | ||
| ``` | ||
|
|
||
| ### Step 4: Test Your Application | ||
|
|
||
| 1. Run your type checker: `npm run typecheck` | ||
| 2. Run your tests: `npm test` | ||
| 3. Check the console for any migration warnings about legacy message formats | ||
|
|
||
| ### Step 5: (Optional) Migrate Legacy Messages | ||
|
|
||
| The Agents SDK now provides migration utilities to help convert messages to the new format: | ||
|
|
||
| ```typescript | ||
| import { | ||
| migrateToUIMessage, | ||
| migrateMessagesToUIFormat, | ||
| needsMigration, | ||
| isUIMessage | ||
| } from "@cloudflare/agents"; | ||
|
|
||
| // Check if migration is needed | ||
| if (needsMigration(messages)) { | ||
| console.log("Some messages need migration"); | ||
| } | ||
|
|
||
| // Migrate a single message | ||
| const newMessage = migrateToUIMessage(oldMessage); | ||
|
|
||
| // Migrate an array of messages | ||
| const newMessages = migrateMessagesToUIFormat(oldMessages); | ||
|
|
||
| // Check if a message is already in UIMessage format | ||
| if (isUIMessage(message)) { | ||
| console.log("Message is already in new format"); | ||
| } | ||
| ``` | ||
|
|
||
| Note: The SDK handles this conversion automatically at runtime, so manual migration is usually not necessary. These utilities are provided for cases where you want to explicitly migrate stored messages. | ||
|
|
||
| ## Converting Messages to New Format | ||
|
|
||
| The SDK automatically handles old format messages, but if you want to convert them: | ||
|
|
||
| ### Automatic Conversion (Recommended) | ||
|
|
||
| ```typescript | ||
| import { convertToModelMessages } from "ai"; | ||
|
|
||
| // Converts any message format to model-compatible format | ||
| const modelMessages = convertToModelMessages(messages); | ||
| ``` | ||
|
|
||
| ### Manual Conversion | ||
|
|
||
| Use the migration utilities from Step 5 above. The Agents SDK now provides these utilities for explicit migration when needed. | ||
|
|
||
| ## Additional Changes | ||
|
|
||
| ### Type Renames | ||
|
|
||
| - `CoreMessage` → `ModelMessage` (when working with model-specific messages) | ||
| - Various streaming chunk properties renamed (e.g., `textDelta` → `delta`) | ||
|
|
||
| ## Need Help? | ||
|
|
||
| - Check the [official AI SDK v5 migration guide](https://ai-sdk.dev/docs/migration-guides/migration-guide-5-0) | ||
| - Check the [AI SDK v5 documentation](https://sdk.vercel.ai/docs) | ||
| - Report issues on the [Agents SDK GitHub repository](https://github.com/cloudflare/agents/issues) | ||
| - Join the community discussions for migration tips and best practices | ||
|
|
||
| Your existing code will continue to work with minimal changes, and the SDK provides backward compatibility for legacy message formats. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,24 +1,15 @@ | ||
| import { AIChatAgent } from "agents/ai-chat-agent"; | ||
| import type { StreamTextOnFinishCallback } from "ai"; | ||
| import { createDataStreamResponse, streamText } from "ai"; | ||
| import { convertToCoreMessages, streamText } from "ai"; | ||
| import { model } from "../model"; | ||
| import type { Env } from "../server"; | ||
|
|
||
| export class Chat extends AIChatAgent<Env> { | ||
| async onChatMessage(onFinish: StreamTextOnFinishCallback<{}>) { | ||
| const dataStreamResponse = createDataStreamResponse({ | ||
| execute: async (dataStream) => { | ||
| const result = streamText({ | ||
| messages: this.messages, | ||
| model, | ||
|
|
||
| onFinish | ||
| }); | ||
|
|
||
| result.mergeIntoDataStream(dataStream); | ||
| } | ||
| async onChatMessage() { | ||
| const result = await streamText({ | ||
| messages: convertToCoreMessages(this.messages), | ||
| model | ||
| }); | ||
|
|
||
| return dataStreamResponse; | ||
| return result.toTextStreamResponse(); | ||
whoiskatrin marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.