Spaces:
Running
Running
| # Tool handler extracted from app.py | |
| import json | |
| import inspect | |
| from .implementations import record_user_details, record_resume_gap | |
| class ToolHandler: | |
| """Handles tool execution with resilient error handling""" | |
| def __init__(self, pushover_service=None): | |
| self.pushover_service = pushover_service | |
| # Tool implementations with dependency injection | |
| self.tool_impl = { | |
| "record_user_details": lambda **kwargs: record_user_details(**kwargs, pushover_service=self.pushover_service), | |
| "record_resume_gap": lambda **kwargs: record_resume_gap(**kwargs, pushover_service=self.pushover_service), | |
| } | |
| def _safe_parse_args(self, raw): | |
| """Safely parse tool arguments from various formats""" | |
| # Some SDKs already hand a dict; otherwise be forgiving with JSON | |
| if isinstance(raw, dict): | |
| return raw | |
| try: | |
| return json.loads(raw or "{}") | |
| except Exception: | |
| try: | |
| return json.loads((raw or "{}").replace("'", '"')) | |
| except Exception: | |
| print(f"[WARN] Unable to parse tool args: {raw}", flush=True) | |
| return {} | |
| def handle_tool_calls(self, tool_calls): | |
| """Execute tool calls and return results""" | |
| results = [] | |
| for tool_call in tool_calls: | |
| tool_name = tool_call.function.name | |
| raw_args = tool_call.function.arguments or "{}" | |
| print(f"[TOOL] {tool_name} args (raw): {raw_args}", flush=True) | |
| args = self._safe_parse_args(raw_args) | |
| impl = self.tool_impl.get(tool_name) | |
| if not impl: | |
| print(f"[WARN] Unknown tool: {tool_name}", flush=True) | |
| results.append({ | |
| "role": "tool", | |
| "content": json.dumps({"error": f"unknown tool {tool_name}"}), | |
| "tool_call_id": tool_call.id | |
| }) | |
| continue | |
| try: | |
| out = impl(**args) | |
| except TypeError as e: | |
| # Model sent unexpected params; retry with filtered args | |
| sig = inspect.signature(impl) | |
| filtered = {k: v for k, v in args.items() if k in sig.parameters} | |
| try: | |
| out = impl(**filtered) | |
| except Exception as e2: | |
| print(f"[ERROR] Tool '{tool_name}' failed: {e2}", flush=True) | |
| out = {"error": "tool execution failed"} | |
| except Exception as e: | |
| print(f"[ERROR] Tool '{tool_name}' crashed: {e}", flush=True) | |
| out = {"error": "tool execution crashed"} | |
| results.append({ | |
| "role": "tool", | |
| "content": json.dumps(out), | |
| "tool_call_id": tool_call.id | |
| }) | |
| return results |