refac
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -128,22 +128,40 @@ def get_content_from_message(message: dict) -> Optional[str]:
|
||||
return None
|
||||
|
||||
|
||||
def convert_output_to_messages(output: list) -> list[dict]:
|
||||
def convert_output_to_messages(output: list, raw: bool = False) -> list[dict]:
|
||||
"""
|
||||
Convert OR-aligned output items to OpenAI-format messages for LLM consumption.
|
||||
|
||||
This is the inverse of convert_content_blocks_to_output() in middleware.py.
|
||||
Convert OR-aligned output items to OpenAI Chat Completion-format messages.
|
||||
|
||||
This reconstructs the full conversation from the stored Responses API-native
|
||||
output items, including assistant messages with tool_calls arrays and tool
|
||||
role messages.
|
||||
|
||||
Args:
|
||||
output: List of OR-aligned output items (Responses API format).
|
||||
raw: If True, include reasoning blocks (with original tags) and code
|
||||
interpreter blocks for LLM re-processing follow-ups.
|
||||
"""
|
||||
if not output or not isinstance(output, list):
|
||||
return []
|
||||
|
||||
|
||||
messages = []
|
||||
pending_tool_calls = []
|
||||
pending_content = []
|
||||
|
||||
|
||||
def flush_pending():
|
||||
nonlocal pending_content, pending_tool_calls
|
||||
if pending_content or pending_tool_calls:
|
||||
messages.append({
|
||||
"role": "assistant",
|
||||
"content": "\n".join(pending_content) if pending_content else "",
|
||||
**({"tool_calls": pending_tool_calls} if pending_tool_calls else {}),
|
||||
})
|
||||
pending_content = []
|
||||
pending_tool_calls = []
|
||||
|
||||
for item in output:
|
||||
item_type = item.get("type", "")
|
||||
|
||||
|
||||
if item_type == "message":
|
||||
# Extract text from output_text content parts
|
||||
content_parts = item.get("content", [])
|
||||
@@ -153,58 +171,86 @@ def convert_output_to_messages(output: list) -> list[dict]:
|
||||
text += part.get("text", "")
|
||||
if text:
|
||||
pending_content.append(text)
|
||||
|
||||
|
||||
elif item_type == "function_call":
|
||||
# Collect tool calls to batch into assistant message
|
||||
arguments = item.get("arguments", "{}")
|
||||
# Ensure arguments is always a JSON string
|
||||
if not isinstance(arguments, str):
|
||||
arguments = json.dumps(arguments)
|
||||
pending_tool_calls.append({
|
||||
"id": item.get("call_id", ""),
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": item.get("name", ""),
|
||||
"arguments": item.get("arguments", "{}"),
|
||||
"arguments": arguments,
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
elif item_type == "function_call_output":
|
||||
# Flush any pending content/tool_calls before adding tool result
|
||||
if pending_content or pending_tool_calls:
|
||||
messages.append({
|
||||
"role": "assistant",
|
||||
"content": "\n".join(pending_content) if pending_content else "",
|
||||
**({"tool_calls": pending_tool_calls} if pending_tool_calls else {}),
|
||||
})
|
||||
pending_content = []
|
||||
pending_tool_calls = []
|
||||
|
||||
flush_pending()
|
||||
|
||||
# Extract text from output content parts
|
||||
output_parts = item.get("output", [])
|
||||
content = ""
|
||||
for part in output_parts:
|
||||
if part.get("type") == "input_text":
|
||||
content += part.get("text", "")
|
||||
|
||||
|
||||
messages.append({
|
||||
"role": "tool",
|
||||
"tool_call_id": item.get("call_id", ""),
|
||||
"content": content,
|
||||
})
|
||||
|
||||
|
||||
elif item_type == "reasoning":
|
||||
# Skip reasoning blocks for LLM messages
|
||||
pass
|
||||
|
||||
if raw:
|
||||
# Include reasoning with original tags for LLM re-processing
|
||||
reasoning_text = ""
|
||||
source_list = item.get("summary", []) or item.get("content", [])
|
||||
for part in source_list:
|
||||
if part.get("type") == "output_text":
|
||||
reasoning_text += part.get("text", "")
|
||||
elif "text" in part:
|
||||
reasoning_text += part.get("text", "")
|
||||
|
||||
if reasoning_text:
|
||||
start_tag = item.get("start_tag", "<think>")
|
||||
end_tag = item.get("end_tag", "</think>")
|
||||
pending_content.append(
|
||||
f"{start_tag}{reasoning_text}{end_tag}"
|
||||
)
|
||||
# else: skip reasoning blocks for normal LLM messages
|
||||
|
||||
elif item_type == "open_webui:code_interpreter":
|
||||
if raw:
|
||||
# Include code interpreter content for LLM re-processing
|
||||
code = item.get("code", "")
|
||||
code_output = item.get("output", "")
|
||||
|
||||
if code:
|
||||
lang = item.get("lang", "python")
|
||||
pending_content.append(f"```{lang}\n{code}\n```")
|
||||
|
||||
if code_output:
|
||||
if isinstance(code_output, dict):
|
||||
stdout = code_output.get("stdout", "")
|
||||
result = code_output.get("result", "")
|
||||
output_text = stdout or result
|
||||
else:
|
||||
output_text = str(code_output)
|
||||
if output_text:
|
||||
pending_content.append(f"Output:\n{output_text}")
|
||||
# else: skip extension types
|
||||
|
||||
elif item_type.startswith("open_webui:"):
|
||||
# Skip extension types
|
||||
# Skip other extension types
|
||||
pass
|
||||
|
||||
|
||||
# Flush remaining content/tool_calls
|
||||
if pending_content or pending_tool_calls:
|
||||
messages.append({
|
||||
"role": "assistant",
|
||||
"content": "\n".join(pending_content) if pending_content else "",
|
||||
**({"tool_calls": pending_tool_calls} if pending_tool_calls else {}),
|
||||
})
|
||||
|
||||
flush_pending()
|
||||
|
||||
return messages
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user