Initialise the ToolManager and context, then call *async_command(...)*. The *async_command* may itself be `async` **or** synchronous – both work. The ToolManager is always closed, even when the callable raises.
(
async_command: Callable[..., Any],
*,
config_file: str,
servers: list[str],
extra_params: dict[str, Any | None],
)
| 149 | # command dispatch # |
| 150 | # --------------------------------------------------------------------------- # |
| 151 | async def run_command( |
| 152 | async_command: Callable[..., Any], |
| 153 | *, |
| 154 | config_file: str, |
| 155 | servers: list[str], |
| 156 | extra_params: dict[str, Any | None], |
| 157 | ) -> Any: |
| 158 | """ |
| 159 | Initialise the ToolManager and context, then call *async_command(...)*. |
| 160 | |
| 161 | The *async_command* may itself be `async` **or** synchronous – both work. |
| 162 | The ToolManager is always closed, even when the callable raises. |
| 163 | """ |
| 164 | tm = None |
| 165 | try: |
| 166 | server_names = (extra_params or {}).get("server_names") |
| 167 | init_timeout = (extra_params or {}).get("init_timeout", 120.0) |
| 168 | |
| 169 | # ------------------------------------------------------------------ |
| 170 | # build ToolManager (patch-friendly, see helper) |
| 171 | # ------------------------------------------------------------------ |
| 172 | tm = await _init_tool_manager( |
| 173 | config_file, servers, server_names, init_timeout or 120.0 |
| 174 | ) |
| 175 | |
| 176 | # ------------------------------------------------------------------ |
| 177 | # Initialize context with tool manager and other params |
| 178 | # ------------------------------------------------------------------ |
| 179 | context = initialize_context( |
| 180 | tool_manager=tm, |
| 181 | config_path=Path(config_file), |
| 182 | provider=(extra_params or {}).get("provider", DEFAULT_PROVIDER), |
| 183 | model=(extra_params or {}).get("model", DEFAULT_MODEL), |
| 184 | api_base=(extra_params or {}).get("api_base"), |
| 185 | api_key=(extra_params or {}).get("api_key"), |
| 186 | ) |
| 187 | |
| 188 | # Initialize the context (load servers, tools, etc.) |
| 189 | await context.initialize() |
| 190 | |
| 191 | # ------------------------------------------------------------------ |
| 192 | # special-case: interactive "app" object |
| 193 | # ------------------------------------------------------------------ |
| 194 | name = getattr(async_command, "__name__", "") |
| 195 | module = getattr(async_command, "__module__", "") |
| 196 | if name == "app" and "interactive" in module: |
| 197 | provider = context.provider |
| 198 | model = context.model |
| 199 | result = await _enter_interactive_mode(tm, provider=provider, model=model) |
| 200 | return result |
| 201 | |
| 202 | # ------------------------------------------------------------------ |
| 203 | # normal pathway - commands no longer need context passed |
| 204 | # ------------------------------------------------------------------ |
| 205 | # Remove tool_manager and context from call_kwargs since commands get it from context |
| 206 | call_kwargs = {} |
| 207 | |
| 208 | # Pass all extra_params to the command |