-
Notifications
You must be signed in to change notification settings - Fork 619
[AI SDK Provider] Auto handle session ids #7956
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
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: 62565a4 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds provider-level per-chat session tracking and changes ThirdwebProvider.chat to accept an optional chat id. Client and server code remove manual sessionId handling in favor of automatic continuation (useChat sendAutomaticallyWhen + addToolResult); API endpoints now accept Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant UI as Chat UI (useChat)
participant Auto as sendAutomaticallyWhen / addToolResult
participant SDK as thirdwebAI.chat(id)
participant Provider as ThirdwebProvider (SessionStore)
participant Backend as Backend (SSE)
Note over UI,Auto: Automatic continuation via lastAssistantMessageIsCompleteWithToolCalls
UI->>SDK: sendMessage({ text })
SDK->>Provider: instantiate model (chatId = id or generated)
Provider->>Provider: context.session_id = SessionStore.get(chatId)
Provider->>Backend: POST chat (includes session_id)
Backend-->>Provider: SSE init { session_id }
Provider->>Provider: SessionStore.set(chatId, session_id)
Backend-->>Provider: SSE tokens / tool call events
Provider-->>UI: Streamed assistant message / tool call events
alt Tool call required
UI->>Auto: addToolResult(toolResult)
Auto->>SDK: auto-continue with tool result
SDK->>Provider: reuse chatId and context.session_id
Provider->>Backend: POST chat (continues session)
Backend-->>Provider: SSE stream (follow-up)
Provider-->>UI: Streamed assistant continuation
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7956 +/- ##
==========================================
- Coverage 56.53% 56.52% -0.02%
==========================================
Files 904 904
Lines 58623 58623
Branches 4146 4146
==========================================
- Hits 33144 33138 -6
- Misses 25373 25380 +7
+ Partials 106 105 -1
🚀 New features to boost your workflow:
|
size-limit report 📦
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/portal/src/app/ai/chat/ai-sdk/page.mdx (1)
120-171: Close theswitchand map blocks properly.There’s a missing closing brace for the
switch(and consequently the.mapcallback).default: return null; - })} + } + })}Also consider removing the unused
iparam frommap:- {message.parts.map((part, i) => { + {message.parts.map((part) => {
🧹 Nitpick comments (7)
packages/ai-sdk-provider/src/provider.ts (4)
73-79: Consider adding null checks for defensive programming.While the current implementation should work, adding defensive checks would make the code more robust.
Apply this diff for safer session handling:
private getSessionId() { - return this.sessionStore.getSessionId(this.chatId); + return this.sessionStore?.getSessionId(this.chatId) ?? null; } private setSessionId(sessionId: string) { + if (!sessionId || !this.sessionStore) return; this.sessionStore.setSessionId(this.chatId, sessionId); }
81-101: Security consideration for the fallback ID generation.The fallback random ID generation using
Math.random()is not cryptographically secure. While this is likely acceptable for chat IDs, consider documenting this limitation.Consider adding a comment about the security implications:
private generateRandomChatId(): string { // Use crypto.randomUUID if available (modern browsers and Node.js 14.17+) if (typeof crypto !== "undefined" && crypto.randomUUID) { return crypto.randomUUID(); } - // Fallback for older environments - generate a random string + // Fallback for older environments - generate a random string + // Note: This uses Math.random() which is not cryptographically secure + // but is acceptable for chat session IDs const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
579-593: Add JSDoc documentation for the SessionStore class.The SessionStore class is a key component but lacks documentation. Consider adding JSDoc comments to explain its purpose and methods.
+/** + * Manages session IDs for multiple chat conversations. + * Each chat is identified by a unique chatId and can have an associated sessionId. + */ class SessionStore { private sessionId: Map<string, string> = new Map(); + /** + * Retrieves the session ID for a given chat. + * @param chatId - The unique identifier for the chat + * @returns The session ID or null if not found + */ getSessionId(chatId: string) { return this.sessionId.get(chatId) || null; } + /** + * Sets the session ID for a given chat. + * @param chatId - The unique identifier for the chat + * @param sessionId - The session ID to associate with the chat + */ setSessionId(chatId: string, sessionId: string) { this.sessionId.set(chatId, sessionId); } + /** + * Removes the session ID for a given chat. + * @param chatId - The unique identifier for the chat + */ clearSessionId(chatId: string) { this.sessionId.delete(chatId); } }
545-553: Consider adding TypeScript return type annotation.The
chatmethod should have an explicit return type for better type safety.-chat(id?: string, settings: ThirdwebSettings = {}) { +chat(id?: string, settings: ThirdwebSettings = {}): ThirdwebLanguageModel { return new ThirdwebLanguageModel( "t0-latest", settings, this.config, this.session, id, ); }apps/portal/src/app/ai/chat/ai-sdk/page.mdx (3)
41-41: Consider backward compatibility for id/sessionId.If any existing clients still post
sessionId, read both and preferidto avoid breaking older UIs.- const { messages, id } = await req.json(); + const { messages, id, sessionId } = await req.json();And pass the resolved value:
- model: thirdwebAI.chat(id, { + model: thirdwebAI.chat(id ?? sessionId, {
84-87: Nit: wording and robustness.
- Prefer “Vercel AI Elements” (proper case).
- Avoid implying
parts[0]; tool parts can appear in any index—“when a tool part arrives (iterate message.parts) …”.-// Use your own UI or the vercel ai elements UI components -// When a tool part arrives (e.g., message.parts[0].type === "tool-sign_transaction"), +// Use your own UI or the Vercel AI Elements UI components +// When a tool part arrives (iterate message.parts and check part.type === "tool-sign_transaction"),
155-157: Surface tool execution failures to the model (optional).Beyond logging, consider sending an error tool result so the assistant can recover gracefully (e.g., suggest retries or alternatives).
- onError={(error) => { - // in case of error, show error UI or send the error message to the model - console.error(error); - }} + onError={(error) => { + console.error(error); + // Optionally, send an error tool result back to the model to continue the convo + addToolResult({ + tool: "sign_transaction", + toolCallId: part.toolCallId, + output: { error: String(error?.message ?? error) }, + }); + }}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (6)
.changeset/pink-hands-find.md(1 hunks)apps/playground-web/src/app/ai/ai-sdk/components/chat-container.tsx(6 hunks)apps/playground-web/src/app/ai/ai-sdk/page.tsx(2 hunks)apps/playground-web/src/app/api/chat/route.ts(1 hunks)apps/portal/src/app/ai/chat/ai-sdk/page.mdx(5 hunks)packages/ai-sdk-provider/src/provider.ts(8 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
.changeset/*.md
📄 CodeRabbit inference engine (AGENTS.md)
.changeset/*.md: Each change inpackages/*must include a changeset for the appropriate package
Version bump rules: patch for non‑API changes; minor for new/modified public API
Files:
.changeset/pink-hands-find.md
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from@/typeswhere applicable
Prefertypealiases overinterfaceexcept for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size
Files:
apps/playground-web/src/app/ai/ai-sdk/page.tsxapps/playground-web/src/app/api/chat/route.tsapps/playground-web/src/app/ai/ai-sdk/components/chat-container.tsxpackages/ai-sdk-provider/src/provider.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
apps/playground-web/src/app/ai/ai-sdk/page.tsxapps/playground-web/src/app/api/chat/route.tsapps/playground-web/src/app/ai/ai-sdk/components/chat-container.tsxpackages/ai-sdk-provider/src/provider.ts
apps/{dashboard,playground-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
UseNavLinkfor internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()from@/lib/utilsfor conditional class logic
Use design system tokens (e.g.,bg-card,border-border,text-muted-foreground)
Server Components (Node edge): Start files withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader – never embed tokens in URLs
Return typed results (e.g.,Project[],User[]) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysfor React Query cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components
Files:
apps/playground-web/src/app/ai/ai-sdk/page.tsxapps/playground-web/src/app/api/chat/route.tsapps/playground-web/src/app/ai/ai-sdk/components/chat-container.tsx
🧠 Learnings (1)
📚 Learning: 2025-08-28T20:33:35.123Z
Learnt from: joaquim-verges
PR: thirdweb-dev/js#7922
File: packages/ai-sdk-provider/README.md:92-101
Timestamp: 2025-08-28T20:33:35.123Z
Learning: The Vercel AI SDK's DefaultChatTransport uses `body` (not `data`) for the transport payload when calling sendMessage with additional data like sessionId.
Applied to files:
apps/portal/src/app/ai/chat/ai-sdk/page.mdx
🧬 Code graph analysis (1)
packages/ai-sdk-provider/src/provider.ts (1)
packages/ai-sdk-provider/src/types.ts (2)
ThirdwebSettings(31-50)ThirdwebConfig(12-29)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Size
- GitHub Check: Analyze (javascript)
🔇 Additional comments (16)
.changeset/pink-hands-find.md (1)
1-5: LGTM!The changeset correctly documents this as a patch release for the AI SDK provider package, which is appropriate for internal implementation improvements that don't break the public API.
apps/playground-web/src/app/api/chat/route.ts (1)
17-17: LGTM! Clean implementation of the chat method.The simplified API with
thirdwebAI.chat(id)is much cleaner than the previous session context approach.apps/playground-web/src/app/ai/ai-sdk/components/chat-container.tsx (2)
5-8: LGTM! Good use of AI SDK's automatic continuation.Using
lastAssistantMessageIsCompleteWithToolCallsfor automatic message sending is the correct approach for handling tool results automatically.
37-43: Ensure sendAutomaticallyWhen does not trigger unintended messages
No other occurrences ofsendAutomaticallyWhenwere found in the repo; review the logic inlastAssistantMessageIsCompleteWithToolCallsand add tests for edge cases to prevent unexpected automatic sends.packages/ai-sdk-provider/src/provider.ts (3)
29-46: LGTM! Well-structured session management initialization.The session store integration and initial session ID handling are implemented correctly.
258-258: Good use of self reference for async callback context.Using
const self = thisto maintain the correct context in the async stream handler is a good pattern.
397-397: LGTM! Session ID correctly updated from stream.The session ID is properly extracted from the init event and stored via the self reference.
apps/playground-web/src/app/ai/ai-sdk/page.tsx (2)
32-32: LGTM! Documentation link updated correctly.The docs link has been properly updated to point to the AI SDK chat documentation.
114-127: LGTM! Client code example simplified.The removal of session management from the client code example makes it cleaner and easier to understand.
apps/portal/src/app/ai/chat/ai-sdk/page.mdx (7)
44-50: Model invocation looks correct.Passing
idintothirdwebAI.chat(id, ...)aligns with the new provider API.
61-62: Verify the API name for resetting sessions.Please confirm the method is
thirdwebAI.session.clearSessionId()(and not a different name likereset()orclear()), and whether it’s server-only. If the public API differs, update the docs accordingly.
71-73: Confirm helper export name and source.Double-check that
lastAssistantMessageIsCompleteWithToolCallsis the current helper name and exported fromai(not a renamed helper in your installed AI SDK version).
79-81: Good: automatic tool-result continuation.Using
sendAutomaticallyWhenwith the “complete with tool calls” predicate is the right pattern here.
90-94: PassingaddToolResultdown is correct.Stable
key={message.id}is also good.
96-96: Confirm ChatInputBox prop name.Ensure your
ChatInputBoxcomponent expectssend(notonSend/onSubmit).
144-148: Correct use oftoolCallId.Echoing back
toolandtoolCallIdis required for continuation. Looks good.
1933c3f to
2f0b0c6
Compare
2f0b0c6 to
66b6143
Compare
66b6143 to
5006746
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
packages/ai-sdk-provider/src/provider.ts (3)
188-197: Persist session_id for non-streamed calls.Without storing
data.session_id, follow-up calls won’t continue the session. Save it when present.const data = (await response.json()) as { message?: string; request_id?: string; session_id?: string; actions?: unknown[]; }; - // TODO (ai): handle actions + // persist session for subsequent turns + if (data.session_id) { + this.setSessionId(data.session_id); + } + + // TODO (ai): handle actions
470-477: Emit structured tool input (not JSON string).AI SDK tool calls expect structured
input; stringifying breaks downstream consumers (e.g. UI readingpart.input.chain_id).controller.enqueue({ type: "tool-call", toolCallId, toolName, - input: JSON.stringify(input), + input, providerExecuted: false, });
398-401: Userequest_idforresponse-metadata.idand includesession_idunderproviderMetadata.Vercel AI SDK’s
response-metadataonly supportsid,model(ormodelId),timestamp,headers, and a top-levelproviderMetadataobject—there is nometadatafield. Update the enqueue call accordingly:- controller.enqueue({ - type: "response-metadata", - id: parsed.session_id || "", - }); + controller.enqueue({ + type: "response-metadata", + id: parsed.request_id ?? "", + providerMetadata: { + // replace PROVIDER_NAME with your provider’s name constant + [PROVIDER_NAME]: { session_id: parsed.session_id }, + }, + });
♻️ Duplicate comments (2)
apps/portal/src/app/ai/chat/ai-sdk/page.mdx (2)
98-100: Remove stray semicolon after JSX.This breaks compilation:
);;→);.- );; + );
115-121: FixRenderMessageprops typing and destructure.Use
UseChatHelpersfor the prop type and remove undeclaredsendMessage.export function RenderMessage(props: { message: ThirdwebAiMessage; - addToolResult: ReturnType<typeof useChat<ThirdwebAiMessage>>["addToolResult"]; + addToolResult: UseChatHelpers<ThirdwebAiMessage>["addToolResult"]; }) { - const { message, addToolResult, sendMessage } = props; + const { message, addToolResult } = props;Add missing import (outside this hunk):
import type { UseChatHelpers } from "@ai-sdk/react";
🧹 Nitpick comments (4)
packages/ai-sdk-provider/src/provider.ts (4)
73-80: Add explicit return types per TS guidelines.- private getSessionId() { + private getSessionId(): string | null { return this.sessionStore.getSessionId(this.chatId); } - private setSessionId(sessionId: string) { + private setSessionId(sessionId: string): void { this.sessionStore.setSessionId(this.chatId, sessionId); }
81-101: Harden chat id generation and typing.Use
globalThis.crypto?.randomUUID()and a stronger fallback (getRandomValues) to avoid relying onMath.random.- private generateRandomChatId(): string { - // Use crypto.randomUUID if available (modern browsers and Node.js 14.17+) - if (typeof crypto !== "undefined" && crypto.randomUUID) { - return crypto.randomUUID(); - } + private generateRandomChatId(): string { + // Prefer Web Crypto + if (typeof globalThis !== "undefined" && globalThis.crypto?.randomUUID) { + return globalThis.crypto.randomUUID(); + } - // Fallback for older environments - generate a random string - const chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - let result = ""; - - // Generate timestamp prefix for uniqueness - const timestamp = Date.now().toString(36); - - // Add random suffix - for (let i = 0; i < 8; i++) { - result += chars.charAt(Math.floor(Math.random() * chars.length)); - } - - return `chat_${timestamp}_${result}`; + // Fallback: timestamp + random bytes (if available) else Math.random + const timestamp = Date.now().toString(36); + let suffix = ""; + if (globalThis.crypto?.getRandomValues) { + const bytes = new Uint8Array(8); + globalThis.crypto.getRandomValues(bytes); + suffix = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join(""); + } else { + suffix = Math.random().toString(36).slice(2, 10); + } + return `chat_${timestamp}_${suffix}`; }
545-566: Type explicit return types on provider methods.- chat(id?: string, settings: ThirdwebSettings = {}) { + chat(id?: string, settings: ThirdwebSettings = {}): LanguageModelV2 { return new ThirdwebLanguageModel( "t0-latest", settings, this.config, this.session, id, ); } @@ - tools() { + tools(): ReturnType<typeof createTools> { return createTools(this.config); } @@ - languageModel(modelId: string, settings: ThirdwebSettings = {}) { + languageModel(modelId: string, settings: ThirdwebSettings = {}): LanguageModelV2 { return new ThirdwebLanguageModel( modelId, settings, this.config, this.session, ); }
579-593: Type SessionStore methods explicitly.class SessionStore { private sessionId: Map<string, string> = new Map(); - getSessionId(chatId: string) { + getSessionId(chatId: string): string | null { return this.sessionId.get(chatId) || null; } - setSessionId(chatId: string, sessionId: string) { + setSessionId(chatId: string, sessionId: string): void { this.sessionId.set(chatId, sessionId); } - clearSessionId(chatId: string) { + clearSessionId(chatId: string): void { this.sessionId.delete(chatId); } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (6)
.changeset/pink-hands-find.md(1 hunks)apps/playground-web/src/app/ai/ai-sdk/components/chat-container.tsx(6 hunks)apps/playground-web/src/app/ai/ai-sdk/page.tsx(3 hunks)apps/playground-web/src/app/api/chat/route.ts(1 hunks)apps/portal/src/app/ai/chat/ai-sdk/page.mdx(5 hunks)packages/ai-sdk-provider/src/provider.ts(8 hunks)
✅ Files skipped from review due to trivial changes (1)
- .changeset/pink-hands-find.md
🚧 Files skipped from review as they are similar to previous changes (3)
- apps/playground-web/src/app/api/chat/route.ts
- apps/playground-web/src/app/ai/ai-sdk/page.tsx
- apps/playground-web/src/app/ai/ai-sdk/components/chat-container.tsx
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from@/typeswhere applicable
Prefertypealiases overinterfaceexcept for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size
Files:
packages/ai-sdk-provider/src/provider.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
packages/ai-sdk-provider/src/provider.ts
🧠 Learnings (4)
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Write idiomatic TypeScript with explicit function declarations and return types
Applied to files:
apps/portal/src/app/ai/chat/ai-sdk/page.mdx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Comment only ambiguous logic; avoid restating TypeScript in prose
Applied to files:
apps/portal/src/app/ai/chat/ai-sdk/page.mdx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to **/*.{ts,tsx} : Use explicit function declarations and explicit return types in TypeScript
Applied to files:
apps/portal/src/app/ai/chat/ai-sdk/page.mdx
📚 Learning: 2025-08-28T20:33:35.123Z
Learnt from: joaquim-verges
PR: thirdweb-dev/js#7922
File: packages/ai-sdk-provider/README.md:92-101
Timestamp: 2025-08-28T20:33:35.123Z
Learning: The Vercel AI SDK's DefaultChatTransport uses `body` (not `data`) for the transport payload when calling sendMessage with additional data like sessionId.
Applied to files:
apps/portal/src/app/ai/chat/ai-sdk/page.mdx
🧬 Code graph analysis (1)
packages/ai-sdk-provider/src/provider.ts (1)
packages/ai-sdk-provider/src/types.ts (2)
ThirdwebSettings(31-50)ThirdwebConfig(12-29)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: Size
- GitHub Check: Unit Tests
- GitHub Check: Lint Packages
- GitHub Check: Analyze (javascript)
5006746 to
e3a2ae2
Compare
e3a2ae2 to
6e25976
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/ai-sdk-provider/src/provider.ts (1)
191-200: Persist session_id for non-streaming calls.doGenerate ignores the returned session_id, so follow-up turns won’t be linked.
- const data = (await response.json()) as { + const data = (await response.json()) as { message?: string; request_id?: string; session_id?: string; actions?: unknown[]; }; // TODO (ai): handle actions + if (data.session_id) { + this.setSessionId(data.session_id); + }Also applies to: 200-220
♻️ Duplicate comments (1)
packages/ai-sdk-provider/src/provider.ts (1)
582-596: Unbounded SessionStore may grow indefinitely.Re-flagging prior feedback: add TTL/eviction to prevent memory growth under load.
🧹 Nitpick comments (9)
apps/playground-web/src/app/ai/ai-sdk/components/chat-container.tsx (5)
36-43: Add explicit return types for components.Align with repo guidelines for TS/TSX explicit returns.
-export function ChatContainer() { +export function ChatContainer(): JSX.Element { ... -const SignTransactionButton = (props: SignTransactionButtonProps) => { +const SignTransactionButton = (props: SignTransactionButtonProps): JSX.Element => { ... -const SignSwapButton = (props: SignSwapButtonProps) => { +const SignSwapButton = (props: SignSwapButtonProps): JSX.Element => {Also applies to: 156-156, 225-225
99-101: Remove debug log from render path.Avoid noisy console logs in production UIs.
- case "tool-sign_swap": - console.log("---sign_swap", part); + case "tool-sign_swap":
180-183: Replace inline styles with Tailwind.Playground apps should use Tailwind only.
- <TransactionButton - style={{ - width: "100%", - }} + <TransactionButton + className="w-full"(Apply in both buttons.)
Also applies to: 251-254
203-204: Don’t echo raw error messages back into the model.Sanitize to avoid leaking internal details; log locally instead.
- sendMessage({ text: `Transaction failed: ${error.message}` }); + console.error(error); + sendMessage({ text: "Transaction failed. Please try again." });(Apply in both handlers.)
Also applies to: 274-275
36-140: Consider splitting child components into files.This file now hosts three components; extracting SignTransactionButton/SignSwapButton improves single‑responsibility and reusability.
packages/ai-sdk-provider/src/provider.ts (1)
169-174: Avoid sendingsession_id: nullin context.Only include session_id when present to keep payloads clean and avoid ambiguous nulls.
- context: { ...this.settings.context, session_id: this.getSessionId() }, + context: this.getSessionId() + ? { ...this.settings.context, session_id: this.getSessionId()! } + : { ...this.settings.context },(Apply in both doGenerate and doStream.)
Also applies to: 232-236
apps/playground-web/src/app/ai/ai-sdk/page.tsx (3)
25-40: Add explicit return types.Match TS guideline for explicit returns.
-export default function Page() { +export default function Page(): JSX.Element { @@ -function ServerCodeExample() { +function ServerCodeExample(): JSX.Element { @@ -function ChatExample() { +function ChatExample(): JSX.Element {Also applies to: 42-57, 99-136
82-83: Fix grammar in comment.- tools: thirdwebAI.tools(), // optional, to use handle transactions and swaps + tools: thirdwebAI.tools(), // optional, to handle transactions and swaps
109-117: Preferimport typefor types in snippet.Avoids emitting an unused runtime import in TS projects.
-import { ThirdwebAiMessage } from '@thirdweb-dev/ai-sdk-provider'; +import type { ThirdwebAiMessage } from '@thirdweb-dev/ai-sdk-provider';
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (6)
.changeset/pink-hands-find.md(1 hunks)apps/playground-web/src/app/ai/ai-sdk/components/chat-container.tsx(6 hunks)apps/playground-web/src/app/ai/ai-sdk/page.tsx(3 hunks)apps/playground-web/src/app/api/chat/route.ts(1 hunks)apps/portal/src/app/ai/chat/ai-sdk/page.mdx(5 hunks)packages/ai-sdk-provider/src/provider.ts(8 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- .changeset/pink-hands-find.md
- apps/playground-web/src/app/api/chat/route.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from@/typeswhere applicable
Prefertypealiases overinterfaceexcept for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size
Files:
packages/ai-sdk-provider/src/provider.tsapps/playground-web/src/app/ai/ai-sdk/page.tsxapps/playground-web/src/app/ai/ai-sdk/components/chat-container.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
packages/ai-sdk-provider/src/provider.tsapps/playground-web/src/app/ai/ai-sdk/page.tsxapps/playground-web/src/app/ai/ai-sdk/components/chat-container.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
UseNavLinkfor internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()from@/lib/utilsfor conditional class logic
Use design system tokens (e.g.,bg-card,border-border,text-muted-foreground)
Server Components (Node edge): Start files withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader – never embed tokens in URLs
Return typed results (e.g.,Project[],User[]) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysfor React Query cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components
Files:
apps/playground-web/src/app/ai/ai-sdk/page.tsxapps/playground-web/src/app/ai/ai-sdk/components/chat-container.tsx
🧠 Learnings (3)
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Write idiomatic TypeScript with explicit function declarations and return types
Applied to files:
apps/portal/src/app/ai/chat/ai-sdk/page.mdx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Comment only ambiguous logic; avoid restating TypeScript in prose
Applied to files:
apps/portal/src/app/ai/chat/ai-sdk/page.mdx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to **/*.{ts,tsx} : Use explicit function declarations and explicit return types in TypeScript
Applied to files:
apps/portal/src/app/ai/chat/ai-sdk/page.mdx
🧬 Code graph analysis (2)
packages/ai-sdk-provider/src/provider.ts (1)
packages/ai-sdk-provider/src/types.ts (2)
ThirdwebSettings(31-50)ThirdwebConfig(12-29)
apps/playground-web/src/app/ai/ai-sdk/components/chat-container.tsx (1)
packages/ai-sdk-provider/src/types.ts (1)
ThirdwebAiMessage(52-71)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Size
🔇 Additional comments (6)
apps/playground-web/src/app/ai/ai-sdk/components/chat-container.tsx (2)
42-43: Good switch to automatic tool-result continuation.Using sendAutomaticallyWhen with lastAssistantMessageIsCompleteWithToolCalls keeps the flow simple.
151-153: Prop types fix looks good.Using UseChatHelpers for addToolResult/sendMessage is correct and future‑proof.
Also applies to: 221-223, 157-158, 226-227
apps/portal/src/app/ai/chat/ai-sdk/page.mdx (2)
41-45: Server changes LGTM.Reading id from the body and calling thirdwebAI.chat(id, …) matches the new API.
Also applies to: 55-59
70-81: Great: aligned React client to auto tool flow and correct typing.Using lastAssistantMessageIsCompleteWithToolCalls and UseChatHelpers types is correct.
Also applies to: 115-120
packages/ai-sdk-provider/src/provider.ts (1)
81-89: Good robustness on randomUUID detection.The typeof check prevents runtime errors on older environments.
apps/playground-web/src/app/ai/ai-sdk/page.tsx (1)
71-88: Server example update looks correct.Using id and thirdwebAI.chat(id, …) matches provider behavior.
6e25976 to
0e7def9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/portal/src/app/ai/chat/ai-sdk/page.mdx (1)
122-171: Syntax fix: missing closing brace for switch.The
switchblock isn’t closed before ending the callback. Add a}to closeswitch.default: return null; - })} + } + })}packages/ai-sdk-provider/src/provider.ts (1)
473-481: Do not stringify tool inputs (breaks consumer typings).Docs and UI expect
part.inputto be an object. Emitting a string forces consumers to JSON-parse and breaks types.controller.enqueue({ type: "tool-call", toolCallId, toolName, - input: JSON.stringify(input), + input, providerExecuted: false, });
♻️ Duplicate comments (3)
apps/portal/src/app/ai/chat/ai-sdk/page.mdx (1)
115-120: Fixed invalid prop type; now correct.Switch to
UseChatHelpers<ThirdwebAiMessage>["addToolResult"]resolves the earlier TS issue.packages/ai-sdk-provider/src/provider.ts (2)
81-89: Robust UUID check is correct.
typeof crypto !== "undefined" && typeof crypto.randomUUID === "function"avoids runtime errors in older environments.
582-596: SessionStore can leak memory; add TTL-based eviction.Unbounded Map grows indefinitely. Add a TTL and expire on access; cheap, no timers required.
-class SessionStore { - private sessionId: Map<string, string> = new Map(); - - getSessionId(chatId: string) { - return this.sessionId.get(chatId) || null; - } - - setSessionId(chatId: string, sessionId: string) { - this.sessionId.set(chatId, sessionId); - } - - clearSessionId(chatId: string) { - this.sessionId.delete(chatId); - } -} +class SessionStore { + // store value + expiry to bound growth + private sessionId = new Map<string, { value: string; exp: number }>(); + private readonly TTL_MS = 24 * 60 * 60 * 1000; // 24h + + getSessionId(chatId: string) { + const entry = this.sessionId.get(chatId); + if (!entry) return null; + if (entry.exp <= Date.now()) { + this.sessionId.delete(chatId); + return null; + } + return entry.value; + } + + setSessionId(chatId: string, sessionId: string) { + this.sessionId.set(chatId, { value: sessionId, exp: Date.now() + this.TTL_MS }); + } + + clearSessionId(chatId: string) { + this.sessionId.delete(chatId); + } +}
🧹 Nitpick comments (4)
apps/portal/src/app/ai/chat/ai-sdk/page.mdx (1)
61-62: Clarify continuity vs. new chats (serverless nuance).Continuity requires reusing the same
idacross requests; omitting it generates an ephemeral id that may not persist across serverless invocations. Suggested copy update:-Continuous conversations are handled automatically. You can create a new conversation by passing a new `id` to the `thirdwebAI.chat()` function. +To continue a conversation across requests, reuse the same `id` you pass to `thirdwebAI.chat(id, …)`. +To start fresh, pass a new `id`. If you omit `id`, the server may generate an ephemeral one that won’t persist across serverless invocations.packages/ai-sdk-provider/src/provider.ts (3)
230-236: Stream: avoidsession_id: nullin context.Mirror the guarded assignment used in
doGenerate.- const body = { - messages, - stream: true, - context: { ...this.settings.context, session_id: this.getSessionId() }, - }; + const sessionId = this.getSessionId(); + const body = { + messages, + stream: true, + context: { + ...this.settings.context, + ...(sessionId ? { session_id: sessionId } : {}), + }, + };
562-569: Optional: allowlanguageModelto accept anidlikechat.Keeps API consistent for callers that prefer explicit model IDs.
- languageModel(modelId: string, settings: ThirdwebSettings = {}) { - return new ThirdwebLanguageModel( - modelId, - settings, - this.config, - this.session, - ); - } + languageModel(modelId: string, settings: ThirdwebSettings = {}, id?: string) { + return new ThirdwebLanguageModel(modelId, settings, this.config, this.session, id); + }
73-80: Add explicit return types to private helpers.Matches repo TS guidelines and improves API readability.
- private getSessionId() { + private getSessionId(): string | null { return this.sessionStore.getSessionId(this.chatId); } - private setSessionId(sessionId: string) { + private setSessionId(sessionId: string): void { this.sessionStore.setSessionId(this.chatId, sessionId); }Additionally (outside the changed range), consider:
private getHeaders(): Record<string, string>private convertMessages(...): Array<{ role: string; content: string }>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (6)
.changeset/pink-hands-find.md(1 hunks)apps/playground-web/src/app/ai/ai-sdk/components/chat-container.tsx(6 hunks)apps/playground-web/src/app/ai/ai-sdk/page.tsx(3 hunks)apps/playground-web/src/app/api/chat/route.ts(1 hunks)apps/portal/src/app/ai/chat/ai-sdk/page.mdx(5 hunks)packages/ai-sdk-provider/src/provider.ts(8 hunks)
✅ Files skipped from review due to trivial changes (1)
- .changeset/pink-hands-find.md
🚧 Files skipped from review as they are similar to previous changes (3)
- apps/playground-web/src/app/api/chat/route.ts
- apps/playground-web/src/app/ai/ai-sdk/page.tsx
- apps/playground-web/src/app/ai/ai-sdk/components/chat-container.tsx
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from@/typeswhere applicable
Prefertypealiases overinterfaceexcept for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size
Files:
packages/ai-sdk-provider/src/provider.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
packages/ai-sdk-provider/src/provider.ts
🧠 Learnings (3)
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Write idiomatic TypeScript with explicit function declarations and return types
Applied to files:
apps/portal/src/app/ai/chat/ai-sdk/page.mdx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Comment only ambiguous logic; avoid restating TypeScript in prose
Applied to files:
apps/portal/src/app/ai/chat/ai-sdk/page.mdx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to **/*.{ts,tsx} : Use explicit function declarations and explicit return types in TypeScript
Applied to files:
apps/portal/src/app/ai/chat/ai-sdk/page.mdx
🧬 Code graph analysis (1)
packages/ai-sdk-provider/src/provider.ts (1)
packages/ai-sdk-provider/src/types.ts (2)
ThirdwebSettings(31-50)ThirdwebConfig(12-29)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Size
- GitHub Check: Build Packages
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: Unit Tests
- GitHub Check: Lint Packages
- GitHub Check: Analyze (javascript)
🔇 Additional comments (4)
apps/portal/src/app/ai/chat/ai-sdk/page.mdx (4)
41-45: Server: id handling looks correct.Switching to
{ id }and passing it tothirdwebAI.chat(id, …)aligns with the new API.
71-81: Good use of sendAutomaticallyWhen.Importing
DefaultChatTransportandlastAssistantMessageIsCompleteWithToolCallsand wiring them intouseChatis spot on.
90-97: Message rendering props look right.Using
key={message.id}and passingaddToolResultintoRenderMessagematches the provider/tool flow.
144-157: Tool result flow is correct.Using
toolCallId={part.toolCallId}andaddToolResultmatches the AI SDK contract.
0e7def9 to
62565a4
Compare

PR-Codex overview
This PR focuses on enhancing the session management for chat interactions within the
thirdwebAISDK, allowing for automatic handling of session IDs and improving the conversation continuity without manual tracking.Detailed summary
idinstead ofsessionId.SessionStoreclass to manage session IDs.thirdwebAI.chat()to support automatic session management.Summary by CodeRabbit
New Features
Documentation
Chores