Unwrap middleware ``ToolExecutionResult`` wrappers and MCP result dicts. When middleware is enabled, ``ToolManager`` returns the result wrapped in a ``ToolExecutionResult`` object (from ``chuk_tool_processor.mcp.middleware``). The inner payload is typically ``{"isError": bool, "content"
(obj: Any, *, max_depth: int = _UNWRAP_MAX_DEPTH)
| 9 | |
| 10 | |
| 11 | def unwrap_tool_result(obj: Any, *, max_depth: int = _UNWRAP_MAX_DEPTH) -> Any: |
| 12 | """Unwrap middleware ``ToolExecutionResult`` wrappers and MCP result dicts. |
| 13 | |
| 14 | When middleware is enabled, ``ToolManager`` returns the result wrapped in |
| 15 | a ``ToolExecutionResult`` object (from ``chuk_tool_processor.mcp.middleware``). |
| 16 | The inner payload is typically ``{"isError": bool, "content": ToolResult}``. |
| 17 | This peels off those layers to get the actual content. |
| 18 | |
| 19 | Raises ``RuntimeError`` if any wrapper layer reports failure. |
| 20 | """ |
| 21 | depth = 0 |
| 22 | while ( |
| 23 | hasattr(obj, "success") |
| 24 | and hasattr(obj, "result") |
| 25 | and not isinstance(obj, dict) |
| 26 | ): |
| 27 | if depth >= max_depth: |
| 28 | raise RuntimeError(f"Exceeded max unwrap depth ({max_depth})") |
| 29 | if not obj.success: |
| 30 | error = getattr(obj, "error", None) or "Unknown tool error" |
| 31 | raise RuntimeError(error) |
| 32 | obj = obj.result |
| 33 | depth += 1 |
| 34 | |
| 35 | # Unwrap MCP call_tool dict pattern: {"isError": ..., "content": ...} |
| 36 | if isinstance(obj, dict) and "content" in obj and "isError" in obj: |
| 37 | if obj["isError"]: |
| 38 | error_msg = obj.get("error") or obj.get("content") or "Tool returned an error" |
| 39 | if not isinstance(error_msg, str): |
| 40 | error_msg = str(error_msg) |
| 41 | raise RuntimeError(error_msg) |
| 42 | obj = obj["content"] |
| 43 | |
| 44 | return obj |
| 45 | |
| 46 | |
| 47 | def to_serializable(obj: Any) -> Any: |