File size: 3,951 Bytes
a5784e9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
"""
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


@dataclass
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

    @classmethod
    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}]"