From ac1f834fe3b978f13cb7dba910fc81dcd35abe2c Mon Sep 17 00:00:00 2001
From: fern-api <115122769+fern-api[bot]@users.noreply.github.com>
Date: Thu, 18 Jun 2026 18:07:40 +0000
Subject: [PATCH 1/5] [fern-generated] Update SDK
Generated by Fern
CLI Version: unknown
Generators:
- fernapi/fern-python-sdk: 5.14.13
---
.fern/metadata.json | 6 +-
poetry.lock | 12 ++--
pyproject.toml | 5 +-
reference.md | 39 +++++++++--
src/phenoml/agent/__init__.py | 3 +
src/phenoml/agent/chat/client.py | 8 +--
src/phenoml/agent/chat/raw_client.py | 53 ++++++++++++--
src/phenoml/agent/errors/__init__.py | 3 +
src/phenoml/agent/errors/conflict_error.py | 10 +++
src/phenoml/core/client_wrapper.py | 4 +-
src/phenoml/fhir2omop/client.py | 70 +++++++++++++++++--
src/phenoml/fhir2omop/raw_client.py | 70 +++++++++++++++++--
.../fhir2omop/types/create_omop_response.py | 5 +-
13 files changed, 247 insertions(+), 41 deletions(-)
create mode 100644 src/phenoml/agent/errors/conflict_error.py
diff --git a/.fern/metadata.json b/.fern/metadata.json
index e4684b3..596f6d3 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": "0.0.0.dev0"
}
\ No newline at end of file
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..cc86d42 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ dynamic = ["version"]
[tool.poetry]
name = "phenoml"
-version = "16.2.0"
+version = "0.0.0.dev0"
description = ""
readme = "README.md"
authors = []
@@ -31,9 +31,6 @@ classifiers = [
packages = [
{ include = "phenoml", from = "src"}
]
-include = [
- { path = "src/phenoml/openapi/openapi.json", format = ["sdist", "wheel"] }
-]
[tool.poetry.urls]
Repository = 'https://github.com/phenoml/phenoml-python-sdk'
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..3421d69 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/0.0.0.dev0",
"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": "0.0.0.dev0",
**(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)
From 93f79b877106e9e2d6246f7cfdd82badcaec0a0c Mon Sep 17 00:00:00 2001
From: fern-api <115122769+fern-api[bot]@users.noreply.github.com>
Date: Thu, 18 Jun 2026 18:07:55 +0000
Subject: [PATCH 2/5] [fern-autoversion] feat: add ConflictError for concurrent
session detection and expand fhir2omop docs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Introduce a new ConflictError (HTTP 409) raised by the agent chat
endpoints when overlapping turns are submitted for the same session ID.
Also expand fhir2omop docstrings with a detailed FHIR-to-OMOP resource
mapping table and clarify the semantics of the `dropped` field.
Key changes:
- Add `phenoml.agent.errors.ConflictError` (ApiError subclass, status 409) and export it from `phenoml.agent`
- Raise `ConflictError` in all four chat client variants (sync/async, raw/high-level) when the server returns 409
- Update `session_id` docstring to document the one-active-request-per-session constraint
- Expand `client.fhir2omop.create()` docstring with a full FHIR resource → OMOP table mapping and unsupported-resource behaviour
- Clarify `CreateOmopResponse.dropped` field description: only supported resource types with missing required data appear here
🌿 Generated with Fern
---
.fern/metadata.json | 2 +-
.fern/replay.lock | 2 +-
changelog.md | 9 +++++++++
pyproject.toml | 2 +-
src/phenoml/core/client_wrapper.py | 4 ++--
5 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/.fern/metadata.json b/.fern/metadata.json
index 596f6d3..585ba06 100644
--- a/.fern/metadata.json
+++ b/.fern/metadata.json
@@ -13,5 +13,5 @@
"invokedBy": "ci",
"requestedVersion": "AUTO",
"ciProvider": "unknown",
- "sdkVersion": "0.0.0.dev0"
+ "sdkVersion": "16.3.0"
}
\ No newline at end of file
diff --git a/.fern/replay.lock b/.fern/replay.lock
index aa2c39d..3f00cca 100644
--- a/.fern/replay.lock
+++ b/.fern/replay.lock
@@ -81,7 +81,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..99bd7cc 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 when the agent chat endpoint returns HTTP 409; callers can now catch this explicitly to detect concurrent session conflicts.
+
+### Changed
+- **`client.agent.chat` `session_id` parameter** — docstring now documents that only one request may be active per session at a time; overlapping turns for the same session return 409 Conflict (now surfaced as `ConflictError`).
+- **`client.fhir2omop.create()` docstring** — expanded with a full FHIR resource → OMOP table mapping (e.g. `Observation` with numeric value → `measurement`, `AllergyIntolerance` → `observation`) and clarifies which resource types are silently ignored vs. listed under `dropped`.
+- **`CreateOmopResponse.dropped`** — field description clarified: only supported resource instances missing required subject/patient, code, or medication reference data appear here; unsupported resource types are silently ignored and never listed.
+
## [16.2.0] - 2026-06-15
### Added
- **`Provider`** — `"aidbox"` is now a supported FHIR provider value in the `Provider` union type.
diff --git a/pyproject.toml b/pyproject.toml
index cc86d42..aced66c 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 = []
diff --git a/src/phenoml/core/client_wrapper.py b/src/phenoml/core/client_wrapper.py
index 3421d69..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/0.0.0.dev0",
+ "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": "0.0.0.dev0",
+ "X-Fern-SDK-Version": "16.3.0",
**(self.get_custom_headers() or {}),
}
token = self._get_token()
From 16025802de99440aa4d1e96ef42416b4cf32946c Mon Sep 17 00:00:00 2001
From: fern-api <115122769+fern-api[bot]@users.noreply.github.com>
Date: Thu, 18 Jun 2026 18:07:57 +0000
Subject: [PATCH 3/5] [fern-replay] Applied customizations
Patches applied (1):
- patch-6516695e: Release 15.0.2: restore bundled openapi.json packaging (#169)
---
.fern/replay.lock | 23 +++++++++++++++++++----
pyproject.toml | 3 +++
2 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/.fern/replay.lock b/.fern/replay.lock
index 3f00cca..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"}
diff --git a/pyproject.toml b/pyproject.toml
index aced66c..678bcb9 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -31,6 +31,9 @@ classifiers = [
packages = [
{ include = "phenoml", from = "src"}
]
+include = [
+ { path = "src/phenoml/openapi/openapi.json", format = ["sdist", "wheel"] }
+]
[tool.poetry.urls]
Repository = 'https://github.com/phenoml/phenoml-python-sdk'
From 437f46cf36a578ba2adc3ca4530af23bd8f2ea37 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Thu, 18 Jun 2026 18:08:20 +0000
Subject: [PATCH 4/5] chore: sync OpenAPI spec + code-examples for
fbaef4c66e97232edfaacb20d23d476aa286ecdd [skip ci]
---
code-examples.json | 4 ++--
src/phenoml/openapi/openapi.json | 18 ++++++++++++------
2 files changed, 14 insertions(+), 8 deletions(-)
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/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"
}
From c49a9a448d7693b18c4ad04091cfc4c49ef6656a Mon Sep 17 00:00:00 2001
From: Gavin Sharp
Date: Thu, 18 Jun 2026 19:02:40 -0400
Subject: [PATCH 5/5] release: 16.3.0 - add agent conflict errors
---
changelog.md | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/changelog.md b/changelog.md
index 99bd7cc..fb5e474 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,11 +1,11 @@
## [16.3.0] - 2026-06-18
### Added
-- **`phenoml.agent.errors.ConflictError`** — new `ApiError` subclass raised when the agent chat endpoint returns HTTP 409; callers can now catch this explicitly to detect concurrent session conflicts.
+- **`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` `session_id` parameter** — docstring now documents that only one request may be active per session at a time; overlapping turns for the same session return 409 Conflict (now surfaced as `ConflictError`).
-- **`client.fhir2omop.create()` docstring** — expanded with a full FHIR resource → OMOP table mapping (e.g. `Observation` with numeric value → `measurement`, `AllergyIntolerance` → `observation`) and clarifies which resource types are silently ignored vs. listed under `dropped`.
-- **`CreateOmopResponse.dropped`** — field description clarified: only supported resource instances missing required subject/patient, code, or medication reference data appear here; unsupported resource types are silently ignored and never listed.
+- **`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
@@ -576,4 +576,3 @@ from phenoml import PhenomlClient
* Update documentation to reflect removed parameter
* Remove AgentCreateRequest.is_active field from type definitions
* 🌿 Generated with Fern
-