Merge pull request #32 from hjertefolger/fix/azure-call-id-and-fstring

fix(azure): normalize tool call IDs and f-string with backslashes
This commit is contained in:
Gabriel Gavilan
2025-09-15 12:12:40 +02:00
committed by GitHub
2 changed files with 44 additions and 7 deletions
+9 -5
View File
@@ -89,11 +89,15 @@ class AzureAdapter:
"azure_response": resp_content,
"request_body": body,
}
error_message = f"""\nCheck "azure_response" for the error details:
\t{json.dumps(report, indent=4).replace("\n", "\n\t")}
If the issue persists, report it to:
\thttps://github.com/gabrii/Cursor-Azure-GPT-5/issues
Including all the details above"""
# Precompute pretty JSON to avoid backslashes inside f-string expressions
report_pretty = json.dumps(report, indent=4).replace("\n", "\n\t")
error_message = (
'\nCheck "azure_response" for the error details:\n'
f"\t{report_pretty}\n"
"If the issue persists, report it to:\n"
"\thttps://github.com/gabrii/Cursor-Azure-GPT-5/issues\n"
"Including all the details above"
)
console.rule(f"[red]Request failed with status code {resp.status_code}[/red]")
console.print(error_message)
return Response(
+35 -2
View File
@@ -28,6 +28,29 @@ class RequestAdapter:
self.adapter = adapter # AzureAdapter instance for shared config/env
# ---- Helpers (kept local to minimize cross-module coupling) ----
def _normalize_call_id(
self, original: Optional[str], mapping: Dict[str, str]
) -> Optional[str]:
"""Return a <=64 char stable call_id.
- Azure Responses API limits function call ids to 64 chars.
- Cursor/OpenAI tool_call ids may exceed that. We map any long ids
to a deterministic 64-char hex digest for this request, while
preserving pairing between function_call and function_call_output.
"""
if not original:
return original
if len(original) <= 64:
# Still ensure consistent mapping if we've seen it before
return mapping.get(original, original)
if original in mapping:
return mapping[original]
import hashlib
norm = hashlib.sha256(original.encode("utf-8")).hexdigest() # 64 hex chars
mapping[original] = norm
return norm
def _parse_json_body(self, req: Request, body: bytes) -> Optional[Any]:
if not body:
return None
@@ -73,6 +96,9 @@ class RequestAdapter:
return "\n".join([p for p in parts if p])
return json.dumps(c, ensure_ascii=False)
# Maintain stable mapping of long tool call ids within a single request
call_id_map: Dict[str, str] = {}
for m in messages:
role = m.get("role")
c = m.get("content")
@@ -83,11 +109,16 @@ class RequestAdapter:
continue
# For user/assistant/tools as inputs
if role == "tool":
# Map tool outputs back to a normalized call id
original_tool_call_id = m.get("tool_call_id")
norm_call_id = self._normalize_call_id(
original_tool_call_id, call_id_map
)
item = {
"type": "function_call_output",
"output": content_to_text(c),
"status": "completed",
"call_id": m.get("tool_call_id"),
"call_id": norm_call_id,
}
input_items.append(item)
else:
@@ -106,11 +137,13 @@ class RequestAdapter:
if tool_calls := m.get("tool_calls"):
for tool_call in tool_calls:
function = tool_call.get("function", {})
original_id = tool_call.get("id")
norm_call_id = self._normalize_call_id(original_id, call_id_map)
item = {
"type": "function_call",
"name": function.get("name"),
"arguments": function.get("arguments"),
"call_id": tool_call.get("id"),
"call_id": norm_call_id,
}
input_items.append(item)