Skip to content

Commit b78ef9a

Browse files
dcramerclaude
andcommitted
fix(cloudflare): Fix remaining AI SDK 6.x type compatibility issues
Additional fixes for UIMessage type changes in AI SDK 5+/6.x: - Remove `content` property usage (UIMessage always uses `parts` array) - Replace `data` with `metadata` for custom message metadata - Remove `createdAt` property (no longer in UIMessage interface) - Update tool part handling to support AI SDK 6 format where tool type is `tool-${toolName}` with properties directly on the part - Remove legacy content fallback in processMessages Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 22b36d1 commit b78ef9a

4 files changed

Lines changed: 48 additions & 51 deletions

File tree

‎packages/mcp-cloudflare/src/client/components/chat/chat-message.tsx‎

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,13 @@ const ToolPart = memo(function ToolPart({
127127
);
128128
});
129129

130+
// Helper to check if a part is a tool part (type starts with "tool-")
131+
const isToolPart = (part: { type: string }): part is {
132+
type: `tool-${string}`;
133+
} & ChatToolInvocation => {
134+
return part.type.startsWith("tool-") && part.type !== "tool-invocation";
135+
};
136+
130137
// Main component for rendering individual message parts
131138
const MessagePart = memo(function MessagePart({
132139
part,
@@ -137,30 +144,43 @@ const MessagePart = memo(function MessagePart({
137144
messageData,
138145
onSlashCommand,
139146
}: MessagePartProps) {
140-
switch (part.type) {
141-
case "text":
142-
return (
143-
<TextPart
144-
text={part.text}
145-
role={messageRole}
146-
messageId={messageId}
147-
isStreaming={isStreaming}
148-
messageData={messageData}
149-
onSlashCommand={onSlashCommand}
150-
/>
151-
);
152-
case "tool-invocation":
153-
return (
154-
<ToolPart
155-
toolInvocation={part.toolInvocation as ChatToolInvocation}
156-
messageId={messageId}
157-
partIndex={partIndex}
158-
/>
159-
);
160-
default:
161-
// Fallback for unknown part types
162-
return null;
147+
// Handle text parts
148+
if (part.type === "text") {
149+
return (
150+
<TextPart
151+
text={part.text}
152+
role={messageRole}
153+
messageId={messageId}
154+
isStreaming={isStreaming}
155+
messageData={messageData}
156+
onSlashCommand={onSlashCommand}
157+
/>
158+
);
163159
}
160+
161+
// Handle tool parts (AI SDK 6 format: type is "tool-${toolName}")
162+
if (isToolPart(part)) {
163+
// Convert AI SDK 6 tool part to our ChatToolInvocation format
164+
const toolInvocation: ChatToolInvocation = {
165+
toolCallId: part.toolCallId,
166+
toolName: part.type.replace(/^tool-/, ""),
167+
args: (part as any).input ?? {},
168+
state: (part as any).state === "result" ? "result" : "call",
169+
result: (part as any).output
170+
? { content: [{ type: "text", text: String((part as any).output) }] }
171+
: undefined,
172+
};
173+
return (
174+
<ToolPart
175+
toolInvocation={toolInvocation}
176+
messageId={messageId}
177+
partIndex={partIndex}
178+
/>
179+
);
180+
}
181+
182+
// Fallback for unknown part types
183+
return null;
164184
});
165185

166186
// Export the memoized components

‎packages/mcp-cloudflare/src/client/components/chat/chat-messages.tsx‎

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@ import { useAuth } from "../../contexts/auth-context";
1010
// Import UIMessage from our types (re-exported as Message for compatibility)
1111
import type { UIMessage } from "@ai-sdk/react";
1212

13-
// Cache for stable part objects to avoid recreating them
14-
const partCache = new WeakMap<UIMessage, { type: "text"; text: string }>();
15-
1613
function processMessages(
1714
messages: UIMessage[],
1815
isChatLoading: boolean,
@@ -50,25 +47,6 @@ function processMessages(
5047
});
5148
},
5249
);
53-
} else if (message.content) {
54-
// Use cached part object to maintain stable references
55-
let part = partCache.get(message);
56-
if (!part) {
57-
part = { type: "text", text: message.content };
58-
partCache.set(message, part);
59-
}
60-
61-
allParts.push({
62-
part,
63-
messageId: message.id,
64-
messageRole: message.role,
65-
partIndex: 0,
66-
// Stream if it's AI response OR local streaming simulation
67-
isStreaming:
68-
(isLastMessage && isChatLoading) ||
69-
isMessageStreaming?.(message.id) ||
70-
false,
71-
});
7250
}
7351
});
7452

@@ -137,7 +115,7 @@ export function ChatMessages({
137115
const originalMessage = messages.find(
138116
(m) => m.id === item.messageId,
139117
);
140-
const messageData = originalMessage?.data as any;
118+
const messageData = originalMessage?.metadata as any;
141119
const hasToolActions =
142120
messageData?.type === "tools-list" &&
143121
messageData?.toolsDetailed &&
@@ -151,7 +129,7 @@ export function ChatMessages({
151129
messageRole={item.messageRole}
152130
partIndex={item.partIndex}
153131
isStreaming={item.isStreaming}
154-
messageData={originalMessage?.data}
132+
messageData={originalMessage?.metadata}
155133
onSlashCommand={onSlashCommand}
156134
/>
157135
{/* Show tool actions list for tools-list messages */}

‎packages/mcp-cloudflare/src/client/components/chat/chat.tsx‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -256,13 +256,12 @@ Try asking me things like:
256256
id: string,
257257
role: "user" | "assistant" | "system",
258258
text: string,
259-
data?: Record<string, unknown>,
259+
metadata?: Record<string, unknown>,
260260
): UIMessage => ({
261261
id,
262262
role,
263263
parts: [{ type: "text", text }],
264-
createdAt: new Date(),
265-
...(data && { data }),
264+
...(metadata && { metadata }),
266265
}),
267266
[],
268267
);

‎packages/mcp-cloudflare/src/client/hooks/use-persisted-chat.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export function usePersistedChat(isAuthenticated: boolean) {
6969
}
7070

7171
// UIMessage should always have parts, but check for empty
72-
return msg.parts && msg.parts.length > 0;
72+
return Boolean(msg.parts && msg.parts.length > 0);
7373
}, []);
7474

7575
// Load initial messages from localStorage

0 commit comments

Comments
 (0)