Skip to content

Commit a48b5cf

Browse files
Merge branch 'main' into feat/add-connector-gh-pages
2 parents e3c55cc + 35f3f4f commit a48b5cf

File tree

106 files changed

+5294
-1055
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

106 files changed

+5294
-1055
lines changed

Diff for: .github/workflows/pr-python-connector-tests.yml

+5
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,16 @@ env:
4545
SHAREPOINT_CLIENT_SECRET: ${{ secrets.SHAREPOINT_CLIENT_SECRET }}
4646
SHAREPOINT_CLIENT_DIRECTORY_ID: ${{ secrets.SHAREPOINT_CLIENT_DIRECTORY_ID }}
4747
SHAREPOINT_SITE: ${{ secrets.SHAREPOINT_SITE }}
48+
# Github
49+
ACCESS_TOKEN_GITHUB: ${{ secrets.ACCESS_TOKEN_GITHUB }}
4850
# Gitbook
4951
GITBOOK_SPACE_ID: ${{ secrets.GITBOOK_SPACE_ID }}
5052
GITBOOK_API_KEY: ${{ secrets.GITBOOK_API_KEY }}
5153
# Notion
5254
NOTION_INTEGRATION_TOKEN: ${{ secrets.NOTION_INTEGRATION_TOKEN }}
55+
# Highspot
56+
HIGHSPOT_KEY: ${{ secrets.HIGHSPOT_KEY }}
57+
HIGHSPOT_SECRET: ${{ secrets.HIGHSPOT_SECRET }}
5358

5459
jobs:
5560
connectors-check:

Diff for: backend/alembic.ini

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ keys = console
8484
keys = generic
8585

8686
[logger_root]
87-
level = WARN
87+
level = INFO
8888
handlers = console
8989
qualname =
9090

Diff for: backend/alembic/env.py

+35-8
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
from onyx.db.models import Base
2626
from celery.backends.database.session import ResultModelBase # type: ignore
2727

28+
# Make sure in alembic.ini [logger_root] level=INFO is set or most logging will be
29+
# hidden! (defaults to level=WARN)
30+
2831
# Alembic Config object
2932
config = context.config
3033

@@ -36,6 +39,7 @@
3639
target_metadata = [Base.metadata, ResultModelBase.metadata]
3740

3841
EXCLUDE_TABLES = {"kombu_queue", "kombu_message"}
42+
3943
logger = logging.getLogger(__name__)
4044

