@chaaskit/client 0.1.0 → 0.1.2
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.
- package/LICENSE +21 -0
- package/dist/lib/index.js +1023 -160
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/routes/AcceptInviteRoute.js +1 -1
- package/dist/lib/routes/AcceptInviteRoute.js.map +1 -1
- package/dist/lib/routes/AdminDashboardRoute.js +1 -1
- package/dist/lib/routes/AdminDashboardRoute.js.map +1 -1
- package/dist/lib/routes/AdminPromoCodesRoute.js +19 -0
- package/dist/lib/routes/AdminPromoCodesRoute.js.map +1 -0
- package/dist/lib/routes/AdminTeamRoute.js +1 -1
- package/dist/lib/routes/AdminTeamRoute.js.map +1 -1
- package/dist/lib/routes/AdminTeamsRoute.js +1 -1
- package/dist/lib/routes/AdminTeamsRoute.js.map +1 -1
- package/dist/lib/routes/AdminUsersRoute.js +1 -1
- package/dist/lib/routes/AdminUsersRoute.js.map +1 -1
- package/dist/lib/routes/AdminWaitlistRoute.js +19 -0
- package/dist/lib/routes/AdminWaitlistRoute.js.map +1 -0
- package/dist/lib/routes/ApiKeysRoute.js +1 -1
- package/dist/lib/routes/ApiKeysRoute.js.map +1 -1
- package/dist/lib/routes/AutomationsRoute.js +1 -1
- package/dist/lib/routes/AutomationsRoute.js.map +1 -1
- package/dist/lib/routes/ChatRoute.js +1 -1
- package/dist/lib/routes/ChatRoute.js.map +1 -1
- package/dist/lib/routes/DocumentsRoute.js +1 -1
- package/dist/lib/routes/DocumentsRoute.js.map +1 -1
- package/dist/lib/routes/OAuthConsentRoute.js +1 -1
- package/dist/lib/routes/OAuthConsentRoute.js.map +1 -1
- package/dist/lib/routes/PricingRoute.js +1 -1
- package/dist/lib/routes/PricingRoute.js.map +1 -1
- package/dist/lib/routes/PrivacyRoute.js +1 -1
- package/dist/lib/routes/PrivacyRoute.js.map +1 -1
- package/dist/lib/routes/TeamSettingsRoute.js +1 -1
- package/dist/lib/routes/TeamSettingsRoute.js.map +1 -1
- package/dist/lib/routes/TermsRoute.js +1 -1
- package/dist/lib/routes/TermsRoute.js.map +1 -1
- package/dist/lib/routes/VerifyEmailRoute.js +1 -1
- package/dist/lib/routes/VerifyEmailRoute.js.map +1 -1
- package/dist/lib/routes.js +47 -37
- package/dist/lib/routes.js.map +1 -1
- package/dist/lib/ssr-utils.js +64 -1
- package/dist/lib/ssr-utils.js.map +1 -1
- package/dist/lib/ssr.js +23 -0
- package/dist/lib/ssr.js.map +1 -1
- package/dist/lib/styles.css +58 -62
- package/dist/lib/useExtensions-B5nX_8XD.js.map +1 -1
- package/package.json +25 -12
- package/src/components/MessageItem.tsx +35 -4
- package/src/components/MessageList.tsx +51 -5
- package/src/components/OAuthAppsSection.tsx +1 -1
- package/src/components/Sidebar.tsx +1 -3
- package/src/components/ToolCallDisplay.tsx +102 -11
- package/src/components/tool-renderers/DocumentListRenderer.tsx +44 -0
- package/src/components/tool-renderers/DocumentReadRenderer.tsx +33 -0
- package/src/components/tool-renderers/DocumentSaveRenderer.tsx +32 -0
- package/src/components/tool-renderers/DocumentSearchRenderer.tsx +33 -0
- package/src/components/tool-renderers/index.ts +36 -0
- package/src/components/tool-renderers/utils.ts +7 -0
- package/src/contexts/AuthContext.tsx +16 -6
- package/src/contexts/ConfigContext.tsx +60 -28
- package/src/contexts/ThemeContext.tsx +39 -68
- package/src/extensions/registry.ts +2 -1
- package/src/hooks/__tests__/basePath.test.ts +42 -0
- package/src/index.tsx +11 -2
- package/src/pages/AdminDashboardPage.tsx +15 -1
- package/src/pages/AdminPromoCodesPage.tsx +378 -0
- package/src/pages/AdminTeamPage.tsx +29 -1
- package/src/pages/AdminTeamsPage.tsx +15 -1
- package/src/pages/AdminUsersPage.tsx +15 -1
- package/src/pages/AdminWaitlistPage.tsx +156 -0
- package/src/pages/RegisterPage.tsx +91 -9
- package/src/routes/AcceptInviteRoute.tsx +1 -1
- package/src/routes/AdminDashboardRoute.tsx +1 -1
- package/src/routes/AdminPromoCodesRoute.tsx +24 -0
- package/src/routes/AdminTeamRoute.tsx +1 -1
- package/src/routes/AdminTeamsRoute.tsx +1 -1
- package/src/routes/AdminUsersRoute.tsx +1 -1
- package/src/routes/AdminWaitlistRoute.tsx +24 -0
- package/src/routes/ApiKeysRoute.tsx +1 -1
- package/src/routes/AutomationsRoute.tsx +1 -1
- package/src/routes/ChatRoute.tsx +2 -1
- package/src/routes/DocumentsRoute.tsx +1 -1
- package/src/routes/OAuthConsentRoute.tsx +1 -1
- package/src/routes/PricingRoute.tsx +1 -1
- package/src/routes/PrivacyRoute.tsx +1 -1
- package/src/routes/TeamSettingsRoute.tsx +1 -1
- package/src/routes/TermsRoute.tsx +1 -1
- package/src/routes/VerifyEmailRoute.tsx +1 -1
- package/src/routes/index.ts +2 -0
- package/src/ssr-utils.tsx +100 -1
- package/src/ssr.ts +59 -0
- package/src/stores/chatStore.ts +5 -0
- package/src/styles/index.css +16 -63
- package/src/tailwind-preset.js +360 -0
- package/dist/favicon.svg +0 -11
- package/dist/index.html +0 -17
- package/dist/logo.svg +0 -12
package/dist/lib/ssr.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr.js","sources":["../../src/ssr.ts"],"sourcesContent":["/**\n * SSR-safe exports for server-side rendering.\n *\n * This module exports components and utilities that can be used on the server\n * without browser APIs like window, document, or localStorage.\n */\n\nimport type { AppConfig } from '@chaaskit/shared';\n\n// SSR-safe context providers\nexport {\n ServerConfigProvider,\n useServerConfig,\n useServerConfigLoaded,\n type ServerConfigProviderProps,\n} from './contexts/ServerConfigProvider';\n\nexport {\n ServerThemeProvider,\n useServerTheme,\n type ServerThemeProviderProps,\n} from './contexts/ServerThemeProvider';\n\n// NOTE: SSRMessageList and SSRMarkdownRenderer are NOT exported here because\n// they depend on react-markdown which has browser-only dependencies.\n// Use them only in client-side code wrapped in <ClientOnly>.\n\n// ============================================\n// Theme utilities for SSR\n// ============================================\n\n/**\n * Converts a hex color to RGB values string (e.g., \"#ff0000\" -> \"255 0 0\")\n */\nfunction hexToRgb(hex: string): string {\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n if (!result) return '';\n return `${parseInt(result[1]!, 16)} ${parseInt(result[2]!, 16)} ${parseInt(result[3]!, 16)}`;\n}\n\n/**\n * Generates CSS variables for a theme.\n * Use this in your React Router root.tsx to inject theme styles.\n *\n * @example\n * ```tsx\n * // app/root.tsx\n * import { generateThemeCSS } from '@chaaskit/client/ssr';\n *\n * export default function Root() {\n * const themeCSS = generateThemeCSS(config, 'dark');\n * return (\n * <html>\n * <head>\n * <style dangerouslySetInnerHTML={{ __html: themeCSS }} />\n * </head>\n * ...\n * </html>\n * );\n * }\n * ```\n */\nexport function generateThemeCSS(config: AppConfig, theme: string): string {\n const themeConfig = config.theming.themes[theme];\n if (!themeConfig) return '';\n\n const cssVars = Object.entries(themeConfig.colors)\n .map(([key, value]) => {\n const cssKey = `--color-${key.replace(/([A-Z])/g, '-$1').toLowerCase()}`;\n return `${cssKey}: ${hexToRgb(value)};`;\n })\n .join('\\n ');\n\n return `\n :root {\n ${cssVars}\n --font-sans: ${config.theming.fonts.sans};\n --font-mono: ${config.theming.fonts.mono};\n --radius-sm: ${config.theming.borderRadius.sm};\n --radius-md: ${config.theming.borderRadius.md};\n --radius-lg: ${config.theming.borderRadius.lg};\n --radius-full: ${config.theming.borderRadius.full};\n }\n `;\n}\n\n/**\n * Returns an object of CSS variable name -> value pairs for a theme.\n * Useful if you need programmatic access to theme values.\n */\nexport function getThemeVariables(config: AppConfig, theme: string): Record<string, string> {\n const themeConfig = config.theming.themes[theme];\n if (!themeConfig) return {};\n\n const vars: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(themeConfig.colors)) {\n const cssKey = `--color-${key.replace(/([A-Z])/g, '-$1').toLowerCase()}`;\n vars[cssKey] = hexToRgb(value);\n }\n\n vars['--font-sans'] = config.theming.fonts.sans;\n vars['--font-mono'] = config.theming.fonts.mono;\n vars['--radius-sm'] = config.theming.borderRadius.sm;\n vars['--radius-md'] = config.theming.borderRadius.md;\n vars['--radius-lg'] = config.theming.borderRadius.lg;\n vars['--radius-full'] = config.theming.borderRadius.full;\n\n return vars;\n}\n\n/**\n * Base CSS styles for SSR pages.\n * Include this in your HTML template for consistent styling.\n */\nexport const baseStyles = `\n html { font-family: var(--font-sans); }\n body {\n margin: 0;\n background-color: rgb(var(--color-background));\n color: rgb(var(--color-text-primary));\n }\n`;\n"],"names":[],"mappings":";AAkCA,SAAS,SAAS,KAAqB;AACrC,QAAM,SAAS,4CAA4C,KAAK,GAAG;AACnE,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,GAAG,SAAS,OAAO,CAAC,GAAI,EAAE,CAAC,IAAI,SAAS,OAAO,CAAC,GAAI,EAAE,CAAC,IAAI,SAAS,OAAO,CAAC,GAAI,EAAE,CAAC;AAC5F;AAwBO,SAAS,iBAAiB,QAAmB,OAAuB;AACzE,QAAM,cAAc,OAAO,QAAQ,OAAO,KAAK;AAC/C,MAAI,CAAC,YAAa,QAAO;AAEzB,QAAM,UAAU,OAAO,QAAQ,YAAY,MAAM,EAC9C,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM;AACrB,UAAM,SAAS,WAAW,IAAI,QAAQ,YAAY,KAAK,EAAE,aAAa;AACtE,WAAO,GAAG,MAAM,KAAK,SAAS,KAAK,CAAC;AAAA,EACtC,CAAC,EACA,KAAK,QAAQ;AAEhB,SAAO;AAAA;AAAA,QAED,OAAO;AAAA,qBACM,OAAO,QAAQ,MAAM,IAAI;AAAA,qBACzB,OAAO,QAAQ,MAAM,IAAI;AAAA,qBACzB,OAAO,QAAQ,aAAa,EAAE;AAAA,qBAC9B,OAAO,QAAQ,aAAa,EAAE;AAAA,qBAC9B,OAAO,QAAQ,aAAa,EAAE;AAAA,uBAC5B,OAAO,QAAQ,aAAa,IAAI;AAAA;AAAA;AAGvD;AAMO,SAAS,kBAAkB,QAAmB,OAAuC;AAC1F,QAAM,cAAc,OAAO,QAAQ,OAAO,KAAK;AAC/C,MAAI,CAAC,YAAa,QAAO,CAAA;AAEzB,QAAM,OAA+B,CAAA;AAErC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,YAAY,MAAM,GAAG;AAC7D,UAAM,SAAS,WAAW,IAAI,QAAQ,YAAY,KAAK,EAAE,aAAa;AACtE,SAAK,MAAM,IAAI,SAAS,KAAK;AAAA,EAC/B;AAEA,OAAK,aAAa,IAAI,OAAO,QAAQ,MAAM;AAC3C,OAAK,aAAa,IAAI,OAAO,QAAQ,MAAM;AAC3C,OAAK,aAAa,IAAI,OAAO,QAAQ,aAAa;AAClD,OAAK,aAAa,IAAI,OAAO,QAAQ,aAAa;AAClD,OAAK,aAAa,IAAI,OAAO,QAAQ,aAAa;AAClD,OAAK,eAAe,IAAI,OAAO,QAAQ,aAAa;AAEpD,SAAO;AACT;AAMO,MAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;"}
|
|
1
|
+
{"version":3,"file":"ssr.js","sources":["../../src/ssr.ts"],"sourcesContent":["/**\n * SSR-safe exports for server-side rendering.\n *\n * This module exports components and utilities that can be used on the server\n * without browser APIs like window, document, or localStorage.\n */\n\nimport type { AppConfig } from '@chaaskit/shared';\n\n// SSR-safe context providers\nexport {\n ServerConfigProvider,\n useServerConfig,\n useServerConfigLoaded,\n type ServerConfigProviderProps,\n} from './contexts/ServerConfigProvider';\n\nexport {\n ServerThemeProvider,\n useServerTheme,\n type ServerThemeProviderProps,\n} from './contexts/ServerThemeProvider';\n\n// NOTE: SSRMessageList and SSRMarkdownRenderer are NOT exported here because\n// they depend on react-markdown which has browser-only dependencies.\n// Use them only in client-side code wrapped in <ClientOnly>.\n\n// ============================================\n// Theme utilities for SSR\n// ============================================\n\n/**\n * Converts a hex color to RGB values string (e.g., \"#ff0000\" -> \"255 0 0\")\n */\nfunction hexToRgb(hex: string): string {\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n if (!result) return '';\n return `${parseInt(result[1]!, 16)} ${parseInt(result[2]!, 16)} ${parseInt(result[3]!, 16)}`;\n}\n\n/**\n * Generates CSS variables for a theme.\n * Use this in your React Router root.tsx to inject theme styles.\n *\n * @example\n * ```tsx\n * // app/root.tsx\n * import { generateThemeCSS } from '@chaaskit/client/ssr';\n *\n * export default function Root() {\n * const themeCSS = generateThemeCSS(config, 'dark');\n * return (\n * <html>\n * <head>\n * <style dangerouslySetInnerHTML={{ __html: themeCSS }} />\n * </head>\n * ...\n * </html>\n * );\n * }\n * ```\n */\nexport function generateThemeCSS(config: AppConfig, theme: string): string {\n const themeConfig = config.theming.themes[theme];\n if (!themeConfig) return '';\n\n const cssVars = Object.entries(themeConfig.colors)\n .map(([key, value]) => {\n const cssKey = `--color-${key.replace(/([A-Z])/g, '-$1').toLowerCase()}`;\n return `${cssKey}: ${hexToRgb(value)};`;\n })\n .join('\\n ');\n\n return `\n :root {\n ${cssVars}\n --font-sans: ${config.theming.fonts.sans};\n --font-mono: ${config.theming.fonts.mono};\n --radius-sm: ${config.theming.borderRadius.sm};\n --radius-md: ${config.theming.borderRadius.md};\n --radius-lg: ${config.theming.borderRadius.lg};\n --radius-full: ${config.theming.borderRadius.full};\n }\n `;\n}\n\n/**\n * Returns an object of CSS variable name -> value pairs for a theme.\n * Useful if you need programmatic access to theme values.\n */\nexport function getThemeVariables(config: AppConfig, theme: string): Record<string, string> {\n const themeConfig = config.theming.themes[theme];\n if (!themeConfig) return {};\n\n const vars: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(themeConfig.colors)) {\n const cssKey = `--color-${key.replace(/([A-Z])/g, '-$1').toLowerCase()}`;\n vars[cssKey] = hexToRgb(value);\n }\n\n vars['--font-sans'] = config.theming.fonts.sans;\n vars['--font-mono'] = config.theming.fonts.mono;\n vars['--radius-sm'] = config.theming.borderRadius.sm;\n vars['--radius-md'] = config.theming.borderRadius.md;\n vars['--radius-lg'] = config.theming.borderRadius.lg;\n vars['--radius-full'] = config.theming.borderRadius.full;\n\n return vars;\n}\n\n/**\n * Generates CSS for ALL themes using html[data-theme] selectors.\n * This is the recommended way to include theme styles - it allows instant\n * theme switching by just changing the data-theme attribute on <html>.\n *\n * @example\n * ```tsx\n * // app/root.tsx\n * import { generateAllThemesCSS, baseStyles } from '@chaaskit/client/ssr';\n *\n * // Cache on server - only generate once\n * let cachedCSS: string | null = null;\n *\n * export async function loader() {\n * if (!cachedCSS) cachedCSS = generateAllThemesCSS(config);\n * return { themeCSS: cachedCSS };\n * }\n *\n * export default function Root() {\n * const { themeCSS } = useLoaderData();\n * return (\n * <html data-theme=\"dark\">\n * <head>\n * <style dangerouslySetInnerHTML={{ __html: themeCSS + baseStyles }} />\n * </head>\n * ...\n * </html>\n * );\n * }\n * ```\n */\nexport function generateAllThemesCSS(config: AppConfig): string {\n const themes = config.theming.themes;\n let css = '';\n\n for (const [themeName, themeConfig] of Object.entries(themes)) {\n const cssVars = Object.entries(themeConfig.colors)\n .map(([key, value]) => {\n const cssKey = `--color-${key.replace(/([A-Z])/g, '-$1').toLowerCase()}`;\n return `${cssKey}: ${hexToRgb(value)};`;\n })\n .join('\\n ');\n\n css += `\n html[data-theme=\"${themeName}\"] {\n ${cssVars}\n --font-sans: ${config.theming.fonts.sans};\n --font-mono: ${config.theming.fonts.mono};\n --radius-sm: ${config.theming.borderRadius.sm};\n --radius-md: ${config.theming.borderRadius.md};\n --radius-lg: ${config.theming.borderRadius.lg};\n --radius-full: ${config.theming.borderRadius.full};\n }\n`;\n }\n\n return css;\n}\n\n/**\n * Base CSS styles for SSR pages.\n * Include this in your HTML template for consistent styling.\n */\nexport const baseStyles = `\n html { font-family: var(--font-sans); }\n body {\n margin: 0;\n background-color: rgb(var(--color-background));\n color: rgb(var(--color-text-primary));\n }\n`;\n"],"names":[],"mappings":";AAkCA,SAAS,SAAS,KAAqB;AACrC,QAAM,SAAS,4CAA4C,KAAK,GAAG;AACnE,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,GAAG,SAAS,OAAO,CAAC,GAAI,EAAE,CAAC,IAAI,SAAS,OAAO,CAAC,GAAI,EAAE,CAAC,IAAI,SAAS,OAAO,CAAC,GAAI,EAAE,CAAC;AAC5F;AAwBO,SAAS,iBAAiB,QAAmB,OAAuB;AACzE,QAAM,cAAc,OAAO,QAAQ,OAAO,KAAK;AAC/C,MAAI,CAAC,YAAa,QAAO;AAEzB,QAAM,UAAU,OAAO,QAAQ,YAAY,MAAM,EAC9C,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM;AACrB,UAAM,SAAS,WAAW,IAAI,QAAQ,YAAY,KAAK,EAAE,aAAa;AACtE,WAAO,GAAG,MAAM,KAAK,SAAS,KAAK,CAAC;AAAA,EACtC,CAAC,EACA,KAAK,QAAQ;AAEhB,SAAO;AAAA;AAAA,QAED,OAAO;AAAA,qBACM,OAAO,QAAQ,MAAM,IAAI;AAAA,qBACzB,OAAO,QAAQ,MAAM,IAAI;AAAA,qBACzB,OAAO,QAAQ,aAAa,EAAE;AAAA,qBAC9B,OAAO,QAAQ,aAAa,EAAE;AAAA,qBAC9B,OAAO,QAAQ,aAAa,EAAE;AAAA,uBAC5B,OAAO,QAAQ,aAAa,IAAI;AAAA;AAAA;AAGvD;AAMO,SAAS,kBAAkB,QAAmB,OAAuC;AAC1F,QAAM,cAAc,OAAO,QAAQ,OAAO,KAAK;AAC/C,MAAI,CAAC,YAAa,QAAO,CAAA;AAEzB,QAAM,OAA+B,CAAA;AAErC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,YAAY,MAAM,GAAG;AAC7D,UAAM,SAAS,WAAW,IAAI,QAAQ,YAAY,KAAK,EAAE,aAAa;AACtE,SAAK,MAAM,IAAI,SAAS,KAAK;AAAA,EAC/B;AAEA,OAAK,aAAa,IAAI,OAAO,QAAQ,MAAM;AAC3C,OAAK,aAAa,IAAI,OAAO,QAAQ,MAAM;AAC3C,OAAK,aAAa,IAAI,OAAO,QAAQ,aAAa;AAClD,OAAK,aAAa,IAAI,OAAO,QAAQ,aAAa;AAClD,OAAK,aAAa,IAAI,OAAO,QAAQ,aAAa;AAClD,OAAK,eAAe,IAAI,OAAO,QAAQ,aAAa;AAEpD,SAAO;AACT;AAiCO,SAAS,qBAAqB,QAA2B;AAC9D,QAAM,SAAS,OAAO,QAAQ;AAC9B,MAAI,MAAM;AAEV,aAAW,CAAC,WAAW,WAAW,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC7D,UAAM,UAAU,OAAO,QAAQ,YAAY,MAAM,EAC9C,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM;AACrB,YAAM,SAAS,WAAW,IAAI,QAAQ,YAAY,KAAK,EAAE,aAAa;AACtE,aAAO,GAAG,MAAM,KAAK,SAAS,KAAK,CAAC;AAAA,IACtC,CAAC,EACA,KAAK,UAAU;AAElB,WAAO;AAAA,uBACY,SAAS;AAAA,QACxB,OAAO;AAAA,qBACM,OAAO,QAAQ,MAAM,IAAI;AAAA,qBACzB,OAAO,QAAQ,MAAM,IAAI;AAAA,qBACzB,OAAO,QAAQ,aAAa,EAAE;AAAA,qBAC9B,OAAO,QAAQ,aAAa,EAAE;AAAA,qBAC9B,OAAO,QAAQ,aAAa,EAAE;AAAA,uBAC5B,OAAO,QAAQ,aAAa,IAAI;AAAA;AAAA;AAAA,EAGrD;AAEA,SAAO;AACT;AAMO,MAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;"}
|
package/dist/lib/styles.css
CHANGED
|
@@ -801,6 +801,9 @@ video {
|
|
|
801
801
|
.min-w-0 {
|
|
802
802
|
min-width: 0px;
|
|
803
803
|
}
|
|
804
|
+
.min-w-\[160px\] {
|
|
805
|
+
min-width: 160px;
|
|
806
|
+
}
|
|
804
807
|
.min-w-\[200px\] {
|
|
805
808
|
min-width: 200px;
|
|
806
809
|
}
|
|
@@ -1179,6 +1182,9 @@ video {
|
|
|
1179
1182
|
.border-purple-500\/20 {
|
|
1180
1183
|
border-color: rgb(168 85 247 / 0.2);
|
|
1181
1184
|
}
|
|
1185
|
+
.border-success\/30 {
|
|
1186
|
+
border-color: rgb(var(--color-success) / 0.3);
|
|
1187
|
+
}
|
|
1182
1188
|
.border-success\/50 {
|
|
1183
1189
|
border-color: rgb(var(--color-success) / 0.5);
|
|
1184
1190
|
}
|
|
@@ -1219,6 +1225,9 @@ video {
|
|
|
1219
1225
|
.bg-background-secondary\/30 {
|
|
1220
1226
|
background-color: rgb(var(--color-background-secondary) / 0.3);
|
|
1221
1227
|
}
|
|
1228
|
+
.bg-background-secondary\/40 {
|
|
1229
|
+
background-color: rgb(var(--color-background-secondary) / 0.4);
|
|
1230
|
+
}
|
|
1222
1231
|
.bg-background-secondary\/50 {
|
|
1223
1232
|
background-color: rgb(var(--color-background-secondary) / 0.5);
|
|
1224
1233
|
}
|
|
@@ -1615,6 +1624,9 @@ video {
|
|
|
1615
1624
|
--tw-text-opacity: 1;
|
|
1616
1625
|
color: rgb(255 255 255 / var(--tw-text-opacity, 1));
|
|
1617
1626
|
}
|
|
1627
|
+
.underline {
|
|
1628
|
+
text-decoration-line: underline;
|
|
1629
|
+
}
|
|
1618
1630
|
.placeholder-text-muted::-moz-placeholder {
|
|
1619
1631
|
--tw-placeholder-opacity: 1;
|
|
1620
1632
|
color: rgb(var(--color-text-muted) / var(--tw-placeholder-opacity, 1));
|
|
@@ -1684,70 +1696,26 @@ video {
|
|
|
1684
1696
|
.ease-in-out {
|
|
1685
1697
|
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
1686
1698
|
}
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
:root {
|
|
1690
|
-
--color-primary: 99 102 241;
|
|
1691
|
-
--color-primary-hover: 79 70 229;
|
|
1692
|
-
--color-secondary: 139 92 246;
|
|
1693
|
-
|
|
1694
|
-
--color-background: 255 255 255;
|
|
1695
|
-
--color-background-secondary: 249 250 251;
|
|
1696
|
-
--color-sidebar: 243 244 246;
|
|
1697
|
-
|
|
1698
|
-
--color-text-primary: 17 24 39;
|
|
1699
|
-
--color-text-secondary: 107 114 128;
|
|
1700
|
-
--color-text-muted: 156 163 175;
|
|
1701
|
-
|
|
1702
|
-
--color-border: 229 231 235;
|
|
1703
|
-
--color-input-background: 255 255 255;
|
|
1704
|
-
--color-input-border: 209 213 219;
|
|
1705
|
-
|
|
1706
|
-
--color-user-message-bg: 99 102 241;
|
|
1707
|
-
--color-user-message-text: 255 255 255;
|
|
1708
|
-
--color-assistant-message-bg: 243 244 246;
|
|
1709
|
-
--color-assistant-message-text: 17 24 39;
|
|
1710
|
-
|
|
1711
|
-
--color-success: 16 185 129;
|
|
1712
|
-
--color-warning: 245 158 11;
|
|
1713
|
-
--color-error: 239 68 68;
|
|
1714
|
-
|
|
1715
|
-
--font-sans: 'Inter', system-ui, sans-serif;
|
|
1716
|
-
--font-mono: 'JetBrains Mono', Menlo, monospace;
|
|
1717
|
-
|
|
1718
|
-
--radius-sm: 0.25rem;
|
|
1719
|
-
--radius-md: 0.5rem;
|
|
1720
|
-
--radius-lg: 0.75rem;
|
|
1721
|
-
--radius-full: 9999px;
|
|
1699
|
+
.ease-out {
|
|
1700
|
+
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
|
1722
1701
|
}
|
|
1723
1702
|
|
|
1724
|
-
/*
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
--color-input-border: 75 85 99;
|
|
1741
|
-
|
|
1742
|
-
--color-user-message-bg: 79 70 229;
|
|
1743
|
-
--color-user-message-text: 255 255 255;
|
|
1744
|
-
--color-assistant-message-bg: 31 41 55;
|
|
1745
|
-
--color-assistant-message-text: 249 250 251;
|
|
1746
|
-
|
|
1747
|
-
--color-success: 52 211 153;
|
|
1748
|
-
--color-warning: 251 191 36;
|
|
1749
|
-
--color-error: 248 113 113;
|
|
1750
|
-
}
|
|
1703
|
+
/*
|
|
1704
|
+
* Theme CSS variables are NOT defined here.
|
|
1705
|
+
* The consuming app (chaaskit-app) is responsible for providing CSS variable values
|
|
1706
|
+
* via inline styles on <html> from config/app.config.ts.
|
|
1707
|
+
*
|
|
1708
|
+
* Required variables:
|
|
1709
|
+
* --color-primary, --color-primary-hover, --color-secondary
|
|
1710
|
+
* --color-background, --color-background-secondary, --color-sidebar
|
|
1711
|
+
* --color-text-primary, --color-text-secondary, --color-text-muted
|
|
1712
|
+
* --color-border, --color-input-background, --color-input-border
|
|
1713
|
+
* --color-user-message-bg, --color-user-message-text
|
|
1714
|
+
* --color-assistant-message-bg, --color-assistant-message-text
|
|
1715
|
+
* --color-success, --color-warning, --color-error
|
|
1716
|
+
* --font-sans, --font-mono
|
|
1717
|
+
* --radius-sm, --radius-md, --radius-lg, --radius-full
|
|
1718
|
+
*/
|
|
1751
1719
|
|
|
1752
1720
|
/* Base styles */
|
|
1753
1721
|
html {
|
|
@@ -2327,6 +2295,18 @@ kbd {
|
|
|
2327
2295
|
}
|
|
2328
2296
|
@media (min-width: 768px) {
|
|
2329
2297
|
|
|
2298
|
+
.md\:col-span-2 {
|
|
2299
|
+
grid-column: span 2 / span 2;
|
|
2300
|
+
}
|
|
2301
|
+
|
|
2302
|
+
.md\:col-span-3 {
|
|
2303
|
+
grid-column: span 3 / span 3;
|
|
2304
|
+
}
|
|
2305
|
+
|
|
2306
|
+
.md\:col-span-4 {
|
|
2307
|
+
grid-column: span 4 / span 4;
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2330
2310
|
.md\:block {
|
|
2331
2311
|
display: block;
|
|
2332
2312
|
}
|
|
@@ -2339,6 +2319,10 @@ kbd {
|
|
|
2339
2319
|
display: none;
|
|
2340
2320
|
}
|
|
2341
2321
|
|
|
2322
|
+
.md\:grid-cols-12 {
|
|
2323
|
+
grid-template-columns: repeat(12, minmax(0, 1fr));
|
|
2324
|
+
}
|
|
2325
|
+
|
|
2342
2326
|
.md\:grid-cols-2 {
|
|
2343
2327
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
2344
2328
|
}
|
|
@@ -2354,6 +2338,10 @@ kbd {
|
|
|
2354
2338
|
.md\:justify-between {
|
|
2355
2339
|
justify-content: space-between;
|
|
2356
2340
|
}
|
|
2341
|
+
|
|
2342
|
+
.md\:gap-4 {
|
|
2343
|
+
gap: 1rem;
|
|
2344
|
+
}
|
|
2357
2345
|
}
|
|
2358
2346
|
@media (min-width: 1024px) {
|
|
2359
2347
|
|
|
@@ -2361,6 +2349,14 @@ kbd {
|
|
|
2361
2349
|
position: relative;
|
|
2362
2350
|
}
|
|
2363
2351
|
|
|
2352
|
+
.lg\:col-span-1 {
|
|
2353
|
+
grid-column: span 1 / span 1;
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2356
|
+
.lg\:col-span-2 {
|
|
2357
|
+
grid-column: span 2 / span 2;
|
|
2358
|
+
}
|
|
2359
|
+
|
|
2364
2360
|
.lg\:hidden {
|
|
2365
2361
|
display: none;
|
|
2366
2362
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useExtensions-B5nX_8XD.js","sources":["../../src/extensions/registry.ts","../../src/extensions/useExtensions.ts"],"sourcesContent":["import type { ComponentType } from 'react';\n\n/**\n * Page extension configuration\n */\nexport interface PageExtension {\n /** Unique identifier for the page */\n id: string;\n /** URL path for the page (e.g., \"/analytics\") */\n path: string;\n /** Display label for navigation */\n label: string;\n /** Optional icon name from lucide-react */\n icon?: string;\n /** React component to render for this page */\n component: ComponentType;\n /** Whether to show in the sidebar navigation */\n showInSidebar?: boolean;\n /** Whether this page requires authentication */\n requiresAuth?: boolean;\n /** Whether this page requires admin access */\n requiresAdmin?: boolean;\n}\n\n/**\n * Tool result renderer extension\n */\nexport interface ToolExtension {\n /** Tool name to match */\n name: string;\n /** Description of the tool */\n description: string;\n /** Custom renderer for tool results */\n resultRenderer?: ComponentType<{
|
|
1
|
+
{"version":3,"file":"useExtensions-B5nX_8XD.js","sources":["../../src/extensions/registry.ts","../../src/extensions/useExtensions.ts"],"sourcesContent":["import type { ComponentType } from 'react';\nimport type { ToolCall, ToolResult } from '@chaaskit/shared';\n\n/**\n * Page extension configuration\n */\nexport interface PageExtension {\n /** Unique identifier for the page */\n id: string;\n /** URL path for the page (e.g., \"/analytics\") */\n path: string;\n /** Display label for navigation */\n label: string;\n /** Optional icon name from lucide-react */\n icon?: string;\n /** React component to render for this page */\n component: ComponentType;\n /** Whether to show in the sidebar navigation */\n showInSidebar?: boolean;\n /** Whether this page requires authentication */\n requiresAuth?: boolean;\n /** Whether this page requires admin access */\n requiresAdmin?: boolean;\n}\n\n/**\n * Tool result renderer extension\n */\nexport interface ToolExtension {\n /** Tool name to match */\n name: string;\n /** Description of the tool */\n description: string;\n /** Custom renderer for tool results */\n resultRenderer?: ComponentType<{ toolCall: ToolCall; toolResult: ToolResult }>;\n}\n\n/**\n * Component override extension\n */\nexport interface ComponentOverride {\n /** Component slot to override */\n slot: 'header' | 'footer' | 'sidebar-header' | 'sidebar-footer' | 'message-actions';\n /** Component to render in the slot */\n component: ComponentType<Record<string, unknown>>;\n}\n\n/**\n * Client-side extension registry for customizing the ChaasKit UI\n *\n * Note: getPages(), getSidebarPages(), and getTools() cache their results\n * to support React's useSyncExternalStore which requires stable references.\n */\nclass ClientExtensionRegistry {\n private pages: Map<string, PageExtension> = new Map();\n private tools: Map<string, ToolExtension> = new Map();\n private overrides: Map<string, ComponentOverride> = new Map();\n private listeners: Set<() => void> = new Set();\n\n // Cached arrays for useSyncExternalStore compatibility\n // These are only updated when the underlying data changes\n private cachedPages: PageExtension[] = [];\n private cachedSidebarPages: PageExtension[] = [];\n private cachedTools: ToolExtension[] = [];\n\n /**\n * Register a custom page\n */\n registerPage(page: PageExtension): void {\n this.pages.set(page.id, page);\n this.invalidateCaches();\n this.notifyListeners();\n }\n\n /**\n * Unregister a custom page\n */\n unregisterPage(id: string): boolean {\n const result = this.pages.delete(id);\n if (result) {\n this.invalidateCaches();\n this.notifyListeners();\n }\n return result;\n }\n\n /**\n * Get all registered pages\n * Returns a cached array for useSyncExternalStore compatibility\n */\n getPages(): PageExtension[] {\n return this.cachedPages;\n }\n\n /**\n * Get pages that should appear in the sidebar\n * Returns a cached array for useSyncExternalStore compatibility\n */\n getSidebarPages(): PageExtension[] {\n return this.cachedSidebarPages;\n }\n\n /**\n * Register a custom tool renderer\n */\n registerTool(tool: ToolExtension): void {\n this.tools.set(tool.name, tool);\n this.invalidateCaches();\n this.notifyListeners();\n }\n\n /**\n * Unregister a tool renderer\n */\n unregisterTool(name: string): boolean {\n const result = this.tools.delete(name);\n if (result) {\n this.invalidateCaches();\n this.notifyListeners();\n }\n return result;\n }\n\n /**\n * Get all registered tools\n * Returns a cached array for useSyncExternalStore compatibility\n */\n getTools(): ToolExtension[] {\n return this.cachedTools;\n }\n\n /**\n * Get a specific tool by name\n */\n getTool(name: string): ToolExtension | undefined {\n return this.tools.get(name);\n }\n\n /**\n * Register a component override\n */\n registerOverride(override: ComponentOverride): void {\n this.overrides.set(override.slot, override);\n this.notifyListeners();\n }\n\n /**\n * Get a component override for a slot\n */\n getOverride(slot: string): ComponentOverride | undefined {\n return this.overrides.get(slot);\n }\n\n /**\n * Subscribe to registry changes\n */\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n private invalidateCaches(): void {\n this.cachedPages = Array.from(this.pages.values());\n this.cachedSidebarPages = this.cachedPages.filter(p => p.showInSidebar);\n this.cachedTools = Array.from(this.tools.values());\n }\n\n private notifyListeners(): void {\n this.listeners.forEach(listener => listener());\n }\n\n /**\n * Clear all registered extensions\n */\n clear(): void {\n this.pages.clear();\n this.tools.clear();\n this.overrides.clear();\n this.invalidateCaches();\n this.notifyListeners();\n }\n}\n\n// Singleton instance\nexport const clientRegistry = new ClientExtensionRegistry();\n\n// Export for use in user extensions\nexport default clientRegistry;\n","import { useSyncExternalStore, useCallback } from 'react';\nimport { clientRegistry, type PageExtension, type ToolExtension, type ComponentOverride } from './registry';\n\n/**\n * Hook to access extension pages with automatic updates\n */\nexport function useExtensionPages(): PageExtension[] {\n const getSnapshot = useCallback(() => clientRegistry.getPages(), []);\n const subscribe = useCallback((callback: () => void) => clientRegistry.subscribe(callback), []);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/**\n * Hook to access sidebar pages with automatic updates\n */\nexport function useSidebarPages(): PageExtension[] {\n const getSnapshot = useCallback(() => clientRegistry.getSidebarPages(), []);\n const subscribe = useCallback((callback: () => void) => clientRegistry.subscribe(callback), []);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/**\n * Hook to access extension tools with automatic updates\n */\nexport function useExtensionTools(): ToolExtension[] {\n const getSnapshot = useCallback(() => clientRegistry.getTools(), []);\n const subscribe = useCallback((callback: () => void) => clientRegistry.subscribe(callback), []);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/**\n * Hook to get a specific tool renderer\n */\nexport function useToolRenderer(toolName: string): ToolExtension | undefined {\n const getSnapshot = useCallback(() => clientRegistry.getTool(toolName), [toolName]);\n const subscribe = useCallback((callback: () => void) => clientRegistry.subscribe(callback), []);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/**\n * Hook to get a component override\n */\nexport function useComponentOverride(slot: string): ComponentOverride | undefined {\n const getSnapshot = useCallback(() => clientRegistry.getOverride(slot), [slot]);\n const subscribe = useCallback((callback: () => void) => clientRegistry.subscribe(callback), []);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chaaskit/client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "React frontend client for ChaasKit AI chat applications",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Matt Ferrante <@ferrants>",
|
|
@@ -13,7 +13,15 @@
|
|
|
13
13
|
"bugs": {
|
|
14
14
|
"url": "https://github.com/ferrants/chaaskit/issues"
|
|
15
15
|
},
|
|
16
|
-
"keywords": [
|
|
16
|
+
"keywords": [
|
|
17
|
+
"chaaskit",
|
|
18
|
+
"ai",
|
|
19
|
+
"chat",
|
|
20
|
+
"saas",
|
|
21
|
+
"client",
|
|
22
|
+
"react",
|
|
23
|
+
"vite"
|
|
24
|
+
],
|
|
17
25
|
"type": "module",
|
|
18
26
|
"exports": {
|
|
19
27
|
".": {
|
|
@@ -41,22 +49,19 @@
|
|
|
41
49
|
"import": "./dist/lib/routes/*.js"
|
|
42
50
|
},
|
|
43
51
|
"./styles": "./dist/lib/styles.css",
|
|
52
|
+
"./tailwind-preset": {
|
|
53
|
+
"types": "./src/tailwind-preset.js",
|
|
54
|
+
"import": "./src/tailwind-preset.js",
|
|
55
|
+
"require": "./src/tailwind-preset.js"
|
|
56
|
+
},
|
|
44
57
|
"./src/*": "./src/*"
|
|
45
58
|
},
|
|
46
59
|
"files": [
|
|
47
60
|
"dist",
|
|
48
61
|
"src"
|
|
49
62
|
],
|
|
50
|
-
"scripts": {
|
|
51
|
-
"dev": "vite --host",
|
|
52
|
-
"build": "tsc && vite build --config vite.config.lib.ts",
|
|
53
|
-
"build:lib": "vite build --config vite.config.lib.ts",
|
|
54
|
-
"preview": "vite preview",
|
|
55
|
-
"typecheck": "tsc --noEmit",
|
|
56
|
-
"clean": "rm -rf dist"
|
|
57
|
-
},
|
|
58
63
|
"dependencies": {
|
|
59
|
-
"@chaaskit/shared": "^0.1.
|
|
64
|
+
"@chaaskit/shared": "^0.1.2",
|
|
60
65
|
"lucide-react": "^0.321.0",
|
|
61
66
|
"react": "^18.2.0",
|
|
62
67
|
"react-dom": "^18.2.0",
|
|
@@ -80,5 +85,13 @@
|
|
|
80
85
|
"react": "^18.2.0",
|
|
81
86
|
"react-dom": "^18.2.0",
|
|
82
87
|
"react-router": "^7.0.0"
|
|
88
|
+
},
|
|
89
|
+
"scripts": {
|
|
90
|
+
"dev": "vite --host",
|
|
91
|
+
"build": "tsc && vite build --config vite.config.lib.ts",
|
|
92
|
+
"build:lib": "vite build --config vite.config.lib.ts",
|
|
93
|
+
"preview": "vite preview",
|
|
94
|
+
"typecheck": "tsc --noEmit",
|
|
95
|
+
"clean": "rm -rf dist"
|
|
83
96
|
}
|
|
84
|
-
}
|
|
97
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
1
|
+
import { useMemo, useState } from 'react';
|
|
2
2
|
import { Copy, Check, RefreshCw, ThumbsUp, ThumbsDown, User, Bot, GitBranch } from 'lucide-react';
|
|
3
3
|
import { useNavigate } from 'react-router';
|
|
4
4
|
import type { Message } from '@chaaskit/shared';
|
|
@@ -6,6 +6,7 @@ import { useChatStore } from '../stores/chatStore';
|
|
|
6
6
|
import { useTheme } from '../contexts/ThemeContext';
|
|
7
7
|
import { useConfig } from '../contexts/ConfigContext';
|
|
8
8
|
import { useAppPath } from '../hooks/useAppPath';
|
|
9
|
+
import { useExtensionTools } from '../extensions/useExtensions';
|
|
9
10
|
import MarkdownRenderer from './content/MarkdownRenderer';
|
|
10
11
|
import ToolCallDisplay, { UIResourceWidget } from './ToolCallDisplay';
|
|
11
12
|
import BranchModal from './BranchModal';
|
|
@@ -27,6 +28,12 @@ export default function MessageItem({ message, isStreaming, messageIndex = 0, pr
|
|
|
27
28
|
const config = useConfig();
|
|
28
29
|
const navigate = useNavigate();
|
|
29
30
|
const appPath = useAppPath();
|
|
31
|
+
const extensionTools = useExtensionTools();
|
|
32
|
+
const toolRendererMap = useMemo(() => {
|
|
33
|
+
const map = new Map<string, typeof extensionTools[number]>();
|
|
34
|
+
extensionTools.forEach((tool) => map.set(tool.name, tool));
|
|
35
|
+
return map;
|
|
36
|
+
}, [extensionTools]);
|
|
30
37
|
|
|
31
38
|
const isUser = message.role === 'user';
|
|
32
39
|
const showToolCalls = config.mcp?.showToolCalls !== false;
|
|
@@ -88,9 +95,22 @@ export default function MessageItem({ message, isStreaming, messageIndex = 0, pr
|
|
|
88
95
|
toolResult: message.toolResults?.find((r) => r.toolCallId === toolCall.id),
|
|
89
96
|
})) || [];
|
|
90
97
|
|
|
98
|
+
const renderedToolCalls = toolCallsWithResults
|
|
99
|
+
.filter(({ toolCall, toolResult }) =>
|
|
100
|
+
toolCall.serverId === 'native' &&
|
|
101
|
+
!!toolResult &&
|
|
102
|
+
!!toolRendererMap.get(toolCall.toolName)?.resultRenderer
|
|
103
|
+
)
|
|
104
|
+
.map(({ toolCall, toolResult }) => {
|
|
105
|
+
const renderer = toolRendererMap.get(toolCall.toolName)!.resultRenderer!;
|
|
106
|
+
return { toolCall, toolResult: toolResult!, Renderer: renderer };
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const renderedToolCallIds = new Set(renderedToolCalls.map((entry) => entry.toolCall.id));
|
|
110
|
+
|
|
91
111
|
// Check if any tool has a UI resource to render
|
|
92
112
|
const uiResources = toolCallsWithResults
|
|
93
|
-
.filter((tc) => tc.toolResult?.uiResource?.text)
|
|
113
|
+
.filter((tc) => tc.toolResult?.uiResource?.text && !renderedToolCallIds.has(tc.toolCall.id))
|
|
94
114
|
.map((tc) => tc.toolResult!.uiResource!);
|
|
95
115
|
|
|
96
116
|
// Debug logging
|
|
@@ -188,7 +208,18 @@ export default function MessageItem({ message, isStreaming, messageIndex = 0, pr
|
|
|
188
208
|
</div>
|
|
189
209
|
)}
|
|
190
210
|
|
|
191
|
-
{/* 2.
|
|
211
|
+
{/* 2. Tool Renderers (native tools) */}
|
|
212
|
+
{renderedToolCalls.length > 0 && (
|
|
213
|
+
<div className="space-y-3">
|
|
214
|
+
{renderedToolCalls.map(({ toolCall, toolResult, Renderer }) => (
|
|
215
|
+
<div key={toolCall.id} className="rounded-lg border border-border bg-background-secondary/40 p-3">
|
|
216
|
+
<Renderer toolCall={toolCall} toolResult={toolResult} />
|
|
217
|
+
</div>
|
|
218
|
+
))}
|
|
219
|
+
</div>
|
|
220
|
+
)}
|
|
221
|
+
|
|
222
|
+
{/* 3. UI Resource Widgets (outside bubble, full width) */}
|
|
192
223
|
{uiResources.length > 0 && (
|
|
193
224
|
<div className="space-y-3">
|
|
194
225
|
{uiResources.map((uiResource, index) => (
|
|
@@ -197,7 +228,7 @@ export default function MessageItem({ message, isStreaming, messageIndex = 0, pr
|
|
|
197
228
|
</div>
|
|
198
229
|
)}
|
|
199
230
|
|
|
200
|
-
{/*
|
|
231
|
+
{/* 4. Text Response Bubble (with avatar) */}
|
|
201
232
|
{(message.content || isStreaming) && (
|
|
202
233
|
<div className="group flex gap-3">
|
|
203
234
|
{/* Avatar */}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { useRef, useEffect } from 'react';
|
|
2
|
-
import type { Message, MCPContent, UIResource } from '@chaaskit/shared';
|
|
1
|
+
import { useMemo, useRef, useEffect } from 'react';
|
|
2
|
+
import type { Message, MCPContent, UIResource, ToolCall, ToolResult } from '@chaaskit/shared';
|
|
3
3
|
import { Bot } from 'lucide-react';
|
|
4
4
|
import { useTheme } from '../contexts/ThemeContext';
|
|
5
5
|
import { useConfig } from '../contexts/ConfigContext';
|
|
6
|
+
import { useExtensionTools } from '../extensions/useExtensions';
|
|
6
7
|
import MessageItem from './MessageItem';
|
|
7
8
|
import ToolCallDisplay, { UIResourceWidget } from './ToolCallDisplay';
|
|
8
9
|
|
|
@@ -17,6 +18,7 @@ interface CompletedToolCall extends PendingToolCall {
|
|
|
17
18
|
result: MCPContent[];
|
|
18
19
|
isError?: boolean;
|
|
19
20
|
uiResource?: UIResource;
|
|
21
|
+
structuredContent?: Record<string, unknown>;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
interface MessageListProps {
|
|
@@ -35,6 +37,12 @@ export default function MessageList({
|
|
|
35
37
|
const bottomRef = useRef<HTMLDivElement>(null);
|
|
36
38
|
const { theme } = useTheme();
|
|
37
39
|
const config = useConfig();
|
|
40
|
+
const extensionTools = useExtensionTools();
|
|
41
|
+
const toolRendererMap = useMemo(() => {
|
|
42
|
+
const map = new Map<string, typeof extensionTools[number]>();
|
|
43
|
+
extensionTools.forEach((tool) => map.set(tool.name, tool));
|
|
44
|
+
return map;
|
|
45
|
+
}, [extensionTools]);
|
|
38
46
|
const showToolCalls = config.mcp?.showToolCalls !== false;
|
|
39
47
|
|
|
40
48
|
useEffect(() => {
|
|
@@ -45,8 +53,34 @@ export default function MessageList({
|
|
|
45
53
|
const isStreaming = Boolean(streamingContent) || hasToolActivity;
|
|
46
54
|
|
|
47
55
|
// Get UI resources from completed tool calls for separate rendering
|
|
56
|
+
const renderedToolCalls = completedToolCalls
|
|
57
|
+
.filter((call) =>
|
|
58
|
+
call.serverId === 'native' &&
|
|
59
|
+
!!toolRendererMap.get(call.name)?.resultRenderer
|
|
60
|
+
)
|
|
61
|
+
.map((call) => {
|
|
62
|
+
const renderer = toolRendererMap.get(call.name)!.resultRenderer!;
|
|
63
|
+
const toolCall: ToolCall = {
|
|
64
|
+
id: call.id,
|
|
65
|
+
serverId: call.serverId,
|
|
66
|
+
toolName: call.name,
|
|
67
|
+
arguments: call.input,
|
|
68
|
+
status: call.isError ? 'error' : 'completed',
|
|
69
|
+
};
|
|
70
|
+
const toolResult: ToolResult = {
|
|
71
|
+
toolCallId: call.id,
|
|
72
|
+
content: call.result,
|
|
73
|
+
isError: call.isError,
|
|
74
|
+
uiResource: call.uiResource,
|
|
75
|
+
structuredContent: call.structuredContent,
|
|
76
|
+
};
|
|
77
|
+
return { toolCall, toolResult, Renderer: renderer };
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const renderedToolCallIds = new Set(renderedToolCalls.map((entry) => entry.toolCall.id));
|
|
81
|
+
|
|
48
82
|
const uiResources = completedToolCalls
|
|
49
|
-
.filter((tc) => tc.uiResource?.text)
|
|
83
|
+
.filter((tc) => tc.uiResource?.text && !renderedToolCallIds.has(tc.id))
|
|
50
84
|
.map((tc) => tc.uiResource!);
|
|
51
85
|
|
|
52
86
|
// Debug logging
|
|
@@ -96,6 +130,7 @@ export default function MessageList({
|
|
|
96
130
|
toolCallId: call.id,
|
|
97
131
|
content: call.result,
|
|
98
132
|
isError: call.isError,
|
|
133
|
+
structuredContent: call.structuredContent,
|
|
99
134
|
}}
|
|
100
135
|
hideUiResource
|
|
101
136
|
/>
|
|
@@ -118,7 +153,18 @@ export default function MessageList({
|
|
|
118
153
|
</div>
|
|
119
154
|
)}
|
|
120
155
|
|
|
121
|
-
{/* 2.
|
|
156
|
+
{/* 2. Tool Renderers (native tools) */}
|
|
157
|
+
{renderedToolCalls.length > 0 && (
|
|
158
|
+
<div className="space-y-3">
|
|
159
|
+
{renderedToolCalls.map(({ toolCall, toolResult, Renderer }) => (
|
|
160
|
+
<div key={toolCall.id} className="rounded-lg border border-border bg-background-secondary/40 p-3">
|
|
161
|
+
<Renderer toolCall={toolCall} toolResult={toolResult} />
|
|
162
|
+
</div>
|
|
163
|
+
))}
|
|
164
|
+
</div>
|
|
165
|
+
)}
|
|
166
|
+
|
|
167
|
+
{/* 3. UI Resource Widgets (outside bubble, full width) */}
|
|
122
168
|
{uiResources.length > 0 && (
|
|
123
169
|
<div className="space-y-3">
|
|
124
170
|
{uiResources.map((uiResource, index) => (
|
|
@@ -127,7 +173,7 @@ export default function MessageList({
|
|
|
127
173
|
</div>
|
|
128
174
|
)}
|
|
129
175
|
|
|
130
|
-
{/*
|
|
176
|
+
{/* 4. Text Response Bubble (with avatar) */}
|
|
131
177
|
{streamingContent && (
|
|
132
178
|
<div className="group flex gap-3">
|
|
133
179
|
{/* Avatar */}
|
|
@@ -18,7 +18,7 @@ export default function OAuthAppsSection() {
|
|
|
18
18
|
const [revokingId, setRevokingId] = useState<string | null>(null);
|
|
19
19
|
|
|
20
20
|
// Check if OAuth is enabled
|
|
21
|
-
const oauthEnabled = config.mcp?.server
|
|
21
|
+
const oauthEnabled = config.mcp?.servers?.some((server) => server.authMode === 'user-oauth');
|
|
22
22
|
|
|
23
23
|
useEffect(() => {
|
|
24
24
|
if (oauthEnabled) {
|
|
@@ -373,9 +373,7 @@ export default function Sidebar({ onClose, onOpenSearch }: SidebarProps) {
|
|
|
373
373
|
)}
|
|
374
374
|
|
|
375
375
|
{/* Admin Dashboard - show for site admins (config or database flag) */}
|
|
376
|
-
{(user?.isAdmin || config.
|
|
377
|
-
(email: string) => email.toLowerCase() === user?.email?.toLowerCase()
|
|
378
|
-
)) && (
|
|
376
|
+
{(user?.isAdmin || config.auth?.isAdmin) && (
|
|
379
377
|
<Link
|
|
380
378
|
to={appPath('/admin')}
|
|
381
379
|
className="mb-1 flex w-full items-center gap-2 rounded-md px-2.5 py-1.5 text-xs text-text-secondary hover:bg-background-secondary hover:text-text-primary active:bg-background-secondary"
|