Merge remote-tracking branch 'upstream/dev' into feat/ui-revamp

This commit is contained in:
Anish Sarkar 2026-05-13 03:02:23 +05:30
commit 481bb406b6
757 changed files with 70989 additions and 4089 deletions

View file

@ -4,7 +4,6 @@ import { useAtom, useAtomValue, useSetAtom } from "jotai";
import { PanelRight } from "lucide-react";
import dynamic from "next/dynamic";
import { startTransition, useEffect } from "react";
import { closeHitlEditPanelAtom, hitlEditPanelAtom } from "@/atoms/chat/hitl-edit-panel.atom";
import { closeReportPanelAtom, reportPanelAtom } from "@/atoms/chat/report-panel.atom";
import { citationPanelAtom, closeCitationPanelAtom } from "@/atoms/citation/citation-panel.atom";
import { documentsSidebarOpenAtom } from "@/atoms/documents/ui.atoms";
@ -12,6 +11,7 @@ import { closeEditorPanelAtom, editorPanelAtom } from "@/atoms/editor/editor-pan
import { rightPanelCollapsedAtom, rightPanelTabAtom } from "@/atoms/layout/right-panel.atom";
import { Button } from "@/components/ui/button";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { closeHitlEditPanelAtom, hitlEditPanelAtom } from "@/features/chat-messages/hitl";
import { DocumentsSidebar } from "../sidebar";
const EditorPanelContent = dynamic(
@ -32,7 +32,7 @@ const CitationPanelContent = dynamic(
const HitlEditPanelContent = dynamic(
() =>
import("@/components/hitl-edit-panel/hitl-edit-panel").then((m) => ({
import("@/features/chat-messages/hitl").then((m) => ({
default: m.HitlEditPanelContent,
})),
{ ssr: false, loading: () => null }

View file

@ -24,7 +24,10 @@ import type React from "react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { toast } from "sonner";
import { agentFlagsAtom } from "@/atoms/agent/agent-flags-query.atom";
import { mentionedDocumentsAtom } from "@/atoms/chat/mentioned-documents.atom";
import {
makeFolderMention,
mentionedDocumentsAtom,
} from "@/atoms/chat/mentioned-documents.atom";
import { connectorDialogOpenAtom } from "@/atoms/connector-dialog/connector-dialog.atoms";
import { connectorsAtom } from "@/atoms/connectors/connector-query.atoms";
import { deleteDocumentMutationAtom } from "@/atoms/documents/document-mutation.atoms";
@ -881,7 +884,7 @@ function AuthenticatedDocumentsSidebarBase({
const handleToggleChatMention = useCallback(
(doc: { id: number; title: string; document_type: string }, isMentioned: boolean) => {
const key = getMentionDocKey(doc);
const key = getMentionDocKey({ ...doc, kind: "doc" });
if (isMentioned) {
setSidebarDocs((prev) => prev.filter((d) => getMentionDocKey(d) !== key));
} else {
@ -889,7 +892,12 @@ function AuthenticatedDocumentsSidebarBase({
if (prev.some((d) => getMentionDocKey(d) === key)) return prev;
return [
...prev,
{ id: doc.id, title: doc.title, document_type: doc.document_type as DocumentTypeEnum },
{
id: doc.id,
title: doc.title,
document_type: doc.document_type as DocumentTypeEnum,
kind: "doc",
},
];
});
}
@ -899,40 +907,29 @@ function AuthenticatedDocumentsSidebarBase({
const handleToggleFolderSelect = useCallback(
(folderId: number, selectAll: boolean) => {
function collectSubtreeDocs(parentId: number): DocumentNodeDoc[] {
const directDocs = (treeDocuments ?? []).filter(
(d) =>
d.folderId === parentId &&
d.status?.state !== "pending" &&
d.status?.state !== "processing" &&
d.status?.state !== "failed"
);
const childFolders = foldersByParent[String(parentId)] ?? [];
const descendantDocs = childFolders.flatMap((cf) => collectSubtreeDocs(cf.id));
return [...directDocs, ...descendantDocs];
}
const subtreeDocs = collectSubtreeDocs(folderId);
if (subtreeDocs.length === 0) return;
// One folder click = one folder-mention chip. The agent
// resolves the chip to its virtual path
// (``/documents/MyFolder/``) and walks it itself with
// ``ls`` / ``find_documents``. We deliberately don't
// fan out to per-doc chips anymore — the previous
// behaviour created N chips for one click and dropped
// nested folders entirely once selected, which the
// agent had no way to recover.
const folder = treeFolders.find((f) => f.id === folderId);
if (!folder) return;
const chip = makeFolderMention({ id: folder.id, name: folder.name });
const chipKey = getMentionDocKey(chip);
if (selectAll) {
setSidebarDocs((prev) => {
const existingDocKeys = new Set(prev.map((d) => getMentionDocKey(d)));
const newDocs = subtreeDocs
.filter((d) => !existingDocKeys.has(getMentionDocKey(d)))
.map((d) => ({
id: d.id,
title: d.title,
document_type: d.document_type as DocumentTypeEnum,
}));
return newDocs.length > 0 ? [...prev, ...newDocs] : prev;
const exists = prev.some((d) => getMentionDocKey(d) === chipKey);
return exists ? prev : [...prev, chip];
});
} else {
const keysToRemove = new Set(subtreeDocs.map((d) => getMentionDocKey(d)));
setSidebarDocs((prev) => prev.filter((d) => !keysToRemove.has(getMentionDocKey(d))));
setSidebarDocs((prev) => prev.filter((d) => getMentionDocKey(d) !== chipKey));
}
},
[treeDocuments, foldersByParent, setSidebarDocs]
[treeFolders, setSidebarDocs]
);
const searchFilteredDocuments = useMemo(() => {
@ -1604,7 +1601,7 @@ function AnonymousDocumentsSidebar({
const handleToggleChatMention = useCallback(
(doc: { id: number; title: string; document_type: string }, isMentioned: boolean) => {
const key = getMentionDocKey(doc);
const key = getMentionDocKey({ ...doc, kind: "doc" });
if (isMentioned) {
setSidebarDocs((prev) => prev.filter((d) => getMentionDocKey(d) !== key));
} else {
@ -1612,7 +1609,12 @@ function AnonymousDocumentsSidebar({
if (prev.some((d) => getMentionDocKey(d) === key)) return prev;
return [
...prev,
{ id: doc.id, title: doc.title, document_type: doc.document_type as DocumentTypeEnum },
{
id: doc.id,
title: doc.title,
document_type: doc.document_type as DocumentTypeEnum,
kind: "doc",
},
];
});
}