Skip to content

fix(llm): omit parallel_tool_calls on tool-less calls (Azure OpenAI 400) - #951

Open
herman-young-ai wants to merge 1 commit into
usestrix:mainfrom
herman-young-ai:fix/azure-parallel-tool-calls
Open

fix(llm): omit parallel_tool_calls on tool-less calls (Azure OpenAI 400)#951
herman-young-ai wants to merge 1 commit into
usestrix:mainfrom
herman-young-ai:fix/azure-parallel-tool-calls

Conversation

@herman-young-ai

Copy link
Copy Markdown

Problem

make_model_settings sets parallel_tool_calls=False unconditionally, but the parameter is only valid alongside a tool list. Azure OpenAI rejects it outright:

BadRequestError - Invalid value for 'parallel_tool_calls':
'parallel_tool_calls' is only allowed when 'tools' are specified.

The native OpenAI route silently tolerates it, so the divergence only surfaces on Azure deployments — where it currently makes Strix unusable end to end. warm_up_llm fails before any scan starts, so strix --target ... exits 1 with LLM CONNECTION FAILED.

Scope

Four call paths send no tools, and all four break on Azure:

Call site When Impact
warm_up_llm, main model startup blocks the scan (sys.exit(1))
warm_up_llm, dedupe model startup blocks the scan
compaction._summarize context overflow, mid-scan summarization fails
dedupe._dedupe_model_settings per vulnerability report dedupe fails

Only the agent loop in core/runner.py carries tools and is unaffected — so fixing the warm-up alone would still leave a scan that dies the first time context fills or a finding is recorded.

Change

Add an explicit with_tools keyword to make_model_settings, defaulting to the current behaviour, and set it False at the four tool-less call sites. ModelSettings drops None fields, so the parameter is simply not sent rather than sent as false.

No behaviour change on any existing route: every tool-carrying call keeps parallel_tool_calls=False.

Verification

Reproduced and confirmed fixed against a live Azure OpenAI deployment (azure/gpt-5.4, Entra ID auth):

  • Before: warm-up 400s, scan never starts.
  • After: warm-up succeeds, sandbox comes up, root agent registers, scan proceeds.

Two regression tests added in tests/test_inputs.py covering both branches.

ruff check / ruff format / mypy clean on all changed files. Full suite: 628 passed, with one pre-existing order-dependent failure in tests/test_execution.py::test_finish_scan_bypasses_active_agent_guard_after_reserve that reproduces on main without this change (it passes in isolation; tests/test_cost_tracking.py leaves an uninitialised ReportState in the module-level global).

`make_model_settings` set `parallel_tool_calls=False` unconditionally, but the
parameter is only valid alongside a tool list. Azure OpenAI rejects it outright:

    BadRequestError - Invalid value for 'parallel_tool_calls':
    'parallel_tool_calls' is only allowed when 'tools' are specified.

The native OpenAI route silently tolerates it, so the divergence only surfaces
on Azure deployments — where it makes Strix unusable end to end.

Four call paths send no tools, and all four break:

  - warm_up_llm, main model    -> blocks startup (sys.exit(1))
  - warm_up_llm, dedupe model  -> blocks startup
  - compaction._summarize      -> fails on context overflow, mid-scan
  - dedupe._dedupe_model_settings -> fails per vulnerability report

Only the agent loop in core/runner.py carries tools, so fixing the warm-up
alone would still leave a scan that dies the first time context fills or a
finding is recorded.

Add an explicit `with_tools` keyword to `make_model_settings`, defaulting to
the existing behaviour, and set it False at the four tool-less call sites.
`ModelSettings` drops None fields, so the parameter is simply not sent.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR prevents Azure OpenAI from receiving parallel_tool_calls on requests that do not provide tools.

  • Adds a with_tools switch to model-settings construction while preserving existing behavior for agent calls that carry tools.
  • Marks warm-up, deduplication, and compaction requests as tool-less.
  • Adds regression coverage for both tool-bearing and tool-less settings.

Confidence Score: 5/5

The PR appears safe to merge, with every current tool-less model request updated consistently and the tool-bearing agent path preserving its existing setting.

All four changed production callers issue requests without tools and now omit the Azure-incompatible parameter, while the only remaining default path constructs agents with a nonempty tool list.

Important Files Changed

Filename Overview
strix/core/inputs.py Adds the with_tools setting and omits parallel_tool_calls for tool-less requests while retaining the existing default for agent calls.
strix/interface/main.py Correctly marks both startup warm-up requests as tool-less, matching their empty tool lists.
strix/llm/compaction.py Correctly omits the tool-specific setting from tool-less context summarization requests.
strix/report/dedupe.py Correctly omits the tool-specific setting from the text-only deduplication judge.
tests/test_inputs.py Covers both branches of the new settings behavior by asserting false for tool-bearing calls and None for tool-less calls.

Reviews (1): Last reviewed commit: "fix(llm): omit parallel_tool_calls on to..." | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants