judgevet.adapters.outbound.http

Status: draft.

judgevet.adapters.outbound.http

HTTP outbound adapter with optional state redaction, gateway metadata and retries.

Error handling

The API error detail field is polymorphic:

  • Array for validation errors (422): [{"type", "loc", "msg", "input"}]
  • Object for auth errors (401/403): {"error_type", "message"}
  • Absent, malformed or unrecognised: falls back to status line alone.

The input key in validation errors contains the caller's request payload and is deliberately excluded from error messages to avoid leaking user data.

Helper functions
  • _build_payload: Build the request payload.
  • _parse_body: Parse the response body into a SystemOneResponse.
  • _translate_status_error: Translate HTTP status errors to JevError subclasses.
  • _translate_request_error: Translate request errors to JevServiceError.
  • _convert_question_to_wire: Convert a Question object to its wire dict.

Examples:

from judgevet.adapters.outbound.http import HTTPSystemOneAdapter
from judgevet.domain.questions import Noul
from judgevet.domain.response import SystemOneResponse

adapter = HTTPSystemOneAdapter(api_key="your-api-key")
try:
    response: SystemOneResponse = adapter.system_one(
        state="Your content here",
        questions={
            "q1": Noul(instructions="Is this correct?"),
        },
    )
    print(response)
    print(response.model)
    print(response.answers)
finally:
    adapter.close()
See Also

Raises:

Type Description
JevAuthError

If the API returns 401 or 403.

JevRateLimitError

If the API returns 429 (rate limit exceeded).

JevRequestError

If the API returns 4xx (except 401/403, 429).

JevServiceError

If the API returns 5xx or a transport error occurs.

JevResponseError

If the API returns 2xx with unparseable body.

Async adapters

The async adapter provides aclose(), __aenter__, and __aexit__ for lifecycle management. It does NOT provide sync names (close, __enter__, __exit__) because calling self._client.aclose() without await would return an un-awaited coroutine and close nothing silently. An AttributeError is the better failure.

AsyncHTTPSystemOneAdapter

Async HTTP adapter with explicit network configuration and bounded retries.

This class satisfies AsyncSystemOnePort structurally without importing it. See: https://api.typesafe.ai/v1/systemone

Note

This adapter provides aclose(), __aenter__, and __aexit__ for lifecycle management. It does NOT provide sync names (close, __enter__, __exit__) because calling self._client.aclose() without await would return an un-awaited coroutine and close nothing silently. An AttributeError is the better failure.

Attributes:

Name Type Description
api_key str | None

The TypeSafe API key.

base_url str

The API base URL.

default_model str

The default model to use.

Raises:

Type Description
JevAuthError

If the API returns 401 or 403.

JevRateLimitError

If the API returns 429 (rate limit exceeded).

JevRequestError

If the API returns 4xx (except 401/403, 429).

JevServiceError

If the API returns 5xx or a transport error occurs.

JevResponseError

If the API returns 2xx with unparseable body.

Error details

Validation errors (422) include an array of error objects. Each object's input key contains the caller's request payload. The adapter deliberately omits this key from the error message.

Auth errors (401/403) return an object with error_type and message fields.

Unknown detail shapes fall back to the HTTP status line alone.

Transport errors (timeouts, connection failures) are mapped to JevServiceError with status_code=None and retryable=True. A retryable=True timeout is advisory: retrying a read timeout may be double-billed because the service may still be processing the first attempt.

Examples:

async def main() -> SystemOneResponse:
    adapter = AsyncHTTPSystemOneAdapter(api_key="your-api-key")
    try:
        response: SystemOneResponse = await adapter.system_one(
            state="Your content here",
            questions={
                "q1": {"type": "noul", "instructions": "Is this correct?"}
            },
        )
        print(response)
        return response
    finally:
        await adapter.aclose()

__aenter__() async

Enter async context manager.

__aexit__(exc_type, exc_val, exc_tb) async

Exit async context manager.

__init__(api_key=None, base_url=None, default_model='jev-latest', transport=None, timeout_seconds=30.0, *, retry=None, network=None, **options)

Initialize the async HTTP adapter.

Parameters:

Name Type Description Default
api_key str | None

TypeSafe API key.

None
base_url str | None

API base URL. Defaults to https://api.typesafe.ai.

None
default_model str

Default model to use. Defaults to jev-latest.

'jev-latest'
transport AsyncBaseTransport | None

Optional httpx async transport for testing. Defaults to None.

None
timeout_seconds float

Read timeout in seconds. Defaults to 30.0.

30.0
retry RetryPolicy | None

Validated retry policy. None preserves one attempt.

None
network NetworkConfig | None

Proxy and TLS options. None retains HTTPX defaults.

None

Other Parameters:

Name Type Description
gateway GatewayConfig | None

Explicit authentication and metadata. Omission retains direct defaults.

redactor StateRedactor | None

Synchronous caller-owned state transformation. Omission preserves state and the existing serialization path.

Raises:

Type Description
ValueError

If the key is absent, timeout is nonpositive, or the CA bundle cannot load.

aclose() async

Close the HTTP async client.

system_one(state, questions, model=None, *, metadata=None) async

Prepare optional redaction once, then await bounded HTTP attempts.

Parameters:

Name Type Description Default
state str | dict[str, Any] | list[Any]

The content to evaluate.

required
questions Mapping[str, Any]

Mapping of question names to question definitions.

required
model str | None

Model name override.

