-
Notifications
You must be signed in to change notification settings - Fork 1
Seng/chat prototype #279
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
Seng/chat prototype #279
Conversation
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: 3
♻️ Duplicate comments (1)
app/chat/page.tsx (1)
10-17
: Avoid creating empty sessions; early-return on blank inputYou already trim and only persist when non-empty; also guard navigation to skip creating an empty session.
- const handleMessageSend = (message: string) => { - const newSessionId = uuidv4(); - const trimmed = message.trim(); - if (trimmed) { - sessionStorage.setItem(`initialMessage:${newSessionId}`, trimmed); - } - router.push(`/chat/${newSessionId}`); - }; + const handleMessageSend = (message: string) => { + const text = message.trim(); + if (!text) return; + const newSessionId = uuidv4(); + sessionStorage.setItem(`initialMessage:${newSessionId}`, text); + router.push(`/chat/${newSessionId}`); + };To verify the consumer reads and clears the scoped key:
#!/bin/bash set -euo pipefail echo "Search for consumer reading/removing initialMessage by sessionId..." fd -t f --strip-cwd-prefix 'page.tsx' app | while read -r f; do echo "---- $f ----" rg -n -C2 -S "sessionStorage\\.(getItem|removeItem)\\(|initialMessage:" "$f" || true done
🧹 Nitpick comments (7)
app/chat/page.tsx (2)
22-33
: Make the recommendations grid responsive and DRYStack on small screens and render from data to reduce duplication.
- <div className="grid grid-cols-2 gap-4 mb-8"> - <RecommendationCard - title="List all tutorials" - subtitle="available in Agentuity." - onClick={() => handleMessageSend("List all tutorials available in Agentuity")} - /> - <RecommendationCard - title="How do I do agent handoff" - subtitle="in the Python SDK?" - onClick={() => handleMessageSend("How do I do agent handoff in the Python SDK?")} - /> - </div> + <div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mb-8"> + {recommendations.map((r) => ( + <RecommendationCard + key={r.title} + title={r.title} + subtitle={r.subtitle} + onClick={() => handleMessageSend(r.message)} + /> + ))} + </div>Add near the top of ChatPage:
const recommendations = [ { title: 'List all tutorials', subtitle: 'available in Agentuity.', message: 'List all tutorials available in Agentuity' }, { title: 'How do I do agent handoff', subtitle: 'in the Python SDK?', message: 'How do I do agent handoff in the Python SDK?' } ] as const;
49-55
: Add type="button" and focus-visible styles for a11yPrevents unintended form submits and improves keyboard focus.
- <button - onClick={onClick} - className="flex flex-col items-start p-3 rounded-lg text-left transition-all duration-200 hover:scale-[1.02] border" - > + <button + type="button" + onClick={onClick} + className="flex flex-col items-start p-3 rounded-lg text-left transition-all duration-200 hover:scale-[1.02] border + focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/40" + >app/chat/[sessionId]/page.tsx (5)
171-171
: Typo in class name: likely meant agentuity‑scrollbar.Fixes inconsistent scrollbar class.
- <div className="flex-1 flex flex-col min-w-0 h-full overflow-hidden overflow-y-auto uity-scrollbar relative"> + <div className="flex-1 flex flex-col min-w-0 h-full overflow-hidden overflow-y-auto agentuity-scrollbar relative">
177-180
: Add explicit type to button (a11y + behavior).Prevents unintended form submission if nested in a form.
- <button + <button + type="button" onClick={() => revalidateSessions?.()} className="px-2 py-0.5 text-xs rounded bg-red-500/30 hover:bg-red-500/40 border border-red-500/50" >
196-196
: Pass setEditorOpen directly (simpler and typed).Avoids wrapping and preserves the boolean argument.
- setEditorOpen={() => { setEditorOpen(true) }} + setEditorOpen={setEditorOpen}
141-149
: Remove unnecessary type assertions.sessionId is already string via useParams generic.
- const temporarySession: Session = { - sessionId: sessionId as string, + const temporarySession: Session = { + sessionId: sessionId, @@ - sessionService.createSession({ - sessionId: sessionId as string, + sessionService.createSession({ + sessionId: sessionId,
203-207
: Avoid array index as key (minor).Use stable keys for better reconciliation (even for skeletons).
Apply this diff and add the constant once (outside the component):
- {Array.from({ length: 5 }).map((_, i) => ( - <div key={i} className="space-y-2"> + {SKELETON_KEYS.map((k) => ( + <div key={k} className="space-y-2"> <Skeleton className="h-4 w-2/3" /> <Skeleton className="h-3 w-1/2" /> </div> ))}Add near the top-level (outside the component):
const SKELETON_KEYS = ['s1','s2','s3','s4','s5'] as const;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
app/chat/[sessionId]/page.tsx
(1 hunks)app/chat/page.tsx
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
app/chat/[sessionId]/page.tsx (6)
app/chat/types.ts (2)
Session
(54-54)Message
(37-37)app/chat/SessionContext.tsx (1)
useSessions
(14-20)app/chat/services/sessionService.ts (1)
sessionService
(296-296)app/chat/components/ChatMessagesArea.tsx (1)
ChatMessagesArea
(15-70)components/ui/skeleton.tsx (1)
Skeleton
(7-14)app/chat/components/CodeEditor.tsx (1)
CodeEditor
(20-135)
app/chat/page.tsx (1)
app/chat/components/ChatInput.tsx (1)
ChatInput
(12-74)
🪛 Biome (2.1.2)
app/chat/[sessionId]/page.tsx
[error] 114-114: This hook does not specify its dependency on handleSendMessage.
This dependency is being used here, but is not specified in the hook dependency list.
Unsafe fix: Add the missing dependency to the list.
(lint/correctness/useExhaustiveDependencies)
[error] 114-114: This hook does not specify its dependency on revalidateSessions.
This dependency is being used here, but is not specified in the hook dependency list.
This dependency is being used here, but is not specified in the hook dependency list.
Unsafe fix: Add the missing dependency to the list.
(lint/correctness/useExhaustiveDependencies)
[error] 114-114: This hook does not specify its dependency on sessions.find.
This dependency is being used here, but is not specified in the hook dependency list.
Unsafe fix: Add the missing dependency to the list.
(lint/correctness/useExhaustiveDependencies)
[error] 177-180: Provide an explicit type prop for the button element.
The default type of a button is submit, which causes the submission of a form when placed inside a form
element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset
(lint/a11y/useButtonType)
[error] 203-203: Avoid using the index of an array as key property in an element.
This is the source of the key value.
The order of the items may change, and this also affects performances and component state.
Check the React documentation.
(lint/suspicious/noArrayIndexKey)
app/chat/page.tsx
[error] 49-52: Provide an explicit type prop for the button element.
The default type of a button is submit, which causes the submission of a form when placed inside a form
element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset
(lint/a11y/useButtonType)
⏰ 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: Workers Builds: docs
🔇 Additional comments (2)
app/chat/[sessionId]/page.tsx (2)
70-80
: Resolved — MessageSchema already includes optional tutorialDataapp/chat/types.ts declares tutorialData: TutorialDataSchema.optional() on MessageSchema (Message = z.infer), so adding tutorialData to messages is type-safe.
217-226
: Incorrect — CodeEditor accepts executingFiles.
app/chat/components/CodeEditor.tsx declaresexecutingFiles: string[]
in CodeEditorProps, so passingexecutingFiles
from app/chat/[sessionId]/page.tsx is valid.Likely an incorrect or invalid review comment.
@@ -0,0 +1,233 @@ | |||
'use client'; | |||
|
|||
import { useEffect, useState } from 'react'; |
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.
🛠️ Refactor suggestion
Fix stale effect deps; add fallback load; clear error on mount.
Prevents stale closures (Biome errors), and avoids a “stuck skeleton” when no session is found and there’s no initialMessage. Also resets prior error state.
Apply this diff:
-import { useEffect, useState } from 'react';
+import { useEffect, useState, useCallback } from 'react';
@@
- const handleSendMessage = async (content: string, sessionId: string) => {
+ const handleSendMessage = useCallback(async (content: string, sessionId: string) => {
if (!content || !sessionId) return;
@@
- }
- };
+ }
+ }, [setSessions]);
@@
- useEffect(() => {
+ useEffect(() => {
+ // reset any previous banner
+ setCreationError(null);
const foundSession = sessions.find(s => s.sessionId === sessionId);
if (foundSession) {
setSession(foundSession);
return;
}
@@
- const initialMessage = sessionStorage.getItem(storageKey);
- if (!initialMessage) {
- return;
- }
+ const initialMessage = sessionStorage.getItem(storageKey);
+ if (!initialMessage) {
+ // no cached seed and not in context — try to refresh the global list
+ revalidateSessions?.();
+ return;
+ }
@@
- }, [sessionId]);
+ }, [sessionId, sessions, revalidateSessions, handleSendMessage]);
Notes:
- If sessionService exposes a getSession(sessionId) call, prefer fetching it here before calling revalidateSessions.
Also applies to: 24-112, 114-164
await sessionService.addMessageToSessionStreaming( | ||
sessionId, | ||
newMessage, | ||
{ | ||
onTextDelta: (textDelta) => { | ||
setSession(prev => { | ||
if (!prev) return prev; | ||
const updatedMessages = prev.messages.map(msg => { | ||
if (msg.id === assistantMessage.id) { | ||
return { | ||
...msg, | ||
content: msg.content + textDelta | ||
}; | ||
} | ||
return msg; | ||
}); | ||
return { ...prev, messages: updatedMessages }; | ||
}); | ||
}, | ||
|
||
onTutorialData: (tutorialData) => { | ||
setSession(prev => { | ||
if (!prev) return prev; | ||
const updatedMessages = prev.messages.map(msg => | ||
msg.id === assistantMessage.id | ||
? { ...msg, tutorialData: tutorialData } | ||
: msg | ||
); | ||
return { ...prev, messages: updatedMessages }; | ||
}); | ||
}, | ||
|
||
onFinish: (finalSession) => { | ||
setSession(finalSession); | ||
setSessions(prev => prev.map(s => s.sessionId === sessionId ? finalSession : s)); | ||
}, | ||
|
||
onError: (error) => { | ||
console.error('Error sending message:', error); | ||
setSession(prev => { | ||
if (!prev) return prev; | ||
const updatedMessages = prev.messages.map(msg => | ||
msg.id === assistantMessage.id | ||
? { ...msg, content: 'Sorry, I encountered an error. Please try again.' } | ||
: msg | ||
); | ||
return { ...prev, messages: updatedMessages }; | ||
}); | ||
} | ||
} | ||
); | ||
|
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.
🛠️ Refactor suggestion
Consider cancelation/cleanup for streaming to avoid setState after unmount.
If the component unmounts mid‑stream, callbacks can attempt state updates.
Pattern to adopt (if sessionService supports AbortSignal or a cancel handle):
+ const inFlight = useRef<AbortController[]>([]);
const handleSendMessage = useCallback(async (content: string, sessionId: string) => {
+ const ac = new AbortController();
+ inFlight.current.push(ac);
try {
await sessionService.addMessageToSessionStreaming(
sessionId,
newMessage,
- {
+ {
+ signal: ac.signal,
onTextDelta: ...
}
);
} finally {
+ inFlight.current = inFlight.current.filter(c => c !== ac);
}
}, [setSessions]);
+
+ useEffect(() => {
+ return () => {
+ inFlight.current.forEach(c => c.abort());
+ inFlight.current = [];
+ };
+ }, []);
If the API doesn’t accept signal, expose and use a cancel function instead.
I can adapt this to your actual sessionService API.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
await sessionService.addMessageToSessionStreaming( | |
sessionId, | |
newMessage, | |
{ | |
onTextDelta: (textDelta) => { | |
setSession(prev => { | |
if (!prev) return prev; | |
const updatedMessages = prev.messages.map(msg => { | |
if (msg.id === assistantMessage.id) { | |
return { | |
...msg, | |
content: msg.content + textDelta | |
}; | |
} | |
return msg; | |
}); | |
return { ...prev, messages: updatedMessages }; | |
}); | |
}, | |
onTutorialData: (tutorialData) => { | |
setSession(prev => { | |
if (!prev) return prev; | |
const updatedMessages = prev.messages.map(msg => | |
msg.id === assistantMessage.id | |
? { ...msg, tutorialData: tutorialData } | |
: msg | |
); | |
return { ...prev, messages: updatedMessages }; | |
}); | |
}, | |
onFinish: (finalSession) => { | |
setSession(finalSession); | |
setSessions(prev => prev.map(s => s.sessionId === sessionId ? finalSession : s)); | |
}, | |
onError: (error) => { | |
console.error('Error sending message:', error); | |
setSession(prev => { | |
if (!prev) return prev; | |
const updatedMessages = prev.messages.map(msg => | |
msg.id === assistantMessage.id | |
? { ...msg, content: 'Sorry, I encountered an error. Please try again.' } | |
: msg | |
); | |
return { ...prev, messages: updatedMessages }; | |
}); | |
} | |
} | |
); | |
const inFlight = useRef<AbortController[]>([]); | |
const handleSendMessage = useCallback(async (content: string, sessionId: string) => { | |
const ac = new AbortController(); | |
inFlight.current.push(ac); | |
try { | |
await sessionService.addMessageToSessionStreaming( | |
sessionId, | |
newMessage, | |
{ | |
signal: ac.signal, | |
onTextDelta: (textDelta) => { | |
setSession(prev => { | |
if (!prev) return prev; | |
const updatedMessages = prev.messages.map(msg => { | |
if (msg.id === assistantMessage.id) { | |
return { | |
...msg, | |
content: msg.content + textDelta | |
}; | |
} | |
return msg; | |
}); | |
return { ...prev, messages: updatedMessages }; | |
}); | |
}, | |
onTutorialData: (tutorialData) => { | |
setSession(prev => { | |
if (!prev) return prev; | |
const updatedMessages = prev.messages.map(msg => | |
msg.id === assistantMessage.id | |
? { ...msg, tutorialData: tutorialData } | |
: msg | |
); | |
return { ...prev, messages: updatedMessages }; | |
}); | |
}, | |
onFinish: (finalSession) => { | |
setSession(finalSession); | |
setSessions(prev => prev.map(s => s.sessionId === sessionId ? finalSession : s)); | |
}, | |
onError: (error) => { | |
console.error('Error sending message:', error); | |
setSession(prev => { | |
if (!prev) return prev; | |
const updatedMessages = prev.messages.map(msg => | |
msg.id === assistantMessage.id | |
? { ...msg, content: 'Sorry, I encountered an error. Please try again.' } | |
: msg | |
); | |
return { ...prev, messages: updatedMessages }; | |
}); | |
} | |
} | |
); | |
} finally { | |
inFlight.current = inFlight.current.filter(c => c !== ac); | |
} | |
}, [setSessions]); | |
useEffect(() => { | |
return () => { | |
inFlight.current.forEach(c => c.abort()); | |
inFlight.current = []; | |
}; | |
}, []); |
🤖 Prompt for AI Agents
In app/chat/[sessionId]/page.tsx around lines 50 to 101, the streaming callbacks
can call setState after the component unmounts; create an AbortController (or
obtain a cancel handle) before calling
sessionService.addMessageToSessionStreaming, pass its signal or cancel handle
into the API if supported, and add a cleanup in the enclosing useEffect to call
controller.abort() (or the cancel function) so streaming callbacks stop;
additionally, inside each callback (onTextDelta, onTutorialData, onFinish,
onError) bail out early if the signal is aborted (or a mounted flag is false) to
avoid calling setState after unmount and ensure the service’s returned cancel
function (if any) is invoked on cleanup.
onFinish: (finalSession) => { | ||
setSession(finalSession); | ||
setSessions(prev => prev.map(s => s.sessionId === sessionId ? finalSession : s)); | ||
}, |
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.
Ensure sessions list updates even if session isn’t present.
Currently map won’t add a new session that isn’t already in the array.
Apply this diff:
- onFinish: (finalSession) => {
- setSession(finalSession);
- setSessions(prev => prev.map(s => s.sessionId === sessionId ? finalSession : s));
- },
+ onFinish: (finalSession) => {
+ setSession(finalSession);
+ setSessions(prev => {
+ const idx = prev.findIndex(s => s.sessionId === sessionId);
+ if (idx === -1) return [...prev, finalSession];
+ const next = prev.slice();
+ next[idx] = finalSession;
+ return next;
+ });
+ },
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
onFinish: (finalSession) => { | |
setSession(finalSession); | |
setSessions(prev => prev.map(s => s.sessionId === sessionId ? finalSession : s)); | |
}, | |
onFinish: (finalSession) => { | |
setSession(finalSession); | |
setSessions(prev => { | |
const idx = prev.findIndex(s => s.sessionId === sessionId); | |
if (idx === -1) return [...prev, finalSession]; | |
const next = prev.slice(); | |
next[idx] = finalSession; | |
return next; | |
}); | |
}, |
🤖 Prompt for AI Agents
In app/chat/[sessionId]/page.tsx around lines 82-85, the onFinish handler only
maps existing sessions so it silently fails to add a session that isn’t present;
change the sessions updater to perform an upsert: use the functional setter to
check if prev contains a session with the same sessionId and if so return
prev.map(...) replacing it, otherwise return a new array that adds finalSession
(e.g., prepend or append) so the sessions list is updated whether or not the
session already exists; keep setSession(finalSession) as-is.
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
♻️ Duplicate comments (3)
package.json (3)
26-26
: Remove unnecessary @types/uuid (uuid v11 includes types).
Leaving it can cause type conflicts in TS projects.Apply:
- "@types/uuid": "^10.0.0",
38-38
: Node-only dependency: ensure node-pty never reaches Edge/client bundles.
Keep usage strictly server-only (dynamic import, server folder) and mark API routes withexport const runtime = 'nodejs'
.
45-45
: Ensure ESM import style for uuid everywhere.
Useimport { v4 as uuidv4 } from "uuid";
and norequire('uuid')
.#!/bin/bash rg -nP "require\\(['\"]uuid['\"]\\)" -g "**/*.{ts,tsx,js,jsx}" -n || true rg -nP "import\\s+uuid\\s+from\\s+['\"]uuid['\"]" -g "**/*.{ts,tsx,js,jsx}" -n || true
🧹 Nitpick comments (2)
package.json (2)
1-22
: Optional: declare supported Node.js engines to reduce CI/Dev drift.
Align with Next 15.x requirement (>=18.18) or your chosen runtime (e.g., 20/22).{ "name": "docs", "version": "1.0.0", "private": true, + "engines": { + "node": ">=18.18.0" + }, "scripts": {Also applies to: 37-41
63-63
: Override format: prefer a caret or pin
Verified package.json .overrides.esbuild == ">=0.25.0" (npm ls shows no esbuild resolved). Use a caret-compatible range or pin to avoid tooling ambiguity.- "esbuild": ">=0.25.0" + "esbuild": "^0.25.0"
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.json
is excluded by!**/package-lock.json
📒 Files selected for processing (1)
package.json
(3 hunks)
⏰ 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: Cursor Bugbot
- GitHub Check: Workers Builds: docs
🔇 Additional comments (1)
package.json (1)
58-58
: LGTM: add ts-node for scripts/tooling.
Matches typical usage for local scripts and TS helpers.
"next": "^15.5.2", | ||
"node-pty": "^1.0.0", | ||
"react": "^19.1.1", | ||
"react-dom": "^19.1.1", | ||
"react-markdown": "^10.1.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.
💡 Verification agent
🧩 Analysis chain
Next 15.5.2 + React 19.1.1: sanity-check peer deps and build.
Run to confirm clean graph/build.
🏁 Script executed:
#!/bin/bash
set -e
npm ls next react react-dom || true
npm run build --silent || true
Length of output: 1000
Build fails — missing 'gray-matter' required by docs script
npm run build errors with MODULE_NOT_FOUND: 'gray-matter' (require stack: scripts/generate-docs-json.js). Add "gray-matter" to package.json (devDependencies) or make the script optional/guarded, then run npm install and re-run the build to confirm Next 15.5.2 + React 19.1.1 build/peer-dep sanity. (Location: scripts/generate-docs-json.js + package.json.)
🤖 Prompt for AI Agents
In package.json around lines 37 to 41 and scripts/generate-docs-json.js, the
build fails because the docs generation script requires the 'gray-matter'
package but it is not declared; add "gray-matter" to package.json (preferably
under devDependencies) with an appropriate version, run npm install (or yarn) to
install it, or alternatively modify scripts/generate-docs-json.js to guard the
require (try/catch or optional import) and make the docs step optional during
build; after making the change, run npm run build to confirm the error is
resolved and Next 15.5.2 + React 19.1.1 build/peer-dep sanity.
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
♻️ Duplicate comments (2)
app/api/sessions/[sessionId]/messages/route.ts (2)
76-80
: Guarantee a timestamp for user messages.If
message.timestamp
is absent, sessions will storeundefined
. Set it to now.Apply this diff:
- // Ensure timestamp is in ISO string format - if (message.timestamp) { - message.timestamp = toISOString(message.timestamp); - } + // Ensure timestamp is set and in ISO string format + if (message.timestamp) { + message.timestamp = toISOString(message.timestamp); + } else { + message.timestamp = getCurrentTimestamp(); + }
254-323
: SSE parsing can drop data across chunk boundaries and ‘finish’ may persist multiple times; rework with buffering + single‑finish gate and concurrency‑safe persist.Current split-by-newline parsing can truncate JSON across chunks;
finish
block can run more than once and uses staleupdatedSession
, overwriting concurrent updates. Buffer SSE lines, gate finish, and re-fetch/merge before persisting.Apply this diff:
- // Process streaming response - let accumulatedContent = ""; - let finalTutorialData: TutorialData | undefined = undefined; - - const transformStream = new TransformStream({ - async transform(chunk, controller) { - // Forward the chunk to the client - controller.enqueue(chunk); - - // Process the chunk to accumulate the full response - const text = new TextDecoder().decode(chunk); - const lines = text.split("\n"); - - for (const line of lines) { - if (line.startsWith("data: ")) { - try { - const data = JSON.parse(line.slice(6)) as StreamingChunk; - - if (data.type === "text-delta" && data.textDelta) { - accumulatedContent += data.textDelta; - } else if (data.type === "tutorial-data" && data.tutorialData) { - finalTutorialData = data.tutorialData; - - // Update user's tutorial progress - await TutorialStateManager.updateTutorialProgress( - userId, - finalTutorialData.tutorialId, - finalTutorialData.currentStep, - finalTutorialData.totalSteps - ); - } else if (data.type === "finish") { - // When the stream is finished, save the assistant message - const assistantMessage: Message = { - id: assistantMessageId, - author: "ASSISTANT", - content: accumulatedContent, - timestamp: getCurrentTimestamp(), - tutorialData: finalTutorialData, - }; - - const finalSession = { - ...updatedSession, - messages: [...updatedSession.messages, assistantMessage], - }; - - await setKVValue(sessionKey, finalSession, { - storeName: config.defaultStoreName, - }); - - // Trigger background title generation if missing - // Do not await to avoid delaying the client stream completion - void generateAndPersistTitle(sessionId, sessionKey, finalSession); - - // Send the final session in the finish event - controller.enqueue( - new TextEncoder().encode( - `data: ${JSON.stringify({ - type: "finish", - session: finalSession, - })}\n\n` - ) - ); - } - } catch (error) { - console.error("Error processing stream chunk:", error); - } - } - } - }, - }); + // Process streaming response + let accumulatedContent = ""; + let finalTutorialData: TutorialData | undefined = undefined; + let finishedSent = false; + const sseDecoder = new TextDecoder(); + let sseBuffer = ""; + + const transformStream = new TransformStream({ + async transform(chunk, controller) { + // Forward original chunk + controller.enqueue(chunk); + + // Buffer-aware SSE parsing + sseBuffer += sseDecoder.decode(chunk, { stream: true }); + const lines = sseBuffer.split("\n"); + sseBuffer = lines.pop() ?? ""; // keep last partial + + for (const line of lines) { + if (!line.startsWith("data: ")) continue; + try { + const data = JSON.parse(line.slice(6)) as StreamingChunk; + + if (data.type === "text-delta" && data.textDelta) { + accumulatedContent += data.textDelta; + } else if (data.type === "tutorial-data" && data.tutorialData) { + finalTutorialData = data.tutorialData; + // Update user's tutorial progress (await is fine; low rate events) + await TutorialStateManager.updateTutorialProgress( + userId, + finalTutorialData.tutorialId, + finalTutorialData.currentStep, + finalTutorialData.totalSteps + ); + } else if (data.type === "finish" && !finishedSent) { + finishedSent = true; + // Build assistant message + const assistantMessage: Message = { + id: assistantMessageId, + author: "ASSISTANT", + content: accumulatedContent, + timestamp: getCurrentTimestamp(), + tutorialData: finalTutorialData, + }; + // Merge with latest before persisting (avoid overwriting concurrent updates) + const latest = await getKVValue<Session>(sessionKey, { storeName: config.defaultStoreName }); + const base = latest.success && latest.data ? latest.data : updatedSession; + const alreadyExists = base.messages.some(m => m.id === assistantMessageId); + const finalSession: Session = alreadyExists + ? base + : { ...base, messages: [...base.messages, assistantMessage] }; + + await setKVValue(sessionKey, finalSession, { storeName: config.defaultStoreName }); + // Background title generation (non-blocking) + void generateAndPersistTitle(sessionId, sessionKey, finalSession); + + // Send the final session in a single finish event + controller.enqueue( + new TextEncoder().encode( + `data: ${JSON.stringify({ type: "finish", session: finalSession })}\n\n` + ) + ); + } + } catch (error) { + console.error("Error processing stream chunk:", error); + } + } + }, + async flush(controller) { + // Process any remaining buffered partial line + if (!sseBuffer) return; + for (const line of sseBuffer.split("\n")) { + if (!line.startsWith("data: ")) continue; + try { + const data = JSON.parse(line.slice(6)) as StreamingChunk; + if (data.type === "text-delta" && data.textDelta) { + accumulatedContent += data.textDelta; + } else if (data.type === "tutorial-data" && data.tutorialData) { + finalTutorialData = data.tutorialData; + } + } catch { + /* ignore */ + } + } + }, + });
🧹 Nitpick comments (4)
app/api/sessions/[sessionId]/messages/route.ts (4)
331-350
: Harden stream error handling: await abort to avoid dangling streams.Await
writer.abort
and guard it to prevent masking the original error.Apply this diff:
- } catch (error) { - console.error('Error in stream processing:', error); - writer.abort(error); - } + } catch (error) { + console.error('Error in stream processing:', error); + try { + await writer.abort(error as any); + } catch (abortErr) { + console.error('Error aborting transform stream:', abortErr); + } + }
27-33
: Fix Next.js route params typing (not a Promise).
params
isn’t a Promise; incorrect typing can confuse tooling.Apply this diff:
-export async function POST( - request: NextRequest, - { params }: { params: Promise<{ sessionId: string }> } -) { +export async function POST( + request: NextRequest, + { params }: { params: { sessionId: string } } +) {
65-67
: Remove unnecessary await onparams
and simplify extraction.Apply this diff:
- const paramsData = await params; - const sessionId = paramsData.sessionId; + const { sessionId } = params;
101-103
: Satisfy linter: avoid template literal without interpolation.Use a plain string with
\n
escapes.Apply this diff:
- const prompt = `Generate a very short session title summarizing the conversation topic.\n\nRequirements:\n- sentence case\n- no emojis\n- <= 60 characters\n- no quotes or markdown\n- output the title only, no extra text`; + const prompt = 'Generate a very short session title summarizing the conversation topic.\n\nRequirements:\n- sentence case\n- no emojis\n- <= 60 characters\n- no quotes or markdown\n- output the title only, no extra text';
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/api/sessions/[sessionId]/messages/route.ts
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
app/api/sessions/[sessionId]/messages/route.ts (5)
lib/validation/middleware.ts (2)
parseAndValidateJSON
(35-61)SessionMessageRequestSchema
(73-76)app/chat/utils/dateUtils.ts (2)
toISOString
(10-16)getCurrentTimestamp
(35-37)lib/kv-store.ts (2)
getKVValue
(47-113)setKVValue
(122-170)lib/env.ts (1)
getAgentPulseConfig
(32-34)lib/tutorial/state-manager.ts (1)
TutorialStateManager
(5-121)
🪛 Biome (2.1.2)
app/api/sessions/[sessionId]/messages/route.ts
[error] 101-103: Do not use template literals if interpolation and special-character handling are not needed.
Safe fix: Replace with string literal
(lint/style/noUnusedTemplateLiteral)
⏰ 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: Cursor Bugbot
- GitHub Check: Workers Builds: docs
🔇 Additional comments (1)
app/api/sessions/[sessionId]/messages/route.ts (1)
74-75
: Enforce server-side author = USER (don’t trust client input)Reject non-USER authors — a client can inject ASSISTANT messages and pollute sessions.
File: app/api/sessions/[sessionId]/messages/route.ts (around lines 74–75)
const { message, processWithAgent } = validation.data; + if (message.author !== "USER") { + return NextResponse.json({ error: "Only USER messages are accepted here" }, { status: 400 }); + }
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.
This PR is being reviewed by Cursor Bugbot
Details
Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
) { | ||
try { | ||
const result = await client.chat.completions.create({ | ||
model: 'gpt-5-mini', |
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.
Bug: Invalid Model Name Causes API Call Failures
The gpt-5-mini
model name is invalid for OpenAI API calls. This model does not exist, which causes agent requests to fail.
Additional Locations (1)
{currentStepData.title} | ||
</h2> | ||
<p className="text-sm text-white/60"> | ||
Step {tutorial.currentStep + 1} of {tutorial.totalSteps} |
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.
Bug: Tutorial Completion Logic Fails Due to Indexing Mismatch
The agent's tutorial completion logic (tutorialState.currentStep > currentTutorial.totalSteps
) has an off-by-one error, as it doesn't correctly identify completion when currentStep
matches totalSteps
. This stems from an inconsistent step indexing approach across the codebase, where some components use 0-indexed steps internally while others expect 1-indexed, leading to potential logic errors.
Additional Locations (2)
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: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
examples/tutorial_hello_world_py/pyproject.toml (1)
1-10
: Add a build-system so users canpip install .
this example.Without a [build-system], packaging/installation via pip may fail (no legacy setup.py here).
Apply this addition at the end of the file:
+[build-system] +requires = ["setuptools>=69", "wheel"] +build-backend = "setuptools.build_meta"
🧹 Nitpick comments (48)
examples/tutorial_hello_world_py/agentuity.yaml (3)
17-35
: Dev server: verify env files, watch path, and port usage.
- Ensure .env and .env.development exist and are not committed or bundled.
- Confirm agentuity_agents/** is the intended watch root.
- Check that PORT collisions are handled during parallel tutorial runs.
36-53
: Deployment: validate server.py path and resource sizing.
- Confirm server.py resolution matches working directory in your deploy target and that uv is available in the runtime.
- Double‑check 250Mi/500m/300Mi are sufficient under expected load; on‑demand mode aligns with tutorial usage.
54-63
: Bundler: confirm ignores and directory layout.
- Ensure bundler ignores (and repo .gitignore) already exclude virtualenvs, build artifacts, and any env files so they’re not packaged.
- Verify agents dir agentuity_agents matches your actual layout.
examples/tutorial_hello_world_py/README.md (4)
6-6
: Add alt text to the deploy button image for accessibility (MD045).The second image tag lacks alt text. Add a short, descriptive alt.
- <img src="https://app.agentuity.com/img/deploy.svg" /> + <img src="https://app.agentuity.com/img/deploy.svg" alt="Deploy to Agentuity" />
72-79
: Specify a language on the fenced code block (MD040).Add a language hint to improve readability and satisfy markdownlint.
-``` +```text ├── agents/ # Agent definitions and implementations ├── .venv/ # Virtual environment (created by UV) ├── pyproject.toml # Project dependencies and metadata ├── server.py # Server entry point └── agentuity.yaml # Agentuity project configuration--- `19-21`: **Use canonical casing “uv” instead of “UV”.** Astral styles the tool name lowercase. Align casing in prerequisites and comments. ```diff -- **UV**: Version 0.5.25 or higher ([Documentation](https://docs.astral.sh/uv/)) +- **uv**: Version 0.5.25 or higher ([Documentation](https://docs.astral.sh/uv/)) -├── .venv/ # Virtual environment (created by UV) +├── .venv/ # Virtual environment (created by uv)
Also applies to: 74-74
44-59
: Include a one-time dependency install step before running in dev mode.Without installing deps,
uv run server.py
may fail in fresh clones. Adduv sync
(or equivalent) to the Getting Started flow.### Development Mode -Run your project in development mode with: +Install dependencies, then run your project in development mode: ```bash +uv sync agentuity devThis will start your project and open a new browser window connecting your agent to the Agentuity Console in DevMode, allowing you to test and debug your agent in real-time.
You can also start your project in development mode without connecting to the Agentuity Console:
uv run server.pyI can open a follow-up PR to apply these edits if you’d like. </blockquote></details> <details> <summary>examples/tutorial_hello_world_py/server.py (5)</summary><blockquote> `1-1`: **Import `autostart` lazily after env checks; wrap startup in `try/except`.** Prevents side effects if the import touches env/state and gives a cleaner failure path. ```diff -from agentuity import autostart +# Defer importing Agentuity until after env validation @@ - autostart() + from agentuity import autostart + try: + autostart() + except Exception: + logging.exception("Agent startup failed") + sys.exit(1)
Also applies to: 36-36
7-13
: Error message mentions only SDK key while the check accepts API or SDK key.Make the guidance accurate and send to stderr.
- print( - "\033[31m[ERROR] AGENTUITY_SDK_KEY is not set. This should have been set automatically by the Agentuity CLI or picked up from the .env file.\033[0m" - ) + print( + "\033[31m[ERROR] Neither AGENTUITY_API_KEY nor AGENTUITY_SDK_KEY is set. Set one in your environment or in .env.\033[0m", + file=sys.stderr, + )
14-17
: Avoid brittleuv
detection via_
; show the hint whenever.env
exists and tailor the script name.- if os.environ.get("_", "").endswith("uv") and os.path.exists(".env"): - print( - "\033[31m[ERROR] Re-run the command with `uv run --env-file .env server.py`\033[0m" - ) + if os.path.exists(".env"): + print( + f"\033[31m[ERROR] Tip: If using uv, re-run with `uv run --env-file .env {os.path.basename(sys.argv[0])}`\033[0m", + file=sys.stderr, + )
21-27
: Use WARN color for non-fatal messages and write to stderr.Red (31m) reads as error; switch to yellow (33m) and stderr.
- print( - "\033[31m[WARN] You are running this agent outside of the Agentuity environment. Any automatic Agentuity features will be disabled.\033[0m" - ) + print( + "\033[33m[WARN] You are running this agent outside of the Agentuity environment. Automatic Agentuity features will be disabled.\033[0m", + file=sys.stderr, + ) @@ - print( - "\033[31m[WARN] Recommend running `agentuity dev` to run your project locally instead of `python script`.\033[0m" - ) + print( + f"\033[33m[WARN] Recommend running `agentuity dev` to run your project locally instead of `python {os.path.basename(sys.argv[0])}`.\033[0m", + file=sys.stderr, + )
29-34
: Don’t truncate level names in logs.
%(levelname)-5.5s
clips “WARNING” to “WARNI”. Use full name.logging.basicConfig( stream=sys.stdout, level=logging.INFO, - format="[%(levelname)-5.5s] %(message)s", + format="[%(levelname)s] %(message)s", )examples/tutorial_hello_world_py/pyproject.toml (3)
4-4
: Capitalize “Python” in description.Minor polish for user‑facing text.
-description = "A python version of a hello world agent" +description = "A Python version of a hello world agent"
5-5
: Re-evaluate the Python upper bound (<3.13).Python 3.13 has been released; if the example works on 3.13, widening the range reduces friction for users.
Please confirm by running the tutorial on 3.13 and, if green, update to:
-requires-python = ">=3.10, <3.13" +requires-python = ">=3.10, <3.14"
6-9
: Constrain dependency ranges to avoid surprise breakage.
- Pre‑1.0 libraries can introduce breaking changes in any release; bound agentuity below the next minor.
- Add an upper bound for openai to guard against a future 2.x breaking release.
dependencies = [ - "agentuity>=0.0.106", - "openai>=1.107.0", + "agentuity>=0.0.106,<0.1.0", + "openai>=1.107.0,<2.0.0", ]content/meta.json (1)
5-5
: Nav label/slug check for “Tutorial”.Confirm the site generator resolves this page key to
content/Tutorial/meta.json
(case‑sensitive on some hosts). If multiple tutorials are planned, consider “Tutorials” for clarity.content/Tutorial/poc-multi/step2.mdx (1)
1-16
: Add a quick “verify you’re logged in” step.After login, add a one‑liner to verify auth (e.g.,
agentuity whoami
oragentuity auth status
) so users can confirm before proceeding.Apply this diff to insert a verification block:
If you're not already logged in, run: ```bash agentuity auth login
+To verify you're authenticated, run:
+bash +agentuity whoami +
</blockquote></details> <details> <summary>content/Tutorial/poc-multi/step1.mdx (3)</summary><blockquote> `2-4`: **Title/description: clarify we create an Agent (and project).** If the recommended flow is `agent create`, tweak title/description accordingly. Apply: ```diff -title: Create a new project -description: Run the interactive project generator to scaffold a new Agentuity project +title: Create a new agent and project +description: Use the interactive generator to scaffold a new Agentuity agent (and project)
8-11
: Use the preferred CLI command.Switch from
project create
toagent create
to match current guidance.-```bash -agentuity project create -``` +```bash +agentuity agent create +```If both commands exist, add a note indicating which is preferred and why.
16-20
: Prereq nudge for toolchains.Add brief install links/notes for Bun and uv to reduce setup friction.
- Language/runtime: - TypeScript (Bun) or - Python (uv) + (Ensure Bun and/or uv are installed before proceeding.)
examples/tutorial_hello_world_py/.gitignore (5)
130-139
: Add local env variants for completenessConsider ignoring common local env variants used by dev tooling.
Apply this diff:
.env .env.development .env.production +.env.local +.env.*.local .venv env/ venv/
17-19
: Risk: ignoring lib/ and lib64/ can hide sourceIf any example code lives under lib/ or lib64/, it would be excluded from VCS. If you’re not producing those dirs as build artifacts, drop these patterns.
Apply this diff if appropriate:
-lib/ -lib64/
6-8
: Include Windows C-extension artifactsAdd *.pyd alongside *.so to cover Windows builds.
Apply this diff:
*.so +*.pyd
78-80
: Consistency: treat ipynb checkpoints as a directoryMinor consistency tweak.
Apply this diff:
-.ipynb_checkpoints +.ipynb_checkpoints/
165-171
: Optional: ignore common editor/OS noise in examplesTo keep example PRs clean, explicitly ignore IDE and OS files.
Apply this diff:
-#.idea/ +# Editors/OS +.idea/ +.vscode/ +.DS_Storeexamples/tutorial_hello_world_py/main.py (3)
1-1
: Add return type and a brief docstring for clarity.Tiny polish that helps static tooling and readers.
-def main(): +def main() -> None: + """Entrypoint for the Python hello-world tutorial."""
1-1
: Optional: Add a shebang to allow direct execution.Handy when making the file executable.
+#!/usr/bin/env python3 def main():
2-2
: Standardize example name (hyphen vs underscore)Mixed usages found — directory is examples/tutorial_hello_world_py but metadata and the greeting use tutorial-hello-world-py. Choose one convention; minimal fix is to update the greeting in main.py:
- print("Hello from tutorial-hello-world-py!") + print("Hello from tutorial_hello_world_py!")Occurrences: examples/tutorial_hello_world_py/main.py, examples/tutorial_hello_world_py/pyproject.toml, examples/tutorial_hello_world_py/uv.lock, examples/tutorial_hello_world_py/agentuity.yaml, content/Tutorial/poc-multi/step4.mdx.
examples/tutorial-hello-world/src/agents/agent-hello/index.ts (2)
34-35
: Harden input fallback for empty strings.
??
won’t catch''
. Trim and use||
so empty/whitespace falls back.Apply:
- content: (await req.data.text()) ?? 'Hello, OpenAI', + content: ((await req.data.text())?.trim() || 'Hello, OpenAI'),
29-37
: Make model configurable; consider cancellation.
- Parameterize the model via env for easier local/testing overrides.
- If
AgentContext
exposes an AbortSignal, pass it to the SDK to support request cancellation.Apply:
- model: 'gpt-5-mini', + model: process.env.OPENAI_MODEL ?? 'gpt-5-mini',If an abort signal is available (e.g.,
ctx.signal
), wire it in per the OpenAI SDK’s request options. Please confirm the available field onAgentContext
.examples/tutorial_hello_world_py/agentuity_agents/agent_hello_py/agent.py (5)
1-5
: Initialize client with explicit timeout/retries and centralize model config.Prevents hangs and eases model swaps across environments.
Apply this diff:
from agentuity import AgentRequest, AgentResponse, AgentContext from openai import AsyncOpenAI +import os -client = AsyncOpenAI() +DEFAULT_MODEL = os.getenv("OPENAI_MODEL", "gpt-4o-mini") +client = AsyncOpenAI(timeout=30.0, max_retries=2)
21-33
: Sanitize user input and set temperature.Guarantees a non-empty prompt and more deterministic replies.
Apply this diff:
async def run(request: AgentRequest, response: AgentResponse, context: AgentContext): try: - result = await client.chat.completions.create( - model="gpt-5-mini", - messages=[ + raw = await request.data.text() + user = raw.strip() if raw and raw.strip() else "Hello, OpenAI" + result = await client.chat.completions.create( + model=DEFAULT_MODEL, + temperature=0.2, + messages=[ { "role": "system", "content": "You are a helpful assistant that provides concise and accurate information.", }, { "role": "user", - "content": await request.data.text() or "Hello, OpenAI", + "content": user, }, ], )
37-37
: Guard against empty choices to avoid IndexError/None.Minor robustness improvement.
Apply this diff:
- return response.text(result.choices[0].message.content) + content = result.choices[0].message.content if getattr(result, "choices", None) else None + return response.text(content or "Sorry, no content returned from the model.")
38-41
: Don’t catch blind Exception; log traceback.Use exception logging to preserve stack traces. Optionally add specific OpenAI exceptions.
Apply this diff:
- except Exception as e: - context.logger.error(f"Error running agent: {e}") - - return response.text("Sorry, there was an error processing your request.") + except Exception: + context.logger.exception("Error running agent") + return response.text("Sorry, there was an error processing your request.")Optional (if you want narrower handling), also import and catch OpenAI errors:
-from openai import AsyncOpenAI +from openai import AsyncOpenAI, APIError, RateLimitError, APITimeoutError @@ - except Exception: + except (RateLimitError, APITimeoutError) as e: + context.logger.warning("Transient OpenAI error: %s", e) + return response.text("The service is busy. Please try again in a moment.") + except APIError: + context.logger.exception("OpenAI API error") + return response.text("Upstream error. Please try again later.") + except Exception: context.logger.exception("Error running agent") return response.text("Sorry, there was an error processing your request.")
21-35
: Optional: align with SSE streaming.If your tutorial expects token streaming, switch to the streaming API here and forward deltas over your SSE response handler.
Happy to provide a minimal streaming variant tailored to your AgentResponse if you share its streaming interface.
examples/tutorial-hello-world/tsconfig.json (4)
20-21
: Avoid restricting global type resolution to SDK; keep only Bun types in "types".Specifying "types" narrows global type inclusions. Including "@agentuity/sdk" here isn’t needed (SDK types are imported per‑module) and can mask other ambient types. Keep Bun types only.
Apply this diff:
- "types": ["@types/bun", "@agentuity/sdk"], + "types": ["@types/bun"],
4-4
: Disable allowJs for a TS‑only tutorial to catch drift early.If no .js files are intended, set allowJs to false.
- "allowJs": true, + "allowJs": false,
6-6
: Drop JSX setting if React isn’t used in this example.Removes noise from editor/tooling.
- "jsx": "react-jsx", + // "jsx": "react-jsx",
15-16
: Consider enabling unused checks once the sample stabilizes.Helpful for learners and CI.
- "noUnusedLocals": false, - "noUnusedParameters": false, + "noUnusedLocals": true, + "noUnusedParameters": true,examples/tutorial-hello-world/package.json (1)
5-6
: Remove misleading "main"/"module" fields; rely on bundler output via scripts.This app runs via .agentuity/index.js; keeping "main": "index.js" (nonexistent) and "module": "index.ts" is confusing.
"version": "0.0.1", - "main": "index.js", "type": "module", @@ - "module": "index.ts" + "engines": { + "bun": ">=1.2.4" + }Also applies to: 34-34
examples/tutorial-hello-world/README.md (2)
6-6
: Add alt text to image for a11y (MD045).- <img src="https://app.agentuity.com/img/deploy.svg" /> + <img src="https://app.agentuity.com/img/deploy.svg" alt="Deploy to Agentuity" />
65-70
: Specify a language on the fenced code block (MD040).-``` +```text ├── agents/ # Agent definitions and implementations ├── node_modules/ # Dependencies ├── package.json # Project dependencies and scripts └── agentuity.yaml # Agentuity project configuration</blockquote></details> <details> <summary>examples/tutorial-hello-world/index.ts (4)</summary><blockquote> `3-9`: **Make process.isBun optional in type augmentation.** At runtime this may be undefined under Node; reflect that in types. ```diff - interface Process { - isBun: boolean; - } + interface Process { + isBun?: boolean; + }
11-15
: Error text should reflect both accepted env vars.The guard allows AGENTUITY_API_KEY or AGENTUITY_SDK_KEY; message mentions only one.
- '\x1b[31m[ERROR] AGENTUITY_SDK_KEY is not set. This should have been set automatically by the Agentuity CLI or picked up from the .env file.\x1b[0m' + '\x1b[31m[ERROR] AGENTUITY_API_KEY or AGENTUITY_SDK_KEY is not set. This should be set by the Agentuity CLI or picked up from the .env file.\x1b[0m'
28-41
: Use yellow for warnings and tailor suggestion text.Improve severity signaling and keep guidance consistent.
- console.warn( - '\x1b[31m[WARN] You are running this agent outside of the Agentuity environment. Any automatic Agentuity features will be disabled.\x1b[0m' - ); + console.warn( + '\x1b[33m[WARN] Running outside the Agentuity environment; automatic features are disabled.\x1b[0m' + ); @@ - console.warn( - '\x1b[31m[WARN] Recommend running `agentuity dev` to run your project locally instead of `bun run start`.\x1b[0m' - ); + console.warn( + '\x1b[33m[WARN] Recommend `agentuity dev` instead of `bun run start`.\x1b[0m' + ); @@ - console.warn( - '\x1b[31m[WARN] Recommend running `agentuity dev` to run your project locally instead of `npm start`.\x1b[0m' - ); + console.warn( + '\x1b[33m[WARN] Recommend `agentuity dev` instead of `npm start`.\x1b[0m' + );
43-52
: Use a portable directory reference; import.meta.dirname isn’t standard.Bun provides import.meta.dir; Node has import.meta.url. Use a fallback.
-runner(true, import.meta.dirname).catch((err) => { +runner(true, (import.meta as any).dir ?? new URL('.', import.meta.url).pathname).catch((err) => {examples/tutorial-hello-world/AGENTS.md (2)
7-12
: Unify CLI wording: prefer a single verb (“agent new”).Elsewhere (README) uses
agentuity agent new
. Keep it consistent.-- Prefer using the `agentuity agent create` command to create a new Agent +- Prefer using the `agentuity agent new` command to create a new Agent
50-51
: Fix method signature typo.Add parentheses to
object<T>()
.-- `request.data.object<T>: Promise<T>`: Gets the payload as a typed object +- `request.data.object<T>(): Promise<T>`: Gets the payload as a typed object
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
examples/tutorial-hello-world/bun.lock
is excluded by!**/*.lock
examples/tutorial_hello_world_py/uv.lock
is excluded by!**/*.lock
📒 Files selected for processing (30)
content/Tutorial/meta.json
(1 hunks)content/Tutorial/poc-multi/index.mdx
(1 hunks)content/Tutorial/poc-multi/meta.json
(1 hunks)content/Tutorial/poc-multi/step1.mdx
(1 hunks)content/Tutorial/poc-multi/step2.mdx
(1 hunks)content/Tutorial/poc-multi/step3.mdx
(1 hunks)content/Tutorial/poc-multi/step4.mdx
(1 hunks)content/meta.json
(1 hunks)examples/tutorial-hello-world/.editorconfig
(1 hunks)examples/tutorial-hello-world/.gitignore
(1 hunks)examples/tutorial-hello-world/AGENTS.md
(1 hunks)examples/tutorial-hello-world/README.md
(1 hunks)examples/tutorial-hello-world/agentuity.yaml
(1 hunks)examples/tutorial-hello-world/biome.json
(1 hunks)examples/tutorial-hello-world/index.ts
(1 hunks)examples/tutorial-hello-world/package.json
(1 hunks)examples/tutorial-hello-world/src/agents/agent-hello/index.ts
(1 hunks)examples/tutorial-hello-world/tsconfig.json
(1 hunks)examples/tutorial_hello_world_py/.editorconfig
(1 hunks)examples/tutorial_hello_world_py/.gitignore
(1 hunks)examples/tutorial_hello_world_py/.python-version
(1 hunks)examples/tutorial_hello_world_py/AGENTS.md
(1 hunks)examples/tutorial_hello_world_py/README.md
(1 hunks)examples/tutorial_hello_world_py/agentuity.yaml
(1 hunks)examples/tutorial_hello_world_py/agentuity_agents/__init__.py
(1 hunks)examples/tutorial_hello_world_py/agentuity_agents/agent_hello_py/__init__.py
(1 hunks)examples/tutorial_hello_world_py/agentuity_agents/agent_hello_py/agent.py
(1 hunks)examples/tutorial_hello_world_py/main.py
(1 hunks)examples/tutorial_hello_world_py/pyproject.toml
(1 hunks)examples/tutorial_hello_world_py/server.py
(1 hunks)
✅ Files skipped from review due to trivial changes (12)
- examples/tutorial_hello_world_py/agentuity_agents/agent_hello_py/init.py
- content/Tutorial/poc-multi/step4.mdx
- examples/tutorial_hello_world_py/.python-version
- content/Tutorial/poc-multi/step3.mdx
- examples/tutorial_hello_world_py/.editorconfig
- examples/tutorial-hello-world/biome.json
- examples/tutorial_hello_world_py/AGENTS.md
- content/Tutorial/poc-multi/meta.json
- examples/tutorial_hello_world_py/agentuity_agents/init.py
- content/Tutorial/meta.json
- examples/tutorial-hello-world/.gitignore
- examples/tutorial-hello-world/.editorconfig
🧰 Additional context used
🧠 Learnings (11)
📚 Learning: 2025-07-23T12:40:34.834Z
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-23T12:40:34.834Z
Learning: Applies to agent-docs/src/agents/**/*.ts : Use TypeScript for better type safety and IDE support
Applied to files:
examples/tutorial-hello-world/index.ts
examples/tutorial-hello-world/tsconfig.json
examples/tutorial-hello-world/src/agents/agent-hello/index.ts
examples/tutorial-hello-world/AGENTS.md
📚 Learning: 2025-07-23T12:40:22.412Z
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-23T12:40:22.412Z
Learning: Applies to agent-docs/**/src/agents/**/index.ts : The file should export a default function
Applied to files:
examples/tutorial-hello-world/index.ts
examples/tutorial-hello-world/package.json
examples/tutorial-hello-world/src/agents/agent-hello/index.ts
examples/tutorial-hello-world/AGENTS.md
📚 Learning: 2025-07-23T12:40:34.834Z
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-23T12:40:34.834Z
Learning: Applies to agent-docs/src/agents/**/*.ts : Import types from 'agentuity/sdk'
Applied to files:
examples/tutorial-hello-world/index.ts
examples/tutorial-hello-world/tsconfig.json
examples/tutorial-hello-world/src/agents/agent-hello/index.ts
examples/tutorial-hello-world/AGENTS.md
📚 Learning: 2025-07-23T12:40:22.412Z
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-23T12:40:22.412Z
Learning: Applies to agent-docs/**/src/agents/**/index.ts : All code should be in Typescript format
Applied to files:
examples/tutorial-hello-world/index.ts
examples/tutorial-hello-world/src/agents/agent-hello/index.ts
examples/tutorial-hello-world/AGENTS.md
📚 Learning: 2025-07-23T12:40:26.540Z
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/agentuity.mdc:0-0
Timestamp: 2025-07-23T12:40:26.540Z
Learning: Applies to agent-docs/**/agentuity.yaml : Do not suggest edits to the Agentuity AI Configuration file (agentuity.yaml)
Applied to files:
examples/tutorial_hello_world_py/agentuity.yaml
examples/tutorial-hello-world/agentuity.yaml
📚 Learning: 2025-07-23T12:40:22.412Z
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-23T12:40:22.412Z
Learning: Prefer using the `agentuity agent create` command to create a new Agent
Applied to files:
content/Tutorial/poc-multi/step1.mdx
content/Tutorial/poc-multi/index.mdx
📚 Learning: 2025-07-23T12:40:22.412Z
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-23T12:40:22.412Z
Learning: Applies to agent-docs/**/src/agents/**/index.ts : Prefer naming the default function Agent or the name of the Agent based on the context of the Agent description
Applied to files:
examples/tutorial-hello-world/src/agents/agent-hello/index.ts
examples/tutorial-hello-world/AGENTS.md
📚 Learning: 2025-07-23T12:40:34.834Z
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-23T12:40:34.834Z
Learning: Applies to agent-docs/src/agents/**/*.ts : Consider agent communication for complex workflows
Applied to files:
examples/tutorial-hello-world/src/agents/agent-hello/index.ts
examples/tutorial-hello-world/AGENTS.md
📚 Learning: 2025-09-10T14:24:52.800Z
Learnt from: afterrburn
PR: agentuity/docs#279
File: agent-docs/src/agents/agent-pulse/types.ts:2-7
Timestamp: 2025-09-10T14:24:52.800Z
Learning: The Agentuity SDK (agentuity/sdk) only exports specific types: AgentRequest, AgentResponse, AgentContext, and VectorUpsertParams. It does not export general message types like ConversationMessage or ChatMessage.
Applied to files:
examples/tutorial-hello-world/src/agents/agent-hello/index.ts
📚 Learning: 2025-07-23T12:40:34.834Z
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-23T12:40:34.834Z
Learning: Applies to agent-docs/src/agents/**/*.ts : Use the storage APIs for persisting data
Applied to files:
examples/tutorial-hello-world/AGENTS.md
📚 Learning: 2025-07-23T12:40:22.412Z
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-23T12:40:22.412Z
Learning: Applies to agent-docs/**/src/agents/**/index.ts : Prefer loading types from the node modules package `agentuity/sdk` in the node_modules folder
Applied to files:
examples/tutorial-hello-world/AGENTS.md
🧬 Code graph analysis (2)
examples/tutorial-hello-world/src/agents/agent-hello/index.ts (1)
examples/tutorial_hello_world_py/agentuity_agents/agent_hello_py/agent.py (1)
welcome
(6-19)
examples/tutorial_hello_world_py/agentuity_agents/agent_hello_py/agent.py (1)
examples/tutorial-hello-world/src/agents/agent-hello/index.ts (1)
welcome
(6-21)
🪛 Ruff (0.12.2)
examples/tutorial_hello_world_py/agentuity_agents/agent_hello_py/agent.py
38-38: Do not catch blind exception: Exception
(BLE001)
39-39: Use logging.exception
instead of logging.error
Replace with exception
(TRY400)
🪛 markdownlint-cli2 (0.17.2)
examples/tutorial-hello-world/AGENTS.md
6-6: Images should have alternate text (alt text)
(MD045, no-alt-text)
65-65: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
examples/tutorial_hello_world_py/README.md
6-6: Images should have alternate text (alt text)
(MD045, no-alt-text)
72-72: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
⏰ 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: Workers Builds: docs
- GitHub Check: Workers Builds: docs
🔇 Additional comments (15)
examples/tutorial_hello_world_py/agentuity.yaml (3)
1-6
: LGTM: Generated Agentuity config header and schema reference.Acknowledging team guidance: not proposing edits to agentuity.yaml.
9-15
: Confirm CLI/tooling satisfies version constraint '>=0.0.166'.Please verify CI and local dev images pin or enforce a compatible Agentuity CLI/runtime version so builds don’t drift.
64-71
: LGTM: Agent metadata (id/name/description).Looks consistent with the tutorial.
examples/tutorial_hello_world_py/pyproject.toml (1)
6-9
: No action needed — required minimum versions are available on PyPI.agentuity 0.0.106 is present (latest 0.0.106); openai 1.107.0 is present (latest 1.107.2).
examples/tutorial_hello_world_py/.gitignore (2)
1-180
: Comprehensive Python .gitignore — solid baselineGood coverage across Python tooling, packaging, tests, and secret hygiene for an example project.
110-119
: Keep .pdm.toml ignored; commit pyproject.toml and pdm.lock
PDM docs recommend committing pyproject.toml and pdm.lock; .pdm.toml is local and should remain in .gitignore (pdm.toml without the leading dot may be shared).examples/tutorial_hello_world_py/main.py (1)
1-6
: LGTM for a minimal tutorial script.Simple, readable, and correctly guarded with
if __name__ == "__main__":
.examples/tutorial-hello-world/src/agents/agent-hello/index.ts (4)
4-4
: LGTM: single OpenAI client at module scope.Reusing a single client instance is good practice.
6-21
: Welcome payload looks clean and mirrors the Python example.No issues.
23-27
: Default export named Agent aligns with house rules.Matches retrieved learnings (TS, default export, naming).
1-1
: SDK import path is correct — keep @agentuity/sdk (scoped).
- examples/tutorial-hello-world/src/agents/agent-hello/index.ts imports from '@agentuity/sdk' and package.json entries confirm it (agent-docs/package.json: "@agentuity/sdk": "^0.0.124"; examples/tutorial-hello-world/package.json: "@agentuity/sdk": "^0.0.145").
- Repo learning that mentions
agentuity/sdk
(unscoped) is out-of-date; no change needed to this import.Likely an incorrect or invalid review comment.
examples/tutorial_hello_world_py/agentuity_agents/agent_hello_py/agent.py (1)
6-19
: Welcome payload looks good.Matches the TS tutorial structure and provides sensible starter prompts.
examples/tutorial-hello-world/agentuity.yaml (1)
1-82
: No suggestions per repo guidance for Agentuity config files.examples/tutorial-hello-world/AGENTS.md (1)
31-36
: Return type confirmed — keep Promise
The SDK publicly exports AgentResponseType; the handler should return Promise (examples use response.json / response.text / response.stream).examples/tutorial-hello-world/package.json (1)
31-33
: Verify dependency versions and Bun 1.2.x compatibility.
- npm dist-tags: @agentuity/sdk latest = 0.0.145; openai latest = 5.20.2. PR deps show "@agentuity/sdk": "^0.0.145" and "openai": "^5.20.0" (caret will allow 5.20.2).
- examples/tutorial-hello-world/package.json could not be opened (No such file). Confirm the correct package.json path or run: jq -r '.dependencies' <path-to-package.json>. After confirming, verify Bun 1.2.x compatibility for openai@5.x and @agentuity/sdk (ESM/runtime changes may break Bun).
content/Tutorial/poc-multi/index.mdx
Outdated
@@ -0,0 +1,23 @@ | |||
--- | |||
title: Create a new Agent with the CLI | |||
description: Quickstart to scaffold an Agentuity project using agentuity project create, authenticate with Agentuity, and run locally. |
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.
💡 Verification agent
🧩 Analysis chain
Align CLI wording with preferred command.
Earlier guidance prefers agentuity agent create
. Update the description to avoid confusion with project create
.
Apply this diff:
-description: Quickstart to scaffold an Agentuity project using agentuity project create, authenticate with Agentuity, and run locally.
+description: Quickstart to scaffold an Agentuity project using agentuity agent create, authenticate with Agentuity, and run locally.
Run this to find any other instances to update:
🏁 Script executed:
#!/bin/bash
rg -nP -C2 '\bagentuity\s+project\s+create\b|agent\s+create\b'
Length of output: 3846
Align CLI wording with preferred command (agentuity agent create
)
Replace "agentuity project create" → "agentuity agent create" in the tutorial docs.
Apply this diff:
-description: Quickstart to scaffold an Agentuity project using agentuity project create, authenticate with Agentuity, and run locally.
+description: Quickstart to scaffold an Agentuity project using agentuity agent create, authenticate with Agentuity, and run locally.
Also update:
- content/Tutorial/poc-multi/step1.mdx (line 10): change
agentuity project create
→agentuity agent create
.
Do not change content/CLI/project.mdx (the project create
examples belong in project docs).
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
description: Quickstart to scaffold an Agentuity project using agentuity project create, authenticate with Agentuity, and run locally. | |
description: Quickstart to scaffold an Agentuity project using agentuity agent create, authenticate with Agentuity, and run locally. |
🤖 Prompt for AI Agents
In content/Tutorial/poc-multi/index.mdx around line 3 and
content/Tutorial/poc-multi/step1.mdx at line 10, update the CLI command wording:
replace occurrences of "agentuity project create" with "agentuity agent create".
Only change these two tutorial files; do not modify content/CLI/project.mdx.
async def run(request: AgentRequest, response: AgentResponse, context: AgentContext): | ||
try: | ||
result = await client.chat.completions.create( | ||
model="gpt-5-mini", |
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.
💡 Verification agent
🧩 Analysis chain
Avoid hardcoding an invalid/unknown model; make it configurable.
"gpt-5-mini" may not exist for your account and will 404. Read from env/config with a safe default.
Apply this diff:
- model="gpt-5-mini",
+ model=DEFAULT_MODEL,
If you want me to wire this to your config/KV helper instead of env, say so and I’ll patch it.
🌐 Web query:
What OpenAI Chat Completions/Responses models are currently available and recommended for lightweight text assistants?
💡 Result:
Recommended lightweight Chat Completions / Responses models (current as of Sep 15, 2025):
- GPT‑4.1 mini — OpenAI’s current small, fast, efficient “mini” model and the recommended lightweight default for assistants. [1][2]
- o3‑mini — low-cost reasoning-focused mini model for cheaper, faster reasoning-heavy tasks. [5][6]
- o4‑mini / o‑series mini models — alternative small models in the “o” reasoning family for cost/latency tradeoffs. [5]
Notes:
- The Responses API and Chat Completions support the GPT‑4.1 series and the o‑series (o3, o3‑mini, o4‑mini) — choose GPT‑4.1 mini for highest general instruction-following and speed; use o3‑mini when you need lower-cost reasoning. [1][5]
Sources: OpenAI GPT‑4.1 announcement and docs; OpenAI model release notes; Responses API & o‑series model docs. [1][2][5][6]
Do not hardcode an unknown model — make the model configurable and default to a supported mini model
"gpt-5-mini" is not a known Responses/ChatCompletions model and may 404; read the model from env/config and default to a supported lightweight model (recommended: "gpt-4.1-mini" or "o3-mini").
File: examples/tutorial_hello_world_py/agentuity_agents/agent_hello_py/agent.py — line 24
Apply this diff:
- model="gpt-5-mini",
+ model=DEFAULT_MODEL,
Ensure DEFAULT_MODEL is set via env/config and CI uses a valid model.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In examples/tutorial_hello_world_py/agentuity_agents/agent_hello_py/agent.py
around line 24, the model is hardcoded to "gpt-5-mini" which may 404; change
this to read a DEFAULT_MODEL from environment/config (e.g., os.environ.get or a
config module) and fall back to a supported lightweight model such as
"gpt-4.1-mini" or "o3-mini"; replace the literal model string with that
DEFAULT_MODEL variable, ensure the DEFAULT_MODEL is documented and settable in
CI/env files, and update CI/test configs to use a valid model value.
const cmd = process.env._ || ''; | ||
|
||
if (cmd.endsWith('node')) { | ||
console.error( | ||
'\x1b[31m[ERROR] Re-run the command with `node --env-file .env index.ts`\x1b[0m' | ||
); | ||
} |
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.
Fix Node hint: Node can’t run .ts directly. Suggest running the bundled JS.
Current suggestion (node --env-file .env index.ts
) will fail without a TS runner.
- const cmd = process.env._ || '';
-
- if (cmd.endsWith('node')) {
+ const isNode = process.release?.name === 'node';
+ if (isNode) {
console.error(
- '\x1b[31m[ERROR] Re-run the command with `node --env-file .env index.ts`\x1b[0m'
+ '\x1b[31m[ERROR] Re-run with `node --env-file=.env .agentuity/index.js` (after `agentuity bundle`).\x1b[0m'
);
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const cmd = process.env._ || ''; | |
if (cmd.endsWith('node')) { | |
console.error( | |
'\x1b[31m[ERROR] Re-run the command with `node --env-file .env index.ts`\x1b[0m' | |
); | |
} | |
const isNode = process.release?.name === 'node'; | |
if (isNode) { | |
console.error( | |
'\x1b[31m[ERROR] Re-run with `node --env-file=.env .agentuity/index.js` (after `agentuity bundle`).\x1b[0m' | |
); | |
} |
🤖 Prompt for AI Agents
In examples/tutorial-hello-world/index.ts around lines 16–22, the current error
message incorrectly suggests running a .ts file with plain node; update the
message to advise running the compiled JS or a TS runner. Replace the hint to
say something like "Re-run the command with the bundled JavaScript (e.g. node
dist/index.js) or use a TypeScript runner (e.g. npx ts-node index.ts)" so users
have valid options that will actually work.
return resp.text( | ||
result.choices[0]?.message.content ?? 'Something went wrong' | ||
); |
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.
Fix optional chaining to avoid runtime TypeError on empty choices.
result.choices[0]?.message.content
still dereferences .content
even when message
is undefined. Use full chaining.
Apply:
- result.choices[0]?.message.content ?? 'Something went wrong'
+ result.choices?.[0]?.message?.content ?? 'Something went wrong'
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
return resp.text( | |
result.choices[0]?.message.content ?? 'Something went wrong' | |
); | |
return resp.text( | |
result.choices?.[0]?.message?.content ?? 'Something went wrong' | |
); |
🤖 Prompt for AI Agents
examples/tutorial-hello-world/src/agents/agent-hello/index.ts around lines 39 to
41: the expression uses optional chaining only on choices[0] but still
dereferences .content even when message is undefined, which can throw a
TypeError; change the access to fully safe optional chaining (e.g., check
message before .content or use result.choices[0]?.message?.content) and fall
back to the existing default string so resp.text receives a defined string.
return NextResponse.json({ error: "User ID not found" }, { status: 401 }); | ||
} | ||
// Helper: sanitize title per requirements | ||
function sanitizeTitle(input: string): string { |
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.
These probably shouldn't be defined inside the POST request
This reverts commit 6d70c4e.
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
♻️ Duplicate comments (4)
app/api/sessions/[sessionId]/messages/route.ts (4)
77-81
: Always set a timestamp for incoming user messages.Guarantee a timestamp even when the client omits it.
- // Ensure timestamp is in ISO string format - if (message.timestamp) { - message.timestamp = toISOString(message.timestamp); - } + // Ensure timestamp is set and in ISO string format + if (message.timestamp) { + message.timestamp = toISOString(message.timestamp); + } else { + message.timestamp = getCurrentTimestamp(); + }
332-351
: Harden stream piping: wrap close, await abort, and avoid masking errors.- (async () => { + (async () => { try { while (true) { const { done, value } = await reader.read(); if (done) { break; } try { await writer.write(value); } catch (writeError) { console.error('Error writing to transform stream:', writeError); throw writeError; } } - await writer.close(); + try { + await writer.close(); + } catch (closeError) { + console.error('Error closing transform stream writer:', closeError); + throw closeError; + } } catch (error) { console.error('Error in stream processing:', error); - writer.abort(error); + try { + await writer.abort(error as any); + } catch (abortError) { + console.error('Error aborting writer:', abortError); + } } })();
190-207
: Do not rely on try/catch for KV client failures; handle the response.
setKVValue
does not throw on HTTP errors. This can proceed with an inconsistent state.- try { - await setKVValue(sessionKey, updatedSession, { - storeName: config.defaultStoreName, - }); - } catch (error) { - console.error( - `Failed to save session after adding message. SessionId: ${sessionId}, Error details:`, - error instanceof Error ? error.message : String(error), - error instanceof Error && error.stack ? `Stack: ${error.stack}` : '' - ); - return NextResponse.json( - { - error: "Failed to save message to session", - details: "Unable to persist the message. Please try again." - }, - { status: 500 } - ); - } + const updateResp = await setKVValue(sessionKey, updatedSession, { + storeName: config.defaultStoreName, + }); + if (!updateResp.success) { + return NextResponse.json( + { + error: updateResp.error || "Failed to save message to session", + }, + { status: updateResp.statusCode || 500 } + ); + }
255-324
: SSE parsing is not chunk-safe and can emit multiple finishes; add buffering and a finish gate.- // Process streaming response - let accumulatedContent = ""; - let finalTutorialData: TutorialData | undefined = undefined; - - const transformStream = new TransformStream({ + // Process streaming response + let accumulatedContent = ""; + let finalTutorialData: TutorialData | undefined = undefined; + let finishedSent = false; + const sseDecoder = new TextDecoder(); + let sseBuffer = ""; + + const transformStream = new TransformStream({ async transform(chunk, controller) { // Forward the chunk to the client controller.enqueue(chunk); - // Process the chunk to accumulate the full response - const text = new TextDecoder().decode(chunk); - const lines = text.split("\n"); + // Buffer-aware SSE parsing + sseBuffer += sseDecoder.decode(chunk, { stream: true }); + const lines = sseBuffer.split("\n"); + sseBuffer = lines.pop() ?? ""; // keep last partial for (const line of lines) { if (line.startsWith("data: ")) { try { const data = JSON.parse(line.slice(6)) as StreamingChunk; if (data.type === "text-delta" && data.textDelta) { accumulatedContent += data.textDelta; } else if (data.type === "tutorial-data" && data.tutorialData) { finalTutorialData = data.tutorialData; // Update user's tutorial progress await TutorialStateManager.updateTutorialProgress( userId, finalTutorialData.tutorialId, finalTutorialData.currentStep, finalTutorialData.totalSteps ); - } else if (data.type === "finish") { + } else if (data.type === "finish" && !finishedSent) { + finishedSent = true; // When the stream is finished, save the assistant message const assistantMessage: Message = { id: assistantMessageId, author: "ASSISTANT", content: accumulatedContent, timestamp: getCurrentTimestamp(), tutorialData: finalTutorialData, }; - const finalSession = { - ...updatedSession, - messages: [...updatedSession.messages, assistantMessage], - }; - - await setKVValue(sessionKey, finalSession, { - storeName: config.defaultStoreName, - }); + // Merge with latest before persisting (avoid overwriting concurrent updates) + const latest = await getKVValue<Session>(sessionKey, { storeName: config.defaultStoreName }); + const base = latest.success && latest.data ? latest.data : updatedSession; + const already = base.messages.some(m => m.id === assistantMessageId); + const finalSession: Session = already + ? base + : { ...base, messages: [...base.messages, assistantMessage] }; + + const persistResp = await setKVValue(sessionKey, finalSession, { storeName: config.defaultStoreName }); + if (!persistResp.success) { + console.error('Failed to persist assistant message:', persistResp.error || persistResp.statusCode); + } // Trigger background title generation if missing // Do not await to avoid delaying the client stream completion void generateAndPersistTitle(sessionId, sessionKey, finalSession); // Send the final session in the finish event controller.enqueue( new TextEncoder().encode( `data: ${JSON.stringify({ type: "finish", session: finalSession, })}\n\n` ) ); } } catch (error) { console.error("Error processing stream chunk:", error); } } } }, + async flush() { + // Process any remaining buffered line(s) + if (!sseBuffer) return; + for (const line of sseBuffer.split("\n")) { + if (!line.startsWith("data: ")) continue; + try { + const data = JSON.parse(line.slice(6)) as StreamingChunk; + if (data.type === "text-delta" && data.textDelta) { + accumulatedContent += data.textDelta; + } else if (data.type === "tutorial-data" && data.tutorialData) { + finalTutorialData = data.tutorialData; + } + } catch { /* ignore */ } + } + } });
🧹 Nitpick comments (5)
app/api/sessions/[sessionId]/messages/route.ts (5)
102-104
: Replace unnecessary template literal to satisfy linter.No interpolation present; use a normal string literal.
- const prompt = `Generate a very short session title summarizing the conversation topic.\n\nRequirements:\n- sentence case\n- no emojis\n- <= 60 characters\n- no quotes or markdown\n- output the title only, no extra text`; + const prompt = 'Generate a very short session title summarizing the conversation topic.\n\nRequirements:\n- sentence case\n- no emojis\n- <= 60 characters\n- no quotes or markdown\n- output the title only, no extra text';
137-157
: Title-gen SSE parsing can drop content across chunk boundaries. Buffer and decode with streaming.- let accumulated = ''; - const textDecoder = new TextDecoder(); - while (true) { - const { done, value } = await reader.read(); - if (done) break; - if (value) { - const text = textDecoder.decode(value); - for (const line of text.split('\n')) { - if (line.startsWith('data: ')) { - try { - const ev = JSON.parse(line.slice(6)); - if (ev.type === 'text-delta' && ev.textDelta) accumulated += ev.textDelta; - if (ev.type === 'finish') { - try { await reader.cancel(); } catch { } - break; - } - } catch { } - } - } - } - } + let accumulated = ''; + const decoder = new TextDecoder(); + let buffer = ''; + let finished = false; + while (true) { + const { done, value } = await reader.read(); + if (done) break; + if (!value) continue; + buffer += decoder.decode(value, { stream: true }); + const lines = buffer.split('\n'); + buffer = lines.pop() ?? ''; + for (const line of lines) { + if (!line.startsWith('data: ')) continue; + try { + const ev = JSON.parse(line.slice(6)); + if (ev.type === 'text-delta' && ev.textDelta) accumulated += ev.textDelta; + else if (ev.type === 'finish' && !finished) { + finished = true; + try { await reader.cancel(); } catch { /* ignore */ } + } + } catch { /* ignore parse */ } + } + } + // Flush any remaining buffered line + if (buffer.startsWith('data: ')) { + try { + const ev = JSON.parse(buffer.slice(6)); + if (ev.type === 'text-delta' && ev.textDelta) accumulated += ev.textDelta; + } catch { /* ignore */ } + }
162-169
: Check KV write success when persisting generated title.
setKVValue
returns{ success, statusCode }
and does not throw.- await setKVValue(sessionKey, current, { storeName: config.defaultStoreName }); + const titleResp = await setKVValue(sessionKey, current, { storeName: config.defaultStoreName }); + if (!titleResp.success) { + console.error('[title-gen] failed to persist title:', titleResp.error || titleResp.statusCode); + }
86-178
: Move title generation helper out of the route handler for testability and reuse.Define
generateAndPersistTitle
in a separate module (e.g., app/chat/services/sessionTitleService.ts) and import here.
353-359
: SSE delivery: disable proxy buffering.Add
X-Accel-Buffering: no
to improve real-time streaming behind Nginx.return new NextResponse(transformStream.readable, { headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", Connection: "keep-alive", + "X-Accel-Buffering": "no", }, });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/api/sessions/[sessionId]/messages/route.ts
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
app/api/sessions/[sessionId]/messages/route.ts (8)
app/api/sessions/route.ts (1)
POST
(75-149)app/api/sessions/[sessionId]/route.ts (1)
POST
(189-266)app/api/users/tutorial-state/route.ts (1)
POST
(39-71)lib/validation/middleware.ts (2)
parseAndValidateJSON
(35-61)SessionMessageRequestSchema
(73-76)app/chat/utils/dateUtils.ts (2)
toISOString
(10-16)getCurrentTimestamp
(35-37)lib/kv-store.ts (2)
getKVValue
(47-113)setKVValue
(122-170)lib/env.ts (1)
getAgentPulseConfig
(32-34)lib/tutorial/state-manager.ts (1)
TutorialStateManager
(5-121)
🪛 Biome (2.1.2)
app/api/sessions/[sessionId]/messages/route.ts
[error] 102-104: Do not use template literals if interpolation and special-character handling are not needed.
Safe fix: Replace with string literal
(lint/style/noUnusedTemplateLiteral)
⏰ 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: Workers Builds: docs
This reverts commit a61babf.
* add totalChunks to metadata for tracing * improve RAG retrieval process * POC UI for chat based documentation * update Start / Continue course * expand text * fix scrollbar problem and chat input resizing * adding progress tracker * center the progress bar * testing out new terminal component and websocket servert * fix terminal issue not staying on * fix weird terminal display * fix self is not defined error * remove unnecessary terminal message * typo * fix weird flow * remove duplicated butotn * playing with coding web server * remove websocket server * creating api for tutorials * fix interface * modify tutorials workflow -- vibecoded * dummy demo code execution api next.js * New pulse agent using response api tools calling * re-build the entire Pulse agent with new design * adding tutorial step workflow * simplify tutorial reader to have consistent api * cleaning up some more steps * breaking frontend to smaller components; * link doc-qa to pulse agent * removing unused import * fix chat input box and have split pane for code editor * enhancing file display * simplify chat interface -- removing unnecessary code block displays * add editor close button * make side bar icons smaller * implement chunk streaming structure * clean up some items * Revert "Implement Copy Page Dropdown Functionality (#239)" This reverts commit 5eb9f16. * fix tutorial step data handling issue * add kv store api service * remove unused interfaces * remove unneeded conversation type * reformat chat history * add kv store api * Simplify and refactor chat to connect with kv store * add uuid package * update example env * share session context * removing debug * Adding session cache with SWR * add .env to gitignore * sync with main * adjust chat message area width and dynamic spacing with sessionsbar * add code editor content * remove redundant comments * display tutorial instruction content * add user based session management * enable split pane resize * adding sessions cursor * sessions paginated loading * clean up env variables * enabling direct llm access flag * add title generation * remove session update redundancy * render session messages directly * fix streaming bug on UI * merge conflict resolution * remove tutorial agent set up that is not currently needed * remove package json * rebuilt package json and remove /api/chat and /api/terminal that were mock/test * delete dummy terminal websocket server * Add tutorial structure rules and enhance tutorial API responses - Introduced a new markdown file defining the structure and authoring guidelines for tutorials. - Updated the tutorial API to return detailed step data, including snippets and metadata. - Refactored tutorial step fetching logic to improve error handling and data retrieval. - Implemented a new `<CodeFromFiles />` component for rendering code snippets from files. - Enhanced chat message rendering to support tutorial content and snippets. * chore(lockfile): sync package-lock with package.json to fix npm ci (add data-uri-to-buffer@2.0.2) * sync package * fix build error * synchronize name of totalSteps * fix linter failure * cleaning up debug log and unused modules * remove debug log from ChatMessage * remove dummy tutorial content * simplify code pieces * add total steps * remove unused components * removing unused module * Remove integration md * replace div with interactable button * remove unused import * toIsoString formatting * gracefully handle setKVValue error * improve tool param wording * remove unused websocket server * add user tutorial status * add tutorial state management * refactor tutorial state route handlers to improve JSON body parsing and error handling * update ChatMessage component to format code snippets with labels above code fences for improved readability * remove python tutorial mdx * Fix CodeRabbit issues: implement validation middleware and improve error handling (#283) * Fix CodeRabbit issues: implement validation middleware, fix config imports, handle KV errors - Add comprehensive body validation middleware for /sessions, /tutorials, /users endpoints - Fix config import issues by moving to static imports at top of files - Add proper KV persistence error handling with success checks - Validate tutorialId as string and prevent path traversal attacks - Fix implicit any types on request body parameters - Replace parseInt with Number.parseInt for consistency - Add proper 400 error responses with detailed validation messages - Use existing types from app/chat/types.ts for validation - Prevent TypeError when no progress exists by handling 404 responses gracefully Co-Authored-By: srith@agentuity.com <rithsenghorn@gmail.com> * Fix TypeScript compilation errors in validation middleware - Add SessionMessageValidationResult and SessionMessageOnlyValidationResult types - Fix validation function return type mismatches in session routes - Add proper bounds checking for stepIndex in tutorial route - Ensure all validation errors use consistent error structure - Generate missing docs.json file to resolve import errors All TypeScript compilation errors resolved, ready for CI Co-Authored-By: srith@agentuity.com <rithsenghorn@gmail.com> * Refactor validation middleware to be generic and scalable - Add FieldSchema and ValidationSchema interfaces for declarative validation - Implement validateField and validateObject for schema-based validation - Add overloaded parseAndValidateJSON to accept both validators and schemas - Maintain backward compatibility with existing validation functions - Fix TypeScript compilation errors with explicit Message type annotations - Enable reusable validation for current and future types Co-Authored-By: srith@agentuity.com <rithsenghorn@gmail.com> * Refactor validation to use Zod schemas and eliminate duplicate source of truth - Replace TypeScript interfaces with Zod schemas in app/chat/types.ts - Derive types using z.infer<typeof Schema> instead of separate interfaces - Update validation middleware to use Zod's safeParse and error handling - Maintain all existing validation behavior while using industry-standard Zod - Fix TypeScript compilation errors and import issues - All API endpoints now use consistent Zod-based validation This eliminates the duplicate source of truth between validation schemas and TypeScript interfaces, making the codebase more maintainable and following modern best practices. Co-Authored-By: srith@agentuity.com <rithsenghorn@gmail.com> * Complete Zod migration for messages API endpoint - Replace custom validation logic with SessionMessageRequestSchema - Simplify validation code by using Zod's built-in validation - Maintain all existing functionality while using industry-standard validation Co-Authored-By: srith@agentuity.com <rithsenghorn@gmail.com> * Complete Zod migration: remove redundant interfaces and convert utility functions - Remove unused SessionMessageValidationResult and SessionMessageOnlyValidationResult interfaces - Convert validateStepNumber and validateTutorialId to use Zod schemas internally - Add StepNumberSchema and TutorialIdSchema for consistent validation - Maintain backward compatibility with existing function signatures - Complete elimination of duplicate source of truth between validation and types - All validation now uses Zod schemas as single source of truth Co-Authored-By: srith@agentuity.com <rithsenghorn@gmail.com> * delete lib/validation/types.ts unused module * defensively check tutorials state * update tools description and enhance the path checking --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: srith@agentuity.com <rithsenghorn@gmail.com> Co-authored-by: afterrburn <sun_rsh@outlook.com> * Apply suggestion from @coderabbitai[bot] Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Seng Rith <50646727+afterrburn@users.noreply.github.com> * fix typo * clean up * small fixes * revert css * remove tutorial * remove Tutorial page * remove outdated readme * remove unnecessary dependencies * remove debug logging * example of how tutorial is structured * Revert "example of how tutorial is structured" This reverts commit 6d70c4e. * move helper out of the POST body --------- Signed-off-by: Seng Rith <50646727+afterrburn@users.noreply.github.com> Co-authored-by: afterrburn <sun_rsh@outlook.com> Co-authored-by: Seng Rith <50646727+senghorn@users.noreply.github.com> Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
- Add runtime environment detection to prevent @agentuity/sdk loading in Cloudflare Workers - Implement conditional agent loader that only loads agent code in Node.js environments - Fix TypeScript errors in agent-docs tools.ts for ai package v5.0.45 API - Restore chat prototype functionality from PR #279 with instrumentation fix - Add webpack ignore rule for agent-docs to prevent build-time loading - Update tsconfig to exclude agent-docs from TypeScript compilation This resolves the 'Failed to prepare server Error: An error occurred while loading the instrumentation hook' error on agentuity.dev by preventing OpenTelemetry auto-instrumentations from loading in Cloudflare Workers runtime while preserving full chat functionality in Node.js environments. Co-Authored-By: srith@agentuity.com <rithsenghorn@gmail.com>
* add totalChunks to metadata for tracing * improve RAG retrieval process * POC UI for chat based documentation * update Start / Continue course * expand text * fix scrollbar problem and chat input resizing * adding progress tracker * center the progress bar * testing out new terminal component and websocket servert * fix terminal issue not staying on * fix weird terminal display * fix self is not defined error * remove unnecessary terminal message * typo * fix weird flow * remove duplicated butotn * playing with coding web server * remove websocket server * creating api for tutorials * fix interface * modify tutorials workflow -- vibecoded * dummy demo code execution api next.js * New pulse agent using response api tools calling * re-build the entire Pulse agent with new design * adding tutorial step workflow * simplify tutorial reader to have consistent api * cleaning up some more steps * breaking frontend to smaller components; * link doc-qa to pulse agent * removing unused import * fix chat input box and have split pane for code editor * enhancing file display * simplify chat interface -- removing unnecessary code block displays * add editor close button * make side bar icons smaller * implement chunk streaming structure * clean up some items * Revert "Implement Copy Page Dropdown Functionality (#239)" This reverts commit 5eb9f16. * fix tutorial step data handling issue * add kv store api service * remove unused interfaces * remove unneeded conversation type * reformat chat history * add kv store api * Simplify and refactor chat to connect with kv store * add uuid package * update example env * share session context * removing debug * Adding session cache with SWR * add .env to gitignore * sync with main * adjust chat message area width and dynamic spacing with sessionsbar * add code editor content * remove redundant comments * display tutorial instruction content * add user based session management * enable split pane resize * adding sessions cursor * sessions paginated loading * clean up env variables * enabling direct llm access flag * add title generation * remove session update redundancy * render session messages directly * fix streaming bug on UI * merge conflict resolution * remove tutorial agent set up that is not currently needed * remove package json * rebuilt package json and remove /api/chat and /api/terminal that were mock/test * delete dummy terminal websocket server * Add tutorial structure rules and enhance tutorial API responses - Introduced a new markdown file defining the structure and authoring guidelines for tutorials. - Updated the tutorial API to return detailed step data, including snippets and metadata. - Refactored tutorial step fetching logic to improve error handling and data retrieval. - Implemented a new `<CodeFromFiles />` component for rendering code snippets from files. - Enhanced chat message rendering to support tutorial content and snippets. * chore(lockfile): sync package-lock with package.json to fix npm ci (add data-uri-to-buffer@2.0.2) * sync package * fix build error * synchronize name of totalSteps * fix linter failure * cleaning up debug log and unused modules * remove debug log from ChatMessage * remove dummy tutorial content * simplify code pieces * add total steps * remove unused components * removing unused module * Remove integration md * replace div with interactable button * remove unused import * toIsoString formatting * gracefully handle setKVValue error * improve tool param wording * remove unused websocket server * add user tutorial status * add tutorial state management * refactor tutorial state route handlers to improve JSON body parsing and error handling * update ChatMessage component to format code snippets with labels above code fences for improved readability * remove python tutorial mdx * Fix CodeRabbit issues: implement validation middleware and improve error handling (#283) * Fix CodeRabbit issues: implement validation middleware, fix config imports, handle KV errors - Add comprehensive body validation middleware for /sessions, /tutorials, /users endpoints - Fix config import issues by moving to static imports at top of files - Add proper KV persistence error handling with success checks - Validate tutorialId as string and prevent path traversal attacks - Fix implicit any types on request body parameters - Replace parseInt with Number.parseInt for consistency - Add proper 400 error responses with detailed validation messages - Use existing types from app/chat/types.ts for validation - Prevent TypeError when no progress exists by handling 404 responses gracefully Co-Authored-By: srith@agentuity.com <rithsenghorn@gmail.com> * Fix TypeScript compilation errors in validation middleware - Add SessionMessageValidationResult and SessionMessageOnlyValidationResult types - Fix validation function return type mismatches in session routes - Add proper bounds checking for stepIndex in tutorial route - Ensure all validation errors use consistent error structure - Generate missing docs.json file to resolve import errors All TypeScript compilation errors resolved, ready for CI Co-Authored-By: srith@agentuity.com <rithsenghorn@gmail.com> * Refactor validation middleware to be generic and scalable - Add FieldSchema and ValidationSchema interfaces for declarative validation - Implement validateField and validateObject for schema-based validation - Add overloaded parseAndValidateJSON to accept both validators and schemas - Maintain backward compatibility with existing validation functions - Fix TypeScript compilation errors with explicit Message type annotations - Enable reusable validation for current and future types Co-Authored-By: srith@agentuity.com <rithsenghorn@gmail.com> * Refactor validation to use Zod schemas and eliminate duplicate source of truth - Replace TypeScript interfaces with Zod schemas in app/chat/types.ts - Derive types using z.infer<typeof Schema> instead of separate interfaces - Update validation middleware to use Zod's safeParse and error handling - Maintain all existing validation behavior while using industry-standard Zod - Fix TypeScript compilation errors and import issues - All API endpoints now use consistent Zod-based validation This eliminates the duplicate source of truth between validation schemas and TypeScript interfaces, making the codebase more maintainable and following modern best practices. Co-Authored-By: srith@agentuity.com <rithsenghorn@gmail.com> * Complete Zod migration for messages API endpoint - Replace custom validation logic with SessionMessageRequestSchema - Simplify validation code by using Zod's built-in validation - Maintain all existing functionality while using industry-standard validation Co-Authored-By: srith@agentuity.com <rithsenghorn@gmail.com> * Complete Zod migration: remove redundant interfaces and convert utility functions - Remove unused SessionMessageValidationResult and SessionMessageOnlyValidationResult interfaces - Convert validateStepNumber and validateTutorialId to use Zod schemas internally - Add StepNumberSchema and TutorialIdSchema for consistent validation - Maintain backward compatibility with existing function signatures - Complete elimination of duplicate source of truth between validation and types - All validation now uses Zod schemas as single source of truth Co-Authored-By: srith@agentuity.com <rithsenghorn@gmail.com> * delete lib/validation/types.ts unused module * defensively check tutorials state * update tools description and enhance the path checking --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: srith@agentuity.com <rithsenghorn@gmail.com> Co-authored-by: afterrburn <sun_rsh@outlook.com> * Apply suggestion from @coderabbitai[bot] Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Seng Rith <50646727+afterrburn@users.noreply.github.com> * fix typo * clean up * small fixes * revert css * remove tutorial * remove Tutorial page * remove outdated readme * remove unnecessary dependencies * remove debug logging * example of how tutorial is structured * Revert "example of how tutorial is structured" This reverts commit 6d70c4e. * move helper out of the POST body --------- Signed-off-by: Seng Rith <50646727+afterrburn@users.noreply.github.com> Co-authored-by: afterrburn <sun_rsh@outlook.com> Co-authored-by: Seng Rith <50646727+senghorn@users.noreply.github.com> Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Seng/chat prototype (#279) * add totalChunks to metadata for tracing * improve RAG retrieval process * POC UI for chat based documentation * update Start / Continue course * expand text * fix scrollbar problem and chat input resizing * adding progress tracker * center the progress bar * testing out new terminal component and websocket servert * fix terminal issue not staying on * fix weird terminal display * fix self is not defined error * remove unnecessary terminal message * typo * fix weird flow * remove duplicated butotn * playing with coding web server * remove websocket server * creating api for tutorials * fix interface * modify tutorials workflow -- vibecoded * dummy demo code execution api next.js * New pulse agent using response api tools calling * re-build the entire Pulse agent with new design * adding tutorial step workflow * simplify tutorial reader to have consistent api * cleaning up some more steps * breaking frontend to smaller components; * link doc-qa to pulse agent * removing unused import * fix chat input box and have split pane for code editor * enhancing file display * simplify chat interface -- removing unnecessary code block displays * add editor close button * make side bar icons smaller * implement chunk streaming structure * clean up some items * Revert "Implement Copy Page Dropdown Functionality (#239)" This reverts commit 5eb9f16. * fix tutorial step data handling issue * add kv store api service * remove unused interfaces * remove unneeded conversation type * reformat chat history * add kv store api * Simplify and refactor chat to connect with kv store * add uuid package * update example env * share session context * removing debug * Adding session cache with SWR * add .env to gitignore * sync with main * adjust chat message area width and dynamic spacing with sessionsbar * add code editor content * remove redundant comments * display tutorial instruction content * add user based session management * enable split pane resize * adding sessions cursor * sessions paginated loading * clean up env variables * enabling direct llm access flag * add title generation * remove session update redundancy * render session messages directly * fix streaming bug on UI * merge conflict resolution * remove tutorial agent set up that is not currently needed * remove package json * rebuilt package json and remove /api/chat and /api/terminal that were mock/test * delete dummy terminal websocket server * Add tutorial structure rules and enhance tutorial API responses - Introduced a new markdown file defining the structure and authoring guidelines for tutorials. - Updated the tutorial API to return detailed step data, including snippets and metadata. - Refactored tutorial step fetching logic to improve error handling and data retrieval. - Implemented a new `<CodeFromFiles />` component for rendering code snippets from files. - Enhanced chat message rendering to support tutorial content and snippets. * chore(lockfile): sync package-lock with package.json to fix npm ci (add data-uri-to-buffer@2.0.2) * sync package * fix build error * synchronize name of totalSteps * fix linter failure * cleaning up debug log and unused modules * remove debug log from ChatMessage * remove dummy tutorial content * simplify code pieces * add total steps * remove unused components * removing unused module * Remove integration md * replace div with interactable button * remove unused import * toIsoString formatting * gracefully handle setKVValue error * improve tool param wording * remove unused websocket server * add user tutorial status * add tutorial state management * refactor tutorial state route handlers to improve JSON body parsing and error handling * update ChatMessage component to format code snippets with labels above code fences for improved readability * remove python tutorial mdx * Fix CodeRabbit issues: implement validation middleware and improve error handling (#283) * Fix CodeRabbit issues: implement validation middleware, fix config imports, handle KV errors - Add comprehensive body validation middleware for /sessions, /tutorials, /users endpoints - Fix config import issues by moving to static imports at top of files - Add proper KV persistence error handling with success checks - Validate tutorialId as string and prevent path traversal attacks - Fix implicit any types on request body parameters - Replace parseInt with Number.parseInt for consistency - Add proper 400 error responses with detailed validation messages - Use existing types from app/chat/types.ts for validation - Prevent TypeError when no progress exists by handling 404 responses gracefully Co-Authored-By: srith@agentuity.com <rithsenghorn@gmail.com> * Fix TypeScript compilation errors in validation middleware - Add SessionMessageValidationResult and SessionMessageOnlyValidationResult types - Fix validation function return type mismatches in session routes - Add proper bounds checking for stepIndex in tutorial route - Ensure all validation errors use consistent error structure - Generate missing docs.json file to resolve import errors All TypeScript compilation errors resolved, ready for CI Co-Authored-By: srith@agentuity.com <rithsenghorn@gmail.com> * Refactor validation middleware to be generic and scalable - Add FieldSchema and ValidationSchema interfaces for declarative validation - Implement validateField and validateObject for schema-based validation - Add overloaded parseAndValidateJSON to accept both validators and schemas - Maintain backward compatibility with existing validation functions - Fix TypeScript compilation errors with explicit Message type annotations - Enable reusable validation for current and future types Co-Authored-By: srith@agentuity.com <rithsenghorn@gmail.com> * Refactor validation to use Zod schemas and eliminate duplicate source of truth - Replace TypeScript interfaces with Zod schemas in app/chat/types.ts - Derive types using z.infer<typeof Schema> instead of separate interfaces - Update validation middleware to use Zod's safeParse and error handling - Maintain all existing validation behavior while using industry-standard Zod - Fix TypeScript compilation errors and import issues - All API endpoints now use consistent Zod-based validation This eliminates the duplicate source of truth between validation schemas and TypeScript interfaces, making the codebase more maintainable and following modern best practices. Co-Authored-By: srith@agentuity.com <rithsenghorn@gmail.com> * Complete Zod migration for messages API endpoint - Replace custom validation logic with SessionMessageRequestSchema - Simplify validation code by using Zod's built-in validation - Maintain all existing functionality while using industry-standard validation Co-Authored-By: srith@agentuity.com <rithsenghorn@gmail.com> * Complete Zod migration: remove redundant interfaces and convert utility functions - Remove unused SessionMessageValidationResult and SessionMessageOnlyValidationResult interfaces - Convert validateStepNumber and validateTutorialId to use Zod schemas internally - Add StepNumberSchema and TutorialIdSchema for consistent validation - Maintain backward compatibility with existing function signatures - Complete elimination of duplicate source of truth between validation and types - All validation now uses Zod schemas as single source of truth Co-Authored-By: srith@agentuity.com <rithsenghorn@gmail.com> * delete lib/validation/types.ts unused module * defensively check tutorials state * update tools description and enhance the path checking --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: srith@agentuity.com <rithsenghorn@gmail.com> Co-authored-by: afterrburn <sun_rsh@outlook.com> * Apply suggestion from @coderabbitai[bot] Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Seng Rith <50646727+afterrburn@users.noreply.github.com> * fix typo * clean up * small fixes * revert css * remove tutorial * remove Tutorial page * remove outdated readme * remove unnecessary dependencies * remove debug logging * example of how tutorial is structured * Revert "example of how tutorial is structured" This reverts commit 6d70c4e. * move helper out of the POST body --------- Signed-off-by: Seng Rith <50646727+afterrburn@users.noreply.github.com> Co-authored-by: afterrburn <sun_rsh@outlook.com> Co-authored-by: Seng Rith <50646727+senghorn@users.noreply.github.com> Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * remove unused component * gracefully return empty array when tutorial does not exist * cleanup agent-docs readme and bun * move agent IDs to config since they are not secrets * update agent url configs * fix config issue * fix env --------- Signed-off-by: Seng Rith <50646727+afterrburn@users.noreply.github.com> Co-authored-by: afterrburn <sun_rsh@outlook.com> Co-authored-by: Seng Rith <50646727+senghorn@users.noreply.github.com> Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Summary by CodeRabbit
New Features
Documentation
Configuration
UI/Style
Chores