diff --git a/client/src/components/SidePanel/Agents/Tools/ItemDialog/__tests__/BuiltinSection.spec.tsx b/client/src/components/SidePanel/Agents/Tools/ItemDialog/__tests__/BuiltinSection.spec.tsx index ccc13227cbd..3060db3ff5c 100644 --- a/client/src/components/SidePanel/Agents/Tools/ItemDialog/__tests__/BuiltinSection.spec.tsx +++ b/client/src/components/SidePanel/Agents/Tools/ItemDialog/__tests__/BuiltinSection.spec.tsx @@ -1,7 +1,7 @@ import '@testing-library/jest-dom/extend-expect'; -import { MemoryScope } from 'librechat-data-provider'; import { useForm, FormProvider, useWatch } from 'react-hook-form'; import { render, screen, fireEvent } from '@testing-library/react'; +import { MemoryScope, ArtifactModes } from 'librechat-data-provider'; import type { ReactNode } from 'react'; import type { AgentForm } from '~/common'; import BuiltinSection from '../sections/BuiltinSection'; @@ -109,3 +109,37 @@ describe('BuiltinSection Run Code settings', () => { expect(screen.getByLabelText('com_ui_agent_git_email')).toBeInTheDocument(); }); }); + +describe('BuiltinSection artifacts mode docs link', () => { + const docsLink = () => screen.queryByRole('link', { name: 'com_ui_artifacts_mode_custom_docs' }); + + test('links Custom mode to the custom instructions docs in a new tab', () => { + renderSection('artifacts', { artifacts: ArtifactModes.CUSTOM }); + + const link = docsLink(); + expect(link).toHaveAttribute( + 'href', + 'https://www.librechat.ai/docs/features/artifacts#custom-instructions', + ); + expect(link).toHaveAttribute('target', '_blank'); + expect(link).toHaveAttribute('rel', 'noopener noreferrer'); + expect(link).toHaveTextContent('com_ui_learn_more'); + expect(screen.getByText(/com_ui_artifacts_mode_custom_info/)).toContainElement(link); + }); + + test.each([ArtifactModes.DEFAULT, ArtifactModes.SHADCNUI])( + 'shows no docs link for the %s mode', + (mode) => { + renderSection('artifacts', { artifacts: mode }); + expect(docsLink()).toBeNull(); + }, + ); + + test('shows the link after switching to Custom', () => { + renderSection('artifacts', { artifacts: ArtifactModes.DEFAULT }); + expect(docsLink()).toBeNull(); + + fireEvent.click(screen.getByRole('radio', { name: 'com_ui_artifacts_mode_custom' })); + expect(docsLink()).toBeInTheDocument(); + }); +}); diff --git a/client/src/components/SidePanel/Agents/Tools/ItemDialog/sections/BuiltinSection.tsx b/client/src/components/SidePanel/Agents/Tools/ItemDialog/sections/BuiltinSection.tsx index d8f3d63ee05..27943babdd1 100644 --- a/client/src/components/SidePanel/Agents/Tools/ItemDialog/sections/BuiltinSection.tsx +++ b/client/src/components/SidePanel/Agents/Tools/ItemDialog/sections/BuiltinSection.tsx @@ -23,10 +23,14 @@ interface Props { description?: string; } +const ARTIFACTS_CUSTOM_DOCS_URL = + 'https://www.librechat.ai/docs/features/artifacts#custom-instructions'; + const ARTIFACT_MODES: Array<{ value: string; labelKey: TranslationKeys; infoKey?: TranslationKeys; + docs?: { url: string; labelKey: TranslationKeys }; }> = [ { value: ArtifactModes.DEFAULT, @@ -42,6 +46,7 @@ const ARTIFACT_MODES: Array<{ value: ArtifactModes.CUSTOM, labelKey: 'com_ui_artifacts_mode_custom', infoKey: 'com_ui_artifacts_mode_custom_info', + docs: { url: ARTIFACTS_CUSTOM_DOCS_URL, labelKey: 'com_ui_artifacts_mode_custom_docs' }, }, ]; @@ -71,7 +76,23 @@ function ArtifactsConfig({ value, onChange }: ArtifactsConfigProps) { aria-labelledby="artifacts-mode-label" /> {active?.infoKey ? ( -

{localize(active.infoKey)}

+

+ {localize(active.infoKey)} + {active.docs ? ( + <> + {' '} + + {localize('com_ui_learn_more')} + + + ) : null} +

) : null} ); diff --git a/client/src/locales/en/translation.json b/client/src/locales/en/translation.json index 293183153d0..2e5d5b3e6ef 100644 --- a/client/src/locales/en/translation.json +++ b/client/src/locales/en/translation.json @@ -1264,7 +1264,8 @@ "com_ui_artifacts": "Artifacts", "com_ui_artifacts_mode": "Mode", "com_ui_artifacts_mode_custom": "Custom", - "com_ui_artifacts_mode_custom_info": "Keeps artifact rendering on but injects no built-in instructions. Write your own in the agent's instructions for full control.", + "com_ui_artifacts_mode_custom_docs": "Learn more about writing custom artifact instructions (opens in a new tab)", + "com_ui_artifacts_mode_custom_info": "Keeps artifact rendering on but injects no built-in instructions. The agent's instructions must teach the artifact syntax and the types it may use.", "com_ui_artifacts_mode_default": "Normal", "com_ui_artifacts_mode_default_info": "Standard artifact instructions: the agent renders React, HTML, SVG, Markdown, and Mermaid inline.", "com_ui_artifacts_mode_shadcn": "shadcn/ui", @@ -1945,6 +1946,7 @@ "com_ui_latest_activity": "Latest activity", "com_ui_latest_footer": "Every AI for Everyone.", "com_ui_latest_version": "Latest version", + "com_ui_learn_more": "Learn more", "com_ui_leave_blank_to_keep": "Leave blank to keep existing", "com_ui_lia_act_bounce_around": "Bounces in place", "com_ui_lia_act_come_closer": "Comes over to say hi",