Skip to content

Azure Foundry (v1) support, dependency fix, LangGraph state fix, SearXNG - #4

Open
breakingcircuits1337 wants to merge 4 commits into
mainfrom
deploy/azure-foundry-fixes
Open

Azure Foundry (v1) support, dependency fix, LangGraph state fix, SearXNG#4
breakingcircuits1337 wants to merge 4 commits into
mainfrom
deploy/azure-foundry-fixes

Conversation

@breakingcircuits1337

Copy link
Copy Markdown
Owner

Changes made while deploying KTRT to a Proxmox LXC against a live Azure AI Foundry resource.

Fixes

  • Azure Foundry v1 endpointazure_openai.py now uses AsyncOpenAI pointed at the /openai/v1 OpenAI-compatible surface. Reasoning models (gpt-5.x, Kimi, DeepSeek) use max_completion_tokens and omit temperature (they reject any value ≠ 1); classic models (Mistral) keep max_tokens + temperature.
  • Dependency conflict — the five provider SDKs pinned conflicting httpx ranges, making pip install unresolvable. Moved anthropic/google-generativeai/groq/mistralai/tavily-python to an optional providers extra; base install is just openai. The other adapters are lazily imported only when their model aliases are used.
  • LangGraph ≥1.x stategraph.ainvoke returns a plain dict even for a pydantic state schema; orchestrator.py rehydrates it into MerlinState before attribute access (was AttributeError: 'dict' object has no attribute 'run_status').

Features / hardening

  • SearXNG search adapter (SEARXNG_URL) tried before Tavily/Exa, with tests.
  • Dockerfile — removed apt entirely (lxml/cryptography ship self-contained manylinux wheels), added pip retries/timeout for slow uplinks.
  • docker-compose — no longer publishes redis/postgres ports to the host.

Verified end-to-end: a research quest completes with judge APPROVED, confidence 0.86.

🤖 Generated with Claude Code

…arXNG

- azure_openai: use AsyncOpenAI against the Foundry /openai/v1 endpoint;
  reasoning models use max_completion_tokens and omit temperature (they
  reject temperature != 1), classic models (Mistral) keep max_tokens+temperature
- registry: point role defaults at live Foundry deployments
- pyproject: move anthropic/google/groq/mistral/tavily SDKs to an optional
  'providers' extra to resolve an httpx version conflict (base install = openai)
- research/search: add self-hosted SearXNG adapter (SEARXNG_URL) tried before
  Tavily/Exa, with tests
- orchestrator: rehydrate LangGraph's dict state into MerlinState (LangGraph >=1.x)
- Dockerfile: drop apt (lxml/cryptography wheels are self-contained), add pip
  retries/timeout for slow links
- docker-compose: stop publishing redis/postgres ports to the host

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request optimizes the Docker build process, migrates the Azure OpenAI adapter to the unified Azure AI Foundry endpoint, introduces SearXNG as a search provider, and refactors provider dependencies into an optional group. Feedback focuses on improving the robustness of reasoning model detection in the Azure OpenAI adapter and ensuring that the newly introduced default models are added to the model aliases to prevent runtime errors during model overrides.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +34 to +37
def _is_reasoning_model(self) -> bool:
# Mistral is the only classic (non-reasoning) chat model in use; every
# other configured deployment is a reasoning model.
return "mistral" not in self.model.lower()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Using "mistral" not in self.model.lower() to identify reasoning models is very fragile. If a user configures or overrides the model to use classic models like gpt-4o, gpt-4, or deepseek-v3 (which are common classic models), they will be incorrectly classified as reasoning models. This will force temperature to be omitted (defaulting to 1.0) and use max_completion_tokens, which can cause API errors or severely degrade output quality (especially for tasks requiring low temperature like code generation).

Consider explicitly checking for known reasoning model patterns (e.g., containing gpt-5, kimi, o1, o3, deepseek-v4, r1) or maintaining an explicit list of classic/reasoning models.

Suggested change
def _is_reasoning_model(self) -> bool:
# Mistral is the only classic (non-reasoning) chat model in use; every
# other configured deployment is a reasoning model.
return "mistral" not in self.model.lower()
def _is_reasoning_model(self) -> bool:
model_lower = self.model.lower()
return any(k in model_lower for k in ["gpt-5", "kimi", "o1", "o3", "deepseek-v4", "r1"])

