Spaces:
Paused
Paused
| """ | |
| FC Debug Payload Truncation Utilities. | |
| Provides intelligent truncation of large payloads (tool definitions, | |
| function arguments, responses) for readable logging without excessive output. | |
| """ | |
| import json | |
| import os | |
| from dataclasses import dataclass | |
| from typing import Any, List | |
| from .modules import FCModule | |
| class TruncationConfig: | |
| """Configuration for payload truncation.""" | |
| enabled: bool = True | |
| max_tool_definition: int = 500 | |
| max_arguments: int = 1000 | |
| max_response: int = 2000 | |
| max_default: int = 500 | |
| def from_env(cls) -> "TruncationConfig": | |
| """Load truncation config from environment.""" | |
| return cls( | |
| enabled=os.environ.get("FC_DEBUG_TRUNCATE_ENABLED", "true").lower() | |
| in ("true", "1", "yes"), | |
| max_tool_definition=int( | |
| os.environ.get("FC_DEBUG_TRUNCATE_MAX_TOOL_DEF", "500") | |
| ), | |
| max_arguments=int(os.environ.get("FC_DEBUG_TRUNCATE_MAX_ARGS", "1000")), | |
| max_response=int(os.environ.get("FC_DEBUG_TRUNCATE_MAX_RESPONSE", "2000")), | |
| ) | |
| def get_max_length(self, payload: Any, module: FCModule) -> int: | |
| """Get the max length for a payload based on module and content type.""" | |
| # Module-specific defaults | |
| if module == FCModule.SCHEMA: | |
| return self.max_tool_definition | |
| elif module in (FCModule.WIRE, FCModule.DOM): | |
| return self.max_arguments | |
| elif module == FCModule.RESPONSE: | |
| return self.max_response | |
| return self.max_default | |
| def truncate_payload(payload: Any, max_length: int) -> str: | |
| """ | |
| Truncate a payload for logging. | |
| Handles dicts, lists, and strings intelligently: | |
| - Shows structure summary for truncated objects | |
| - Preserves enough context to be useful | |
| Args: | |
| payload: The payload to truncate | |
| max_length: Maximum allowed length | |
| Returns: | |
| Truncated string representation | |
| """ | |
| try: | |
| if isinstance(payload, str): | |
| if len(payload) <= max_length: | |
| return payload | |
| return f"{payload[:max_length]}... [truncated, total={len(payload)}]" | |
| if isinstance(payload, (dict, list)): | |
| json_str = json.dumps(payload, indent=2, default=str) | |
| if len(json_str) <= max_length: | |
| return json_str | |
| # Show truncated with summary | |
| truncated = json_str[:max_length] | |
| # Add summary | |
| if isinstance(payload, dict): | |
| keys = list(payload.keys())[:5] | |
| summary = f"{{...}} [keys={keys}, truncated={len(json_str)}]" | |
| else: | |
| summary = f"[...] [length={len(payload)}, truncated={len(json_str)}]" | |
| return f"{truncated}\n... {summary}" | |
| # For other types, convert to string and truncate | |
| str_val = str(payload) | |
| if len(str_val) <= max_length: | |
| return str_val | |
| return f"{str_val[:max_length]}... [truncated]" | |
| except Exception as e: | |
| return f"[Error formatting payload: {e}]" | |
| def summarize_tools(tools: List[Any]) -> str: | |
| """ | |
| Create a summary of tool definitions without full schemas. | |
| Args: | |
| tools: List of tool definition dicts | |
| Returns: | |
| Concise summary string | |
| """ | |
| if not tools: | |
| return "[]" | |
| summaries = [] | |
| for tool in tools[:10]: # Max 10 tools in summary | |
| if isinstance(tool, dict): | |
| func = tool.get("function", tool) | |
| name = func.get("name", "unknown") | |
| params = func.get("parameters", {}) | |
| param_count = ( | |
| len(params.get("properties", {})) if isinstance(params, dict) else 0 | |
| ) | |
| summaries.append(f"{name}({param_count} params)") | |
| result = ", ".join(summaries) | |
| if len(tools) > 10: | |
| result += f", ... +{len(tools) - 10} more" | |
| return f"[{result}]" | |