chore: format
This commit is contained in:
@@ -2599,8 +2599,7 @@ def oauth_client_kwargs(scope: str, **kwargs):
|
|||||||
client_kwargs['code_challenge_method'] = 'S256'
|
client_kwargs['code_challenge_method'] = 'S256'
|
||||||
elif OAUTH_CODE_CHALLENGE_METHOD:
|
elif OAUTH_CODE_CHALLENGE_METHOD:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
'Code challenge methods other than "%s" not supported. Given: "%s"'
|
'Code challenge methods other than "%s" not supported. Given: "%s"' % ('S256', OAUTH_CODE_CHALLENGE_METHOD)
|
||||||
% ('S256', OAUTH_CODE_CHALLENGE_METHOD)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return client_kwargs
|
return client_kwargs
|
||||||
|
|||||||
@@ -837,7 +837,9 @@ async def get_models(request: Request, refresh: bool = False, user=Depends(get_v
|
|||||||
all_models = await get_all_models(request, refresh=refresh, user=user)
|
all_models = await get_all_models(request, refresh=refresh, user=user)
|
||||||
|
|
||||||
# Filter out filter pipelines
|
# Filter out filter pipelines
|
||||||
models = [model for model in all_models if not ('pipeline' in model and model['pipeline'].get('type', None) == 'filter')]
|
models = [
|
||||||
|
model for model in all_models if not ('pipeline' in model and model['pipeline'].get('type', None) == 'filter')
|
||||||
|
]
|
||||||
|
|
||||||
# Chat requests resolve models by ID from request.app.state.MODELS, where
|
# Chat requests resolve models by ID from request.app.state.MODELS, where
|
||||||
# duplicate IDs collapse to the last model. Return the same effective list.
|
# duplicate IDs collapse to the last model. Return the same effective list.
|
||||||
@@ -1142,11 +1144,7 @@ async def chat_completion(
|
|||||||
chat_id = form_data.get('chat_id') or ''
|
chat_id = form_data.get('chat_id') or ''
|
||||||
chat_variables = form_data.pop('chat_variables', None)
|
chat_variables = form_data.pop('chat_variables', None)
|
||||||
if chat_variables is None:
|
if chat_variables is None:
|
||||||
existing_chat = (
|
existing_chat = await Chats.get_chat_by_id(chat_id) if is_saved_chat_id(chat_id) else None
|
||||||
await Chats.get_chat_by_id(chat_id)
|
|
||||||
if is_saved_chat_id(chat_id)
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
chat_variables = existing_chat.variables if existing_chat else {}
|
chat_variables = existing_chat.variables if existing_chat else {}
|
||||||
|
|
||||||
chat_variables = normalize_chat_variables(chat_variables)
|
chat_variables = normalize_chat_variables(chat_variables)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ Revises: 55f1302ac17c
|
|||||||
Create Date: 2026-07-26 19:19:31.345756
|
Create Date: 2026-07-26 19:19:31.345756
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
|
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ Revises: c49178636c78
|
|||||||
Create Date: 2026-07-24 01:21:46.457057
|
Create Date: 2026-07-24 01:21:46.457057
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Sequence, Union
|
from typing import Sequence, Union
|
||||||
|
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ Revises: 9a1b2c3d4e5f
|
|||||||
Create Date: 2026-07-23 23:33:45.497453
|
Create Date: 2026-07-23 23:33:45.497453
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Sequence, Union
|
from typing import Sequence, Union
|
||||||
|
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
|
|||||||
@@ -174,9 +174,7 @@ def normalize_access_grants(access_grants: Optional[list]) -> list[dict]:
|
|||||||
continue
|
continue
|
||||||
if not isinstance(principal_id, str) or not principal_id:
|
if not isinstance(principal_id, str) or not principal_id:
|
||||||
continue
|
continue
|
||||||
if principal_type == PRINCIPAL_TYPE_ANYONE and (
|
if principal_type == PRINCIPAL_TYPE_ANYONE and (principal_id != WILDCARD_PRINCIPAL_ID or permission != 'read'):
|
||||||
principal_id != WILDCARD_PRINCIPAL_ID or permission != 'read'
|
|
||||||
):
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
key = (principal_type, principal_id, permission)
|
key = (principal_type, principal_id, permission)
|
||||||
|
|||||||
@@ -777,9 +777,7 @@ class CalendarEventAttendeeTable:
|
|||||||
existing_status = {
|
existing_status = {
|
||||||
row.user_id: row.status
|
row.user_id: row.status
|
||||||
for row in (
|
for row in (
|
||||||
await db.execute(
|
await db.execute(select(CalendarEventAttendee).filter(CalendarEventAttendee.event_id == event_id))
|
||||||
select(CalendarEventAttendee).filter(CalendarEventAttendee.event_id == event_id)
|
|
||||||
)
|
|
||||||
).scalars()
|
).scalars()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,25 +21,25 @@ async def search_openserp(
|
|||||||
|
|
||||||
No API key is required -- only a reachable OpenSERP base URL.
|
No API key is required -- only a reachable OpenSERP base URL.
|
||||||
"""
|
"""
|
||||||
url = f"{base_url.rstrip('/')}/mega/search"
|
url = f'{base_url.rstrip("/")}/mega/search'
|
||||||
params = {"text": query, "limit": count}
|
params = {'text': query, 'limit': count}
|
||||||
|
|
||||||
log.debug("searching OpenSERP at %s", url)
|
log.debug('searching OpenSERP at %s', url)
|
||||||
|
|
||||||
session = await get_session()
|
session = await get_session()
|
||||||
async with session.get(url, params=params) as response:
|
async with session.get(url, params=params) as response:
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
payload = await response.json()
|
payload = await response.json()
|
||||||
|
|
||||||
results = payload.get("results", [])
|
results = payload.get('results', [])
|
||||||
if filter_list:
|
if filter_list:
|
||||||
results = get_filtered_results(results, filter_list)
|
results = get_filtered_results(results, filter_list)
|
||||||
|
|
||||||
return [
|
return [
|
||||||
SearchResult(
|
SearchResult(
|
||||||
link=item.get("url", ""),
|
link=item.get('url', ''),
|
||||||
title=item.get("title"),
|
title=item.get('title'),
|
||||||
snippet=item.get("snippet"),
|
snippet=item.get('snippet'),
|
||||||
)
|
)
|
||||||
for item in results[:count]
|
for item in results[:count]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -995,7 +995,10 @@ async def get_user_chats(user=Depends(get_verified_user)):
|
|||||||
|
|
||||||
@router.get('/all/archived', response_model=list[ChatResponse])
|
@router.get('/all/archived', response_model=list[ChatResponse])
|
||||||
async def get_user_archived_chats(user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session)):
|
async def get_user_archived_chats(user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session)):
|
||||||
return [ChatResponse.model_validate(chat, from_attributes=True) for chat in await Chats.get_archived_chats_by_user_id(user.id, db=db)]
|
return [
|
||||||
|
ChatResponse.model_validate(chat, from_attributes=True)
|
||||||
|
for chat in await Chats.get_archived_chats_by_user_id(user.id, db=db)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
############################
|
############################
|
||||||
@@ -1357,12 +1360,15 @@ async def update_chat_by_id(
|
|||||||
touch = 'history' in form_data.chat or 'messages' in form_data.chat
|
touch = 'history' in form_data.chat or 'messages' in form_data.chat
|
||||||
chat = await Chats.update_chat_by_id(id, updated_chat, db=db, touch=touch)
|
chat = await Chats.update_chat_by_id(id, updated_chat, db=db, touch=touch)
|
||||||
if form_data.variables is not None:
|
if form_data.variables is not None:
|
||||||
chat = await Chats.update_chat_variables_by_id(
|
chat = (
|
||||||
id,
|
await Chats.update_chat_variables_by_id(
|
||||||
form_data.variables,
|
id,
|
||||||
db=db,
|
form_data.variables,
|
||||||
touch=False,
|
db=db,
|
||||||
) or chat
|
touch=False,
|
||||||
|
)
|
||||||
|
or chat
|
||||||
|
)
|
||||||
|
|
||||||
# Reconcile chat_message rows without inferring deletes from missing IDs.
|
# Reconcile chat_message rows without inferring deletes from missing IDs.
|
||||||
# Message deletion has its own endpoint below.
|
# Message deletion has its own endpoint below.
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ router = APIRouter()
|
|||||||
|
|
||||||
|
|
||||||
def add_chat_variables_schema(model_dict: dict) -> dict:
|
def add_chat_variables_schema(model_dict: dict) -> dict:
|
||||||
system = ((model_dict.get('params') or {}).get('system') if isinstance(model_dict.get('params'), dict) else None)
|
system = (model_dict.get('params') or {}).get('system') if isinstance(model_dict.get('params'), dict) else None
|
||||||
schema = get_chat_variables_schema(system)
|
schema = get_chat_variables_schema(system)
|
||||||
if schema:
|
if schema:
|
||||||
model_dict.setdefault('meta', {})['chat_variables_schema'] = schema
|
model_dict.setdefault('meta', {})['chat_variables_schema'] = schema
|
||||||
|
|||||||
@@ -378,9 +378,7 @@ async def check_model_access(
|
|||||||
raise HTTPException(status_code=403, detail='Model not found')
|
raise HTTPException(status_code=403, detail='Model not found')
|
||||||
|
|
||||||
# Enforce access on chained base models
|
# Enforce access on chained base models
|
||||||
if not await has_base_model_access(
|
if not await has_base_model_access(user.id, model_info, user_role=user.role, user_group_ids=user_group_ids):
|
||||||
user.id, model_info, user_role=user.role, user_group_ids=user_group_ids
|
|
||||||
):
|
|
||||||
raise HTTPException(status_code=403, detail='Model not found')
|
raise HTTPException(status_code=403, detail='Model not found')
|
||||||
else:
|
else:
|
||||||
if user.role != 'admin':
|
if user.role != 'admin':
|
||||||
|
|||||||
@@ -477,7 +477,7 @@ async def execute_automation(app, automation: AutomationModel) -> None:
|
|||||||
{'role': 'user', 'content': prompt},
|
{'role': 'user', 'content': prompt},
|
||||||
],
|
],
|
||||||
'meta': {'automation_id': automation.id},
|
'meta': {'automation_id': automation.id},
|
||||||
}
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -205,9 +205,7 @@ async def _load_config() -> dict:
|
|||||||
'enable': bool(values.get('chat.context_compaction.enable', False)),
|
'enable': bool(values.get('chat.context_compaction.enable', False)),
|
||||||
'token_threshold': token_threshold,
|
'token_threshold': token_threshold,
|
||||||
'token_cap': _parse_positive_int(values.get('chat.context_compaction.token_cap')) or token_threshold,
|
'token_cap': _parse_positive_int(values.get('chat.context_compaction.token_cap')) or token_threshold,
|
||||||
'retention_percentage': _clamp_retention_percentage(
|
'retention_percentage': _clamp_retention_percentage(values.get('chat.context_compaction.retention_percentage')),
|
||||||
values.get('chat.context_compaction.retention_percentage')
|
|
||||||
),
|
|
||||||
'prompt_template': values.get('chat.context_compaction.prompt_template', '') or '',
|
'prompt_template': values.get('chat.context_compaction.prompt_template', '') or '',
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,14 +259,9 @@ async def get_chat_context_usage(chat: Any, model_id: str | None = None) -> dict
|
|||||||
|
|
||||||
for idx in range(len(messages) - 1, -1, -1):
|
for idx in range(len(messages) - 1, -1, -1):
|
||||||
usage = messages[idx].get('usage') or (messages[idx].get('info') or {}).get('usage')
|
usage = messages[idx].get('usage') or (messages[idx].get('info') or {}).get('usage')
|
||||||
input_tokens = (
|
input_tokens = (usage or {}).get('prompt_tokens') or (usage or {}).get('input_tokens')
|
||||||
(usage or {}).get('prompt_tokens')
|
|
||||||
or (usage or {}).get('input_tokens')
|
|
||||||
)
|
|
||||||
if isinstance(usage, dict) and input_tokens:
|
if isinstance(usage, dict) and input_tokens:
|
||||||
tokens = int(input_tokens or 0) + int(
|
tokens = int(input_tokens or 0) + int(usage.get('completion_tokens') or usage.get('output_tokens') or 0)
|
||||||
usage.get('completion_tokens') or usage.get('output_tokens') or 0
|
|
||||||
)
|
|
||||||
tokens += _estimate_messages_tokens(messages[idx + 1 :])
|
tokens += _estimate_messages_tokens(messages[idx + 1 :])
|
||||||
return _build_context_usage(tokens, threshold)
|
return _build_context_usage(tokens, threshold)
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,9 @@ def custom_headers_require_user_groups(custom_headers: Optional[dict]) -> bool:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def get_user_groups_for_custom_headers(custom_headers: Optional[dict], user: Optional[Any] = None) -> Optional[list]:
|
async def get_user_groups_for_custom_headers(
|
||||||
|
custom_headers: Optional[dict], user: Optional[Any] = None
|
||||||
|
) -> Optional[list]:
|
||||||
"""Fetch the user's groups only when a header value actually references a groups placeholder."""
|
"""Fetch the user's groups only when a header value actually references a groups placeholder."""
|
||||||
if user is None or not custom_headers_require_user_groups(custom_headers):
|
if user is None or not custom_headers_require_user_groups(custom_headers):
|
||||||
return None
|
return None
|
||||||
|
|||||||
@@ -3567,11 +3567,7 @@ async def non_streaming_chat_response_handler(response, ctx):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
title = (
|
title = await Chats.get_chat_title_by_id(metadata['chat_id']) if save_to_chat else ''
|
||||||
await Chats.get_chat_title_by_id(metadata['chat_id'])
|
|
||||||
if save_to_chat
|
|
||||||
else ''
|
|
||||||
)
|
|
||||||
|
|
||||||
# Use output from backend if provided (OR-compliant backends),
|
# Use output from backend if provided (OR-compliant backends),
|
||||||
# otherwise generate from response content
|
# otherwise generate from response content
|
||||||
@@ -3648,11 +3644,7 @@ async def non_streaming_chat_response_handler(response, ctx):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.debug(f'Error occurred while processing request: {e}')
|
log.debug(f'Error occurred while processing request: {e}')
|
||||||
chat_id = metadata.get('chat_id')
|
chat_id = metadata.get('chat_id')
|
||||||
if (
|
if getattr(request.state, 'internal', False) is not True and chat_id and is_saved_chat_id(chat_id):
|
||||||
getattr(request.state, 'internal', False) is not True
|
|
||||||
and chat_id
|
|
||||||
and is_saved_chat_id(chat_id)
|
|
||||||
):
|
|
||||||
webui_url = await Config.get('webui.url')
|
webui_url = await Config.get('webui.url')
|
||||||
await publish_event(
|
await publish_event(
|
||||||
request,
|
request,
|
||||||
@@ -5337,11 +5329,7 @@ async def streaming_chat_response_handler(response, ctx):
|
|||||||
if item.get('status') == 'in_progress':
|
if item.get('status') == 'in_progress':
|
||||||
item['status'] = 'completed'
|
item['status'] = 'completed'
|
||||||
|
|
||||||
title = (
|
title = await Chats.get_chat_title_by_id(metadata['chat_id']) if save_to_chat else ''
|
||||||
await Chats.get_chat_title_by_id(metadata['chat_id'])
|
|
||||||
if save_to_chat
|
|
||||||
else ''
|
|
||||||
)
|
|
||||||
data = {
|
data = {
|
||||||
'done': True,
|
'done': True,
|
||||||
'output': output,
|
'output': output,
|
||||||
|
|||||||
@@ -194,9 +194,7 @@ def get_output_text(output: list | None) -> str:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
text = ''.join(
|
text = ''.join(
|
||||||
str(part.get('text'))
|
str(part.get('text')) for part in parts if isinstance(part, dict) and part.get('text') is not None
|
||||||
for part in parts
|
|
||||||
if isinstance(part, dict) and part.get('text') is not None
|
|
||||||
)
|
)
|
||||||
if text.strip():
|
if text.strip():
|
||||||
texts.append(text)
|
texts.append(text)
|
||||||
|
|||||||
@@ -214,11 +214,23 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="mb-1 text-xs text-gray-500">{$i18n.t('When')}</div>
|
<div class="mb-1 text-xs text-gray-500">{$i18n.t('When')}</div>
|
||||||
<div class="flex items-center gap-2 text-sm flex-wrap">
|
<div class="flex items-center gap-2 text-sm flex-wrap">
|
||||||
<input type="date" class="bg-transparent outline-hidden dark:scheme-dark" bind:value={startDate} />
|
<input
|
||||||
|
type="date"
|
||||||
|
class="bg-transparent outline-hidden dark:scheme-dark"
|
||||||
|
bind:value={startDate}
|
||||||
|
/>
|
||||||
{#if !allDay}
|
{#if !allDay}
|
||||||
<input type="time" class="bg-transparent outline-hidden dark:scheme-dark" bind:value={startTime} />
|
<input
|
||||||
|
type="time"
|
||||||
|
class="bg-transparent outline-hidden dark:scheme-dark"
|
||||||
|
bind:value={startTime}
|
||||||
|
/>
|
||||||
<span class="text-gray-300 dark:text-gray-600">–</span>
|
<span class="text-gray-300 dark:text-gray-600">–</span>
|
||||||
<input type="time" class="bg-transparent outline-hidden dark:scheme-dark" bind:value={endTime} />
|
<input
|
||||||
|
type="time"
|
||||||
|
class="bg-transparent outline-hidden dark:scheme-dark"
|
||||||
|
bind:value={endTime}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
<label class="flex items-center gap-1.5 cursor-pointer text-xs text-gray-400 ml-auto">
|
<label class="flex items-center gap-1.5 cursor-pointer text-xs text-gray-400 ml-auto">
|
||||||
<input type="checkbox" class="accent-blue-500" bind:checked={allDay} />
|
<input type="checkbox" class="accent-blue-500" bind:checked={allDay} />
|
||||||
|
|||||||
@@ -793,9 +793,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div
|
<div class="translate-y-[0.5px] flex min-w-0 flex-1 items-center gap-1.5 pr-6 text-start">
|
||||||
class="translate-y-[0.5px] flex min-w-0 flex-1 items-center gap-1.5 pr-6 text-start"
|
|
||||||
>
|
|
||||||
{#if edit}
|
{#if edit}
|
||||||
<input
|
<input
|
||||||
id="folder-{folderId}-input"
|
id="folder-{folderId}-input"
|
||||||
|
|||||||
@@ -309,7 +309,10 @@
|
|||||||
commitAccessGrants(next);
|
commitAccessGrants(next);
|
||||||
};
|
};
|
||||||
|
|
||||||
const togglePrincipalWrite = (principalType: 'user' | 'group' | 'anyone', principalId: string) => {
|
const togglePrincipalWrite = (
|
||||||
|
principalType: 'user' | 'group' | 'anyone',
|
||||||
|
principalId: string
|
||||||
|
) => {
|
||||||
let next = [...currentGrants()];
|
let next = [...currentGrants()];
|
||||||
const hasWrite = hasPrincipalGrant(principalType, principalId, 'write');
|
const hasWrite = hasPrincipalGrant(principalType, principalId, 'write');
|
||||||
if (hasWrite) {
|
if (hasWrite) {
|
||||||
|
|||||||
@@ -75,7 +75,10 @@ export const registerFolderRefreshHandler = (handler: FolderRefreshHandler) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const refreshFolderChatLists = async (folderId?: string | null, chat?: ChatListItem | null) => {
|
export const refreshFolderChatLists = async (
|
||||||
|
folderId?: string | null,
|
||||||
|
chat?: ChatListItem | null
|
||||||
|
) => {
|
||||||
await Promise.all([...folderRefreshHandlers].map((handler) => handler(folderId, chat)));
|
await Promise.all([...folderRefreshHandlers].map((handler) => handler(folderId, chat)));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user