File size: 5,853 Bytes
1390f29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#!/usr/bin/env python3
"""
Validate that the configured Azure OpenAI resource supports the Responses
API before enabling USE_RESPONSES_API=true (see .env.example and
agents/analyzer.py / agents/synthesis.py).

Responses API requires a specific minimum preview api-version and has
historically had narrower deployment/region availability than Chat
Completions -- this is a required go/no-go check, not an assumption
(this codebase has been burned before by unverified API-version
assumptions; see AZURE_API_VERSION_FIX.md and CLAUDE.md's version history).

Run: python scripts/validate_responses_api.py
"""
import os
import sys

from dotenv import load_dotenv
from openai import AzureOpenAI

load_dotenv()

# Ordered oldest -> newest. Azure OpenAI's own error message names the exact
# minimum version it requires, so this list only needs to bracket that value
# closely enough to report it -- it is not meant to be exhaustive.
CANDIDATE_VERSIONS = [
    "2024-05-01-preview",
    "2024-08-01-preview",
    "2024-10-01-preview",
    "2024-12-01-preview",
    "2025-01-01-preview",
    "2025-02-01-preview",
    "2025-03-01-preview",
    "2025-04-01-preview",
]


def _try_responses_call(client: AzureOpenAI, deployment: str) -> tuple[bool, str]:
    try:
        response = client.responses.create(
            model=deployment,
            instructions="You are a helpful assistant.",
            input="Say hello in one word.",
            max_output_tokens=20,
        )
        return True, response.output_text
    except Exception as e:
        return False, str(e)


def main() -> bool:
    print("=" * 80)
    print("Validating Azure OpenAI Responses API availability")
    print("=" * 80)
    print()

    endpoint = os.getenv("AZURE_OPENAI_ENDPOINT")
    api_key = os.getenv("AZURE_OPENAI_API_KEY")
    deployment = os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME")
    configured_version = os.getenv("AZURE_OPENAI_API_VERSION", "2024-02-01")

    print(f"Endpoint: {endpoint}")
    print(f"Deployment: {deployment}")
    print(f"Currently configured AZURE_OPENAI_API_VERSION: {configured_version}")
    print()

    # Step 1: does the *currently configured* version work?
    client = AzureOpenAI(api_key=api_key, api_version=configured_version, azure_endpoint=endpoint)
    ok, detail = _try_responses_call(client, deployment)
    if ok:
        print(f"βœ… Responses API works with your CURRENT AZURE_OPENAI_API_VERSION ({configured_version}).")
        print(f"   Sample output: {detail!r}")
        print()
        print("Safe to set USE_RESPONSES_API=true without changing AZURE_OPENAI_API_VERSION.")
        return True

    print(f"❌ Responses API failed at your current API version ({configured_version}):")
    print(f"   {detail[:200]}")
    print()
    print("Probing newer API versions to find the minimum that works...")
    print()

    working_version = None
    for v in CANDIDATE_VERSIONS:
        client = AzureOpenAI(api_key=api_key, api_version=v, azure_endpoint=endpoint)
        ok, detail = _try_responses_call(client, deployment)
        status = "βœ… SUCCESS" if ok else "❌ failed"
        print(f"  {v}: {status}" + ("" if ok else f" ({detail[:120]})"))
        if ok:
            working_version = v
            break

    print()
    if not working_version:
        print("=" * 80)
        print("❌ Responses API is NOT available on this resource/deployment/region")
        print("   at any of the probed API versions.")
        print("   USE_RESPONSES_API=true would fall back to Chat Completions on every")
        print("   call (the code degrades gracefully), but that means no benefit from")
        print("   enabling the flag -- leave it false until this is resolved with Azure.")
        print("=" * 80)
        return False

    print("=" * 80)
    print(f"βœ… Responses API works starting at api-version {working_version}")
    print()
    print("Before enabling USE_RESPONSES_API=true, also confirm the embeddings call")
    print("(rag/embeddings.py) and Chat Completions fallback path still work if you")
    print("bump AZURE_OPENAI_API_VERSION -- both currently read the same env var.")
    print("=" * 80)

    # Step 2: confirm embeddings and Chat Completions still work at the
    # newer version, since rag/embeddings.py reads the SAME
    # AZURE_OPENAI_API_VERSION env var (falls back to "2024-02-01" only if
    # unset) -- bumping it for Responses API is a global change, not scoped
    # to the analyzer/synthesis agents.
    embedding_deployment = os.getenv("AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME")
    client = AzureOpenAI(api_key=api_key, api_version=working_version, azure_endpoint=endpoint)

    if embedding_deployment:
        try:
            resp = client.embeddings.create(input="test", model=embedding_deployment)
            print(f"βœ… Embeddings still work at {working_version} (dim={len(resp.data[0].embedding)})")
        except Exception as e:
            print(f"⚠️  Embeddings FAILED at {working_version}: {str(e)[:150]}")
            print("   Do not bump AZURE_OPENAI_API_VERSION globally without resolving this --")
            print("   consider a separate api_version for rag/embeddings.py instead.")

    try:
        resp = client.chat.completions.create(
            model=deployment,
            messages=[{"role": "user", "content": "Say hi in one word."}],
            temperature=0,
            max_tokens=10,
        )
        print(f"βœ… Chat Completions fallback path still works at {working_version}")
    except Exception as e:
        print(f"⚠️  Chat Completions FAILED at {working_version}: {str(e)[:150]}")

    print()
    print(f"Next step: set AZURE_OPENAI_API_VERSION={working_version} in .env, then")
    print("USE_RESPONSES_API=true.")
    return True


if __name__ == "__main__":
    success = main()
    sys.exit(0 if success else 1)