This commit is contained in:
Timothy Jaeryang Baek 2025-09-28 14:46:01 -05:00
parent 4f06f29348
commit 91b6483aa9
2 changed files with 226 additions and 277 deletions

View File

@ -705,6 +705,23 @@ def get_event_emitter(request_info, update_db=True):
},
)
if "type" in event_data and event_data["type"] == "embeds":
message = Chats.get_message_by_id_and_message_id(
request_info["chat_id"],
request_info["message_id"],
)
embeds = event_data.get("data", {}).get("embeds", [])
embeds.extend(message.get("embeds", []))
Chats.upsert_message_to_chat_by_id_and_message_id(
request_info["chat_id"],
request_info["message_id"],
{
"embeds": embeds,
},
)
if "type" in event_data and event_data["type"] == "files":
message = Chats.get_message_by_id_and_message_id(
request_info["chat_id"],

View File

@ -133,6 +133,149 @@ DEFAULT_SOLUTION_TAGS = [("<|begin_of_solution|>", "<|end_of_solution|>")]
DEFAULT_CODE_INTERPRETER_TAGS = [("<code_interpreter>", "</code_interpreter>")]
def process_tool_result(
request,
tool_function_name,
tool_result,
tool_type,
direct_tool=False,
metadata=None,
user=None,
):
tool_result_embeds = []
if isinstance(tool_result, HTMLResponse):
content_disposition = tool_result.headers.get("Content-Disposition", "")
if "inline" in content_disposition:
content = tool_result.body.decode("utf-8")
tool_result_embeds.append(content)
if 200 <= tool_result.status_code < 300:
tool_result = {
"status": "success",
"code": "ui_component",
"message": f"{tool_function_name}: Embedded UI result is active and visible to the user.",
}
elif 400 <= tool_result.status_code < 500:
tool_result = {
"status": "error",
"code": "ui_component",
"message": f"{tool_function_name}: Client error {tool_result.status_code} from embedded UI result.",
}
elif 500 <= tool_result.status_code < 600:
tool_result = {
"status": "error",
"code": "ui_component",
"message": f"{tool_function_name}: Server error {tool_result.status_code} from embedded UI result.",
}
else:
tool_result = {
"status": "error",
"code": "ui_component",
"message": f"{tool_function_name}: Unexpected status code {tool_result.status_code} from embedded UI result.",
}
else:
tool_result = tool_result.body.decode("utf-8")
elif (tool_type == "external" and isinstance(tool_result, tuple)) or (
direct_tool and isinstance(tool_result, list) and len(tool_result) == 2
):
tool_result, tool_response_headers = tool_result
try:
if not isinstance(tool_response_headers, dict):
tool_response_headers = dict(tool_response_headers)
except Exception as e:
tool_response_headers = {}
log.debug(e)
if tool_response_headers and isinstance(tool_response_headers, dict):
content_disposition = tool_response_headers.get(
"Content-Disposition",
tool_response_headers.get("content-disposition", ""),
)
if "inline" in content_disposition:
content_type = tool_response_headers.get(
"Content-Type",
tool_response_headers.get("content-type", ""),
)
location = tool_response_headers.get(
"Location",
tool_response_headers.get("location", ""),
)
if "text/html" in content_type:
# Display as iframe embed
tool_result_embeds.append(tool_result)
tool_result = {
"status": "success",
"code": "ui_component",
"message": f"{tool_function_name}: Embedded UI result is active and visible to the user.",
}
elif location:
tool_result_embeds.append(location)
tool_result = {
"status": "success",
"code": "ui_component",
"message": f"{tool_function_name}: Embedded UI result is active and visible to the user.",
}
tool_result_files = []
if isinstance(tool_result, list):
if tool_type == "mcp": # MCP
tool_response = []
for item in tool_result:
if isinstance(item, dict):
if item.get("type") == "text":
text = item.get("text", "")
if isinstance(text, str):
try:
text = json.loads(text)
except json.JSONDecodeError:
pass
tool_response.append(text)
elif item.get("type") in ["image", "audio"]:
file_url = get_file_url_from_base64(
request,
f"data:{item.get('mimeType')};base64,{item.get('data', item.get('blob', ''))}",
{
"chat_id": metadata.get("chat_id", None),
"message_id": metadata.get("message_id", None),
"session_id": metadata.get("session_id", None),
"result": item,
},
user,
)
tool_result_files.append(
{
"type": item.get("type", "data"),
"url": file_url,
}
)
tool_result = tool_response[0] if len(tool_response) == 1 else tool_response
else: # OpenAPI
for item in tool_result:
if isinstance(item, str) and item.startswith("data:"):
tool_result_files.append(
{
"type": "data",
"content": item,
}
)
tool_result.remove(item)
if isinstance(tool_result, list):
tool_result = {"results": tool_result}
if isinstance(tool_result, dict) or isinstance(tool_result, list):
tool_result = json.dumps(tool_result, indent=2, ensure_ascii=False)
return tool_result, tool_result_files, tool_result_embeds
async def chat_completion_tools_handler(
request: Request, body: dict, extra_params: dict, user: UserModel, models, tools
) -> tuple[dict, dict]:
@ -172,6 +315,7 @@ async def chat_completion_tools_handler(
}
event_caller = extra_params["__event_call__"]
event_emitter = extra_params["__event_emitter__"]
metadata = extra_params["__metadata__"]
task_model_id = get_task_model_id(
@ -226,8 +370,14 @@ async def chat_completion_tools_handler(
tool_function_params = tool_call.get("parameters", {})
tool = None
tool_type = ""
direct_tool = False
try:
tool = tools[tool_function_name]
tool_type = tool.get("type", "")
direct_tool = tool.get("direct", False)
spec = tool.get("spec", {})
allowed_params = (
@ -259,106 +409,31 @@ async def chat_completion_tools_handler(
except Exception as e:
tool_result = str(e)
tool_result_embeds = []
if isinstance(tool_result, HTMLResponse):
content_disposition = tool_result.headers.get(
"Content-Disposition", ""
tool_result, tool_result_files, tool_result_embeds = (
process_tool_result(
request,
tool_function_name,
tool_result,
tool_type,
direct_tool,
metadata,
user,
)
if "inline" in content_disposition:
content = tool_result.body.decode("utf-8")
tool_result_embeds.append(content)
if 200 <= tool_result.status_code < 300:
tool_result = {
"status": "success",
"code": "ui_component",
"message": "Embedded UI result is active and visible to the user.",
}
elif 400 <= tool_result.status_code < 500:
tool_result = {
"status": "error",
"code": "ui_component",
"message": f"Client error {tool_result.status_code} from embedded UI result.",
}
elif 500 <= tool_result.status_code < 600:
tool_result = {
"status": "error",
"code": "ui_component",
"message": f"Server error {tool_result.status_code} from embedded UI result.",
}
else:
tool_result = {
"status": "error",
"code": "ui_component",
"message": f"Unexpected status code {tool_result.status_code} from embedded UI result.",
}
else:
tool_result = tool_result.body.decode("utf-8")
elif (
tool.get("type") == "external" and isinstance(tool_result, tuple)
) or (
tool.get("direct", True)
and isinstance(tool_result, list)
and len(tool_result) == 2
):
tool_result, tool_response_headers = tool_result
try:
if not isinstance(tool_response_headers, dict):
tool_response_headers = dict(tool_response_headers)
except Exception as e:
tool_response_headers = {}
log.debug(e)
if tool_response_headers and isinstance(
tool_response_headers, dict
):
content_disposition = tool_response_headers.get(
"Content-Disposition",
tool_response_headers.get("content-disposition", ""),
)
if "inline" in content_disposition:
content_type = tool_response_headers.get(
"Content-Type",
tool_response_headers.get("content-type", ""),
)
location = tool_response_headers.get(
"Location",
tool_response_headers.get("location", ""),
)
if "text/html" in content_type:
# Display as iframe embed
tool_result_embeds.append(tool_result)
tool_result = {
"status": "success",
"code": "ui_component",
"message": "Embedded UI result is active and visible to the user.",
if event_emitter:
if tool_result_files:
await event_emitter(
{
"type": "files",
"data": {
"files": tool_result_files,
},
}
elif location:
tool_result_embeds.append(location)
tool_result = {
"status": "success",
"code": "ui_component",
"message": "Embedded UI result is active and visible to the user.",
}
tool_result_files = []
if isinstance(tool_result, list):
for item in tool_result:
# check if string
if isinstance(item, str) and item.startswith("data:"):
tool_result_files.append(item)
tool_result.remove(item)
if isinstance(tool_result, dict) or isinstance(tool_result, list):
tool_result = json.dumps(tool_result, indent=2)
)
if tool_result_embeds:
if event_caller:
await event_caller(
await event_emitter(
{
"type": "embeds",
"data": {
@ -367,7 +442,13 @@ async def chat_completion_tools_handler(
}
)
if isinstance(tool_result, str):
print(
f"Tool {tool_function_name} result: {tool_result}",
tool_result_files,
tool_result_embeds,
)
if tool_result:
tool = tools[tool_function_name]
tool_id = tool.get("tool_id", "")
@ -381,18 +462,19 @@ async def chat_completion_tools_handler(
sources.append(
{
"source": {
"name": (f"TOOL:{tool_name}"),
"name": (f"{tool_name}"),
},
"document": [tool_result],
"document": [str(tool_result)],
"metadata": [
{
"source": (f"TOOL:{tool_name}"),
"source": (f"{tool_name}"),
"parameters": tool_function_params,
}
],
"tool_result": True,
}
)
# Citation is not enabled for this tool
body["messages"] = add_or_update_user_message(
f"\nTool `{tool_name}` Output: {tool_result}",
@ -1267,9 +1349,7 @@ async def process_chat_payload(request, form_data, user, metadata, model):
citation_idx_map = {}
for source in sources:
is_tool_result = source.get("tool_result", False)
if "document" in source and not is_tool_result:
if "document" in source:
for document_text, document_metadata in zip(
source["document"], source["metadata"]
):
@ -1330,6 +1410,10 @@ async def process_chat_payload(request, form_data, user, metadata, model):
}
)
print("Final form_data:", form_data)
print("Final metadata:", metadata)
print("Final events:", events)
return form_data, metadata, events
@ -2538,7 +2622,9 @@ async def process_chat_response(
print("tool_call", tool_call)
tool_call_id = tool_call.get("id", "")
tool_name = tool_call.get("function", {}).get("name", "")
tool_function_name = tool_call.get("function", {}).get(
"name", ""
)
tool_args = tool_call.get("function", {}).get("arguments", "{}")
tool_function_params = {}
@ -2568,11 +2654,17 @@ async def process_chat_response(
)
tool_result = None
tool = None
tool_type = None
direct_tool = False
if tool_name in tools:
tool = tools[tool_name]
if tool_function_name in tools:
tool = tools[tool_function_name]
spec = tool.get("spec", {})
tool_type = tool.get("type", "")
direct_tool = tool.get("direct", False)
try:
allowed_params = (
spec.get("parameters", {})
@ -2586,13 +2678,13 @@ async def process_chat_response(
if k in allowed_params
}
if tool.get("direct", False):
if direct_tool:
tool_result = await event_caller(
{
"type": "execute:tool",
"data": {
"id": str(uuid4()),
"name": tool_name,
"name": tool_function_name,
"params": tool_function_params,
"server": tool.get("server", {}),
"session_id": metadata.get(
@ -2611,175 +2703,16 @@ async def process_chat_response(
except Exception as e:
tool_result = str(e)
tool_result_embeds = []
if isinstance(tool_result, HTMLResponse):
content_disposition = tool_result.headers.get(
"Content-Disposition", ""
)
if "inline" in content_disposition:
content = tool_result.body.decode("utf-8")
tool_result_embeds.append(content)
if 200 <= tool_result.status_code < 300:
tool_result = {
"status": "success",
"code": "ui_component",
"message": "Embedded UI result is active and visible to the user.",
}
elif 400 <= tool_result.status_code < 500:
tool_result = {
"status": "error",
"code": "ui_component",
"message": f"Client error {tool_result.status_code} from embedded UI result.",
}
elif 500 <= tool_result.status_code < 600:
tool_result = {
"status": "error",
"code": "ui_component",
"message": f"Server error {tool_result.status_code} from embedded UI result.",
}
else:
tool_result = {
"status": "error",
"code": "ui_component",
"message": f"Unexpected status code {tool_result.status_code} from embedded UI result.",
}
else:
tool_result = tool_result.body.decode("utf-8")
elif (
tool.get("type") == "external"
and isinstance(tool_result, tuple)
) or (
tool.get("direct", True)
and isinstance(tool_result, list)
and len(tool_result) == 2
):
tool_result, tool_response_headers = tool_result
try:
if not isinstance(tool_response_headers, dict):
tool_response_headers = dict(tool_response_headers)
except Exception as e:
tool_response_headers = {}
log.debug(e)
print(tool_response_headers)
print(type(tool_response_headers))
if tool_response_headers and isinstance(
tool_response_headers, dict
):
content_disposition = tool_response_headers.get(
"Content-Disposition",
tool_response_headers.get(
"content-disposition", ""
),
)
if "inline" in content_disposition:
content_type = tool_response_headers.get(
"Content-Type",
tool_response_headers.get("content-type", ""),
)
location = tool_response_headers.get(
"Location",
tool_response_headers.get("location", ""),
)
if "text/html" in content_type:
# Display as iframe embed
tool_result_embeds.append(tool_result)
tool_result = {
"status": "success",
"code": "ui_component",
"message": "Embedded UI result is active and visible to the user.",
}
elif location:
tool_result_embeds.append(location)
tool_result = {
"status": "success",
"code": "ui_component",
"message": "Embedded UI result is active and visible to the user.",
}
tool_result_files = []
if isinstance(tool_result, list):
if tool.get("type") == "mcp": # MCP
tool_response = []
for item in tool_result:
if isinstance(item, dict):
if item.get("type") == "text":
text = item.get("text", "")
if isinstance(text, str):
try:
text = json.loads(text)
except json.JSONDecodeError:
pass
tool_response.append(text)
elif item.get("type") in ["image", "audio"]:
file_url = get_file_url_from_base64(
tool_result, tool_result_files, tool_result_embeds = (
process_tool_result(
request,
f"data:{item.get('mimeType')};base64,{item.get('data', item.get('blob', ''))}",
{
"chat_id": metadata.get(
"chat_id", None
),
"message_id": metadata.get(
"message_id", None
),
"session_id": metadata.get(
"session_id", None
),
"result": item,
},
tool_function_name,
tool_result,
tool_type,
direct_tool,
metadata,
user,
)
tool_result_files.append(
{
"type": item.get("type", "data"),
"url": file_url,
}
)
tool_result = (
tool_response[0]
if len(tool_response) == 1
else tool_response
)
else: # OpenAPI
for item in tool_result:
# check if string
if isinstance(item, str) and item.startswith(
"data:"
):
tool_result_files.append(
{
"type": "data",
"content": item,
}
)
tool_result.remove(item)
if tool_result_files:
if not isinstance(tool_result, list):
tool_result = [
tool_result,
]
for file in tool_result_files:
tool_result.append(
{
"type": file.get("type", "data"),
"content": "Result is being displayed as a file.",
}
)
if isinstance(tool_result, dict) or isinstance(
tool_result, list
):
tool_result = json.dumps(
tool_result, indent=2, ensure_ascii=False
)
results.append(
@ -2800,7 +2733,6 @@ async def process_chat_response(
)
content_blocks[-1]["results"] = results
content_blocks.append(
{
"type": "text",