@nexo-labs/chat-agent 1.6.17 → 1.6.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/react.d.mts +73 -0
  2. package/dist/react.d.mts.map +1 -0
  3. package/dist/{index.mjs → react.mjs} +4 -280
  4. package/dist/react.mjs.map +1 -0
  5. package/dist/{index.d.mts → server.d.mts} +3 -72
  6. package/dist/server.d.mts.map +1 -0
  7. package/dist/server.mjs +280 -0
  8. package/dist/server.mjs.map +1 -0
  9. package/package.json +14 -8
  10. package/src/components/ChatInput.tsx +40 -0
  11. package/src/components/ChatInterface.tsx +199 -0
  12. package/src/components/ChatMenuDropdown.tsx +154 -0
  13. package/src/components/ChatMessages.tsx +103 -0
  14. package/src/components/DocumentSelector.tsx +292 -0
  15. package/src/components/FloatingChatManager.tsx +45 -0
  16. package/src/components/FloatingChatPanel.tsx +172 -0
  17. package/src/components/MainButton.tsx +98 -0
  18. package/src/components/SourcesList.tsx +410 -0
  19. package/src/components/UsageDisplay.tsx +47 -0
  20. package/src/components/buttons/FloatingChatButton.tsx +37 -0
  21. package/src/components/buttons/ViewMoreLink.tsx +55 -0
  22. package/src/components/chat-context.tsx +168 -0
  23. package/src/components/icons/ArticleIcon.tsx +28 -0
  24. package/src/components/icons/BookIcon.tsx +26 -0
  25. package/src/components/icons/ChevronDownIcon.tsx +26 -0
  26. package/src/components/icons/CloseXIcon.tsx +33 -0
  27. package/src/components/icons/ExpandIcon.tsx +32 -0
  28. package/src/components/icons/ListIcon.tsx +23 -0
  29. package/src/components/icons/SearchIcon.tsx +25 -0
  30. package/src/components/icons/index.ts +7 -0
  31. package/src/components/index.ts +4 -0
  32. package/src/components/useDocumentSelector.ts +185 -0
  33. package/src/hooks/useChatMessages.ts +317 -0
  34. package/src/hooks/useChatSession.ts +118 -0
  35. package/src/hooks/useChunkLoader.ts +125 -0
  36. package/src/index.ts +6 -0
  37. package/src/react.ts +5 -0
  38. package/src/server.ts +20 -0
  39. package/src/types/components.tsx +54 -0
  40. package/src/usage/limits.ts +284 -0
  41. package/src/usage/token-calculator.ts +188 -0
  42. package/dist/index.d.mts.map +0 -1
  43. package/dist/index.mjs.map +0 -1
