feat(deployments): add environment variable overrides for IBM IAM URLs (wxO) (#12373)

* fix: harden verify_credentials error handling and add dev IAM URL overrides
Move authenticator construction inside try/except to catch SDK validation
errors directly from the constructor instead of calling validate() twice.
Add env var overrides (IBM_IAM_MCSP_DEV_URL_OVERRIDE, IBM_IAM_DEV_URL_OVERRIDE)
for non-production wxO environments that use different IAM endpoints.
Expand test coverage for constructor failures, 403 responses, and
empty/whitespace env var fallback behavior.

* improve docs

* tighten up docs

* fix typo

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes (attempt 2/3)

---------

Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
Hamza Rashid
2026-03-30 16:13:15 +00:00
committed by GitHub
co-authored by Hanzo Dev
parent 7ff7ba77a0
commit e0232518b1
36 changed files with 325 additions and 189 deletions
@@ -661,7 +661,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -622,7 +622,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -538,7 +538,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -1037,7 +1037,7 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "bs4",
@@ -2273,7 +2273,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -416,7 +416,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -1319,7 +1319,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -130,7 +130,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -674,7 +674,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -1755,7 +1755,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "lfx",
@@ -456,7 +456,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -1124,7 +1124,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -2084,7 +2084,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 3
@@ -342,7 +342,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -1192,7 +1192,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 3
@@ -259,7 +259,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -545,7 +545,7 @@
},
{
"name": "cryptography",
"version": "43.0.3"
"version": "46.0.6"
},
{
"name": "langchain_chroma",
@@ -452,7 +452,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -1204,7 +1204,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 3
@@ -685,7 +685,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -965,7 +965,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -1245,7 +1245,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -425,7 +425,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -886,7 +886,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -1186,7 +1186,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 3
@@ -1757,7 +1757,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "pandas",
@@ -512,7 +512,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -812,7 +812,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 3
@@ -2338,7 +2338,7 @@
"dependencies": [
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "lfx",
@@ -396,7 +396,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -1251,7 +1251,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 3
@@ -328,7 +328,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -928,7 +928,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -420,7 +420,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -1620,7 +1620,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 3
@@ -1768,7 +1768,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -2823,7 +2823,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 3
@@ -372,7 +372,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -628,7 +628,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -405,7 +405,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -905,7 +905,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 3
@@ -571,7 +571,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -952,7 +952,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 3
@@ -370,7 +370,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 3
@@ -958,7 +958,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 3
@@ -2403,7 +2403,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 3
@@ -2976,7 +2976,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -3791,7 +3791,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -652,7 +652,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -951,7 +951,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 3
@@ -1840,7 +1840,7 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "bs4",
@@ -160,7 +160,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -392,7 +392,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -976,7 +976,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -1301,7 +1301,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 3
@@ -826,7 +826,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -1108,7 +1108,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -3581,7 +3581,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -503,7 +503,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -1679,7 +1679,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 3
@@ -2262,7 +2262,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 3
@@ -2845,7 +2845,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 3
@@ -706,7 +706,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -1042,7 +1042,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -1588,7 +1588,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -2659,7 +2659,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "lfx",
@@ -3570,7 +3570,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "lfx",
@@ -513,7 +513,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 3
@@ -1454,7 +1454,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -2,6 +2,7 @@
from __future__ import annotations
import os
import re
from enum import Enum
@@ -25,10 +26,43 @@ WXO_TRANSLATE = str.maketrans({" ": "_", "-": "_"})
ERROR_PREFIX = "An error occurred while"
ERROR_SUFFIX_IN = "in Watsonx Orchestrate."
# The IAM endpoints below generate
# authentication tokens for production
# wxO environments and are documented publicly:
# Documentation: https://www.ibm.com/docs/en/watsonx/watson-orchestrate/base?topic=api-generating-jwt-aws
IBM_IAM_MCSP_PRODUCTION_URL = "https://iam.platform.saas.ibm.com"
# Documentation: https://www.ibm.com/docs/en/watsonx/watson-orchestrate/base?topic=api-generating-access-token-cloud
IBM_IAM_PRODUCTION_URL = "https://iam.cloud.ibm.com"
# Non-production wxO environments use different
# IAM URLs, which are not documented publicly
# and must not be used publicly in plain text.
class WxOAuthURL(str, Enum):
MCSP = "https://iam.platform.saas.ibm.com"
IBM_IAM = "https://iam.cloud.ibm.com"
"""IAM token endpoint URLs used to authenticate against Watsonx Orchestrate.
Non-production wxO environments use a different IAM URL than
production environments. These cannot be exposed in plain text so
environment variables are surfaced instead.
Set ``IBM_IAM_MCSP_DEV_URL_OVERRIDE`` for AWS wxO environments,
``IBM_IAM_DEV_URL_OVERRIDE`` for IBM Cloud.
When unset, the production URLs are used
("https://iam.platform.saas.ibm.com" and "https://iam.cloud.ibm.com" respectively).
Please note:
- The stated environment variables are solely for
internal testing and development purposes,
and must be left unset when shipping Langflow
for general availability.
- The IAM URLs cannot be changed during runtime,
and Langflow does not dynamically resolve the IAM URL based on
the environment of a given wxO tenant. It simply uses the
default production IAM URLs, or the environment variable
overrides if set.
"""
MCSP = os.getenv("IBM_IAM_MCSP_DEV_URL_OVERRIDE", "").strip() or IBM_IAM_MCSP_PRODUCTION_URL
IBM_IAM = os.getenv("IBM_IAM_DEV_URL_OVERRIDE", "").strip() or IBM_IAM_PRODUCTION_URL
class ErrorPrefix(str, Enum):
@@ -13,6 +13,7 @@ from lfx.services.adapters.deployment.base import BaseDeploymentService
from lfx.services.adapters.deployment.exceptions import (
AuthenticationError,
AuthorizationError,
AuthSchemeError,
DeploymentConflictError,
DeploymentError,
DeploymentNotFoundError,
@@ -776,27 +777,35 @@ class WatsonxOrchestrateDeploymentService(BaseDeploymentService):
raise DeploymentError(message=msg, error_code="deployment_error")
provider_creds = verify_slot.parse(payload.provider_data)
authenticator = get_authenticator(
instance_url=payload.base_url,
api_key=provider_creds.api_key,
malformed_credentials_msg = (
"Provider credentials are malformed. Please ensure the URL and API key are correctly formatted."
)
# AuthSchemeError bubbles up from get_authenticator for unrecognised URLs
try:
authenticator.validate()
authenticator = get_authenticator(
instance_url=payload.base_url,
api_key=provider_creds.api_key,
)
except ValueError as exc:
raise InvalidContentError(
message=(
"Provider credentials are malformed. Please ensure the URL and API key are correctly formatted."
),
message=malformed_credentials_msg,
cause=exc,
) from exc
except AuthSchemeError:
raise
except Exception as exc:
raise DeploymentError(
message="Credential verification failed unexpectedly.",
error_code="deployment_error",
cause=exc,
) from exc
try:
await asyncio.to_thread(authenticator.token_manager.get_token)
except ApiException as exc:
# Log the raw provider detail for diagnostics but do not
# propagate it — the response body could echo secrets.
# Log only the status code for diagnostics and avoid exposing
# provider response details that could include sensitive values.
logger.error( # noqa: TRY400
"Credential verification failed (status=%s)",
exc.status_code,
@@ -65,6 +65,12 @@ WxOCredentials = importlib.import_module(
).WxOCredentials
def _reload_wxo_auth_modules():
constants_module = importlib.import_module("langflow.services.adapters.deployment.watsonx_orchestrate.constants")
importlib.reload(constants_module)
return importlib.reload(client_module)
def _tool_refs(*tool_ids: str) -> list[dict[str, str]]:
"""Build WatsonxToolRefBinding dicts for test data."""
return [{"source_ref": f"fv-{tid}", "tool_id": tid} for tid in tool_ids]
@@ -3155,6 +3161,58 @@ def test_get_authenticator_unknown_url():
get_authenticator("https://example.com", "test-key")
def test_get_authenticator_uses_default_iam_urls_when_unset(monkeypatch):
try:
with monkeypatch.context() as context:
context.delenv("IBM_IAM_MCSP_DEV_URL_OVERRIDE", raising=False)
context.delenv("IBM_IAM_DEV_URL_OVERRIDE", raising=False)
reloaded_client_module = _reload_wxo_auth_modules()
iam_auth = reloaded_client_module.get_authenticator("https://api.region-foobar.cloud.ibm.com", "test-key")
mcsp_auth = reloaded_client_module.get_authenticator("https://api.wxo.ibm.com", "test-key")
assert iam_auth.token_manager.url == "https://iam.cloud.ibm.com"
assert mcsp_auth.token_manager.url == "https://iam.platform.saas.ibm.com"
finally:
_reload_wxo_auth_modules()
@pytest.mark.parametrize("env_value", ["", " "])
def test_get_authenticator_empty_or_whitespace_env_var_falls_through_to_default(monkeypatch, env_value):
try:
with monkeypatch.context() as context:
context.setenv("IBM_IAM_MCSP_DEV_URL_OVERRIDE", env_value)
context.setenv("IBM_IAM_DEV_URL_OVERRIDE", env_value)
reloaded_client_module = _reload_wxo_auth_modules()
iam_auth = reloaded_client_module.get_authenticator("https://api.region-foobar.cloud.ibm.com", "test-key")
mcsp_auth = reloaded_client_module.get_authenticator("https://api.wxo.ibm.com", "test-key")
assert iam_auth.token_manager.url == "https://iam.cloud.ibm.com"
assert mcsp_auth.token_manager.url == "https://iam.platform.saas.ibm.com"
finally:
_reload_wxo_auth_modules()
def test_get_authenticator_uses_override_iam_urls(monkeypatch):
custom_mcsp_url = " https://iam.platform.saas.ibm.com/custom-mcsp "
custom_iam_url = " https://iam.cloud.ibm.com/custom-iam "
try:
with monkeypatch.context() as context:
context.setenv("IBM_IAM_MCSP_DEV_URL_OVERRIDE", custom_mcsp_url)
context.setenv("IBM_IAM_DEV_URL_OVERRIDE", custom_iam_url)
reloaded_client_module = _reload_wxo_auth_modules()
iam_auth = reloaded_client_module.get_authenticator("https://api.region-foobar.cloud.ibm.com", "test-key")
mcsp_auth = reloaded_client_module.get_authenticator("https://api.wxo.ibm.com", "test-key")
assert iam_auth.token_manager.url == custom_iam_url.strip()
assert mcsp_auth.token_manager.url == custom_mcsp_url.strip()
finally:
_reload_wxo_auth_modules()
@pytest.mark.anyio
async def test_get_provider_clients_uses_request_scoped_context_memoization(monkeypatch):
resolve_calls = 0
@@ -4744,9 +4802,6 @@ async def test_verify_credentials_success(monkeypatch):
class FakeAuthenticator:
token_manager = FakeTokenManager()
def validate(self):
pass
monkeypatch.setattr(
service_module,
"get_authenticator",
@@ -4776,9 +4831,6 @@ async def test_verify_credentials_invalid_key_raises(monkeypatch):
class FailingAuthenticator:
token_manager = FakeTokenManager()
def validate(self):
pass
monkeypatch.setattr(
service_module,
"get_authenticator",
@@ -4795,27 +4847,17 @@ async def test_verify_credentials_invalid_key_raises(monkeypatch):
@pytest.mark.anyio
async def test_verify_credentials_malformed_key_raises(monkeypatch):
"""verify_credentials raises InvalidContentError when local validation fails."""
async def test_verify_credentials_malformed_key_from_authenticator_constructor_raises():
"""verify_credentials raises InvalidContentError when authenticator creation fails validation."""
from lfx.services.adapters.deployment.exceptions import InvalidContentError
from lfx.services.adapters.deployment.schema import VerifyCredentials
class MalformedAuthenticator:
def validate(self):
msg = "api key contains bad characters"
raise ValueError(msg)
monkeypatch.setattr(
service_module,
"get_authenticator",
lambda **_kwargs: MalformedAuthenticator(),
)
svc = WatsonxOrchestrateDeploymentService(settings_service=DummySettingsService())
payload = VerifyCredentials(
base_url="https://api.us-south.wxo.cloud.ibm.com",
provider_data={"api_key": "bad\x00key"}, # pragma: allowlist secret
provider_data={"api_key": "{bad-key}"}, # pragma: allowlist secret
)
with pytest.raises(InvalidContentError, match="malformed"):
await svc.verify_credentials(user_id="u1", payload=payload)
@@ -4850,6 +4892,60 @@ async def test_verify_credentials_bad_auth_scheme_raises():
await svc.verify_credentials(user_id="u1", payload=payload)
@pytest.mark.anyio
async def test_verify_credentials_authenticator_construction_unexpected_error(monkeypatch):
"""verify_credentials raises DeploymentError when get_authenticator() throws unexpectedly."""
from lfx.services.adapters.deployment.exceptions import DeploymentError
from lfx.services.adapters.deployment.schema import VerifyCredentials
def _exploding_authenticator(**_kwargs):
msg = "something unexpected"
raise RuntimeError(msg)
monkeypatch.setattr(
service_module,
"get_authenticator",
_exploding_authenticator,
)
svc = WatsonxOrchestrateDeploymentService(settings_service=DummySettingsService())
payload = VerifyCredentials(
base_url="https://api.us-south.wxo.cloud.ibm.com",
provider_data={"api_key": "some-key"}, # pragma: allowlist secret
)
with pytest.raises(DeploymentError, match="failed unexpectedly"):
await svc.verify_credentials(user_id="u1", payload=payload)
@pytest.mark.anyio
async def test_verify_credentials_forbidden_key_raises(monkeypatch):
"""verify_credentials raises AuthorizationError when provider returns 403."""
from ibm_cloud_sdk_core import ApiException
from lfx.services.adapters.deployment.exceptions import AuthorizationError
from lfx.services.adapters.deployment.schema import VerifyCredentials
class FakeTokenManager:
def get_token(self):
raise ApiException(403, message="forbidden")
class ForbiddenAuthenticator:
token_manager = FakeTokenManager()
monkeypatch.setattr(
service_module,
"get_authenticator",
lambda **_kwargs: ForbiddenAuthenticator(),
)
svc = WatsonxOrchestrateDeploymentService(settings_service=DummySettingsService())
payload = VerifyCredentials(
base_url="https://api.us-south.wxo.cloud.ibm.com",
provider_data={"api_key": "some-key"}, # pragma: allowlist secret
)
with pytest.raises(AuthorizationError, match="Credential verification"):
await svc.verify_credentials(user_id="u1", payload=payload)
@pytest.mark.anyio
async def test_verify_credentials_provider_unreachable(monkeypatch):
"""verify_credentials raises DeploymentError on network failure."""
@@ -4864,9 +4960,6 @@ async def test_verify_credentials_provider_unreachable(monkeypatch):
class UnreachableAuthenticator:
token_manager = FakeTokenManager()
def validate(self):
pass
monkeypatch.setattr(
service_module,
"get_authenticator",
+85 -85
View File
@@ -304,7 +304,7 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "bs4",
@@ -312,11 +312,11 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "markdown",
"version": "3.7"
"version": "3.10.2"
},
{
"name": "pydantic",
@@ -481,11 +481,11 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -622,11 +622,11 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -791,11 +791,11 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -932,11 +932,11 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -1102,11 +1102,11 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -1273,11 +1273,11 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -1466,11 +1466,11 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -3588,7 +3588,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 2
@@ -5712,7 +5712,7 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "pydantic",
@@ -6062,7 +6062,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -12786,7 +12786,7 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "langchain_openai",
@@ -13162,7 +13162,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "lfx",
@@ -56096,7 +56096,7 @@
"dependencies": [
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "lfx",
@@ -56104,7 +56104,7 @@
},
{
"name": "cuga",
"version": "0.2.9"
"version": "0.2.10"
}
],
"total_dependencies": 3
@@ -57738,7 +57738,7 @@
},
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "bs4",
@@ -57984,7 +57984,7 @@
},
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "bs4",
@@ -58305,7 +58305,7 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "bs4",
@@ -58685,7 +58685,7 @@
},
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "bs4",
@@ -59621,7 +59621,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "lfx",
@@ -60045,7 +60045,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "lfx",
@@ -60920,11 +60920,11 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -62120,7 +62120,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "lfx",
@@ -62786,7 +62786,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -64872,7 +64872,7 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "pydantic",
@@ -66748,7 +66748,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "langchain_elasticsearch",
@@ -68795,7 +68795,7 @@
"dependencies": [
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "metaphor_python",
@@ -69256,7 +69256,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -69944,7 +69944,7 @@
},
{
"name": "cryptography",
"version": "43.0.3"
"version": "46.0.6"
},
{
"name": "langchain_chroma",
@@ -70195,7 +70195,7 @@
},
{
"name": "cryptography",
"version": "43.0.3"
"version": "46.0.6"
},
{
"name": "langchain_chroma",
@@ -70555,7 +70555,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "pandas",
@@ -73620,7 +73620,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -73973,7 +73973,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "langchain_google_community",
@@ -74126,7 +74126,7 @@
"dependencies": [
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "langchain_google_genai",
@@ -74658,7 +74658,7 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "pydantic",
@@ -75839,11 +75839,11 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -76022,11 +76022,11 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -76188,7 +76188,7 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "langchain_community",
@@ -77655,7 +77655,7 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "lfx",
@@ -78150,7 +78150,7 @@
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
"version": "3.11.7"
},
{
"name": "fastapi",
@@ -81665,7 +81665,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "lfx",
@@ -82332,7 +82332,7 @@
"dependencies": [
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "lfx",
@@ -82960,7 +82960,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "lfx",
@@ -84839,7 +84839,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "lfx",
@@ -85237,7 +85237,7 @@
"dependencies": [
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "langchain_experimental",
@@ -85805,7 +85805,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "lfx",
@@ -86616,7 +86616,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "lfx",
@@ -91635,7 +91635,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
}
],
"total_dependencies": 3
@@ -92945,7 +92945,7 @@
"dependencies": [
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "lfx",
@@ -94347,11 +94347,11 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -94624,7 +94624,7 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "langchain_openai",
@@ -95582,7 +95582,7 @@
"dependencies": [
{
"name": "pypdf",
"version": "6.6.2"
"version": "6.9.2"
},
{
"name": "lfx",
@@ -99682,7 +99682,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "lfx",
@@ -102677,7 +102677,7 @@
"dependencies": [
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "lfx",
@@ -105247,7 +105247,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "lfx",
@@ -107193,7 +107193,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -108264,7 +108264,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -108390,7 +108390,7 @@
"dependencies": [
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "lfx",
@@ -108580,7 +108580,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -108803,7 +108803,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -109094,7 +109094,7 @@
"dependencies": [
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "langchain_experimental",
@@ -109260,7 +109260,7 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "langchain_classic",
@@ -109268,7 +109268,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -109451,7 +109451,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -109690,7 +109690,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -109912,7 +109912,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -110310,7 +110310,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -110651,7 +110651,7 @@
"dependencies": [
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -116335,7 +116335,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "lfx",
@@ -116780,7 +116780,7 @@
"dependencies": [
{
"name": "requests",
"version": "2.32.5"
"version": "2.33.0"
},
{
"name": "langchain_openai",
@@ -117164,7 +117164,7 @@
},
{
"name": "langchain_core",
"version": "1.2.20"
"version": "1.2.22"
},
{
"name": "pydantic",
@@ -118890,6 +118890,6 @@
"num_components": 360,
"num_modules": 97
},
"sha256": "5740df4879d7590f10593825698265eefbded28feb020373f66e74a6dd83374b",
"sha256": "6acfb292943005c8b3a887f4d4ae6cb41b725e05335e638e035d791ab4d3c7dc",
"version": "0.4.0"
}