fix: resolve chat prompt read-only state for subagent sessions
Allows prompting subagent sessions without needing the parent record Keeps subagents read-only when prompting is disabled Covers root and subagent cases with unit tests
This commit is contained in:
@@ -43,6 +43,7 @@ import {
|
|||||||
useScopedBlockingPermissions,
|
useScopedBlockingPermissions,
|
||||||
useScopedBlockingQuestions,
|
useScopedBlockingQuestions,
|
||||||
useParentSession,
|
useParentSession,
|
||||||
|
useSession,
|
||||||
} from '@/sync/sync-context';
|
} from '@/sync/sync-context';
|
||||||
import { useSync } from '@/sync/use-sync';
|
import { useSync } from '@/sync/use-sync';
|
||||||
import { usePlanDetection } from '@/hooks/usePlanDetection';
|
import { usePlanDetection } from '@/hooks/usePlanDetection';
|
||||||
@@ -53,6 +54,7 @@ import { getEmbeddedSessionChatOriginSessionId } from '@/components/layout/conte
|
|||||||
import { isFullySyntheticMessage } from '@/lib/messages/synthetic';
|
import { isFullySyntheticMessage } from '@/lib/messages/synthetic';
|
||||||
import { normalizeUserDisplayParts } from './message/normalizeUserDisplayParts';
|
import { normalizeUserDisplayParts } from './message/normalizeUserDisplayParts';
|
||||||
import { findShellCommandForMessage, isUserShellMarkerMessage } from './lib/shellBridge';
|
import { findShellCommandForMessage, isUserShellMarkerMessage } from './lib/shellBridge';
|
||||||
|
import { resolveChatPromptReadOnly } from './chatPromptReadOnly';
|
||||||
|
|
||||||
const EMPTY_MESSAGES: Array<{ info: Message; parts: Part[] }> = [];
|
const EMPTY_MESSAGES: Array<{ info: Message; parts: Part[] }> = [];
|
||||||
const IDLE_SESSION_STATUS = { type: 'idle' as const };
|
const IDLE_SESSION_STATUS = { type: 'idle' as const };
|
||||||
@@ -679,6 +681,7 @@ export const ChatContainer: React.FC<ChatContainerProps> = ({ active = true, aut
|
|||||||
const isDesktopExpandedInput = isExpandedInput;
|
const isDesktopExpandedInput = isExpandedInput;
|
||||||
const useCompactDraftLayout = isMobile || isVSCode || chatSurfaceMode === 'mini-chat';
|
const useCompactDraftLayout = isMobile || isVSCode || chatSurfaceMode === 'mini-chat';
|
||||||
const messageListRef = React.useRef<MessageListHandle | null>(null);
|
const messageListRef = React.useRef<MessageListHandle | null>(null);
|
||||||
|
const currentSession = useSession(currentSessionId, effectiveSessionDirectory);
|
||||||
const parentSession = useParentSession(currentSessionId, effectiveSessionDirectory);
|
const parentSession = useParentSession(currentSessionId, effectiveSessionDirectory);
|
||||||
|
|
||||||
// In the embedded session-chat iframe, hide "Return to parent" when
|
// In the embedded session-chat iframe, hide "Return to parent" when
|
||||||
@@ -712,7 +715,7 @@ export const ChatContainer: React.FC<ChatContainerProps> = ({ active = true, aut
|
|||||||
{t('chat.container.returnToParent.label')}
|
{t('chat.container.returnToParent.label')}
|
||||||
</Button>
|
</Button>
|
||||||
) : null;
|
) : null;
|
||||||
const promptReadOnly = parentSession ? !allowPromptingSubagentSessions : readOnly;
|
const promptReadOnly = resolveChatPromptReadOnly(currentSession, allowPromptingSubagentSessions, readOnly);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
// VS Code/Cursor/Positron webviews delete window.parent (and window.top).
|
// VS Code/Cursor/Positron webviews delete window.parent (and window.top).
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { describe, expect, test } from 'bun:test';
|
||||||
|
import type { Session } from '@opencode-ai/sdk/v2';
|
||||||
|
|
||||||
|
import { resolveChatPromptReadOnly } from './chatPromptReadOnly';
|
||||||
|
|
||||||
|
const session = (parentID?: string): Session => ({
|
||||||
|
id: 'session',
|
||||||
|
slug: 'session',
|
||||||
|
title: 'Session',
|
||||||
|
version: '1',
|
||||||
|
projectID: 'project',
|
||||||
|
directory: '/repo',
|
||||||
|
parentID,
|
||||||
|
time: { created: 1, updated: 1 },
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('resolveChatPromptReadOnly', () => {
|
||||||
|
test('allows prompting a subagent without requiring its parent record', () => {
|
||||||
|
expect(resolveChatPromptReadOnly(session('parent'), true, true)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('keeps a subagent read-only when prompting is disabled', () => {
|
||||||
|
expect(resolveChatPromptReadOnly(session('parent'), false, false)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('preserves the surface read-only state for root sessions', () => {
|
||||||
|
expect(resolveChatPromptReadOnly(session(), true, true)).toBe(true);
|
||||||
|
expect(resolveChatPromptReadOnly(session(), true, false)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import type { Session } from '@opencode-ai/sdk/v2';
|
||||||
|
|
||||||
|
export const resolveChatPromptReadOnly = (
|
||||||
|
session: Session | null | undefined,
|
||||||
|
allowPromptingSubagentSessions: boolean,
|
||||||
|
readOnly: boolean,
|
||||||
|
): boolean => {
|
||||||
|
if (session?.parentID) {
|
||||||
|
return !allowPromptingSubagentSessions;
|
||||||
|
}
|
||||||
|
|
||||||
|
return readOnly;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user