Add --debug flag to dump full requests and replies

- Add --debug CLI argument to enable debug mode
- When enabled, dumps full request body (no truncation)
- When enabled, dumps full generated text (no truncation)
- When enabled, dumps extracted tool calls in JSON format
- Useful for troubleshooting tool call issues
parent 910238ba
...@@ -1998,6 +1998,9 @@ model_manager = ModelManager() ...@@ -1998,6 +1998,9 @@ model_manager = ModelManager()
# None = don't inject, True = use default, string = use custom text # None = don't inject, True = use default, string = use custom text
global_system_prompt = None global_system_prompt = None
# Global debug flag
global_debug = False
# ============================================================================= # =============================================================================
# FastAPI Application # FastAPI Application
...@@ -2030,19 +2033,33 @@ async def log_requests(request: Request, call_next): ...@@ -2030,19 +2033,33 @@ async def log_requests(request: Request, call_next):
try: try:
body = await request.body() body = await request.body()
body_str = body.decode('utf-8') body_str = body.decode('utf-8')
print(f"\n{'='*60}")
print(f"=== INCOMING REQUEST ===") # In debug mode, dump the full request
print(f"{'='*60}") if global_debug:
print(f"Path: {request.url.path}") print(f"\n{'='*80}")
print(f"Method: {request.method}") print(f"=== FULL DEBUG REQUEST ===")
print(f"Headers: {dict(request.headers)}") print(f"{'='*80}")
print(f"\n--- RAW BODY ({len(body)} bytes) ---") print(f"Path: {request.url.path}")
# Print body with truncation for very large bodies print(f"Method: {request.method}")
if len(body_str) > 2000: print(f"Headers: {dict(request.headers)}")
print(f"{body_str[:1000]}...\n... [truncated {len(body_str)-2000} chars] ...\n...{body_str[-1000:]}") print(f"\n--- FULL BODY ({len(body)} bytes) ---")
else:
print(body_str) print(body_str)
print(f"--- END RAW BODY ---") print(f"--- END FULL BODY ---")
print(f"{'='*80}\n")
else:
print(f"\n{'='*60}")
print(f"=== INCOMING REQUEST ===")
print(f"{'='*60}")
print(f"Path: {request.url.path}")
print(f"Method: {request.method}")
print(f"Headers: {dict(request.headers)}")
print(f"\n--- RAW BODY ({len(body)} bytes) ---")
# Print body with truncation for very large bodies
if len(body_str) > 2000:
print(f"{body_str[:1000]}...\n... [truncated {len(body_str)-2000} chars] ...\n...{body_str[-1000:]}")
else:
print(body_str)
print(f"--- END RAW BODY ---")
# Try to parse as JSON to see if it's valid # Try to parse as JSON to see if it's valid
try: try:
...@@ -2589,6 +2606,14 @@ async def stream_chat_response( ...@@ -2589,6 +2606,14 @@ async def stream_chat_response(
if not generated_text.strip(): if not generated_text.strip():
print(f"DEBUG: Warning - no content generated!") print(f"DEBUG: Warning - no content generated!")
# In debug mode, dump the full generated text
if global_debug:
print(f"\n{'='*80}")
print(f"=== FULL GENERATED TEXT (DEBUG) ===")
print(f"{'='*80}")
print(repr(generated_text))
print(f"{'='*80}\n")
# Check for tool calls in complete output (for API response format) # Check for tool calls in complete output (for API response format)
if tools: if tools:
# Convert tools back to Tool objects for parsing # Convert tools back to Tool objects for parsing
...@@ -2603,6 +2628,13 @@ async def stream_chat_response( ...@@ -2603,6 +2628,13 @@ async def stream_chat_response(
tool_objects.append(Tool(type=t.get("type", "function"), function=tool_func)) tool_objects.append(Tool(type=t.get("type", "function"), function=tool_func))
tool_calls = tool_parser.extract_tool_calls(generated_text, tool_objects) tool_calls = tool_parser.extract_tool_calls(generated_text, tool_objects)
if tool_calls: if tool_calls:
# In debug mode, dump tool calls
if global_debug:
print(f"\n{'='*80}")
print(f"=== EXTRACTED TOOL CALLS (DEBUG) ===")
print(f"{'='*80}")
print(json.dumps(tool_calls, indent=2))
print(f"{'='*80}\n")
# Tool calls were extracted and stripped from content during streaming # Tool calls were extracted and stripped from content during streaming
# Just send the tool_calls chunk # Just send the tool_calls chunk
data = { data = {
...@@ -3021,12 +3053,17 @@ def parse_args(): ...@@ -3021,12 +3053,17 @@ def parse_args():
default=None, default=None,
help="Vision model GPU offload percentage (0-100). If not set, loads fully on GPU", help="Vision model GPU offload percentage (0-100). If not set, loads fully on GPU",
) )
parser.add_argument(
"--debug",
action="store_true",
help="Enable debug mode - dumps full request/response to stdout for troubleshooting",
)
return parser.parse_args() return parser.parse_args()
def main(): def main():
"""Main entry point.""" """Main entry point."""
global global_system_prompt, model_manager, multi_model_manager global global_system_prompt, model_manager, multi_model_manager, global_debug
# Optional: set process name if procname is available # Optional: set process name if procname is available
try: try:
...@@ -3039,6 +3076,11 @@ def main(): ...@@ -3039,6 +3076,11 @@ def main():
# Set global system prompt from --system-prompt flag # Set global system prompt from --system-prompt flag
global_system_prompt = args.system_prompt global_system_prompt = args.system_prompt
# Set global debug flag
global_debug = args.debug
if global_debug:
print("DEBUG MODE ENABLED - Full requests and replies will be dumped to stdout")
# Handle --vulkan-list-devices # Handle --vulkan-list-devices
if args.vulkan_list_devices: if args.vulkan_list_devices:
print("\nListing Vulkan devices...") print("\nListing Vulkan devices...")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment