Skip to content

feat(providers): honor Azure reasoning profiles#199

Closed
kfallah wants to merge 7 commits into
codex/project-capacity-retry-stackedfrom
codex/provider-runtime-stacked-v2
Closed

feat(providers): honor Azure reasoning profiles#199
kfallah wants to merge 7 commits into
codex/project-capacity-retry-stackedfrom
codex/provider-runtime-stacked-v2

Conversation

@kfallah

@kfallah kfallah commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Scope

This branch explored reusable Azure reasoning support:

  • Responses API routing when reasoning is enabled
  • reasoning profile propagation through provider configuration
  • provider-bound replay of signed reasoning state
  • structured tool-call compatibility

Disposition

The branch is stacked on superseded work and is closed without merge. The focused provider changes will be rebuilt on current main.

@greptile-apps

greptile-apps Bot commented Jul 20, 2026

Copy link
Copy Markdown

Greptile Summary

This PR wires Azure reasoning configurations end-to-end through the Azure v1 Responses API rather than Chat Completions, preserving reasoning effort, deployment alias, and usage identity across every call path. The changes also add per-provider tagging of reasoning snapshots so Azure and OpenAI Responses encrypted state cannot be replayed across provider boundaries.

  • Routing: complete() and complete_chat() now dispatch to a new _get_responses_client() (plain OpenAI pointed at <endpoint>/openai/v1/) when reasoning_effort is set; the trusted-endpoint credential boundary (WMH_ENDPOINT_API_KEY vs AZURE_OPENAI_API_KEY) is preserved for both clients.
  • Snapshot isolation: _encode_responses_snapshot / _signed_responses_snapshot are parameterized with snapshot_provider; "azure" and "openai_responses" envelopes are now mutually exclusive at replay.
  • Usage / receipt fidelity: TokenUsage gains extra="allow" for extra billing dimensions, Completion gains system_fingerprint, the Responses→ChatUsage translator passes through total_tokens, input_tokens_details, etc., and receipt validation maps max_output_tokens for Azure reasoning routes.

Confidence Score: 5/5

Safe to merge — all reasoning call paths are well-tested, the trusted-endpoint credential boundary is preserved for both the Chat Completions and Responses clients, and the snapshot isolation between Azure and OpenAI providers is correctly enforced.

Every new code path (text-only reasoning via Responses, structured tool calls, receipt building, cross-provider snapshot rejection, and structured-tool verify) is covered by unit and transport-level tests. The credential security model for untrusted config-controlled endpoints is correctly carried forward to the new Responses client. No logic gaps or unguarded failure modes were found.

No files require special attention. The most complex file, azure_openai.py, has matching transport-level httpx tests that exercise the exact URL, header, and credential behaviour.

Important Files Changed

Filename Overview
wmh/providers/azure_openai.py Core change: adds _get_responses_client() with matching trusted-endpoint credential logic, routes both complete() and complete_chat() through Responses API when reasoning_effort is set, and delegates verify() to verify_via_structured_tool_ping(). Usage bridging and reserved-field guards are correct.
wmh/providers/_responses_common.py Adds snapshot_provider tagging throughout encode/decode path, receipt building via with_raw_response, id/system_fingerprint passthrough, and extra usage field preservation with a guard against reserved alias collision.
wmh/providers/base.py Adds responses_api_version to ProviderConfig (excluded from serialization when None), TokenUsage extra=allow, system_fingerprint on Completion, and verify_via_structured_tool_ping() with paid_request_attempts guard.
wmh/providers/_openai_common.py Refactors complete() to a unified payload dict, adds reasoning_effort parameter, and tightens BadRequestError retry guard. The reasoning_effort parameter is unused by current callers; the addition is forward-compatible.
wmh/providers/receipt.py validate_chat_provider_receipt() now maps max_output_tokens for Azure reasoning configs, matching the field emitted by the Responses API.
wmh/cli/model_roles.py Adds _AZURE_REASONING_RESPONSES_API_VERSION and injects responses_api_version into ProviderConfig when resolving an Azure reasoning role.
wmh/providers/waterfall.py Adds early rejection for Azure reasoning profiles in to_backend() to prevent silent profile stripping when the llm-waterfall Chat Completions backend is used.
wmh/providers/models.py Adds reasoning_efforts to Azure GPT-5.5, GPT-5.4, and GPT-5.4-mini catalog entries.
wmh/providers/tests/azure_openai_test.py Comprehensive test coverage: Responses routing for text and tool-call paths, receipt validation, credential boundary tests, transport-level URL/header checks via httpx.MockTransport, verify() flow, and reserved-field guards.
wmh/providers/_responses_common_test.py Adds cross-provider snapshot isolation test, extra usage field passthrough test, and reserved-alias rejection test.
wmh/cli/model_roles_test.py Confirms that an Azure reasoning role resolves to responses_api_version=v1 while preserving the explicit api_version.
wmh/providers/base_test.py Verifies responses_api_version is excluded from non-Azure configs, rejected outside Azure, and rejected for Azure configs without reasoning_effort.
wmh/providers/waterfall_test.py Confirms to_backend() raises for an Azure reasoning config instead of silently dropping the reasoning profile.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["complete() / complete_chat()"] --> B{"reasoning_effort set?"}
    B -- "No" --> C["_get_client() → AzureOpenAI\nChat Completions endpoint"]
    B -- "Yes" --> D["_get_responses_client() → OpenAI\nbase_url = endpoint/openai/v1/\napi-version=v1"]
    C --> E["_openai_common.complete/complete_chat()"]
    D --> F["_responses_common.complete_chat()\nsnapshot_provider=azure\nallow_sampling=False\nreceipt_provider=azure"]
    F --> G["responses_request()\nreasoning={effort}\nmax_output_tokens"]
    F --> H["with_raw_response.create()\ncaptures apim-request-id"]
    H --> I["responses_response()\npreserves id, system_fingerprint\ntags snapshot with azure"]
    I --> J["build_chat_provider_receipt()\nmax_tokens_field=max_output_tokens"]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["complete() / complete_chat()"] --> B{"reasoning_effort set?"}
    B -- "No" --> C["_get_client() → AzureOpenAI\nChat Completions endpoint"]
    B -- "Yes" --> D["_get_responses_client() → OpenAI\nbase_url = endpoint/openai/v1/\napi-version=v1"]
    C --> E["_openai_common.complete/complete_chat()"]
    D --> F["_responses_common.complete_chat()\nsnapshot_provider=azure\nallow_sampling=False\nreceipt_provider=azure"]
    F --> G["responses_request()\nreasoning={effort}\nmax_output_tokens"]
    F --> H["with_raw_response.create()\ncaptures apim-request-id"]
    H --> I["responses_response()\npreserves id, system_fingerprint\ntags snapshot with azure"]
    I --> J["build_chat_provider_receipt()\nmax_tokens_field=max_output_tokens"]
Loading

Reviews (5): Last reviewed commit: "fix(providers): reject Azure usage alias..." | Re-trigger Greptile

Comment thread wmh/providers/azure_openai.py
Comment thread wmh/providers/base.py
@kfallah kfallah closed this Jul 20, 2026
@kfallah

kfallah commented Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

Closing because this branch is superseded and is not intended for merge. Exact head preserved: 4e2786f. No branch was deleted.

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.

1 participant