diff --git a/.fern/metadata.json b/.fern/metadata.json index e4684b3..585ba06 100644 --- a/.fern/metadata.json +++ b/.fern/metadata.json @@ -1,5 +1,5 @@ { - "cliVersion": "5.49.1", + "cliVersion": "5.50.1", "generatorName": "fernapi/fern-python-sdk", "generatorVersion": "5.14.13", "generatorConfig": { @@ -8,10 +8,10 @@ "enabled": true } }, - "originGitCommit": "64f369254225bd6c2d4c58d87f59165d7e8e8dc9", + "originGitCommit": "fbaef4c66e97232edfaacb20d23d476aa286ecdd", "originGitCommitIsDirty": true, "invokedBy": "ci", "requestedVersion": "AUTO", "ciProvider": "unknown", - "sdkVersion": "16.2.0" + "sdkVersion": "16.3.0" } \ No newline at end of file diff --git a/.fern/replay.lock b/.fern/replay.lock index aa2c39d..56c4194 100644 --- a/.fern/replay.lock +++ b/.fern/replay.lock @@ -48,21 +48,36 @@ generations: cli_version: unknown generator_versions: fernapi/fern-python-sdk: 5.14.13 -current_generation: 4cf14c8a12c24732e7d4159109b7c1924eead6f9 + - commit_sha: ac1f834fe3b978f13cb7dba910fc81dcd35abe2c + tree_hash: 4e39300cb35b6c3a4ea82cf4eba2ea918b856859 + timestamp: 2026-06-18T18:07:40.772Z + cli_version: unknown + generator_versions: + fernapi/fern-python-sdk: 5.14.13 +current_generation: ac1f834fe3b978f13cb7dba910fc81dcd35abe2c patches: - id: patch-6516695e - content_hash: sha256:29d85120d58e5f06a344be0c1228262bb29c8c57591581d8a56b6d3eabe65d75 + content_hash: sha256:07505f8175d78f0dc3cab8f1bc99e9588c1c24f0c43427439a4c685d56635932 original_commit: 6516695ecaba47ae4bcc8119acca86a1113adeeb original_message: "Release 15.0.2: restore bundled openapi.json packaging (#169)" original_author: Gavin Sharp - base_generation: 4cf14c8a12c24732e7d4159109b7c1924eead6f9 + base_generation: ac1f834fe3b978f13cb7dba910fc81dcd35abe2c files: - pyproject.toml patch_content: | diff --git a/pyproject.toml b/pyproject.toml - index cc86d42..79689b9 100644 + index cc86d42..678bcb9 100644 --- a/pyproject.toml +++ b/pyproject.toml + @@ -4,7 +4,7 @@ dynamic = ["version"] + + [tool.poetry] + name = "phenoml" + -version = "0.0.0.dev0" + +version = "16.3.0" + description = "" + readme = "README.md" + authors = [] @@ -31,6 +31,9 @@ classifiers = [ packages = [ { include = "phenoml", from = "src"} @@ -81,7 +96,7 @@ patches: [tool.poetry] name = "phenoml" - version = "0.0.0.dev0" + version = "16.3.0" description = "" readme = "README.md" authors = [] diff --git a/changelog.md b/changelog.md index 6f61323..fb5e474 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,12 @@ +## [16.3.0] - 2026-06-18 +### Added +- **`phenoml.agent.errors.ConflictError`** — new `ApiError` subclass raised by `client.agent.chat.send(...)` and `client.agent.chat.stream(...)` for HTTP 409 responses when a session already has an active turn. + +### Changed +- **`client.agent.chat.send(...)` and `client.agent.chat.stream(...)` `session_id` parameter** — docstring now states that only one request may be active per session at a time and overlapping turns return `409 Conflict`. +- **`client.fhir2omop.create(...)`** — docstring now lists the supported FHIR resource-to-OMOP table mappings and clarifies that unsupported resource types are accepted but ignored. +- **`CreateOmopResponse.dropped`** — field description now clarifies that only supported resources missing required subject/patient, code, or medication reference data appear in `dropped`; unsupported resource types are ignored. + ## [16.2.0] - 2026-06-15 ### Added - **`Provider`** — `"aidbox"` is now a supported FHIR provider value in the `Provider` union type. @@ -567,4 +576,3 @@ from phenoml import PhenomlClient * Update documentation to reflect removed parameter * Remove AgentCreateRequest.is_active field from type definitions * 🌿 Generated with Fern - diff --git a/code-examples.json b/code-examples.json index 081309b..29025a1 100644 --- a/code-examples.json +++ b/code-examples.json @@ -2,8 +2,8 @@ "metadata": { "language": "python", "packageName": "phenoml", - "sdkVersion": "16.2.0", - "specCommit": "64f369254225bd6c2d4c58d87f59165d7e8e8dc9", + "sdkVersion": "16.3.0", + "specCommit": "fbaef4c66e97232edfaacb20d23d476aa286ecdd", "generatorName": "fernapi/fern-python-sdk" }, "renderRules": { diff --git a/poetry.lock b/poetry.lock index a57204a..2811db4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -188,14 +188,14 @@ files = [ [[package]] name = "anyio" -version = "4.13.0" +version = "4.14.0" description = "High-level concurrency and networking framework on top of asyncio or Trio" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708"}, - {file = "anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc"}, + {file = "anyio-4.14.0-py3-none-any.whl", hash = "sha256:dd9b7a2a9799ed6552fde617b2c5df02b7fdd7d88392fc48101e51bae46164d9"}, + {file = "anyio-4.14.0.tar.gz", hash = "sha256:b47c1f9ccf73e67021df785332508f99379c68fa7d0684e8e3492cb1d4b23f89"}, ] [package.dependencies] @@ -247,14 +247,14 @@ files = [ [[package]] name = "certifi" -version = "2026.5.20" +version = "2026.6.17" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" groups = ["main", "dev"] files = [ - {file = "certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897"}, - {file = "certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d"}, + {file = "certifi-2026.6.17-py3-none-any.whl", hash = "sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db"}, + {file = "certifi-2026.6.17.tar.gz", hash = "sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432"}, ] [[package]] diff --git a/pyproject.toml b/pyproject.toml index 6e5fdf7..678bcb9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ dynamic = ["version"] [tool.poetry] name = "phenoml" -version = "16.2.0" +version = "16.3.0" description = "" readme = "README.md" authors = [] diff --git a/reference.md b/reference.md index 6e8eb1c..81797cd 100644 --- a/reference.md +++ b/reference.md @@ -598,7 +598,7 @@ Multiple FHIR provider integrations can be provided as comma-separated values.
-**session_id:** `typing.Optional[str]` — Optional session ID for conversation continuity +**session_id:** `typing.Optional[str]` — Optional session ID for conversation continuity. Only one request may be active for a session at a time; overlapping turns for the same session return 409 Conflict.
@@ -732,7 +732,7 @@ Multiple FHIR provider integrations can be provided as comma-separated values.
-**session_id:** `typing.Optional[str]` — Optional session ID for conversation continuity +**session_id:** `typing.Optional[str]` — Optional session ID for conversation continuity. Only one request may be active for a session at a time; overlapping turns for the same session return 409 Conflict.
@@ -3526,6 +3526,32 @@ Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows (person, visit_occurrence, condition_occurrence, drug_exposure, procedure_occurrence, measurement, observation). +Resource support is intentionally limited to the OMOP tables returned by +this endpoint: +- `Patient` -> `person` +- `Encounter` -> `visit_occurrence` +- `Condition` -> `condition_occurrence` +- `Procedure` -> `procedure_occurrence` +- `MedicationRequest`, `MedicationStatement`, and + `MedicationAdministration` -> `drug_exposure` +- `Immunization` -> `drug_exposure` +- `Observation` with a numeric `valueQuantity`, `valueInteger`, or + numeric-looking `valueString` (for example `"<2"`) -> `measurement` +- non-numeric `Observation` -> `observation` +- `AllergyIntolerance` -> `observation` + +`Medication` is supported only as reference data for medication +resources; it is not emitted as its own row because OMOP CDM has no +Medication table. Other reference/admin resources such as `Practitioner`, +`Organization`, `Location`, `Coverage`, and `Claim`, and clinical +workflow/document resources such as `DiagnosticReport`, `ServiceRequest`, +`CarePlan`, `DocumentReference`, `Composition`, `Specimen`, and +`DeviceUseStatement`, are currently accepted in a Bundle but are not +shaped into OMOP rows. Unsupported resource types are ignored rather than +listed under `dropped`; `dropped` is reserved for supported resource types +that were missing the subject/patient, code, or medication reference data +needed to produce a valid row. + Each resource's primary clinical coding is resolved to a standard OMOP `concept_id`. Alongside the OMOP rows grouped by table (`tables`), the response carries `mappings` (how each source coding resolved, linked back @@ -3599,9 +3625,12 @@ client.fhir2omop.create( **fhir_resources:** `typing.Dict[str, typing.Any]` FHIR resources (single resource or Bundle). Must contain at least one -Patient resource. Resources are mapped to OMOP rows; standalone -Medication resources are consumed by medication references rather than -mapped to their own table. +Patient resource. Supported row-producing resources are Patient, +Encounter, Condition, Procedure, MedicationRequest, +MedicationStatement, MedicationAdministration, Immunization, +Observation, and AllergyIntolerance. Standalone Medication resources +are consumed by medication references rather than mapped to their own +table. Other resource types are accepted but ignored. diff --git a/src/phenoml/agent/__init__.py b/src/phenoml/agent/__init__.py index f45f586..cd6baa4 100644 --- a/src/phenoml/agent/__init__.py +++ b/src/phenoml/agent/__init__.py @@ -29,6 +29,7 @@ ) from .errors import ( BadRequestError, + ConflictError, ForbiddenError, GatewayTimeoutError, InternalServerError, @@ -52,6 +53,7 @@ "ChatMessageTemplate": ".types", "ChatMessageTemplateRole": ".types", "ChatSessionTemplate": ".types", + "ConflictError": ".errors", "DeleteResponse": ".types", "ForbiddenError": ".errors", "GatewayTimeoutError": ".errors", @@ -109,6 +111,7 @@ def __dir__(): "ChatMessageTemplate", "ChatMessageTemplateRole", "ChatSessionTemplate", + "ConflictError", "DeleteResponse", "ForbiddenError", "GatewayTimeoutError", diff --git a/src/phenoml/agent/chat/client.py b/src/phenoml/agent/chat/client.py index 8957f52..9939bf6 100644 --- a/src/phenoml/agent/chat/client.py +++ b/src/phenoml/agent/chat/client.py @@ -65,7 +65,7 @@ def send( Optional context for the conversation session_id : typing.Optional[str] - Optional session ID for conversation continuity + Optional session ID for conversation continuity. Only one request may be active for a session at a time; overlapping turns for the same session return 409 Conflict. enhanced_reasoning : typing.Optional[bool] Enable enhanced reasoning capabilities. Increases latency but improves response quality and reliability. @@ -143,7 +143,7 @@ def stream( Optional context for the conversation session_id : typing.Optional[str] - Optional session ID for conversation continuity + Optional session ID for conversation continuity. Only one request may be active for a session at a time; overlapping turns for the same session return 409 Conflict. enhanced_reasoning : typing.Optional[bool] Enable enhanced reasoning capabilities. Increases latency but improves response quality and reliability. @@ -304,7 +304,7 @@ async def send( Optional context for the conversation session_id : typing.Optional[str] - Optional session ID for conversation continuity + Optional session ID for conversation continuity. Only one request may be active for a session at a time; overlapping turns for the same session return 409 Conflict. enhanced_reasoning : typing.Optional[bool] Enable enhanced reasoning capabilities. Increases latency but improves response quality and reliability. @@ -390,7 +390,7 @@ async def stream( Optional context for the conversation session_id : typing.Optional[str] - Optional session ID for conversation continuity + Optional session ID for conversation continuity. Only one request may be active for a session at a time; overlapping turns for the same session return 409 Conflict. enhanced_reasoning : typing.Optional[bool] Enable enhanced reasoning capabilities. Increases latency but improves response quality and reliability. diff --git a/src/phenoml/agent/chat/raw_client.py b/src/phenoml/agent/chat/raw_client.py index 6c4f0fc..b163d97 100644 --- a/src/phenoml/agent/chat/raw_client.py +++ b/src/phenoml/agent/chat/raw_client.py @@ -13,6 +13,7 @@ from ...core.pydantic_utilities import parse_obj_as, parse_sse_obj from ...core.request_options import RequestOptions from ..errors.bad_request_error import BadRequestError +from ..errors.conflict_error import ConflictError from ..errors.forbidden_error import ForbiddenError from ..errors.gateway_timeout_error import GatewayTimeoutError from ..errors.internal_server_error import InternalServerError @@ -68,7 +69,7 @@ def send( Optional context for the conversation session_id : typing.Optional[str] - Optional session ID for conversation continuity + Optional session ID for conversation continuity. Only one request may be active for a session at a time; overlapping turns for the same session return 409 Conflict. enhanced_reasoning : typing.Optional[bool] Enable enhanced reasoning capabilities. Increases latency but improves response quality and reliability. @@ -153,6 +154,17 @@ def send( ), ), ) + if _response.status_code == 409: + raise ConflictError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 500: raise InternalServerError( headers=dict(_response.headers), @@ -222,7 +234,7 @@ def stream( Optional context for the conversation session_id : typing.Optional[str] - Optional session ID for conversation continuity + Optional session ID for conversation continuity. Only one request may be active for a session at a time; overlapping turns for the same session return 409 Conflict. enhanced_reasoning : typing.Optional[bool] Enable enhanced reasoning capabilities. Increases latency but improves response quality and reliability. @@ -331,6 +343,17 @@ def _iter(): ), ), ) + if _response.status_code == 409: + raise ConflictError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 500: raise InternalServerError( headers=dict(_response.headers), @@ -535,7 +558,7 @@ async def send( Optional context for the conversation session_id : typing.Optional[str] - Optional session ID for conversation continuity + Optional session ID for conversation continuity. Only one request may be active for a session at a time; overlapping turns for the same session return 409 Conflict. enhanced_reasoning : typing.Optional[bool] Enable enhanced reasoning capabilities. Increases latency but improves response quality and reliability. @@ -620,6 +643,17 @@ async def send( ), ), ) + if _response.status_code == 409: + raise ConflictError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 500: raise InternalServerError( headers=dict(_response.headers), @@ -689,7 +723,7 @@ async def stream( Optional context for the conversation session_id : typing.Optional[str] - Optional session ID for conversation continuity + Optional session ID for conversation continuity. Only one request may be active for a session at a time; overlapping turns for the same session return 409 Conflict. enhanced_reasoning : typing.Optional[bool] Enable enhanced reasoning capabilities. Increases latency but improves response quality and reliability. @@ -798,6 +832,17 @@ async def _iter(): ), ), ) + if _response.status_code == 409: + raise ConflictError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 500: raise InternalServerError( headers=dict(_response.headers), diff --git a/src/phenoml/agent/errors/__init__.py b/src/phenoml/agent/errors/__init__.py index c60a65d..13df44d 100644 --- a/src/phenoml/agent/errors/__init__.py +++ b/src/phenoml/agent/errors/__init__.py @@ -7,6 +7,7 @@ if typing.TYPE_CHECKING: from .bad_request_error import BadRequestError + from .conflict_error import ConflictError from .forbidden_error import ForbiddenError from .gateway_timeout_error import GatewayTimeoutError from .internal_server_error import InternalServerError @@ -14,6 +15,7 @@ from .unauthorized_error import UnauthorizedError _dynamic_imports: typing.Dict[str, str] = { "BadRequestError": ".bad_request_error", + "ConflictError": ".conflict_error", "ForbiddenError": ".forbidden_error", "GatewayTimeoutError": ".gateway_timeout_error", "InternalServerError": ".internal_server_error", @@ -45,6 +47,7 @@ def __dir__(): __all__ = [ "BadRequestError", + "ConflictError", "ForbiddenError", "GatewayTimeoutError", "InternalServerError", diff --git a/src/phenoml/agent/errors/conflict_error.py b/src/phenoml/agent/errors/conflict_error.py new file mode 100644 index 0000000..abe1a9f --- /dev/null +++ b/src/phenoml/agent/errors/conflict_error.py @@ -0,0 +1,10 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ...core.api_error import ApiError + + +class ConflictError(ApiError): + def __init__(self, body: typing.Any, headers: typing.Optional[typing.Dict[str, str]] = None): + super().__init__(status_code=409, headers=headers, body=body) diff --git a/src/phenoml/core/client_wrapper.py b/src/phenoml/core/client_wrapper.py index be50d73..be7351c 100644 --- a/src/phenoml/core/client_wrapper.py +++ b/src/phenoml/core/client_wrapper.py @@ -29,12 +29,12 @@ def get_headers(self) -> typing.Dict[str, str]: import platform headers: typing.Dict[str, str] = { - "User-Agent": "phenoml/16.2.0", + "User-Agent": "phenoml/16.3.0", "X-Fern-Language": "Python", "X-Fern-Runtime": f"python/{platform.python_version()}", "X-Fern-Platform": f"{platform.system().lower()}/{platform.release()}", "X-Fern-SDK-Name": "phenoml", - "X-Fern-SDK-Version": "16.2.0", + "X-Fern-SDK-Version": "16.3.0", **(self.get_custom_headers() or {}), } token = self._get_token() diff --git a/src/phenoml/fhir2omop/client.py b/src/phenoml/fhir2omop/client.py index 41dfca6..ac8e881 100644 --- a/src/phenoml/fhir2omop/client.py +++ b/src/phenoml/fhir2omop/client.py @@ -34,6 +34,32 @@ def create( (person, visit_occurrence, condition_occurrence, drug_exposure, procedure_occurrence, measurement, observation). + Resource support is intentionally limited to the OMOP tables returned by + this endpoint: + - `Patient` -> `person` + - `Encounter` -> `visit_occurrence` + - `Condition` -> `condition_occurrence` + - `Procedure` -> `procedure_occurrence` + - `MedicationRequest`, `MedicationStatement`, and + `MedicationAdministration` -> `drug_exposure` + - `Immunization` -> `drug_exposure` + - `Observation` with a numeric `valueQuantity`, `valueInteger`, or + numeric-looking `valueString` (for example `"<2"`) -> `measurement` + - non-numeric `Observation` -> `observation` + - `AllergyIntolerance` -> `observation` + + `Medication` is supported only as reference data for medication + resources; it is not emitted as its own row because OMOP CDM has no + Medication table. Other reference/admin resources such as `Practitioner`, + `Organization`, `Location`, `Coverage`, and `Claim`, and clinical + workflow/document resources such as `DiagnosticReport`, `ServiceRequest`, + `CarePlan`, `DocumentReference`, `Composition`, `Specimen`, and + `DeviceUseStatement`, are currently accepted in a Bundle but are not + shaped into OMOP rows. Unsupported resource types are ignored rather than + listed under `dropped`; `dropped` is reserved for supported resource types + that were missing the subject/patient, code, or medication reference data + needed to produce a valid row. + Each resource's primary clinical coding is resolved to a standard OMOP `concept_id`. Alongside the OMOP rows grouped by table (`tables`), the response carries `mappings` (how each source coding resolved, linked back @@ -64,9 +90,12 @@ def create( ---------- fhir_resources : typing.Dict[str, typing.Any] FHIR resources (single resource or Bundle). Must contain at least one - Patient resource. Resources are mapped to OMOP rows; standalone - Medication resources are consumed by medication references rather than - mapped to their own table. + Patient resource. Supported row-producing resources are Patient, + Encounter, Condition, Procedure, MedicationRequest, + MedicationStatement, MedicationAdministration, Immunization, + Observation, and AllergyIntolerance. Standalone Medication resources + are consumed by medication references rather than mapped to their own + table. Other resource types are accepted but ignored. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -170,6 +199,32 @@ async def create( (person, visit_occurrence, condition_occurrence, drug_exposure, procedure_occurrence, measurement, observation). + Resource support is intentionally limited to the OMOP tables returned by + this endpoint: + - `Patient` -> `person` + - `Encounter` -> `visit_occurrence` + - `Condition` -> `condition_occurrence` + - `Procedure` -> `procedure_occurrence` + - `MedicationRequest`, `MedicationStatement`, and + `MedicationAdministration` -> `drug_exposure` + - `Immunization` -> `drug_exposure` + - `Observation` with a numeric `valueQuantity`, `valueInteger`, or + numeric-looking `valueString` (for example `"<2"`) -> `measurement` + - non-numeric `Observation` -> `observation` + - `AllergyIntolerance` -> `observation` + + `Medication` is supported only as reference data for medication + resources; it is not emitted as its own row because OMOP CDM has no + Medication table. Other reference/admin resources such as `Practitioner`, + `Organization`, `Location`, `Coverage`, and `Claim`, and clinical + workflow/document resources such as `DiagnosticReport`, `ServiceRequest`, + `CarePlan`, `DocumentReference`, `Composition`, `Specimen`, and + `DeviceUseStatement`, are currently accepted in a Bundle but are not + shaped into OMOP rows. Unsupported resource types are ignored rather than + listed under `dropped`; `dropped` is reserved for supported resource types + that were missing the subject/patient, code, or medication reference data + needed to produce a valid row. + Each resource's primary clinical coding is resolved to a standard OMOP `concept_id`. Alongside the OMOP rows grouped by table (`tables`), the response carries `mappings` (how each source coding resolved, linked back @@ -200,9 +255,12 @@ async def create( ---------- fhir_resources : typing.Dict[str, typing.Any] FHIR resources (single resource or Bundle). Must contain at least one - Patient resource. Resources are mapped to OMOP rows; standalone - Medication resources are consumed by medication references rather than - mapped to their own table. + Patient resource. Supported row-producing resources are Patient, + Encounter, Condition, Procedure, MedicationRequest, + MedicationStatement, MedicationAdministration, Immunization, + Observation, and AllergyIntolerance. Standalone Medication resources + are consumed by medication references rather than mapped to their own + table. Other resource types are accepted but ignored. request_options : typing.Optional[RequestOptions] Request-specific configuration. diff --git a/src/phenoml/fhir2omop/raw_client.py b/src/phenoml/fhir2omop/raw_client.py index 6c5058d..51990ac 100644 --- a/src/phenoml/fhir2omop/raw_client.py +++ b/src/phenoml/fhir2omop/raw_client.py @@ -32,6 +32,32 @@ def create( (person, visit_occurrence, condition_occurrence, drug_exposure, procedure_occurrence, measurement, observation). + Resource support is intentionally limited to the OMOP tables returned by + this endpoint: + - `Patient` -> `person` + - `Encounter` -> `visit_occurrence` + - `Condition` -> `condition_occurrence` + - `Procedure` -> `procedure_occurrence` + - `MedicationRequest`, `MedicationStatement`, and + `MedicationAdministration` -> `drug_exposure` + - `Immunization` -> `drug_exposure` + - `Observation` with a numeric `valueQuantity`, `valueInteger`, or + numeric-looking `valueString` (for example `"<2"`) -> `measurement` + - non-numeric `Observation` -> `observation` + - `AllergyIntolerance` -> `observation` + + `Medication` is supported only as reference data for medication + resources; it is not emitted as its own row because OMOP CDM has no + Medication table. Other reference/admin resources such as `Practitioner`, + `Organization`, `Location`, `Coverage`, and `Claim`, and clinical + workflow/document resources such as `DiagnosticReport`, `ServiceRequest`, + `CarePlan`, `DocumentReference`, `Composition`, `Specimen`, and + `DeviceUseStatement`, are currently accepted in a Bundle but are not + shaped into OMOP rows. Unsupported resource types are ignored rather than + listed under `dropped`; `dropped` is reserved for supported resource types + that were missing the subject/patient, code, or medication reference data + needed to produce a valid row. + Each resource's primary clinical coding is resolved to a standard OMOP `concept_id`. Alongside the OMOP rows grouped by table (`tables`), the response carries `mappings` (how each source coding resolved, linked back @@ -62,9 +88,12 @@ def create( ---------- fhir_resources : typing.Dict[str, typing.Any] FHIR resources (single resource or Bundle). Must contain at least one - Patient resource. Resources are mapped to OMOP rows; standalone - Medication resources are consumed by medication references rather than - mapped to their own table. + Patient resource. Supported row-producing resources are Patient, + Encounter, Condition, Procedure, MedicationRequest, + MedicationStatement, MedicationAdministration, Immunization, + Observation, and AllergyIntolerance. Standalone Medication resources + are consumed by medication references rather than mapped to their own + table. Other resource types are accepted but ignored. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -162,6 +191,32 @@ async def create( (person, visit_occurrence, condition_occurrence, drug_exposure, procedure_occurrence, measurement, observation). + Resource support is intentionally limited to the OMOP tables returned by + this endpoint: + - `Patient` -> `person` + - `Encounter` -> `visit_occurrence` + - `Condition` -> `condition_occurrence` + - `Procedure` -> `procedure_occurrence` + - `MedicationRequest`, `MedicationStatement`, and + `MedicationAdministration` -> `drug_exposure` + - `Immunization` -> `drug_exposure` + - `Observation` with a numeric `valueQuantity`, `valueInteger`, or + numeric-looking `valueString` (for example `"<2"`) -> `measurement` + - non-numeric `Observation` -> `observation` + - `AllergyIntolerance` -> `observation` + + `Medication` is supported only as reference data for medication + resources; it is not emitted as its own row because OMOP CDM has no + Medication table. Other reference/admin resources such as `Practitioner`, + `Organization`, `Location`, `Coverage`, and `Claim`, and clinical + workflow/document resources such as `DiagnosticReport`, `ServiceRequest`, + `CarePlan`, `DocumentReference`, `Composition`, `Specimen`, and + `DeviceUseStatement`, are currently accepted in a Bundle but are not + shaped into OMOP rows. Unsupported resource types are ignored rather than + listed under `dropped`; `dropped` is reserved for supported resource types + that were missing the subject/patient, code, or medication reference data + needed to produce a valid row. + Each resource's primary clinical coding is resolved to a standard OMOP `concept_id`. Alongside the OMOP rows grouped by table (`tables`), the response carries `mappings` (how each source coding resolved, linked back @@ -192,9 +247,12 @@ async def create( ---------- fhir_resources : typing.Dict[str, typing.Any] FHIR resources (single resource or Bundle). Must contain at least one - Patient resource. Resources are mapped to OMOP rows; standalone - Medication resources are consumed by medication references rather than - mapped to their own table. + Patient resource. Supported row-producing resources are Patient, + Encounter, Condition, Procedure, MedicationRequest, + MedicationStatement, MedicationAdministration, Immunization, + Observation, and AllergyIntolerance. Standalone Medication resources + are consumed by medication references rather than mapped to their own + table. Other resource types are accepted but ignored. request_options : typing.Optional[RequestOptions] Request-specific configuration. diff --git a/src/phenoml/fhir2omop/types/create_omop_response.py b/src/phenoml/fhir2omop/types/create_omop_response.py index 7ac0282..122c5a9 100644 --- a/src/phenoml/fhir2omop/types/create_omop_response.py +++ b/src/phenoml/fhir2omop/types/create_omop_response.py @@ -21,7 +21,10 @@ class CreateOmopResponse(UniversalBaseModel): dropped: typing.Optional[typing.List[DroppedResource]] = pydantic.Field(default=None) """ - Resources that could not be shaped into an OMOP row (rather than emitted as blank rows). + Supported resource instances that could not be shaped into an OMOP + row because required subject/patient, code, or medication reference + data was missing. Unsupported resource types are ignored and do not + appear here. """ vocab_version: typing.Optional[str] = pydantic.Field(default=None) diff --git a/src/phenoml/openapi/openapi.json b/src/phenoml/openapi/openapi.json index 3882086..20e6e8a 100644 --- a/src/phenoml/openapi/openapi.json +++ b/src/phenoml/openapi/openapi.json @@ -2,7 +2,7 @@ "openapi": "3.0.3", "info": { "title": "Phenoml API", - "version": "64f369254225bd6c2d4c58d87f59165d7e8e8dc9" + "version": "fbaef4c66e97232edfaacb20d23d476aa286ecdd" }, "x-services": [ { @@ -672,6 +672,9 @@ "404": { "description": "Agent or session not found" }, + "409": { + "description": "Chat session already has an active request. Retry after the in-flight turn completes." + }, "500": { "description": "Server error" }, @@ -746,6 +749,9 @@ "404": { "description": "Agent or session not found" }, + "409": { + "description": "Chat session already has an active request. Retry after the in-flight turn completes." + }, "500": { "description": "Server error" }, @@ -3021,7 +3027,7 @@ "post": { "operationId": "fhir2omop_create", "summary": "Map FHIR resources to OMOP CDM v5.4", - "description": "Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows\n(person, visit_occurrence, condition_occurrence, drug_exposure,\nprocedure_occurrence, measurement, observation).\n\nEach resource's primary clinical coding is resolved to a standard OMOP\n`concept_id`. Alongside the OMOP rows grouped by table (`tables`), the\nresponse carries `mappings` (how each source coding resolved, linked back\nto the row it produced), `dropped` (resources that could not be shaped\ninto a row), `vocab_version` (the OMOP vocabulary release codes were\nresolved against), and a small `summary` of the resolution outcomes.\n\nA `concept_id` of `0` is reported, not omitted (OMOP \"no matching\nconcept\" semantics): it covers both a coding with no standard match\n(`UNMAPPED`) and an unverified suggestion for a text-only resource\n(`UNCHECKED`). Only the primary clinical coding is resolved, so\n`gender`/`race`/`ethnicity`/`visit`/`value`/`unit` `concept_id`s are\nalways `0`; the one populated non-resolved concept is measurement\n`operator_concept_id`, set from a value comparator (`<`, `<=`, `>`, `>=`)\nrather than the resolver. Each `*_source_value` carries the verbatim FHIR\ncoding (`system#code`), and `*_type_concept_id` is set to `32817` (EHR).\n\nMedication codes are resolved whether they appear inline\n(`medicationCodeableConcept`) or via a `medicationReference` to a contained,\nrelative (`Type/id`), or bundle-entry (`urn:uuid`) `Medication` resource.\nResources that cannot be shaped into a row \u2014 a medication with no usable\ncode, resolvable reference, or display, or any clinical resource whose\nsubject/patient reference cannot be tied to a person \u2014 are reported under\n`dropped` rather than emitted as blank rows. The\nbundle must contain at least one Patient resource.\n", + "description": "Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows\n(person, visit_occurrence, condition_occurrence, drug_exposure,\nprocedure_occurrence, measurement, observation).\n\nResource support is intentionally limited to the OMOP tables returned by\nthis endpoint:\n- `Patient` -> `person`\n- `Encounter` -> `visit_occurrence`\n- `Condition` -> `condition_occurrence`\n- `Procedure` -> `procedure_occurrence`\n- `MedicationRequest`, `MedicationStatement`, and\n `MedicationAdministration` -> `drug_exposure`\n- `Immunization` -> `drug_exposure`\n- `Observation` with a numeric `valueQuantity`, `valueInteger`, or\n numeric-looking `valueString` (for example `\"<2\"`) -> `measurement`\n- non-numeric `Observation` -> `observation`\n- `AllergyIntolerance` -> `observation`\n\n`Medication` is supported only as reference data for medication\nresources; it is not emitted as its own row because OMOP CDM has no\nMedication table. Other reference/admin resources such as `Practitioner`,\n`Organization`, `Location`, `Coverage`, and `Claim`, and clinical\nworkflow/document resources such as `DiagnosticReport`, `ServiceRequest`,\n`CarePlan`, `DocumentReference`, `Composition`, `Specimen`, and\n`DeviceUseStatement`, are currently accepted in a Bundle but are not\nshaped into OMOP rows. Unsupported resource types are ignored rather than\nlisted under `dropped`; `dropped` is reserved for supported resource types\nthat were missing the subject/patient, code, or medication reference data\nneeded to produce a valid row.\n\nEach resource's primary clinical coding is resolved to a standard OMOP\n`concept_id`. Alongside the OMOP rows grouped by table (`tables`), the\nresponse carries `mappings` (how each source coding resolved, linked back\nto the row it produced), `dropped` (resources that could not be shaped\ninto a row), `vocab_version` (the OMOP vocabulary release codes were\nresolved against), and a small `summary` of the resolution outcomes.\n\nA `concept_id` of `0` is reported, not omitted (OMOP \"no matching\nconcept\" semantics): it covers both a coding with no standard match\n(`UNMAPPED`) and an unverified suggestion for a text-only resource\n(`UNCHECKED`). Only the primary clinical coding is resolved, so\n`gender`/`race`/`ethnicity`/`visit`/`value`/`unit` `concept_id`s are\nalways `0`; the one populated non-resolved concept is measurement\n`operator_concept_id`, set from a value comparator (`<`, `<=`, `>`, `>=`)\nrather than the resolver. Each `*_source_value` carries the verbatim FHIR\ncoding (`system#code`), and `*_type_concept_id` is set to `32817` (EHR).\n\nMedication codes are resolved whether they appear inline\n(`medicationCodeableConcept`) or via a `medicationReference` to a contained,\nrelative (`Type/id`), or bundle-entry (`urn:uuid`) `Medication` resource.\nResources that cannot be shaped into a row \u2014 a medication with no usable\ncode, resolvable reference, or display, or any clinical resource whose\nsubject/patient reference cannot be tied to a person \u2014 are reported under\n`dropped` rather than emitted as blank rows. The\nbundle must contain at least one Patient resource.\n", "requestBody": { "required": true, "content": { @@ -7345,7 +7351,7 @@ }, "session_id": { "type": "string", - "description": "Optional session ID for conversation continuity", + "description": "Optional session ID for conversation continuity. Only one request may be active for a session at a time; overlapping turns for the same session return 409 Conflict.", "example": "session-abc123" }, "agent_id": { @@ -7381,7 +7387,7 @@ }, "session_id": { "type": "string", - "description": "Optional session ID for conversation continuity", + "description": "Optional session ID for conversation continuity. Only one request may be active for a session at a time; overlapping turns for the same session return 409 Conflict.", "example": "session-abc123" }, "agent_id": { @@ -8544,7 +8550,7 @@ "fhir_resources": { "type": "object", "additionalProperties": true, - "description": "FHIR resources (single resource or Bundle). Must contain at least one\nPatient resource. Resources are mapped to OMOP rows; standalone\nMedication resources are consumed by medication references rather than\nmapped to their own table.\n" + "description": "FHIR resources (single resource or Bundle). Must contain at least one\nPatient resource. Supported row-producing resources are Patient,\nEncounter, Condition, Procedure, MedicationRequest,\nMedicationStatement, MedicationAdministration, Immunization,\nObservation, and AllergyIntolerance. Standalone Medication resources\nare consumed by medication references rather than mapped to their own\ntable. Other resource types are accepted but ignored.\n" } } }, @@ -8569,7 +8575,7 @@ }, "dropped": { "type": "array", - "description": "Resources that could not be shaped into an OMOP row (rather than emitted as blank rows).", + "description": "Supported resource instances that could not be shaped into an OMOP\nrow because required subject/patient, code, or medication reference\ndata was missing. Unsupported resource types are ignored and do not\nappear here.\n", "items": { "$ref": "#/components/schemas/fhir2omop_DroppedResource" }