4145
ssl_context: ssl.SSLContext | None = None
@@ -64,7 +68,7 @@ def include_object(
6468
return True
6569

6670

67-
def get_schema_options() -> tuple[str, bool, bool]:
71+
def get_schema_options() -> tuple[str, bool, bool, bool]:
6872
x_args_raw = context.get_x_argument()
6973
x_args = {}
7074
for arg in x_args_raw:
@@ -76,6 +80,10 @@ def get_schema_options() -> tuple[str, bool, bool]:
7680
create_schema = x_args.get("create_schema", "true").lower() == "true"
7781
upgrade_all_tenants = x_args.get("upgrade_all_tenants", "false").lower() == "true"
7882

83+
# continue on error with individual tenant
84+
# only applies to online migrations
85+
continue_on_error = x_args.get("continue", "false").lower() == "true"
86+
7987
if (
8088
MULTI_TENANT
8189
and schema_name == POSTGRES_DEFAULT_SCHEMA
@@ -86,14 +94,12 @@ def get_schema_options() -> tuple[str, bool, bool]:
8694
"Please specify a tenant-specific schema."
8795
)
8896

89-
return schema_name, create_schema, upgrade_all_tenants
97+
return schema_name, create_schema, upgrade_all_tenants, continue_on_error
9098

9199

92100
def do_run_migrations(
93101
connection: Connection, schema_name: str, create_schema: bool
94102
) -> None:
95-
logger.info(f"About to migrate schema: {schema_name}")
96-
97103
if create_schema:
98104
connection.execute(text(f'CREATE SCHEMA IF NOT EXISTS "{schema_name}"'))
99105
connection.execute(text("COMMIT"))
@@ -134,7 +140,12 @@ def provide_iam_token_for_alembic(
134140

135141

136142
async def run_async_migrations() -> None:
137-
schema_name, create_schema, upgrade_all_tenants = get_schema_options()
143+
(
144+
schema_name,
145+
create_schema,
146+
upgrade_all_tenants,
147+
continue_on_error,
148+
) = get_schema_options()
138149

139150
engine = create_async_engine(
140151
build_connection_string(),
@@ -151,9 +162,15 @@ def event_provide_iam_token_for_alembic(
151162

152163
if upgrade_all_tenants:
153164
tenant_schemas = get_all_tenant_ids()
165+
166+
i_tenant = 0
167+
num_tenants = len(tenant_schemas)
154168
for schema in tenant_schemas:
169+
i_tenant += 1
170+
logger.info(
171+
f"Migrating schema: index={i_tenant} num_tenants={num_tenants} schema={schema}"
172+
)
155173
try:
156-
logger.info(f"Migrating schema: {schema}")
157174
async with engine.connect() as connection:
158175
await connection.run_sync(
159176
do_run_migrations,
@@ -162,7 +179,12 @@ def event_provide_iam_token_for_alembic(
162179
)
163180
except Exception as e:
164181
logger.error(f"Error migrating schema {schema}: {e}")
165-
raise
182+
if not continue_on_error:
183+
logger.error("--continue is not set, raising exception!")
184+
raise
185+
186+
logger.warning("--continue is set, continuing to next schema.")
187+
166188
else:
167189
try:
168190
logger.info(f"Migrating schema: {schema_name}")
@@ -180,7 +202,11 @@ def event_provide_iam_token_for_alembic(
180202

181203

182204
def run_migrations_offline() -> None:
183-
schema_name, _, upgrade_all_tenants = get_schema_options()
205+
"""This doesn't really get used when we migrate in the cloud."""
206+
207+
logger.info("run_migrations_offline starting.")
208+
209+
schema_name, _, upgrade_all_tenants, continue_on_error = get_schema_options()
184210
url = build_connection_string()
185211

186212
if upgrade_all_tenants:
@@ -230,6 +256,7 @@ def event_provide_iam_token_for_alembic_offline(
230256

231257

232258
def run_migrations_online() -> None:
259+
logger.info("run_migrations_online starting.")
233260
asyncio.run(run_async_migrations())
234261

235262

Diff for: backend/ee/onyx/server/enterprise_settings/api.py

+31-13
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515

1616
from ee.onyx.server.enterprise_settings.models import AnalyticsScriptUpload
1717
from ee.onyx.server.enterprise_settings.models import EnterpriseSettings
18-
from ee.onyx.server.enterprise_settings.store import _LOGO_FILENAME
19-
from ee.onyx.server.enterprise_settings.store import _LOGOTYPE_FILENAME
18+
from ee.onyx.server.enterprise_settings.store import get_logo_filename
19+
from ee.onyx.server.enterprise_settings.store import get_logotype_filename
2020
from ee.onyx.server.enterprise_settings.store import load_analytics_script
2121
from ee.onyx.server.enterprise_settings.store import load_settings
2222
from ee.onyx.server.enterprise_settings.store import store_analytics_script
@@ -28,7 +28,7 @@
2828
from onyx.auth.users import UserManager
2929
from onyx.db.engine import get_session
3030
from onyx.db.models import User
31-
from onyx.file_store.file_store import get_default_file_store
31+
from onyx.file_store.file_store import PostgresBackedFileStore
3232
from onyx.utils.logger import setup_logger
3333

3434
admin_router = APIRouter(prefix="/admin/enterprise-settings")
@@ -131,31 +131,49 @@ def put_logo(
131131
upload_logo(file=file, db_session=db_session, is_logotype=is_logotype)
132132

133133

134-
def fetch_logo_or_logotype(is_logotype: bool, db_session: Session) -> Response:
134+
def fetch_logo_helper(db_session: Session) -> Response:
135135
try:
136-
file_store = get_default_file_store(db_session)
137-
filename = _LOGOTYPE_FILENAME if is_logotype else _LOGO_FILENAME
138-
file_io = file_store.read_file(filename, mode="b")
139-
# NOTE: specifying "image/jpeg" here, but it still works for pngs
140-
# TODO: do this properly
141-
return Response(content=file_io.read(), media_type="image/jpeg")
136+
file_store = PostgresBackedFileStore(db_session)
137+
onyx_file = file_store.get_file_with_mime_type(get_logo_filename())
138+
if not onyx_file:
139+
raise ValueError("get_onyx_file returned None!")
142140
except Exception:
143141
raise HTTPException(
144142
status_code=404,
145-
detail=f"No {'logotype' if is_logotype else 'logo'} file found",
143+
detail="No logo file found",
146144
)
145+
else:
146+
return Response(content=onyx_file.data, media_type=onyx_file.mime_type)
147+
148+
149+
def fetch_logotype_helper(db_session: Session) -> Response:
150+
try:
151+
file_store = PostgresBackedFileStore(db_session)
152+
onyx_file = file_store.get_file_with_mime_type(get_logotype_filename())
153+
if not onyx_file:
154+
raise ValueError("get_onyx_file returned None!")
155+
except Exception:
156+
raise HTTPException(
157+
status_code=404,
158+
detail="No logotype file found",
159+
)
160+
else:
161+
return Response(content=onyx_file.data, media_type=onyx_file.mime_type)
147162

148163

149164
@basic_router.get("/logotype")
150165
def fetch_logotype(db_session: Session = Depends(get_session)) -> Response:
151-
return fetch_logo_or_logotype(is_logotype=True, db_session=db_session)
166+
return fetch_logotype_helper(db_session)
152167

153168

154169
@basic_router.get("/logo")
155170
def fetch_logo(
156171
is_logotype: bool = False, db_session: Session = Depends(get_session)
157172
) -> Response:
158-
return fetch_logo_or_logotype(is_logotype=is_logotype, db_session=db_session)
173+
if is_logotype:
174+
return fetch_logotype_helper(db_session)
175+
176+
return fetch_logo_helper(db_session)
159177

160178

161179
@admin_router.put("/custom-analytics-script")

Diff for: backend/ee/onyx/server/enterprise_settings/store.py

+34-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from onyx.configs.constants import FileOrigin
1414
from onyx.configs.constants import KV_CUSTOM_ANALYTICS_SCRIPT_KEY
1515
from onyx.configs.constants import KV_ENTERPRISE_SETTINGS_KEY
16+
from onyx.configs.constants import ONYX_DEFAULT_APPLICATION_NAME
1617
from onyx.file_store.file_store import get_default_file_store
1718
from onyx.key_value_store.factory import get_kv_store
1819
from onyx.key_value_store.interface import KvKeyNotFoundError
@@ -21,8 +22,18 @@
2122

2223
logger = setup_logger()
2324

25+
_LOGO_FILENAME = "__logo__"
26+
_LOGOTYPE_FILENAME = "__logotype__"
27+
2428

2529
def load_settings() -> EnterpriseSettings:
30+
"""Loads settings data directly from DB. This should be used primarily
31+
for checking what is actually in the DB, aka for editing and saving back settings.
32+
33+
Runtime settings actually used by the application should be checked with
34+
load_runtime_settings as defaults may be applied at runtime.
35+
"""
36+
2637
dynamic_config_store = get_kv_store()
2738
try:
2839
settings = EnterpriseSettings(
@@ -36,9 +47,24 @@ def load_settings() -> EnterpriseSettings:
3647

3748

3849
def store_settings(settings: EnterpriseSettings) -> None:
50+
"""Stores settings directly to the kv store / db."""
51+
3952
get_kv_store().store(KV_ENTERPRISE_SETTINGS_KEY, settings.model_dump())
4053

4154

55+
def load_runtime_settings() -> EnterpriseSettings:
56+
"""Loads settings from DB and applies any defaults or transformations for use
57+
at runtime.
58+
59+
Should not be stored back to the DB.
60+
"""
61+
enterprise_settings = load_settings()
62+
if not enterprise_settings.application_name:
63+
enterprise_settings.application_name = ONYX_DEFAULT_APPLICATION_NAME
64+
65+
return enterprise_settings
66+
67+
4268
_CUSTOM_ANALYTICS_SECRET_KEY = os.environ.get("CUSTOM_ANALYTICS_SECRET_KEY")
4369

4470

@@ -60,10 +86,6 @@ def store_analytics_script(analytics_script_upload: AnalyticsScriptUpload) -> No
6086
get_kv_store().store(KV_CUSTOM_ANALYTICS_SCRIPT_KEY, analytics_script_upload.script)
6187

6288

63-
_LOGO_FILENAME = "__logo__"
64-
_LOGOTYPE_FILENAME = "__logotype__"
65-
66-
6789
def is_valid_file_type(filename: str) -> bool:
6890
valid_extensions = (".png", ".jpg", ".jpeg")
6991
return filename.endswith(valid_extensions)
@@ -116,3 +138,11 @@ def upload_logo(
116138
file_type=file_type,
117139
)
118140
return True
141+
142+
143+
def get_logo_filename() -> str:
144+
return _LOGO_FILENAME
145+
146+
147+
def get_logotype_filename() -> str:
148+
return _LOGOTYPE_FILENAME

Diff for: backend/ee/onyx/server/tenants/provisioning.py

+9-12
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,14 @@ async def get_or_provision_tenant(
8787
# If we have a pre-provisioned tenant, assign it to the user
8888
await assign_tenant_to_user(tenant_id, email, referral_source)
8989
logger.info(f"Assigned pre-provisioned tenant {tenant_id} to user {email}")
90-
return tenant_id
9190
else:
9291
# If no pre-provisioned tenant is available, create a new one on-demand
9392
tenant_id = await create_tenant(email, referral_source)
94-
return tenant_id
93+
94+
# Notify control plane if we have created / assigned a new tenant
95+
if not DEV_MODE:
96+
await notify_control_plane(tenant_id, email, referral_source)
97+
return tenant_id
9598

9699
except Exception as e:
97100
# If we've encountered an error, log and raise an exception
@@ -116,10 +119,6 @@ async def create_tenant(email: str, referral_source: str | None = None) -> str:
116119
# Provision tenant on data plane
117120
await provision_tenant(tenant_id, email)
118121

119-
# Notify control plane if not already done in provision_tenant
120-
if not DEV_MODE and referral_source:
121-
await notify_control_plane(tenant_id, email, referral_source)
122-
123122
except Exception as e:
124123
logger.exception(f"Tenant provisioning failed: {str(e)}")
125124
# Attempt to rollback the tenant provisioning
@@ -271,6 +270,7 @@ def configure_default_api_keys(db_session: Session) -> None:
271270
fast_default_model_name="claude-3-5-sonnet-20241022",
272271
model_names=ANTHROPIC_MODEL_NAMES,
273272
display_model_names=["claude-3-5-sonnet-20241022"],
273+
api_key_changed=True,
274274
)
275275
try:
276276
full_provider = upsert_llm_provider(anthropic_provider, db_session)
@@ -283,17 +283,18 @@ def configure_default_api_keys(db_session: Session) -> None:
283283
)
284284

285285
if OPENAI_DEFAULT_API_KEY:
286-
open_provider = LLMProviderUpsertRequest(
286+
openai_provider = LLMProviderUpsertRequest(
287287
name="OpenAI",
288288
provider=OPENAI_PROVIDER_NAME,
289289
api_key=OPENAI_DEFAULT_API_KEY,
290290
default_model_name="gpt-4o",
291291
fast_default_model_name="gpt-4o-mini",
292292
model_names=OPEN_AI_MODEL_NAMES,
293293
display_model_names=["o1", "o3-mini", "gpt-4o", "gpt-4o-mini"],
294+
api_key_changed=True,
294295
)
295296
try:
296-
full_provider = upsert_llm_provider(open_provider, db_session)
297+
full_provider = upsert_llm_provider(openai_provider, db_session)
297298
update_default_provider(full_provider.id, db_session)
298299
except Exception as e:
299300
logger.error(f"Failed to configure OpenAI provider: {e}")
@@ -559,7 +560,3 @@ async def assign_tenant_to_user(
559560
except Exception:
560561
logger.exception(f"Failed to assign tenant {tenant_id} to user {email}")
561562
raise Exception("Failed to assign tenant to user")
562-
563-
# Notify control plane with retry logic
564-
if not DEV_MODE:
565-
await notify_control_plane(tenant_id, email, referral_source)

Diff for: backend/model_server/main.py

+11-5
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,17 @@ async def lifespan(app: FastAPI) -> AsyncGenerator:
6565

6666
app.state.gpu_type = gpu_type
6767

68-
if TEMP_HF_CACHE_PATH.is_dir():
69-
logger.notice("Moving contents of temp_huggingface to huggingface cache.")
70-
_move_files_recursively(TEMP_HF_CACHE_PATH, HF_CACHE_PATH)
71-
shutil.rmtree(TEMP_HF_CACHE_PATH, ignore_errors=True)
72-
logger.notice("Moved contents of temp_huggingface to huggingface cache.")
68+
try:
69+
if TEMP_HF_CACHE_PATH.is_dir():
70+
logger.notice("Moving contents of temp_huggingface to huggingface cache.")
71+
_move_files_recursively(TEMP_HF_CACHE_PATH, HF_CACHE_PATH)
72+
shutil.rmtree(TEMP_HF_CACHE_PATH, ignore_errors=True)
73+
logger.notice("Moved contents of temp_huggingface to huggingface cache.")
74+
except Exception as e:
75+
logger.warning(
76+
f"Error moving contents of temp_huggingface to huggingface cache: {e}. "
77+
"This is not a critical error and the model server will continue to run."
78+
)
7379

7480
torch.set_num_threads(max(MIN_THREADS_ML_MODELS, torch.get_num_threads()))
7581
logger.notice(f"Torch Threads: {torch.get_num_threads()}")

0 commit comments

Comments
 (0)