@@ -0,0 +1,73 @@
1
+ import React, { ReactNode } from "react";
2
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
3
+ import { BaseUser } from "@nexo-labs/payload-stripe-inventory";
4
+
5
+ //#region src/components/chat-context.d.ts
6
+
7
+ declare const ChatProvider: ({
8
+ children
9
+ }: {
10
+ children: ReactNode;
11
+ }) => react_jsx_runtime0.JSX.Element;
12
+ //#endregion
13
+ //#region src/types/components.d.ts
14
+ /**
15
+ * Props for a Link component that can be injected
16
+ * Compatible with next/link and regular <a> tags
17
+ */
18
+ interface LinkComponentProps {
19
+ href: string;
20
+ children: React.ReactNode;
21
+ onClick?: () => void;
22
+ className?: string;
23
+ target?: string;
24
+ 'aria-label'?: string;
25
+ }
26
+ /**
27
+ * Type for a Link component that can be injected from outside
28
+ * Default fallback is a regular <a> tag
29
+ */
30
+ type LinkComponent = React.ComponentType<LinkComponentProps>;
31
+ /**
32
+ * Props for an Image component that can be injected
33
+ * Compatible with next/image and regular <img> tags
34
+ */
35
+ interface ImageComponentProps {
36
+ src: string;
37
+ alt: string;
38
+ width?: number;
39
+ height?: number;
40
+ className?: string;
41
+ }
42
+ /**
43
+ * Type for an Image component that can be injected from outside
44
+ * Default fallback is a regular <img> tag
45
+ */
46
+ type ImageComponent = React.ComponentType<ImageComponentProps>;
47
+ //#endregion
48
+ //#region src/components/FloatingChatManager.d.ts
49
+ interface FloatingChatManagerProps {
50
+ aiIcon: string;
51
+ useUser: () => {
52
+ user: BaseUser | null;
53
+ };
54
+ generateHref: (props: {
55
+ type: string;
56
+ value: {
57
+ id: number;
58
+ slug?: string | null;
59
+ };
60
+ }) => string;
61
+ LinkComponent?: LinkComponent;
62
+ ImageComponent?: ImageComponent;
63
+ }
64
+ declare const FloatingChatManager: ({
65
+ aiIcon,
66
+ useUser,
67
+ generateHref,
68
+ LinkComponent,
69
+ ImageComponent
70
+ }: FloatingChatManagerProps) => react_jsx_runtime0.JSX.Element | null;
71
+ //#endregion
72
+ export { ChatProvider, FloatingChatManager };
73
+ //# sourceMappingURL=react.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.d.mts","names":[],"sources":["../src/components/chat-context.tsx","../src/types/components.tsx","../src/components/FloatingChatManager.tsx"],"sourcesContent":[],"mappings":";;;;;;AEgByB,cFuBZ,YEvBY,EAAA,CAAA;EAAA;CAAA,EAAA;EAAA,QAAA,EFuB8B,SEvB9B;CAAA,EAAA,GFuByC,kBAAA,CAAA,GAAA,CAAA,OEvBzC;;;;;;;AFuBZ,UCjCI,kBAAA,CDyJhB;EAxHwB,IAAA,EAAA,MAAA;EAA8B,QAAA,EC/B3C,KAAA,CAAM,SD+BqC;EAAW,OAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAwHjE,SAAA,CAAA,EAAA,MAAA;;;;ACzJD;AAaA;AAMA;AAYA;KAlBY,aAAA,GAAgB,KAAA,CAAM,cAAc;;;ACbsB;;AAMpD,UDaD,mBAAA,CCbC;EACC,GAAA,EAAA,MAAA;EAAc,GAAA,EAAA,MAAA;EAG3B,KAAA,CAAA,EAAA,MAAA;EAAmB,MAAA,CAAA,EAAA,MAAA;EAAA,SAAA,CAAA,EAAA,MAAA;;;;;;AAME,KDef,cAAA,GAAiB,KAAA,CAAM,aCfR,CDesB,mBCftB,CAAA;;;UAdjB,wBAAA;;;IF+BG,IAAA,EE7BY,QFqJxB,GAAA,IAAA;EAxHwB,CAAA;EAA8B,YAAA,EAAA,CAAA,KAAA,EAAA;IAAW,IAAA,EAAA,MAAA;IAwHjE,KAAA,EAAA;;;;ECzJgB,CAAA,EAAA,GAAA,MAAA;EAaL,aAAA,CAAA,ECPM,aDO8B;EAM/B,cAAA,CAAA,ECZE,cDYiB;AAYpC;cCrBM;;;;;;GAMH,6BAAwB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import React, { createContext, forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
2
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
5
  import clsx from "clsx";
@@ -1811,283 +1813,5 @@ const FloatingChatManager = ({ aiIcon, useUser, generateHref, LinkComponent, Ima
1811
1813
  var FloatingChatManager_default = FloatingChatManager;
1812
1814
 
1813
1815
  //#endregion
1814
- //#region src/usage/limits.ts
1815
- const DEFAULT_LIMITS = {
1816
- free: 1e3,
1817
- basic: 5e3,
1818
- pro: 2e4,
1819
- enterprise: 1e5
1820
- };
1821
- /**
1822
- * Get the daily token limit for a user based on their Stripe subscription
1823
- */
1824
- async function getUserDailyLimit(payload, userId) {
1825
- try {
1826
- const user = await payload.findByID({
1827
- collection: "users",
1828
- id: userId,
1829
- depth: 2
1830
- });
1831
- if (!user) {
1832
- console.warn("[Token Limits] User not found:", userId);
1833
- return DEFAULT_LIMITS.free;
1834
- }
1835
- const userTyped = user;
1836
- if (userTyped.daily_token_limit && userTyped.daily_token_limit > 0) return userTyped.daily_token_limit;
1837
- const limitFromStripe = await getLimitFromStripeSubscription(user);
1838
- if (limitFromStripe > 0) return limitFromStripe;
1839
- return DEFAULT_LIMITS.free;
1840
- } catch (error) {
1841
- console.error("[Token Limits] Error getting user limit:", error);
1842
- return DEFAULT_LIMITS.free;
1843
- }
1844
- }
1845
- /**
1846
- * Extract token limit from user's active Stripe subscription
1847
- */
1848
- async function getLimitFromStripeSubscription(user) {
1849
- try {
1850
- const customer = user?.customer;
1851
- if (!customer || typeof customer === "string" || typeof customer === "number") return 0;
1852
- const inventory = customer?.inventory;
1853
- if (!inventory || !inventory.subscriptions) return 0;
1854
- const activeSubscription = Object.values(inventory.subscriptions).find((sub) => sub.status === "active" || sub.status === "trialing");
1855
- if (!activeSubscription) return 0;
1856
- const items = activeSubscription.items?.data || [];
1857
- for (const item of items) {
1858
- const product = item.price?.product;
1859
- if (!product) continue;
1860
- if (typeof product === "string") continue;
1861
- if (product.deleted) continue;
1862
- const metadata = product.metadata;
1863
- if (metadata && metadata.daily_token_limit) {
1864
- const limit = parseInt(metadata.daily_token_limit, 10);
1865
- if (!isNaN(limit) && limit > 0) return limit;
1866
- }
1867
- }
1868
- return 0;
1869
- } catch (error) {
1870
- console.error("[Token Limits] Error extracting limit from Stripe:", error);
1871
- return 0;
1872
- }
1873
- }
1874
- /**
1875
- * Get the current daily usage for a user by querying chat-sessions
1876
- * Counts tokens from spending entries that occurred today
1877
- */
1878
- async function getCurrentDailyUsage(payload, userId) {
1879
- const today = /* @__PURE__ */ new Date();
1880
- today.setUTCHours(0, 0, 0, 0);
1881
- today.toISOString();
1882
- const resetAt = getNextResetTime();
1883
- try {
1884
- const sessions = await payload.find({
1885
- collection: "chat-sessions",
1886
- where: { user: { equals: userId } },
1887
- limit: 1e3,
1888
- pagination: false
1889
- });
1890
- let totalTokens = 0;
1891
- for (const session of sessions.docs) {
1892
- const spending = session.spending || [];
1893
- for (const entry of spending) if (new Date(entry.timestamp) >= today) totalTokens += entry.tokens.total || 0;
1894
- }
1895
- return {
1896
- date: today.toISOString().split("T")[0] ?? "",
1897
- tokens_used: totalTokens,
1898
- reset_at: resetAt.toISOString()
1899
- };
1900
- } catch (error) {
1901
- console.error("[Token Limits] Error calculating daily usage:", error);
1902
- return {
1903
- date: today.toISOString().split("T")[0] ?? "",
1904
- tokens_used: 0,
1905
- reset_at: resetAt.toISOString()
1906
- };
1907
- }
1908
- }
1909
- /**
1910
- * Get the next reset time (midnight UTC)
1911
- */
1912
- function getNextResetTime() {
1913
- const now = /* @__PURE__ */ new Date();
1914
- const tomorrow = new Date(now);
1915
- tomorrow.setUTCDate(tomorrow.getUTCDate() + 1);
1916
- tomorrow.setUTCHours(0, 0, 0, 0);
1917
- return tomorrow;
1918
- }
1919
- /**
1920
- * Check if a user can use the specified number of tokens
1921
- */
1922
- async function checkTokenLimit(payload, userId, tokensToUse) {
1923
- try {
1924
- const limit = await getUserDailyLimit(payload, userId);
1925
- const currentUsage = await getCurrentDailyUsage(payload, userId);
1926
- const remaining = Math.max(0, limit - currentUsage.tokens_used);
1927
- const allowed = currentUsage.tokens_used + tokensToUse <= limit;
1928
- return {
1929
- allowed,
1930
- limit,
1931
- used: currentUsage.tokens_used,
1932
- remaining,
1933
- reset_at: currentUsage.reset_at,
1934
- message: allowed ? void 0 : `Daily token limit exceeded. Resets at ${currentUsage.reset_at}`
1935
- };
1936
- } catch (error) {
1937
- console.error("[Token Limits] Error checking limit:", error);
1938
- return {
1939
- allowed: false,
1940
- limit: 0,
1941
- used: 0,
1942
- remaining: 0,
1943
- reset_at: (/* @__PURE__ */ new Date()).toISOString(),
1944
- message: "Error checking token limit"
1945
- };
1946
- }
1947
- }
1948
- /**
1949
- * Get usage statistics for a user (for display in UI)
1950
- */
1951
- async function getUserUsageStats(payload, userId) {
1952
- const limit = await getUserDailyLimit(payload, userId);
1953
- const currentUsage = await getCurrentDailyUsage(payload, userId);
1954
- const remaining = Math.max(0, limit - currentUsage.tokens_used);
1955
- const percentage = limit > 0 ? currentUsage.tokens_used / limit * 100 : 0;
1956
- return {
1957
- limit,
1958
- used: currentUsage.tokens_used,
1959
- remaining,
1960
- percentage: Math.min(100, percentage),
1961
- reset_at: currentUsage.reset_at
1962
- };
1963
- }
1964
-
1965
- //#endregion
1966
- //#region src/usage/token-calculator.ts
1967
- /**
1968
- * Token Calculator and Cost Estimator
1969
- * Utility functions for calculating token usage and estimating costs for AI services
1970
- */
1971
- const PRICING = {
1972
- "text-embedding-3-large": { input: 13e-5 / 1e3 },
1973
- "gpt-4o-mini": {
1974
- input: .15 / 1e6,
1975
- output: .6 / 1e6
1976
- },
1977
- "openai/gpt-4o-mini": {
1978
- input: .15 / 1e6,
1979
- output: .6 / 1e6
1980
- }
1981
- };
1982
- /**
1983
- * Calculate the cost in USD for a given model and token usage
1984
- */
1985
- function calculateCost(model, tokens) {
1986
- const pricing = PRICING[model];
1987
- if (!pricing) {
1988
- console.warn(`[Token Calculator] No pricing data for model: ${model}`);
1989
- return 0;
1990
- }
1991
- let cost = 0;
1992
- if ("input" in pricing && "output" in pricing) {
1993
- cost += (tokens.input || 0) * pricing.input;
1994
- cost += (tokens.output || 0) * pricing.output;
1995
- } else if ("input" in pricing) cost += tokens.total * pricing.input;
1996
- return cost;
1997
- }
1998
- /**
1999
- * Create a spending entry for embedding operations
2000
- */
2001
- function createEmbeddingSpending(model, tokens, timestamp) {
2002
- const tokenUsage = {
2003
- input: tokens,
2004
- total: tokens
2005
- };
2006
- return {
2007
- service: "openai_embedding",
2008
- model,
2009
- tokens: tokenUsage,
2010
- cost_usd: calculateCost(model, tokenUsage),
2011
- timestamp: (timestamp || /* @__PURE__ */ new Date()).toISOString()
2012
- };
2013
- }
2014
- /**
2015
- * Create a spending entry for LLM operations
2016
- */
2017
- function createLLMSpending(model, inputTokens, outputTokens, timestamp) {
2018
- const tokenUsage = {
2019
- input: inputTokens,
2020
- output: outputTokens,
2021
- total: inputTokens + outputTokens
2022
- };
2023
- return {
2024
- service: "openai_llm",
2025
- model,
2026
- tokens: tokenUsage,
2027
- cost_usd: calculateCost(model, tokenUsage),
2028
- timestamp: (timestamp || /* @__PURE__ */ new Date()).toISOString()
2029
- };
2030
- }
2031
- /**
2032
- * Calculate total tokens from an array of spending entries
2033
- */
2034
- function calculateTotalTokens(spending) {
2035
- return spending.reduce((total, entry) => total + entry.tokens.total, 0);
2036
- }
2037
- /**
2038
- * Calculate total cost from an array of spending entries
2039
- */
2040
- function calculateTotalCost(spending) {
2041
- return spending.reduce((total, entry) => total + (entry.cost_usd || 0), 0);
2042
- }
2043
- /**
2044
- * Estimate tokens from text length (rough approximation: 1 token ≈ 4 characters)
2045
- */
2046
- function estimateTokensFromText(text) {
2047
- return Math.ceil(text.length / 4);
2048
- }
2049
- /**
2050
- * Format cost in USD with appropriate precision
2051
- */
2052
- function formatCost(cost) {
2053
- if (cost < .01) return `$${cost.toFixed(6)}`;
2054
- else if (cost < 1) return `$${cost.toFixed(4)}`;
2055
- else return `$${cost.toFixed(2)}`;
2056
- }
2057
- /**
2058
- * Get spending breakdown by service
2059
- */
2060
- function getSpendingBreakdown(spending) {
2061
- const breakdown = {
2062
- embedding: {
2063
- tokens: 0,
2064
- cost: 0
2065
- },
2066
- llm: {
2067
- tokens: 0,
2068
- cost: 0
2069
- },
2070
- total: {
2071
- tokens: 0,
2072
- cost: 0
2073
- }
2074
- };
2075
- for (const entry of spending) {
2076
- const tokens = entry.tokens.total;
2077
- const cost = entry.cost_usd || 0;
2078
- if (entry.service === "openai_embedding") {
2079
- breakdown.embedding.tokens += tokens;
2080
- breakdown.embedding.cost += cost;
2081
- } else if (entry.service === "openai_llm") {
2082
- breakdown.llm.tokens += tokens;
2083
- breakdown.llm.cost += cost;
2084
- }
2085
- breakdown.total.tokens += tokens;
2086
- breakdown.total.cost += cost;
2087
- }
2088
- return breakdown;
2089
- }
2090
-
2091
- //#endregion
2092
- export { ChatProvider, FloatingChatManager_default as FloatingChatManager, calculateCost, calculateTotalCost, calculateTotalTokens, checkTokenLimit, createEmbeddingSpending, createLLMSpending, estimateTokensFromText, formatCost, getCurrentDailyUsage, getSpendingBreakdown, getUserDailyLimit, getUserUsageStats };
2093
- //# sourceMappingURL=index.mjs.map
1816
+ export { ChatProvider, FloatingChatManager_default as FloatingChatManager };
1817
+ //# sourceMappingURL=react.mjs.map