diff --git a/frontend/nyaysetu-frontend/public/locales/en/litigant.json b/frontend/nyaysetu-frontend/public/locales/en/litigant.json
index 0b6baf19f..d5e36ad33 100644
--- a/frontend/nyaysetu-frontend/public/locales/en/litigant.json
+++ b/frontend/nyaysetu-frontend/public/locales/en/litigant.json
@@ -517,7 +517,9 @@
"hideAvatar": "Hide AI Avatar",
"showAvatar": "Show AI Avatar",
"avatarGreeting": "Namaste. I am your AI Legal Assistant. You can speak to me anytime.",
- "history": "History"
+ "history": "History",
+ "injectionAdvisory": "Your message contains phrasing that may not produce useful legal results. Please describe your legal question directly.",
+ "inputTooLong": "Your message is too long. Please shorten it to {{limit}} characters or fewer."
},
"common": {
diff --git a/frontend/nyaysetu-frontend/public/locales/hi/litigant.json b/frontend/nyaysetu-frontend/public/locales/hi/litigant.json
index 03934c244..e4a555085 100644
--- a/frontend/nyaysetu-frontend/public/locales/hi/litigant.json
+++ b/frontend/nyaysetu-frontend/public/locales/hi/litigant.json
@@ -519,7 +519,9 @@
"hideAvatar": "एआई अवतार छिपाएँ",
"showAvatar": "एआई अवतार दिखाएँ",
"avatarGreeting": "नमस्ते। मैं आपका एआई कानूनी सहायक हूँ। आप मुझसे कभी भी बात कर सकते हैं।",
- "history": "इतिहास"
+ "history": "इतिहास",
+ "injectionAdvisory": "आपके संदेश में ऐसी भाषा है जिससे उपयोगी कानूनी उत्तर नहीं मिल सकता। कृपया अपना कानूनी प्रश्न सीधे लिखें।",
+ "inputTooLong": "आपका संदेश बहुत लंबा है। कृपया इसे {{limit}} अक्षरों या उससे कम तक सीमित करें।"
},
"common": {
diff --git a/frontend/nyaysetu-frontend/public/locales/mr/litigant.json b/frontend/nyaysetu-frontend/public/locales/mr/litigant.json
index c50797f9c..4f0e4b3ae 100644
--- a/frontend/nyaysetu-frontend/public/locales/mr/litigant.json
+++ b/frontend/nyaysetu-frontend/public/locales/mr/litigant.json
@@ -665,7 +665,9 @@
"avatarGreeting": "नमस्कार. मी तुमचा AI कायदेशीर सहाय्यक आहे. तुम्ही कधीही माझ्याशी बोलू शकता.",
- "history": "इतिहास"
+ "history": "इतिहास",
+ "injectionAdvisory": "तुमच्या संदेशातील मजकुरामुळे उपयुक्त कायदेशीर उत्तर मिळणार नाही. कृपया तुमचा कायदेशीर प्रश्न थेट लिहा.",
+ "inputTooLong": "तुमचा संदेश खूप मोठा आहे. कृपया तो {{limit}} अक्षरांपर्यंत कमी करा."
},
diff --git a/frontend/nyaysetu-frontend/public/locales/ta/litigant.json b/frontend/nyaysetu-frontend/public/locales/ta/litigant.json
index 3e8aa536b..5f1042744 100644
--- a/frontend/nyaysetu-frontend/public/locales/ta/litigant.json
+++ b/frontend/nyaysetu-frontend/public/locales/ta/litigant.json
@@ -508,7 +508,9 @@
"hideAvatar": "AI Avatar மறைக்கவும்",
"showAvatar": "AI Avatar காட்டவும்",
"avatarGreeting": "வணக்கம். நான் உங்கள் AI சட்ட உதவியாளர். நீங்கள் எப்போதும் என்னிடம் பேசலாம்.",
- "history": "வரலாறு"
+ "history": "வரலாறு",
+ "injectionAdvisory": "உங்கள் செய்தியில் உள்ள சொற்றொடர்கள் பயனுள்ள சட்ட விளக்கத்தை அளிக்காமல் போகலாம். உங்கள் சட்டக் கேள்வியை நேரடியாக விவரிக்கவும்.",
+ "inputTooLong": "உங்கள் செய்தி மிக நீளமாக உள்ளது. தயவுசெய்து அதை {{limit}} எழுத்துகளுக்குள் சுருக்கவும்."
},
"common": {
diff --git a/frontend/nyaysetu-frontend/public/locales/te/litigant.json b/frontend/nyaysetu-frontend/public/locales/te/litigant.json
index 1d5b0c581..78f68d0de 100644
--- a/frontend/nyaysetu-frontend/public/locales/te/litigant.json
+++ b/frontend/nyaysetu-frontend/public/locales/te/litigant.json
@@ -508,7 +508,9 @@
"hideAvatar": "AI Avatar దాచండి",
"showAvatar": "AI Avatar చూపించండి",
"avatarGreeting": "నమస్కారం. నేను మీ AI న్యాయ సహాయకుడిని. మీరు ఎప్పుడైనా నాతో మాట్లాడవచ్చు.",
- "history": "చరిత్ర"
+ "history": "చరిత్ర",
+ "injectionAdvisory": "మీ సందేశంలోని పదజాలం ఉపయోగకరమైన న్యాయ సమాధానాన్ని ఇవ్వకపోవచ్చు. దయచేసి మీ న్యాయ ప్రశ్నను నేరుగా వివరించండి.",
+ "inputTooLong": "మీ సందేశం చాలా పొడవుగా ఉంది. దయచేసి దానిని {{limit}} అక్షరాలలోపు తగ్గించండి."
},
"common": {
diff --git a/frontend/nyaysetu-frontend/src/pages/litigant/VakilFriendPage.jsx b/frontend/nyaysetu-frontend/src/pages/litigant/VakilFriendPage.jsx
index 32a4d02b6..211e2272e 100644
--- a/frontend/nyaysetu-frontend/src/pages/litigant/VakilFriendPage.jsx
+++ b/frontend/nyaysetu-frontend/src/pages/litigant/VakilFriendPage.jsx
@@ -13,6 +13,14 @@ import AvatarPanel from '../../components/avatar/AvatarPanel';
import { useTranslation } from 'react-i18next';
import useChatStore from '../../store/chatStore';
import CaseSummaryViewer from '../../components/Summary/CaseSummaryViewer';
+import {
+ MAX_CHAT_INPUT_LENGTH,
+ formatCharacterCount,
+ hasPromptInjectionPattern,
+ isChatInputNearLimit,
+ isChatInputOverLimit,
+ sanitizeChatInput,
+} from '../../utils/chatInputSafety';
export default function VakilFriendChat() {
const { t } = useTranslation('litigant');
@@ -268,7 +276,20 @@ const {
const textToSend = overrideText || inputMessage;
if ((!textToSend.trim() && !audioData) || isLoading || isStarting) return;
- const userMessage = textToSend.trim();
+ // The send button is already disabled past the limit, but voice input and
+ // the wake-word buffer call sendMessage() directly, so re-check here.
+ if (isChatInputOverLimit(textToSend)) {
+ setError(t('vakilFriend.inputTooLong', {
+ limit: MAX_CHAT_INPUT_LENGTH.toLocaleString('en-IN')
+ }));
+ return;
+ }
+
+ // Strip tags and control characters before the text reaches the AI prompt
+ const userMessage = sanitizeChatInput(textToSend);
+ if (!userMessage && !audioData) return;
+
+ setError(null);
// Only clear the input message box if we aren't overriding it (standard UI flow)
if (!overrideText) setInputMessage('');
@@ -972,6 +993,12 @@ const startDeepResearch = async (query) => {
return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
};
+ // Input safety state derived from the current draft message
+ const inputOverLimit = isChatInputOverLimit(inputMessage);
+ const inputNearLimit = isChatInputNearLimit(inputMessage);
+ const showInjectionAdvisory = hasPromptInjectionPattern(inputMessage);
+ const sendDisabled = !inputMessage.trim() || inputOverLimit || isLoading || isStarting || rateLimited;
+
return (
{/* History Sidebar - Full screen modal */}
@@ -1278,6 +1305,8 @@ const startDeepResearch = async (query) => {
}}>
-
+ {/*
+ * User text is rendered as a plain React text child rather than
+ * as Markdown. React HTML-entity-encodes text children, so any
+ * tags a user types are displayed literally instead of being
+ * interpreted by the renderer.
+ */}
+ {msg.role === 'user' ? (
+