chore: test deploy snapshot
This commit is contained in:
@@ -617,6 +617,10 @@ function resolvePromptSubmissionParentRequestId(
|
||||
return resolveChildComposerParentRequestId(request, requestStateMap) || normalizedRequestId;
|
||||
}
|
||||
|
||||
function isPromptFollowupRequest(request: ChatConversationRequest) {
|
||||
return request.requestOrigin === 'prompt';
|
||||
}
|
||||
|
||||
function resolveConversationMessageGroupRequestId(
|
||||
requestId: string | null | undefined,
|
||||
requestStateMap: Map<string, ChatConversationRequest>,
|
||||
@@ -1155,6 +1159,10 @@ function collapseDuplicatedLeadingExecutorHeaders(text: string) {
|
||||
return collapsedLines.join('\n');
|
||||
}
|
||||
|
||||
function isRequestInFlightStatus(status: ChatConversationRequestStatus | null | undefined) {
|
||||
return status === 'accepted' || status === 'queued' || status === 'started';
|
||||
}
|
||||
|
||||
function extractMessageRenderPayload(message: ChatMessage): MessageRenderPayload {
|
||||
const structuredParts = Array.isArray(message.parts) ? message.parts : [];
|
||||
const attachmentExtraction = extractAttachmentPreviewUrls(message.text);
|
||||
@@ -1752,6 +1760,9 @@ function formatRequestStatusLabel(
|
||||
},
|
||||
) {
|
||||
const hideFinalizedLabel = options?.hideFinalizedLabel === true;
|
||||
const retryCount = Math.max(0, Number(request?.retryCount ?? 0) || 0);
|
||||
const appendRetryLabel = (label: string | null) =>
|
||||
label && retryCount > 0 ? `${label} · 재처리 ${retryCount}회` : label;
|
||||
|
||||
if (hasAnsweredRequest(request)) {
|
||||
if (request?.status === "completed") {
|
||||
@@ -1759,27 +1770,29 @@ function formatRequestStatusLabel(
|
||||
return null;
|
||||
}
|
||||
|
||||
return attentionState?.hasPendingPromptBadge || attentionState?.hasPendingVerificationBadge ? "확인대기" : "완료";
|
||||
return appendRetryLabel(
|
||||
attentionState?.hasPendingPromptBadge || attentionState?.hasPendingVerificationBadge ? "확인대기" : "완료",
|
||||
);
|
||||
}
|
||||
|
||||
return hideFinalizedLabel ? null : "답변도착";
|
||||
return appendRetryLabel(hideFinalizedLabel ? null : "답변도착");
|
||||
}
|
||||
|
||||
switch (request?.status) {
|
||||
case 'accepted':
|
||||
return '접수됨';
|
||||
return appendRetryLabel('접수됨');
|
||||
case 'queued':
|
||||
return '대기중';
|
||||
return appendRetryLabel('대기중');
|
||||
case 'started':
|
||||
return request.hasResponse ? '응답작성중' : '처리중';
|
||||
return appendRetryLabel(request.hasResponse ? '응답작성중' : '처리중');
|
||||
case 'completed':
|
||||
return '완료';
|
||||
return appendRetryLabel('완료');
|
||||
case 'failed':
|
||||
return '실패';
|
||||
return appendRetryLabel('실패');
|
||||
case 'cancelled':
|
||||
return '취소됨';
|
||||
return appendRetryLabel('취소됨');
|
||||
case 'removed':
|
||||
return '삭제됨';
|
||||
return appendRetryLabel('삭제됨');
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -2144,6 +2157,20 @@ function getRequestDetailBadge(request: ChatConversationRequest | undefined): Sy
|
||||
return null;
|
||||
}
|
||||
|
||||
function getRequestRetryBadge(request: ChatConversationRequest | undefined): SystemExecutionBadge | null {
|
||||
const retryCount = Math.max(0, Number(request?.retryCount ?? 0) || 0);
|
||||
|
||||
if (retryCount <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
label: `재처리 ${retryCount}회`,
|
||||
shortLabel: `재처리 ${retryCount}`,
|
||||
tone: 'processing',
|
||||
};
|
||||
}
|
||||
|
||||
function buildChecklistStageBadge(lines: string[], request?: ChatConversationRequest): SystemExecutionBadge | null {
|
||||
const entries = buildChatActivityChecklistEntries(lines, request);
|
||||
const activeEntry =
|
||||
@@ -2186,6 +2213,7 @@ function buildPromptStateBadge(options: {
|
||||
promptTargets: Extract<ChatMessagePart, { type: 'prompt' }>[];
|
||||
submittedCount: number;
|
||||
isManuallyCompleted?: boolean;
|
||||
isPromptManuallyCompleted?: boolean;
|
||||
}): SystemExecutionBadge | null {
|
||||
const { promptTargets, submittedCount, isManuallyCompleted } = options;
|
||||
|
||||
@@ -2254,6 +2282,7 @@ function buildVerificationStateBadge(options: {
|
||||
hasVerificationTarget: boolean;
|
||||
hasConfirmedVerificationTarget: boolean;
|
||||
isManuallyCompleted?: boolean;
|
||||
isPromptManuallyCompleted?: boolean;
|
||||
}): SystemExecutionBadge | null {
|
||||
const {
|
||||
request,
|
||||
@@ -2262,23 +2291,32 @@ function buildVerificationStateBadge(options: {
|
||||
hasVerificationTarget,
|
||||
hasConfirmedVerificationTarget,
|
||||
isManuallyCompleted,
|
||||
isPromptManuallyCompleted,
|
||||
} = options;
|
||||
|
||||
if (!request || promptTargets.length > 0 || !hasVerificationTarget) {
|
||||
if (!request || isPromptManuallyCompleted || promptTargets.length > 0 || !hasVerificationTarget) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const verificationText = [request.userText, request.responseText, ...activityLines].join('\n');
|
||||
const usesVerificationLabel = VERIFICATION_REQUEST_PATTERN.test(verificationText);
|
||||
const completedLabel = usesVerificationLabel ? '검증 확인' : '응답 확인';
|
||||
const pendingLabel = usesVerificationLabel ? '검증 미확인' : '응답 미확인';
|
||||
|
||||
if (!usesVerificationLabel) {
|
||||
if (!request.hasResponse && request.status !== 'completed') {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return isManuallyCompleted
|
||||
? {
|
||||
label: usesVerificationLabel ? '검증 확인' : '응답 확인',
|
||||
label: completedLabel,
|
||||
shortLabel: '확인',
|
||||
tone: 'completed',
|
||||
}
|
||||
: {
|
||||
label: usesVerificationLabel ? '검증 미확인' : '응답 미확인',
|
||||
label: pendingLabel,
|
||||
shortLabel: '미확인',
|
||||
tone: 'attention',
|
||||
};
|
||||
@@ -2291,6 +2329,7 @@ function hasPendingVerificationState(options: {
|
||||
hasVerificationTarget: boolean;
|
||||
hasConfirmedVerificationTarget: boolean;
|
||||
isManuallyCompleted?: boolean;
|
||||
isPromptManuallyCompleted?: boolean;
|
||||
}) {
|
||||
return buildVerificationStateBadge(options)?.tone === 'attention';
|
||||
}
|
||||
@@ -3304,14 +3343,32 @@ const ChatComposerInput = memo(function ChatComposerInput({
|
||||
|
||||
function SharedRoomsRequestCard({
|
||||
request,
|
||||
attentionState,
|
||||
canCompletePrompt = false,
|
||||
canCompleteVerification = false,
|
||||
canReplyToResponse = false,
|
||||
isManualCompletionSaving = false,
|
||||
isReplyReferenceActive = false,
|
||||
onCompletePrompt,
|
||||
onCompleteVerification,
|
||||
onReplyToResponse,
|
||||
onSelect,
|
||||
}: {
|
||||
request: ChatConversationRequest;
|
||||
attentionState?: SystemExecutionAttentionState;
|
||||
canCompletePrompt?: boolean;
|
||||
canCompleteVerification?: boolean;
|
||||
canReplyToResponse?: boolean;
|
||||
isManualCompletionSaving?: boolean;
|
||||
isReplyReferenceActive?: boolean;
|
||||
onCompletePrompt?: (() => void) | null;
|
||||
onCompleteVerification?: (() => void) | null;
|
||||
onReplyToResponse?: (() => void) | null;
|
||||
onSelect?: (() => void) | null;
|
||||
}) {
|
||||
const questionText = (request.userText ?? "").trim() || "-";
|
||||
const answerText = (request.responseText ?? "").trim() || request.statusMessage?.trim() || "아직 답변이 없습니다.";
|
||||
const requestStatusLabel = formatRequestStatusLabel(request);
|
||||
const requestStatusLabel = formatRequestStatusLabel(request, attentionState);
|
||||
|
||||
return (
|
||||
<section
|
||||
@@ -3354,6 +3411,58 @@ function SharedRoomsRequestCard({
|
||||
<div className="app-chat-bubble__content">{answerText}</div>
|
||||
</div>
|
||||
</div>
|
||||
{canCompletePrompt || canCompleteVerification || canReplyToResponse ? (
|
||||
<div className="app-chat-message__response-actions">
|
||||
{canCompletePrompt ? (
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
className="app-chat-message__response-action"
|
||||
icon={<CheckOutlined />}
|
||||
loading={isManualCompletionSaving}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
onCompletePrompt?.();
|
||||
}}
|
||||
>
|
||||
완료 처리
|
||||
</Button>
|
||||
) : null}
|
||||
{canCompleteVerification ? (
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
className="app-chat-message__response-action"
|
||||
icon={<CheckOutlined />}
|
||||
loading={isManualCompletionSaving}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
onCompleteVerification?.();
|
||||
}}
|
||||
>
|
||||
완료 처리
|
||||
</Button>
|
||||
) : null}
|
||||
{canReplyToResponse ? (
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
className={[
|
||||
'app-chat-message__response-action',
|
||||
'app-chat-message__response-reply-button',
|
||||
isReplyReferenceActive ? 'app-chat-message__response-reply-button--active' : '',
|
||||
].filter(Boolean).join(' ')}
|
||||
icon={<SendOutlined />}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
onReplyToResponse?.();
|
||||
}}
|
||||
>
|
||||
{isReplyReferenceActive ? '답변 참조 중' : '답변하기'}
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -3480,9 +3589,7 @@ export function ChatConversationView({
|
||||
const [systemExecutionDisplayMode, setSystemExecutionDisplayMode] = useState<SystemExecutionDisplayMode>('collapsed');
|
||||
const [systemExecutionFilter, setSystemExecutionFilter] = useState<SystemExecutionFilter>('active-attention');
|
||||
const [systemExecutionSort, setSystemExecutionSort] = useState<SystemExecutionSort>('latest');
|
||||
const [roomShareExpandMode, setRoomShareExpandMode] = useState<RoomShareExpandMode>(
|
||||
useRoomsShareBubbleFlow ? 'latest' : 'pending',
|
||||
);
|
||||
const [roomShareExpandMode, setRoomShareExpandMode] = useState<RoomShareExpandMode>('pending');
|
||||
const [selectedRoomShareGroupId, setSelectedRoomShareGroupId] = useState<string | null>(null);
|
||||
const [replyReferenceRequestId, setReplyReferenceRequestId] = useState('');
|
||||
const [composerForceDraftSyncVersion, setComposerForceDraftSyncVersion] = useState(0);
|
||||
@@ -3702,7 +3809,7 @@ export function ChatConversationView({
|
||||
return [...ordered, ...orphanActivityMessages];
|
||||
}, [requestStateMap, visibleMessages]);
|
||||
useEffect(() => {
|
||||
setRoomShareExpandMode(useRoomsShareBubbleFlow ? 'latest' : 'pending');
|
||||
setRoomShareExpandMode('pending');
|
||||
}, [useRoomsShareBubbleFlow]);
|
||||
|
||||
const useSharedRoomsSimplifiedView = showRoomsShareHeader && useSharedComposerChrome && !roomsShareUseSharedPageNav;
|
||||
@@ -4104,7 +4211,8 @@ export function ChatConversationView({
|
||||
() =>
|
||||
visibleSystemExecutionRequests.filter(
|
||||
(request) =>
|
||||
request.status === 'accepted' || request.status === 'queued' || request.status === 'started',
|
||||
!isPromptFollowupRequest(request)
|
||||
&& (request.status === 'accepted' || request.status === 'queued' || request.status === 'started'),
|
||||
),
|
||||
[visibleSystemExecutionRequests],
|
||||
);
|
||||
@@ -4161,6 +4269,22 @@ export function ChatConversationView({
|
||||
const nextMap = new Map<string, SystemExecutionAttentionState>();
|
||||
|
||||
visibleSystemExecutionRequests.forEach((request) => {
|
||||
if (isPromptFollowupRequest(request)) {
|
||||
nextMap.set(request.requestId, {
|
||||
activityLines: [],
|
||||
promptTargets: [],
|
||||
promptSubmittedCount: 0,
|
||||
isPromptManuallyCompleted: true,
|
||||
hasVerificationTarget: false,
|
||||
hasConfirmedVerificationTarget: true,
|
||||
isVerificationManuallyCompleted: true,
|
||||
hasPendingPromptBadge: false,
|
||||
hasPendingVerificationBadge: false,
|
||||
hasOwnAttentionState: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const activityLines = activityLinesByRequestId.get(request.requestId) ?? [];
|
||||
const promptTargets = promptTargetsByRequestId.get(request.requestId) ?? [];
|
||||
const promptSubmittedCount =
|
||||
@@ -4193,6 +4317,7 @@ export function ChatConversationView({
|
||||
promptTargets,
|
||||
hasVerificationTarget,
|
||||
hasConfirmedVerificationTarget,
|
||||
isPromptManuallyCompleted,
|
||||
});
|
||||
const hasOwnAttentionState =
|
||||
hasPendingPromptBadge || hasPendingVerificationBadge || isDisconnectedRequestNeedingAttention(request);
|
||||
@@ -4219,6 +4344,7 @@ export function ChatConversationView({
|
||||
lastReadResponseMessageId,
|
||||
openedPreviewArtifactRequestIdSet,
|
||||
openedPreviewRequestIds,
|
||||
childRequestIdsByParentRequestId,
|
||||
localSubmittedPromptCountByRequestId,
|
||||
promptFollowupCountByParentRequestId,
|
||||
promptTargetsByRequestId,
|
||||
@@ -4233,12 +4359,18 @@ export function ChatConversationView({
|
||||
|
||||
if (systemExecutionFilter === 'active') {
|
||||
return visibleSystemExecutionRequests.filter(
|
||||
(request) => request.status === 'accepted' || request.status === 'queued' || request.status === 'started',
|
||||
(request) =>
|
||||
!isPromptFollowupRequest(request)
|
||||
&& (request.status === 'accepted' || request.status === 'queued' || request.status === 'started'),
|
||||
);
|
||||
}
|
||||
|
||||
if (systemExecutionFilter === 'active-attention') {
|
||||
return visibleSystemExecutionRequests.filter((request) => {
|
||||
if (isPromptFollowupRequest(request)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (request.status === 'accepted' || request.status === 'queued' || request.status === 'started') {
|
||||
return true;
|
||||
}
|
||||
@@ -4248,7 +4380,9 @@ export function ChatConversationView({
|
||||
}
|
||||
|
||||
return visibleSystemExecutionRequests.filter(
|
||||
(request) => systemExecutionAttentionStateByRequestId.get(request.requestId)?.hasOwnAttentionState === true,
|
||||
(request) =>
|
||||
!isPromptFollowupRequest(request)
|
||||
&& systemExecutionAttentionStateByRequestId.get(request.requestId)?.hasOwnAttentionState === true,
|
||||
);
|
||||
},
|
||||
[systemExecutionAttentionStateByRequestId, visibleSystemExecutionRequests, systemExecutionFilter],
|
||||
@@ -4362,12 +4496,23 @@ export function ChatConversationView({
|
||||
});
|
||||
}
|
||||
|
||||
return messageEntries
|
||||
const groupRequestIdsByRootId = new Map<string, string[]>();
|
||||
|
||||
requestIdsByRootRequestId.forEach((requestIds, rootRequestId) => {
|
||||
const dedupedRequestIds = Array.from(new Set(requestIds.map((requestId) => requestId.trim()).filter(Boolean)));
|
||||
|
||||
if (dedupedRequestIds.length > 0) {
|
||||
groupRequestIdsByRootId.set(rootRequestId, dedupedRequestIds);
|
||||
}
|
||||
});
|
||||
|
||||
const groupedEntries = messageEntries
|
||||
.filter((entry): entry is Extract<ConversationMessageEntry, { kind: 'group' }> => entry.kind === 'group')
|
||||
.map((entry) => {
|
||||
const groupedRequestIds = groupRequestIdsByRootId.get(entry.groupId) ?? entry.requestIds;
|
||||
const groupedRequests = Array.from(
|
||||
new Map(
|
||||
entry.requestIds
|
||||
groupedRequestIds
|
||||
.map((requestId) => requestStateMap.get(requestId))
|
||||
.filter((item): item is ChatConversationRequest => item != null)
|
||||
.map((request) => [request.requestId, request] as const),
|
||||
@@ -4393,10 +4538,60 @@ export function ChatConversationView({
|
||||
statusSummary,
|
||||
hasAttention,
|
||||
};
|
||||
});
|
||||
const existingGroupIdSet = new Set(groupedEntries.map((entry) => entry.groupId));
|
||||
const pendingOnlyGroups = Array.from(groupRequestIdsByRootId.entries())
|
||||
.filter(([groupId]) => !existingGroupIdSet.has(groupId))
|
||||
.map(([groupId, groupedRequestIds]) => {
|
||||
const groupedRequests = Array.from(
|
||||
new Map(
|
||||
groupedRequestIds
|
||||
.map((requestId) => requestStateMap.get(requestId))
|
||||
.filter((item): item is ChatConversationRequest => item != null)
|
||||
.map((request) => [request.requestId, request] as const),
|
||||
).values(),
|
||||
);
|
||||
|
||||
if (groupedRequests.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const hasAttention = groupedRequests.some((request) => {
|
||||
if (isRequestRunningStatus(request.status) || isRequestQueueStatus(request.status)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return systemExecutionAttentionStateByRequestId.get(request.requestId)?.hasOwnAttentionState === true;
|
||||
});
|
||||
|
||||
if (!hasAttention) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const representativeRequest = groupedRequests[groupedRequests.length - 1] ?? null;
|
||||
|
||||
return {
|
||||
groupId,
|
||||
groupedRequests,
|
||||
representativeRequest,
|
||||
statusSummary: resolveAggregatedRequestStatusSummary(groupedRequests, systemExecutionAttentionStateByRequestId),
|
||||
hasAttention,
|
||||
};
|
||||
})
|
||||
.filter((entry) => entry.representativeRequest != null);
|
||||
.filter((entry): entry is NonNullable<typeof entry> => entry != null);
|
||||
|
||||
return [...groupedEntries, ...pendingOnlyGroups]
|
||||
.filter((entry) => entry.representativeRequest != null)
|
||||
.sort((left, right) => left.representativeRequest.createdAt.localeCompare(right.representativeRequest.createdAt));
|
||||
},
|
||||
[messageEntries, orderedMessages, requestStateMap, systemExecutionAttentionStateByRequestId, useSharedRoomsSimplifiedView],
|
||||
[
|
||||
messageEntries,
|
||||
orderedMessages,
|
||||
requestIdsByRootRequestId,
|
||||
requestStateMap,
|
||||
systemExecutionAttentionStateByRequestId,
|
||||
useSharedRoomsSimplifiedView,
|
||||
],
|
||||
);
|
||||
const roomShareNavigableGroups = useMemo(() => {
|
||||
if (roomShareExpandMode === 'pending') {
|
||||
@@ -4501,7 +4696,7 @@ export function ChatConversationView({
|
||||
const nowMs = Date.now();
|
||||
const processingRequests = roomShareAllRequests.filter(
|
||||
(request) => isRequestRunningStatus(request.status) || isRequestQueueStatus(request.status),
|
||||
);
|
||||
).filter((request) => !isPromptFollowupRequest(request));
|
||||
const processingTarget = processingRequests[processingRequests.length - 1] ?? null;
|
||||
const elapsedLabel = processingTarget ? formatOngoingElapsedLabel(processingTarget.createdAt, nowMs) : '';
|
||||
const processingCount = processingRequests.length;
|
||||
@@ -5344,6 +5539,7 @@ export function ChatConversationView({
|
||||
hasVerificationTarget,
|
||||
hasConfirmedVerificationTarget,
|
||||
isManuallyCompleted: isVerificationManuallyCompleted,
|
||||
isPromptManuallyCompleted,
|
||||
});
|
||||
const hasPendingVerificationBadge = attentionState?.hasPendingVerificationBadge === true;
|
||||
const manualCompletionTypes = buildManualCompletionTypes({
|
||||
@@ -5353,9 +5549,11 @@ export function ChatConversationView({
|
||||
const checklistBadge = buildChecklistStageBadge(activityLines, representativeRequest);
|
||||
const readStateBadge =
|
||||
verificationStateBadge ? null : buildReadStateBadge(representativeRequest, lastReadResponseMessageId);
|
||||
const retryBadge = getRequestRetryBadge(representativeRequest);
|
||||
const secondaryBadges = [
|
||||
hierarchyBadge,
|
||||
rootRelationshipBadge,
|
||||
retryBadge,
|
||||
detailBadge,
|
||||
promptStateBadge,
|
||||
verificationStateBadge,
|
||||
@@ -5812,6 +6010,25 @@ export function ChatConversationView({
|
||||
}, 0);
|
||||
};
|
||||
|
||||
const activateReplyReference = (
|
||||
requestId: string | null | undefined,
|
||||
options?: {
|
||||
focusComposer?: boolean;
|
||||
},
|
||||
) => {
|
||||
const normalizedRequestId = requestId?.trim() || '';
|
||||
|
||||
if (!normalizedRequestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
setReplyReferenceRequestId(normalizedRequestId);
|
||||
|
||||
if (options?.focusComposer !== false) {
|
||||
composerRef.current?.focus({ cursor: 'end' });
|
||||
}
|
||||
};
|
||||
|
||||
const closeChildComposer = (groupId: string) => {
|
||||
const normalizedGroupId = groupId.trim();
|
||||
|
||||
@@ -5959,13 +6176,19 @@ export function ChatConversationView({
|
||||
hasVerificationTarget: responseHasVerificationTarget,
|
||||
hasConfirmedVerificationTarget: responseHasConfirmedVerificationTarget,
|
||||
isManuallyCompleted: isResponseVerificationManuallyCompleted,
|
||||
isPromptManuallyCompleted: isResponsePromptManuallyCompleted,
|
||||
});
|
||||
const responseHasPendingVerificationBadge = attentionState?.hasPendingVerificationBadge === true;
|
||||
const responseSecondaryBadges = [responsePromptStateBadge, responseVerificationStateBadge].filter(
|
||||
(badge): badge is SystemExecutionBadge => badge != null,
|
||||
);
|
||||
const responseRetryBadge = getRequestRetryBadge(requestState);
|
||||
const responseDisplayBadges = [
|
||||
...(responseRetryBadge ? [responseRetryBadge] : []),
|
||||
...responseSecondaryBadges,
|
||||
];
|
||||
const responsePrimaryManualCompletionType = resolvePrimaryManualCompletionType({
|
||||
secondaryBadges: responseSecondaryBadges,
|
||||
secondaryBadges: responseDisplayBadges,
|
||||
promptStateBadge: responsePromptStateBadge,
|
||||
verificationStateBadge: responseVerificationStateBadge,
|
||||
hasPendingPromptBadge: responseHasPendingPromptBadge,
|
||||
@@ -5991,9 +6214,6 @@ export function ChatConversationView({
|
||||
promptSignature: buildPromptTargetSignature(promptTargets[0]!),
|
||||
}
|
||||
: null;
|
||||
const hasChildRequest =
|
||||
Boolean(message.clientRequestId) &&
|
||||
(childRequestIdsByParentRequestId.get(message.clientRequestId ?? '')?.length ?? 0) > 0;
|
||||
const showResponseManualCompleteAction =
|
||||
enableExecutionReviewUi &&
|
||||
message.author === 'codex' &&
|
||||
@@ -6004,19 +6224,21 @@ export function ChatConversationView({
|
||||
message.author === 'codex' &&
|
||||
Boolean(message.clientRequestId) &&
|
||||
responsePromptTargets.length > 0 &&
|
||||
!isResponsePromptManuallyCompleted;
|
||||
!isResponsePromptManuallyCompleted &&
|
||||
!isRequestInFlightStatus(requestState?.status);
|
||||
const canCompleteVerificationFromResponse =
|
||||
showRoomsShareHeader &&
|
||||
message.author === 'codex' &&
|
||||
Boolean(message.clientRequestId) &&
|
||||
responsePromptTargets.length === 0 &&
|
||||
responsePrimaryManualCompletionType === 'verification' &&
|
||||
!hasChildRequest;
|
||||
!isRequestInFlightStatus(requestState?.status);
|
||||
const canReplyToResponse =
|
||||
showRoomsShareHeader &&
|
||||
message.author === 'codex' &&
|
||||
Boolean(message.clientRequestId) &&
|
||||
responsePromptTargets.length === 0;
|
||||
responsePromptTargets.length === 0 &&
|
||||
!isRequestInFlightStatus(requestState?.status);
|
||||
const isReplyReferenceActive =
|
||||
canReplyToResponse &&
|
||||
replyReferenceRequestId.trim() === (message.clientRequestId?.trim() ?? '');
|
||||
@@ -6247,8 +6469,9 @@ export function ChatConversationView({
|
||||
className={['app-chat-message__response-action', 'app-chat-message__response-reply-button', isReplyReferenceActive ? 'app-chat-message__response-reply-button--active' : ''].filter(Boolean).join(' ')}
|
||||
icon={<SendOutlined />}
|
||||
onClick={() => {
|
||||
setReplyReferenceRequestId(message.clientRequestId?.trim() ?? '');
|
||||
composerRef.current?.focus({ cursor: 'end' });
|
||||
activateReplyReference(message.clientRequestId, {
|
||||
focusComposer: false,
|
||||
});
|
||||
}}
|
||||
>
|
||||
{isReplyReferenceActive ? '답변 참조 중' : '답변하기'}
|
||||
@@ -6997,6 +7220,44 @@ export function ChatConversationView({
|
||||
const visibleMessages = Array.isArray(entry.messages) ? entry.messages.filter((message) => !isActivityLogMessage(message)) : [];
|
||||
const collapsedVisibleFinalMessage =
|
||||
visibleMessages.length > 0 ? visibleMessages[visibleMessages.length - 1] : null;
|
||||
const representativeAttentionState = representativeRequest
|
||||
? systemExecutionAttentionStateByRequestId.get(representativeRequest.requestId)
|
||||
: undefined;
|
||||
const representativePromptTargets = representativeAttentionState?.promptTargets ?? [];
|
||||
const isRepresentativePromptManuallyCompleted =
|
||||
representativeAttentionState?.isPromptManuallyCompleted === true;
|
||||
const representativeHasPendingPromptBadge =
|
||||
representativeAttentionState?.hasPendingPromptBadge === true;
|
||||
const representativeHasPendingVerificationBadge =
|
||||
representativeAttentionState?.hasPendingVerificationBadge === true;
|
||||
const representativeManualCompletionTypes = buildManualCompletionTypes({
|
||||
hasPendingPromptBadge: representativeHasPendingPromptBadge,
|
||||
hasPendingVerificationBadge: representativeHasPendingVerificationBadge,
|
||||
});
|
||||
const isRepresentativeManualCompletionSaving =
|
||||
representativeRequest != null &&
|
||||
representativeManualCompletionTypes.some((type) =>
|
||||
pendingManualCompletionActionKeySet.has(`${type}:${representativeRequest.requestId}`),
|
||||
);
|
||||
const canCompletePromptFromCard =
|
||||
representativeRequest != null &&
|
||||
representativePromptTargets.length > 0 &&
|
||||
!isRepresentativePromptManuallyCompleted &&
|
||||
!isRequestInFlightStatus(representativeRequest.status);
|
||||
const canCompleteVerificationFromCard =
|
||||
representativeRequest != null &&
|
||||
representativePromptTargets.length === 0 &&
|
||||
representativeHasPendingVerificationBadge &&
|
||||
!isRequestInFlightStatus(representativeRequest.status);
|
||||
const canReplyToCardResponse =
|
||||
representativeRequest != null &&
|
||||
representativeRequest.hasResponse &&
|
||||
representativePromptTargets.length === 0 &&
|
||||
!isRequestInFlightStatus(representativeRequest.status);
|
||||
const isCardReplyReferenceActive =
|
||||
representativeRequest != null &&
|
||||
canReplyToCardResponse &&
|
||||
replyReferenceRequestId.trim() === representativeRequest.requestId.trim();
|
||||
|
||||
if (!representativeRequest) {
|
||||
return null;
|
||||
@@ -7011,6 +7272,29 @@ export function ChatConversationView({
|
||||
<SharedRoomsRequestCard
|
||||
key={entry.groupId}
|
||||
request={representativeRequest}
|
||||
attentionState={representativeAttentionState}
|
||||
canCompletePrompt={canCompletePromptFromCard}
|
||||
canCompleteVerification={canCompleteVerificationFromCard}
|
||||
canReplyToResponse={canReplyToCardResponse}
|
||||
isManualCompletionSaving={isRepresentativeManualCompletionSaving}
|
||||
isReplyReferenceActive={isCardReplyReferenceActive}
|
||||
onCompletePrompt={() => {
|
||||
void completeManualBadge({
|
||||
requestId: representativeRequest.requestId,
|
||||
type: 'prompt',
|
||||
});
|
||||
}}
|
||||
onCompleteVerification={() => {
|
||||
void completeManualBadge({
|
||||
requestId: representativeRequest.requestId,
|
||||
type: 'verification',
|
||||
});
|
||||
}}
|
||||
onReplyToResponse={() => {
|
||||
activateReplyReference(representativeRequest.requestId, {
|
||||
focusComposer: false,
|
||||
});
|
||||
}}
|
||||
onSelect={() => {
|
||||
setSelectedRoomShareGroupId(entry.groupId);
|
||||
scrollToRoomShareGroup(entry.groupId);
|
||||
@@ -7113,9 +7397,7 @@ export function ChatConversationView({
|
||||
const parentRequestId = entry.request?.parentRequestId?.trim() || '';
|
||||
const parentRequest = parentRequestId ? requestStateMap.get(parentRequestId) : null;
|
||||
const groupRelationText = parentRequest
|
||||
? `${
|
||||
entry.request?.requestOrigin === 'prompt' ? '상위 질의' : '상위 요청 연결'
|
||||
}: ${summarizeQueuedText(parentRequest.userText || parentRequest.responseText || parentRequestId, 52)}`
|
||||
? `부모 요청: ${summarizeQueuedText(parentRequest.userText || parentRequest.responseText || parentRequestId, 52)}`
|
||||
: null;
|
||||
const childComposerGroupId = entry.groupId;
|
||||
const childComposerParentRequestId = resolveChildComposerParentRequestId(entry.request, requestStateMap);
|
||||
|
||||
Reference in New Issue
Block a user