-
Notifications
You must be signed in to change notification settings - Fork 1
feat: implement chat API with agent streaming capabilities #6
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
- Added new API route for chat functionality in r.ts. - Integrated agent streaming response using createAgentStreamResponse. - Implemented error handling for invalid agent IDs and missing messages. - Returned available agents and their count in the GET request.
|
Keep this PR in a mergeable state → Learn moreAll Green is an AI agent that automatically: ✅ Addresses code review comments ✅ Fixes failing CI checks ✅ Resolves merge conflicts |
Reviewer's GuideImplements a new Next.js API route for chat that streams responses from Mastra agents, including validation of agent IDs and messages, and exposes an endpoint to list available agents, along with a minor docstring tweak in the streaming helper. Sequence diagram for POST /api/chat streaming flowsequenceDiagram
actor Client
participant ChatAPI as ChatRoute_POST
participant Mastra as mastra
participant StreamHelper as createAgentStreamResponse
Client->>ChatAPI: POST /api/chat with body (messages, agentId?, threadId?, resourceId?, memory?, maxSteps?)
ChatAPI->>ChatAPI: Parse JSON body into ChatRequestBody
ChatAPI->>Mastra: getAgents()
Mastra-->>ChatAPI: agentsMap
ChatAPI->>ChatAPI: availableAgents = Object.keys(agentsMap)
ChatAPI->>ChatAPI: agentId = body.agentId || availableAgents[0]
alt missing_or_invalid_agentId
ChatAPI-->>Client: 400 JSON { error: Invalid or missing agentId, Available: ... }
else valid_agentId
alt missing_messages
ChatAPI-->>Client: 400 JSON { error: messages required }
else valid_messages
ChatAPI->>StreamHelper: createAgentStreamResponse(mastra, agentId, body.messages, options)
note over StreamHelper: options: { threadId, resourceId, memory, maxSteps (default 50) }
alt stream_success
StreamHelper-->>ChatAPI: streaming Response
ChatAPI-->>Client: 200 streaming Response
else stream_error
StreamHelper-->>ChatAPI: throw Error
ChatAPI-->>Client: 500 JSON { error: error.message or Stream failed }
end
end
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Caution Review failedThe pull request is closed. Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings. WalkthroughThis PR introduces a new chat API route ( Changes
Sequence DiagramsequenceDiagram
participant Client
participant API as POST Handler
participant Mastra as Mastra Utils
participant Stream as Streaming Response
Client->>API: POST /api/chat/r<br/>(messages, agentId?, threadId, etc.)
API->>Mastra: getAgents()
Mastra-->>API: agents[]
alt agentId provided
API->>API: Validate agentId<br/>against agents
else agentId not provided
API->>API: Select default agent
end
alt Validation passes
API->>Stream: createAgentStreamResponse<br/>(agentId, messages, payload)
Stream-->>Client: Streaming response
else Validation fails
API-->>Client: 500 Error
end
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes
Possibly related PRs
Suggested reviewers
Poem
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: ASSERTIVE Plan: Pro 📒 Files selected for processing (2)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
🤖 Hi @ssdeanx, I've received your request, and I'm working on it now! You can track my progress in the logs for more details. |
Summary of ChangesHello @ssdeanx, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a new chat API endpoint designed to facilitate real-time conversational interactions. It integrates agent streaming capabilities, allowing for dynamic and responsive communication. The implementation includes comprehensive error handling to ensure stability and provides a mechanism for discovering available agents, enhancing the flexibility and usability of the chat system. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
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.
Hey there - I've reviewed your changes - here's some feedback:
- The JSDoc comment in client-stream-to-ai-sdk.ts was changed to
API 5stra instance, which looks like a typo and also removed the clarification about using the server-side Mastra instance; consider restoring/correcting that sentence so the intended usage is clear. - The cast
mastra as Parameters<typeof createAgentStreamResponse>[0]in the POST handler suggests a type mismatch; it would be cleaner to align the type signature ofcreateAgentStreamResponsewith the actual mastra instance or introduce a shared interface rather than relying on a loose cast.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The JSDoc comment in client-stream-to-ai-sdk.ts was changed to `API 5stra instance`, which looks like a typo and also removed the clarification about using the server-side Mastra instance; consider restoring/correcting that sentence so the intended usage is clear.
- The cast `mastra as Parameters<typeof createAgentStreamResponse>[0]` in the POST handler suggests a type mismatch; it would be cleaner to align the type signature of `createAgentStreamResponse` with the actual mastra instance or introduce a shared interface rather than relying on a loose cast.
## Individual Comments
### Comment 1
<location> `lib/client-stream-to-ai-sdk.ts:53` </location>
<code_context>
/**
* Creates a streaming Response for Next.js API routes using server-side Mastra agent.
*
- * IMPORTANT: This should be used in API routes with the SERVER-SIDE mastra instance,
+ * IMPORTANT: This should be used in API 5stra instance,
* not the client SDK. The client SDK (MastraClient) is for frontend use only.
*
</code_context>
<issue_to_address>
**nitpick (typo):** The updated docstring introduces a likely typo in the product name.
`API 5stra instance` looks like an accidental typo for `Mastra` and could confuse readers. Please change this back to something like `SERVER-SIDE Mastra instance` or another intentional phrasing.
```suggestion
* IMPORTANT: This should be used in API routes with the server-side Mastra instance,
```
</issue_to_address>
### Comment 2
<location> `app/api/chat/r.ts:28-32` </location>
<code_context>
+ const body: ChatRequestBody = await req.json();
+
+ // Get available agents dynamically from mastra
+ const agentsMap = await mastra.getAgents();
+ const availableAgents = Object.keys(agentsMap);
+
+ // Use first available agent if none specified
+ const agentId = body.agentId || availableAgents[0];
+
+ if (!agentId || !availableAgents.includes(agentId)) {
</code_context>
<issue_to_address>
**issue:** Handling an empty agents list would avoid ambiguous errors when no agents are configured.
When `mastra.getAgents()` returns an empty object, `availableAgents[0]` is `undefined`, so the request fails with a 400 `Invalid or missing agentId` and an empty `Available:` list. Consider explicitly checking `availableAgents.length === 0` and returning a clearer “no agents configured” error (e.g. 503) instead of implying a client error.
</issue_to_address>
### Comment 3
<location> `app/api/chat/r.ts:25` </location>
<code_context>
+}
+
+export async function POST(req: Request) {
+ const body: ChatRequestBody = await req.json();
+
+ // Get available agents dynamically from mastra
</code_context>
<issue_to_address>
**issue:** JSON parsing errors on the request body are not caught and will surface as unhandled errors.
Because `await req.json()` is called before the `try` block, invalid JSON will throw an unhandled error and bypass your structured error handling. Move `req.json()` inside the `try` (or wrap it in its own try/catch) so malformed bodies return a controlled 4xx response instead of an unstructured error.
</issue_to_address>
### Comment 4
<location> `app/api/chat/r.ts:52-57` </location>
<code_context>
+ memory: body.memory,
+ maxSteps: body.maxSteps ?? 50,
+ });
+ } catch (error) {
+ return Response.json(
+ { error: error instanceof Error ? error.message : "Stream failed" },
+ { status: 500 }
+ );
</code_context>
<issue_to_address>
**🚨 suggestion (security):** Returning raw error messages may expose internal implementation details to clients.
Instead of returning `error.message` to the client, consider logging the full error on the server and sending a generic error string in the JSON body, while keeping the 500 status code unchanged.
```suggestion
} catch (error) {
console.error("Error creating agent stream response", error);
return Response.json(
{ error: "Stream failed" },
{ status: 500 }
);
}
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| /** | ||
| * Creates a streaming Response for Next.js API routes using server-side Mastra agent. | ||
| * | ||
| * IMPORTANT: This should be used in API routes with the SERVER-SIDE mastra instance, |
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.
nitpick (typo): The updated docstring introduces a likely typo in the product name.
API 5stra instance looks like an accidental typo for Mastra and could confuse readers. Please change this back to something like SERVER-SIDE Mastra instance or another intentional phrasing.
| * IMPORTANT: This should be used in API routes with the SERVER-SIDE mastra instance, | |
| * IMPORTANT: This should be used in API routes with the server-side Mastra instance, |
| const agentsMap = await mastra.getAgents(); | ||
| const availableAgents = Object.keys(agentsMap); | ||
|
|
||
| // Use first available agent if none specified | ||
| const agentId = body.agentId || availableAgents[0]; |
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.
issue: Handling an empty agents list would avoid ambiguous errors when no agents are configured.
When mastra.getAgents() returns an empty object, availableAgents[0] is undefined, so the request fails with a 400 Invalid or missing agentId and an empty Available: list. Consider explicitly checking availableAgents.length === 0 and returning a clearer “no agents configured” error (e.g. 503) instead of implying a client error.
| } | ||
|
|
||
| export async function POST(req: Request) { | ||
| const body: ChatRequestBody = await req.json(); |
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.
issue: JSON parsing errors on the request body are not caught and will surface as unhandled errors.
Because await req.json() is called before the try block, invalid JSON will throw an unhandled error and bypass your structured error handling. Move req.json() inside the try (or wrap it in its own try/catch) so malformed bodies return a controlled 4xx response instead of an unstructured error.
| } catch (error) { | ||
| return Response.json( | ||
| { error: error instanceof Error ? error.message : "Stream failed" }, | ||
| { status: 500 } | ||
| ); | ||
| } |
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.
🚨 suggestion (security): Returning raw error messages may expose internal implementation details to clients.
Instead of returning error.message to the client, consider logging the full error on the server and sending a generic error string in the JSON body, while keeping the 500 status code unchanged.
| } catch (error) { | |
| return Response.json( | |
| { error: error instanceof Error ? error.message : "Stream failed" }, | |
| { status: 500 } | |
| ); | |
| } | |
| } catch (error) { | |
| console.error("Error creating agent stream response", error); | |
| return Response.json( | |
| { error: "Stream failed" }, | |
| { status: 500 } | |
| ); | |
| } |
|
🤖 I'm sorry @ssdeanx, but I was unable to process your request. Please see the logs for more details. |
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.
Code Review
This pull request introduces a new chat API endpoint with streaming capabilities and an endpoint to list available agents. The implementation is solid, but there are a few areas for improvement. My main feedback concerns error handling in both the POST and GET handlers, which currently don't handle all potential exceptions, leading to possible unhandled promise rejections. I've suggested refactoring them to be more robust. I also noted some minor code duplication that could be refactored for better maintainability and a typo in a comment. Overall, these changes add valuable functionality.
| export async function POST(req: Request) { | ||
| const body: ChatRequestBody = await req.json(); | ||
|
|
||
| // Get available agents dynamically from mastra | ||
| const agentsMap = await mastra.getAgents(); | ||
| const availableAgents = Object.keys(agentsMap); | ||
|
|
||
| // Use first available agent if none specified | ||
| const agentId = body.agentId || availableAgents[0]; | ||
|
|
||
| if (!agentId || !availableAgents.includes(agentId)) { | ||
| return Response.json( | ||
| { error: `Invalid or missing agentId. Available: ${availableAgents.join(", ")}` }, | ||
| { status: 400 } | ||
| ); | ||
| } | ||
|
|
||
| if (!body.messages?.length) { | ||
| return Response.json({ error: "messages required" }, { status: 400 }); | ||
| } | ||
|
|
||
| try { | ||
| return await createAgentStreamResponse(mastra as Parameters<typeof createAgentStreamResponse>[0], agentId, body.messages, { | ||
| threadId: body.threadId, | ||
| resourceId: body.resourceId, | ||
| memory: body.memory, | ||
| maxSteps: body.maxSteps ?? 50, | ||
| }); | ||
| } catch (error) { | ||
| return Response.json( | ||
| { error: error instanceof Error ? error.message : "Stream failed" }, | ||
| { status: 500 } | ||
| ); | ||
| } | ||
| } |
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.
The POST handler has a couple of areas for improvement:
- Error Handling: The current
try...catchblock only wraps the call tocreateAgentStreamResponse. Any errors occurring before that, such as parsing the request body withreq.json()or fetching agents withmastra.getAgents(), will result in unhandled promise rejections. This can lead to non-descriptive 500 errors. It's best practice to wrap the entire function body in atry...catchblock to handle all potential errors gracefully. You can also specifically catchSyntaxErrorto return a 400 for invalid JSON. - Type Assertion: The type assertion
mastra as Parameters<typeof createAgentStreamResponse>[0]on line 46 is redundant. Themastrainstance is already correctly typed, so this assertion adds unnecessary verbosity.
I've provided a suggestion that addresses both points by restructuring the error handling and simplifying the code.
export async function POST(req: Request) {
try {
const body: ChatRequestBody = await req.json();
// Get available agents dynamically from mastra
const agentsMap = await mastra.getAgents();
const availableAgents = Object.keys(agentsMap);
// Use first available agent if none specified
const agentId = body.agentId || availableAgents[0];
if (!agentId || !availableAgents.includes(agentId)) {
return Response.json(
{ error: `Invalid or missing agentId. Available: ${availableAgents.join(", ")}` },
{ status: 400 }
);
}
if (!body.messages?.length) {
return Response.json({ error: "messages required" }, { status: 400 });
}
return await createAgentStreamResponse(mastra, agentId, body.messages, {
threadId: body.threadId,
resourceId: body.resourceId,
memory: body.memory,
maxSteps: body.maxSteps ?? 50,
});
} catch (error) {
if (error instanceof SyntaxError) {
return Response.json({ error: "Invalid request body" }, { status: 400 });
}
return Response.json(
{ error: error instanceof Error ? error.message : "An internal server error occurred" },
{ status: 500 }
);
}
}| export async function GET() { | ||
| const agentsMap = await mastra.getAgents(); | ||
| const availableAgents = Object.keys(agentsMap); | ||
| return Response.json({ agents: availableAgents, count: availableAgents.length }); | ||
| } No newline at end of file |
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.
Similar to the POST handler, the GET handler lacks error handling. If mastra.getAgents() throws an exception, it will result in an unhandled promise rejection and a generic 500 error. It's important to wrap the logic in a try...catch block to handle potential failures gracefully.
export async function GET() {
try {
const agentsMap = await mastra.getAgents();
const availableAgents = Object.keys(agentsMap);
return Response.json({ agents: availableAgents, count: availableAgents.length });
} catch (error) {
return Response.json(
{ error: error instanceof Error ? error.message : "Failed to retrieve agents" },
{ status: 500 }
);
}
}| const agentsMap = await mastra.getAgents(); | ||
| const availableAgents = Object.keys(agentsMap); |
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.
The logic for fetching and processing the list of available agents is duplicated in both the POST (lines 28-29) and GET (lines 61-62) handlers. To improve maintainability and adhere to the DRY (Don't Repeat Yourself) principle, consider extracting this logic into a separate helper function within the module.
| * Creates a streaming Response for Next.js API routes using server-side Mastra agent. | ||
| * | ||
| * IMPORTANT: This should be used in API routes with the SERVER-SIDE mastra instance, | ||
| * IMPORTANT: This should be used in API 5stra instance, |
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.
There appears to be a typo in this comment. The text API 5stra instance seems incorrect and makes the comment's meaning unclear. It looks like part of the original sentence was accidentally deleted and replaced. Restoring it would improve clarity for future developers.
| * IMPORTANT: This should be used in API 5stra instance, | |
| * IMPORTANT: This should be used in API routes with the SERVER-SIDE mastra instance, |
Greptile OverviewGreptile SummaryAdds new chat API route (
Issues Found:
Confidence Score: 3/5
Important Files ChangedFile Analysis
Sequence DiagramsequenceDiagram
participant Client
participant API as /api/chat/r
participant Mastra
participant Agent
participant StreamUtil as createAgentStreamResponse
Client->>API: POST /api/chat/r {messages, agentId?, ...}
API->>Mastra: getAgents()
Mastra-->>API: agentsMap
API->>API: Extract agent IDs
API->>API: Validate agentId or use first available
alt Invalid/Missing agentId
API-->>Client: 400 {error: "Invalid or missing agentId..."}
end
alt Missing messages
API-->>Client: 400 {error: "messages required"}
end
API->>StreamUtil: createAgentStreamResponse(mastra, agentId, messages, options)
StreamUtil->>Mastra: getAgent(agentId)
Mastra-->>StreamUtil: agent
StreamUtil->>Agent: stream(messages, streamOptions)
Agent-->>StreamUtil: stream result
alt Has toUIMessageStreamResponse
StreamUtil->>StreamUtil: stream.toUIMessageStreamResponse()
StreamUtil-->>API: Response (AI SDK format)
else Fallback
StreamUtil->>StreamUtil: Manual transformation with toAISdkFormat
StreamUtil->>StreamUtil: createUIMessageStream + createUIMessageStreamResponse
StreamUtil-->>API: Response (AI SDK format)
end
alt Success
API-->>Client: 200 Stream Response
else Error
API-->>Client: 500 {error: message}
end
Note over Client,Agent: GET /api/chat/r returns available agents
Client->>API: GET /api/chat/r
API->>Mastra: getAgents()
Mastra-->>API: agentsMap
API->>API: Extract agent IDs
API-->>Client: 200 {agents: [...], count: N}
|
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.
2 files reviewed, 2 comments
| * Creates a streaming Response for Next.js API routes using server-side Mastra agent. | ||
| * | ||
| * IMPORTANT: This should be used in API routes with the SERVER-SIDE mastra instance, | ||
| * IMPORTANT: This should be used in API 5stra instance, |
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.
syntax: typo: "5stra" should be "Mastra"
| * IMPORTANT: This should be used in API 5stra instance, | |
| * IMPORTANT: This should be used in API routes with the SERVER-SIDE Mastra instance, |
Prompt To Fix With AI
This is a comment left during a code review.
Path: lib/client-stream-to-ai-sdk.ts
Line: 53:53
Comment:
**syntax:** typo: "5stra" should be "Mastra"
```suggestion
* IMPORTANT: This should be used in API routes with the SERVER-SIDE Mastra instance,
```
How can I resolve this? If you propose a fix, please make it concise.| const availableAgents = Object.keys(agentsMap); | ||
|
|
||
| // Use first available agent if none specified | ||
| const agentId = body.agentId || availableAgents[0]; |
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.
logic: if availableAgents array is empty, availableAgents[0] will be undefined, causing the validation on line 34 to pass incorrectly when no agentId is provided
Prompt To Fix With AI
This is a comment left during a code review.
Path: app/api/chat/r.ts
Line: 32:32
Comment:
**logic:** if `availableAgents` array is empty, `availableAgents[0]` will be `undefined`, causing the validation on line 34 to pass incorrectly when no `agentId` is provided
How can I resolve this? If you propose a fix, please make it concise.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.
Pull request overview
This PR introduces a new chat API endpoint with agent streaming capabilities using Mastra. The implementation provides dynamic agent selection, proper error handling, and a GET endpoint to list available agents. However, there are concerns regarding naming conventions, error message consistency, and potential security/performance improvements.
Key Changes:
- Added new chat API route with streaming support and dynamic agent management
- Fixed documentation typo in the streaming utility function
- Implemented input validation and error handling for the chat endpoint
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| app/api/chat/r.ts | New API route providing POST endpoint for agent streaming chat and GET endpoint for listing agents |
| lib/client-stream-to-ai-sdk.ts | Corrected documentation comment (though introduced a typo in the process) |
| const agentsMap = await mastra.getAgents(); | ||
| const availableAgents = Object.keys(agentsMap); |
Copilot
AI
Dec 5, 2025
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.
The mastra.getAgents() call is executed on every POST request (line 28) and again on every GET request (line 61). If the agents list is static or changes infrequently, consider caching this result to avoid repeated async calls on each request. This could improve response times, especially under high load.
| } | ||
|
|
||
| try { | ||
| return await createAgentStreamResponse(mastra as Parameters<typeof createAgentStreamResponse>[0], agentId, body.messages, { |
Copilot
AI
Dec 5, 2025
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.
The type assertion as Parameters<typeof createAgentStreamResponse>[0] is fragile and suggests a type mismatch between the mastra instance and what createAgentStreamResponse expects. This could indicate:
- The
mastraimport may not have the correct type - There could be runtime type safety issues
Consider either:
- Ensuring
mastrais typed asMastrafrom@mastra/core/mastra - Adding explicit type validation
- Removing the type assertion if the types actually align
This type casting bypasses TypeScript's type checking and could hide potential runtime errors.
| return await createAgentStreamResponse(mastra as Parameters<typeof createAgentStreamResponse>[0], agentId, body.messages, { | |
| return await createAgentStreamResponse(mastra, agentId, body.messages, { |
| }); | ||
| } catch (error) { | ||
| return Response.json( | ||
| { error: error instanceof Error ? error.message : "Stream failed" }, |
Copilot
AI
Dec 5, 2025
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.
The generic error handling exposes internal error messages directly to clients. Consider sanitizing error messages in production to avoid leaking implementation details. For example:
catch (error) {
console.error('Agent stream error:', error);
return Response.json(
{ error: process.env.NODE_ENV === 'production'
? 'Failed to process chat request'
: error instanceof Error ? error.message : "Stream failed"
},
{ status: 500 }
);
}This prevents potential information disclosure while maintaining helpful error messages during development.
| { error: error instanceof Error ? error.message : "Stream failed" }, | |
| { error: process.env.NODE_ENV === 'production' | |
| ? 'Failed to process chat request' | |
| : error instanceof Error ? error.message : "Stream failed" | |
| }, |
| * Creates a streaming Response for Next.js API routes using server-side Mastra agent. | ||
| * | ||
| * IMPORTANT: This should be used in API routes with the SERVER-SIDE mastra instance, | ||
| * IMPORTANT: This should be used in API 5stra instance, |
Copilot
AI
Dec 5, 2025
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.
Typo in documentation comment: "API 5stra instance" should be "API routes with the SERVER-SIDE Mastra instance".
| * IMPORTANT: This should be used in API 5stra instance, | |
| * IMPORTANT: This should be used in API routes with the SERVER-SIDE Mastra instance, |
| import { mastra } from "@/src/mastra"; | ||
| import { createAgentStreamResponse } from "@/lib/client-stream-to-ai-sdk"; | ||
| import type { UIMessage } from "ai"; | ||
|
|
||
| export const maxDuration = 60; | ||
|
|
||
| interface ChatRequestBody { | ||
| messages: UIMessage[]; | ||
| agentId?: string; | ||
| threadId?: string; | ||
| resourceId?: string; | ||
| memory?: { | ||
| thread?: string | { id: string; resourceId?: string }; | ||
| resource?: string; | ||
| options?: { | ||
| lastMessages?: number; | ||
| semanticRecall?: boolean; | ||
| workingMemory?: { enabled?: boolean }; | ||
| }; | ||
| }; | ||
| maxSteps?: number; | ||
| } | ||
|
|
||
| export async function POST(req: Request) { | ||
| const body: ChatRequestBody = await req.json(); | ||
|
|
||
| // Get available agents dynamically from mastra | ||
| const agentsMap = await mastra.getAgents(); | ||
| const availableAgents = Object.keys(agentsMap); | ||
|
|
||
| // Use first available agent if none specified | ||
| const agentId = body.agentId || availableAgents[0]; | ||
|
|
||
| if (!agentId || !availableAgents.includes(agentId)) { | ||
| return Response.json( | ||
| { error: `Invalid or missing agentId. Available: ${availableAgents.join(", ")}` }, | ||
| { status: 400 } | ||
| ); | ||
| } | ||
|
|
||
| if (!body.messages?.length) { | ||
| return Response.json({ error: "messages required" }, { status: 400 }); | ||
| } | ||
|
|
||
| try { | ||
| return await createAgentStreamResponse(mastra as Parameters<typeof createAgentStreamResponse>[0], agentId, body.messages, { | ||
| threadId: body.threadId, | ||
| resourceId: body.resourceId, | ||
| memory: body.memory, | ||
| maxSteps: body.maxSteps ?? 50, | ||
| }); | ||
| } catch (error) { | ||
| return Response.json( | ||
| { error: error instanceof Error ? error.message : "Stream failed" }, | ||
| { status: 500 } | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| export async function GET() { | ||
| const agentsMap = await mastra.getAgents(); | ||
| const availableAgents = Object.keys(agentsMap); | ||
| return Response.json({ agents: availableAgents, count: availableAgents.length }); | ||
| } No newline at end of file |
Copilot
AI
Dec 5, 2025
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.
The file name r.ts is unclear and non-standard for Next.js API routes. According to Next.js conventions, API route files should be named route.ts (for App Router) or use descriptive names. Since app/api/chat/route.ts already exists, consider either:
- Replacing the existing
route.tswith this implementation - Using a more descriptive name like
stream-route.tsor organizing into a subdirectory likeapp/api/chat/stream/route.ts
The current name r.ts is ambiguous and makes the codebase harder to navigate.
| } | ||
|
|
||
| if (!body.messages?.length) { | ||
| return Response.json({ error: "messages required" }, { status: 400 }); |
Copilot
AI
Dec 5, 2025
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.
The error message "messages required" is inconsistent with the more detailed error messages used elsewhere in the file (line 36). Consider using a more descriptive and consistent format: "Missing required field: messages" or "messages array is required and cannot be empty".
| return Response.json({ error: "messages required" }, { status: 400 }); | |
| return Response.json({ error: "Missing required field: messages. The messages array is required and cannot be empty." }, { status: 400 }); |
Summary by Sourcery
Add a new chat API route that streams agent responses and exposes available agents.
New Features:
Enhancements: