e.stopPropagation()}>
+
e.stopPropagation()}>
{isUpdate ? t('shareMode.titleUpdate') : t('share.toHub')}
diff --git a/packages/web-ui/src/pages/Team.tsx b/packages/web-ui/src/pages/Team.tsx
index 33ba2010..dfba2a94 100644
--- a/packages/web-ui/src/pages/Team.tsx
+++ b/packages/web-ui/src/pages/Team.tsx
@@ -653,13 +653,14 @@ function AgentMessageBody({
: undefined;
const textSegments = segments.filter(s => s.type === 'text');
const allText = !isStreaming ? textSegments.map(s => s.content).join('') : null;
- const displayText = allText
- ? allText
- .replace(/[\s\S]*?(<\/think>|$)/g, '')
- .replace(/<(invoke|function_calls|antml:\w+)\b[\s\S]*?(<\/\1>|$)/g, '')
- .replace(/<\/?(invoke|function_calls|antml:\w+)[^>]*>/g, '')
- .trim() || null
- : null;
+ const stripMarkup = (t: string) => t
+ .replace(/[\s\S]*?(<\/think>|$)/g, '')
+ .replace(/<(invoke|function_calls|antml:\w+)\b[\s\S]*?(<\/\1>|$)/g, '')
+ .replace(/<\/?(invoke|function_calls|antml:\w+)[^>]*>/g, '')
+ .trim() || null;
+ const segmentText = allText ? stripMarkup(allText) : null;
+ const displayText = segmentText
+ || (!isStreaming && msg.text ? stripMarkup(msg.text) : null);
// For the full execution log, prefer server-committed clean segments
// (populated from thinking_commit/text_commit SSE events) over fragmented
@@ -983,7 +984,7 @@ export function TeamPage({ initialAgentId, authUser }: { initialAgentId?: string
const thinkingTimeoutRef = useRef | null>(null);
const [streamingVisual, setStreamingVisual] = useState(false);
const streamingTimerRef = useRef | null>(null);
- const STREAMING_MIN_DISPLAY_MS = 1500;
+ const STREAMING_MIN_DISPLAY_MS = 400;
useEffect(() => {
if (sending) {
if (streamingTimerRef.current) { clearTimeout(streamingTimerRef.current); streamingTimerRef.current = null; }
@@ -1258,9 +1259,10 @@ export function TeamPage({ initialAgentId, authUser }: { initialAgentId?: string
useEffect(() => {
if (!isActive) return;
refreshAgents();
+ refreshTeams();
const timer = setInterval(refreshAgents, 30_000);
const teamTimer = setInterval(refreshTeams, 60_000);
- const unsub = wsClient.on('agent:update', throttledRefreshAgents);
+ const unsub = wsClient.on('agent:update', () => { throttledRefreshAgents(); throttledRefreshTeams(); });
const unsubTeamUpdate = wsClient.on('team:update', throttledRefreshTeams);
const unsubTeamOnAgentRemoved = wsClient.on('agent:removed', throttledRefreshTeams);
const unsubGroup = wsClient.on('chat:group_created', () => { throttledRefreshGroupChats(); throttledRefreshTeams(); });
diff --git a/packages/web-ui/src/pages/Work.tsx b/packages/web-ui/src/pages/Work.tsx
index b83446cb..af9d0b24 100644
--- a/packages/web-ui/src/pages/Work.tsx
+++ b/packages/web-ui/src/pages/Work.tsx
@@ -1,6 +1,6 @@
import { useState, useEffect, useCallback, useMemo, useRef, type DragEvent } from 'react';
import { useTranslation } from 'react-i18next';
-import { api, wsClient, ApiError, type ProjectInfo, type TaskInfo, type AgentInfo, type TaskLogEntry, type TaskComment, type RequirementComment, type RequirementInfo, type HumanUserInfo, type RoundSummary, type AuthUser, type ActivityRecord, type StatusTransitionInfo } from '../api.ts';
+import { api, wsClient, ApiError, invalidateApiCache, type ProjectInfo, type TaskInfo, type AgentInfo, type TaskLogEntry, type TaskComment, type RequirementComment, type RequirementInfo, type HumanUserInfo, type RoundSummary, type AuthUser, type ActivityRecord, type StatusTransitionInfo } from '../api.ts';
import { ConfirmModal } from '../components/ConfirmModal.tsx';
import { MemoExecEntryRow, ThinkingDots, StreamingText, filterCompletedStarts, streamEntryToExecEntry, attachSubagentLogsToEntries, FullExecutionLog, type ExecEntry, type ExecutionStreamEntryUI } from '../components/ExecutionTimeline.tsx';
import { taskLogToStreamEntry, activityLogToStreamEntry } from '../api.ts';
@@ -3493,7 +3493,9 @@ export function WorkPage({ authUser }: { authUser?: AuthUser }) {
const reqUnsubs = reqEvents.map(evt =>
wsClient.on(evt, () => { debouncedRefreshReqs(); })
);
- return () => { clearInterval(i); unsub(); unsubTaskCreate(); reqUnsubs.forEach(u => u()); if (boardDebounce) clearTimeout(boardDebounce); if (reqDebounce) clearTimeout(reqDebounce); };
+ const onDataChanged = () => { invalidateApiCache('/taskboard'); refreshBoard(); refreshRequirements(); };
+ window.addEventListener('markus:data-changed', onDataChanged);
+ return () => { clearInterval(i); unsub(); unsubTaskCreate(); reqUnsubs.forEach(u => u()); window.removeEventListener('markus:data-changed', onDataChanged); if (boardDebounce) clearTimeout(boardDebounce); if (reqDebounce) clearTimeout(reqDebounce); };
}, [isActive, refreshBoard, refreshAgents, refreshRequirements]);
// Refs for event handlers that need current state without re-registering