This commit is contained in:
pablonyx 2025-03-22 16:28:38 -07:00
parent eff93825e8
commit c602ee2ed5
10 changed files with 115 additions and 50 deletions

View File

@ -226,7 +226,6 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
setup_onyx(db_session, POSTGRES_DEFAULT_SCHEMA)
else:
setup_multitenant_onyx()
print("onyz set up")
if not MULTI_TENANT:
# don't emit a metric for every pod rollover/restart

View File

@ -594,7 +594,7 @@ def prefilter_requests(req: SocketModeRequest, client: TenantSocketModeClient) -
bot_tag_id = get_onyx_bot_slack_bot_id(client.web_client)
if event_type == "message":
is_dm = event.get("channel_type") == "im"
is_tagged = bot_tag_id and bot_tag_id in msg
is_tagged = bot_tag_id and f"<@{bot_tag_id}>" in msg
is_onyx_bot_msg = bot_tag_id and bot_tag_id in event.get("user", "")
# OnyxBot should never respond to itself
@ -727,7 +727,11 @@ def build_request_details(
event = cast(dict[str, Any], req.payload["event"])
msg = cast(str, event["text"])
channel = cast(str, event["channel"])
tagged = event.get("type") == "app_mention"
# Check for both app_mention events and messages containing bot tag
bot_tag_id = get_onyx_bot_slack_bot_id(client.web_client)
tagged = (event.get("type") == "app_mention") or (
event.get("type") == "message" and bot_tag_id and f"<@{bot_tag_id}>" in msg
)
message_ts = event.get("ts")
thread_ts = event.get("thread_ts")
sender_id = event.get("user") or None

View File

@ -145,7 +145,7 @@ def update_emote_react(
def remove_onyx_bot_tag(message_str: str, client: WebClient) -> str:
bot_tag_id = get_onyx_bot_slack_bot_id(web_client=client)
return re.sub(rf"<@{bot_tag_id}>\s", "", message_str)
return re.sub(rf"<@{bot_tag_id}>\s*", "", message_str)
def _check_for_url_in_block(block: Block) -> bool:

View File

@ -25,6 +25,7 @@ from onyx.db.connector_credential_pair import add_credential_to_connector
from onyx.db.credentials import create_credential
from onyx.db.engine import get_session
from onyx.db.enums import AccessType
from onyx.db.enums import ConnectorCredentialPairStatus
from onyx.db.models import ConnectorCredentialPair
from onyx.db.models import User
from onyx.db.models import UserFile
@ -488,6 +489,9 @@ def reindex_file(
# Trigger immediate reindexing with highest priority
tenant_id = get_current_tenant_id()
# Update the cc_pair status to ACTIVE to ensure it's processed
cc_pair.status = ConnectorCredentialPairStatus.ACTIVE
db_session.commit()
try:
trigger_indexing_for_cc_pair(
[], cc_pair.connector_id, True, tenant_id, db_session, is_user_file=True

View File

@ -6,7 +6,6 @@ from uuid import UUID
from pydantic import BaseModel
from onyx.db.enums import ConnectorCredentialPairStatus
from onyx.db.enums import IndexingStatus
from onyx.db.models import UserFile
from onyx.db.models import UserFolder
@ -49,11 +48,7 @@ class UserFileSnapshot(BaseModel):
if model.cc_pair
and len(model.cc_pair.index_attempts) > 0
and model.cc_pair.last_successful_index_time is None
and (
model.cc_pair.status == ConnectorCredentialPairStatus.PAUSED
or len(model.cc_pair.index_attempts) == 1
and model.cc_pair.index_attempts[0].status == IndexingStatus.FAILED
)
and model.cc_pair.status == ConnectorCredentialPairStatus.PAUSED
else UserFileStatus.INDEXED
if model.cc_pair
and model.cc_pair.last_successful_index_time is not None

View File

@ -82,6 +82,7 @@ import {
FileIcon,
FolderIcon,
InfoIcon,
BookIcon,
} from "lucide-react";
import { LLMSelector } from "@/components/llm/LLMSelector";
import useSWR from "swr";
@ -99,6 +100,7 @@ import { RadioGroupItemField } from "@/components/ui/RadioGroupItemField";
import { SEARCH_TOOL_ID } from "@/app/chat/tools/constants";
import TextView from "@/components/chat/TextView";
import { MinimalOnyxDocument } from "@/lib/search/interfaces";
import { TabToggle } from "@/components/ui/TabToggle";
function findSearchTool(tools: ToolSnapshot[]) {
return tools.find((tool) => tool.in_code_tool_id === SEARCH_TOOL_ID);
@ -905,27 +907,25 @@ export function AssistantEditor({
<div>
{canShowKnowledgeSource && (
<>
<Label>Knowledge Source</Label>
<RadioGroup
className="flex flex-col gap-y-4 mt-2"
<TabToggle
options={[
{
id: "user_files",
label: "User Knowledge",
icon: <FileIcon size={16} />,
},
{
id: "team_knowledge",
label: "Team Knowledge",
icon: <BookIcon size={16} />,
},
]}
value={values.knowledge_source}
onValueChange={(value: string) => {
onChange={(value) => {
setFieldValue("knowledge_source", value);
}}
>
<RadioGroupItemField
value="user_files"
id="user_files"
label="User Knowledge"
sublabel="Select specific user files and groups for this Assistant to use"
/>
<RadioGroupItemField
value="team_knowledge"
id="team_knowledge"
label="Team Knowledge"
sublabel="Use team-wide document sets for this Assistant"
/>
</RadioGroup>
className="mt-2 mb-4 w-full max-w-sm"
/>
</>
)}

View File

@ -158,16 +158,15 @@ export const DocumentsProvider: React.FC<DocumentsProviderProps> = ({
fetchFolders();
}, []);
const refreshFolders = useCallback(async () => {
const refreshFolders = async () => {
try {
const data = await documentsService.fetchFolders();
setFolders(data);
} catch (error) {
console.error("Failed to fetch folders:", error);
setError("Failed to fetch folders");
}
}, []);
};
const uploadFile = useCallback(
async (

View File

@ -68,7 +68,8 @@ export const FileListItem: React.FC<FileListItemProps> = ({
const { setPopup, popup } = usePopup();
const [showMoveOptions, setShowMoveOptions] = useState(false);
const [indexingStatus, setIndexingStatus] = useState<boolean | null>(null);
const { getFilesIndexingStatus, refreshFolders } = useDocumentsContext();
const { getFilesIndexingStatus, refreshFolderDetails } =
useDocumentsContext();
useEffect(() => {
const checkStatus = async () => {
@ -78,7 +79,7 @@ export const FileListItem: React.FC<FileListItemProps> = ({
checkStatus();
const interval = setInterval(() => {
refreshFolders();
refreshFolderDetails();
if (indexingStatus === false) {
checkStatus();
}
@ -133,7 +134,7 @@ export const FileListItem: React.FC<FileListItemProps> = ({
throw new Error("Failed to reindex file");
}
setIndexingStatus(false); // Set to false to show indexing status
refreshFolders(); // Refresh the folder list
refreshFolderDetails();
setPopup({
type: "success",
message: "Reindexing will start shortly.",
@ -217,12 +218,15 @@ export const FileListItem: React.FC<FileListItemProps> = ({
</div>
<div className="w-[30%] text-sm text-text-400 dark:text-neutral-400">
{indexingStatus == false ? (
{file.status == FileStatus.INDEXING ||
file.status == FileStatus.REINDEXING ? (
<>
N/A, indexing
<AnimatedDots />
</>
) : indexingStatus != undefined && file.token_count !== undefined ? (
) : file.status == FileStatus.FAILED ? (
<>Failed</>
) : file.token_count !== undefined ? (
`${file.token_count?.toLocaleString()} tokens`
) : (
"N/A"

View File

@ -119,7 +119,9 @@ const DraggableItem: React.FC<{
>
<div className="w-6 flex items-center justify-center shrink-0">
<div
className="opacity-0 group-hover:opacity-100 transition-opacity duration-150"
className={`${
isSelected ? "" : "opacity-0 group-hover:opacity-100"
} transition-opacity duration-150`}
onClick={(e) => {
e.stopPropagation();
e.preventDefault();
@ -258,18 +260,24 @@ const FilePickerFolderItem: React.FC<{
<div className="flex text-sm items-center gap-2 w-[65%] min-w-0">
<FolderIcon className="h-5 w-5 text-black dark:text-black shrink-0 fill-black dark:fill-black" />
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<span className="truncate text-text-dark dark:text-text-dark">
{folder.name}
</span>
</TooltipTrigger>
<TooltipContent>
<p>{folder.name}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
{folder.name.length > 40 ? (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<span className="truncate text-text-dark dark:text-text-dark">
{truncateString(folder.name, 40)}
</span>
</TooltipTrigger>
<TooltipContent>
<p>{folder.name}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
) : (
<span className="truncate text-text-dark dark:text-text-dark">
{folder.name}
</span>
)}
</div>
<div className="w-[35%] text-right text-sm text-text-400 dark:text-neutral-400 pr-4">
@ -1222,7 +1230,6 @@ export const FilePickerModal: React.FC<FilePickerModalProps> = ({
isSelected={selectedFileIds.has(file.id)}
/>
))}
{/* Add uploading files visualization */}
</div>
</SortableContext>

View File

@ -0,0 +1,53 @@
import React from "react";
import { cn } from "@/lib/utils";
export interface TabOption {
id: string;
label: string;
icon?: React.ReactNode;
}
interface TabToggleProps {
options: TabOption[];
value: string;
onChange: (value: string) => void;
className?: string;
}
export function TabToggle({
options,
value,
onChange,
className,
}: TabToggleProps) {
return (
<div className={cn("flex w-fit border-b border-border", className)}>
{options.map((option) => (
<button
key={option.id}
type="button"
onClick={() => onChange(option.id)}
className={cn(
"flex items-center justify-center gap-2 px-6 py-2 text-sm font-medium transition-colors",
"border-b-2 -mb-[2px]",
value === option.id
? "border-primary text-primary font-semibold"
: "border-transparent text-gray-500 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-300"
)}
>
{option.icon && (
<span
className={cn(
"flex-shrink-0",
value === option.id ? "text-primary" : ""
)}
>
{option.icon}
</span>
)}
<span>{option.label}</span>
</button>
))}
</div>
);
}