feat: add session review handoff flow
Introduce a desktop/web-only /handoff-review flow that generates a handoff from the active implementation session, creates or reuses a separate review session in the same directory, and links the pair through hidden OpenChamber session metadata. Add review flow orchestration, metadata helpers, magic prompts, localized command/action labels, session metadata create/update support, and assistant message transfer actions for sending reviewer feedback back to the implementer or implementation responses back to the reviewer. Review sessions are ordinary sessions, not child sessions. The flow avoids exposing session IDs or routing metadata to agents, hides review controls on mobile and VS Code, hides unrelated assistant actions inside review sessions, cleans up stale metadata where possible, and uses the optimistic send path so cross-session sends scroll like normal composer messages.
This commit is contained in:
@@ -15,6 +15,7 @@ import { useInlineCommentDraftStore, type InlineCommentDraft } from '@/stores/us
|
||||
import { useSnippetsStore } from '@/stores/useSnippetsStore';
|
||||
import { appendInlineComments } from '@/lib/messages/inlineComments';
|
||||
import { renderMagicPrompt } from '@/lib/magicPrompts';
|
||||
import { startReviewFlow } from '@/lib/reviewFlow';
|
||||
import { AttachedFilesList, AttachedVSCodeFileChips, ActiveEditorFileSuggestion } from './FileAttachment';
|
||||
import ToolOutputDialog from './message/ToolOutputDialog';
|
||||
import type { ToolPopupContent } from './message/types';
|
||||
@@ -1106,10 +1107,11 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
|
||||
const names = new Set<string>([
|
||||
'init', 'review', 'undo', 'redo', 'timeline', 'compact', 'summary', 'workspace-review', 'plan-feature', 'catch-up', 'debug', 'weigh', 'explore',
|
||||
]);
|
||||
if (!isMobile && !isVSCodeRuntime()) names.add('handoff-review');
|
||||
for (const command of availableCommands) names.add(command.name.toLowerCase());
|
||||
for (const skill of availableSkills) names.add(skill.name.toLowerCase());
|
||||
return names;
|
||||
}, [availableCommands, availableSkills]);
|
||||
}, [availableCommands, availableSkills, isMobile]);
|
||||
|
||||
// /command and /skill spans (primary color). Only tokens that match a known
|
||||
// command/skill name are highlighted — partial/unknown tokens stay plain.
|
||||
@@ -1937,6 +1939,27 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (commandName === 'handoff-review' && currentSessionId && !isMobile && !isVSCodeRuntime()) {
|
||||
try {
|
||||
const directory = useSessionUIStore.getState().getDirectoryForSession(currentSessionId) || currentDirectory || '';
|
||||
if (!directory) {
|
||||
throw new Error('Session directory is unavailable');
|
||||
}
|
||||
await startReviewFlow({
|
||||
originalSessionID: currentSessionId,
|
||||
directory,
|
||||
providerID: providerIdToSend,
|
||||
modelID: modelIdToSend,
|
||||
agent: agentNameToSend,
|
||||
variant: variantToSend,
|
||||
agentMentionName,
|
||||
});
|
||||
scrollToBottom?.();
|
||||
} catch (error) {
|
||||
console.error('[review-flow] failed to start review flow', error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (commandName === 'plan-feature' && (currentSessionId || newSessionDraftOpen)) {
|
||||
try {
|
||||
await sessionActions.waitForConnectionOrThrow();
|
||||
|
||||
Reference in New Issue
Block a user