dataface 0.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- d3_format/__init__.py +14 -0
- d3_format/errors.py +19 -0
- d3_format/format.py +551 -0
- d3_format/spec.py +159 -0
- dataface/DATAFACE_SYNTAX.md +1135 -0
- dataface/__init__.py +93 -0
- dataface/_docs_site.py +20 -0
- dataface/_install_hint.py +26 -0
- dataface/agent_api/__init__.py +79 -0
- dataface/agent_api/_init_templates/__init__.py +0 -0
- dataface/agent_api/_init_templates/agents_dft_snippet.md +26 -0
- dataface/agent_api/_init_templates/dataface.yml +15 -0
- dataface/agent_api/_init_templates/faces-dataface.yml +144 -0
- dataface/agent_api/_init_templates/index.md +24 -0
- dataface/agent_api/_paths.py +118 -0
- dataface/agent_api/_project_agents_md.py +43 -0
- dataface/agent_api/_session_store.py +486 -0
- dataface/agent_api/_state.py +28 -0
- dataface/agent_api/chat.py +221 -0
- dataface/agent_api/dashboards.py +257 -0
- dataface/agent_api/describe.py +366 -0
- dataface/agent_api/describe_query.py +120 -0
- dataface/agent_api/docs/__init__.py +25 -0
- dataface/agent_api/docs/_loader.py +292 -0
- dataface/agent_api/docs/yaml-reference.md +2757 -0
- dataface/agent_api/file_refs.py +118 -0
- dataface/agent_api/init.py +126 -0
- dataface/agent_api/inspect.py +128 -0
- dataface/agent_api/mcp_install.py +170 -0
- dataface/agent_api/query.py +274 -0
- dataface/agent_api/schema.py +658 -0
- dataface/agent_api/schema_search.py +284 -0
- dataface/agent_api/search.py +270 -0
- dataface/agent_api/skill_install.py +141 -0
- dataface/agent_api/skill_render.py +90 -0
- dataface/agent_api/skills.py +293 -0
- dataface/agent_api/surface_aliases.yaml +128 -0
- dataface/agent_api/validate.py +175 -0
- dataface/agent_api/validate_query.py +84 -0
- dataface/ai/__init__.py +39 -0
- dataface/ai/agent.py +139 -0
- dataface/ai/context.py +45 -0
- dataface/ai/events.py +62 -0
- dataface/ai/external_mcp.py +610 -0
- dataface/ai/generate_sql.py +96 -0
- dataface/ai/llm.py +403 -0
- dataface/ai/mcp/__init__.py +51 -0
- dataface/ai/mcp/server.py +289 -0
- dataface/ai/memories.py +85 -0
- dataface/ai/prompts.py +177 -0
- dataface/ai/schema_context.py +138 -0
- dataface/ai/skills/before-after-comparison/SKILL.md +102 -0
- dataface/ai/skills/before-after-comparison/examples/before-after-comparison.yml +24 -0
- dataface/ai/skills/dashboard-build/SKILL.md +212 -0
- dataface/ai/skills/dashboard-build/examples/_smoke.yml +15 -0
- dataface/ai/skills/dashboard-design/SKILL.md +182 -0
- dataface/ai/skills/dashboard-review/SKILL.md +113 -0
- dataface/ai/skills/dashboard-structural-review/SKILL.md +173 -0
- dataface/ai/skills/dashboard-visual-review/SKILL.md +139 -0
- dataface/ai/skills/dataface-mcp-setup/SKILL.md +177 -0
- dataface/ai/skills/dataface-troubleshooting/SKILL.md +225 -0
- dataface/ai/skills/drill-down-link/SKILL.md +112 -0
- dataface/ai/skills/drill-down-link/examples/drill-down-link.yml +27 -0
- dataface/ai/skills/faceted-small-multiples/SKILL.md +116 -0
- dataface/ai/skills/faceted-small-multiples/examples/faceted-small-multiples.yml +33 -0
- dataface/ai/skills/filter-bar-with-variables/SKILL.md +105 -0
- dataface/ai/skills/filter-bar-with-variables/examples/filter-bar-with-variables.yml +49 -0
- dataface/ai/skills/kpi-row/SKILL.md +101 -0
- dataface/ai/skills/kpi-row/examples/kpi-row.yml +55 -0
- dataface/ai/skills/report-design/SKILL.md +184 -0
- dataface/ai/skills/single-metric-bignum/SKILL.md +90 -0
- dataface/ai/skills/single-metric-bignum/examples/single-metric-bignum.yml +27 -0
- dataface/ai/skills/table-heavy-ops-dashboard/SKILL.md +114 -0
- dataface/ai/skills/table-heavy-ops-dashboard/examples/table-heavy-ops-dashboard.yml +48 -0
- dataface/ai/skills/time-series-trend/SKILL.md +93 -0
- dataface/ai/skills/time-series-trend/examples/time-series-trend.yml +26 -0
- dataface/ai/skills/top-n-with-detail/SKILL.md +98 -0
- dataface/ai/skills/top-n-with-detail/examples/top-n-with-detail.yml +45 -0
- dataface/ai/skills/two-by-two-grid-overview/SKILL.md +78 -0
- dataface/ai/skills/two-by-two-grid-overview/examples/two-by-two-grid-overview.yml +64 -0
- dataface/ai/tool_schemas.py +132 -0
- dataface/ai/tools/__init__.py +312 -0
- dataface/ai/yaml_utils.py +57 -0
- dataface/cli/__init__.py +3 -0
- dataface/cli/_console.py +48 -0
- dataface/cli/_error_format.py +83 -0
- dataface/cli/_extras.py +190 -0
- dataface/cli/_json_output.py +8 -0
- dataface/cli/_parsing.py +17 -0
- dataface/cli/_version_info.py +56 -0
- dataface/cli/commands/__init__.py +3 -0
- dataface/cli/commands/_agent_input.py +205 -0
- dataface/cli/commands/_agent_server.py +115 -0
- dataface/cli/commands/chat.py +645 -0
- dataface/cli/commands/describe.py +107 -0
- dataface/cli/commands/docs.py +131 -0
- dataface/cli/commands/extension.py +179 -0
- dataface/cli/commands/init.py +240 -0
- dataface/cli/commands/inspect.py +94 -0
- dataface/cli/commands/mcp_init.py +167 -0
- dataface/cli/commands/query.py +386 -0
- dataface/cli/commands/render.py +291 -0
- dataface/cli/commands/schema.py +411 -0
- dataface/cli/commands/search.py +49 -0
- dataface/cli/commands/serve.py +114 -0
- dataface/cli/commands/skills.py +133 -0
- dataface/cli/commands/skills_init.py +161 -0
- dataface/cli/commands/validate.py +63 -0
- dataface/cli/main.py +1501 -0
- dataface/core/__init__.py +75 -0
- dataface/core/compile/__init__.py +244 -0
- dataface/core/compile/_jinja_helpers.py +78 -0
- dataface/core/compile/channel.py +222 -0
- dataface/core/compile/chart_focus.py +101 -0
- dataface/core/compile/chart_resolved.py +169 -0
- dataface/core/compile/chart_type_detection.py +489 -0
- dataface/core/compile/chart_update.py +261 -0
- dataface/core/compile/colors.py +64 -0
- dataface/core/compile/compiler.py +904 -0
- dataface/core/compile/config.py +823 -0
- dataface/core/compile/custom_chart_types.py +208 -0
- dataface/core/compile/data_table_attachment.py +1287 -0
- dataface/core/compile/detect.py +110 -0
- dataface/core/compile/errors.py +302 -0
- dataface/core/compile/filter_injection.py +319 -0
- dataface/core/compile/introspection.py +527 -0
- dataface/core/compile/jinja.py +511 -0
- dataface/core/compile/labels_env.py +52 -0
- dataface/core/compile/markdown.py +154 -0
- dataface/core/compile/meta.py +388 -0
- dataface/core/compile/models/__init__.py +0 -0
- dataface/core/compile/models/chart/__init__.py +0 -0
- dataface/core/compile/models/chart/authored.py +2137 -0
- dataface/core/compile/models/chart/compiled.py +398 -0
- dataface/core/compile/models/config.py +347 -0
- dataface/core/compile/models/face/__init__.py +0 -0
- dataface/core/compile/models/face/authored.py +659 -0
- dataface/core/compile/models/face/compiled.py +522 -0
- dataface/core/compile/models/factories.py +201 -0
- dataface/core/compile/models/markers.py +40 -0
- dataface/core/compile/models/palette.py +36 -0
- dataface/core/compile/models/primitives.py +415 -0
- dataface/core/compile/models/query/__init__.py +0 -0
- dataface/core/compile/models/query/authored.py +246 -0
- dataface/core/compile/models/query/compiled.py +710 -0
- dataface/core/compile/models/refs.py +137 -0
- dataface/core/compile/models/source.py +611 -0
- dataface/core/compile/models/style/__init__.py +0 -0
- dataface/core/compile/models/style/authored.py +481 -0
- dataface/core/compile/models/style/compiled.py +3399 -0
- dataface/core/compile/models/style/merged.py +1682 -0
- dataface/core/compile/models/theme.py +362 -0
- dataface/core/compile/models/variable/__init__.py +0 -0
- dataface/core/compile/models/variable/authored.py +254 -0
- dataface/core/compile/models/vega_lite/__init__.py +0 -0
- dataface/core/compile/models/vega_lite/config.py +510 -0
- dataface/core/compile/models/vega_lite/contracts.py +171 -0
- dataface/core/compile/normalize_charts.py +494 -0
- dataface/core/compile/normalize_layout.py +1000 -0
- dataface/core/compile/normalize_queries.py +297 -0
- dataface/core/compile/normalize_variables.py +489 -0
- dataface/core/compile/normalizer.py +543 -0
- dataface/core/compile/palette.py +1100 -0
- dataface/core/compile/parameterized.py +658 -0
- dataface/core/compile/parser.py +228 -0
- dataface/core/compile/schema.py +20 -0
- dataface/core/compile/schema_renderers/__init__.py +0 -0
- dataface/core/compile/schema_renderers/json_schema.py +163 -0
- dataface/core/compile/schema_renderers/prompt.py +152 -0
- dataface/core/compile/schema_renderers/vscode_schema.py +301 -0
- dataface/core/compile/sizing.py +2126 -0
- dataface/core/compile/sources.py +518 -0
- dataface/core/compile/sql_authoring_lint.py +56 -0
- dataface/core/compile/style_cascade.py +471 -0
- dataface/core/compile/typography.py +299 -0
- dataface/core/compile/validator.py +301 -0
- dataface/core/compile/variables.py +53 -0
- dataface/core/compile/vega_config.py +98 -0
- dataface/core/compile/vega_lite/__init__.py +6 -0
- dataface/core/compile/vega_lite/validation.py +95 -0
- dataface/core/compile/yaml_error_formatter.py +838 -0
- dataface/core/connections.py +38 -0
- dataface/core/dashboard.py +358 -0
- dataface/core/defaults/default_config.yml +101 -0
- dataface/core/defaults/palettes/categorical/category-10-dark.yml +32 -0
- dataface/core/defaults/palettes/categorical/category-10-light.yml +43 -0
- dataface/core/defaults/palettes/categorical/category-10.yml +31 -0
- dataface/core/defaults/palettes/categorical/category-6-tonal-blue.yml +22 -0
- dataface/core/defaults/palettes/categorical/category-6-tonal-brown.yml +29 -0
- dataface/core/defaults/palettes/categorical/category-6-tonal-green.yml +20 -0
- dataface/core/defaults/palettes/categorical/category-6-tonal-orange.yml +21 -0
- dataface/core/defaults/palettes/categorical/category-6-tonal-purple.yml +20 -0
- dataface/core/defaults/palettes/categorical/editorial-10-dark.yml +32 -0
- dataface/core/defaults/palettes/categorical/editorial-10.yml +40 -0
- dataface/core/defaults/palettes/categorical/hero-6.yml +17 -0
- dataface/core/defaults/palettes/categorical/single-blue.yml +11 -0
- dataface/core/defaults/palettes/categorical/tableau.yml +20 -0
- dataface/core/defaults/palettes/data/xkcd_colors.json +3803 -0
- dataface/core/defaults/palettes/diverging/blue-red.yml +25 -0
- dataface/core/defaults/palettes/diverging/coolwarm.yml +24 -0
- dataface/core/defaults/palettes/diverging/crimson-green.yml +23 -0
- dataface/core/defaults/palettes/diverging/orange-teal.yml +23 -0
- dataface/core/defaults/palettes/diverging/sunset.yml +24 -0
- dataface/core/defaults/palettes/scaffold/dft-creams.yml +38 -0
- dataface/core/defaults/palettes/scaffold/dft-grays.yml +53 -0
- dataface/core/defaults/palettes/sequential/amber.yml +22 -0
- dataface/core/defaults/palettes/sequential/blue.yml +22 -0
- dataface/core/defaults/palettes/sequential/brown.yml +22 -0
- dataface/core/defaults/palettes/sequential/gray.yml +22 -0
- dataface/core/defaults/palettes/sequential/green.yml +22 -0
- dataface/core/defaults/palettes/sequential/purple.yml +22 -0
- dataface/core/defaults/palettes/sequential/rust.yml +22 -0
- dataface/core/defaults/palettes/sequential/teal.yml +22 -0
- dataface/core/defaults/palettes/tone/negative.yml +32 -0
- dataface/core/defaults/palettes/tone/positive.yml +22 -0
- dataface/core/defaults/palettes/tone/warning.yml +22 -0
- dataface/core/defaults/themes/_base.yaml +786 -0
- dataface/core/defaults/themes/bi.yaml +16 -0
- dataface/core/defaults/themes/carbong100.yaml +41 -0
- dataface/core/defaults/themes/cream.yaml +122 -0
- dataface/core/defaults/themes/dark.yaml +40 -0
- dataface/core/defaults/themes/diagnostics-title-angle-extreme.yaml +9 -0
- dataface/core/defaults/themes/diagnostics-title-baseline-extreme.yaml +9 -0
- dataface/core/defaults/themes/diagnostics-title-baseline.yaml +24 -0
- dataface/core/defaults/themes/diagnostics-title-center.yaml +8 -0
- dataface/core/defaults/themes/diagnostics-title-color-extreme.yaml +24 -0
- dataface/core/defaults/themes/diagnostics-title-font-extreme.yaml +25 -0
- dataface/core/defaults/themes/diagnostics-title-left.yaml +8 -0
- dataface/core/defaults/themes/diagnostics-title-offset-extreme.yaml +9 -0
- dataface/core/defaults/themes/diagnostics-title-size-extreme.yaml +24 -0
- dataface/core/defaults/themes/diagnostics-title-weight-extreme.yaml +24 -0
- dataface/core/defaults/themes/editorial.yaml +147 -0
- dataface/core/defaults/themes/light.yaml +30 -0
- dataface/core/defaults/themes/looker.yaml +17 -0
- dataface/core/defaults/themes/stark.yaml +134 -0
- dataface/core/errors/__init__.py +67 -0
- dataface/core/errors/codes_compile.py +56 -0
- dataface/core/errors/codes_execute.py +177 -0
- dataface/core/errors/codes_render.py +106 -0
- dataface/core/errors/codes_unknown.py +15 -0
- dataface/core/errors/hints.py +74 -0
- dataface/core/errors/registry.py +42 -0
- dataface/core/errors/structured.py +92 -0
- dataface/core/execute/__init__.py +91 -0
- dataface/core/execute/adapters/__init__.py +49 -0
- dataface/core/execute/adapters/adapter_registry.py +400 -0
- dataface/core/execute/adapters/base.py +245 -0
- dataface/core/execute/adapters/csv_adapter.py +239 -0
- dataface/core/execute/adapters/dbt_adapter.py +283 -0
- dataface/core/execute/adapters/dbt_adapter_factory.py +212 -0
- dataface/core/execute/adapters/dbt_macro_loader.py +95 -0
- dataface/core/execute/adapters/dbt_utils.py +150 -0
- dataface/core/execute/adapters/http_adapter.py +224 -0
- dataface/core/execute/adapters/metricflow_adapter.py +94 -0
- dataface/core/execute/adapters/schema_resolver_adapter.py +144 -0
- dataface/core/execute/adapters/sql_adapter.py +710 -0
- dataface/core/execute/adapters/values_adapter.py +58 -0
- dataface/core/execute/batch.py +744 -0
- dataface/core/execute/cache_backend.py +135 -0
- dataface/core/execute/cache_keys.py +66 -0
- dataface/core/execute/dbt_jinja.py +21 -0
- dataface/core/execute/dialects/__init__.py +121 -0
- dataface/core/execute/dialects/athena.py +75 -0
- dataface/core/execute/dialects/base.py +302 -0
- dataface/core/execute/dialects/bigquery.py +38 -0
- dataface/core/execute/dialects/databricks.py +68 -0
- dataface/core/execute/dialects/duckdb.py +35 -0
- dataface/core/execute/dialects/mysql.py +68 -0
- dataface/core/execute/dialects/postgres.py +39 -0
- dataface/core/execute/dialects/redshift.py +12 -0
- dataface/core/execute/dialects/snowflake.py +51 -0
- dataface/core/execute/dialects/sqlserver.py +92 -0
- dataface/core/execute/duckdb_cache.py +712 -0
- dataface/core/execute/duckdb_config.py +26 -0
- dataface/core/execute/errors.py +213 -0
- dataface/core/execute/executor.py +1249 -0
- dataface/core/execute/parallel.py +162 -0
- dataface/core/execute/setup_sql.py +58 -0
- dataface/core/execute/source_registry.py +72 -0
- dataface/core/execute/source_resolver.py +255 -0
- dataface/core/execute/sql_guard.py +387 -0
- dataface/core/execute/sql_literals.py +199 -0
- dataface/core/fonts.py +52 -0
- dataface/core/inspect/__init__.py +32 -0
- dataface/core/inspect/cache_factory.py +98 -0
- dataface/core/inspect/db_types.py +162 -0
- dataface/core/inspect/dbt_schema.py +96 -0
- dataface/core/inspect/defaults.yml +37 -0
- dataface/core/inspect/fanout_risk.py +109 -0
- dataface/core/inspect/manifest_utils.py +77 -0
- dataface/core/inspect/partials/categorical.yml +40 -0
- dataface/core/inspect/partials/date.yml +40 -0
- dataface/core/inspect/partials/numeric.yml +55 -0
- dataface/core/inspect/partition_types.py +38 -0
- dataface/core/inspect/query_validator.py +975 -0
- dataface/core/inspect/renderer.py +354 -0
- dataface/core/inspect/resolver.py +808 -0
- dataface/core/inspect/search.py +461 -0
- dataface/core/inspect/sources/__init__.py +32 -0
- dataface/core/inspect/sources/dbt.py +738 -0
- dataface/core/inspect/sources/duckdb_utils.py +66 -0
- dataface/core/inspect/templates/__init__.py +1 -0
- dataface/core/inspect/templates/categorical_column.yml +196 -0
- dataface/core/inspect/templates/charts.yml +109 -0
- dataface/core/inspect/templates/date_column.yml +248 -0
- dataface/core/inspect/templates/model.yml +138 -0
- dataface/core/inspect/templates/numeric_column.yml +261 -0
- dataface/core/inspect/templates/quality.yml +80 -0
- dataface/core/inspect/templates/string_column.yml +263 -0
- dataface/core/project_roots.py +165 -0
- dataface/core/render/__init__.py +87 -0
- dataface/core/render/board_links.py +176 -0
- dataface/core/render/chart/__init__.py +27 -0
- dataface/core/render/chart/arc_attached_table.py +251 -0
- dataface/core/render/chart/artifacts.py +16 -0
- dataface/core/render/chart/callout.py +225 -0
- dataface/core/render/chart/decisions.py +358 -0
- dataface/core/render/chart/geo.py +700 -0
- dataface/core/render/chart/kpi.py +916 -0
- dataface/core/render/chart/labels.py +76 -0
- dataface/core/render/chart/pipeline.py +818 -0
- dataface/core/render/chart/presentation.py +36 -0
- dataface/core/render/chart/profile.py +3438 -0
- dataface/core/render/chart/render_single.py +347 -0
- dataface/core/render/chart/renderers.py +193 -0
- dataface/core/render/chart/rendering.py +565 -0
- dataface/core/render/chart/serialization.py +90 -0
- dataface/core/render/chart/spark.py +496 -0
- dataface/core/render/chart/spark_bar.py +370 -0
- dataface/core/render/chart/spec_builders.py +154 -0
- dataface/core/render/chart/standard_renderer.py +2645 -0
- dataface/core/render/chart/table.py +2957 -0
- dataface/core/render/chart/table_support.py +1452 -0
- dataface/core/render/chart/tick_values.py +66 -0
- dataface/core/render/chart/time_unit_detect.py +809 -0
- dataface/core/render/chart/title_overflow.py +157 -0
- dataface/core/render/chart/type_inference.py +122 -0
- dataface/core/render/chart/validation.py +99 -0
- dataface/core/render/chart/vega_lite.py +125 -0
- dataface/core/render/chart/vega_lite_types.py +268 -0
- dataface/core/render/chart/vl_field_maps.py +346 -0
- dataface/core/render/chart_interactivity.py +24 -0
- dataface/core/render/control_registry.py +287 -0
- dataface/core/render/converters/__init__.py +24 -0
- dataface/core/render/converters/chart.py +276 -0
- dataface/core/render/converters/html.py +98 -0
- dataface/core/render/converters/pdf.py +40 -0
- dataface/core/render/converters/png.py +41 -0
- dataface/core/render/errors.py +144 -0
- dataface/core/render/face_api.py +160 -0
- dataface/core/render/faces.py +1194 -0
- dataface/core/render/font_measurement.py +48 -0
- dataface/core/render/font_support.py +197 -0
- dataface/core/render/fonts/DFTSansTabular-Regular.ttf +0 -0
- dataface/core/render/fonts/DFTSansTabular-Regular.woff2 +0 -0
- dataface/core/render/fonts/DFTSerifOldstyleProportional-Regular.ttf +0 -0
- dataface/core/render/fonts/DFTSerifOldstyleTabular-Regular.ttf +0 -0
- dataface/core/render/fonts/InterVariable.ttf +0 -0
- dataface/core/render/fonts/InterVariable.woff2 +0 -0
- dataface/core/render/fonts/NOTO_COLOR_EMOJI_LICENSE.txt +93 -0
- dataface/core/render/fonts/NOTO_EMOJI_LICENSE.txt +93 -0
- dataface/core/render/fonts/NotoColorEmoji-Regular.ttf +0 -0
- dataface/core/render/fonts/NotoColorEmoji-Regular.woff2 +0 -0
- dataface/core/render/fonts/NotoEmoji-Regular.ttf +0 -0
- dataface/core/render/fonts/NotoEmoji-Regular.woff2 +0 -0
- dataface/core/render/fonts/SOURCE_CODE_PRO_LICENSE.txt +93 -0
- dataface/core/render/fonts/SOURCE_SERIF_4_LICENSE.txt +98 -0
- dataface/core/render/fonts/SourceCodePro-Regular.ttf +0 -0
- dataface/core/render/fonts/SourceSerif4-Regular.ttf +0 -0
- dataface/core/render/fonts/_emoji_font_face.css +43 -0
- dataface/core/render/fonts/source-serif-4-variable-latin.woff2 +0 -0
- dataface/core/render/format_utils.py +329 -0
- dataface/core/render/geo_defaults.yml +28 -0
- dataface/core/render/json_format.py +146 -0
- dataface/core/render/layout_sizing.py +865 -0
- dataface/core/render/layouts.py +541 -0
- dataface/core/render/markdown_defaults.yml +16 -0
- dataface/core/render/missing_vars_prompt.py +79 -0
- dataface/core/render/placeholder.py +389 -0
- dataface/core/render/render_result.py +14 -0
- dataface/core/render/renderer.py +467 -0
- dataface/core/render/script_embedding.py +16 -0
- dataface/core/render/svg_utils.py +212 -0
- dataface/core/render/template_loader.py +69 -0
- dataface/core/render/templates/controls/_styles.css +606 -0
- dataface/core/render/templates/controls/checkbox.html +16 -0
- dataface/core/render/templates/controls/date.html +16 -0
- dataface/core/render/templates/controls/number.html +19 -0
- dataface/core/render/templates/controls/readonly.html +9 -0
- dataface/core/render/templates/controls/select.html +21 -0
- dataface/core/render/templates/controls/slider.html +22 -0
- dataface/core/render/templates/controls/text.html +16 -0
- dataface/core/render/templates/scripts/chart_interactivity.js +191 -0
- dataface/core/render/templates/scripts/variables.js +976 -0
- dataface/core/render/templates/svg/grid_pattern.svg +3 -0
- dataface/core/render/templates/svg/styles.css +51 -0
- dataface/core/render/terminal.py +311 -0
- dataface/core/render/terminal_charts.py +563 -0
- dataface/core/render/terminal_defaults.yml +2 -0
- dataface/core/render/terminal_layouts.py +299 -0
- dataface/core/render/terminal_text.py +31 -0
- dataface/core/render/text/__init__.py +1 -0
- dataface/core/render/text/case.py +113 -0
- dataface/core/render/text_format.py +129 -0
- dataface/core/render/utils.py +106 -0
- dataface/core/render/variable_controls.py +946 -0
- dataface/core/render/variable_input_refinement.py +140 -0
- dataface/core/render/warnings/__init__.py +15 -0
- dataface/core/render/warnings/bar_color_1_to_1_with_x.py +80 -0
- dataface/core/render/warnings/base.py +44 -0
- dataface/core/render/warnings/fanout_risk.py +15 -0
- dataface/core/render/warnings/from_query_diagnostic.py +56 -0
- dataface/core/render/warnings/missing_join_predicate.py +13 -0
- dataface/core/render/warnings/query_parse_error.py +14 -0
- dataface/core/render/warnings/query_returned_zero_rows.py +42 -0
- dataface/core/render/warnings/reaggregation.py +14 -0
- dataface/core/render/warnings/registry.py +45 -0
- dataface/core/render/warnings/suppression.py +46 -0
- dataface/core/render/warnings/temporal_single_point.py +63 -0
- dataface/core/render/warnings/unreferenced_chart.py +15 -0
- dataface/core/render/warnings/y_encoding_mostly_null.py +76 -0
- dataface/core/render/yaml_format.py +167 -0
- dataface/core/resolve_face.py +195 -0
- dataface/core/schema/__init__.py +0 -0
- dataface/core/schema/guidance.py +151 -0
- dataface/core/scoped_paths.py +59 -0
- dataface/core/serve/__init__.py +14 -0
- dataface/core/serve/bootstrap.py +39 -0
- dataface/core/serve/embedded.py +57 -0
- dataface/core/serve/port.py +129 -0
- dataface/core/serve/server.py +938 -0
- dataface/core/serve/templates/__init__.py +0 -0
- dataface/core/serve/templates/directory.yml +6 -0
- dataface/core/serve/templates/error.html.j2 +217 -0
- dataface/core/utils.py +121 -0
- dataface/core/validate.py +64 -0
- dataface/integrations/__init__.py +0 -0
- dataface/integrations/highlighting.py +351 -0
- dataface/integrations/markdown.py +537 -0
- dataface/py.typed +0 -0
- dataface-0.1.2.dist-info/METADATA +375 -0
- dataface-0.1.2.dist-info/RECORD +455 -0
- dataface-0.1.2.dist-info/WHEEL +4 -0
- dataface-0.1.2.dist-info/entry_points.txt +2 -0
- dataface-0.1.2.dist-info/licenses/LICENSE +202 -0
- mdsvg/__init__.py +168 -0
- mdsvg/fonts.py +656 -0
- mdsvg/images.py +299 -0
- mdsvg/parser.py +629 -0
- mdsvg/playground.py +284 -0
- mdsvg/py.typed +2 -0
- mdsvg/renderer.py +1623 -0
- mdsvg/style.py +355 -0
- mdsvg/types.py +200 -0
- mdsvg/utils.py +86 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: time-series-trend
|
|
3
|
+
kind: pattern
|
|
4
|
+
description: >
|
|
5
|
+
Pattern for a line (or area) chart tracking one or more numeric metrics over
|
|
6
|
+
time. Use when the question is "how has X changed over time?" with a date
|
|
7
|
+
dimension on x. Triggers on: 'trend', 'over time', 'time series', 'daily',
|
|
8
|
+
'weekly', 'monthly', 'historical'. Add a date-range variable to make it
|
|
9
|
+
interactive. Do NOT use for category comparisons without a time axis (use
|
|
10
|
+
top-n-with-detail or before-after-comparison). Do NOT use for composition
|
|
11
|
+
over time (use faceted-small-multiples with area type).
|
|
12
|
+
metadata:
|
|
13
|
+
author: fivetran
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Time-Series Trend
|
|
17
|
+
|
|
18
|
+
A line chart with a date dimension on x and a numeric metric on y. Data must
|
|
19
|
+
be monotonically ordered by date; add `ORDER BY date` to every time-series
|
|
20
|
+
query. Add a `date_range` variable when users need to zoom into a window.
|
|
21
|
+
|
|
22
|
+
## When to reach for this
|
|
23
|
+
|
|
24
|
+
- The data has a date/timestamp column and a numeric value per period
|
|
25
|
+
- The question is directional: "is this metric going up or down?"
|
|
26
|
+
- You want to compare two metrics on the same time axis (multi-series)
|
|
27
|
+
|
|
28
|
+
## When NOT to use this
|
|
29
|
+
|
|
30
|
+
- Comparing categories without time → `top-n-with-detail`
|
|
31
|
+
- Showing composition across time → area chart in `faceted-small-multiples`
|
|
32
|
+
- Single current-period metric → `single-metric-bignum`
|
|
33
|
+
|
|
34
|
+
## The pattern
|
|
35
|
+
|
|
36
|
+
```yaml
|
|
37
|
+
variables:
|
|
38
|
+
date_range:
|
|
39
|
+
input: daterange
|
|
40
|
+
column: orders.order_date
|
|
41
|
+
default: ["2025-01-01", "2025-12-31"]
|
|
42
|
+
|
|
43
|
+
queries:
|
|
44
|
+
monthly_revenue:
|
|
45
|
+
sql: |
|
|
46
|
+
SELECT DATE_TRUNC('month', order_date) AS month,
|
|
47
|
+
SUM(revenue) AS revenue
|
|
48
|
+
FROM orders
|
|
49
|
+
WHERE {{ filter_date_range('order_date', date_range) }}
|
|
50
|
+
GROUP BY 1
|
|
51
|
+
ORDER BY 1
|
|
52
|
+
|
|
53
|
+
charts:
|
|
54
|
+
revenue_trend:
|
|
55
|
+
type: line
|
|
56
|
+
query: monthly_revenue
|
|
57
|
+
x: month
|
|
58
|
+
y: revenue
|
|
59
|
+
title: Monthly Revenue
|
|
60
|
+
style:
|
|
61
|
+
axis_x:
|
|
62
|
+
time_unit: yearmonth
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
See `examples/time-series-trend.yml` for the inline-data worked example.
|
|
66
|
+
|
|
67
|
+
## Variations
|
|
68
|
+
|
|
69
|
+
| Variation | YAML knob | When |
|
|
70
|
+
|---|---|---|
|
|
71
|
+
| Multi-series | `color: series_col` | Comparing two segments over time |
|
|
72
|
+
| Area fill | `type: area` | Emphasize magnitude, not just direction |
|
|
73
|
+
| Label cadence | `style.axis_x.label.time_unit` | Label a finer data grain at a coarser readable cadence |
|
|
74
|
+
| Date-range variable | `variables: date_range: input: daterange` | User-controlled window |
|
|
75
|
+
| Rolling window | wrap SQL in a window function | Smooth noisy daily data |
|
|
76
|
+
|
|
77
|
+
## Common pitfalls
|
|
78
|
+
|
|
79
|
+
| Pitfall | Why it breaks | Fix |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| Missing `ORDER BY date` | Jagged, non-temporal line | Always order by the date column |
|
|
82
|
+
| Date column as string without cast | Wrong sort, string ordering | `CAST(date AS DATE)` or use `DATE_TRUNC` |
|
|
83
|
+
| Too many series (>5) | Legend unreadable | Filter or group remainder into "Other" |
|
|
84
|
+
| Hourly data on a monthly face | Too many points, slow | Pre-aggregate to the right grain in SQL |
|
|
85
|
+
|
|
86
|
+
## Worked example
|
|
87
|
+
|
|
88
|
+
See `examples/time-series-trend.yml` — six months of revenue, no warehouse
|
|
89
|
+
needed. Add `variables:` + `WHERE` clause when connecting to a live source.
|
|
90
|
+
|
|
91
|
+
## YAML Reference
|
|
92
|
+
|
|
93
|
+
For syntax and field details: {{ s_yaml_reference_footer }}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
title: Monthly Revenue Trend
|
|
2
|
+
description: Time-series trend pattern — line chart with date on x, metric on y
|
|
3
|
+
|
|
4
|
+
queries:
|
|
5
|
+
monthly_revenue:
|
|
6
|
+
description: Monthly revenue totals, ordered chronologically
|
|
7
|
+
columns: [month, revenue]
|
|
8
|
+
values:
|
|
9
|
+
- ["2025-07-01", 182000]
|
|
10
|
+
- ["2025-08-01", 194000]
|
|
11
|
+
- ["2025-09-01", 208000]
|
|
12
|
+
- ["2025-10-01", 221000]
|
|
13
|
+
- ["2025-11-01", 237000]
|
|
14
|
+
- ["2025-12-01", 248500]
|
|
15
|
+
|
|
16
|
+
charts:
|
|
17
|
+
revenue_trend:
|
|
18
|
+
description: Monthly revenue trajectory over the last six months
|
|
19
|
+
type: line
|
|
20
|
+
query: monthly_revenue
|
|
21
|
+
x: month
|
|
22
|
+
y: revenue
|
|
23
|
+
title: Monthly Revenue
|
|
24
|
+
|
|
25
|
+
rows:
|
|
26
|
+
- revenue_trend
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: top-n-with-detail
|
|
3
|
+
kind: pattern
|
|
4
|
+
description: >
|
|
5
|
+
Pattern pairing a top-N bar chart with a detail table on the same query.
|
|
6
|
+
Use when the question is "which are the top performers?" and the user also
|
|
7
|
+
needs row-level detail. Triggers on: 'top N', 'top products', 'best
|
|
8
|
+
customers', 'ranked list', 'leaderboard', 'ranked + detail'. The bar chart
|
|
9
|
+
gives the ranking at a glance; the table provides drill-in context. Do NOT
|
|
10
|
+
use when there is no natural ranking (use two-by-two-grid-overview). Do NOT
|
|
11
|
+
use when detail is not needed (a plain bar chart suffices).
|
|
12
|
+
metadata:
|
|
13
|
+
author: fivetran
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Top-N with Detail
|
|
17
|
+
|
|
18
|
+
A bar chart ranking the top N categories by a metric, sitting beside a detail
|
|
19
|
+
table that exposes the same rows. One query powers both — add `ORDER BY metric
|
|
20
|
+
DESC LIMIT N` in the SQL so the data arrives pre-ranked.
|
|
21
|
+
|
|
22
|
+
## When to reach for this
|
|
23
|
+
|
|
24
|
+
- You have a "who/what is biggest?" question with a categorical dimension
|
|
25
|
+
- Row-level context matters (e.g., rank + order count + avg order value)
|
|
26
|
+
- The list is bounded and the user benefits from scanning the full ranked table
|
|
27
|
+
|
|
28
|
+
## When NOT to use this
|
|
29
|
+
|
|
30
|
+
- No natural ranking or comparison → plain `bar` chart
|
|
31
|
+
- Too many categories for a table (>50 rows) → add pagination or a filter
|
|
32
|
+
- Time-based ranking → pair with `time-series-trend` instead
|
|
33
|
+
|
|
34
|
+
## The pattern
|
|
35
|
+
|
|
36
|
+
```yaml
|
|
37
|
+
queries:
|
|
38
|
+
top_products:
|
|
39
|
+
sql: |
|
|
40
|
+
SELECT product, SUM(revenue) AS revenue, COUNT(*) AS orders
|
|
41
|
+
FROM orders
|
|
42
|
+
GROUP BY product
|
|
43
|
+
ORDER BY revenue DESC
|
|
44
|
+
LIMIT 10
|
|
45
|
+
|
|
46
|
+
charts:
|
|
47
|
+
ranking_bar:
|
|
48
|
+
type: bar
|
|
49
|
+
query: top_products
|
|
50
|
+
x: product
|
|
51
|
+
y: revenue
|
|
52
|
+
title: Top Products by Revenue
|
|
53
|
+
|
|
54
|
+
detail_table:
|
|
55
|
+
type: table
|
|
56
|
+
query: top_products
|
|
57
|
+
title: Product Detail
|
|
58
|
+
style:
|
|
59
|
+
columns:
|
|
60
|
+
- column: product
|
|
61
|
+
label: Product
|
|
62
|
+
- column: revenue
|
|
63
|
+
label: Revenue
|
|
64
|
+
format: "$,.0f"
|
|
65
|
+
- column: orders
|
|
66
|
+
label: Orders
|
|
67
|
+
|
|
68
|
+
rows:
|
|
69
|
+
- cols: [ranking_bar, detail_table]
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
See `examples/top-n-with-detail.yml` for the inline-data worked example.
|
|
73
|
+
|
|
74
|
+
## Variations
|
|
75
|
+
|
|
76
|
+
| Variation | YAML knob | When |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| Color by category | `color: category_col` on the bar | Distinguish groups within the ranking |
|
|
79
|
+
| Horizontal bars | `type: bar` with long labels reads naturally as horizontal | Long category names |
|
|
80
|
+
| Click-through | add `link: "/detail?id={{ x }}"` to bar chart | Link to a per-item face |
|
|
81
|
+
| Tighter N | `LIMIT 5` | Space-constrained layouts |
|
|
82
|
+
|
|
83
|
+
## Common pitfalls
|
|
84
|
+
|
|
85
|
+
| Pitfall | Why it breaks | Fix |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| Forgetting `ORDER BY` | Arbitrary bar ordering | Always `ORDER BY metric DESC` |
|
|
88
|
+
| Two separate queries | Bar and table can diverge | Use one query for both |
|
|
89
|
+
| Too many bars (>15) | Bar chart unreadable | Set `LIMIT 10` or fewer |
|
|
90
|
+
|
|
91
|
+
## Worked example
|
|
92
|
+
|
|
93
|
+
See `examples/top-n-with-detail.yml` — top 5 products, bar + table, inline
|
|
94
|
+
data. No warehouse required.
|
|
95
|
+
|
|
96
|
+
## YAML Reference
|
|
97
|
+
|
|
98
|
+
For syntax and field details: {{ s_yaml_reference_footer }}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
title: Top Products
|
|
2
|
+
description: Top-N with detail pattern — bar chart and table from the same query
|
|
3
|
+
|
|
4
|
+
queries:
|
|
5
|
+
top_products:
|
|
6
|
+
description: Top 5 products by revenue, pre-ranked
|
|
7
|
+
columns: [product, revenue, orders, avg_order]
|
|
8
|
+
values:
|
|
9
|
+
- ["Widget B", 85680, 320, 268]
|
|
10
|
+
- ["Widget A", 66300, 281, 236]
|
|
11
|
+
- ["Tool Z", 34900, 145, 241]
|
|
12
|
+
- ["Gadget Y", 30490, 122, 250]
|
|
13
|
+
- ["Gadget X", 18350, 88, 208]
|
|
14
|
+
|
|
15
|
+
charts:
|
|
16
|
+
ranking_bar:
|
|
17
|
+
description: Top products ranked by revenue
|
|
18
|
+
type: bar
|
|
19
|
+
query: top_products
|
|
20
|
+
x: product
|
|
21
|
+
y: revenue
|
|
22
|
+
title: Top Products by Revenue
|
|
23
|
+
|
|
24
|
+
detail_table:
|
|
25
|
+
description: Row-level detail for the same top-5 ranking
|
|
26
|
+
type: table
|
|
27
|
+
query: top_products
|
|
28
|
+
title: Product Detail
|
|
29
|
+
style:
|
|
30
|
+
columns:
|
|
31
|
+
product:
|
|
32
|
+
label: Product
|
|
33
|
+
revenue:
|
|
34
|
+
label: Revenue
|
|
35
|
+
format: currency_whole
|
|
36
|
+
orders:
|
|
37
|
+
label: Orders
|
|
38
|
+
avg_order:
|
|
39
|
+
label: Avg Order
|
|
40
|
+
format: currency_whole
|
|
41
|
+
|
|
42
|
+
rows:
|
|
43
|
+
- cols:
|
|
44
|
+
- ranking_bar
|
|
45
|
+
- detail_table
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: two-by-two-grid-overview
|
|
3
|
+
kind: pattern
|
|
4
|
+
description: >
|
|
5
|
+
Pattern for a 2×2 (or 2×3) grid of equally-weighted summary charts giving a
|
|
6
|
+
balanced multi-metric overview. Use when four to six metrics are equally
|
|
7
|
+
important and no single chart dominates. Triggers on: '2x2', 'grid overview',
|
|
8
|
+
'equal weight', 'four charts', 'overview dashboard', 'balanced layout',
|
|
9
|
+
'summary grid'. Each cell carries the same visual weight — no chart is
|
|
10
|
+
emphasized over another. Do NOT use when one chart is the hero (use
|
|
11
|
+
single-metric-bignum or put it in a wider column). Do NOT use when the four
|
|
12
|
+
metrics belong in a KPI row (use kpi-row for aggregated numbers).
|
|
13
|
+
metadata:
|
|
14
|
+
author: fivetran
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Two-by-Two Grid Overview
|
|
18
|
+
|
|
19
|
+
Four charts arranged in a 2×2 grid, each with equal column width, giving users
|
|
20
|
+
a balanced multi-metric overview before diving into detail. Implemented as two
|
|
21
|
+
`rows:` of `cols:` with two items each — Dataface splits the width evenly by
|
|
22
|
+
default.
|
|
23
|
+
|
|
24
|
+
## When to reach for this
|
|
25
|
+
|
|
26
|
+
- A face opens with a balanced overview ("revenue / cost / margin / users")
|
|
27
|
+
- All four charts have equal analytical importance
|
|
28
|
+
- Each chart answers a different question about the same domain
|
|
29
|
+
|
|
30
|
+
## When NOT to use this
|
|
31
|
+
|
|
32
|
+
- One chart is clearly the hero → enlarge it via `width:` or move it to its own row
|
|
33
|
+
- All four are KPI numbers → use `kpi-row` instead (it handles delta and format)
|
|
34
|
+
- More than 6 equally-weighted charts → split into tabs or multiple faces
|
|
35
|
+
|
|
36
|
+
## The pattern
|
|
37
|
+
|
|
38
|
+
```yaml
|
|
39
|
+
rows:
|
|
40
|
+
- title: Overview
|
|
41
|
+
cols:
|
|
42
|
+
- revenue_trend # top-left
|
|
43
|
+
- cost_trend # top-right
|
|
44
|
+
- cols:
|
|
45
|
+
- by_region # bottom-left
|
|
46
|
+
- by_product # bottom-right
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Each chart is defined as usual in `charts:`. The 2×2 is purely a layout
|
|
50
|
+
decision — swap in any chart type per cell.
|
|
51
|
+
|
|
52
|
+
See `examples/two-by-two-grid-overview.yml` for the inline-data worked example.
|
|
53
|
+
|
|
54
|
+
## Variations
|
|
55
|
+
|
|
56
|
+
| Variation | YAML knob | When |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| 2×3 (six cells) | Add a third `cols:` row | Six equally-weighted metrics |
|
|
59
|
+
| Asymmetric | `width: "60%"` on one cell | Slightly more emphasis on one chart |
|
|
60
|
+
| Section title | `title:` on a `rows:` item | Separate the two rows conceptually |
|
|
61
|
+
| Grid layout | `grid: columns: 24` + `col_span: 12` | Finer column control |
|
|
62
|
+
|
|
63
|
+
## Common pitfalls
|
|
64
|
+
|
|
65
|
+
| Pitfall | Why it breaks | Fix |
|
|
66
|
+
|---|---|---|
|
|
67
|
+
| Charts with very different heights | Mismatched row heights look accidental | Use charts of the same type per row |
|
|
68
|
+
| All four showing the same metric | No additional insight | Ensure each cell answers a distinct question |
|
|
69
|
+
| Nesting cols in cols | Unexpected layout behavior | Use rows at the top level, cols inside rows |
|
|
70
|
+
|
|
71
|
+
## Worked example
|
|
72
|
+
|
|
73
|
+
See `examples/two-by-two-grid-overview.yml` — four charts (two line + two bar)
|
|
74
|
+
arranged 2×2 from two inline-data queries. No warehouse required.
|
|
75
|
+
|
|
76
|
+
## YAML Reference
|
|
77
|
+
|
|
78
|
+
For syntax and field details: {{ s_yaml_reference_footer }}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
title: Business Overview
|
|
2
|
+
description: Two-by-two grid overview pattern — four equal-weight summary charts
|
|
3
|
+
|
|
4
|
+
queries:
|
|
5
|
+
monthly:
|
|
6
|
+
description: Monthly revenue and cost trend
|
|
7
|
+
columns: [month, revenue, cost]
|
|
8
|
+
values:
|
|
9
|
+
- ["2025-09-01", 208000, 134000]
|
|
10
|
+
- ["2025-10-01", 221000, 141000]
|
|
11
|
+
- ["2025-11-01", 237000, 149000]
|
|
12
|
+
- ["2025-12-01", 248500, 155000]
|
|
13
|
+
|
|
14
|
+
by_region:
|
|
15
|
+
description: Revenue totals by region
|
|
16
|
+
columns: [region, revenue]
|
|
17
|
+
values:
|
|
18
|
+
- [North, 85000]
|
|
19
|
+
- [East, 71000]
|
|
20
|
+
- [South, 62000]
|
|
21
|
+
- [West, 54000]
|
|
22
|
+
|
|
23
|
+
charts:
|
|
24
|
+
revenue_trend:
|
|
25
|
+
description: Revenue trajectory — is it growing?
|
|
26
|
+
type: line
|
|
27
|
+
query: monthly
|
|
28
|
+
x: month
|
|
29
|
+
y: revenue
|
|
30
|
+
title: Revenue Trend
|
|
31
|
+
|
|
32
|
+
cost_trend:
|
|
33
|
+
description: Cost trajectory — are costs tracking revenue?
|
|
34
|
+
type: line
|
|
35
|
+
query: monthly
|
|
36
|
+
x: month
|
|
37
|
+
y: cost
|
|
38
|
+
title: Cost Trend
|
|
39
|
+
|
|
40
|
+
revenue_by_region:
|
|
41
|
+
description: Which regions drive the most revenue?
|
|
42
|
+
type: bar
|
|
43
|
+
query: by_region
|
|
44
|
+
x: region
|
|
45
|
+
y: revenue
|
|
46
|
+
title: Revenue by Region
|
|
47
|
+
|
|
48
|
+
cost_by_month:
|
|
49
|
+
description: Monthly cost as a bar for easy comparison
|
|
50
|
+
type: bar
|
|
51
|
+
query: monthly
|
|
52
|
+
x: month
|
|
53
|
+
y: cost
|
|
54
|
+
title: Monthly Cost
|
|
55
|
+
|
|
56
|
+
rows:
|
|
57
|
+
- title: Trends
|
|
58
|
+
cols:
|
|
59
|
+
- revenue_trend
|
|
60
|
+
- cost_trend
|
|
61
|
+
- title: Breakdown
|
|
62
|
+
cols:
|
|
63
|
+
- revenue_by_region
|
|
64
|
+
- cost_by_month
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""Canonical tool definitions for Dataface AI interfaces.
|
|
2
|
+
|
|
3
|
+
Single source of truth for tool names, descriptions, and input schemas.
|
|
4
|
+
Consumed by both the MCP server and OpenAI function-calling wrappers.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import textwrap
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from pydantic import BaseModel
|
|
13
|
+
|
|
14
|
+
from dataface.agent_api.dashboards import RenderDashboardArgs
|
|
15
|
+
from dataface.agent_api.describe import DescribeFaceArgs
|
|
16
|
+
from dataface.agent_api.describe_query import DescribeQueryArgs
|
|
17
|
+
from dataface.agent_api.query import ExecuteQueryArgs, QueryFaceArgs
|
|
18
|
+
from dataface.agent_api.schema import SchemaArgs
|
|
19
|
+
from dataface.agent_api.schema_search import SchemaSearchArgs
|
|
20
|
+
from dataface.agent_api.search import SearchDashboardsArgs
|
|
21
|
+
from dataface.agent_api.skills import GetSkillArgs, SearchSkillsArgs
|
|
22
|
+
from dataface.agent_api.validate import ValidateDashboardArgs
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _mcp_tool(name: str, model: type[BaseModel]) -> dict[str, Any]:
|
|
26
|
+
desc = textwrap.dedent(model.__doc__ or "").strip()
|
|
27
|
+
return {
|
|
28
|
+
"name": name,
|
|
29
|
+
"description": desc,
|
|
30
|
+
"input_schema": model.model_json_schema(by_alias=True),
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
VALIDATE_DASHBOARD = _mcp_tool("validate_dashboard", ValidateDashboardArgs)
|
|
35
|
+
RENDER_DASHBOARD = _mcp_tool("render_dashboard", RenderDashboardArgs)
|
|
36
|
+
EXECUTE_QUERY = _mcp_tool("execute_query", ExecuteQueryArgs)
|
|
37
|
+
DESCRIBE_QUERY = _mcp_tool("describe_query", DescribeQueryArgs)
|
|
38
|
+
SCHEMA = _mcp_tool("schema", SchemaArgs)
|
|
39
|
+
SCHEMA_SEARCH = _mcp_tool("schema_search", SchemaSearchArgs)
|
|
40
|
+
SEARCH_DASHBOARDS = _mcp_tool("search_dashboards", SearchDashboardsArgs)
|
|
41
|
+
|
|
42
|
+
DOCS = {
|
|
43
|
+
"name": "docs",
|
|
44
|
+
"description": (
|
|
45
|
+
"Browse the Dataface YAML reference offline. "
|
|
46
|
+
"Modes: no args = topic index (slug + one-line description per H2), "
|
|
47
|
+
"topic='<slug>' = one section, topic='all' = whole reference unsliced, "
|
|
48
|
+
"search='<query>' = substring search across topics. "
|
|
49
|
+
"Use this before writing YAML to learn field names, valid values, "
|
|
50
|
+
"and examples. Call with no args first to see the available topics."
|
|
51
|
+
),
|
|
52
|
+
"input_schema": {
|
|
53
|
+
"type": "object",
|
|
54
|
+
"properties": {
|
|
55
|
+
"topic": {
|
|
56
|
+
"type": "string",
|
|
57
|
+
"description": "Topic slug (e.g. 'face', 'charts', 'cheatsheet') or 'all' for the whole file. Omit for the topic index.",
|
|
58
|
+
},
|
|
59
|
+
"search": {
|
|
60
|
+
"type": "string",
|
|
61
|
+
"description": "Substring query — scans all H2 sections and returns ranked hits",
|
|
62
|
+
},
|
|
63
|
+
"limit": {
|
|
64
|
+
"type": "integer",
|
|
65
|
+
"description": "Max search hits to return (default 5, max 50)",
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
QUERY_FACE = _mcp_tool("query_face", QueryFaceArgs)
|
|
72
|
+
|
|
73
|
+
DESCRIBE_DASHBOARD = _mcp_tool("describe_dashboard", DescribeFaceArgs)
|
|
74
|
+
|
|
75
|
+
LIST_SKILLS = {
|
|
76
|
+
"name": "list_skills",
|
|
77
|
+
"description": (
|
|
78
|
+
"List all agent skills packaged with dft. "
|
|
79
|
+
"Returns name, description, kind (workflow or pattern), and has_examples "
|
|
80
|
+
"for each skill. Call this first to discover what patterns are available, "
|
|
81
|
+
"then use get_skill to read the full guide for the pattern you want, "
|
|
82
|
+
"or search_skills to filter by keyword."
|
|
83
|
+
),
|
|
84
|
+
"input_schema": {"type": "object", "properties": {}},
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
GET_SKILL = _mcp_tool("get_skill", GetSkillArgs)
|
|
88
|
+
SEARCH_SKILLS = _mcp_tool("search_skills", SearchSkillsArgs)
|
|
89
|
+
|
|
90
|
+
ALL_TOOLS: list[dict[str, Any]] = [
|
|
91
|
+
VALIDATE_DASHBOARD,
|
|
92
|
+
RENDER_DASHBOARD,
|
|
93
|
+
EXECUTE_QUERY,
|
|
94
|
+
DESCRIBE_QUERY,
|
|
95
|
+
SCHEMA,
|
|
96
|
+
SCHEMA_SEARCH,
|
|
97
|
+
SEARCH_DASHBOARDS,
|
|
98
|
+
DOCS,
|
|
99
|
+
QUERY_FACE,
|
|
100
|
+
DESCRIBE_DASHBOARD,
|
|
101
|
+
LIST_SKILLS,
|
|
102
|
+
GET_SKILL,
|
|
103
|
+
SEARCH_SKILLS,
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def to_openai_tool(
|
|
108
|
+
tool: dict[str, Any],
|
|
109
|
+
property_subset: list[str] | None = None,
|
|
110
|
+
required: list[str] | None = None,
|
|
111
|
+
) -> dict[str, Any]:
|
|
112
|
+
"""Convert a canonical tool definition to OpenAI function-calling format."""
|
|
113
|
+
schema = dict(tool["input_schema"])
|
|
114
|
+
if property_subset is not None:
|
|
115
|
+
schema = {
|
|
116
|
+
**schema,
|
|
117
|
+
"properties": {
|
|
118
|
+
k: v for k, v in schema["properties"].items() if k in property_subset
|
|
119
|
+
},
|
|
120
|
+
}
|
|
121
|
+
if required is not None:
|
|
122
|
+
schema["required"] = required
|
|
123
|
+
elif "required" in schema and property_subset is not None:
|
|
124
|
+
schema["required"] = [r for r in schema["required"] if r in property_subset]
|
|
125
|
+
return {
|
|
126
|
+
"type": "function",
|
|
127
|
+
"function": {
|
|
128
|
+
"name": tool["name"],
|
|
129
|
+
"description": tool["description"],
|
|
130
|
+
"parameters": schema,
|
|
131
|
+
},
|
|
132
|
+
}
|