refac
This commit is contained in:
1 parent
5418ac921b
commit
cf887b68ea
5 files changed
+326
-9
No files matched your search
+139
@@ -0,0 +1,139 @@
|
|||||||
|
"""add current_message_id to chat
|
||||||
|
|
||||||
|
Revision ID: 9a1b2c3d4e5f
|
||||||
|
Revises: 856c5b02fb54
|
||||||
|
Create Date: 2026-07-23 00:00:00.000000
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
from typing import Sequence, Union
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
revision: str = '9a1b2c3d4e5f'
|
||||||
|
down_revision: Union[str, None] = '856c5b02fb54'
|
||||||
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
conn = op.get_bind()
|
||||||
|
columns = [col['name'] for col in sa.inspect(conn).get_columns('chat')]
|
||||||
|
if 'current_message_id' not in columns:
|
||||||
|
op.add_column('chat', sa.Column('current_message_id', sa.Text(), nullable=True))
|
||||||
|
|
||||||
|
chat = sa.table(
|
||||||
|
'chat',
|
||||||
|
sa.column('id', sa.String()),
|
||||||
|
sa.column('chat', sa.Text()),
|
||||||
|
sa.column('current_message_id', sa.Text()),
|
||||||
|
)
|
||||||
|
chat_message = sa.table(
|
||||||
|
'chat_message',
|
||||||
|
sa.column('id', sa.Text()),
|
||||||
|
sa.column('chat_id', sa.Text()),
|
||||||
|
sa.column('parent_id', sa.Text()),
|
||||||
|
sa.column('created_at', sa.BigInteger()),
|
||||||
|
)
|
||||||
|
|
||||||
|
messages_by_chat: dict[str, dict[str, dict]] = {}
|
||||||
|
for row in conn.execute(
|
||||||
|
sa.select(
|
||||||
|
chat_message.c.chat_id,
|
||||||
|
chat_message.c.id,
|
||||||
|
chat_message.c.parent_id,
|
||||||
|
chat_message.c.created_at,
|
||||||
|
)
|
||||||
|
):
|
||||||
|
values = row._mapping
|
||||||
|
chat_id = values['chat_id']
|
||||||
|
prefix = f'{chat_id}-'
|
||||||
|
message_id = values['id']
|
||||||
|
if message_id and message_id.startswith(prefix):
|
||||||
|
message_id = message_id[len(prefix) :]
|
||||||
|
if not message_id:
|
||||||
|
continue
|
||||||
|
parent_id = values['parent_id']
|
||||||
|
if parent_id and parent_id.startswith(prefix):
|
||||||
|
parent_id = parent_id[len(prefix) :]
|
||||||
|
messages_by_chat.setdefault(chat_id, {})[message_id] = {
|
||||||
|
'parent_id': parent_id,
|
||||||
|
'created_at': values['created_at'] or 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
for row in conn.execute(sa.select(chat.c.id, chat.c.chat, chat.c.current_message_id)):
|
||||||
|
values = row._mapping
|
||||||
|
chat_id = values['id']
|
||||||
|
prefix = f'{chat_id}-'
|
||||||
|
chat_messages = messages_by_chat.get(chat_id, {})
|
||||||
|
|
||||||
|
chat_data = {}
|
||||||
|
if isinstance(values['chat'], dict):
|
||||||
|
chat_data = values['chat']
|
||||||
|
elif isinstance(values['chat'], str):
|
||||||
|
try:
|
||||||
|
parsed = json.loads(values['chat'])
|
||||||
|
chat_data = parsed if isinstance(parsed, dict) else {}
|
||||||
|
except (TypeError, ValueError, json.JSONDecodeError):
|
||||||
|
chat_data = {}
|
||||||
|
|
||||||
|
history = chat_data.get('history') if isinstance(chat_data.get('history'), dict) else {}
|
||||||
|
messages = history.get('messages') if isinstance(history.get('messages'), dict) else {}
|
||||||
|
if not messages and isinstance(chat_data.get('messages'), list):
|
||||||
|
messages = {
|
||||||
|
message['id']: message
|
||||||
|
for message in chat_data['messages']
|
||||||
|
if isinstance(message, dict) and message.get('id')
|
||||||
|
}
|
||||||
|
json_messages = {
|
||||||
|
message_id: {
|
||||||
|
'parent_id': message.get('parentId') if isinstance(message, dict) else None,
|
||||||
|
'created_at': message.get('timestamp', 0) if isinstance(message, dict) else 0,
|
||||||
|
}
|
||||||
|
for message_id, message in messages.items()
|
||||||
|
}
|
||||||
|
available_messages = chat_messages or json_messages
|
||||||
|
candidates = [
|
||||||
|
values['current_message_id'],
|
||||||
|
history.get('currentId'),
|
||||||
|
chat_data.get('currentId'),
|
||||||
|
chat_data.get('branchPointMessageId'),
|
||||||
|
]
|
||||||
|
|
||||||
|
current_message_id = next(
|
||||||
|
(
|
||||||
|
candidate[len(prefix) :] if candidate.startswith(prefix) else candidate
|
||||||
|
for candidate in candidates
|
||||||
|
if candidate
|
||||||
|
and (
|
||||||
|
not available_messages
|
||||||
|
or (candidate[len(prefix) :] if candidate.startswith(prefix) else candidate) in available_messages
|
||||||
|
)
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not current_message_id and available_messages:
|
||||||
|
parent_ids = {
|
||||||
|
message['parent_id']
|
||||||
|
for message in available_messages.values()
|
||||||
|
if message.get('parent_id') in available_messages
|
||||||
|
}
|
||||||
|
leaf_ids = [message_id for message_id in available_messages if message_id not in parent_ids]
|
||||||
|
current_message_id = max(
|
||||||
|
leaf_ids or list(available_messages),
|
||||||
|
key=lambda message_id: available_messages[message_id].get('created_at') or 0,
|
||||||
|
)
|
||||||
|
|
||||||
|
if current_message_id and current_message_id != values['current_message_id']:
|
||||||
|
conn.execute(
|
||||||
|
sa.update(chat)
|
||||||
|
.where(chat.c.id == chat_id)
|
||||||
|
.values(current_message_id=current_message_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
op.drop_column('chat', 'current_message_id')
|
||||||
@@ -62,6 +62,7 @@ class Chat(Base): # database table mapping for chat entity
|
|||||||
|
|
||||||
tasks = Column(JSON, nullable=True)
|
tasks = Column(JSON, nullable=True)
|
||||||
summary = Column(Text, nullable=True)
|
summary = Column(Text, nullable=True)
|
||||||
|
current_message_id = Column(Text, nullable=True)
|
||||||
|
|
||||||
last_read_at = Column(BigInteger, nullable=True)
|
last_read_at = Column(BigInteger, nullable=True)
|
||||||
|
|
||||||
@@ -98,6 +99,7 @@ class ChatModel(BaseModel):
|
|||||||
|
|
||||||
tasks: list | None = None
|
tasks: list | None = None
|
||||||
summary: str | None = None
|
summary: str | None = None
|
||||||
|
current_message_id: str | None = None
|
||||||
|
|
||||||
last_read_at: int | None = None
|
last_read_at: int | None = None
|
||||||
|
|
||||||
@@ -145,6 +147,7 @@ class ChatForm(BaseModel):
|
|||||||
class ChatImportForm(ChatForm):
|
class ChatImportForm(ChatForm):
|
||||||
meta: dict | None = {}
|
meta: dict | None = {}
|
||||||
pinned: bool | None = False
|
pinned: bool | None = False
|
||||||
|
current_message_id: str | None = None
|
||||||
created_at: int | None = None
|
created_at: int | None = None
|
||||||
updated_at: int | None = None
|
updated_at: int | None = None
|
||||||
|
|
||||||
@@ -177,6 +180,7 @@ class ChatResponse(BaseModel):
|
|||||||
|
|
||||||
tasks: list | None = None
|
tasks: list | None = None
|
||||||
summary: str | None = None
|
summary: str | None = None
|
||||||
|
current_message_id: str | None = None
|
||||||
context_usage: dict | None = None
|
context_usage: dict | None = None
|
||||||
|
|
||||||
|
|
||||||
@@ -280,6 +284,21 @@ class ChatTable:
|
|||||||
"""Recursively remove null bytes from strings in dict/list structures."""
|
"""Recursively remove null bytes from strings in dict/list structures."""
|
||||||
return sanitize_data_for_db(obj)
|
return sanitize_data_for_db(obj)
|
||||||
|
|
||||||
|
def get_current_message_id(self, chat: dict | None) -> str | None:
|
||||||
|
chat = chat or {}
|
||||||
|
history = chat.get('history') if isinstance(chat.get('history'), dict) else {}
|
||||||
|
current_id = history.get('currentId') or chat.get('currentId') or chat.get('branchPointMessageId')
|
||||||
|
if current_id:
|
||||||
|
return current_id
|
||||||
|
|
||||||
|
messages = chat.get('messages')
|
||||||
|
if isinstance(messages, list):
|
||||||
|
for message in reversed(messages):
|
||||||
|
if isinstance(message, dict) and message.get('id'):
|
||||||
|
return message['id']
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
def _sanitize_chat_row(self, chat_item):
|
def _sanitize_chat_row(self, chat_item):
|
||||||
"""
|
"""
|
||||||
Clean a Chat SQLAlchemy model's title + chat JSON,
|
Clean a Chat SQLAlchemy model's title + chat JSON,
|
||||||
@@ -375,6 +394,7 @@ class ChatTable:
|
|||||||
'chat': self._clean_null_bytes(form_data.chat),
|
'chat': self._clean_null_bytes(form_data.chat),
|
||||||
'folder_id': form_data.folder_id,
|
'folder_id': form_data.folder_id,
|
||||||
'meta': internal_meta or {},
|
'meta': internal_meta or {},
|
||||||
|
'current_message_id': self.get_current_message_id(form_data.chat),
|
||||||
'created_at': int(time.time()),
|
'created_at': int(time.time()),
|
||||||
'updated_at': int(time.time()),
|
'updated_at': int(time.time()),
|
||||||
'last_read_at': int(time.time()),
|
'last_read_at': int(time.time()),
|
||||||
@@ -388,8 +408,14 @@ class ChatTable:
|
|||||||
|
|
||||||
# Dual-write initial messages to chat_message table
|
# Dual-write initial messages to chat_message table
|
||||||
try:
|
try:
|
||||||
history = form_data.chat.get('history', {})
|
history = form_data.chat.get('history') if isinstance(form_data.chat.get('history'), dict) else {}
|
||||||
messages = history.get('messages', {})
|
messages = history.get('messages') if isinstance(history.get('messages'), dict) else {}
|
||||||
|
if not messages and isinstance(form_data.chat.get('messages'), list):
|
||||||
|
messages = {
|
||||||
|
message.get('id'): message
|
||||||
|
for message in form_data.chat['messages']
|
||||||
|
if isinstance(message, dict) and message.get('id')
|
||||||
|
}
|
||||||
for message_id, message in messages.items():
|
for message_id, message in messages.items():
|
||||||
if isinstance(message, dict) and message.get('role'):
|
if isinstance(message, dict) and message.get('role'):
|
||||||
await ChatMessages.upsert_message(
|
await ChatMessages.upsert_message(
|
||||||
@@ -458,6 +484,7 @@ class ChatTable:
|
|||||||
'meta': form_data.meta,
|
'meta': form_data.meta,
|
||||||
'pinned': form_data.pinned,
|
'pinned': form_data.pinned,
|
||||||
'folder_id': form_data.folder_id,
|
'folder_id': form_data.folder_id,
|
||||||
|
'current_message_id': form_data.current_message_id or self.get_current_message_id(form_data.chat),
|
||||||
'created_at': (form_data.created_at if form_data.created_at else int(time.time())),
|
'created_at': (form_data.created_at if form_data.created_at else int(time.time())),
|
||||||
'updated_at': (form_data.updated_at if form_data.updated_at else int(time.time())),
|
'updated_at': (form_data.updated_at if form_data.updated_at else int(time.time())),
|
||||||
}
|
}
|
||||||
@@ -497,8 +524,14 @@ class ChatTable:
|
|||||||
|
|
||||||
# Dual-write messages to chat_message table
|
# Dual-write messages to chat_message table
|
||||||
for form_data, chat_obj in zip(chat_import_forms, chats):
|
for form_data, chat_obj in zip(chat_import_forms, chats):
|
||||||
history = form_data.chat.get('history', {})
|
history = form_data.chat.get('history') if isinstance(form_data.chat.get('history'), dict) else {}
|
||||||
messages = history.get('messages', {})
|
messages = history.get('messages') if isinstance(history.get('messages'), dict) else {}
|
||||||
|
if not messages and isinstance(form_data.chat.get('messages'), list):
|
||||||
|
messages = {
|
||||||
|
message.get('id'): message
|
||||||
|
for message in form_data.chat['messages']
|
||||||
|
if isinstance(message, dict) and message.get('id')
|
||||||
|
}
|
||||||
for message_id, message in messages.items():
|
for message_id, message in messages.items():
|
||||||
if isinstance(message, dict) and message.get('role'):
|
if isinstance(message, dict) and message.get('role'):
|
||||||
try:
|
try:
|
||||||
@@ -530,6 +563,8 @@ class ChatTable:
|
|||||||
|
|
||||||
chat_item.chat = self._clean_null_bytes(chat)
|
chat_item.chat = self._clean_null_bytes(chat)
|
||||||
chat_item.title = self._clean_null_bytes(chat['title']) if 'title' in chat else 'New Chat'
|
chat_item.title = self._clean_null_bytes(chat['title']) if 'title' in chat else 'New Chat'
|
||||||
|
if any(key in chat for key in ('history', 'messages', 'currentId', 'branchPointMessageId')):
|
||||||
|
chat_item.current_message_id = self.get_current_message_id(chat)
|
||||||
|
|
||||||
if touch:
|
if touch:
|
||||||
chat_item.updated_at = int(time.time())
|
chat_item.updated_at = int(time.time())
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ from open_webui.tasks import has_active_tasks, stop_item_tasks
|
|||||||
from open_webui.utils.access_control import filter_allowed_access_grants, has_permission
|
from open_webui.utils.access_control import filter_allowed_access_grants, has_permission
|
||||||
from open_webui.utils.access_control.folders import has_folder_access
|
from open_webui.utils.access_control.folders import has_folder_access
|
||||||
from open_webui.utils.auth import get_admin_user, get_verified_user
|
from open_webui.utils.auth import get_admin_user, get_verified_user
|
||||||
|
from open_webui.utils.chat_fork import build_fork_history
|
||||||
from open_webui.utils.context_compaction import compact_chat_branch, get_chat_context_usage
|
from open_webui.utils.context_compaction import compact_chat_branch, get_chat_context_usage
|
||||||
from open_webui.utils.misc import get_message_list
|
from open_webui.utils.misc import get_message_list
|
||||||
from open_webui.utils.models import get_all_models
|
from open_webui.utils.models import get_all_models
|
||||||
@@ -1167,7 +1168,8 @@ async def compact_chat_by_id(
|
|||||||
|
|
||||||
history = (chat.chat or {}).get('history') or {}
|
history = (chat.chat or {}).get('history') or {}
|
||||||
messages_map = await Chats.get_messages_map_by_chat_id(id)
|
messages_map = await Chats.get_messages_map_by_chat_id(id)
|
||||||
message_list = get_message_list(messages_map or history.get('messages') or {}, history.get('currentId'))
|
current_message_id = chat.current_message_id or history.get('currentId')
|
||||||
|
message_list = get_message_list(messages_map or history.get('messages') or {}, current_message_id)
|
||||||
model_id = (form_data.model if form_data else None) or next(
|
model_id = (form_data.model if form_data else None) or next(
|
||||||
(message.get('model') for message in reversed(message_list) if message.get('model')),
|
(message.get('model') for message in reversed(message_list) if message.get('model')),
|
||||||
None,
|
None,
|
||||||
@@ -1564,6 +1566,96 @@ class CloneForm(BaseModel):
|
|||||||
title: str | None = None
|
title: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class ForkForm(BaseModel):
|
||||||
|
message_id: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
@router.post('/{id}/fork', response_model=ChatResponse | None)
|
||||||
|
async def fork_chat_by_id(
|
||||||
|
request: Request,
|
||||||
|
id: str,
|
||||||
|
form_data: ForkForm | None = None,
|
||||||
|
user=Depends(get_verified_user),
|
||||||
|
db: AsyncSession = Depends(get_async_session),
|
||||||
|
):
|
||||||
|
await require_chat_import_permission(request, user, db)
|
||||||
|
|
||||||
|
chat = await Chats.get_chat_by_id_and_user_id(id, user.id, db=db)
|
||||||
|
if not chat:
|
||||||
|
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.DEFAULT())
|
||||||
|
|
||||||
|
if await has_active_tasks(request.app.state.redis, id):
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_409_CONFLICT,
|
||||||
|
detail='Wait for the current response to finish before forking.',
|
||||||
|
)
|
||||||
|
|
||||||
|
history = (chat.chat or {}).get('history') or {}
|
||||||
|
messages_map = await Chats.get_messages_map_by_chat_id(id) or history.get('messages') or {}
|
||||||
|
if any(
|
||||||
|
message.get('role') == 'assistant' and message.get('done') is False
|
||||||
|
for message in messages_map.values()
|
||||||
|
if isinstance(message, dict)
|
||||||
|
):
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_409_CONFLICT,
|
||||||
|
detail='Wait for the current response to finish before forking.',
|
||||||
|
)
|
||||||
|
|
||||||
|
source_message_id = (form_data.message_id if form_data else None) or chat.current_message_id or history.get('currentId')
|
||||||
|
if not source_message_id:
|
||||||
|
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='chat has no messages to fork')
|
||||||
|
|
||||||
|
try:
|
||||||
|
fork_history, fork_messages = build_fork_history(messages_map, source_message_id)
|
||||||
|
except ValueError as exc:
|
||||||
|
detail = str(exc)
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_404_NOT_FOUND if detail == 'message not found' else status.HTTP_400_BAD_REQUEST,
|
||||||
|
detail=detail,
|
||||||
|
) from exc
|
||||||
|
|
||||||
|
updated_chat = {**(chat.chat or {})}
|
||||||
|
updated_chat.pop('currentId', None)
|
||||||
|
updated_chat.update(
|
||||||
|
{
|
||||||
|
'originalChatId': chat.id,
|
||||||
|
'branchPointMessageId': source_message_id,
|
||||||
|
'title': f'{chat.title} (fork)',
|
||||||
|
'history': fork_history,
|
||||||
|
'messages': fork_messages,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
meta = {
|
||||||
|
**(chat.meta or {}),
|
||||||
|
'forked_from': chat.id,
|
||||||
|
'forked_from_message_id': source_message_id,
|
||||||
|
}
|
||||||
|
|
||||||
|
fork = await Chats.insert_new_chat(
|
||||||
|
str(uuid4()),
|
||||||
|
user.id,
|
||||||
|
ChatForm(chat=updated_chat, folder_id=chat.folder_id),
|
||||||
|
db=db,
|
||||||
|
internal_meta=meta,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not fork:
|
||||||
|
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=ERROR_MESSAGES.DEFAULT())
|
||||||
|
|
||||||
|
if chat.pinned:
|
||||||
|
fork = await Chats.toggle_chat_pinned_by_id(fork.id, db=db) or fork
|
||||||
|
|
||||||
|
await publish_event(
|
||||||
|
request,
|
||||||
|
EVENTS.CHAT_CLONED,
|
||||||
|
actor=user,
|
||||||
|
subject_id=fork.id,
|
||||||
|
data={'original_chat_id': id, 'forked_from_message_id': source_message_id},
|
||||||
|
)
|
||||||
|
return ChatResponse(**fork.model_dump())
|
||||||
|
|
||||||
|
|
||||||
@router.post('/{id}/clone', response_model=ChatResponse | None)
|
@router.post('/{id}/clone', response_model=ChatResponse | None)
|
||||||
async def clone_chat_by_id(
|
async def clone_chat_by_id(
|
||||||
request: Request,
|
request: Request,
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
|
||||||
|
def build_fork_history(messages_map: dict, source_message_id: str) -> tuple[dict, list[dict]]:
|
||||||
|
if not messages_map:
|
||||||
|
raise ValueError('chat has no messages to fork')
|
||||||
|
|
||||||
|
branch: list[tuple[str, dict]] = []
|
||||||
|
seen: set[str] = set()
|
||||||
|
message_id = source_message_id
|
||||||
|
|
||||||
|
while message_id:
|
||||||
|
if message_id in seen:
|
||||||
|
raise ValueError('message branch contains a cycle')
|
||||||
|
seen.add(message_id)
|
||||||
|
|
||||||
|
message = messages_map.get(message_id)
|
||||||
|
if not isinstance(message, dict):
|
||||||
|
raise ValueError('message not found')
|
||||||
|
|
||||||
|
branch.append((message_id, message))
|
||||||
|
message_id = message.get('parentId')
|
||||||
|
|
||||||
|
fork_messages: dict[str, dict] = {}
|
||||||
|
ordered_messages: list[dict] = []
|
||||||
|
parent_id = None
|
||||||
|
|
||||||
|
for message_id, message in reversed(branch):
|
||||||
|
copied = deepcopy(message)
|
||||||
|
copied['id'] = message_id
|
||||||
|
copied['parentId'] = parent_id
|
||||||
|
copied['childrenIds'] = []
|
||||||
|
|
||||||
|
if parent_id:
|
||||||
|
fork_messages[parent_id]['childrenIds'] = [message_id]
|
||||||
|
|
||||||
|
fork_messages[message_id] = copied
|
||||||
|
ordered_messages.append(copied)
|
||||||
|
parent_id = message_id
|
||||||
|
|
||||||
|
return {'messages': fork_messages, 'currentId': source_message_id}, ordered_messages
|
||||||
@@ -148,8 +148,13 @@ async def compact_chat_branch(request, user, chat: Any, model_id: str, models: d
|
|||||||
if not config['enable']:
|
if not config['enable']:
|
||||||
return {'ok': True, 'compacted': False, 'reason': 'disabled'}
|
return {'ok': True, 'compacted': False, 'reason': 'disabled'}
|
||||||
|
|
||||||
history = (chat.chat or {}).get('history') or {}
|
chat_data = chat.chat or {}
|
||||||
current_id = history.get('currentId')
|
history = chat_data.get('history') or {}
|
||||||
|
current_id = getattr(chat, 'current_message_id', None) or history.get('currentId')
|
||||||
|
if not current_id:
|
||||||
|
current_id = chat_data.get('currentId') or chat_data.get('branchPointMessageId')
|
||||||
|
if not current_id and isinstance(chat_data.get('messages'), list) and chat_data['messages']:
|
||||||
|
current_id = chat_data['messages'][-1].get('id')
|
||||||
if not current_id:
|
if not current_id:
|
||||||
return {'ok': True, 'compacted': False, 'reason': 'empty'}
|
return {'ok': True, 'compacted': False, 'reason': 'empty'}
|
||||||
|
|
||||||
@@ -216,8 +221,13 @@ def _resolve_token_threshold(global_threshold: int, global_cap: int, metadata: d
|
|||||||
|
|
||||||
|
|
||||||
async def get_chat_context_usage(chat: Any, model_id: str | None = None) -> dict | None:
|
async def get_chat_context_usage(chat: Any, model_id: str | None = None) -> dict | None:
|
||||||
history = (chat.chat or {}).get('history') or {}
|
chat_data = chat.chat or {}
|
||||||
current_id = history.get('currentId')
|
history = chat_data.get('history') or {}
|
||||||
|
current_id = getattr(chat, 'current_message_id', None) or history.get('currentId')
|
||||||
|
if not current_id:
|
||||||
|
current_id = chat_data.get('currentId') or chat_data.get('branchPointMessageId')
|
||||||
|
if not current_id and isinstance(chat_data.get('messages'), list) and chat_data['messages']:
|
||||||
|
current_id = chat_data['messages'][-1].get('id')
|
||||||
if not current_id:
|
if not current_id:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user