- {!isAtBottom && (
-
- )}
-
{children}
+
+
+
setIsSettled(true)}
+ onExit={() => setIsSettled(false)}
+ >
+
+
);
}
-const toContentPart = (
- item: ChildActivityItem,
- reasoningMarkerLabel: string,
-): TMessageContentParts => {
+const toContentPart = (item: ChildActivityItem): TMessageContentParts => {
if (item.type === 'writing') {
return {
type: ContentTypes.TEXT,
@@ -188,14 +200,15 @@ const toContentPart = (
if (item.type === 'reasoning') {
if (item.text == null || item.text === '') {
return {
- type: ContentTypes.ACTIVITY_LABEL,
- [ContentTypes.ACTIVITY_LABEL]: item.label ?? reasoningMarkerLabel,
- activity_label_type: 'phase',
+ type: ContentTypes.THINK,
+ think: '',
+ reasoning_unavailable: true,
+ ...(item.label == null ? {} : { reasoning_label: item.label }),
} as TMessageContentParts;
}
return {
type: ContentTypes.THINK,
- think: item.text ?? '',
+ think: item.text,
...(item.label == null ? {} : { reasoning_label: item.label }),
} as TMessageContentParts;
}
@@ -305,11 +318,7 @@ export function SubagentActivityContent({
}) {
const localize = useLocalize();
const isSubmitting = activity.status === 'running' || activity.status === 'dispatched';
- const reasoningMarkerLabel = localize('com_ui_subagent_ticker_reasoning');
- const parts = useMemo(
- () => activity.items.map((item) => toContentPart(item, reasoningMarkerLabel)),
- [activity.items, reasoningMarkerLabel],
- );
+ const parts = useMemo(() => activity.items.map(toContentPart), [activity.items]);
const activityDetailsTruncated = hasTruncatedActivityDetails(activity);
let body: React.ReactNode;
diff --git a/client/src/components/Chat/Subagents/SubagentConversation.test.tsx b/client/src/components/Chat/Subagents/SubagentConversation.test.tsx
index c2a49c2bff..0049992b72 100644
--- a/client/src/components/Chat/Subagents/SubagentConversation.test.tsx
+++ b/client/src/components/Chat/Subagents/SubagentConversation.test.tsx
@@ -120,10 +120,10 @@ describe('SubagentConversation', () => {
expect(container.querySelectorAll('.agent-turn')).toHaveLength(2);
expect(container.querySelector('[data-subagent-conversation]')).toBeInTheDocument();
expect(screen.queryByText('com_ui_prompt')).not.toBeInTheDocument();
+ expect(screen.getByText('com_ui_subagent_activity_details_truncated')).toBeInTheDocument();
expect(
- screen.queryByText('com_ui_subagent_activity_details_truncated'),
+ screen.queryByText('com_ui_subagent_activity_details_unavailable'),
).not.toBeInTheDocument();
- expect(screen.getByText('com_ui_subagent_activity_details_unavailable')).toBeInTheDocument();
fireEvent.click(
screen.getByRole('button', {
diff --git a/client/src/components/Chat/Subagents/SubagentConversation.tsx b/client/src/components/Chat/Subagents/SubagentConversation.tsx
index cc841d4c66..40638fa8d6 100644
--- a/client/src/components/Chat/Subagents/SubagentConversation.tsx
+++ b/client/src/components/Chat/Subagents/SubagentConversation.tsx
@@ -4,6 +4,7 @@ import { ContentTypes, EModelEndpoint } from 'librechat-data-provider';
import { Bot, ChevronDown, CornerDownRight, Radio } from 'lucide-react';
import { Button, Collapsible, CollapsibleContent, CollapsibleTrigger } from '@librechat/client';
import type { TMessageContentParts } from 'librechat-data-provider';
+import type { ReactNode } from 'react';
import type { ChildConversationTurn } from './adapters';
import type { TranslationKeys } from '~/hooks';
import {
@@ -166,8 +167,27 @@ function ChildMessage({
const agentsMap = useAgentsMapContext();
const agent = agentId == null ? undefined : agentsMap?.[agentId];
const label = agent?.name ?? turn.activity.title;
- const detailsLimited =
- turn.activity.activityTruncated === true || hasTruncatedActivityDetails(turn.activity);
+ const wholeActivityTruncated = turn.activity.activityTruncated === true;
+ const detailsLimited = wholeActivityTruncated || hasTruncatedActivityDetails(turn.activity);
+ let limitedNotice: ReactNode;
+ if (wholeActivityTruncated && onLoadDetails != null && detailState !== 'unavailable') {
+ limitedNotice = (
+
+ );
+ } else if (wholeActivityTruncated) {
+ limitedNotice = localize('com_ui_subagent_activity_details_unavailable');
+ } else {
+ /** Only item-level fields were shortened for display; the run's full
+ * activity is otherwise present, so avoid the alarming "unavailable"
+ * framing there. */
+ limitedNotice = (
+
{localize('com_ui_subagent_activity_details_truncated')}
+ );
+ }
const iconData = {
endpoint: EModelEndpoint.agents,
modelLabel: label,
@@ -204,19 +224,7 @@ function ChildMessage({
onCancelControl={onCancelControl}
/>
{detailsLimited && detailState !== 'loading' && (
-
- {turn.activity.activityTruncated === true &&
- onLoadDetails != null &&
- detailState !== 'unavailable' ? (
-
- ) : (
- localize('com_ui_subagent_activity_details_unavailable')
- )}
-
+
{limitedNotice}
)}
{detailState === 'loading' && (
diff --git a/client/src/components/Chat/Subagents/SubagentThreadPanel.test.tsx b/client/src/components/Chat/Subagents/SubagentThreadPanel.test.tsx
index ba4177aaf6..01d062328c 100644
--- a/client/src/components/Chat/Subagents/SubagentThreadPanel.test.tsx
+++ b/client/src/components/Chat/Subagents/SubagentThreadPanel.test.tsx
@@ -237,7 +237,15 @@ jest.mock('@librechat/client', () => {
);
},
- Textarea: (props: React.ComponentProps<'textarea'>) => ,
+ composerSurfaceClasses: () => '',
+ composerSurfaceShadow: { focused: '', blurred: '', within: '' },
+ TextareaAutosize: ({
+ minRows: _minRows,
+ maxRows: _maxRows,
+ ...props
+ }: React.ComponentProps<'textarea'> & { minRows?: number; maxRows?: number }) => (
+
+ ),
useMediaQuery: () => mockIsMobile,
useToastContext: () => ({ showToast: mockShowToast }),
};
diff --git a/client/src/components/Chat/Subagents/SubagentThreadPanel.tsx b/client/src/components/Chat/Subagents/SubagentThreadPanel.tsx
index fcd0b732af..038b3e4d65 100644
--- a/client/src/components/Chat/Subagents/SubagentThreadPanel.tsx
+++ b/client/src/components/Chat/Subagents/SubagentThreadPanel.tsx
@@ -12,12 +12,14 @@ import {
import {
Button,
Alert,
+ composerSurfaceClasses,
+ composerSurfaceShadow,
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
- Textarea,
+ TextareaAutosize,
useMediaQuery,
useToastContext,
} from '@librechat/client';
@@ -58,6 +60,7 @@ import { useParentSubagents } from './ParentSubagentsProvider';
import SubagentConversation from './SubagentConversation';
import { eventSubagentSelection } from './eventSelection';
import { useAgentsMapContext } from '~/Providers';
+import { cn } from '~/utils';
const EVENT_TASK_PAGE_SIZE = 3;
const TERMINAL_CONTROL_REASONS = new Set([
@@ -230,6 +233,7 @@ export default function SubagentThreadPanel({ selection }: { selection: ActiveSu
useEffect(() => {
if (
selection.event == null ||
+ selection.event.pinnedTask === true ||
eventSummary?.latestTaskId == null ||
eventSummary.latestTaskId === taskId
) {
@@ -1082,20 +1086,6 @@ export default function SubagentThreadPanel({ selection }: { selection: ActiveSu
)}
- {canContinueAsChat && (
-
- )}