Skip to content

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 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.