118 lines
4.8 KiB
Python
118 lines
4.8 KiB
Python
"""Adapter from the verified text Open Agent API to ProcessingTransport."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
from typing import Any, Callable, Mapping, Optional
|
|
|
|
from agent_integration.client import (
|
|
OpenAgentAPIError,
|
|
OpenAgentProtocolError,
|
|
OpenAgentTransportError,
|
|
)
|
|
from agent_integration.service import AgentResponseError, OpenAgentService
|
|
from arr_processing.contracts import PROCESSING_REQUEST_VERSION, ProcessingRequest
|
|
from arr_processing.errors import ProcessingTransportError
|
|
from arr_processing.runner import RemoteRunSnapshot
|
|
|
|
|
|
class OpenAgentProcessingTransport:
|
|
"""Uses only text Session/Run APIs; file resolution remains a runtime provider seam."""
|
|
|
|
def __init__(
|
|
self,
|
|
service: OpenAgentService,
|
|
*,
|
|
message_builder: Optional[Callable[[ProcessingRequest], str]] = None,
|
|
) -> None:
|
|
self._service = service
|
|
self._message_builder = message_builder or (lambda request: request.message())
|
|
|
|
def submit(self, request: ProcessingRequest, idempotency_key: str) -> RemoteRunSnapshot:
|
|
conversation_id = self.conversation_id(request.job_id)
|
|
try:
|
|
response = self._service.send_message(
|
|
conversation_id,
|
|
self._message_builder(request),
|
|
message_id=idempotency_key,
|
|
external_subject_id=conversation_id,
|
|
metadata={
|
|
"contract_version": PROCESSING_REQUEST_VERSION,
|
|
"processing_kind": "opera_daily",
|
|
},
|
|
)
|
|
except (OpenAgentAPIError, OpenAgentTransportError, OpenAgentProtocolError, AgentResponseError) as error:
|
|
self._raise_mapped(error)
|
|
return self._snapshot(response)
|
|
|
|
def get(self, request: ProcessingRequest, remote_run_id: str) -> RemoteRunSnapshot:
|
|
try:
|
|
response = self._service.get_run(
|
|
self.conversation_id(request.job_id),
|
|
remote_run_id,
|
|
)
|
|
except (OpenAgentAPIError, OpenAgentTransportError, OpenAgentProtocolError, AgentResponseError) as error:
|
|
self._raise_mapped(error)
|
|
return self._snapshot(response, expected_run_id=remote_run_id)
|
|
|
|
def cancel(self, request: ProcessingRequest, remote_run_id: str) -> RemoteRunSnapshot:
|
|
try:
|
|
response = self._service.cancel_run(
|
|
self.conversation_id(request.job_id),
|
|
remote_run_id,
|
|
)
|
|
except (OpenAgentAPIError, OpenAgentTransportError, OpenAgentProtocolError, AgentResponseError) as error:
|
|
self._raise_mapped(error)
|
|
return self._snapshot(response, expected_run_id=remote_run_id)
|
|
|
|
@staticmethod
|
|
def conversation_id(job_id: str) -> str:
|
|
digest = hashlib.sha256(job_id.encode("utf-8")).hexdigest()
|
|
return "arrproc_" + digest[:48]
|
|
|
|
@staticmethod
|
|
def _snapshot(
|
|
response: Mapping[str, Any],
|
|
expected_run_id: Optional[str] = None,
|
|
) -> RemoteRunSnapshot:
|
|
if not isinstance(response, Mapping):
|
|
raise ProcessingTransportError("PROCESSING_REMOTE_PROTOCOL_INVALID", retryable=False)
|
|
run_id = response.get("run_id")
|
|
status = response.get("status")
|
|
final_content = response.get("final_content")
|
|
if (
|
|
not isinstance(run_id, str)
|
|
or not run_id
|
|
or not isinstance(status, str)
|
|
or not status
|
|
or (expected_run_id is not None and run_id != expected_run_id)
|
|
or (final_content is not None and not isinstance(final_content, str))
|
|
):
|
|
raise ProcessingTransportError("PROCESSING_REMOTE_PROTOCOL_INVALID", retryable=False)
|
|
return RemoteRunSnapshot(run_id, status.lower(), final_content)
|
|
|
|
@staticmethod
|
|
def _raise_mapped(error: BaseException) -> None:
|
|
if isinstance(error, OpenAgentAPIError):
|
|
if error.active_run_conflict:
|
|
raise ProcessingTransportError(
|
|
"PROCESSING_ACTIVE_RUN_CONFLICT",
|
|
retryable=True,
|
|
active_run_conflict=True,
|
|
) from None
|
|
if error.retryable:
|
|
code = (
|
|
"PROCESSING_REMOTE_RATE_LIMITED"
|
|
if error.status_code == 429
|
|
else "PROCESSING_REMOTE_UNAVAILABLE"
|
|
)
|
|
raise ProcessingTransportError(code, retryable=True) from None
|
|
raise ProcessingTransportError("PROCESSING_REMOTE_REJECTED", retryable=False) from None
|
|
if isinstance(error, OpenAgentTransportError):
|
|
raise ProcessingTransportError(
|
|
"PROCESSING_REMOTE_UNAVAILABLE", retryable=True
|
|
) from None
|
|
raise ProcessingTransportError(
|
|
"PROCESSING_REMOTE_PROTOCOL_INVALID", retryable=False
|
|
) from None
|