Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
553 changes: 308 additions & 245 deletions package-lock.json

Large diffs are not rendered by default.

34 changes: 17 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "agent-web",
"private": true,
"version": "5.12.1",
"version": "5.12.3",
"type": "module",
"scripts": {
"clean": "rm -rf dist .vite node_modules/.vite",
Expand All @@ -27,50 +27,50 @@
"@radix-ui/react-switch": "^1.2.6",
"@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-tooltip": "^1.2.8",
"@tailwindcss/vite": "^4.2.2",
"@tailwindcss/vite": "^4.3.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"embla-carousel-react": "^8.6.0",
"input-otp": "^1.4.2",
"jwt-decode": "^4.0.0",
"lucide-react": "^1.8.0",
"lucide-react": "^1.14.0",
"make-plural": "^8.1.0",
"next-themes": "^0.4.6",
"radix-ui": "^1.4.3",
"react": "^19.2.5",
"react-dom": "^19.2.5",
"react-router-dom": "^7.14.0",
"react": "^19.2.6",
"react-dom": "^19.2.6",
"react-router-dom": "^7.15.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.5.0",
"tailwindcss": "^4.2.2",
"tailwind-merge": "^3.6.0",
"tailwindcss": "^4.3.0",
"vaul": "^1.1.2"
},
"devDependencies": {
"@eslint/js": "^9.39.4",
"@tailwindcss/postcss": "^4.2.2",
"@types/node": "^25.6.0",
"@tailwindcss/postcss": "^4.3.0",
"@types/node": "^25.6.2",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@types/react-router-dom": "^5.3.3",
"@vitejs/plugin-react": "^6.0.1",
"autoprefixer": "^10.4.27",
"autoprefixer": "^10.5.0",
"eslint": "^9.39.4",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.2",
"globals": "^17.4.0",
"globals": "^17.6.0",
"postcss-custom-media": "^12.0.1",
"postcss-custom-properties": "^15.0.1",
"postcss-custom-selectors": "^9.0.1",
"postcss-import": "^16.1.1",
"postcss-nesting": "^14.0.0",
"postcss-theme-ui": "^0.10.0",
"shadcn": "^4.2.0",
"stylelint": "17.6.0",
"shadcn": "^4.7.0",
"stylelint": "17.11.0",
"stylelint-config-standard": "^40.0.0",
"stylelint-config-tailwindcss": "^1.0.1",
"tw-animate-css": "^1.4.0",
"typescript": "~5.8.3",
"typescript-eslint": "^8.58.1",
"vite": "^8.0.2"
"typescript-eslint": "^8.59.2",
"vite": "^8.0.11"
}
}
1 change: 1 addition & 0 deletions src/components/ProvidersCarousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const ProvidersCarousel: React.FC<ProvidersCarouselProps> = ({
React.useEffect(() => {
if (!api) return;

// eslint-disable-next-line react-hooks/set-state-in-effect
setCanScrollPrev(api.canScrollPrev());
setCanScrollNext(api.canScrollNext());

Expand Down
1 change: 1 addition & 0 deletions src/components/ui/carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ function Carousel({

React.useEffect(() => {
if (!api) return;
// eslint-disable-next-line react-hooks/set-state-in-effect
onSelect(api);
api.on("reInit", onSelect);
api.on("select", onSelect);
Expand Down
14 changes: 7 additions & 7 deletions src/hooks/useChats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ export const useChats = (
const [error, setError] = useState<Error | null>(null);

useEffect(() => {
if (!userId || !rawToken) {
setChats([]);
setIsLoading(false);
setError(null);
return;
}

const fetchChats = async () => {
if (!userId || !rawToken) {
setChats([]);
setIsLoading(false);
setError(null);
return;
}

if (areChatsCached(userId)) {
const cachedChats = getCachedChats(userId);
if (cachedChats) {
Expand Down
2 changes: 2 additions & 0 deletions src/hooks/useExternalTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const useExternalTools = (

const fetchTools = useCallback(
async (forceRefresh = false) => {
await Promise.resolve();
if (!userId || !rawToken) {
setExternalTools(null);
return;
Expand Down Expand Up @@ -60,6 +61,7 @@ export const useExternalTools = (
);

useEffect(() => {
// eslint-disable-next-line react-hooks/set-state-in-effect
fetchTools();
}, [fetchTools]);

Expand Down
2 changes: 2 additions & 0 deletions src/hooks/useUserSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const useUserSettings = (

const fetchSettings = useCallback(
async (forceRefresh = false) => {
await Promise.resolve();
if (!userId || !rawToken) {
setUserSettings(null);
return;
Expand Down Expand Up @@ -64,6 +65,7 @@ export const useUserSettings = (

// Initial fetch
useEffect(() => {
// eslint-disable-next-line react-hooks/set-state-in-effect
fetchSettings();
}, [fetchSettings]);

Expand Down
9 changes: 3 additions & 6 deletions src/pages/AccessSettingsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,9 @@ const AccessSettingsPage: React.FC = () => {
const hasLoadedOnce = useRef(false);
const indexToRestore = useRef<number | null>(null);

// Initialize local editing state when remote settings first load
useEffect(() => {
if (remoteSettings && !userSettings) {
setUserSettings(remoteSettings);
}
}, [remoteSettings, userSettings]);
if (remoteSettings && !userSettings) {
setUserSettings(remoteSettings);
}

// Fetch external tools and check sponsorship when session and settings are ready
useEffect(() => {
Expand Down
22 changes: 10 additions & 12 deletions src/pages/ChatSettingsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState, useRef } from "react";
import React, { useState, useRef } from "react";
import { useParams } from "react-router-dom";
import BaseSettingsPage, {
BaseSettingsPageRef,
Expand Down Expand Up @@ -53,18 +53,16 @@ const ChatSettingsPage: React.FC = () => {
null,
);

// Seed form state from the chat list once it resolves
useEffect(() => {
if (!accessToken || isChatsLoading || !chat_id || error?.isBlocker) return;
if (chatSettings && chatSettings.chat_config.chat_id === chat_id) return;
const found = chats.find((chat) => chat.chat_config.chat_id === chat_id);
if (!found) {
setError(PageError.blocker("error_codes.chat_not_found"));
return;
if (accessToken && !isChatsLoading && chat_id && !error?.isBlocker) {
if (!(chatSettings?.chat_config.chat_id === chat_id)) {
if (selectedChat) {
setChatSettings(selectedChat);
setRemoteSettings(selectedChat);
} else {
setError(PageError.blocker("error_codes.chat_not_found"));
}
}
setChatSettings(found);
setRemoteSettings(found);
}, [accessToken, isChatsLoading, chats, chat_id, chatSettings, error, setError]);
}

// prettier-ignore
const areSettingsChanged = !!(
Expand Down
27 changes: 11 additions & 16 deletions src/pages/IntelligenceSettingsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,9 @@ const IntelligenceSettingsPage: React.FC = () => {
const [selectedPreset, setSelectedPreset] = useState<ToolPreset | null>(null);
const [isWarningDismissed, setIsWarningDismissed] = useState(false);

// Initialize local editing state when remote settings first load
useEffect(() => {
if (remoteSettings && !userSettings) {
setUserSettings(remoteSettings);
}
}, [remoteSettings, userSettings]);

// Detect current preset when both settings and presets are available (only on initial load)
useEffect(() => {
if (remoteSettings && externalToolsData?.presets && selectedPreset === null) {
setSelectedPreset(detectCurrentPreset(remoteSettings, externalToolsData.presets));
}
}, [remoteSettings, externalToolsData, selectedPreset]);
if (remoteSettings && !userSettings) {
setUserSettings(remoteSettings);
}

// Check sponsorship and set blocker error if sponsored
useEffect(() => {
Expand All @@ -89,10 +79,15 @@ const IntelligenceSettingsPage: React.FC = () => {
areSettingsChanged(userSettings, remoteSettings)
);

const presets = externalToolsData?.presets;

if (remoteSettings && presets && selectedPreset === null) {
setSelectedPreset(detectCurrentPreset(remoteSettings, presets));
}
const remotePreset = useMemo(() => {
if (!remoteSettings || !externalToolsData?.presets) return null;
return detectCurrentPreset(remoteSettings, externalToolsData.presets);
}, [remoteSettings, externalToolsData?.presets]);
if (!remoteSettings || !presets) return null;
return detectCurrentPreset(remoteSettings, presets);
}, [remoteSettings, presets]);

const handleSave = async () => {
if (!userSettings || !remoteSettings || !user_id || !accessToken || !externalToolsData) return;
Expand Down
14 changes: 7 additions & 7 deletions src/pages/OnboardingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,20 +78,20 @@ const OnboardingPage: React.FC = () => {
const [fullName, setFullName] = useState("");
const [aboutMe, setAboutMe] = useState("");
const [customPrompt, setCustomPrompt] = useState("");
const [hasSyncedRemote, setHasSyncedRemote] = useState(false);
const [selectedPreset, setSelectedPreset] = useState<IntelligencePreset | null>(
"agent_choice",
);
const [accessChoice, setAccessChoice] = useState<AccessChoice | null>(null);
const [currentStep, setCurrentStep] = useState(0);
const [carouselApi, setCarouselApi] = useState<CarouselApi | undefined>();

useEffect(() => {
if (remoteSettings) {
setFullName(remoteSettings.full_name || "");
setAboutMe(remoteSettings.about_me || "");
setCustomPrompt(remoteSettings.custom_prompt || "");
}
}, [remoteSettings]);
if (remoteSettings && !hasSyncedRemote) {
setFullName(remoteSettings.full_name || "");
setAboutMe(remoteSettings.about_me || "");
setCustomPrompt(remoteSettings.custom_prompt || "");
setHasSyncedRemote(true);
}

useEffect(() => {
if (!carouselApi) return;
Expand Down
92 changes: 46 additions & 46 deletions src/pages/UsagePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,52 @@ const UsagePage: React.FC = () => {
loadProducts();
}, [accessToken, user_id]);

const getDateRange = (range: TimeRange): { start: Date | null; end: Date | null } => {
const now = new Date();

if (range === "all") {
return { start: null, end: null };
}

const msPerMinute = 60 * 1000;
const msPerHour = 60 * msPerMinute;
const msPerDay = 24 * msPerHour;

switch (range) {
case "10min":
return { start: new Date(Date.now() - 10 * msPerMinute), end: now };
case "30min":
return { start: new Date(Date.now() - 30 * msPerMinute), end: now };
case "1h":
return { start: new Date(Date.now() - msPerHour), end: now };
case "3h":
return { start: new Date(Date.now() - 3 * msPerHour), end: now };
case "6h":
return { start: new Date(Date.now() - 6 * msPerHour), end: now };
case "12h":
return { start: new Date(Date.now() - 12 * msPerHour), end: now };
case "today": {
const startOfToday = new Date();
startOfToday.setUTCHours(0, 0, 0, 0);
return { start: startOfToday, end: now };
}
case "yesterday": {
const startOfToday = new Date();
startOfToday.setUTCHours(0, 0, 0, 0);
const startOfYesterday = new Date(startOfToday.getTime() - msPerDay);
return { start: startOfYesterday, end: startOfToday };
}
case "week":
return { start: new Date(Date.now() - 7 * msPerDay), end: now };
case "2weeks":
return { start: new Date(Date.now() - 14 * msPerDay), end: now };
case "month":
return { start: new Date(Date.now() - 30 * msPerDay), end: now };
default:
return { start: null, end: null };
}
};

useEffect(() => {
if (!accessToken || !user_id || error) return;

Expand Down Expand Up @@ -194,52 +240,6 @@ const UsagePage: React.FC = () => {
dataRefreshCounter,
]);

const getDateRange = (range: TimeRange): { start: Date | null; end: Date | null } => {
const now = new Date();

if (range === "all") {
return { start: null, end: null };
}

const msPerMinute = 60 * 1000;
const msPerHour = 60 * msPerMinute;
const msPerDay = 24 * msPerHour;

switch (range) {
case "10min":
return { start: new Date(Date.now() - 10 * msPerMinute), end: now };
case "30min":
return { start: new Date(Date.now() - 30 * msPerMinute), end: now };
case "1h":
return { start: new Date(Date.now() - msPerHour), end: now };
case "3h":
return { start: new Date(Date.now() - 3 * msPerHour), end: now };
case "6h":
return { start: new Date(Date.now() - 6 * msPerHour), end: now };
case "12h":
return { start: new Date(Date.now() - 12 * msPerHour), end: now };
case "today": {
const startOfToday = new Date();
startOfToday.setUTCHours(0, 0, 0, 0);
return { start: startOfToday, end: now };
}
case "yesterday": {
const startOfToday = new Date();
startOfToday.setUTCHours(0, 0, 0, 0);
const startOfYesterday = new Date(startOfToday.getTime() - msPerDay);
return { start: startOfYesterday, end: startOfToday };
}
case "week":
return { start: new Date(Date.now() - 7 * msPerDay), end: now };
case "2weeks":
return { start: new Date(Date.now() - 14 * msPerDay), end: now };
case "month":
return { start: new Date(Date.now() - 30 * msPerDay), end: now };
default:
return { start: null, end: null };
}
};

const handleLoadMore = async () => {
if (!accessToken || !user_id || isLoadingMore) return;

Expand Down
Loading