@danhachuel/thunderbolt 0.7.64 → 0.7.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -9,6 +9,7 @@ from __future__ import annotations
|
|
|
9
9
|
import hashlib
|
|
10
10
|
import json
|
|
11
11
|
import os
|
|
12
|
+
import re
|
|
12
13
|
import time
|
|
13
14
|
from contextlib import contextmanager
|
|
14
15
|
from dataclasses import dataclass
|
|
@@ -274,6 +275,38 @@ def classify_response(response: Any) -> None:
|
|
|
274
275
|
)
|
|
275
276
|
|
|
276
277
|
|
|
278
|
+
def _validate_llm_json_response(response: Any) -> None:
|
|
279
|
+
"""Reject HTTP-200 LLM responses that cannot satisfy the JSON pool contract."""
|
|
280
|
+
try:
|
|
281
|
+
payload = response if isinstance(response, Mapping) else response.json()
|
|
282
|
+
except (ValueError, TypeError, AttributeError) as exc:
|
|
283
|
+
raise ProviderCallError(
|
|
284
|
+
"Provider LLM devolveu um corpo JSON de transporte inválido.",
|
|
285
|
+
category="payload",
|
|
286
|
+
retryable=False,
|
|
287
|
+
) from exc
|
|
288
|
+
if not isinstance(payload, Mapping):
|
|
289
|
+
raise ProviderCallError("Provider LLM devolveu um payload inválido.", category="payload", retryable=False)
|
|
290
|
+
choices = payload.get("choices") or []
|
|
291
|
+
message = (choices[0] or {}).get("message") if choices and isinstance(choices[0], Mapping) else None
|
|
292
|
+
content = message.get("content") if isinstance(message, Mapping) else None
|
|
293
|
+
if isinstance(content, list):
|
|
294
|
+
content = "".join(str(item.get("text", "")) for item in content if isinstance(item, Mapping))
|
|
295
|
+
text = str(content or "").strip()
|
|
296
|
+
text = re.sub(r"^```(?:json)?\s*", "", text, flags=re.IGNORECASE)
|
|
297
|
+
text = re.sub(r"\s*```$", "", text).strip()
|
|
298
|
+
try:
|
|
299
|
+
parsed = json.loads(text)
|
|
300
|
+
except json.JSONDecodeError as exc:
|
|
301
|
+
raise ProviderCallError(
|
|
302
|
+
"Provider LLM devolveu conteúdo que não é JSON válido.",
|
|
303
|
+
category="payload",
|
|
304
|
+
retryable=False,
|
|
305
|
+
) from exc
|
|
306
|
+
if not isinstance(parsed, dict):
|
|
307
|
+
raise ProviderCallError("Provider LLM devolveu JSON que não é um objecto.", category="payload", retryable=False)
|
|
308
|
+
|
|
309
|
+
|
|
277
310
|
def enabled_cards(settings: Mapping[str, Any], pool: str) -> list[dict[str, Any]]:
|
|
278
311
|
"""Return cards in deterministic priority order; media pools keep active-card preference."""
|
|
279
312
|
if pool == POOL_LLM:
|
|
@@ -473,6 +506,9 @@ def route_llm_json(settings: Mapping[str, Any], system_prompt: str, user_prompt:
|
|
|
473
506
|
}
|
|
474
507
|
if not body["model"]:
|
|
475
508
|
raise ProviderCallError("O cartão LLM não tem modelo configurado.", category="payload", retryable=False)
|
|
476
|
-
|
|
509
|
+
response = requests.post(endpoint, headers=headers, json=body, timeout=120)
|
|
510
|
+
if 200 <= int(getattr(response, "status_code", 0) or 0) < 300:
|
|
511
|
+
_validate_llm_json_response(response.json())
|
|
512
|
+
return response
|
|
477
513
|
|
|
478
514
|
return route_json_request(settings, pool=POOL_LLM, cards=None, request=request)
|
|
@@ -157,6 +157,8 @@ def _connected_account_id(client: Any, user_id: str, toolkit: str, selector: str
|
|
|
157
157
|
if len(matching_items) == 1:
|
|
158
158
|
item = matching_items[0]
|
|
159
159
|
return str(item.get("id") or item.get("nanoid") or "").strip()
|
|
160
|
+
except ComposioUploadError:
|
|
161
|
+
raise
|
|
160
162
|
except Exception:
|
|
161
163
|
# Preserve the original selector so Composio returns its actionable error.
|
|
162
164
|
return value
|
package/package.json
CHANGED