diff --git a/client/src/components/Chat/Messages/Content/AgentHandoff.tsx b/client/src/components/Chat/Messages/Content/AgentHandoff.tsx index b3ac9f3efb..b4c0004273 100644 --- a/client/src/components/Chat/Messages/Content/AgentHandoff.tsx +++ b/client/src/components/Chat/Messages/Content/AgentHandoff.tsx @@ -4,6 +4,7 @@ import { ChevronDown } from 'lucide-react'; import { Button } from '@librechat/client'; import { EModelEndpoint, Constants } from 'librechat-data-provider'; import type { TMessage } from 'librechat-data-provider'; +import type { TranslationKeys } from '~/hooks'; import CopyButton from '~/components/Messages/Content/CopyButton'; import { unescapeJsonString } from './Parts/parseJsonField'; import MessageIcon from '~/components/Share/MessageIcon'; @@ -78,7 +79,23 @@ function parseHandoffFields(args: string | Record): HandoffFiel } } -function fieldLabel(key: string): string { +/** + * The SDK's own prompt keys, which are the ones that carry product meaning. + * Any other key is an admin-authored `promptKey` from the agent graph (see + * `handoffPromptKeyCompatibility`), so it is author content with no + * localization key to map to and is left as written, like an agent's own name. + */ +const HANDOFF_FIELD_LABELS: Record = { + instruction: 'com_ui_handoff_field_instructions', + instructions: 'com_ui_handoff_field_instructions', + context: 'com_ui_handoff_field_context', +}; + +function fieldLabel(key: string, localize: (translationKey: TranslationKeys) => string): string { + const known = HANDOFF_FIELD_LABELS[key.toLowerCase()]; + if (known) { + return localize(known); + } const words = key .replace(/([a-z0-9])([A-Z])/g, '$1 $2') .replace(/[_-]+/g, ' ') @@ -118,9 +135,9 @@ const AgentHandoff: React.FC = ({ name, args: _args = '' }) = fields.length === 1 ? fields[0].value : fields - .map(({ key, value }) => `${key ? `${fieldLabel(key)}\n` : ''}${value}`) + .map(({ key, value }) => `${key ? `${fieldLabel(key, localize)}\n` : ''}${value}`) .join('\n\n'), - [fields], + [fields, localize], ); const hasInfo = fields.length > 0; const agentName = targetAgent?.name || localize('com_ui_agent'); @@ -215,7 +232,7 @@ const AgentHandoff: React.FC = ({ name, args: _args = '' }) =
{key && (
- {fieldLabel(key)} + {fieldLabel(key, localize)}
)}
diff --git a/client/src/hooks/Input/useAskAnswerMode.ts b/client/src/hooks/Input/useAskAnswerMode.ts index e9c0fce4ad..c862d3d72e 100644 --- a/client/src/hooks/Input/useAskAnswerMode.ts +++ b/client/src/hooks/Input/useAskAnswerMode.ts @@ -227,16 +227,14 @@ export default function useAskAnswerMode(conversationId?: string | null) { runHandoff(() => { if (!batchMode) { setAnswerDrafts((current) => ({ ...current, [liveAsk.actionId]: composerAnswer })); - if (!saveDrafts) { - /** Hand back whatever ordinary message was typed while this - * question owned the card, rather than clearing the composer and - * losing it. */ - const released = releasedComposerText[liveAsk.actionId]; - if (released) { - formContext?.setValue('text', released); - } else { - formContext?.reset(); - } + /** An existing stash is restored regardless of the CURRENT + * preference: it was captured while saving was off, so it never + * reached the conversation draft and this is its only recovery path. + * Gating on `!saveDrafts` dropped it whenever the user enabled + * saving between expanding and collapsing. */ + const released = releasedComposerText[liveAsk.actionId]; + if (released) { + formContext?.setValue('text', released); setReleasedComposerText((current) => { if (current[liveAsk.actionId] == null) { return current; @@ -245,6 +243,8 @@ export default function useAskAnswerMode(conversationId?: string | null) { delete next[liveAsk.actionId]; return next; }); + } else if (!saveDrafts) { + formContext?.reset(); } } setCollapsedIds((prev) => diff --git a/client/src/locales/en/translation.json b/client/src/locales/en/translation.json index 4b6b673d3f..4a28729e9f 100644 --- a/client/src/locales/en/translation.json +++ b/client/src/locales/en/translation.json @@ -1406,6 +1406,8 @@ "com_ui_greeting_working_on": "What are we working on?", "com_ui_greeting_working_on_named": "What are we working on, {{name}}?", "com_ui_group": "Group", + "com_ui_handoff_field_context": "Context", + "com_ui_handoff_field_instructions": "Instructions", "com_ui_handoff_instructions": "Handoff instructions", "com_ui_happy_birthday": "It's my 1st birthday!", "com_ui_header_format": "Header Format",