chore: format
This commit is contained in:
@@ -228,12 +228,7 @@ class FunctionsTable:
|
||||
|
||||
def get_function_list(self, db: Optional[Session] = None) -> list[FunctionUserResponse]:
|
||||
with get_db_context(db) as db:
|
||||
functions = (
|
||||
db.query(Function)
|
||||
.options(defer(Function.content))
|
||||
.order_by(Function.updated_at.desc())
|
||||
.all()
|
||||
)
|
||||
functions = db.query(Function).options(defer(Function.content)).order_by(Function.updated_at.desc()).all()
|
||||
user_ids = list(set(func.user_id for func in functions))
|
||||
|
||||
users = Users.get_users_by_user_ids(user_ids, db=db) if user_ids else []
|
||||
|
||||
@@ -582,9 +582,7 @@ async def signin(
|
||||
if user.role != trusted_role:
|
||||
Users.update_user_role_by_id(user.id, trusted_role, db=db)
|
||||
elif trusted_role:
|
||||
log.warning(
|
||||
f'Ignoring invalid trusted role header value: {trusted_role}'
|
||||
)
|
||||
log.warning(f'Ignoring invalid trusted role header value: {trusted_role}')
|
||||
|
||||
elif WEBUI_AUTH == False:
|
||||
admin_email = 'admin@localhost'
|
||||
|
||||
@@ -1096,7 +1096,7 @@ async def export_knowledge_by_id(id: str, user=Depends(get_admin_user), db: Sess
|
||||
|
||||
# Use RFC 5987 filename* for non-ASCII names so the browser gets the real name
|
||||
quoted_name = quote(f'{knowledge.name}.zip')
|
||||
content_disposition = f"attachment; filename=\"{zip_filename}\"; filename*=UTF-8''{quoted_name}"
|
||||
content_disposition = f'attachment; filename="{zip_filename}"; filename*=UTF-8\'\'{quoted_name}'
|
||||
|
||||
return StreamingResponse(
|
||||
zip_buffer,
|
||||
|
||||
@@ -839,32 +839,41 @@ def convert_to_responses_payload(payload: dict) -> dict:
|
||||
if role == 'assistant' and msg.get('tool_calls'):
|
||||
# Add text content as message if present
|
||||
if content:
|
||||
text = content if isinstance(content, str) else '\n'.join(
|
||||
p.get('text', '') for p in content if p.get('type') == 'text'
|
||||
text = (
|
||||
content
|
||||
if isinstance(content, str)
|
||||
else '\n'.join(p.get('text', '') for p in content if p.get('type') == 'text')
|
||||
)
|
||||
if text.strip():
|
||||
input_items.append({
|
||||
'type': 'message', 'role': 'assistant',
|
||||
'content': [{'type': 'output_text', 'text': text}],
|
||||
})
|
||||
input_items.append(
|
||||
{
|
||||
'type': 'message',
|
||||
'role': 'assistant',
|
||||
'content': [{'type': 'output_text', 'text': text}],
|
||||
}
|
||||
)
|
||||
# Convert each tool_call to a function_call input item
|
||||
for tool_call in msg['tool_calls']:
|
||||
func = tool_call.get('function', {})
|
||||
input_items.append({
|
||||
'type': 'function_call',
|
||||
'call_id': tool_call.get('id', ''),
|
||||
'name': func.get('name', ''),
|
||||
'arguments': func.get('arguments', '{}'),
|
||||
})
|
||||
input_items.append(
|
||||
{
|
||||
'type': 'function_call',
|
||||
'call_id': tool_call.get('id', ''),
|
||||
'name': func.get('name', ''),
|
||||
'arguments': func.get('arguments', '{}'),
|
||||
}
|
||||
)
|
||||
continue
|
||||
|
||||
# Handle tool result messages
|
||||
if role == 'tool':
|
||||
input_items.append({
|
||||
'type': 'function_call_output',
|
||||
'call_id': msg.get('tool_call_id', ''),
|
||||
'output': msg.get('content', ''),
|
||||
})
|
||||
input_items.append(
|
||||
{
|
||||
'type': 'function_call_output',
|
||||
'call_id': msg.get('tool_call_id', ''),
|
||||
'output': msg.get('content', ''),
|
||||
}
|
||||
)
|
||||
continue
|
||||
|
||||
# Convert content format
|
||||
@@ -1132,8 +1141,7 @@ async def generate_chat_completion(
|
||||
for message in payload['messages']:
|
||||
if message.get('role') == 'tool' and isinstance(message.get('content'), list):
|
||||
message['content'] = ''.join(
|
||||
part.get('text', '') for part in message['content']
|
||||
if part.get('type') in ('input_text', 'text')
|
||||
part.get('text', '') for part in message['content'] if part.get('type') in ('input_text', 'text')
|
||||
)
|
||||
|
||||
payload = json.dumps(payload)
|
||||
|
||||
@@ -1604,13 +1604,15 @@ async def search_knowledge_files(
|
||||
)
|
||||
|
||||
for file in result.items:
|
||||
all_files.append({
|
||||
'id': file.id,
|
||||
'filename': file.filename,
|
||||
'knowledge_id': knowledge.id,
|
||||
'knowledge_name': knowledge.name,
|
||||
'updated_at': file.updated_at,
|
||||
})
|
||||
all_files.append(
|
||||
{
|
||||
'id': file.id,
|
||||
'filename': file.filename,
|
||||
'knowledge_id': knowledge.id,
|
||||
'knowledge_name': knowledge.name,
|
||||
'updated_at': file.updated_at,
|
||||
}
|
||||
)
|
||||
|
||||
# Search within directly attached files (filename match)
|
||||
if not knowledge_id and attached_file_ids:
|
||||
@@ -1618,14 +1620,16 @@ async def search_knowledge_files(
|
||||
for file_id in attached_file_ids:
|
||||
file = Files.get_file_by_id(file_id)
|
||||
if file and (not query_lower or query_lower in file.filename.lower()):
|
||||
all_files.append({
|
||||
'id': file.id,
|
||||
'filename': file.filename,
|
||||
'updated_at': file.updated_at,
|
||||
})
|
||||
all_files.append(
|
||||
{
|
||||
'id': file.id,
|
||||
'filename': file.filename,
|
||||
'updated_at': file.updated_at,
|
||||
}
|
||||
)
|
||||
|
||||
# Apply pagination across combined results
|
||||
all_files = all_files[skip:skip + count]
|
||||
all_files = all_files[skip : skip + count]
|
||||
return json.dumps(all_files, ensure_ascii=False)
|
||||
|
||||
# No attached knowledge - search all accessible KBs
|
||||
@@ -1739,7 +1743,7 @@ async def view_file(
|
||||
content = file.data.get('content', '')
|
||||
|
||||
total_chars = len(content)
|
||||
sliced = content[offset:offset + max_chars]
|
||||
sliced = content[offset : offset + max_chars]
|
||||
is_truncated = (offset + len(sliced)) < total_chars
|
||||
|
||||
result = {
|
||||
@@ -1844,7 +1848,7 @@ async def view_knowledge_file(
|
||||
content = file.data.get('content', '')
|
||||
|
||||
total_chars = len(content)
|
||||
sliced = content[offset:offset + max_chars]
|
||||
sliced = content[offset : offset + max_chars]
|
||||
is_truncated = (offset + len(sliced)) < total_chars
|
||||
|
||||
result = {
|
||||
@@ -1935,21 +1939,20 @@ async def list_knowledge(
|
||||
|
||||
# Include file listing for each KB
|
||||
if kb_files:
|
||||
kb_entry['files'] = [
|
||||
{'id': f.id, 'filename': f.filename}
|
||||
for f in kb_files
|
||||
]
|
||||
kb_entry['files'] = [{'id': f.id, 'filename': f.filename} for f in kb_files]
|
||||
|
||||
knowledge_bases.append(kb_entry)
|
||||
|
||||
elif item_type == 'file':
|
||||
file = Files.get_file_by_id(item_id)
|
||||
if file:
|
||||
files.append({
|
||||
'id': file.id,
|
||||
'filename': file.filename,
|
||||
'updated_at': file.updated_at,
|
||||
})
|
||||
files.append(
|
||||
{
|
||||
'id': file.id,
|
||||
'filename': file.filename,
|
||||
'updated_at': file.updated_at,
|
||||
}
|
||||
)
|
||||
|
||||
elif item_type == 'note':
|
||||
note = Notes.get_note_by_id(item_id)
|
||||
@@ -1963,16 +1966,21 @@ async def list_knowledge(
|
||||
permission='read',
|
||||
)
|
||||
):
|
||||
notes.append({
|
||||
'id': note.id,
|
||||
'title': note.title,
|
||||
})
|
||||
notes.append(
|
||||
{
|
||||
'id': note.id,
|
||||
'title': note.title,
|
||||
}
|
||||
)
|
||||
|
||||
return json.dumps({
|
||||
'knowledge_bases': knowledge_bases,
|
||||
'files': files,
|
||||
'notes': notes,
|
||||
}, ensure_ascii=False)
|
||||
return json.dumps(
|
||||
{
|
||||
'knowledge_bases': knowledge_bases,
|
||||
'files': files,
|
||||
'notes': notes,
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
except Exception as e:
|
||||
log.exception(f'list_knowledge error: {e}')
|
||||
return json.dumps({'error': str(e)})
|
||||
|
||||
@@ -226,7 +226,9 @@ def filter_allowed_access_grants(
|
||||
return access_grants
|
||||
|
||||
# Check if user can share publicly
|
||||
if (has_public_read_access_grant(access_grants) or has_public_write_access_grant(access_grants)) and not has_permission(
|
||||
if (
|
||||
has_public_read_access_grant(access_grants) or has_public_write_access_grant(access_grants)
|
||||
) and not has_permission(
|
||||
user_id,
|
||||
public_permission_key,
|
||||
default_permissions,
|
||||
|
||||
@@ -3534,7 +3534,6 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
)
|
||||
# Check for Responses API events (type field starts with "response.")
|
||||
elif data.get('type', '').startswith('response.'):
|
||||
|
||||
output, response_metadata = handle_responses_streaming_event(data, output)
|
||||
|
||||
processed_data = {
|
||||
@@ -3973,19 +3972,20 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
}
|
||||
responses_api_tool_calls = []
|
||||
for item in output:
|
||||
if (
|
||||
item.get('type') == 'function_call'
|
||||
and item.get('call_id') not in handled_call_ids
|
||||
):
|
||||
if item.get('type') == 'function_call' and item.get('call_id') not in handled_call_ids:
|
||||
arguments = item.get('arguments', '{}')
|
||||
responses_api_tool_calls.append({
|
||||
'id': item.get('call_id', ''),
|
||||
'index': len(responses_api_tool_calls),
|
||||
'function': {
|
||||
'name': item.get('name', ''),
|
||||
'arguments': arguments if isinstance(arguments, str) else json.dumps(arguments),
|
||||
},
|
||||
})
|
||||
responses_api_tool_calls.append(
|
||||
{
|
||||
'id': item.get('call_id', ''),
|
||||
'index': len(responses_api_tool_calls),
|
||||
'function': {
|
||||
'name': item.get('name', ''),
|
||||
'arguments': arguments
|
||||
if isinstance(arguments, str)
|
||||
else json.dumps(arguments),
|
||||
},
|
||||
}
|
||||
)
|
||||
if responses_api_tool_calls:
|
||||
tool_calls.append(_split_tool_calls(responses_api_tool_calls))
|
||||
|
||||
@@ -4021,10 +4021,7 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
|
||||
# Append function_call items for each tool call
|
||||
# (Responses API already has them from streaming, so skip duplicates)
|
||||
existing_call_ids = {
|
||||
item.get('call_id') for item in output
|
||||
if item.get('type') == 'function_call'
|
||||
}
|
||||
existing_call_ids = {item.get('call_id') for item in output if item.get('type') == 'function_call'}
|
||||
for tc in response_tool_calls:
|
||||
call_id = tc.get('id', '')
|
||||
if call_id not in existing_call_ids:
|
||||
@@ -4312,9 +4309,8 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
if ENABLE_RESPONSES_API_STATEFUL and last_response_id:
|
||||
system_message = get_system_message(form_data['messages'])
|
||||
new_form_data['messages'] = (
|
||||
([system_message] if system_message else [])
|
||||
+ convert_output_to_messages(output, raw=True)
|
||||
)
|
||||
[system_message] if system_message else []
|
||||
) + convert_output_to_messages(output, raw=True)
|
||||
new_form_data['previous_response_id'] = last_response_id
|
||||
else:
|
||||
tool_messages = convert_output_to_messages(output, raw=True)
|
||||
@@ -4338,13 +4334,18 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
]
|
||||
|
||||
if image_urls:
|
||||
new_form_data['messages'].append({
|
||||
'role': 'user',
|
||||
'content': [
|
||||
{'type': 'text', 'text': 'Here are the images from the tool results above. Please analyze them.'},
|
||||
*[{'type': 'image_url', 'image_url': {'url': url}} for url in image_urls],
|
||||
],
|
||||
})
|
||||
new_form_data['messages'].append(
|
||||
{
|
||||
'role': 'user',
|
||||
'content': [
|
||||
{
|
||||
'type': 'text',
|
||||
'text': 'Here are the images from the tool results above. Please analyze them.',
|
||||
},
|
||||
*[{'type': 'image_url', 'image_url': {'url': url}} for url in image_urls],
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
res = await generate_chat_completion(
|
||||
request,
|
||||
@@ -4370,10 +4371,7 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
and prior_output[-1].get('status') == 'in_progress'
|
||||
):
|
||||
msg_parts = prior_output[-1].get('content', [])
|
||||
if (
|
||||
not msg_parts
|
||||
or (len(msg_parts) == 1 and not msg_parts[0].get('text', '').strip())
|
||||
):
|
||||
if not msg_parts or (len(msg_parts) == 1 and not msg_parts[0].get('text', '').strip()):
|
||||
prior_output.pop()
|
||||
output = []
|
||||
await stream_body_handler(res, new_form_data)
|
||||
|
||||
@@ -433,11 +433,7 @@ def strip_empty_content_blocks(messages: list[dict]) -> list[dict]:
|
||||
cleaned = [
|
||||
block
|
||||
for block in content
|
||||
if not (
|
||||
isinstance(block, dict)
|
||||
and block.get('type') == 'text'
|
||||
and not block.get('text', '').strip()
|
||||
)
|
||||
if not (isinstance(block, dict) and block.get('type') == 'text' and not block.get('text', '').strip())
|
||||
]
|
||||
if cleaned:
|
||||
message['content'] = cleaned
|
||||
@@ -521,7 +517,6 @@ def get_gravatar_url(email):
|
||||
return f'https://www.gravatar.com/avatar/{hash_hex}?d=mp'
|
||||
|
||||
|
||||
|
||||
# Give us each day the data we require, and forgive us our
|
||||
# technical debts as we forgive those who commit upstream.
|
||||
# Lead the bits not into corruption but deliver them from
|
||||
|
||||
@@ -862,9 +862,7 @@ async def get_terminal_system_prompt(
|
||||
return None
|
||||
|
||||
# 2. Fetch system prompt
|
||||
async with session.get(
|
||||
f'{base}/system', headers=headers, cookies=cookies or {}
|
||||
) as resp:
|
||||
async with session.get(f'{base}/system', headers=headers, cookies=cookies or {}) as resp:
|
||||
if resp.status == 200:
|
||||
data = await resp.json()
|
||||
return data.get('prompt')
|
||||
@@ -1190,7 +1188,6 @@ async def get_tool_servers_data(servers: List[Dict[str, Any]]) -> List[Dict[str,
|
||||
return results
|
||||
|
||||
|
||||
|
||||
async def execute_tool_server(
|
||||
url: str,
|
||||
headers: Dict[str, str],
|
||||
|
||||
Reference in New Issue
Block a user