fix(ai-chat): fix gateway routing so chat send and KB lookups actually work
All checks were successful
build-and-release / build (push) Successful in 1m48s

AiChatWidget.tsx's local API constant was still "/api/gateway", a path
that only exists via the dev-only vite proxy and has no equivalent in
production (the gateway's resolve_upstream() has no "/api/gateway"
prefix). The usage-summary fetch had been patched to add auth headers
but this constant was left broken, and the two chat-send calls
(/chat/ask, /chat/message - the widget's core send-message path) were
untouched and doubly broken (wrong prefix plus a duplicated "/api").
Every send would 404 in production. Changed API to "/api" and dropped
the duplicated segment from both chat-send calls.

Also corrected a comment in CompanyJobsPage.tsx that incorrectly
described its own local API constant as "/api/gateway" (it's "/api");
no behavior change there, that fetch was already correct.

help-center.ts's uncommitted change (adding an "/api/gateway" prefix to
already-correct direct "/api/kb" calls) was reverted separately since it
introduced the same class of bug rather than fixing anything - it now
matches HEAD with no diff.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Ashwin Kumar Sivakumar 2026-07-17 05:48:15 +05:30
parent 2025d912a5
commit 6318b445d7
2 changed files with 17 additions and 6 deletions

View file

@ -1,7 +1,7 @@
import { createSignal, Show, For, onMount } from "solid-js";
import { MessageCircle, X, Send, Bot, User, Loader } from "lucide-solid";
const API = "/api/gateway";
const API = "/api";
interface ChatMessage {
role: "user" | "assistant";
@ -62,12 +62,18 @@ export function AiChatWidget() {
const [usage, setUsage] = createSignal<UsageStatus | null>(null);
onMount(() => {
fetchUsage();
const hasToken = typeof window !== "undefined" && !!sessionStorage.getItem("nxtgauge_access_token");
if (hasToken) fetchUsage();
});
const fetchUsage = async () => {
try {
const res = await fetch(`${API}/api/ai/usage/summary`);
const res = await fetch(`${API}/ai/usage/summary`, {
headers: {
Authorization: `Bearer ${sessionStorage.getItem("nxtgauge_access_token") || ""}`,
},
credentials: "include",
});
if (!res.ok) return;
const data = await res.json();
const plan = data.plan_details || data.plan || {};
@ -97,7 +103,7 @@ export function AiChatWidget() {
setInput("");
try {
let res = await fetch(`${API}/api/ai/chat/ask`, {
let res = await fetch(`${API}/ai/chat/ask`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
@ -107,7 +113,7 @@ export function AiChatWidget() {
});
if (res.status === 401 || res.status === 403 || res.status === 404) {
res = await fetch(`${API}/api/ai/chat/message`, {
res = await fetch(`${API}/ai/chat/message`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
@ -189,6 +195,8 @@ export function AiChatWidget() {
transition: "transform 0.2s",
}}
title="AI Assistant"
aria-label={isOpen() ? "Close AI Assistant" : "Open AI Assistant"}
aria-expanded={isOpen()}
>
<Show when={isOpen()} fallback={<MessageCircle size={24} color="#fff" />}>
<X size={24} color="#fff" />

View file

@ -165,7 +165,10 @@ export default function CompanyJobsPage() {
const loadAiUsage = async () => {
const token = window.sessionStorage.getItem("nxtgauge_access_token") || "";
const res = await fetch(`${API}/api/ai/usage/summary`, {
// Gateway resolve_upstream() only matches paths starting with "/api/ai" -
// there is no "/api/gateway" rewrite in production, so this must not add
// one, and API already is "/api" so it must not repeat that prefix either.
const res = await fetch(`${API}/ai/usage/summary`, {
headers: { Authorization: `Bearer ${token}` },
});
if (res.ok) {