{"record":{"id":"eefad93bee26b389","repo":"JuliusBrussee/caveman","slug":"expected-an-autogen-workbench-or-list-of-workbenches","errorCode":null,"errorMessage":"Expected an AutoGen Workbench or list of workbenches","messagePattern":"Expected an AutoGen Workbench or list of workbenches","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/middleware/python/caveman_middleware/autogen.py","lineNumber":379,"sourceCode":"                attempt.observe(\"failed\")\n            raise\n        finally:\n            await iterator.aclose()\n\n\nclass CavemanWorkbench(StaticStreamWorkbench):\n    \"\"\"Add scoped recovery to a real workbench without changing its tool results.\n\n    AutoGen 0.7.5 selects streaming tools by this public base class. Delegating\n    call_tool_stream preserves native streaming workbenches and their events.\n    \"\"\"\n    component_provider_override = \"caveman_middleware.autogen.CavemanWorkbench\"\n    component_config_schema = CavemanWorkbenchConfig\n\n    def __init__(self, workbench: Workbench | list[Workbench], *, runtime, scope: Scope, runtime_key=\"default\"):\n        delegates = workbench if type(workbench) is list else [workbench]\n        if not all(isinstance(item, Workbench) for item in delegates):\n            raise TypeError(\"Expected an AutoGen Workbench or list of workbenches\")\n        super().__init__([])\n        self.workbench = workbench\n        self.delegates = tuple(delegates)\n        self.runtime, self.scope = _check(runtime, scope), scope\n        self.runtime_key = runtime_key\n        self.binding = self.runtime.recovery(scope)\n        self.recovery_schema = _RecoverySchema(self)\n        self.recovery_enabled = False\n        self.stopped = False\n\n    async def list_tools(self):\n        tools = [tool for workbench in self.delegates for tool in await workbench.list_tools()]\n        self.recovery_enabled = (not self.stopped and _supported(self.runtime) and self.runtime.mode == \"compress\"\n                                 and not any(t.get(\"name\") == \"caveman_retrieve\" for t in tools))\n        return [*tools, self.recovery_schema] if self.recovery_enabled else tools\n\n    async def call_tool(self, name, arguments=None, cancellation_token=None, call_id=None):\n        # Refresh dynamic registries before deciding which implementation owns","sourceCodeStart":361,"sourceCodeEnd":397,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/middleware/python/caveman_middleware/autogen.py#L361-L397","documentation":"CavemanWorkbench wraps one or more AutoGen Workbench instances to add Caveman recovery tooling. The constructor validates every delegate is a Workbench instance and raises this TypeError otherwise, because it forwards tool calls and state (save_state/load_state) to each delegate.","triggerScenarios":"Passing a single non-Workbench object (MCP adapter, tool list, None, string) or a list containing any non-Workbench item as the workbench argument to CavemanWorkbench(...).","commonSituations":"Passing an MCPWorkbench-like object from another library or version; passing a plain list of tools/functions instead of Workbench objects; passing a config dict loaded from JSON instead of constructed Workbench instances.","solutions":["Pass an AutoGen Workbench instance, or a list whose every element is a Workbench.","If starting from tools, first construct a Workbench (e.g. via the AutoGen MCP or tool workbench adapters) that supports the same autogen-core version as the middleware.","If you have serialized configs, load each with Workbench.load_component(...) before passing.","Check imports: the isinstance check is against AutoGen's Workbench base class, so subclass/mix from that."],"exampleFix":"// before\nwb = CavemanWorkbench([tool_a, tool_b], runtime=rt, scope=scope)\n// after\nfrom autogen_agentchat.tools import Workbench\nwb = CavemanWorkbench([MyToolWorkbench(tool_a), MyToolWorkbench(tool_b)], runtime=rt, scope=scope)","handlingStrategy":"type-guard","validationCode":"delegates = wb if isinstance(wb, list) else [wb]\nif not all(isinstance(d, Workbench) for d in delegates):\n    raise TypeError(\"each delegate must be an AutoGen Workbench\")","typeGuard":"def is_workbench_list(obj) -> bool:\n    items = obj if isinstance(obj, list) else [obj]\n    return bool(items) and all(isinstance(i, Workbench) for i in items)","tryCatchPattern":"try:\n    wrapper = CavemanWorkbench(wb, runtime=rt, scope=scope)\nexcept TypeError as e:\n    if \"Workbench\" in str(e):\n        wrapper = CavemanWorkbench(load_component(wb), runtime=rt, scope=scope)\n    else:\n        raise","preventionTips":["Wrap bare tools in a Workbench adapter before passing to CavemanWorkbench.","Keep delegate lists built from a single factory function so every element is typed Workbench.","Pin autogen versions (0.7.x/0.8.x) compatible with the middleware; check imports resolve to AutoGen's Workbench."],"tags":["python","autogen","type-error","workbench","constructor"],"backgroundTag":"invalid-constructor-argument","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}