Skip to content

fix(azure-sql): wire is_available + extract_params into Azure SQL @tool decorators#707

Merged
yashksaini-coder merged 2 commits intoTracer-Cloud:mainfrom
ebrahim-sameh:fix/azure-sql-tool-injection
Apr 20, 2026
Merged

fix(azure-sql): wire is_available + extract_params into Azure SQL @tool decorators#707
yashksaini-coder merged 2 commits intoTracer-Cloud:mainfrom
ebrahim-sameh:fix/azure-sql-tool-injection

Conversation

@ebrahim-sameh
Copy link
Copy Markdown
Collaborator

Fixes #706

Follow-up to #703 and #704. Third of three SQL tool families sharing the same @tool decorator wiring bug. Completes the cleanup.

Summary

Adds the missing is_available and extract_params callbacks to the @tool(...) decorators on all 5 Azure SQL diagnostic tools. Mirrors the approach already landed for PostgreSQL in #703 and MySQL in #704, and the working MariaDB pattern at app/integrations/mariadb.py:160-176.

What changed

  • Added azure_sql_is_available and azure_sql_extract_params to app/integrations/azure_sql.py.
  • Wired both helpers into the @tool(...) decorator of all 5 Azure SQL tools: current queries, resource stats, server status, slow queries, wait stats.
  • Added 14 unit tests covering both helpers.

Azure SQL integration resolves credentials internally via resolve_azure_sql_config (reading from the store/env), so extract_params only surfaces the three identifying params: server, database, port. Credentials (username, password, driver, encrypt) stay out of tool signatures and are never seen by the LLM.

Scope: 7 files, +155 / -5 lines.

Port-None hardening applied preemptively

Used the or fallback for the port cast that Greptile flagged on #704:

"port": int(az.get("port") or DEFAULT_AZURE_SQL_PORT),

Both missing and explicit-None port values collapse to the default, avoiding a TypeError if a stored integration holds {"port": null}. Covered by a dedicated unit test (test_port_none_collapses_to_default).

Evidence

