osi
osi ¶
OSI Semantic Layer integration for crew-dcs.
Exports Domo Data Models and Dataset Views (DSVs) into the Open Semantic Index (OSI) format — a vendor-neutral semantic layer schema that can be consumed by AI agents and BI tooling.
Phase 1.0 scope: - DataModelTemplate → list[OsiSemanticModel] via DataModelConverter - ViewDefinition → list[OsiSemanticModel] via DsvConverter - YAML / JSON file export via export_to_file() - Live DomoSemanticModel → list[OsiSemanticModel] via from_domo_semantic_model()
Phase 1.5 scope (shipped):
- Beast Mode aggregated columns → OsiMetric via Beast Mode route
(DataModelConverter.convert(..., beastmodes=..., domo_instance=...),
wired end-to-end through from_domo_semantic_model())
- AI_Readiness_Column subType == "METRIC" → OsiMetric (primary path,
DataModelConverter and DsvConverter both)
- DOMO_BEAST_MODE() reference resolution — exported metric expressions
are self-contained; an unresolved reference raises
UnresolvedBeastModeReferenceError rather than shipping silently
Usage
from crew_dcs.integrations.osi import from_domo_semantic_model
osi_models = await from_domo_semantic_model(domo_semantic_model) for m in osi_models: print(m.to_yaml)
DataModelConverter ¶
Bases: OsiConverter
Converts a Domo DataModelTemplate to a list of OsiSemanticModels.
One OsiSemanticModel is produced per DataModelObject (source table). Join key columns become OsiEntity instances; all other columns are classified as dimensions or metrics based on AI_Readiness subType, falling back to data-type inference.
Cross-model relationships (JOINs) are attached to the left-side model.
Metrics (Phase 1.5) come from two routes, per the PRD's classification
rules — both can contribute to the same model, they are not mutually
exclusive:
1. Primary: columns with AI_Readiness_Column.subType == 'METRIC'.
2. Fallback: Beast Modes with BeastModeTemplate.aggregated is True,
passed in via the beastmodes param (keyed by datasource_id).
A Beast Mode whose name collides with an AI-Readiness-derived
metric name is skipped — the AI Readiness path wins.
Usage
converter = DataModelConverter() models = converter.convert(template, datasets) converter.export_to_file(models, "output.yaml")
With Beast Mode metrics:¶
models = converter.convert( template, datasets, beastmodes={"ds-orders": [aggregated_template, ...]}, domo_instance="mycompany", )
convert ¶
convert(
source,
datasets: dict,
beastmodes: (
dict[str, list[BeastModeTemplate]] | None
) = None,
domo_instance: str | None = None,
**options
) -> list[OsiSemanticModel]
Convert a DataModelTemplate to OSI semantic models.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
DataModelTemplate with objects and relationships |
required | |
datasets
|
dict
|
dict mapping datasource_id -> DomoDataset (or None) |
required |
beastmodes
|
dict[str, list[BeastModeTemplate]] | None
|
dict mapping datasource_id -> list[BeastModeTemplate]
(Phase 1.5). Only templates with |
None
|
domo_instance
|
str | None
|
Domo instance hostname, recorded on Beast-Mode-
derived metrics' |
None
|
**options
|
Unused beyond the params above |
{}
|
Returns:
| Type | Description |
|---|---|
list[OsiSemanticModel]
|
list[OsiSemanticModel], one per DataModelObject |
Source code in src/crew_dcs/integrations/osi/data_model_converter.py
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | |
DsvConverter ¶
Bases: OsiConverter
Converts a Domo ViewDefinition (DSV) to a list of OsiSemanticModels.
One OsiSemanticModel is produced per participating dataset: the base (FROM) dataset plus each JOIN target. Cardinality is always None for DSV joins because the ViewJoin schema does not expose it.
Usage
converter = DsvConverter() models = converter.convert(view_def, datasets) converter.export_to_file(models, "output.yaml")
convert ¶
convert(
source, datasets: dict, **options
) -> list[OsiSemanticModel]
Convert a ViewDefinition to OSI semantic models.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
ViewDefinition with from_item and joins |
required | |
datasets
|
dict
|
dict mapping datasource_id -> DomoDataset (or None) |
required |
**options
|
Unused in Phase 1.0 |
{}
|
Returns:
| Type | Description |
|---|---|
list[OsiSemanticModel]
|
list[OsiSemanticModel], one per participating dataset |
Source code in src/crew_dcs/integrations/osi/dsv_converter.py
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | |
OsiDimension
dataclass
¶
OsiDimension(
name: str,
type: str,
description: str = "",
synonyms: list[str] = list(),
domo_extensions: dict = dict(),
)
A dimension (non-aggregatable field) in an OSI semantic model.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Column name |
type |
str
|
"categorical" or "time" |
description |
str
|
Human-readable description (from AI Readiness if available) |
synonyms |
list[str]
|
Alternative names (from AI Readiness if available) |
domo_extensions |
dict
|
DOMO-specific metadata |
OsiEntity
dataclass
¶
OsiEntity(
name: str, type: str, domo_extensions: dict = dict()
)
An entity (join key column) in an OSI semantic model.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Column name |
type |
str
|
"primary" (left/source side) or "foreign" (right/target side) |
domo_extensions |
dict
|
DOMO-specific metadata to include in custom_extensions |
OsiMermaidConverter
dataclass
¶
OsiMermaidConverter()
Convert a list of OsiSemanticModel objects to a MermaidERDiagram.
Each OsiSemanticModel becomes one entity. Entities, dimensions, and metrics become typed columns. Relationships become ERD relationship lines with cardinality and join-field labels.
Example
from crew_dcs.integrations.osi import OsiMermaidConverter diagram = OsiMermaidConverter().convert(osi_models, title="DomoStats") print(diagram.export_to_markdown())
convert ¶
convert(
models: list[OsiSemanticModel],
title: str | None = None,
simple: bool = False,
) -> MermaidERDiagram
Convert OSI models to a Mermaid ERD.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
models
|
list[OsiSemanticModel]
|
OSI semantic models to render. |
required |
title
|
str | None
|
Optional diagram title. |
None
|
simple
|
bool
|
When True, render only PK/FK entity columns using the
standard |
False
|
Source code in src/crew_dcs/integrations/osi/mermaid_converter.py
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | |
OsiMetric
dataclass
¶
OsiMetric(
name: str,
expression: str,
datatype: str = "UNKNOWN",
description: str = "",
domo_extensions: dict = dict(),
)
A metric (aggregatable field) in an OSI semantic model.
Field names and shape follow the OSI spec's metrics[] object
(core-spec/spec.yaml: name, expression.dialects[], description,
datatype, custom_extensions). Domo-specific derived data — the mapped
aggregation semantic and the raw Beast Mode functions — is NOT a
spec field (there is no aggregation key in OSI); it lives in
domo_extensions instead, alongside the rest of the vendor metadata.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Metric name |
expression |
str
|
SQL/Beast Mode expression (resolved — self-contained,
never a dangling |
datatype |
str
|
Logical data type (default "UNKNOWN") |
description |
str
|
Human-readable description |
domo_extensions |
dict
|
DOMO-specific metadata (dataset id, beast mode
template id, legacy id, raw |
OsiRelationship
dataclass
¶
OsiRelationship(
from_model: str,
to_model: str,
from_field: str,
to_field: str,
join_type: str,
cardinality: str | None = None,
)
A relationship (JOIN) between two OSI semantic models.
Attributes:
| Name | Type | Description |
|---|---|---|
from_model |
str
|
Name of the source/left model |
to_model |
str
|
Name of the target/right model |
from_field |
str
|
Join column on the from_model side |
to_field |
str
|
Join column on the to_model side |
join_type |
str
|
SQL join type (e.g., "INNER", "LEFT") |
cardinality |
str | None
|
Relationship cardinality (omitted from output if None) |
OsiSemanticModel
dataclass
¶
OsiSemanticModel(
name: str,
source_dataset_id: str,
description: str = "",
entities: list[OsiEntity] = list(),
dimensions: list[OsiDimension] = list(),
metrics: list[OsiMetric] = list(),
relationships: list[OsiRelationship] = list(),
domo_extensions: dict = dict(),
)
Top-level OSI semantic model for a single source table.
One OsiSemanticModel is generated per source table (DataModelObject or dataset participating in a ViewDefinition join).
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Human-readable model name (from DomoDataset.name if available) |
source_dataset_id |
str
|
The underlying Domo dataset ID |
description |
str
|
Model description (from AI_Readiness.unit_of_analysis if set) |
entities |
list[OsiEntity]
|
Join key columns |
dimensions |
list[OsiDimension]
|
Non-aggregatable fields |
metrics |
list[OsiMetric]
|
Aggregatable Beast Mode fields (Phase 1.5) |
relationships |
list[OsiRelationship]
|
Cross-model JOIN relationships |
domo_extensions |
dict
|
DOMO-specific metadata for custom_extensions block |
SemanticConverter ¶
Bases: ABC
Abstract base converter for OSI semantic layer.
Converters transform Domo source definitions (DataModelTemplate, ViewDefinition) into OSI-compliant semantic model output.
All conversion is synchronous — operates on pre-loaded data objects.
convert
abstractmethod
¶
convert(source: Any, datasets: dict, **options) -> list
Convert source definition to a list of OsiSemanticModels.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
Any
|
A DataModelTemplate or ViewDefinition |
required |
datasets
|
dict
|
dict mapping datasource_id -> DomoDataset (or None) |
required |
**options
|
Converter-specific options |
{}
|
Returns:
| Type | Description |
|---|---|
list
|
list[OsiSemanticModel] |
Source code in src/crew_dcs/integrations/osi/converter.py
20 21 22 23 24 25 26 27 28 29 30 31 | |
export_to_file
abstractmethod
¶
export_to_file(
output: list, file_path: str, **options
) -> None
Export converted semantic models to file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
output
|
list
|
Result from convert() |
required |
file_path
|
str
|
Destination file path |
required |
**options
|
format="yaml" (default) | "json" |
{}
|
Source code in src/crew_dcs/integrations/osi/converter.py
33 34 35 36 37 38 39 40 41 | |
UnresolvedBeastModeReferenceError ¶
Bases: ValueError
Raised when a Beast Mode's DOMO_BEAST_MODE() reference can't be resolved.
Emitting an OSI metric with a dangling DOMO_BEAST_MODE(nnn) token
would ship an expression that means nothing outside Domo. Callers must
resolve refs via BeastModeTemplate.resolve_domo_beast_mode_refs()
before converting — this error means that either wasn't done, or the
resolution attempt itself failed to reach every referenced template.
from_domo_semantic_model
async
¶
from_domo_semantic_model(sm) -> list[OsiSemanticModel]
Fetch a data model's definition and convert it to OSI output.
Calls sm.Model.get() to hydrate the definition, then runs
DataModelConverter with an empty datasets dict (Phase 1.0 — no AI
Readiness hydration). Pass enriched datasets directly to
DataModelConverter().convert() if you need AI Readiness metadata.
Phase 1.5: also fetches each source dataset's aggregated Beast Modes and
resolves any DOMO_BEAST_MODE() refs they contain, so the returned
models include Beast-Mode-derived OsiMetric entries with
self-contained expressions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sm
|
DomoSemanticModel with auth embedded. |
required |
Returns:
| Type | Description |
|---|---|
list[OsiSemanticModel]
|
list[OsiSemanticModel], one per source table in the data model. |
Raises:
| Type | Description |
|---|---|
ValueError
|
if the API returns no model definition. |
Source code in src/crew_dcs/integrations/osi/from_domo.py
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | |