diff --git a/bun.lock b/bun.lock index 53f07be..5cb0e1e 100644 --- a/bun.lock +++ b/bun.lock @@ -6,7 +6,7 @@ "name": "tanstack-start-app", "dependencies": { "@clickhouse/click-ui": "0.2.0-rc.4", - "@librechat/data-schemas": "^0.0.48", + "@librechat/data-schemas": "^0.0.51", "@tailwindcss/vite": "^4.1.18", "@tanstack/react-devtools": "0.10.0", "@tanstack/react-query": "5.95.2", @@ -25,7 +25,7 @@ "i18next-browser-languagedetector": "^8.2.1", "input-otp": "^1.4.2", "js-yaml": "^4.1.1", - "librechat-data-provider": "^0.8.407", + "librechat-data-provider": "^0.8.502", "lucide-react": "^0.545.0", "prom-client": "^15.1.3", "react": "^19.2.0", @@ -292,7 +292,7 @@ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "3.1.2", "@jridgewell/sourcemap-codec": "1.5.5" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - "@librechat/data-schemas": ["@librechat/data-schemas@0.0.48", "", { "peerDependencies": { "jsonwebtoken": "^9.0.2", "klona": "^2.0.6", "librechat-data-provider": "*", "lodash": "^4.17.23", "meilisearch": "^0.38.0", "mongoose": "^8.12.1", "nanoid": "^3.3.7", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0" } }, "sha512-b9RWcBmK+b6ZctVX4sx6b77muzGOrNEGWc/RQbVwcnrVqsXitkwEGXylxv30ASE7mbbhqlnpm6sqCeQdexn5YA=="], + "@librechat/data-schemas": ["@librechat/data-schemas@0.0.51", "", { "peerDependencies": { "jsonwebtoken": "^9.0.2", "klona": "^2.0.6", "librechat-data-provider": "*", "lodash": "^4.17.23", "meilisearch": "^0.38.0", "mongoose": "^8.23.1", "nanoid": "^3.3.7", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0" } }, "sha512-EBfuq2NitbxgnoJZMXvH8FARvDkte8vNTfE+QDqpnktbM0ftvRqh6wxXQcq2JL50ED8ApuSewoni6gLVCVBwkw=="], "@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.4.6", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-y+x3H1xBZd38n10NZF/rEBlvDOOMQ6LKUTHqr8R9VkJ+mmQOYtJFxIlkkK8fZrtOiL6VixbOBWMbZGBdal3Z1g=="], @@ -762,7 +762,7 @@ "axe-core": ["axe-core@4.11.1", "", {}, "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A=="], - "axios": ["axios@1.13.6", "", { "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ=="], + "axios": ["axios@1.16.1", "", { "dependencies": { "follow-redirects": "^1.16.0", "form-data": "^4.0.5", "https-proxy-agent": "^5.0.1", "proxy-from-env": "^2.1.0" } }, "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A=="], "babel-dead-code-elimination": ["babel-dead-code-elimination@1.0.12", "", { "dependencies": { "@babel/core": "7.29.0", "@babel/parser": "7.29.0", "@babel/traverse": "7.29.0", "@babel/types": "7.29.0" } }, "sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig=="], @@ -1018,7 +1018,7 @@ "fn.name": ["fn.name@1.1.0", "", {}, "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="], - "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], + "follow-redirects": ["follow-redirects@1.16.0", "", {}, "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw=="], "form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], @@ -1188,7 +1188,7 @@ "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], - "librechat-data-provider": ["librechat-data-provider@0.8.407", "", { "dependencies": { "axios": "1.13.6", "dayjs": "^1.11.13", "js-yaml": "^4.1.1", "zod": "^3.22.4" }, "peerDependencies": { "@tanstack/react-query": "^4.28.0" } }, "sha512-oMp+d7YFnKRCUu9CAFX0fzU7Z4xOFkiA/Ib9abug+5lRiIvTHZ2r+LvQI+xGJ8aJEcIvBdTPmxrtAIuG3St8pA=="], + "librechat-data-provider": ["librechat-data-provider@0.8.502", "", { "dependencies": { "axios": "^1.16.0", "dayjs": "^1.11.13", "js-yaml": "^4.1.1", "zod": "^3.22.4" }, "peerDependencies": { "@tanstack/react-query": "^4.28.0" } }, "sha512-t88K1SNZ/o/uSK/MyuMfxhLp4FJsf2shxpa855Lbu0jvtiM4HQ0Mau7GJfuJUzZff9ycOirVTc1xiKmyMl7HPA=="], "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], @@ -1374,7 +1374,7 @@ "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], - "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], + "proxy-from-env": ["proxy-from-env@2.1.0", "", {}, "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA=="], "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], @@ -1924,6 +1924,8 @@ "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "axios/https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="], + "cheerio/parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "6.0.1" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], "chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "4.0.3" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], @@ -2070,6 +2072,8 @@ "@vitest/mocker/vite/postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "3.3.11", "picocolors": "1.1.1", "source-map-js": "1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], + "axios/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="], + "color/color-convert/color-name": ["color-name@2.1.0", "", {}, "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg=="], "eslint-plugin-click-ui/eslint/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], diff --git a/package.json b/package.json index b28deed..a15c01d 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ }, "dependencies": { "@clickhouse/click-ui": "0.2.0-rc.4", - "@librechat/data-schemas": "^0.0.48", + "@librechat/data-schemas": "^0.0.51", "@tailwindcss/vite": "^4.1.18", "@tanstack/react-devtools": "0.10.0", "@tanstack/react-query": "5.95.2", @@ -41,7 +41,7 @@ "i18next-browser-languagedetector": "^8.2.1", "input-otp": "^1.4.2", "js-yaml": "^4.1.1", - "librechat-data-provider": "^0.8.407", + "librechat-data-provider": "^0.8.502", "lucide-react": "^0.545.0", "prom-client": "^15.1.3", "react": "^19.2.0", diff --git a/src/components/access/RolePermissionsPanel.tsx b/src/components/access/RolePermissionsPanel.tsx index 3b670b6..20f8c72 100644 --- a/src/components/access/RolePermissionsPanel.tsx +++ b/src/components/access/RolePermissionsPanel.tsx @@ -12,6 +12,7 @@ const PERMISSION_TYPE_ORDER: PermissionTypes[] = [ PermissionTypes.MEMORIES, PermissionTypes.MCP_SERVERS, PermissionTypes.REMOTE_AGENTS, + PermissionTypes.SKILLS, PermissionTypes.BOOKMARKS, PermissionTypes.MULTI_CONVO, PermissionTypes.TEMPORARY_CHAT, diff --git a/src/components/configuration/configMeta.ts b/src/components/configuration/configMeta.ts index 6a7931b..97c957c 100644 --- a/src/components/configuration/configMeta.ts +++ b/src/components/configuration/configMeta.ts @@ -109,6 +109,11 @@ export const SECTION_META: Record< descriptionKey: 'com_config_section_fileStrategies_desc', tab: 'files', }, + cloudfront: { + titleKey: 'com_config_section_cloudfront', + descriptionKey: 'com_config_section_cloudfront_desc', + tab: 'files', + }, imageOutputType: { titleKey: 'com_config_section_imageOutputType', descriptionKey: 'com_config_section_imageOutputType_desc', diff --git a/src/constants/role.ts b/src/constants/role.ts index 97f7790..6ce305b 100644 --- a/src/constants/role.ts +++ b/src/constants/role.ts @@ -47,6 +47,12 @@ export const PERMISSION_TYPE_SCHEMA: Record = { Permissions.SHARE, Permissions.SHARE_PUBLIC, ], + [PermissionTypes.SKILLS]: [ + Permissions.USE, + Permissions.CREATE, + Permissions.SHARE, + Permissions.SHARE_PUBLIC, + ], }; export function defaultPermissions(): t.RolePermissions { diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 9719e25..13fed10 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -240,6 +240,8 @@ "com_config_field_firecrawlVersion": "Firecrawl version", "com_config_field_jinaApiKey": "Jina API key", "com_config_field_jinaApiUrl": "Jina API URL", + "com_config_field_tavilyApiKey": "Tavily API key", + "com_config_field_tavilySearchUrl": "Tavily search URL", "com_config_field_cohereApiKey": "Cohere API key", "com_config_field_searchProvider": "Search provider", "com_config_field_scraperProvider": "Scraper provider", @@ -606,8 +608,52 @@ "com_config_field_mcpServers_item": "server", "com_config_field_default_item": "item", "com_config_field_capabilities_item": "capability", + "com_config_field_tavilyExtractUrl": "Tavily extract URL", + "com_config_field_tavilySearchOptions": "Tavily search options", + "com_config_field_tavilyScraperOptions": "Tavily scraper options", + "com_config_field_searchDepth": "Search depth", + "com_config_field_extractDepth": "Extract depth", + "com_config_field_maxResults": "Max results", + "com_config_field_includeImages": "Include images", + "com_config_field_includeImageDescriptions": "Include image descriptions", + "com_config_field_includeFavicon": "Include favicon", + "com_config_field_includeAnswer": "Include answer", + "com_config_field_includeRawContent": "Include raw content", + "com_config_field_includeDomains": "Include domains", + "com_config_field_excludeDomains": "Exclude domains", + "com_config_field_topic": "Topic", + "com_config_field_timeRange": "Time range", + "com_config_field_chunksPerSource": "Chunks per source", + "com_config_field_format": "Format", + "com_config_field_allowedAddresses": "Allowed addresses", + "com_config_field_autoSubmitFromUrl": "Auto-submit from URL", + "com_config_field_skills": "Skills", + "com_config_field_defaultActiveOnShare": "Default active on share", + "com_config_field_thinkingDisplay": "Thinking display", + "com_config_field_cloudfront": "CloudFront", + "com_config_field_domain": "Domain", + "com_config_field_distributionId": "Distribution ID", + "com_config_field_invalidateOnDelete": "Invalidate on delete", + "com_config_field_imageSigning": "Image signing", + "com_config_field_urlExpiry": "URL expiry", + "com_config_field_cookieExpiry": "Cookie expiry", + "com_config_field_cookieDomain": "Cookie domain", + "com_config_field_storageRegion": "Storage region", + "com_config_field_includeRegionInPath": "Include region in path", + "com_config_field_requireSignedAccess": "Require signed access", + "com_config_field_remoteApi": "Remote API", + "com_config_field_auth": "Auth", + "com_config_field_oidc": "OIDC", + "com_config_field_issuer": "Issuer", + "com_config_field_audience": "Audience", + "com_config_field_jwksUri": "JWKS URI", + "com_config_field_allowedAddresses_item": "address", + "com_config_field_includeDomains_item": "domain", + "com_config_field_excludeDomains_item": "domain", "com_config_section_fileStrategies": "File strategies", "com_config_section_fileStrategies_desc": "Configure file handling strategies per endpoint", + "com_config_section_cloudfront": "CloudFront", + "com_config_section_cloudfront_desc": "Serve files through an Amazon CloudFront distribution", "com_config_section_filteredTools": "Filtered tools", "com_config_section_filteredTools_desc": "Tools excluded from availability", "com_config_section_imageOutputType": "Image output type", @@ -852,6 +898,7 @@ "com_perm_desc_MEMORIES": "Manage persistent memory across conversations", "com_perm_desc_MCP_SERVERS": "Connect and manage MCP tool servers", "com_perm_desc_REMOTE_AGENTS": "Connect and manage remote agent endpoints", + "com_perm_desc_SKILLS": "Create, share, and use agent skills", "com_perm_desc_PEOPLE_PICKER": "Control visibility of users, groups, and roles", "com_perm_type_BOOKMARKS": "Bookmarks", "com_perm_type_PROMPTS": "Prompts", @@ -867,6 +914,7 @@ "com_perm_type_FILE_CITATIONS": "File citations", "com_perm_type_MCP_SERVERS": "MCP servers", "com_perm_type_REMOTE_AGENTS": "Remote agents", + "com_perm_type_SKILLS": "Skills", "com_perm_USE": "Use", "com_perm_CREATE": "Create", "com_perm_UPDATE": "Update", @@ -946,6 +994,8 @@ "com_cap_manage_mcpservers": "Manage MCP servers", "com_cap_read_prompts": "Read prompts", "com_cap_manage_prompts": "Manage prompts", + "com_cap_read_skills": "Read skills", + "com_cap_manage_skills": "Manage skills", "com_cap_read_assistants": "Read assistants", "com_cap_manage_assistants": "Manage assistants", "com_cap_desc_access_admin": "Full admin panel access", @@ -964,6 +1014,8 @@ "com_cap_desc_manage_mcpservers": "Manage MCP server connections", "com_cap_desc_read_prompts": "View prompt library", "com_cap_desc_manage_prompts": "Create, edit, and delete prompts", + "com_cap_desc_read_skills": "View skill configurations", + "com_cap_desc_manage_skills": "Create, edit, and delete skills", "com_cap_desc_read_assistants": "View assistant configurations", "com_cap_desc_manage_assistants": "Create, edit, and delete assistants", "com_access_denied_title": "Access denied", diff --git a/src/server/config.test.ts b/src/server/config.test.ts index fddc4bf..43e0327 100644 --- a/src/server/config.test.ts +++ b/src/server/config.test.ts @@ -634,8 +634,22 @@ describe('validateFieldValue', () => { * that LibreChat would reject at startup * -----------------------------------------------------------------------*/ +/** Per-path sample overrides for fields whose schema applies stricter + * validation than the generic control sample (URLs, host:port, etc.). */ +const SAMPLE_OVERRIDES: Record = { + 'cloudfront.domain': 'https://example.com', + 'cloudfront.cookieDomain': '.example.com', + 'mcpSettings.allowedAddresses': ['localhost:11434'], + 'actions.allowedAddresses': ['localhost:11434'], + 'endpoints.allowedAddresses': ['localhost:11434'], + 'endpoints.agents.remoteApi.auth.oidc.issuer': 'https://example.com', + 'endpoints.agents.remoteApi.auth.oidc.jwksUri': 'https://example.com/.well-known/jwks.json', + 'summarization.trigger': { type: 'token_ratio', value: 0.5 }, +}; + /** Generates a representative value that a given UI control would produce. */ -function sampleValueForControl(field: t.SchemaField): unknown { +function sampleValueForControl(field: t.SchemaField, path?: string): unknown { + if (path && path in SAMPLE_OVERRIDES) return SAMPLE_OVERRIDES[path]; const control = getControlType(field); switch (control) { case 'toggle': @@ -733,7 +747,7 @@ describe('control → value → safeParse round-trip (real configSchema)', () => const control = getControlType(field); it(`${path} (${field.type} → ${control}): sample value passes safeParse`, () => { - const value = sampleValueForControl(field); + const value = sampleValueForControl(field, path); const sub = resolveSubSchema(realConfigSchema, path.split('.')); if (!sub) return;