|
17 | 17 | "model": "gpt-5.4", |
18 | 18 | "language": "en", |
19 | 19 | "pageindex_threshold": 20, |
| 20 | + # Whether query/chat agents may call tools in parallel. None (default) omits |
| 21 | + # the setting so the provider decides — required for Amazon Bedrock's Claude |
| 22 | + # models, where sending parallel_tool_calls makes LiteLLM emit a malformed |
| 23 | + # tool_choice (missing `type`) and every query/chat fails (issue #175). Set |
| 24 | + # false to force sequential tool calls (fine on OpenAI/Anthropic-direct). |
| 25 | + "parallel_tool_calls": None, |
20 | 26 | } |
21 | 27 |
|
22 | 28 | # Default entity-type vocabulary. Overridable per-KB via the optional |
@@ -144,6 +150,26 @@ def resolve_extra_headers(config: dict) -> dict[str, str]: |
144 | 150 | return headers |
145 | 151 |
|
146 | 152 |
|
| 153 | +def resolve_parallel_tool_calls(config: dict) -> bool | None: |
| 154 | + """Resolve the optional ``parallel_tool_calls:`` key. |
| 155 | +
|
| 156 | + Returns ``None`` (omit the setting — provider default) when absent or |
| 157 | + explicitly null; ``True``/``False`` when set to a bool. A non-bool value is |
| 158 | + invalid and treated as unset, with a warning. ``None`` is the normal |
| 159 | + "unset" case and warns silently, matching ``resolve_timeout``. |
| 160 | + """ |
| 161 | + value = config.get("parallel_tool_calls") |
| 162 | + if value is None: |
| 163 | + return None |
| 164 | + if not isinstance(value, bool): |
| 165 | + logger.warning( |
| 166 | + "config: 'parallel_tool_calls' must be true or false, got %r — ignoring it.", |
| 167 | + value, |
| 168 | + ) |
| 169 | + return None |
| 170 | + return value |
| 171 | + |
| 172 | + |
147 | 173 | def resolve_timeout(config: dict) -> float | None: |
148 | 174 | """Resolve the optional ``timeout:`` key to a finite positive number of seconds. |
149 | 175 |
|
@@ -243,6 +269,24 @@ def get_timeout_extra_args() -> dict[str, float] | None: |
243 | 269 | return {"timeout": _runtime_timeout} if _runtime_timeout is not None else None |
244 | 270 |
|
245 | 271 |
|
| 272 | +# Process-wide agent ``parallel_tool_calls`` setting, resolved from config by |
| 273 | +# the CLI (cli._setup_llm_key) and read when building query/chat agents. None = |
| 274 | +# omit the setting (provider default) — see the DEFAULT_CONFIG note on why |
| 275 | +# Bedrock needs this. |
| 276 | +_runtime_parallel_tool_calls: bool | None = None |
| 277 | + |
| 278 | + |
| 279 | +def set_parallel_tool_calls(value: bool | None) -> None: |
| 280 | + """Set the process-wide agent ``parallel_tool_calls`` setting.""" |
| 281 | + global _runtime_parallel_tool_calls |
| 282 | + _runtime_parallel_tool_calls = value |
| 283 | + |
| 284 | + |
| 285 | +def get_parallel_tool_calls() -> bool | None: |
| 286 | + """Return the process-wide agent ``parallel_tool_calls`` setting (or None).""" |
| 287 | + return _runtime_parallel_tool_calls |
| 288 | + |
| 289 | + |
246 | 290 | def load_config(config_path: Path) -> dict[str, Any]: |
247 | 291 | """Load YAML config from config_path, merged with DEFAULT_CONFIG. |
248 | 292 |
|
|
0 commit comments