refac
This commit is contained in:
1 parent
20647bd2d5
commit
57e60423b9
4 files changed
+349
-47
No files matched your search
@@ -2162,6 +2162,309 @@ DEFAULT_VIEW_FILE_MAX_CHARS = 10_000
|
|||||||
MAX_GREP_RESULTS = 50
|
MAX_GREP_RESULTS = 50
|
||||||
|
|
||||||
|
|
||||||
|
async def _get_accessible_chat_files(
|
||||||
|
files: Optional[list[dict]],
|
||||||
|
user: dict,
|
||||||
|
file_id: Optional[str] = None,
|
||||||
|
) -> list[tuple[dict, object]]:
|
||||||
|
from open_webui.models.files import Files
|
||||||
|
|
||||||
|
user_id = user.get('id')
|
||||||
|
user_role = user.get('role', 'user')
|
||||||
|
accessible = []
|
||||||
|
seen = set()
|
||||||
|
|
||||||
|
for item in files or []:
|
||||||
|
if not isinstance(item, dict) or item.get('type', 'file') != 'file':
|
||||||
|
continue
|
||||||
|
fid = item.get('id') or item.get('url') or ''
|
||||||
|
if (
|
||||||
|
not isinstance(fid, str)
|
||||||
|
or not fid
|
||||||
|
or fid in seen
|
||||||
|
or fid.startswith(('http://', 'https://', 'data:'))
|
||||||
|
or (file_id and fid != file_id)
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
normalized = {**item, 'id': fid, 'type': 'file'}
|
||||||
|
if 'name' not in normalized and item.get('filename'):
|
||||||
|
normalized['name'] = item.get('filename')
|
||||||
|
seen.add(fid)
|
||||||
|
|
||||||
|
file = await Files.get_file_by_id(fid)
|
||||||
|
if file and await _has_read_access_to_file(file, user_id, user_role):
|
||||||
|
accessible.append((normalized, file))
|
||||||
|
|
||||||
|
return accessible
|
||||||
|
|
||||||
|
|
||||||
|
def _grep_file_models(
|
||||||
|
files_to_search: list,
|
||||||
|
pattern: str,
|
||||||
|
case_insensitive: bool = False,
|
||||||
|
count_only: bool = False,
|
||||||
|
) -> str:
|
||||||
|
from open_webui.tools.knowledge_fs import build_matcher
|
||||||
|
|
||||||
|
matches, err = build_matcher(pattern, case_insensitive)
|
||||||
|
if err:
|
||||||
|
return json.dumps({'error': err})
|
||||||
|
|
||||||
|
results = []
|
||||||
|
total_matches = 0
|
||||||
|
counts = []
|
||||||
|
|
||||||
|
for file in files_to_search:
|
||||||
|
content = ''
|
||||||
|
if file.data:
|
||||||
|
content = file.data.get('content', '')
|
||||||
|
if not content:
|
||||||
|
continue
|
||||||
|
|
||||||
|
lines = content.split('\n')
|
||||||
|
file_matches = 0
|
||||||
|
|
||||||
|
for i, line in enumerate(lines, 1):
|
||||||
|
if matches(line):
|
||||||
|
file_matches += 1
|
||||||
|
total_matches += 1
|
||||||
|
if not count_only and len(results) < MAX_GREP_RESULTS:
|
||||||
|
results.append(f'{file.id} {file.filename}:{i}: {line}')
|
||||||
|
|
||||||
|
if file_matches > 0 and count_only:
|
||||||
|
counts.append(f'{file.id} {file.filename}: {file_matches}')
|
||||||
|
|
||||||
|
if count_only:
|
||||||
|
if not counts:
|
||||||
|
return f'No matches for "{pattern}"'
|
||||||
|
return '\n'.join(counts) + f'\n[{total_matches} total matches]'
|
||||||
|
|
||||||
|
if not results:
|
||||||
|
return f'No matches for "{pattern}"'
|
||||||
|
|
||||||
|
output = '\n'.join(results)
|
||||||
|
if total_matches > MAX_GREP_RESULTS:
|
||||||
|
output += f'\n[{MAX_GREP_RESULTS} of {total_matches} matches shown — use file_id to narrow]'
|
||||||
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
async def list_chat_files(
|
||||||
|
__request__: Request = None,
|
||||||
|
__user__: dict = None,
|
||||||
|
__files__: list[dict] = None,
|
||||||
|
) -> str:
|
||||||
|
"""
|
||||||
|
List files attached to the current chat.
|
||||||
|
|
||||||
|
:return: JSON with attached chat files containing id, filename, content type, size, and updated time when available
|
||||||
|
"""
|
||||||
|
if __request__ is None:
|
||||||
|
return json.dumps({'error': 'Request context not available'})
|
||||||
|
|
||||||
|
if not __user__:
|
||||||
|
return json.dumps({'error': 'User context not available'})
|
||||||
|
|
||||||
|
try:
|
||||||
|
files = []
|
||||||
|
for item, file in await _get_accessible_chat_files(__files__, __user__):
|
||||||
|
file_info = {
|
||||||
|
'id': file.id,
|
||||||
|
'filename': file.filename,
|
||||||
|
'name': item.get('name') or file.filename,
|
||||||
|
'type': item.get('type', 'file'),
|
||||||
|
'updated_at': file.updated_at,
|
||||||
|
}
|
||||||
|
content_type = item.get('content_type') or (file.meta or {}).get('content_type')
|
||||||
|
size = item.get('size') or (file.meta or {}).get('size')
|
||||||
|
if content_type:
|
||||||
|
file_info['content_type'] = content_type
|
||||||
|
if size:
|
||||||
|
file_info['size'] = size
|
||||||
|
files.append(file_info)
|
||||||
|
|
||||||
|
return json.dumps(files, ensure_ascii=False)
|
||||||
|
except Exception as e:
|
||||||
|
log.exception(f'list_chat_files error: {e}')
|
||||||
|
return json.dumps({'error': str(e)})
|
||||||
|
|
||||||
|
|
||||||
|
async def grep_chat_files(
|
||||||
|
pattern: str,
|
||||||
|
file_id: Optional[str] = None,
|
||||||
|
case_insensitive: bool = False,
|
||||||
|
count_only: bool = False,
|
||||||
|
__request__: Request = None,
|
||||||
|
__user__: dict = None,
|
||||||
|
__files__: list[dict] = None,
|
||||||
|
) -> str:
|
||||||
|
"""
|
||||||
|
Search exact text across files attached to the current chat.
|
||||||
|
Pass file_id from the attached_files block to search one file.
|
||||||
|
|
||||||
|
:param pattern: The text pattern to search for
|
||||||
|
:param file_id: Optional attached file ID to search within a single file
|
||||||
|
:param case_insensitive: If true, ignore case when matching
|
||||||
|
:param count_only: If true, return only match counts per file
|
||||||
|
:return: Matching lines with file IDs, filenames, and line numbers
|
||||||
|
"""
|
||||||
|
if __request__ is None:
|
||||||
|
return json.dumps({'error': 'Request context not available'})
|
||||||
|
|
||||||
|
if not __user__:
|
||||||
|
return json.dumps({'error': 'User context not available'})
|
||||||
|
|
||||||
|
if not pattern or not pattern.strip():
|
||||||
|
return json.dumps({'error': 'Pattern is required'})
|
||||||
|
|
||||||
|
if isinstance(file_id, str) and file_id.lower() in ('none', 'null', ''):
|
||||||
|
file_id = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
attached_ids = set()
|
||||||
|
for item in __files__ or []:
|
||||||
|
if not isinstance(item, dict) or item.get('type', 'file') != 'file':
|
||||||
|
continue
|
||||||
|
fid = item.get('id') or item.get('url')
|
||||||
|
if isinstance(fid, str) and fid and not fid.startswith(('http://', 'https://', 'data:')):
|
||||||
|
attached_ids.add(fid)
|
||||||
|
|
||||||
|
if not attached_ids:
|
||||||
|
return json.dumps({'error': 'No files are attached to this chat'})
|
||||||
|
if file_id and file_id not in attached_ids:
|
||||||
|
return json.dumps({'error': 'File not found'})
|
||||||
|
|
||||||
|
files_to_search = [file for _, file in await _get_accessible_chat_files(__files__, __user__, file_id)]
|
||||||
|
if not files_to_search:
|
||||||
|
return json.dumps({'error': 'No accessible files found'})
|
||||||
|
|
||||||
|
return _grep_file_models(files_to_search, pattern, case_insensitive, count_only)
|
||||||
|
except Exception as e:
|
||||||
|
log.exception(f'grep_chat_files error: {e}')
|
||||||
|
return json.dumps({'error': str(e)})
|
||||||
|
|
||||||
|
|
||||||
|
async def query_chat_files(
|
||||||
|
query: str,
|
||||||
|
file_id: Optional[str] = None,
|
||||||
|
count: Optional[int] = None,
|
||||||
|
__request__: Request = None,
|
||||||
|
__user__: dict = None,
|
||||||
|
__files__: list[dict] = None,
|
||||||
|
) -> str:
|
||||||
|
"""
|
||||||
|
Search files attached to the current chat using semantic/vector search.
|
||||||
|
Pass file_id from the attached_files block to search one file, or omit it to search all attached chat files.
|
||||||
|
|
||||||
|
:param query: The search query to find semantically relevant content
|
||||||
|
:param file_id: Optional attached file ID to search within a single file
|
||||||
|
:param count: Maximum number of results to return, capped by the server RAG top k
|
||||||
|
:return: JSON with relevant chunks containing content, source filename, and relevance score
|
||||||
|
"""
|
||||||
|
if __request__ is None:
|
||||||
|
return json.dumps({'error': 'Request context not available'})
|
||||||
|
|
||||||
|
if not __user__:
|
||||||
|
return json.dumps({'error': 'User context not available'})
|
||||||
|
|
||||||
|
if isinstance(file_id, str) and file_id.lower() in ('none', 'null', ''):
|
||||||
|
file_id = None
|
||||||
|
if isinstance(count, str):
|
||||||
|
if count.lower() in ('none', 'null', ''):
|
||||||
|
count = None
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
count = int(count)
|
||||||
|
except ValueError:
|
||||||
|
count = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
from open_webui.retrieval.utils import get_sources_from_items
|
||||||
|
|
||||||
|
attached_ids = set()
|
||||||
|
for item in __files__ or []:
|
||||||
|
if not isinstance(item, dict) or item.get('type', 'file') != 'file':
|
||||||
|
continue
|
||||||
|
fid = item.get('id') or item.get('url')
|
||||||
|
if isinstance(fid, str) and fid and not fid.startswith(('http://', 'https://', 'data:')):
|
||||||
|
attached_ids.add(fid)
|
||||||
|
|
||||||
|
if not attached_ids:
|
||||||
|
return json.dumps({'error': 'No files are attached to this chat'})
|
||||||
|
if file_id and file_id not in attached_ids:
|
||||||
|
return json.dumps({'error': 'File not found'})
|
||||||
|
|
||||||
|
accessible = await _get_accessible_chat_files(__files__, __user__, file_id)
|
||||||
|
if not accessible:
|
||||||
|
return json.dumps({'error': 'No accessible files found'})
|
||||||
|
|
||||||
|
file_items = [{**item} for item, _ in accessible]
|
||||||
|
rag_config = await Config.get_many(
|
||||||
|
'rag.top_k',
|
||||||
|
'rag.top_k_reranker',
|
||||||
|
'rag.relevance_threshold',
|
||||||
|
'rag.hybrid_bm25_weight',
|
||||||
|
'rag.enable_hybrid_search',
|
||||||
|
'rag.full_context',
|
||||||
|
)
|
||||||
|
top_k = rag_config.get('rag.top_k') or 5
|
||||||
|
count = top_k if count is None else max(1, min(count, top_k))
|
||||||
|
full_context = all(item.get('context') == 'full' for item in file_items) or rag_config.get('rag.full_context')
|
||||||
|
|
||||||
|
embedding_function = getattr(__request__.app.state, 'EMBEDDING_FUNCTION', None)
|
||||||
|
if not embedding_function and not full_context:
|
||||||
|
return json.dumps({'error': 'Embedding function not configured'})
|
||||||
|
|
||||||
|
user_model = UserModel.model_construct(
|
||||||
|
id=__user__.get('id'),
|
||||||
|
role=__user__.get('role', 'user'),
|
||||||
|
)
|
||||||
|
sources = await get_sources_from_items(
|
||||||
|
request=__request__,
|
||||||
|
items=file_items,
|
||||||
|
queries=[query],
|
||||||
|
embedding_function=(
|
||||||
|
lambda queries, prefix: embedding_function(queries, prefix=prefix, user=user_model)
|
||||||
|
if embedding_function
|
||||||
|
else None
|
||||||
|
),
|
||||||
|
k=count,
|
||||||
|
reranking_function=(
|
||||||
|
(lambda q, docs: __request__.app.state.RERANKING_FUNCTION(q, docs, user=user_model))
|
||||||
|
if getattr(__request__.app.state, 'RERANKING_FUNCTION', None)
|
||||||
|
else None
|
||||||
|
),
|
||||||
|
k_reranker=rag_config.get('rag.top_k_reranker'),
|
||||||
|
r=rag_config.get('rag.relevance_threshold'),
|
||||||
|
hybrid_bm25_weight=rag_config.get('rag.hybrid_bm25_weight'),
|
||||||
|
hybrid_search=rag_config.get('rag.enable_hybrid_search'),
|
||||||
|
full_context=full_context,
|
||||||
|
user=user_model,
|
||||||
|
)
|
||||||
|
|
||||||
|
chunks = []
|
||||||
|
for source in sources or []:
|
||||||
|
documents = source.get('document') or []
|
||||||
|
metadatas = source.get('metadata') or []
|
||||||
|
distances = source.get('distances') or []
|
||||||
|
source_info = source.get('source') or {}
|
||||||
|
|
||||||
|
for idx, doc in enumerate(documents):
|
||||||
|
metadata = metadatas[idx] if idx < len(metadatas) and isinstance(metadatas[idx], dict) else {}
|
||||||
|
chunk = {
|
||||||
|
'content': doc,
|
||||||
|
'source': metadata.get('source', metadata.get('name', source_info.get('name', 'Unknown'))),
|
||||||
|
'file_id': metadata.get('file_id', source_info.get('id', '')),
|
||||||
|
}
|
||||||
|
if idx < len(distances):
|
||||||
|
chunk['distance'] = distances[idx]
|
||||||
|
chunks.append(chunk)
|
||||||
|
|
||||||
|
return json.dumps(chunks[:count], ensure_ascii=False)
|
||||||
|
except Exception as e:
|
||||||
|
log.exception(f'query_chat_files error: {e}')
|
||||||
|
return json.dumps({'error': str(e)})
|
||||||
|
|
||||||
|
|
||||||
async def grep_knowledge_files(
|
async def grep_knowledge_files(
|
||||||
pattern: str,
|
pattern: str,
|
||||||
file_id: Optional[str] = None,
|
file_id: Optional[str] = None,
|
||||||
@@ -2195,16 +2498,11 @@ async def grep_knowledge_files(
|
|||||||
try:
|
try:
|
||||||
from open_webui.models.files import Files
|
from open_webui.models.files import Files
|
||||||
from open_webui.models.knowledge import Knowledges
|
from open_webui.models.knowledge import Knowledges
|
||||||
from open_webui.tools.knowledge_fs import build_matcher
|
|
||||||
|
|
||||||
user_id = __user__.get('id')
|
user_id = __user__.get('id')
|
||||||
user_role = __user__.get('role', 'user')
|
user_role = __user__.get('role', 'user')
|
||||||
user_group_ids = [group.id for group in await Groups.get_groups_by_member_id(user_id)]
|
user_group_ids = [group.id for group in await Groups.get_groups_by_member_id(user_id)]
|
||||||
|
|
||||||
_matches, err = build_matcher(pattern, case_insensitive)
|
|
||||||
if err:
|
|
||||||
return json.dumps({'error': err})
|
|
||||||
|
|
||||||
# Collect files to search
|
# Collect files to search
|
||||||
files_to_search = []
|
files_to_search = []
|
||||||
|
|
||||||
@@ -2280,43 +2578,7 @@ async def grep_knowledge_files(
|
|||||||
if not files_to_search:
|
if not files_to_search:
|
||||||
return json.dumps({'error': 'No accessible files found'})
|
return json.dumps({'error': 'No accessible files found'})
|
||||||
|
|
||||||
# Search
|
return _grep_file_models(files_to_search, pattern, case_insensitive, count_only)
|
||||||
results = []
|
|
||||||
total_matches = 0
|
|
||||||
counts = []
|
|
||||||
|
|
||||||
for file in files_to_search:
|
|
||||||
content = ''
|
|
||||||
if file.data:
|
|
||||||
content = file.data.get('content', '')
|
|
||||||
if not content:
|
|
||||||
continue
|
|
||||||
|
|
||||||
lines = content.split('\n')
|
|
||||||
file_matches = 0
|
|
||||||
|
|
||||||
for i, line in enumerate(lines, 1):
|
|
||||||
if _matches(line):
|
|
||||||
file_matches += 1
|
|
||||||
total_matches += 1
|
|
||||||
if not count_only and len(results) < MAX_GREP_RESULTS:
|
|
||||||
results.append(f'{file.id} {file.filename}:{i}: {line}')
|
|
||||||
|
|
||||||
if file_matches > 0 and count_only:
|
|
||||||
counts.append(f'{file.id} {file.filename}: {file_matches}')
|
|
||||||
|
|
||||||
if count_only:
|
|
||||||
if not counts:
|
|
||||||
return f'No matches for "{pattern}"'
|
|
||||||
return '\n'.join(counts) + f'\n[{total_matches} total matches]'
|
|
||||||
|
|
||||||
if not results:
|
|
||||||
return f'No matches for "{pattern}"'
|
|
||||||
|
|
||||||
output = '\n'.join(results)
|
|
||||||
if total_matches > MAX_GREP_RESULTS:
|
|
||||||
output += f'\n[{MAX_GREP_RESULTS} of {total_matches} matches shown — use file_id to narrow]'
|
|
||||||
return output
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.exception(f'grep_knowledge_files error: {e}')
|
log.exception(f'grep_knowledge_files error: {e}')
|
||||||
|
|||||||
@@ -278,9 +278,9 @@ def get_citation_source_from_tool_result(
|
|||||||
- document: list of document contents
|
- document: list of document contents
|
||||||
- metadata: list of metadata objects with source, file_id, name fields
|
- metadata: list of metadata objects with source, file_id, name fields
|
||||||
|
|
||||||
Returns a list of sources (usually one, but query_knowledge_files may return multiple).
|
Returns a list of sources (usually one, but query_knowledge_files/query_chat_files may return multiple).
|
||||||
"""
|
"""
|
||||||
_EXPECTS_LIST = {'search_web', 'query_knowledge_files'}
|
_EXPECTS_LIST = {'search_web', 'query_knowledge_files', 'query_chat_files'}
|
||||||
_EXPECTS_DICT = {'view_knowledge_file', 'view_file'}
|
_EXPECTS_DICT = {'view_knowledge_file', 'view_file'}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -369,7 +369,7 @@ def get_citation_source_from_tool_result(
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
elif tool_name == 'query_knowledge_files':
|
elif tool_name in ('query_knowledge_files', 'query_chat_files'):
|
||||||
chunks = tool_result
|
chunks = tool_result
|
||||||
|
|
||||||
# Group chunks by source for better citation display
|
# Group chunks by source for better citation display
|
||||||
@@ -1565,7 +1565,11 @@ async def add_file_context(messages: list, chat_id: str, user) -> list:
|
|||||||
stored_messages = get_message_list(history.get('messages', {}), history.get('currentId'))
|
stored_messages = get_message_list(history.get('messages', {}), history.get('currentId'))
|
||||||
|
|
||||||
def format_file_tag(file):
|
def format_file_tag(file):
|
||||||
attrs = f'type="{file.get("type", "file")}" url="{file["url"]}"'
|
file_id = file.get('id') or file.get('url')
|
||||||
|
attrs = f'type="{file.get("type", "file")}"'
|
||||||
|
if file_id:
|
||||||
|
attrs += f' id="{file_id}"'
|
||||||
|
attrs += f' url="{file["url"]}"'
|
||||||
if file.get('content_type'):
|
if file.get('content_type'):
|
||||||
attrs += f' content_type="{file["content_type"]}"'
|
attrs += f' content_type="{file["content_type"]}"'
|
||||||
if file.get('name'):
|
if file.get('name'):
|
||||||
@@ -4892,6 +4896,7 @@ async def streaming_chat_response_handler(response, ctx):
|
|||||||
'view_file',
|
'view_file',
|
||||||
'view_knowledge_file',
|
'view_knowledge_file',
|
||||||
'query_knowledge_files',
|
'query_knowledge_files',
|
||||||
|
'query_chat_files',
|
||||||
]
|
]
|
||||||
and tool_result
|
and tool_result
|
||||||
):
|
):
|
||||||
|
|||||||
@@ -62,14 +62,17 @@ from open_webui.tools.builtin import (
|
|||||||
fetch_url,
|
fetch_url,
|
||||||
generate_image,
|
generate_image,
|
||||||
get_current_timestamp,
|
get_current_timestamp,
|
||||||
|
grep_chat_files,
|
||||||
grep_knowledge_files,
|
grep_knowledge_files,
|
||||||
kb_exec,
|
kb_exec,
|
||||||
|
list_chat_files,
|
||||||
list_automations,
|
list_automations,
|
||||||
list_knowledge,
|
list_knowledge,
|
||||||
list_knowledge_bases,
|
list_knowledge_bases,
|
||||||
list_memories,
|
list_memories,
|
||||||
list_memory_paths,
|
list_memory_paths,
|
||||||
notify,
|
notify,
|
||||||
|
query_chat_files,
|
||||||
query_knowledge_bases,
|
query_knowledge_bases,
|
||||||
query_knowledge_files,
|
query_knowledge_files,
|
||||||
read_memory_path,
|
read_memory_path,
|
||||||
@@ -519,10 +522,38 @@ async def get_builtin_tools(
|
|||||||
await Config.get('user.permissions'),
|
await Config.get('user.permissions'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def has_user_chat_permission(permission_key: str) -> bool:
|
||||||
|
if user.get('role') == 'admin':
|
||||||
|
return True
|
||||||
|
return await has_permission(
|
||||||
|
user.get('id', ''),
|
||||||
|
f'chat.{permission_key}',
|
||||||
|
await Config.get('user.permissions'),
|
||||||
|
)
|
||||||
|
|
||||||
# Time utilities - available for date calculations
|
# Time utilities - available for date calculations
|
||||||
if is_builtin_tool_enabled('time'):
|
if is_builtin_tool_enabled('time'):
|
||||||
builtin_functions.extend([get_current_timestamp, calculate_timestamp])
|
builtin_functions.extend([get_current_timestamp, calculate_timestamp])
|
||||||
|
|
||||||
|
metadata = extra_params.get('__metadata__') or {}
|
||||||
|
chat_files = metadata.get('files') or extra_params.get('__files__') or []
|
||||||
|
has_chat_files = any(
|
||||||
|
isinstance(item, dict)
|
||||||
|
and item.get('type', 'file') == 'file'
|
||||||
|
and (item.get('id') or item.get('url'))
|
||||||
|
and not str(item.get('id') or item.get('url')).startswith(('http://', 'https://', 'data:'))
|
||||||
|
for item in chat_files
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
is_builtin_tool_enabled('files')
|
||||||
|
and get_model_capability('file_upload')
|
||||||
|
and not get_model_capability('file_context')
|
||||||
|
and has_chat_files
|
||||||
|
and await has_user_chat_permission('file_upload')
|
||||||
|
):
|
||||||
|
builtin_functions.extend([list_chat_files, query_chat_files, grep_chat_files, view_file])
|
||||||
|
|
||||||
# Knowledge base tools - conditional injection based on model knowledge
|
# Knowledge base tools - conditional injection based on model knowledge
|
||||||
# If model has attached knowledge (any type), only provide query_knowledge_files
|
# If model has attached knowledge (any type), only provide query_knowledge_files
|
||||||
# Otherwise, provide all KB browsing tools
|
# Otherwise, provide all KB browsing tools
|
||||||
@@ -640,7 +671,6 @@ async def get_builtin_tools(
|
|||||||
):
|
):
|
||||||
builtin_functions.append(execute_code)
|
builtin_functions.append(execute_code)
|
||||||
|
|
||||||
metadata = extra_params.get('__metadata__') or {}
|
|
||||||
chat_id = metadata.get('chat_id') or ''
|
chat_id = metadata.get('chat_id') or ''
|
||||||
chat = None
|
chat = None
|
||||||
if is_saved_chat_id(chat_id):
|
if is_saved_chat_id(chat_id):
|
||||||
@@ -709,6 +739,7 @@ async def get_builtin_tools(
|
|||||||
'__event_emitter__': extra_params.get('__event_emitter__'),
|
'__event_emitter__': extra_params.get('__event_emitter__'),
|
||||||
'__event_call__': extra_params.get('__event_call__'),
|
'__event_call__': extra_params.get('__event_call__'),
|
||||||
'__metadata__': extra_params.get('__metadata__'),
|
'__metadata__': extra_params.get('__metadata__'),
|
||||||
|
'__files__': chat_files,
|
||||||
'__chat_id__': extra_params.get('__chat_id__'),
|
'__chat_id__': extra_params.get('__chat_id__'),
|
||||||
'__message_id__': extra_params.get('__message_id__'),
|
'__message_id__': extra_params.get('__message_id__'),
|
||||||
'__model_knowledge__': model_knowledge,
|
'__model_knowledge__': model_knowledge,
|
||||||
|
|||||||
@@ -27,6 +27,10 @@
|
|||||||
label: $i18n.t('Knowledge Base'),
|
label: $i18n.t('Knowledge Base'),
|
||||||
description: $i18n.t('Browse and query knowledge bases')
|
description: $i18n.t('Browse and query knowledge bases')
|
||||||
},
|
},
|
||||||
|
files: {
|
||||||
|
label: $i18n.t('Files'),
|
||||||
|
description: $i18n.t('List, search, and read files attached to the current chat')
|
||||||
|
},
|
||||||
channels: {
|
channels: {
|
||||||
label: $i18n.t('Channels'),
|
label: $i18n.t('Channels'),
|
||||||
description: $i18n.t('Search channels and channel messages')
|
description: $i18n.t('Search channels and channel messages')
|
||||||
|
|||||||
Reference in new issue
Block a user