fix: restore baseline validation (#3142)
This commit is contained in:
committed by
GitHub
parent
27377efaf3
commit
8ea94a119f
@@ -15,7 +15,7 @@ import { useFilesViewTabsStore } from '@/stores/useFilesViewTabsStore';
|
||||
import { useTerminalStore } from '@/stores/useTerminalStore';
|
||||
import { useSessionUIStore } from '@/sync/session-ui-store';
|
||||
import { resetStreamingState } from '@/sync/streaming';
|
||||
import { useGlobalSessionStatusStore, replaceGlobalSessionStatusById } from '@/sync/global-session-status';
|
||||
import { replaceGlobalSessionStatusById } from '@/sync/global-session-status';
|
||||
import { resetSessionOrdering } from '@/sync/session-ordering';
|
||||
import { resetSessionActivityTiming } from '@/sync/session-activity-timing';
|
||||
import { syncDesktopSettings } from '@/lib/persistence';
|
||||
|
||||
@@ -457,13 +457,6 @@ const ChatMessage: React.FC<ChatMessageProps> = ({
|
||||
}, [chatRenderMode, isMessageCompleted, isUser, visibleParts]);
|
||||
|
||||
|
||||
const assistantTextParts = React.useMemo(() => {
|
||||
if (isUser) {
|
||||
return [];
|
||||
}
|
||||
return visibleParts.filter((part) => part.type === 'text');
|
||||
}, [isUser, visibleParts]);
|
||||
|
||||
const toolParts = React.useMemo(() => {
|
||||
if (isUser) {
|
||||
return [];
|
||||
@@ -545,19 +538,6 @@ const ChatMessage: React.FC<ChatMessageProps> = ({
|
||||
|
||||
const shouldHideUserMessage = isUser && displayParts.length === 0;
|
||||
|
||||
// Message is considered to have an "open step" if info.finish is not yet present
|
||||
const hasOpenStep = typeof messageFinish !== 'string';
|
||||
|
||||
const shouldCoordinateRendering = React.useMemo(() => {
|
||||
if (isUser) {
|
||||
return false;
|
||||
}
|
||||
if (assistantTextParts.length === 0 || toolParts.length === 0) {
|
||||
return hasOpenStep;
|
||||
}
|
||||
return true;
|
||||
}, [assistantTextParts.length, toolParts.length, hasOpenStep, isUser]);
|
||||
|
||||
const themeVariant = currentTheme?.metadata.variant;
|
||||
const isDarkTheme = React.useMemo(() => {
|
||||
if (themeVariant) {
|
||||
|
||||
@@ -1343,16 +1343,6 @@ const AssistantMessageBody = React.memo(({
|
||||
return resolved ? { id: resolved.id, path: resolved.path } : null;
|
||||
}, [availableWorktreesByProject, canUseProjectPlanActions, currentSessionId, effectiveDirectory, getDirectoryForSession, projects]);
|
||||
|
||||
const hasTools = toolParts.length > 0;
|
||||
|
||||
const hasPendingTools = React.useMemo(() => {
|
||||
return toolParts.some((toolPart) => {
|
||||
const state = (toolPart as Record<string, unknown>).state as Record<string, unknown> | undefined ?? {};
|
||||
const status = state?.status;
|
||||
return status === 'pending' || status === 'running' || status === 'started';
|
||||
});
|
||||
}, [toolParts]);
|
||||
|
||||
const isActiveTool = React.useCallback((toolPart: ToolPartType): boolean => {
|
||||
const state = (toolPart as Record<string, unknown>).state as Record<string, unknown> | undefined ?? {};
|
||||
const status = state?.status;
|
||||
@@ -1381,42 +1371,6 @@ const AssistantMessageBody = React.memo(({
|
||||
return isActiveTool(toolPart) || isToolFinalized(toolPart);
|
||||
}, [isActiveTool, isToolFinalized]);
|
||||
|
||||
const allToolsFinalized = React.useMemo(() => {
|
||||
if (toolParts.length === 0) {
|
||||
return true;
|
||||
}
|
||||
if (hasPendingTools) {
|
||||
return false;
|
||||
}
|
||||
return toolParts.every((toolPart) => isToolFinalized(toolPart));
|
||||
}, [toolParts, hasPendingTools, isToolFinalized]);
|
||||
|
||||
const reasoningParts = React.useMemo(() => {
|
||||
return visibleParts.filter((part) => part.type === 'reasoning');
|
||||
}, [visibleParts]);
|
||||
|
||||
const reasoningComplete = React.useMemo(() => {
|
||||
if (reasoningParts.length === 0) {
|
||||
return true;
|
||||
}
|
||||
return reasoningParts.every((part) => {
|
||||
const time = (part as Record<string, unknown>).time as { end?: number } | undefined;
|
||||
return typeof time?.end === 'number';
|
||||
});
|
||||
}, [reasoningParts]);
|
||||
|
||||
// Message is considered to have an "open step" if info.finish is not yet present
|
||||
const hasOpenStep = typeof messageFinish !== 'string';
|
||||
|
||||
const shouldHoldForReasoning =
|
||||
reasoningParts.length > 0 &&
|
||||
hasTools &&
|
||||
(hasPendingTools || hasOpenStep || !allToolsFinalized);
|
||||
|
||||
const shouldHoldTools = awaitingMessageCompletion
|
||||
|| (hasTools && (hasPendingTools || hasOpenStep || !allToolsFinalized));
|
||||
const shouldHoldReasoning = awaitingMessageCompletion || shouldHoldForReasoning;
|
||||
|
||||
const hasCopyableText = Boolean(hasTextContent) && !awaitingMessageCompletion;
|
||||
|
||||
const handleForkClick = React.useCallback(
|
||||
|
||||
@@ -486,8 +486,6 @@ export const Header: React.FC = () => {
|
||||
const pathSegments = activeProject.path.split(/[\\/]/).filter(Boolean);
|
||||
return pathSegments[pathSegments.length - 1] ?? null;
|
||||
}, [activeProject]);
|
||||
const quotaResults = useQuotaStore((state) => state.results);
|
||||
const fetchAllQuotas = useQuotaStore((state) => state.fetchAllQuotas);
|
||||
const loadQuotaSettings = useQuotaStore((state) => state.loadSettings);
|
||||
|
||||
const { isMobile } = useDeviceInfo();
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { Event } from '@opencode-ai/sdk/v2/client';
|
||||
import React, { act } from 'react';
|
||||
import { createRoot, type Root } from 'react-dom/client';
|
||||
import { deriveRecentSessions } from '../recent/activitySections';
|
||||
import { applyGlobalSessionStatusEvent, useGlobalSessionStatusStore , replaceGlobalSessionStatusById} from '@/sync/global-session-status';
|
||||
import { applyGlobalSessionStatusEvent, replaceGlobalSessionStatusById } from '@/sync/global-session-status';
|
||||
import {
|
||||
buildSidebarSessionProjection,
|
||||
getDescendantIds,
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import { describe, expect, test } from 'bun:test';
|
||||
import React, { act } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import type { Session } from '@opencode-ai/sdk/v2';
|
||||
import { useGlobalSessionStatusStore , replaceGlobalSessionStatusById} from '@/sync/global-session-status';
|
||||
import { replaceGlobalSessionStatusById } from '@/sync/global-session-status';
|
||||
import { useNotificationStore } from '@/sync/notification-store';
|
||||
import { useCollapsedSessionActivityState } from './collapsedActivityState';
|
||||
import type { SessionNode } from '../types';
|
||||
|
||||
@@ -249,6 +249,7 @@ export const createSessionGoalRuntime = ({
|
||||
getOpenCodeAuthHeaders,
|
||||
getSmallModelService,
|
||||
emitGoalNotification,
|
||||
isEnabled = isSessionGoalEnabled,
|
||||
idleQuietMs = IDLE_QUIET_MS,
|
||||
kickoffQuietMs = KICKOFF_QUIET_MS,
|
||||
maxAutoTurns = MAX_AUTO_TURNS,
|
||||
@@ -444,7 +445,7 @@ export const createSessionGoalRuntime = ({
|
||||
};
|
||||
|
||||
const tick = async (sessionId, directory) => {
|
||||
if (!isSessionGoalEnabled()) return;
|
||||
if (!isEnabled()) return;
|
||||
|
||||
const session = await openCodeFetch(`/session/${encodeURIComponent(sessionId)}`, { directory })
|
||||
.catch((error) => {
|
||||
|
||||
@@ -35,13 +35,14 @@ const startIdleTick = async (fetchImpl) => {
|
||||
buildOpenCodeUrl: (pathname) => `http://opencode.test${pathname}`,
|
||||
getOpenCodeAuthHeaders: () => ({}),
|
||||
getSmallModelService,
|
||||
isEnabled: () => true,
|
||||
idleQuietMs: 10,
|
||||
});
|
||||
runtime.processPayload({
|
||||
type: 'session.status',
|
||||
properties: { sessionID: SESSION_ID, status: { type: 'idle' }, directory: DIRECTORY },
|
||||
});
|
||||
await vi.advanceTimersByTimeAsync(10);
|
||||
await vi.runOnlyPendingTimersAsync();
|
||||
return { runtime, getSmallModelService };
|
||||
};
|
||||
|
||||
@@ -156,6 +157,7 @@ describe('session goal live activity gate', () => {
|
||||
buildOpenCodeUrl: (pathname) => `http://opencode.test${pathname}`,
|
||||
getOpenCodeAuthHeaders: () => ({}),
|
||||
getSmallModelService: async () => service,
|
||||
isEnabled: () => true,
|
||||
idleQuietMs: 10,
|
||||
});
|
||||
|
||||
@@ -163,7 +165,7 @@ describe('session goal live activity gate', () => {
|
||||
type: 'session.status',
|
||||
properties: { sessionID: SESSION_ID, status: { type: 'idle' }, directory: DIRECTORY },
|
||||
});
|
||||
await vi.advanceTimersByTimeAsync(10);
|
||||
await vi.runOnlyPendingTimersAsync();
|
||||
|
||||
expect(service.generateSmallModelText).toHaveBeenCalledOnce();
|
||||
const patch = requests.find((request) => request.pathname === `/session/${SESSION_ID}` && request.method === 'PATCH');
|
||||
|
||||
Reference in New Issue
Block a user