{"record":{"id":"39fd9e12f9a21a73","repo":"HKUDS/Vibe-Trading","slug":"live-runner-for-broker-r-does-not-define-remote","errorCode":null,"errorMessage":"live runner for {broker!r} does not define remote tool {operation!r}","messagePattern":"live runner for (.+?) does not define remote tool (.+?)","errorType":"exception","errorClass":"LiveRunnerUnavailable","httpStatus":503,"severity":"error","filePath":"agent/src/api/live_routes.py","lineNumber":554,"sourceCode":"    \"\"\"\n    h = _host()\n\n    # _runner_factory is monkeypatched on host by tests\n    factory = getattr(h, \"_runner_factory\", None)\n    if factory is not None:\n        return factory(broker)\n\n    from src.live.audit import write_live_action\n    from src.live.runtime.reconcile import reconcile\n    from src.live.runtime.runner import LiveRunner\n    from src.live.runtime.scheduler import Scheduler\n    from src.live.runtime.triggers import Trigger\n    from src.trading.service import runner_tool_name\n\n    def _tool(operation: str) -> str:\n        remote_tool = runner_tool_name(broker, operation)\n        if remote_tool is None:\n            raise LiveRunnerUnavailable(\n                f\"live runner for {broker!r} does not define remote tool {operation!r}\"\n            )\n        return remote_tool\n\n    positions_tool = _tool(\"positions\")\n    balance_tool = _tool(\"account\")\n    open_orders_tool = _tool(\"orders\")\n    submit_order_tool = _tool(\"submit_order\")\n    cancel_order_tool = _tool(\"cancel_order\")\n\n    # _live_broker_adapter is monkeypatched on host by tests\n    adapter = h._live_broker_adapter(broker)\n\n    def _read(remote_tool: str):\n        return lambda: adapter.call_tool(remote_tool, {})\n\n    def _submit(order: Dict[str, Any]) -> Dict[str, Any]:\n        if order.get(\"action\") == \"cancel\":","sourceCodeStart":536,"sourceCodeEnd":572,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/api/live_routes.py#L536-L572","documentation":"Raised by LiveRunnerUnavailable when the helper _tool() cannot map a broker's operation (e.g. 'positions' or 'account') to a remote tool name via runner_tool_name(broker, operation). This happens during _build_live_runner, meaning the selected broker's live runner contract has no registered tool for that operation — typically a registration/mapping gap in src/trading/service.py or an unsupported broker slipped through earlier validation.","triggerScenarios":"Calling any live endpoint that builds a live runner for a broker whose runner_tool_name(broker, 'positions') or (broker, 'account') returns None — e.g. GET /live/status?broker=<new-broker> after adding a broker connector without registering its remote tool names.","commonSituations":"Adding a new broker's live runner but forgetting to add its tool-name mapping; renaming operations in the runner registry without updating runner_tool_name; version skew between the agent API and the runner definitions.","solutions":["Check runner_tool_name in src/trading/service.py and confirm the broker/operation pair is registered","Add the missing mapping entry for the broker's 'positions' and 'account' tools","If the broker genuinely lacks an operation, gate the endpoint earlier with a 400 'not supported' instead of building the runner","Retry after upgrading/redeploying so agent and runner versions match"],"exampleFix":"// before (src/trading/service.py)\nRUNNER_TOOLS = {\"ibkr\": {\"positions\": \"ibkr_positions\", \"account\": \"ibkr_account\"}}\n\n// after\nRUNNER_TOOLS = {\n    \"ibkr\": {\"positions\": \"ibkr_positions\", \"account\": \"ibkr_account\"},\n    \"tradier\": {\"positions\": \"tradier_positions\", \"account\": \"tradier_balances\"},\n}","handlingStrategy":"validation","validationCode":"from src.trading.service import runner_tool_name\n\ndef can_build_runner(broker: str, ops=(\"positions\", \"account\")) -> bool:\n    return all(runner_tool_name(broker, op) is not None for op in ops)","typeGuard":"def has_runner_tools(broker: str) -> bool:\n    from src.trading.service import runner_tool_name\n    return runner_tool_name(broker, 'positions') is not None and runner_tool_name(broker, 'account') is not None","tryCatchPattern":"try:\n    runner = _build_live_runner(broker)\nexcept LiveRunnerUnavailable as e:\n    logger.warning('runner tools missing for %s: %s', broker, e)\n    return JSONResponse(status_code=501, content={'detail': str(e)})","preventionTips":["Register positions/account tool names whenever adding a broker runner","Add a startup check that every known live broker maps all required operations","Pin agent and runner versions together in deploys"],"tags":["live-trading","broker","runner","tool-mapping","fastapi"],"backgroundTag":"unsupported-operation","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}