Services — API Reference
Application Composition
build_application(config) is the shared composition root for direct Python
consumers. It builds the adapters, the service container, and returns a
GroundworkersApp with both attached.
groundworkers.app
VocabService
VocabService provides vocabulary search and concept navigation over OMOP CDM
vocabulary tables. It is the backing service for the search MCP tools and a
dependency of MappingService.
groundworkers.services.vocab
ConceptMatch
dataclass
A single candidate returned by search_exact, search_normalized, or search_fulltext.
MappedConcept
dataclass
A standard concept that a source concept maps to.
RelatedConceptMapping
dataclass
Relationship-driven mapping result for a single source concept_id.
StandardMapping
dataclass
Navigation result for a single source concept_id.
VocabService
Direct Python API for OMOP vocabulary search and concept navigation.
Exposes raw quality signals (ts_rank, standard_concept flag) so callers can apply their own quality thresholds and decide whether to navigate non-standard results to their standard equivalents.
Raises GroundworkersError for database or query errors. Raises ValueError for invalid arguments.
fts_available
property
True when the concept_name_tsvector sidecar column is present.
navigate_to_standard(concept_ids)
Return standard equivalents for a list of concept_ids via "Maps to" relationship edges.
For concept_ids that are already standard: standard_concepts = [self]. For concept_ids with no outbound "Maps to" relationship: standard_concepts = []. concept_ids not found in the vocabulary are silently omitted.
navigate_to_unit(concept_ids)
Return "Maps to unit" related concepts for the given concept_ids.
navigate_to_value(concept_ids)
Return "Maps to value" related concepts for the given concept_ids.
search_exact(query, *, domain=None, vocabulary_id=None, standard_only=False, active_only=False, include_synonyms=True, parent_ids=None, limit=20)
Case-insensitive exact match against concept_name and optionally concept_synonym_name.
standard_only defaults to False so the caller can inspect non-standard candidates and decide whether to navigate to their standard equivalents.
Returns name matches before synonym matches; deduplicates by concept_id so a concept that matches both name and synonym only appears once.
search_fulltext(query, *, domain=None, vocabulary_id=None, standard_only=False, active_only=False, include_synonyms=True, parent_ids=None, min_rank=0.0, limit=20)
PostgreSQL FTS match using the tsvector sidecar column (GIN-indexed).
Returns (results, fts_available). When fts_available is False the sidecar column was not detected and results is always []; the caller should fall through to another search strategy.
ts_rank is included in each result so the caller can apply its own quality threshold. Synonym FTS is included when the synonym sidecar column is also present; otherwise synonym results are silently omitted.
search_normalized(query, *, domain=None, vocabulary_id=None, standard_only=False, active_only=False, include_synonyms=False, normalization_profile='verbatim', parent_ids=None, remove_stop_phrases=True, limit=20)
Deterministic near-verbatim search after text normalization.
Both the query and candidate text are normalized before comparison. Distinct from full-text search: deterministic equality, not ranked retrieval.
normalize_text_for_matching(text, *, profile='verbatim', remove_stop_phrases=True)
Normalize free text into a deterministic matching form.
serialise_concept_match(match)
Serialise a ConceptMatch to a JSON-safe dict for MCP tool responses.
serialise_related_concept_mapping(mapping)
Serialise a RelatedConceptMapping to a JSON-safe dict for MCP tool responses.
serialise_standard_mapping(mapping)
Serialise a StandardMapping to a JSON-safe dict for MCP tool responses.
GraphService
GraphService is the direct-Python surface for deterministic graph-backed
concept lookup, hierarchy traversal, path finding, standard mapping, and
neighbor exploration.
groundworkers.services.graph
GraphService
Caller-facing graph domain logic backed by the omop-graph runtime.
This service owns multi-step orchestration — hierarchy walks, edge and path
assembly, neighbourhood shaping, standard-mapping, and grounding tier
selection — composing the normalized primitives exposed by
OmopGraphAdapter. It never touches omop-graph internals directly; the
adapter owns the backend and returns plain dicts/tuples.
concept_views(concept_ids)
Batch-fetch normalized concept views keyed by concept_id.
Thin passthrough to the adapter's batch lookup. Returns an empty dict for unknown ids or on backend failure (the adapter swallows enrichment errors), so callers can treat a missing key as "unknown concept".
get_associations(concept_id, *, direction='out', predicate_subkinds=None, active_only=True, limit=50)
Enumerate ASSOCIATION-kind edges (therapeutic/associative links).
get_extended_inheritance(concept_id, *, direction='out', predicate_subkinds=None, active_only=True, limit=50)
Enumerate HIERARCHY-kind relationship edges (extended inheritance).
This is the raw edge-level HIERARCHY view — NOT the concept_ancestor closure used by get_ancestors/get_descendants. See the tool docstring.
ground_with_plan(request)
Execute a caller-supplied grounding plan: run tiers in order, keep the first tier that yields (FTS-overlap filtered) hits, then enrich and shape.
ConceptGroundingService
ConceptGroundingService owns the caller-facing grounding policy over
GraphService: resolver tier ordering, ancestry constraints, and grounding
explanations.
groundworkers.services.grounding
ConceptGroundingService
Use-case policy for free-text grounding over the OMOP graph.
The graph service owns omop-graph execution details. This service owns the caller-facing grounding strategy: domain normalization, optional ancestry constraints, tier ordering, and response explanation.
MappingService
MappingService is the direct-Python API for mapping workflows. The mapping MCP
tools delegate to this service rather than implementing orchestration in the tool
module.
groundworkers.services.mapping
MappingService
Direct Python API for mapping-oriented vocabulary workflows.
TextService
TextService provides LLM-backed clinical text preprocessing. The text MCP tools
(text_normalize, text_decompose, text_disambiguate) delegate to this service.
groundworkers.services.text
LLM-backed clinical text semantics.
This package keeps the public TextService surface small and stable while separating result models, prompt definitions, and service orchestration into modules that can grow independently.
DecomposeResult
Bases: BaseModel
Result of decomposing free text into a list of clinical search terms.
DecomposeTerm
Bases: BaseModel
One extracted clinical concept from a decomposition.
DisambiguateResult
Bases: BaseModel
Result of listing all plausible interpretations of an ambiguous term.
Interpretation
Bases: BaseModel
One candidate interpretation of an ambiguous term.
MappingCleanupResult
Bases: BaseModel
Result of rewriting source text into a more mappable search phrase.
NormalizeResult
Bases: BaseModel
Result of a single-term normalization.
TextService
Direct Python API for LLM-backed clinical text preprocessing.
TextService interprets caller-provided clinical phrases. It normalizes single terms, decomposes multi-concept free text, and surfaces ranked interpretations when the input is ambiguous. The outputs are typed and ready to feed into downstream concept grounding workflows.
All methods raise ValueError for invalid input and GroundworkersError for LLM backend failures or malformed structured responses.
decompose(text, *, domain_hint=None, max_terms=10, model_name=None)
Decompose a free-text clinical description into normalized search terms.
disambiguate(text, *, domain_hint=None, max_interpretations=5, model_name=None)
List all plausible clinical interpretations of an ambiguous term.
mapping_cleanup(text, *, context=None, domain_hint=None, model_name=None)
Rewrite source text into a more mappable OMOP search phrase.
normalize(text, *, domain_hint=None, model_name=None)
Normalize a clinical term, abbreviation, lay phrase, or misspelling.
build_user_prompt(operation, text, **kwargs)
Construct the user-turn prompt for a text operation.
Shared between TextService methods and MCP prompt handlers so both present the same request surface to the LLM.
Clamping is applied here so prompt handlers and service calls always show the same bounded values.
DomainService
DomainService provides LLM-backed batch OMOP domain classification for structured
field labels and example values. The domain_classify MCP tool delegates to this
service.
groundworkers.services.domain
DomainService — LLM-assisted OMOP domain classification for data dictionary attributes.
Accepts a batch of field labels and their example response values, and returns a mapping of label → OMOP domain string for any label that can be confidently classified. Labels that yield null or an unrecognised domain are omitted so that callers fall through to the next resolution tier (keyword heuristics).
Valid domains returned: Measurement, Condition, Observation, Procedure, Drug, Device, Metadata, Identifier.
"Metadata" and "Identifier" are groundcrew-internal sentinel values, not OMOP CDM domains. The ingester treats them as skip signals and does not create SourceItems for those rows.
DomainService
Classify data dictionary field labels into OMOP CDM domains via the LLM adapter.
classify_attributes(label_values, model_name=None)
Classify field labels into OMOP domains.
label_values maps each field label text to a (possibly empty) list of example response-value strings. Returns a dict containing only labels that received a valid domain string — labels mapped to null or an unrecognised value are excluded so callers fall through to the next tier.
Raises BACKEND_UNAVAIL when the LLM cannot be reached.
Raises QUERY_ERROR when the response is not valid JSON.
SourcePlanningService
SourcePlanningService provides stateless source-analysis and assisted planning
workflows for pre-ingest artifacts.
groundworkers.services.source_planning
Stateless source-planning artifacts.
This package defines the neutral planning objects that dependency-facing services can produce without knowing anything about ACP session state, review queues, or persistence models.
AnnotatedTable
dataclass
Bases: NormalisedTable
Normalized table plus semantic annotation.
This is the first stage that may infer downstream semantic intent. It should retain enough signal for caller-facing orchestration to decide whether the result is strong enough to accept, assist, or route for review.
from_normalised(table, **kwargs)
classmethod
Build semantic annotation output from a normalized table.
AssistedColumnRoleClassifier
Apply explicit LLM assistance to uncertain or unresolved columns only.
ColumnAnnotation
dataclass
Semantic annotation for one normalized column.
ColumnRole
Bases: StrEnum
Semantic role assigned during column annotation.
ColumnRoleClassifier
Classify normalized columns using deterministic header and sample rules.
The classifier is intentionally conservative. It should assign obvious semantic roles confidently and leave weaker cases visible as uncertain instead of overfitting to one source-system shape.
classify(table)
Return semantic annotations for one normalized table.
classify_tables(tables)
Classify multiple normalized tables.
FormatDetector
Identify a submitted source container format from bytes and filename.
detect(content, filename=None)
Return the most likely SourceFormat for content.
HeaderProvenance
dataclass
Column-level record of structural cleanup performed during normalization.
Attributes
original:
The raw header surface emitted by decomposition.
normalised:
The final structural header surface used by downstream semantic stages.
operations:
Ordered normalization steps applied to reach normalised.
IngesterRouter
Map semantically annotated tables to ingestion strategies.
The router stays deterministic and stateless. It does not create chunks, items, or review records; it only turns semantic table annotation into a planning decision that caller-facing orchestration can consume.
route(table)
Return (strategy, routed_table) for one annotated table.
route_tables(tables)
Route multiple annotated tables.
IngestionPlan
dataclass
Cross-table planning result consumed by stateful orchestration.
groundable_tables()
Return tables that remain eligible for downstream ingestion.
is_safe_to_ingest()
Return True when the plan has no hard failures.
IngestionStrategy
Bases: StrEnum
Downstream ingestion strategy chosen from semantic annotation outputs.
NormalisationPolicy
dataclass
Configuration for structural cleanup.
The defaults are intentionally conservative
- preserve table identity and row order
- stabilize headers and cell text
- prune only columns that are structurally empty after cleanup
NormalisedTable
dataclass
Structural cleanup output for downstream semantic reasoning.
This is the stage where header surfaces and cell text are stabilized. It must not assign column roles, domain hints, or strategy choices.
from_raw(table, *, headers, rows, sample_rows, header_provenance, normalisation_notes=None, warnings=None)
classmethod
Build a normalized table while preserving non-semantic identity.
PlanningError
dataclass
Hard planning failure that should stop autonomous progression.
PlanningWarning
dataclass
Recoverable planning issue that should remain visible to callers.
PreIngestBundle
dataclass
Top-level stateless planning result envelope.
IngestionPlan remains the core decision object. The optional artifact
lists exist for transparency, debugging, and adapter-facing inspection.
RawTable
dataclass
Post-decomposition table artifact before structural normalization.
RawTable stays close to the extracted source shape. It may preserve
typed or format-specific cell values and should not imply downstream
semantic meaning.
SourceFormat
Bases: StrEnum
Container format of the submitted source content.
SourcePlanningService
Thin composition root for the stateless source-planning pipeline.
This service owns stage sequencing only. It detects source format,
decomposes content into tables, normalises structure, classifies columns,
routes tables to ingestion strategies, and packages the result as a
PreIngestBundle.
classify_columns(table)
Expose deterministic classification directly when needed.
plan_source(content, *, filename=None, caller_hint=None)
Plan one submitted source artifact end to end.
plan_source_assisted(content, *, filename=None, caller_hint=None)
Plan one submitted source artifact with explicit LLM assistance.
plan_tables(tables, *, caller_hint=None)
Plan already-decomposed tables.
plan_tables_assisted(tables, *, caller_hint=None)
Plan already-decomposed tables with explicit LLM assistance.
TableDecomposer
Convert source bytes into one or more RawTable artifacts.
classify_columns(table)
Convenience wrapper for one-shot deterministic classification.
classify_tables(tables)
Convenience wrapper for one-shot classification over many tables.
normalise_headers(*args, **kwargs)
Backward-compatible alias for the PR1 helper name.
normalise_table(table, *, policy=None)
Normalize a raw table into a stable structural representation.
It takes a RawTable and returns a NormalisedTable with cleaned
headers, cleaned cell text, deterministic duplicate handling, conservative
empty-column pruning, and explicit provenance about the structural changes
that were made.
normalise_tables(tables, *, policy=None)
Normalize multiple raw tables with one shared policy.
plan_source(content, *, filename=None, caller_hint=None)
Convenience wrapper for one-shot source planning.
plan_tables(tables, *, caller_hint=None)
Convenience wrapper for planning already-decomposed tables.
route_table(table)
Convenience wrapper for routing one annotated table.
route_tables(tables)
Convenience wrapper for routing many annotated tables.