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:
Bohdan Triapitsyn
2026-06-07 01:22:40 +03:00
parent e0113c637d
commit 1f9769a932
19 changed files with 1381 additions and 13 deletions
+3
View File
@@ -1641,6 +1641,7 @@ export const dict = {
'chat.commandAutocomplete.command.compactDescription': 'Compress session history using AI to reduce context size',
'chat.commandAutocomplete.command.summaryDescription': 'Non-destructive session summary. Optional topic hint after the command.',
'chat.commandAutocomplete.command.workspaceReviewDescription': 'Review the workspace diff for intent, correctness, and adequacy, graded by severity.',
'chat.commandAutocomplete.command.handoffReviewDescription': 'Create or reuse a separate review session from a generated handoff.',
'chat.commandAutocomplete.command.featurePlanDescription': 'Start a guided, back-and-forth planning session for a new feature.',
'chat.commandAutocomplete.command.catchUpDescription': 'Re-establish context: what you were doing and where to pick up.',
'chat.commandAutocomplete.command.debugDescription': 'Guided root-cause investigation for a bug before proposing a fix.',
@@ -1767,6 +1768,8 @@ export const dict = {
'snippets.source.project': 'project',
'chat.chatInput.toast.compactFailed': 'Failed to compact session',
'chat.chatInput.toast.summaryFailed': 'Failed to generate summary',
'chat.messageBody.actions.sendReviewFeedback': 'Send review feedback to implementing agent',
'chat.messageBody.actions.sendImplementationResponse': 'Send implementation response to reviewing agent',
'chat.chatInput.toast.reviewFailed': 'Failed to review changes',
'chat.chatInput.toast.planFeatureFailed': 'Failed to start feature planning',
'chat.chatInput.toast.catchUpFailed': 'Failed to catch up',
+3
View File
@@ -1607,6 +1607,7 @@ export const dict: Record<I18nKey, string> = {
"chat.commandAutocomplete.command.compactDescription": "Comprimir el historial de la sesión usando IA para reducir el tamaño del contexto",
"chat.commandAutocomplete.command.summaryDescription": "Resumen no destructivo de la sesión. Pista opcional del tema después del comando.",
"chat.commandAutocomplete.command.workspaceReviewDescription": "Revisa el diff del espacio de trabajo en intención, corrección y adecuación, con hallazgos por severidad.",
"chat.commandAutocomplete.command.handoffReviewDescription": "Crea o reutiliza una sesión de revisión separada a partir de un handoff generado.",
"chat.commandAutocomplete.command.featurePlanDescription": "Inicia una sesión de planificación guiada e interactiva para una nueva función.",
"chat.commandAutocomplete.command.catchUpDescription": "Recupera el contexto: qué estabas haciendo y por dónde continuar.",
"chat.commandAutocomplete.command.debugDescription": "Investigación guiada de la causa raíz de un error antes de proponer una solución.",
@@ -1733,6 +1734,8 @@ export const dict: Record<I18nKey, string> = {
"snippets.source.project": "proyecto",
"chat.chatInput.toast.compactFailed": "No se pudo comprimir la sesión",
"chat.chatInput.toast.summaryFailed": "No se pudo generar el resumen",
"chat.messageBody.actions.sendReviewFeedback": "Enviar feedback de revisión al agente que implementa los cambios",
"chat.messageBody.actions.sendImplementationResponse": "Enviar respuesta de implementación al agente revisor",
"chat.chatInput.toast.reviewFailed": "No se pudieron revisar los cambios",
"chat.chatInput.toast.planFeatureFailed": "No se pudo iniciar la planificación de la función",
"chat.chatInput.toast.catchUpFailed": "No se pudo recuperar el contexto",
+3
View File
@@ -1643,6 +1643,7 @@ export const dict: Record<I18nKey, string> = {
'chat.commandAutocomplete.command.compactDescription': 'AI로 세션 기록을 압축해 컨텍스트 크기를 줄입니다',
'chat.commandAutocomplete.command.summaryDescription': '세션 기록을 안전하게 요약합니다. 명령 뒤에 선택적으로 주제 힌트를 넣을 수 있습니다.',
'chat.commandAutocomplete.command.workspaceReviewDescription': '워크스페이스 diff의 의도, 정확성, 적절성을 검토하고 심각도별로 분류합니다.',
'chat.commandAutocomplete.command.handoffReviewDescription': '생성된 인수인계로 별도의 리뷰 세션을 만들거나 재사용합니다.',
'chat.commandAutocomplete.command.featurePlanDescription': '새 기능을 위한 대화형 가이드 계획 세션을 시작합니다.',
'chat.commandAutocomplete.command.catchUpDescription': '맥락을 다시 파악합니다: 무엇을 하고 있었고 어디서 이어서 할지.',
'chat.commandAutocomplete.command.debugDescription': '수정안을 제시하기 전에 버그의 근본 원인을 단계적으로 조사합니다.',
@@ -1767,6 +1768,8 @@ export const dict: Record<I18nKey, string> = {
'snippets.source.project': '프로젝트',
'chat.chatInput.toast.compactFailed': '세션 압축 실패',
'chat.chatInput.toast.summaryFailed': '요약 생성 실패',
'chat.messageBody.actions.sendReviewFeedback': '리뷰 피드백을 변경 구현 에이전트에게 보내기',
'chat.messageBody.actions.sendImplementationResponse': '구현 응답을 리뷰 에이전트에게 보내기',
'chat.chatInput.toast.reviewFailed': '변경사항 검토 실패',
'chat.chatInput.toast.planFeatureFailed': '기능 계획을 시작하지 못했습니다',
'chat.chatInput.toast.catchUpFailed': '컨텍스트를 불러오지 못했습니다',
+3
View File
@@ -622,6 +622,7 @@ export const dict: Record<I18nKey, string> = {
'chat.commandAutocomplete.command.compactDescription': 'Skompresuj historię sesji używając AI aby zredukować rozmiar kontekstu',
'chat.commandAutocomplete.command.summaryDescription': 'Niedestrukcyjne podsumowanie sesji. Opcjonalna wskazówka tematu po poleceniu.',
'chat.commandAutocomplete.command.workspaceReviewDescription': 'Sprawdź diff obszaru roboczego pod kątem zamiaru, poprawności i adekwatności — ze znaleziskami według wagi.',
'chat.commandAutocomplete.command.handoffReviewDescription': 'Utwórz lub użyj ponownie osobnej sesji przeglądu z wygenerowanego handoffu.',
'chat.commandAutocomplete.command.featurePlanDescription': 'Rozpocznij prowadzoną, interaktywną sesję planowania nowej funkcji.',
'chat.commandAutocomplete.command.catchUpDescription': 'Przywróć kontekst: nad czym pracowałeś i od czego kontynuować.',
'chat.commandAutocomplete.command.debugDescription': 'Prowadzone badanie pierwotnej przyczyny błędu przed zaproponowaniem poprawki.',
@@ -1052,6 +1053,8 @@ export const dict: Record<I18nKey, string> = {
'chat.chatInput.toast.sendAttachmentsFailed': 'Nie udało się wysłać załączników. Spróbuj użyć mniejszej liczby plików lub mniejszych obrazów.',
'chat.chatInput.toast.someFilesSkipped': 'Pominięto niektóre pliki:\n{summary}',
'chat.chatInput.toast.summaryFailed': 'Nie udało się wygenerować podsumowania',
'chat.messageBody.actions.sendReviewFeedback': 'Wyślij uwagi z przeglądu do agenta wdrażającego zmiany',
'chat.messageBody.actions.sendImplementationResponse': 'Wyślij odpowiedź wdrożeniową do agenta przeglądającego',
'chat.chatInput.toast.togglePermissionAutoAcceptFailed': 'Nie udało się przełączyć automatycznej akceptacji uprawnień',
'chat.chatInput.toast.vscodePickFailed': 'Nie udało się wybrać plików w VS Code',
'chat.chatInput.worktreeNew': '+ Nowe',
@@ -1607,6 +1607,7 @@ export const dict: Record<I18nKey, string> = {
"chat.commandAutocomplete.command.compactDescription": "Comprimir o histórico da sessão usando IA para reduzir o tamanho do contexto",
"chat.commandAutocomplete.command.summaryDescription": "Resumo não destrutivo da sessão. Dica opcional do tema após o comando.",
"chat.commandAutocomplete.command.workspaceReviewDescription": "Revisa o diff do workspace quanto a intenção, correção e adequação, com achados por severidade.",
"chat.commandAutocomplete.command.handoffReviewDescription": "Crie ou reutilize uma sessão separada de revisão a partir de um handoff gerado.",
"chat.commandAutocomplete.command.featurePlanDescription": "Inicie uma sessão de planejamento guiada e interativa para uma nova funcionalidade.",
"chat.commandAutocomplete.command.catchUpDescription": "Retome o contexto: o que você estava fazendo e por onde continuar.",
"chat.commandAutocomplete.command.debugDescription": "Investigação guiada da causa raiz de um bug antes de propor uma correção.",
@@ -1733,6 +1734,8 @@ export const dict: Record<I18nKey, string> = {
"snippets.source.project": "projeto",
"chat.chatInput.toast.compactFailed": "Não foi possível comprimir a sessão",
"chat.chatInput.toast.summaryFailed": "Não foi possível gerar o resumo",
"chat.messageBody.actions.sendReviewFeedback": "Enviar feedback da revisão ao agente que implementa as mudanças",
"chat.messageBody.actions.sendImplementationResponse": "Enviar resposta da implementação ao agente revisor",
"chat.chatInput.toast.reviewFailed": "Não foi possível revisar as alterações",
"chat.chatInput.toast.planFeatureFailed": "Não foi possível iniciar o planejamento da funcionalidade",
"chat.chatInput.toast.catchUpFailed": "Não foi possível retomar o contexto",
+3
View File
@@ -1607,6 +1607,7 @@ export const dict: Record<I18nKey, string> = {
"chat.commandAutocomplete.command.compactDescription": "Стиснути історію сесії за допомогою ШІ, щоб зменшити розмір контексту",
"chat.commandAutocomplete.command.summaryDescription": "Неруйнівний підсумок сесії. Після команди можна додати тему.",
"chat.commandAutocomplete.command.workspaceReviewDescription": "Перевірити diff робочого простору на намір, коректність і адекватність — зі знахідками за рівнем критичності.",
"chat.commandAutocomplete.command.handoffReviewDescription": "Створити або повторно використати окрему сесію ревʼю зі згенерованого handoff.",
"chat.commandAutocomplete.command.featurePlanDescription": "Розпочати покрокову діалогову сесію планування нової фічі.",
"chat.commandAutocomplete.command.catchUpDescription": "Повернутись у контекст: над чим працювали і звідки продовжити.",
"chat.commandAutocomplete.command.debugDescription": "Кероване дослідження першопричини бага перед тим, як пропонувати фікс.",
@@ -1733,6 +1734,8 @@ export const dict: Record<I18nKey, string> = {
"snippets.source.project": "проєкт",
"chat.chatInput.toast.compactFailed": "Не вдалося стиснути сесію",
"chat.chatInput.toast.summaryFailed": "Не вдалося створити підсумок",
"chat.messageBody.actions.sendReviewFeedback": "Надіслати фідбек ревʼю агенту, який реалізує зміни",
"chat.messageBody.actions.sendImplementationResponse": "Надіслати відповідь щодо реалізації агенту-ревʼюеру",
"chat.chatInput.toast.reviewFailed": "Не вдалося переглянути зміни",
"chat.chatInput.toast.planFeatureFailed": "Не вдалося розпочати планування фічі",
"chat.chatInput.toast.catchUpFailed": "Не вдалося зібрати контекст",
@@ -1607,6 +1607,7 @@ export const dict: Record<I18nKey, string> = {
'chat.commandAutocomplete.command.compactDescription': '使用 AI 压缩会话历史以减少上下文大小',
'chat.commandAutocomplete.command.summaryDescription': '非破坏性会话总结。命令后可选填主题提示。',
'chat.commandAutocomplete.command.workspaceReviewDescription': '审查工作区 diff 的意图、正确性与充分性,并按严重程度分级。',
'chat.commandAutocomplete.command.handoffReviewDescription': '根据生成的交接内容创建或复用独立的审查会话。',
'chat.commandAutocomplete.command.featurePlanDescription': '为新功能开始一次引导式的来回规划会话。',
'chat.commandAutocomplete.command.catchUpDescription': '重新进入上下文:你之前在做什么、从哪里继续。',
'chat.commandAutocomplete.command.debugDescription': '在提出修复方案前,引导式地排查 bug 的根本原因。',
@@ -1733,6 +1734,8 @@ export const dict: Record<I18nKey, string> = {
'snippets.source.project': '项目',
'chat.chatInput.toast.compactFailed': '压缩会话失败',
'chat.chatInput.toast.summaryFailed': '生成总结失败',
'chat.messageBody.actions.sendReviewFeedback': '将审查反馈发送给实现更改的代理',
'chat.messageBody.actions.sendImplementationResponse': '将实现回应发送给审查代理',
'chat.chatInput.toast.reviewFailed': '审查变更失败',
'chat.chatInput.toast.planFeatureFailed': '无法开始功能规划',
'chat.chatInput.toast.catchUpFailed': '无法获取上下文',
@@ -1611,6 +1611,7 @@ export const dict: Record<I18nKey, string> = {
'chat.commandAutocomplete.command.compactDescription': '使用 AI 壓縮會話歷史以減少上下文大小',
'chat.commandAutocomplete.command.summaryDescription': '非破壞性會話總結。命令後可選填主題提示。',
'chat.commandAutocomplete.command.workspaceReviewDescription': '審查工作區 diff 的意圖、正確性與充分性,並依嚴重程度分級。',
'chat.commandAutocomplete.command.handoffReviewDescription': '根據生成的交接內容建立或重用獨立的審查會話。',
'chat.commandAutocomplete.command.featurePlanDescription': '為新功能開始一次引導式的來回規劃工作階段。',
'chat.commandAutocomplete.command.catchUpDescription': '重新進入上下文:你之前在做什麼、從哪裡繼續。',
'chat.commandAutocomplete.command.debugDescription': '在提出修復方案前,引導式地排查 bug 的根本原因。',
@@ -1737,6 +1738,8 @@ export const dict: Record<I18nKey, string> = {
'snippets.source.project': '項目',
'chat.chatInput.toast.compactFailed': '壓縮會話失敗',
'chat.chatInput.toast.summaryFailed': '生成總結失敗',
'chat.messageBody.actions.sendReviewFeedback': '將審查回饋傳送給實作變更的代理',
'chat.messageBody.actions.sendImplementationResponse': '將實作回應傳送給審查代理',
'chat.chatInput.toast.reviewFailed': '審查變更失敗',
'chat.chatInput.toast.planFeatureFailed': '無法開始功能規劃',
'chat.chatInput.toast.catchUpFailed': '無法取得上下文',