Comment thread app/providers/registry.py
Comment on lines 12 to 29
_DEFAULTS: dict[str, tuple[str, str, str | None]] = {
# Fast factual retrieval — DeepSeek V3.2 is fast and strong at research synthesis
"researcher": ("app.providers.azure_openai", "AzureOpenAIAdapter", "deepseek-v3.2"),
# Evidence weighing — Kimi-K2 Thinking's extended reasoning excels here
"evidence": ("app.providers.azure_openai", "AzureOpenAIAdapter", "kimi-k2-thinking"),
# Strategic planning — GPT-5.4 Pro flagship for complex multi-step reasoning
"planner": ("app.providers.azure_openai", "AzureOpenAIAdapter", "gpt-5.4-pro"),
# Adversarial critique — DeepSeek V3.2-Speciale tuned for deep critical analysis
"critic": ("app.providers.azure_openai", "AzureOpenAIAdapter", "deepseek-v3.2-speciale"),
# Final verdict — GPT-5.4 Pro for authoritative evaluation
"judge": ("app.providers.azure_openai", "AzureOpenAIAdapter", "gpt-5.4-pro"),
# Code generation — GPT-5.1 Codex Max, purpose-built for code
"builder": ("app.providers.azure_openai", "AzureOpenAIAdapter", "gpt-5.1-codex-max"),
# Debugging — GPT-5.1 Codex Max, code-native model
"debugger": ("app.providers.azure_openai", "AzureOpenAIAdapter", "gpt-5.1-codex-max"),
# Deployment names below match the live Azure AI Foundry resource
# (brokencircuits-1334) validated against /openai/v1/chat/completions.
# Fast factual retrieval
"researcher": ("app.providers.azure_openai", "AzureOpenAIAdapter", "DeepSeek-V4-Pro"),
# Evidence weighing — Kimi's extended reasoning excels here
"evidence": ("app.providers.azure_openai", "AzureOpenAIAdapter", "Kimi-K2.6"),
# Strategic planning — GPT-5.5 flagship reasoning
"planner": ("app.providers.azure_openai", "AzureOpenAIAdapter", "gpt-5.5"),
# Adversarial critique — Mistral Large 3 (classic chat model)
"critic": ("app.providers.azure_openai", "AzureOpenAIAdapter", "Mistral-Large-3"),
# Final verdict — GPT-5.5 for authoritative evaluation
"judge": ("app.providers.azure_openai", "AzureOpenAIAdapter", "gpt-5.5"),
# Code generation — GPT-5.5 (gpt-5.3-codex is Responses-API only, unusable here)
"builder": ("app.providers.azure_openai", "AzureOpenAIAdapter", "gpt-5.5"),
# Debugging — GPT-5.5
"debugger": ("app.providers.azure_openai", "AzureOpenAIAdapter", "gpt-5.5"),
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The new default models (DeepSeek-V4-Pro, Kimi-K2.6, gpt-5.5, Mistral-Large-3) are not defined in _MODEL_ALIASES. If a user attempts to explicitly override a role's model using one of these new models (e.g., via azure:gpt-5.5), get_adapter will raise a ValueError because the alias is missing.

Consider adding aliases for these new models to _MODEL_ALIASES to keep them consistent with the defaults.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ea0984f7c7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if self._is_reasoning_model:
# Reasoning models: token budget via max_completion_tokens and
# temperature must stay at the default (1) — omit it entirely.
kwargs["max_completion_tokens"] = max_tokens

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Bump the OpenAI SDK minimum for max_completion_tokens

This new reasoning-model branch is used by every default Azure role except Mistral, but pyproject.toml still permits openai==1.30.0; that SDK's async chat-completions method does not accept max_completion_tokens, so an install satisfying the declared dependency can fail with TypeError before any Azure request is sent. Please raise the minimum OpenAI SDK version to one that supports this parameter, or send it through a compatible extension path.

Useful? React with 👍 / 👎.

api_key=settings.azure_openai_api_key,
azure_endpoint=settings.azure_openai_endpoint,
api_version=settings.azure_openai_api_version,
base_url=settings.azure_openai_endpoint.rstrip("/"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Normalize the Azure v1 base URL before use

The client now appends /chat/completions directly to AZURE_OPENAI_ENDPOINT, but the repo's existing .env.example and README still tell operators to use a root Azure endpoint such as https://your-resource.openai.azure.com/. In that configuration all default Azure roles call https://.../chat/completions instead of the required /openai/v1/chat/completions route, so fresh or existing deployments following the repo config will fail until the suffix is added or validated here.

Useful? React with 👍 / 👎.

joebruce1313 and others added 3 commits July 5, 2026 17:47
Single self-contained static page served by the FastAPI app (FileResponse at
/ui, / redirects there). Submits to /v1/quests same-origin with an X-API-Key
from localStorage, shows an animated eight-knight progress view during the
synchronous wait, then renders the markdown answer with confidence, judge
verdict, debate critiques, and sources.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Stream the LangGraph workflow with a wall-clock deadline (via astream) and keep
the latest state after each super-step. When the budget is exhausted before the
workflow finishes — common in build mode where slow reasoning models make each
planner/debate/judge revision cycle 1-2 minutes — stop after the current node
and return the best draft produced so far (final_answer -> draft_answer ->
implementation_plan -> evidence_report -> research_notes) with status 'partial',
rather than hard-cancelling and returning 'The quest timed out before completion'.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Critic (debate) fix:
- CRITIC prompt now returns a JSON object {"critiques":[{issue,severity,
  recommendation}]} instead of loose ISSUE:/SEVERITY: lines that the reasoning
  models rendered as prose. debate_node parses it via _extract_json, treats an
  empty array as 'plan is sound', and only falls back to raw text on genuine
  parse failure. The judge now sees clean severity-tagged critiques and approves
  in fewer rounds (verified: a research quest approved in one debate round
  instead of looping to the time budget).

SSE streaming:
- New POST /v1/quests/stream returns text/event-stream: a 'node' event as each
  knight finishes, then a 'result' event with the full QuestResponse. Shared
  response-building refactored into _build_response used by both endpoints.
- Web console consumes the stream and lights each knight in real time.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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