Repository navigation
Harden StudentHubHelp chatbot reliability and controls - #20
StudentHubHelp wants to merge 95 commits into
Conversation
Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
| permissions: | ||
| contents: write |
There was a problem hiding this comment.
Suggestion: This grants write access to the token in pull-request runs while npm install executes PR-controlled lifecycle scripts, letting those scripts push arbitrary commits to the repository.
Assessment: 🔴 Critical · 🔁 Occurrence: Rarely · 🏷️ Security
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** .github/workflows/chatbot-pr-check.yml
**Line:** 21:22
**Comment:**
*Security: This grants write access to the token in pull-request runs while `npm install` executes PR-controlled lifecycle scripts, letting those scripts push arbitrary commits to the repository.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| git add package-lock.json | ||
| if ! git diff --cached --quiet; then | ||
| git commit -m "chore(chatbot): patch audited dependencies [skip ci]" | ||
| git push origin "HEAD:$TARGET_BRANCH" |
There was a problem hiding this comment.
Suggestion: push and pull_request both run for this branch; if npm update changes the lockfile, both workflows push from the same parent, so one push is rejected and its check fails.
Assessment: 🟠 Major · 🔁 Occurrence: Rarely · 🏷️ Race condition
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** .github/workflows/chatbot-pr-check.yml
**Line:** 64:64
**Comment:**
*Race Condition: `push` and `pull_request` both run for this branch; if `npm update` changes the lockfile, both workflows push from the same parent, so one push is rejected and its check fails.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| onClick={() => { | ||
| if (onSendQuery) { | ||
| onSendQuery(`Mera monthly budget ₹${sliderBudget} hai, isme best verified hostel aur tiffin combo suggest karo`); | ||
| onSendQuery(`Mera monthly budget ₹${sliderBudget} hai, ${initialPlan.city ? initialPlan.city + " mein " : ""}best verified hostel aur tiffin combo suggest karo`); |
There was a problem hiding this comment.
Suggestion: This request asks for verified listings, but the combo search selects active, priced rows without filtering verified, so unverified options can be returned.
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes · 🏷️ Api mismatch
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** ai-chatbot/src/components/BudgetPlannerCard.tsx
**Line:** 288:288
**Comment:**
*Api Mismatch: This request asks for verified listings, but the combo search selects active, priced rows without filtering `verified`, so unverified options can be returned.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| if (!SUPABASE_ANON_KEY) throw new Error('Missing VITE_SUPABASE_ANON_KEY. Add the public Supabase anon/publishable key to the Vite build environment.'); | ||
| const controller = new AbortController(); const timeoutId = window.setTimeout(() => controller.abort(), 20000); let res: Response; | ||
| const clientCoords = asksForNearbyLocation(text) ? await getUserDeviceLocation() : null; | ||
| const controller = new AbortController(); const timeoutId = window.setTimeout(() => controller.abort(), 15000); let res: Response; |
There was a problem hiding this comment.
Suggestion: The abort timer is cleared once response headers arrive, before res.json() consumes the body; a stalled body leaves loading stuck with no retry.
Assessment: 🟠 Major · 🔁 Occurrence: Rarely · 🏷️ Possible bug
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** ai-chatbot/src/components/ChatWidget.tsx
**Line:** 152:152
**Comment:**
*Possible Bug: The abort timer is cleared once response headers arrive, before `res.json()` consumes the body; a stalled body leaves loading stuck with no retry.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| const hostelCap=Math.floor(totalBudget*0.70),tiffinCap=Math.floor(totalBudget*0.35); | ||
| const [hostelRows,tiffinRows]=await Promise.all([direct("hostel",cityName,hostelCap,undefined,genderFilter),direct("tiffin",cityName,tiffinCap)]); |
There was a problem hiding this comment.
Suggestion: The per-category caps discard valid pairs before checking the total: a hostel costing 75% and tiffin costing 20% fits the budget but is excluded by the 70% hostel cap.
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes · 🏷️ Logic error
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** supabase/functions/studenthubhelp-chat/index.ts
**Line:** 63:64
**Comment:**
*Logic Error: The per-category caps discard valid pairs before checking the total: a hostel costing 75% and tiffin costing 20% fits the budget but is excluded by the 70% hostel cap.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| const pricedHostels=hostels.map(p=>({p,cost:monthlyAmount(p,"hostel")})).filter(x=>x.cost!==undefined) as Array<{p:any;cost:number}>; | ||
| const pricedTiffins=tiffins.map(p=>({p,cost:monthlyAmount(p,"tiffin")})).filter(x=>x.cost!==undefined) as Array<{p:any;cost:number}>; | ||
| let best:{hostel:any;tiffin:any;hostelCost:number;tiffinCost:number;total:number;score:number}|undefined; | ||
| for(const h of pricedHostels)for(const t of pricedTiffins){const total=h.cost+t.cost;if(total>totalBudget)continue;const score=Math.abs(h.cost-totalBudget*0.65)+Math.abs(t.cost-totalBudget*0.35)+(totalBudget-total)*0.15;if(!best||score<best.score)best={hostel:h.p,tiffin:t.p,hostelCost:h.cost,tiffinCost:t.cost,total,score}} |
There was a problem hiding this comment.
Suggestion: The UI requests a “verified” combo, but this selection scores all active priced rows without checking verified, so an unverified hostel or tiffin can be returned.
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes · 🏷️ Incorrect condition logic
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** supabase/functions/studenthubhelp-chat/index.ts
**Line:** 69:69
**Comment:**
*Incorrect Condition Logic: The UI requests a “verified” combo, but this selection scores all active priced rows without checking `verified`, so an unverified hostel or tiffin can be returned.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| for(const h of pricedHostels)for(const t of pricedTiffins){const total=h.cost+t.cost;if(total>totalBudget)continue;const score=Math.abs(h.cost-totalBudget*0.65)+Math.abs(t.cost-totalBudget*0.35)+(totalBudget-total)*0.15;if(!best||score<best.score)best={hostel:h.p,tiffin:t.p,hostelCost:h.cost,tiffinCost:t.cost,total,score}} | ||
| return best; | ||
| } | ||
| function genderWanted(s:string){const x=n(normalizeSearchTerms(s));if(/\b(girls|girl|female|ladki|ladkiyo|ladkiyon|महिला|लड़क|लड़की|girls hostel)\b/i.test(x))return "girls";if(/\b(boys|boy|male|ladke|ladkon|लड़के|लड़का|boys hostel)\b/i.test(x))return "boys";return ""} |
There was a problem hiding this comment.
Suggestion: \\b uses ASCII word boundaries, so Devanagari alternatives such as महिला and लड़के do not match; offline searches can omit the requested gender filter and show the wrong listings.
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes · 🏷️ Incorrect condition logic
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** supabase/functions/studenthubhelp-chat/index.ts
**Line:** 72:72
**Comment:**
*Incorrect Condition Logic: `\\b` uses ASCII word boundaries, so Devanagari alternatives such as `महिला` and `लड़के` do not match; offline searches can omit the requested gender filter and show the wrong listings.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| return "Main bina external AI API key ke live StudentHubHelp listings, location-based search, booking guidance aur kuch common study/general questions handle kar sakta hoon. Is sawaal ka reliable jawab dene ke liye thoda aur context ya specific question bhej dijiye 😊"; | ||
| } | ||
| async function aiGeneral(msg:string,history:any[]){const offline=offlineGeneralReply(msg);if(!GEMINI||offline!=="Main bina external AI API key ke live StudentHubHelp listings, location-based search, booking guidance aur kuch common study/general questions handle kar sakta hoon. Is sawaal ka reliable jawab dene ke liye thoda aur context ya specific question bhej dijiye 😊")return{reply:offline,webGrounded:false,webSources:[]};try{const h=history.slice(-8).map(x=>({role:x.role==="assistant"?"model":"user",parts:[{text:String(x.text||"").slice(0,1500)}]}));const system=`You are StudentHubHelp's Ultra Advance AI Assistant for students. | ||
| async function aiGeneral(msg:string,history:any[],cfg:ChatbotRuntimeConfig=DEFAULT_RUNTIME_CONFIG,deadlineAt?:number){const offline=offlineGeneralReply(msg);if(!GEMINI||offline!=="Main bina external AI API key ke live StudentHubHelp listings, location-based search, booking guidance aur kuch common study/general questions handle kar sakta hoon. Is sawaal ka reliable jawab dene ke liye thoda aur context ya specific question bhej dijiye 😊")return{reply:offline,webGrounded:false,webSources:[]};try{const h=history.slice(-8).map(x=>({role:x.role==="assistant"?"model":"user",parts:[{text:String(x.text||"").slice(0,1500)}]}));const system=`You are StudentHubHelp's Ultra Advance AI Assistant for students. |
There was a problem hiding this comment.
Suggestion: React sends assistant history with role model, but this mapper treats every non-assistant role as user; Gemini then receives prior assistant text as user statements.
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes · 🏷️ Api mismatch
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** supabase/functions/studenthubhelp-chat/index.ts
**Line:** 282:282
**Comment:**
*Api Mismatch: React sends assistant history with role `model`, but this mapper treats every non-`assistant` role as `user`; Gemini then receives prior assistant text as user statements.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| const previous=history.filter(x=>x.role==="user").map(x=>x.text||"").join(" "),combined=previous+" "+msg,aiRaw=await aiUnderstand(msg,history),u=mergeIntent(aiRaw,msg,history),explicitCat=cat(msg),nearCats=secondaryCats(msg),aiCats=u.categories||[],c=u.category||explicitCat||(u.followUp?cat(previous):""),propertyMode=u.intent.startsWith("property_")||isPropertyQuery(msg,u.followUp?previous:""),ct=u.city||(u.followUp?city(previous):""),near=u.landmark||u.area||u.locality||(u.nearRelation?nearTerm(msg):""),locationForFilter=strictLocation(msg),action=String(b?.action||u.action||""),shownList=(Array.isArray(b?.shownPropertyIds)?b.shownPropertyIds:[]).map((x:any)=>String(x)),shownIds=new Set(shownList); | ||
| const previous=history.filter(x=>x.role==="user").map(x=>x.text||"").join(" "),combined=previous+" "+msg,aiRaw=await aiUnderstand(msg,history,cfg,requestDeadlineAt),u=mergeIntent(aiRaw,msg,history),explicitCat=cat(msg),nearCats=secondaryCats(msg),multiCategoryRequest=/(?:\b(?:and|plus|with)\b|\+|\baur\b|और)/i.test(n(msg)),detectedCats=["hostel","tiffin","library","cafe","bookstore"].filter(type=>new RegExp(type==="hostel"?"hostel|\\bpg\\b|हॉस्टल|पीजी":type==="tiffin"?"tiffin|mess|meal|टिफिन|मेस":type==="library"?"library|reading room|लाइब्रेरी":type==="cafe"?"cafe|कैफे":"bookstore|book shop|stationery|बुकस्टोर","i").test(n(msg))),aiCats=explicitCat&&!multiCategoryRequest?[explicitCat]:[...new Set([...(u.categories||[]),...detectedCats])],c=explicitCat&&!multiCategoryRequest?explicitCat:(u.category||explicitCat||(u.followUp?cat(previous):"")),propertyMode=u.intent.startsWith("property_")||isPropertyQuery(msg,u.followUp?previous:""),ct=u.city||(u.followUp?city(previous):""),near=u.landmark||u.area||u.locality||(u.nearRelation?nearTerm(msg):""),locationForFilter=strictLocation(msg),action=String(b?.action||u.action||""),shownList=(Array.isArray(b?.shownPropertyIds)?b.shownPropertyIds:[]).map((x:any)=>String(x)),shownIds=new Set(shownList); | ||
| const clientCoords=coords(b?.clientCoords); | ||
| const genericNearbyIntent=/(?:\bnear me\b|\bnearby\b|\bnearest\b|mere paas|mere pass|mere aas paas|aas paas|पास में|मेरे पास)/i.test(n(msg))&&!u.landmark&&!u.area&&!u.locality&&!nearTerm(msg); |
There was a problem hiding this comment.
Suggestion: nearTerm captures hostel in “Mere paas hostel dikhao,” making this condition false; without GPS, the handler skips the location prompt and searches hostels globally.
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes · 🏷️ Incorrect condition logic
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** supabase/functions/studenthubhelp-chat/index.ts
**Line:** 355:355
**Comment:**
*Incorrect Condition Logic: `nearTerm` captures `hostel` in “Mere paas hostel dikhao,” making this condition false; without GPS, the handler skips the location prompt and searches hostels globally.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| return await chatResponse({reply,intent:"Combined Budget Plan",primaryTopic:"Hostel + Tiffin Combo Budget",budgetPlan,recommendedProperties:[hostelCard,tiffinCard],recommendations:[hostelCard,tiffinCard],suggestedFollowUps:["Hostel ki full details batao","Tiffin ki full details batao","Aur combo options dikhao"],grounded:true,sessionId,targetCity:ct,targetCategory:"hostel+tiffin"},{headers:H},sessionId,msg); | ||
| } | ||
| let rows=await multiDirect(aiCats.length?aiCats:(c?[c]:(nearCats.length?nearCats:["hostel"])),ct,u.budgetMax??undefined,u.area||u.locality||undefined,u.gender||genderWanted(msg)); | ||
| if(clientCoords)for(const p of rows){const d=distanceKm(clientCoords,p);if(d!==undefined)p._distanceKm=d} |
There was a problem hiding this comment.
Suggestion: GPS distance only affects ranking; no radius removes distant rows. When no close listing exists, an arbitrary far-away listing can still be returned as a nearby match.
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes · 🏷️ Incorrect condition logic
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** supabase/functions/studenthubhelp-chat/index.ts
**Line:** 448:448
**Comment:**
*Incorrect Condition Logic: GPS distance only affects ranking; no radius removes distant rows. When no close listing exists, an arbitrary far-away listing can still be returned as a nearby match.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
|
User description
Scope
Hardens the existing StudentHubHelp chatbot on the isolated branch
fix/chatbot-reliability-security. Website pages, Add Listing flow, and unrelated admin/property workflows are not changed. The Edge Function is not deployed and this PR is not merged.Implemented
private.chatbot_rate_limitstable and a restrictedservice_role-only RPC. The migration was applied to Supabase production and verified: anon/authenticated cannot execute the RPC; service_role can. A concurrent smoke test with 8 requests and a limit of 2 allowed exactly 2 and blocked 6.cf-connecting-ipno longer causes every normal user to receive 503. The fallback uses a low-limit, explicitly untrustedx-forwarded-forkey plus session/user-agent keys. This is weaker than a verified Cloudflare IP and must still be checked after Edge Function deployment.hostelsandtiffinstables, respects city/gender and known monthly prices, and returns a bundle budget plan only when the admin planner toggle is enabled.widget.js, and bundledai-chatbot/public/widget.jspass optional GPS coordinates and gracefully handle permission/API errors.hi-IN; unsupported browsers show a typed-input fallback instead of crashing..env.productionand enforced in production builds; the embed-code generator now emits the same Edge Function URL.npm run dev:legacy-server;npm startserves only the static Vite preview.Dependency remediation
npm audit: vulnerable transitivebody-parser,proxy-addr,qs,source-map-js, and direct Vite 6.4.3.npm update(no--force), persists the updated lockfile, then runsnpm audit.Validation
Production / rollout
20261108164241_chatbot_distributed_rate_limithas been applied and smoke-tested.widget.jshave not been deployed to production.ai-chatbot/tests/chatbot-regression.mjswithCHATBOT_TEST_URLandSUPABASE_ANON_KEY, verifycf-connecting-ip, then approve production Edge Function deployment.CodeAnt-AI Description
Make chatbot recommendations more accurate and easier to recover when requests fail
What Changed
Impact
✅ Fewer out-of-city and over-budget recommendations✅ Nearby results with clearer distance evidence✅ Retry temporary chat failures without retyping💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.