During the end-to-end audit (make test-rds-synthetic on Gemini 2.5-flash, post-#703/#704 baseline), the agent opportunistically invoked Azure SQL tools on RDS PostgreSQL scenarios, producing 92 Azure SQL TypeError failures across the 15 scenarios:

Tool Before After
get_azure_sql_resource_stats 38 0
get_azure_sql_current_queries 34 0
get_azure_sql_server_status 14 0
get_azure_sql_wait_stats 6 0
Total 92 0

After this fix, the agent no longer attempts Azure SQL tools on unrelated scenarios — the tools correctly report unavailable when no Azure SQL integration is present.

Test plan

Out-of-scope adjacent gap (will file separately)

While verifying, I noticed app/nodes/plan_actions/detect_sources.py has no Azure SQL branch — sources["azure_sql"] is never populated at runtime even when a user configures the integration. This fix makes the tools correctly report unavailable when they shouldn't fire, but they also won't fire when they should until that gap closes. Will file as a follow-up issue after this lands.

… decorators

Same @tool decorator wiring bug the PostgreSQL and MySQL sides fixed in
Tracer-Cloud#703 and Tracer-Cloud#704, now for Azure SQL. All 5 Azure SQL diagnostic tools were
silently failing with TypeError: missing 2 required positional arguments
('server' and 'database') on every agent invocation, because the decorator
was missing the is_available and extract_params callbacks that inject
identifying params from resolved integrations.

Mirror the MariaDB/PostgreSQL/MySQL pattern: add azure_sql_is_available
and azure_sql_extract_params to app/integrations/azure_sql.py, then wire
both into all 5 Azure SQL tools (current queries, resource stats, server
status, slow queries, wait stats).

Azure SQL integration resolves credentials internally via
resolve_azure_sql_config, so extract_params only surfaces the three
identifying params (server, database, port). Credentials stay out of tool
signatures and are never seen by the LLM.

Applied Greptile's port-None hardening preemptively:
int(az.get("port") or DEFAULT_AZURE_SQL_PORT). Covers both missing and
explicit None port values in the resolved integration dict.

Added 14 unit tests covering azure_sql_is_available (6 cases) and
azure_sql_extract_params (8 cases including port-None, port-0,
port-as-string, and credential isolation).

Verified on make test-rds-synthetic (Gemini 2.5-flash): Azure SQL
TypeError failures drop from 92 to 0 across the 15 RDS scenarios.
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 20, 2026

Greptile Summary

This PR completes the three-part fix for the @tool decorator wiring bug across SQL integrations, adding is_available and extract_params callbacks to all 5 Azure SQL diagnostic tools. The implementation faithfully mirrors the PostgreSQL (#703) and MySQL (#704) patterns, with proactive or-fallback hardening for None port and None server/database values in extract_params.

Confidence Score: 5/5

Safe to merge — no functional regressions, all edge cases covered, and prior review concerns fully addressed.

All changes are additive and narrowly scoped. The two new helpers are defensively implemented with or-fallback patterns, the previous str(None) concern is resolved, and 14 targeted unit tests cover every identified edge case. No P1 or P0 findings remain.

No files require special attention.

Important Files Changed

Filename Overview
app/integrations/azure_sql.py Adds azure_sql_is_available and azure_sql_extract_params helpers; uses or "" and or DEFAULT_AZURE_SQL_PORT defensive fallbacks addressing prior str(None) and TypeError concerns.
app/tools/AzureSQLCurrentQueriesTool/init.py Wires is_available and extract_params into @tool decorator; consistent with the pattern established for the other four Azure SQL tools.
app/tools/AzureSQLResourceStatsTool/init.py Adds is_available/extract_params callbacks to @tool decorator; mirrors the current-queries pattern exactly.
app/tools/AzureSQLServerStatusTool/init.py Adds is_available/extract_params callbacks to @tool decorator; no other changes.
app/tools/AzureSQLSlowQueriesTool/init.py Adds is_available/extract_params callbacks to @tool decorator; no other changes.
app/tools/AzureSQLWaitStatsTool/init.py Adds is_available/extract_params callbacks to @tool decorator; no other changes.
tests/integrations/test_azure_sql.py Adds 14 unit tests for azure_sql_is_available and azure_sql_extract_params, covering happy paths, missing fields, None values, port coercion, whitespace stripping, and credential isolation.

Sequence Diagram

sequenceDiagram
    participant Agent as LLM Agent
    participant TD as @tool decorator
    participant IAv as azure_sql_is_available()
    participant EP as azure_sql_extract_params()
    participant Tool as get_azure_sql_*()
    participant Res as resolve_azure_sql_config()
    participant DB as Azure SQL Database

    Agent->>TD: tool invocation request
    TD->>IAv: is_available(sources)
    IAv-->>TD: bool (server && database present?)
    alt not available
        TD-->>Agent: tool skipped / unavailable
    else available
        TD->>EP: extract_params(sources)
        EP-->>TD: {server, database, port}
        TD->>Tool: call(server, database, port, ...)
        Tool->>Res: resolve_azure_sql_config(server, db, port)
        Note over Res: Resolves credentials from store or env — never via LLM
        Res-->>Tool: AzureSQLConfig
        Tool->>DB: DMV query (read-only)
        DB-->>Tool: results
        Tool-->>Agent: diagnostic data
    end
Loading

Reviews (2): Last reviewed commit: "fix(azure-sql): harden server/database c..." | Re-trigger Greptile

Comment thread app/integrations/azure_sql.py Outdated
Address Greptile review on Tracer-Cloud#707: `str(None).strip()` produces the literal
string "None", not an empty string. If a stored integration has
`{"server": null}` or `{"database": null}`, az.get("server", "") returns
None (the default only applies when the key is absent), and
str(None).strip() yields "None" — a misleading non-empty string.

In practice is_available guards against this, but the extract_params
function can be called directly in tests or future code paths and
silently produce garbage. Mirror the `or` pattern already applied to
port, and match the AzureSQLConfig._normalize_server / _normalize_database
validators which use str(value or "").strip().

Added two unit tests covering the None case for both server and database.
Copy link
Copy Markdown
Collaborator

@yashksaini-coder yashksaini-coder left a comment

Choose a reason for hiding this comment

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

Pulled the branch and ran it locally. All 35 tests in tests/integrations/test_azure_sql.py pass, ruff is clean on the changed files, and CI is fully green. The wiring mirrors what already landed for Postgres in #703 and MySQL in #704, so the pattern is well-trodden at this point.

The port=None / server=None / database=None fallbacks are a nice touch, those are exactly the cases that would have bitten us later with int(None) and str(None) gotchas, and each one has its own test.

One thing worth mentioning (you already called it out in the PR description): app/nodes/plan_actions/detect_sources.py has branches for postgresql, mariadb, and mysql but no azure_sql branch, so sources['azure_sql'] never gets populated at runtime. This PR correctly fixes the false-positive case where the tools crash on unrelated scenarios, but the false-negative case where they never fire when Azure SQL is actually configured still needs a separate fix. Not a blocker for #706 since that issue was scoped to the TypeError wiring, but please do open that follow-up right after this lands so Azure SQL tools are actually reachable end to end.

@ebrahim-sameh LGTM, approving.

@yashksaini-coder
Copy link
Copy Markdown
Collaborator

yashksaini-coder commented Apr 20, 2026

Follow-up filed as #711detect_sources.py missing the azure_sql branch so sources['azure_sql'] never gets populated. Paper trail is in place, safe to merge this one now.

@ebrahim-sameh Works for this one, but next time bundle the full feature — tools + detect_sources wiring — into a single PR so we don't ship things that look green but aren't actually reachable.

@yashksaini-coder yashksaini-coder merged commit de97aff into Tracer-Cloud:main Apr 20, 2026
8 checks passed
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.

Azure SQL diagnostic tools fail with TypeError because @tool decorator is missing is_available/extract_params wiring

2 participants