None
metadata RequestMetadata | None

Explicit per-call headers overriding gateway defaults.

None

Returns:

Type Description
SystemOneResponse

Typed SystemOneResponse with parsed answer objects.

Raises:

Type Description
ValueError

If metadata or redacted JSON violates input rules.

Exception

If a configured redactor or its input copy fails before IO.

JevAuthError

If the API returns 401 or 403.

JevRateLimitError

If the API returns 429 (rate limit exceeded).

JevRequestError

If the API returns 4xx (except 401/403, 429).

JevServiceError

If the API returns 5xx or a transport error occurs.

JevResponseError

If the API returns 2xx with unparseable body.

Error details

Validation errors (422) include an array of error objects. Each object's input key contains the caller's request payload. The adapter deliberately omits this key from the error message.

Auth errors (401/403) return an object with error_type and message fields.

Unknown detail shapes fall back to the HTTP status line alone.

Transport errors (timeouts, connection failures) are mapped to JevServiceError with status_code=None and retryable=True. A retryable=True timeout is advisory: retrying a read timeout may be double-billed because the service may still be processing the first attempt.

HTTPSystemOneAdapter

HTTP adapter with explicit network configuration and opt-in retries.

This class satisfies SystemOnePort structurally without importing it. See: https://api.typesafe.ai/v1/systemone

See: https://api.typesafe.ai/v1/systemone

Attributes:

Name Type Description
api_key str | None

The TypeSafe API key.

base_url str

The API base URL.

default_model str

The default model to use.

Raises:

Type Description
JevAuthError

If the API returns 401 or 403.

JevRateLimitError

If the API returns 429 (rate limit exceeded).

JevRequestError

If the API returns 4xx (except 401/403, 429).

JevServiceError

If the API returns 5xx or a transport error occurs.

JevResponseError

If the API returns 2xx with unparseable body.

Error details

Validation errors (422) include an array of error objects. Each object's input key contains the caller's request payload. The adapter deliberately omits this key from the error message.

Auth errors (401/403) return an object with error_type and message fields.

Unknown detail shapes fall back to the HTTP status line alone.

Transport errors (timeouts, connection failures) are mapped to JevServiceError with status_code=None and retryable=True. A retryable=True timeout is advisory: retrying a read timeout may be double-billed because the service may still be processing the first attempt.

Examples:

adapter = HTTPSystemOneAdapter(api_key="your-api-key")
try:
    response: SystemOneResponse = adapter.system_one(
        state="Your content here",
        questions={"q1": {"type": "noul", "instructions": "Is this correct?"}},
    )
    print(response)
finally:
    adapter.close()

__enter__()

Enter context manager.

__exit__(exc_type, exc_val, exc_tb)

Exit context manager.

__init__(api_key=None, base_url=None, default_model='jev-latest', transport=None, timeout_seconds=30.0, *, retry=None, network=None, **options)

Initialize the HTTP adapter.

Parameters:

Name Type Description Default
api_key str | None

TypeSafe API key.

None
base_url str | None

API base URL. Defaults to https://api.typesafe.ai.

None
default_model str

Default model to use. Defaults to jev-latest.

'jev-latest'
transport BaseTransport | None

Optional httpx transport for testing. Defaults to None.

None
timeout_seconds float

Read timeout in seconds. Defaults to 30.0.

30.0
retry RetryPolicy | None

Validated retry policy. None preserves one attempt.

None
network NetworkConfig | None

Proxy and TLS options. None retains HTTPX defaults.

None

Other Parameters:

Name Type Description
gateway GatewayConfig | None

Explicit authentication and metadata. Omission retains direct defaults.

redactor StateRedactor | None

Synchronous caller-owned state transformation. Omission preserves state and the existing serialization path.

Raises:

Type Description
ValueError

If the key is absent, timeout is nonpositive, or the CA bundle cannot load.

close()

Close the HTTP client.

system_one(state, questions, model=None, *, metadata=None)

Prepare optional redaction once, call Jev and emit terminal metadata.

Parameters:

Name Type Description Default
state str | dict[str, Any] | list[Any]

The content to evaluate.

required
questions Mapping[str, Any]

Mapping of question names to question definitions.

required
model str | None

Model name override.

None
metadata RequestMetadata | None

Explicit per-call headers overriding gateway defaults.

None

Returns:

Type Description
SystemOneResponse

Typed SystemOneResponse with parsed answer objects.

Raises:

Type Description
ValueError

If metadata or redacted JSON violates input rules.

Exception

If a configured redactor or its input copy fails before IO.

JevAuthError

If the API returns 401 or 403.

JevRateLimitError

If the API returns 429 (rate limit exceeded).

JevRequestError

If the API returns 4xx (except 401/403, 429).

JevServiceError

If the API returns 5xx or a transport error occurs.

JevResponseError

If the API returns 2xx with unparseable body.

Error details

Validation errors (422) include an array of error objects. Each object's input key contains the caller's request payload. The adapter deliberately omits this key from the error message.

Auth errors (401/403) return an object with error_type and message fields.

Unknown detail shapes fall back to the HTTP status line alone.

Transport errors (timeouts, connection failures) are mapped to JevServiceError with status_code=None and retryable=True. A retryable=True timeout is advisory: retrying a read timeout may be double-billed because the service may still be processing the first attempt.

Implementation notes

Uses helper functions for payload building, response parsing, and error translation to ensure consistent behavior across adapters.