Compare commits

...

10 Commits

Author SHA1 Message Date
Wenxi Onyx
135e63b231 agents 2025-09-08 12:08:47 -07:00
Wenxi Onyx
eac2566c13 agents 2025-09-07 21:38:58 -07:00
Wenxi Onyx
4929feed18 fix transparent modal 2025-09-07 13:15:07 -07:00
Wenxi Onyx
3bec4b07ee make admin match mock color scheme 2025-09-07 13:15:07 -07:00
Wenxi Onyx
e8994369fb escape apostrophe 2025-09-07 13:15:07 -07:00
Wenxi Onyx
e6b4f93137 prettier 2025-09-07 13:15:07 -07:00
Wenxi
79cb2ffd02 cubic: clear default model if unavailable
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2025-09-07 13:15:07 -07:00
Wenxi Onyx
4b6723c32b greptile nits and illegal usememo 2025-09-07 13:15:07 -07:00
Wenxi Onyx
391f0a010c filter bedrock models to what is actually available to the user 2025-09-07 13:15:07 -07:00
Wenxi Onyx
5cbe47e13a allow bedrock api key 2025-09-07 13:15:07 -07:00
32 changed files with 378 additions and 157 deletions

View File

@@ -226,21 +226,30 @@ def fetch_available_well_known_llms() -> list[WellKnownLLMProviderDescriptor]:
name="AWS_ACCESS_KEY_ID",
display_name="AWS Access Key ID",
is_required=False,
description="If using AWS IAM roles, AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY can be left blank.",
description="If using IAM role or a long-term API key, leave this field blank.",
),
CustomConfigKey(
name="AWS_SECRET_ACCESS_KEY",
display_name="AWS Secret Access Key",
is_required=False,
is_secret=True,
description="If using AWS IAM roles, AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY can be left blank.",
description="If using IAM role or a long-term API key, leave this field blank.",
),
CustomConfigKey(
name="AWS_BEARER_TOKEN_BEDROCK",
display_name="AWS Bedrock Long-term API Key",
is_required=False,
is_secret=True,
description=(
"If using IAM role or access key, leave this field blank."
),
),
],
model_configurations=fetch_model_configurations_for_provider(
BEDROCK_PROVIDER_NAME
),
default_model=BEDROCK_DEFAULT_MODEL,
default_fast_model=BEDROCK_DEFAULT_MODEL,
default_fast_model=None,
),
WellKnownLLMProviderDescriptor(
name=VERTEXAI_PROVIDER_NAME,
@@ -304,6 +313,7 @@ def fetch_model_configurations_for_provider(
visible_model_names = (
fetch_visible_model_names_for_provider_as_set(provider_name) or set()
)
return [
ModelConfigurationView(
name=model_name,

View File

@@ -1,7 +1,12 @@
import os
from collections.abc import Callable
from datetime import datetime
from datetime import timezone
import boto3
from botocore.exceptions import BotoCoreError
from botocore.exceptions import ClientError
from botocore.exceptions import NoCredentialsError
from fastapi import APIRouter
from fastapi import Depends
from fastapi import HTTPException
@@ -22,12 +27,14 @@ from onyx.db.models import User
from onyx.llm.factory import get_default_llms
from onyx.llm.factory import get_llm
from onyx.llm.factory import get_max_input_tokens_from_llm_provider
from onyx.llm.llm_provider_options import BEDROCK_MODEL_NAMES
from onyx.llm.llm_provider_options import fetch_available_well_known_llms
from onyx.llm.llm_provider_options import WellKnownLLMProviderDescriptor
from onyx.llm.utils import get_llm_contextual_cost
from onyx.llm.utils import litellm_exception_to_error_msg
from onyx.llm.utils import model_supports_image_input
from onyx.llm.utils import test_llm
from onyx.server.manage.llm.models import BedrockModelsRequest
from onyx.server.manage.llm.models import LLMCost
from onyx.server.manage.llm.models import LLMProviderDescriptor
from onyx.server.manage.llm.models import LLMProviderUpsertRequest
@@ -386,3 +393,77 @@ def get_provider_contextual_cost(
)
return costs
@admin_router.post("/bedrock/available-models")
def get_bedrock_available_models(
request: BedrockModelsRequest,
_: User | None = Depends(current_admin_user),
) -> list[str]:
"""Fetch available Bedrock models for a specific region and credentials"""
try:
# Build a session with the simplest precedence: bearer, keys, IAM
if request.aws_bearer_token_bedrock:
os.environ["AWS_BEARER_TOKEN_BEDROCK"] = request.aws_bearer_token_bedrock
elif request.aws_access_key_id and request.aws_secret_access_key:
os.environ["AWS_ACCESS_KEY_ID"] = request.aws_access_key_id
os.environ["AWS_SECRET_ACCESS_KEY"] = request.aws_secret_access_key
session = boto3.Session(region_name=request.aws_region_name)
try:
bedrock = session.client("bedrock")
except Exception as e:
raise HTTPException(
status_code=400,
detail=f"Failed to create Bedrock client: {e}. Check AWS credentials and region.",
)
# Available Bedrock models: text-only, streaming supported
model_summaries = bedrock.list_foundation_models().get("modelSummaries", [])
available_models = {
model.get("modelId", "")
for model in model_summaries
if model.get("modelId")
and "embed" not in model.get("modelId", "").lower()
and model.get("responseStreamingSupported", False)
}
# Available inference profiles. Invoking these allows cross-region inference (preferred over base models).
profile_ids: set[str] = set()
cross_region_models: set[str] = set()
try:
inference_profiles = bedrock.list_inference_profiles(
typeEquals="SYSTEM_DEFINED"
).get("inferenceProfileSummaries", [])
for profile in inference_profiles:
if profile_id := profile.get("inferenceProfileId"):
profile_ids.add(profile_id)
# The model id is everything after the first period in the profile id
if "." in profile_id:
model_id = profile_id.split(".", 1)[1]
cross_region_models.add(model_id)
except Exception as e:
# Cross-region inference isn't guaranteed; ignore failures here.
logger.warning(f"Couldn't fetch inference profiles for Bedrock: {e}")
# Prefer profiles: de-dupe available models, then add profile IDs
candidates = (available_models - cross_region_models) | profile_ids
# Keep only models we support (compatibility with litellm)
filtered = sorted(
[model for model in candidates if model in BEDROCK_MODEL_NAMES],
reverse=True,
)
return filtered
except (ClientError, NoCredentialsError, BotoCoreError) as e:
raise HTTPException(
status_code=400, detail=f"Failed to connect to AWS Bedrock: {e}"
)
except Exception as e:
raise HTTPException(
status_code=500, detail=f"Unexpected error fetching Bedrock models: {e}"
)

View File

@@ -188,3 +188,11 @@ class LLMCost(BaseModel):
provider: str
model_name: str
cost: float
class BedrockModelsRequest(BaseModel):
aws_region_name: str
aws_access_key_id: str | None = None
aws_secret_access_key: str | None = None
aws_bearer_token_bedrock: str | None = None
provider_name: str | None = None # Optional: to save models to existing provider

View File

@@ -1,10 +1,10 @@
aioboto3==14.0.0
aioboto3==15.1.0
aiohttp==3.11.16
alembic==1.10.4
asyncpg==0.30.0
atlassian-python-api==3.41.16
beautifulsoup4==4.12.3
boto3==1.36.23
boto3==1.39.11
celery==5.5.1
chardet==5.2.0
chonkie==1.0.10
@@ -93,7 +93,7 @@ zulip==0.8.2
hubspot-api-client==8.1.0
asana==5.0.8
dropbox==11.36.2
boto3-stubs[s3]==1.34.133
boto3-stubs[s3]==1.39.11
shapely==2.0.6
stripe==10.12.0
urllib3==2.2.3

View File

@@ -1,5 +1,5 @@
black==25.1.0
boto3-stubs[s3]==1.34.133
boto3-stubs[s3]==1.39.11
celery-types==0.19.0
cohere==5.6.1
faker==37.1.0

View File

@@ -17,5 +17,5 @@ uvicorn==0.35.0
voyageai==0.2.3
litellm==1.76.2
sentry-sdk[fastapi,celery,starlette]==2.14.0
aioboto3==14.0.0
aioboto3==15.1.0
prometheus_fastapi_instrumentator==7.1.0

View File

@@ -779,18 +779,16 @@ export function AssistantEditor({
Edit assistant <b>{existingPersona.name}</b>
</>
) : (
"Create an Assistant"
"Create an Agent"
)}
</p>
<div className="max-w-4xl w-full">
<Separator />
<div className="flex gap-x-2 items-center">
<div className="block font-medium text-sm">
Assistant Icon
</div>
<div className="block font-medium text-sm">Agent Icon</div>
</div>
<SubLabel>
The icon that will visually represent your Assistant
The icon that will visually represent your Agent
</SubLabel>
<div className="flex gap-x-2 items-center">
<div
@@ -804,14 +802,14 @@ export function AssistantEditor({
{values.uploaded_image ? (
<img
src={URL.createObjectURL(values.uploaded_image)}
alt="Uploaded assistant icon"
alt="Uploaded agent icon"
className="w-12 h-12 rounded-full object-cover"
/>
) : existingPersona?.uploaded_image_id &&
!removePersonaImage ? (
<img
src={buildImgUrl(existingPersona?.uploaded_image_id)}
alt="Uploaded assistant icon"
alt="Uploaded agent icon"
className="w-12 h-12 rounded-full object-cover"
/>
) : (
@@ -935,7 +933,7 @@ export function AssistantEditor({
maxWidth="max-w-lg"
name="name"
label="Name"
placeholder="Email Assistant"
placeholder="Email Agent"
aria-label="assistant-name-input"
className="[&_input]:placeholder:text-text-muted/50"
/>
@@ -944,7 +942,7 @@ export function AssistantEditor({
maxWidth="max-w-lg"
name="description"
label="Description"
placeholder="Use this Assistant to help draft professional emails"
placeholder="Use this Agent to help draft professional emails"
className="[&_input]:placeholder:text-text-muted/50"
/>
@@ -1125,9 +1123,9 @@ export function AssistantEditor({
) : (
"Team Document Sets"
)}{" "}
this Assistant should use to inform its
this Agent should use to inform its
responses. If none are specified, the
Assistant will reference all available
Agent will reference all available
documents.
</>
</SubLabel>
@@ -1198,7 +1196,7 @@ export function AssistantEditor({
}
disabledTooltip={
!currentLLMSupportsImageOutput
? "To use Image Generation, select GPT-4 or another image compatible model as the default model for this Assistant."
? "To use Image Generation, select GPT-4 or another image compatible model as the default model for this Agent."
: "Image Generation requires an OpenAI or Azure Dall-E configuration."
}
/>
@@ -1381,8 +1379,8 @@ export function AssistantEditor({
}
}}
name="is_default_persona"
label="Featured Assistant"
subtext="If set, this assistant will be pinned for all new users and appear in the Featured list in the assistant explorer. This also makes the assistant public."
label="Featured Agent"
subtext="If set, this agent will be pinned for all new users and appear in the Featured list in the agent explorer. This also makes the agent public."
/>
)}
@@ -1392,7 +1390,7 @@ export function AssistantEditor({
<div className="block font-medium text-sm">Access</div>
</div>
<SubLabel>
Control who can access and use this assistant
Control who can access and use this agent
</SubLabel>
<div className="min-h-[100px]">
@@ -1609,7 +1607,7 @@ export function AssistantEditor({
className="text-sm text-subtle"
style={{ color: "rgb(113, 114, 121)" }}
>
Select labels to categorize this assistant
Select labels to categorize this agent
</p>
<div className="mt-3">
<SearchMultiSelectDropdown
@@ -1754,7 +1752,7 @@ export function AssistantEditor({
removeIndent
name="datetime_aware"
label="Date and Time Aware"
subtext='Toggle this option to let the assistant know the current date and time (formatted like: "Thursday Jan 1, 1970 00:01"). To inject it in a specific place in the prompt, use the pattern [[CURRENT_DATETIME]]'
subtext='Toggle this option to let the agent know the current date and time (formatted like: "Thursday Jan 1, 1970 00:01"). To inject it in a specific place in the prompt, use the pattern [[CURRENT_DATETIME]]'
/>
<Separator />

View File

@@ -204,7 +204,7 @@ export function PersonasTable({
"Name",
"Description",
"Type",
"Featured Assistant",
"Featured Agent",
"Is Visible",
"Delete",
]}

View File

@@ -23,8 +23,8 @@ function MainContent({
return (
<div>
<Text className="mb-2">
Assistants are a way to build custom search/question-answering
experiences for different use cases.
Agents are a way to build custom search/question-answering experiences
for different use cases.
</Text>
<Text className="mt-2">They allow you to customize:</Text>
<div className="text-sm">
@@ -39,17 +39,16 @@ function MainContent({
<div>
<Separator />
<Title>Create an Assistant</Title>
<CreateButton href="/assistants/new?admin=true" text="New Assistant" />
<Title>Create an Agent</Title>
<CreateButton href="/assistants/new?admin=true" text="New Agent" />
<Separator />
<Title>Existing Assistants</Title>
<Title>Existing Agents</Title>
<SubLabel>
Assistants will be displayed as options on the Chat / Search
interfaces in the order they are displayed below. Assistants marked as
hidden will not be displayed. Editable assistants are shown at the
top.
Agents will be displayed as options on the Chat / Search interfaces in
the order they are displayed below. Agents marked as hidden will not
be displayed. Editable agents are shown at the top.
</SubLabel>
<PersonasTable personas={personas} refreshPersonas={refreshPersonas} />
</div>
@@ -62,13 +61,13 @@ export default function Page() {
return (
<div className="mx-auto container">
<AdminPageTitle icon={<AssistantsIcon size={32} />} title="Assistants" />
<AdminPageTitle icon={<AssistantsIcon size={32} />} title="Agents" />
{isLoading && <ThreeDotsLoader />}
{error && (
<ErrorCallout
errorTitle="Failed to load assistants"
errorTitle="Failed to load agents"
errorMsg={
error?.info?.message ||
error?.info?.detail ||

View File

@@ -66,7 +66,7 @@ export function SlackChannelConfigsTable({
<TableHeader>
<TableRow>
<TableHead>Channel</TableHead>
<TableHead>Assistant</TableHead>
<TableHead>Agent</TableHead>
<TableHead>Document Sets</TableHead>
<TableHead>Actions</TableHead>
</TableRow>

View File

@@ -159,7 +159,7 @@ export const SlackChannelConfigCreationForm = ({
is: "assistant",
then: (schema) =>
schema.required(
"A persona is required when using the'Assistant' knowledge source"
"A persona is required when using the'Agent' knowledge source"
),
}),
standard_answer_categories: Yup.array(),

View File

@@ -230,14 +230,14 @@ export function SlackChannelConfigFormFields({
<RadioGroupItemField
value="assistant"
id="assistant"
label="Search Assistant"
label="Search Agent"
sublabel="Control both the documents and the prompt to use for answering questions"
/>
<RadioGroupItemField
value="non_search_assistant"
id="non_search_assistant"
label="Non-Search Assistant"
sublabel="Chat with an assistant that does not use documents"
label="Non-Search Agent"
sublabel="Chat with an agent that does not use documents"
/>
</RadioGroup>
</div>

View File

@@ -48,6 +48,8 @@ export function LLMProviderUpdateForm({
const [isTesting, setIsTesting] = useState(false);
const [testError, setTestError] = useState<string>("");
const [isFetchingModels, setIsFetchingModels] = useState(false);
const [fetchModelsError, setFetchModelsError] = useState<string>("");
const [showAdvancedOptions, setShowAdvancedOptions] = useState(false);
@@ -90,6 +92,9 @@ export function LLMProviderUpdateForm({
(llmProviderDescriptor.model_configurations
.filter((modelConfiguration) => modelConfiguration.is_visible)
.map((modelConfiguration) => modelConfiguration.name) as string[]),
// Helper field to force re-renders when model list updates
_modelListUpdated: 0,
};
// Setup validation schema if required
@@ -142,6 +147,99 @@ export function LLMProviderUpdateForm({
);
};
const fetchBedrockModels = async (values: any, setFieldValue: any) => {
if (llmProviderDescriptor.name !== "bedrock") {
return;
}
setIsFetchingModels(true);
setFetchModelsError("");
try {
const response = await fetch("/api/admin/llm/bedrock/available-models", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
aws_region_name: values.custom_config?.AWS_REGION_NAME,
aws_access_key_id: values.custom_config?.AWS_ACCESS_KEY_ID,
aws_secret_access_key: values.custom_config?.AWS_SECRET_ACCESS_KEY,
aws_bearer_token_bedrock:
values.custom_config?.AWS_BEARER_TOKEN_BEDROCK,
provider_name: existingLlmProvider?.name, // Save models to existing provider if editing
}),
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.detail || "Failed to fetch models");
}
const availableModels: string[] = await response.json();
// Update the model configurations with the fetched models
const updatedModelConfigs = availableModels.map((modelName) => {
// Find existing configuration to preserve is_visible setting
const existingConfig = llmProviderDescriptor.model_configurations.find(
(config) => config.name === modelName
);
return {
name: modelName,
is_visible: existingConfig?.is_visible ?? false, // Preserve existing visibility or default to false
max_input_tokens: null,
supports_image_input: false, // Will be determined by the backend
};
});
// Update the descriptor and form values
llmProviderDescriptor.model_configurations = updatedModelConfigs;
// Update selected model names to only include previously visible models that are available
const previouslySelectedModels = values.selected_model_names || [];
const stillAvailableSelectedModels = previouslySelectedModels.filter(
(modelName: string) => availableModels.includes(modelName)
);
setFieldValue("selected_model_names", stillAvailableSelectedModels);
// Set a default model if none is set
if (
(!values.default_model_name ||
!availableModels.includes(values.default_model_name)) &&
availableModels.length > 0
) {
setFieldValue("default_model_name", availableModels[0]);
}
// Clear fast model if it's not in the new list
if (
values.fast_default_model_name &&
!availableModels.includes(values.fast_default_model_name)
) {
setFieldValue("fast_default_model_name", null);
}
// Force a re-render by updating a timestamp or counter
setFieldValue("_modelListUpdated", Date.now());
setPopup?.({
message: `Successfully fetched ${availableModels.length} models for the selected region (including cross-region inference models).`,
type: "success",
});
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : "Unknown error";
setFetchModelsError(errorMessage);
setPopup?.({
message: `Failed to fetch models: ${errorMessage}`,
type: "error",
});
} finally {
setIsFetchingModels(false);
}
};
return (
<Formik
initialValues={initialValues}
@@ -153,6 +251,7 @@ export function LLMProviderUpdateForm({
const {
selected_model_names: visibleModels,
model_configurations: modelConfigurations,
_modelListUpdated,
...rest
} = values;
@@ -323,6 +422,7 @@ export function LLMProviderUpdateForm({
</ReactMarkdown>
}
placeholder={customConfigKey.default_value || undefined}
type={customConfigKey.is_secret ? "password" : "text"}
/>
</div>
);
@@ -340,6 +440,47 @@ export function LLMProviderUpdateForm({
}
})}
{/* Bedrock-specific fetch models button */}
{llmProviderDescriptor.name === "bedrock" && (
<div className="flex flex-col gap-2">
<Button
type="button"
onClick={() =>
fetchBedrockModels(
formikProps.values,
formikProps.setFieldValue
)
}
disabled={
isFetchingModels ||
!formikProps.values.custom_config?.AWS_REGION_NAME
}
className="w-fit"
>
{isFetchingModels ? (
<>
<LoadingAnimation size="text-sm" />
<span className="ml-2">Fetching Models...</span>
</>
) : (
"Fetch Available Models for Region"
)}
</Button>
{fetchModelsError && (
<Text className="text-red-600 text-sm">{fetchModelsError}</Text>
)}
<Text className="text-sm text-gray-600">
Enter your AWS region, then click this button to fetch available
Bedrock models.
<br />
If you&apos;re updating your existing provider, you&apos;ll need
to click this button to fetch the latest models.
</Text>
</div>
)}
{!firstTimeConfiguration && (
<>
<Separator />

View File

@@ -6,8 +6,17 @@ export default async function Page(props: {
}) {
const params = await props.params;
return (
<ConnectorWrapper
connector={params.connector.replace("-", "_") as ConfigurableSources}
/>
<div
className="min-h-screen w-screen bg-background"
style={{
["--background-input-background" as any]: "#FAFAFA",
["--background" as any]: "#FAFAFA",
["--background-chatbar-sidebar" as any]: "#F0F0F1",
}}
>
<ConnectorWrapper
connector={params.connector.replace("-", "_") as ConfigurableSources}
/>
</div>
);
}

View File

@@ -7,7 +7,14 @@ import EmbeddingForm from "./pages/EmbeddingFormPage";
export default function EmbeddingWrapper() {
return (
<EmbeddingFormProvider>
<div className="flex justify-center w-full h-full">
<div
className="flex justify-center w-full h-full bg-background"
style={{
["--background-input-background" as any]: "#FAFAFA",
["--background" as any]: "#FAFAFA",
["--background-chatbar-sidebar" as any]: "#F0F0F1",
}}
>
<EmbeddingSidebar />
<div className="mt-12 w-full max-w-5xl mx-auto">
<EmbeddingForm />

View File

@@ -327,7 +327,7 @@ const AssistantCard: React.FC<{
</button>
</TooltipTrigger>
<TooltipContent>
Start a new chat with this assistant
Start a new chat with this agent
</TooltipContent>
</Tooltip>
</TooltipProvider>

View File

@@ -143,7 +143,7 @@ export function AssistantModal({ hideModal }: AssistantModalProps) {
transform: "translateX(-50%)",
margin: 0,
}}
aria-label="Assistant Modal"
aria-label="Agent Modal"
>
<div className="absolute top-2 right-2">
<button
@@ -232,7 +232,7 @@ export function AssistantModal({ hideModal }: AssistantModalProps) {
<div className="flex-grow overflow-y-auto">
<h2 className="text-2xl font-semibold text-text-800 mb-2 px-4 py-2">
Featured Assistants
Featured Agents
</h2>
<div className="w-full px-2 pb-10 grid grid-cols-1 md:grid-cols-2 gap-x-6 gap-y-6">
@@ -258,7 +258,7 @@ export function AssistantModal({ hideModal }: AssistantModalProps) {
{allAssistants && allAssistants.length > 0 && (
<>
<h2 className="text-2xl font-semibold text-text-800 mt-4 mb-2 px-4 py-2">
All Assistants
All Agents
</h2>
<div className="w-full mt-2 px-2 pb-2 grid grid-cols-1 md:grid-cols-2 gap-x-6 gap-y-6">

View File

@@ -139,7 +139,7 @@ export function AssistantSharingModal({
>
<div>
<p className="text-text-600 text-lg mb-6">
Manage access to this assistant by sharing it with other users.
Manage access to this agent by sharing it with other users.
</p>
<div className="mb-8 flex flex-col gap-y-4">
@@ -148,7 +148,7 @@ export function AssistantSharingModal({
</div>
<div className="mb-8 flex flex-col gap-y-4">
<h3 className="text-lg font-semibold">Share Assistant</h3>
<h3 className="text-lg font-semibold">Share Agent</h3>
<SearchMultiSelectDropdown
options={allUsers
.filter(

View File

@@ -126,7 +126,7 @@ export function AssistantSharingPopover({
</h2>
</div>
<p className="text-text-600 text-sm mb-4">
Manage access to this assistant by sharing it with other users.
Manage access to this agent by sharing it with other users.
</p>
<div className="mb-4">
@@ -135,7 +135,7 @@ export function AssistantSharingPopover({
</div>
<div className="mb-4">
<h3 className="text-sm font-semibold mb-2">Share Assistant</h3>
<h3 className="text-sm font-semibold mb-2">Share Agent</h3>
<SearchMultiSelectDropdown
options={allUsers
.filter(

View File

@@ -16,16 +16,16 @@ export function MakePublicAssistantPopover({
return (
<div className="p-4 space-y-4">
<h2 className="text-lg font-semibold">
{isPublic ? "Public Assistant" : "Make Assistant Public"}
{isPublic ? "Public Agent" : "Make Agent Public"}
</h2>
<p className="text-sm">
This assistant is currently{" "}
This agent is currently{" "}
<span className="font-semibold">{isPublic ? "public" : "private"}</span>
.
{isPublic
? " Anyone can currently access this assistant."
: " Only you can access this assistant."}
? " Anyone can currently access this agent."
: " Only you can access this agent."}
</p>
<Separator />
@@ -33,7 +33,7 @@ export function MakePublicAssistantPopover({
{isPublic ? (
<div className="space-y-4">
<p className="text-sm">
To restrict access to this assistant, you can make it private again.
To restrict access to this agent, you can make it private again.
</p>
<Button
onClick={async () => {
@@ -43,15 +43,15 @@ export function MakePublicAssistantPopover({
size="sm"
variant="destructive"
>
Make Assistant Private
Make Agent Private
</Button>
</div>
) : (
<div className="space-y-4">
<p className="text-sm">
Making this assistant public will allow anyone with the link to view
and use it. Ensure that all content and capabilities of the
assistant are safe to share.
Making this agent public will allow anyone with the link to view and
use it. Ensure that all content and capabilities of the agent are
safe to share.
</p>
<Button
onClick={async () => {
@@ -60,7 +60,7 @@ export function MakePublicAssistantPopover({
}}
size="sm"
>
Make Assistant Public
Make Agent Public
</Button>
</div>
)}

View File

@@ -16,18 +16,18 @@ export function MakePublicAssistantModal({
<Modal onOutsideClick={onClose} width="max-w-3xl">
<div className="space-y-6">
<h2 className="text-2xl font-bold text-text-darker">
{isPublic ? "Public Assistant" : "Make Assistant Public"}
{isPublic ? "Public Agent" : "Make Agent Public"}
</h2>
<Text>
This assistant is currently{" "}
This agent is currently{" "}
<span className="font-semibold">
{isPublic ? "public" : "private"}
</span>
.
{isPublic
? " Anyone can currently access this assistant."
: " Only you can access this assistant."}
? " Anyone can currently access this agent."
: " Only you can access this agent."}
</Text>
<Separator />
@@ -35,8 +35,7 @@ export function MakePublicAssistantModal({
{isPublic ? (
<div className="space-y-4">
<Text>
To restrict access to this assistant, you can make it private
again.
To restrict access to this agent, you can make it private again.
</Text>
<Button
onClick={async () => {
@@ -46,15 +45,15 @@ export function MakePublicAssistantModal({
size="sm"
variant="destructive"
>
Make Assistant Private
Make Agent Private
</Button>
</div>
) : (
<div className="space-y-4">
<Text>
Making this assistant public will allow anyone with the link to
view and use it. Ensure that all content and capabilities of the
assistant are safe to share.
Making this agent public will allow anyone with the link to view
and use it. Ensure that all content and capabilities of the agent
are safe to share.
</Text>
<Button
onClick={async () => {
@@ -64,7 +63,7 @@ export function MakePublicAssistantModal({
size="sm"
variant="submit"
>
Make Assistant Public
Make Agent Public
</Button>
</div>
)}

View File

@@ -66,7 +66,7 @@ export function AssistantsTab({
return (
<div className="py-4">
<h3 className="px-4 text-lg font-semibold">Change Assistant</h3>
<h3 className="px-4 text-lg font-semibold">Change Agent</h3>
<DndContext
sensors={sensors}
collisionDetection={closestCenter}

View File

@@ -470,7 +470,7 @@ export const GroupDisplay = ({
<Separator />
<h2 className="text-xl font-bold mt-8 mb-2">Assistants</h2>
<h2 className="text-xl font-bold mt-8 mb-2">Agents</h2>
<div>
{userGroup.document_sets.length > 0 ? (
@@ -488,7 +488,7 @@ export const GroupDisplay = ({
</div>
) : (
<>
<Text>No Assistants in this group...</Text>
<Text>No Agents in this group...</Text>
</>
)}
</div>

View File

@@ -152,7 +152,7 @@ export function PersonaMessagesChart({
} else if (selectedPersonaId === undefined) {
content = (
<div className="h-80 text-text-500 flex flex-col">
<p className="m-auto">Select an assistant to view analytics</p>
<p className="m-auto">Select an agent to view analytics</p>
</div>
);
} else if (!personaMessagesData?.length) {
@@ -178,11 +178,9 @@ export function PersonaMessagesChart({
return (
<CardSection className="mt-8">
<Title>Assistant Analytics</Title>
<Title>Agent Analytics</Title>
<div className="flex flex-col gap-4">
<Text>
Messages and unique users per day for the selected assistant
</Text>
<Text>Messages and unique users per day for the selected agent</Text>
<div className="flex items-center gap-4">
<Select
value={selectedPersonaId?.toString() ?? ""}
@@ -191,14 +189,14 @@ export function PersonaMessagesChart({
}}
>
<SelectTrigger className="flex w-full max-w-xs">
<SelectValue placeholder="Select an assistant to display" />
<SelectValue placeholder="Select an agent to display" />
</SelectTrigger>
<SelectContent>
<div className="flex items-center px-2 pb-2 sticky top-0 bg-background border-b">
<Search className="h-4 w-4 mr-2 shrink-0 opacity-50" />
<input
className="flex h-8 w-full rounded-sm bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"
placeholder="Search assistants..."
placeholder="Search agents..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
onClick={(e) => e.stopPropagation()}

View File

@@ -125,7 +125,7 @@ export function AssistantStats({ assistantId }: { assistantId: number }) {
content = (
<div className="h-80 text-text-500 flex flex-col">
<p className="m-auto">
No data found for this assistant in the selected date range
No data found for this agent in the selected date range
</p>
</div>
);
@@ -145,7 +145,7 @@ export function AssistantStats({ assistantId }: { assistantId: number }) {
return (
<Card className="w-full">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<p className="text-base font-normal text-2xl">Assistant Analytics</p>
<p className="text-base font-normal text-2xl">Agent Analytics</p>
<AdminDateRangeSelector
value={dateRange}
onValueChange={setDateRange}

View File

@@ -63,7 +63,8 @@ export function Modal({
<div
onMouseDown={handleMouseDown}
className={cn(
`fixed inset-0 bg-neutral-950/50 border border-neutral-200 dark:border-neutral-800 bg-opacity-30 backdrop-blur-sm h-full
`fixed inset-0 h-full w-full
bg-neutral-950/50 dark:bg-neutral-950/60 backdrop-blur-sm
flex items-center justify-center z-50 transition-opacity duration-300 ease-in-out`
)}
>
@@ -75,7 +76,7 @@ export function Modal({
}
}}
className={`
bg-neutral-50 dark:bg-neutral-800
bg-white dark:bg-neutral-800 opacity-100
text-neutral-950 dark:text-neutral-50
rounded
shadow-2xl

View File

@@ -28,12 +28,12 @@ export default function SourceTile({
w-40
cursor-pointer
shadow-md
hover:bg-accent-background-hovered
hover:bg-background-settings-hover/50
relative
${
preSelect
? "bg-accent-background-hovered subtle-pulse"
: "bg-accent-background"
? "bg-background-settings-hover subtle-pulse"
: "bg-background-sidebar"
}
`}
href={navigationUrl}

View File

@@ -2,10 +2,8 @@
import { AdminSidebar } from "@/components/admin/connectors/AdminSidebar";
import {
ClipboardIcon,
NotebookIconSkeleton,
ConnectorIconSkeleton,
ThumbsUpIconSkeleton,
ToolIconSkeleton,
CpuIconSkeleton,
UsersIconSkeleton,
@@ -15,7 +13,6 @@ import {
DatabaseIconSkeleton,
SettingsIconSkeleton,
PaintingIconSkeleton,
ZoomInIconSkeleton,
SlackIconSkeleton,
DocumentSetIconSkeleton,
AssistantsIconSkeleton,
@@ -65,35 +62,7 @@ const connectors_items = () => [
},
];
const document_management_items = () => [
{
name: (
<div className="flex">
<DocumentSetIconSkeleton className="text-text-700" size={18} />
<div className="ml-1">Document Sets</div>
</div>
),
link: "/admin/documents/sets",
},
{
name: (
<div className="flex">
<ZoomInIconSkeleton className="text-text-700" size={18} />
<div className="ml-1">Explorer</div>
</div>
),
link: "/admin/documents/explorer",
},
{
name: (
<div className="flex">
<ThumbsUpIconSkeleton className="text-text-700" size={18} />
<div className="ml-1">Feedback</div>
</div>
),
link: "/admin/documents/feedback",
},
];
// Document Management group removed; Document Sets moved under Assistants
const custom_assistants_items = (
isCurator: boolean,
@@ -104,11 +73,20 @@ const custom_assistants_items = (
name: (
<div className="flex">
<AssistantsIconSkeleton className="text-text-700" size={18} />
<div className="ml-1">Assistants</div>
<div className="ml-1">Agents</div>
</div>
),
link: "/admin/assistants",
},
{
name: (
<div className="flex">
<DocumentSetIconSkeleton className="text-text-700" size={18} />
<div className="ml-1">Document Sets</div>
</div>
),
link: "/admin/documents/sets",
},
];
if (!isCurator) {
@@ -134,17 +112,7 @@ const custom_assistants_items = (
);
}
if (enableEnterprise) {
items.push({
name: (
<div className="flex">
<ClipboardIcon className="text-text-700" size={18} />
<div className="ml-1">Standard Answers</div>
</div>
),
link: "/admin/standard-answer",
});
}
// Standard Answers removed from sidebar
return items;
};
@@ -162,11 +130,7 @@ const collections = (
items: connectors_items(),
},
{
name: "Document Management",
items: document_management_items(),
},
{
name: "Custom Assistants",
name: "Custom Agents",
items: custom_assistants_items(isCurator, enableEnterprise),
},
...(isCurator
@@ -427,7 +391,14 @@ export function ClientLayout({
}
return (
<div className="h-screen w-screen flex overflow-y-hidden">
<div
className="h-screen w-screen flex overflow-y-hidden"
style={{
["--background-input-background" as any]: "#FAFAFA",
["--background" as any]: "#FAFAFA",
["--background-chatbar-sidebar" as any]: "#F0F0F1",
}}
>
{popup}
{userSettingsOpen && (
@@ -472,7 +443,7 @@ export function ClientLayout({
)}
/>
</div>
<div className="overflow-y-scroll w-full">
<div className="overflow-y-scroll w-full bg-background">
<div className="fixed left-0 gap-x-4 px-4 top-4 h-8 mb-auto w-full items-start flex justify-end">
<UserDropdown toggleUserSettings={toggleUserSettings} />
</div>

View File

@@ -161,7 +161,7 @@ export const Notifications = ({
)}
<div className="flex-grow">
<p className="font-semibold text-sm text-text-800">
New Assistant Shared: {persona?.name}
New Agent Shared: {persona?.name}
</p>
{persona?.description && (
<p className="text-xs text-text-600 mt-1">

View File

@@ -24,13 +24,12 @@ export default function EmbeddingSidebar() {
className={`flex-none
h-screen
transition-all
bg-opacity-80
duration-300
ease-in-out
w-[250px]
`}
>
<div className="fixed h-full left-0 top-0 bg- w-[250px]">
<div className="fixed h-full left-0 top-0 w-[250px] bg-background-sidebar">
<div className="ml-4 mr-3 flex flex gap-x-1 items-center mt-2 my-auto text-text-700 text-xl">
<div className="mr-1 my-auto h-6 w-6">
<Logo height={24} width={24} />

View File

@@ -5,17 +5,17 @@ export const NoAssistantModal = ({ isAdmin }: { isAdmin: boolean }) => {
<Modal width="bg-white max-w-2xl rounded-lg shadow-xl text-center">
<>
<h2 className="text-3xl font-bold text-text-800 mb-4">
No Assistant Available
No Agent Available
</h2>
<p className="text-text-600 mb-6">
You currently have no assistant configured. To use this feature, you
need to take action.
You currently have no agent configured. To use this feature, you need
to take action.
</p>
{isAdmin ? (
<>
<p className="text-text-600 mb-6">
As an administrator, you can create a new assistant by visiting
the admin panel.
As an administrator, you can create a new agent by visiting the
admin panel.
</p>
<button
onClick={() => {
@@ -28,7 +28,7 @@ export const NoAssistantModal = ({ isAdmin }: { isAdmin: boolean }) => {
</>
) : (
<p className="text-text-600 mb-2">
Please contact your administrator to configure an assistant for you.
Please contact your administrator to configure an agent for you.
</p>
)}
</>

View File

@@ -160,8 +160,8 @@ const SortableAssistant: React.FC<SortableAssistantProps> = ({
</TooltipTrigger>
<TooltipContent>
{pinned
? "Unpin this assistant from the sidebar"
: "Pin this assistant to the sidebar"}
? "Unpin this agent from the sidebar"
: "Pin this agent to the sidebar"}
</TooltipContent>
</Tooltip>
</TooltipProvider>
@@ -342,7 +342,7 @@ export const HistorySidebar = React.memo(
)}
<div className="h-full relative overflow-x-hidden overflow-y-auto">
<div className="flex px-4 font-normal text-sm gap-x-2 leading-normal text-text-500/80 dark:text-[#D4D4D4] items-center font-normal leading-normal">
Assistants
Agents
</div>
<DndContext
sensors={sensors}
@@ -412,11 +412,11 @@ export const HistorySidebar = React.memo(
<div className="w-full px-4">
<button
aria-label="Explore Assistants"
aria-label="Explore Agents"
onClick={() => setShowAssistantsModal(true)}
className="w-full cursor-pointer text-base text-black dark:text-[#D4D4D4] hover:bg-background-chat-hover flex items-center gap-x-2 py-1 px-2 rounded-md"
>
Explore Assistants
Explore Agents
</button>
</div>