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
dataface/ai/llm.py
ADDED
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
"""Thin LLM client adapters for the terminal agent."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
from collections.abc import Iterator
|
|
8
|
+
from typing import Any, Protocol
|
|
9
|
+
|
|
10
|
+
import httpx
|
|
11
|
+
|
|
12
|
+
from dataface._install_hint import install_hint
|
|
13
|
+
from dataface.ai.events import ContentDelta, StreamEvent, ThinkingStatus, ToolCallEvent
|
|
14
|
+
from dataface.ai.tool_schemas import ALL_TOOLS
|
|
15
|
+
|
|
16
|
+
DEFAULT_OPENAI_MODEL = "gpt-4.1-mini"
|
|
17
|
+
DEFAULT_ANTHROPIC_MODEL = "claude-sonnet-4-5"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def infer_provider(model: str | None) -> str:
|
|
21
|
+
if model and model.startswith("anthropic:"):
|
|
22
|
+
return "anthropic"
|
|
23
|
+
if model and model.startswith("openai:"):
|
|
24
|
+
return "openai"
|
|
25
|
+
if model and model.lower().startswith("claude"):
|
|
26
|
+
return "anthropic"
|
|
27
|
+
if model and model.lower().startswith(("gpt", "o1", "o3", "o4")):
|
|
28
|
+
return "openai"
|
|
29
|
+
if not model and not os.getenv("OPENAI_API_KEY") and os.getenv("ANTHROPIC_API_KEY"):
|
|
30
|
+
return "anthropic"
|
|
31
|
+
return "openai"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _strip_provider_prefix(model: str | None) -> str | None:
|
|
35
|
+
if model and ":" in model:
|
|
36
|
+
provider, _, raw_model = model.partition(":")
|
|
37
|
+
if provider in {"openai", "anthropic"} and raw_model:
|
|
38
|
+
return raw_model
|
|
39
|
+
return model
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _resolve_model(
|
|
43
|
+
explicit_model: str | None,
|
|
44
|
+
env_var: str,
|
|
45
|
+
default_model: str,
|
|
46
|
+
) -> str:
|
|
47
|
+
return _strip_provider_prefix(explicit_model) or os.getenv(env_var) or default_model
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _normalize_openai_tools(
|
|
51
|
+
tools: list[dict[str, Any]] | None,
|
|
52
|
+
) -> list[dict[str, Any]]:
|
|
53
|
+
source_tools = tools or ALL_TOOLS
|
|
54
|
+
if not source_tools:
|
|
55
|
+
return []
|
|
56
|
+
if "input_schema" in source_tools[0]:
|
|
57
|
+
return [
|
|
58
|
+
{
|
|
59
|
+
"type": "function",
|
|
60
|
+
"name": tool["name"],
|
|
61
|
+
"description": tool["description"],
|
|
62
|
+
"parameters": tool["input_schema"],
|
|
63
|
+
}
|
|
64
|
+
for tool in source_tools
|
|
65
|
+
]
|
|
66
|
+
return source_tools
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _normalize_anthropic_tools(
|
|
70
|
+
tools: list[dict[str, Any]] | None,
|
|
71
|
+
) -> list[dict[str, Any]]:
|
|
72
|
+
source_tools = tools or ALL_TOOLS
|
|
73
|
+
if not source_tools:
|
|
74
|
+
return []
|
|
75
|
+
if "input_schema" in source_tools[0]:
|
|
76
|
+
return [
|
|
77
|
+
{
|
|
78
|
+
"name": tool["name"],
|
|
79
|
+
"description": tool["description"],
|
|
80
|
+
"input_schema": tool["input_schema"],
|
|
81
|
+
}
|
|
82
|
+
for tool in source_tools
|
|
83
|
+
]
|
|
84
|
+
return source_tools
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class LLMClientError(RuntimeError):
|
|
88
|
+
"""Raised when a provider request fails."""
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _is_openai_api_error(exc: Exception) -> bool:
|
|
92
|
+
try:
|
|
93
|
+
from openai import APIError
|
|
94
|
+
except ImportError:
|
|
95
|
+
return isinstance(exc, httpx.HTTPError)
|
|
96
|
+
return isinstance(exc, (APIError, httpx.HTTPError))
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _is_anthropic_api_error(exc: Exception) -> bool:
|
|
100
|
+
try:
|
|
101
|
+
from anthropic import APIError
|
|
102
|
+
except ImportError:
|
|
103
|
+
return isinstance(exc, httpx.HTTPError)
|
|
104
|
+
return isinstance(exc, (APIError, httpx.HTTPError))
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# -- Provider stream adapter ------------------------------------------------
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _iter_anthropic_stream(stream_ctx: Any) -> Iterator[StreamEvent]:
|
|
111
|
+
"""Parse Anthropic Messages API stream context manager into typed events."""
|
|
112
|
+
with stream_ctx as stream:
|
|
113
|
+
for event in stream:
|
|
114
|
+
if event.type == "content_block_delta" and event.delta.type == "text_delta":
|
|
115
|
+
yield ContentDelta(delta=event.delta.text)
|
|
116
|
+
|
|
117
|
+
final_message = stream.get_final_message()
|
|
118
|
+
|
|
119
|
+
for block in final_message.content:
|
|
120
|
+
if block.type == "tool_use":
|
|
121
|
+
yield ToolCallEvent(
|
|
122
|
+
id=block.id, name=block.name, arguments=dict(block.input)
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
# -- Client protocol and implementations ------------------------------------
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class LLMClient(Protocol):
|
|
130
|
+
"""Provider-neutral streaming interface."""
|
|
131
|
+
|
|
132
|
+
provider: str
|
|
133
|
+
model: str
|
|
134
|
+
|
|
135
|
+
def stream_with_tools(
|
|
136
|
+
self,
|
|
137
|
+
*,
|
|
138
|
+
messages: list[dict[str, Any]],
|
|
139
|
+
system_prompt: str,
|
|
140
|
+
tools: list[dict[str, Any]] | None = None,
|
|
141
|
+
) -> Iterator[StreamEvent]: ...
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class OpenAIClient:
|
|
145
|
+
"""Responses API client with streaming output and tool calls."""
|
|
146
|
+
|
|
147
|
+
provider = "openai"
|
|
148
|
+
|
|
149
|
+
def __init__(self, model: str | None = None, api_key: str | None = None) -> None:
|
|
150
|
+
self.model = _resolve_model(
|
|
151
|
+
model,
|
|
152
|
+
"OPENAI_MODEL",
|
|
153
|
+
DEFAULT_OPENAI_MODEL,
|
|
154
|
+
)
|
|
155
|
+
self.api_key = api_key or os.getenv("OPENAI_API_KEY")
|
|
156
|
+
self._client: Any = None
|
|
157
|
+
self._previous_response_id: str | None = None
|
|
158
|
+
self._sent_message_count = 0
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def client(self) -> Any:
|
|
162
|
+
if self._client is None:
|
|
163
|
+
try:
|
|
164
|
+
from openai import OpenAI
|
|
165
|
+
except ImportError as exc:
|
|
166
|
+
raise RuntimeError(
|
|
167
|
+
f"OpenAI client is not installed. Install with: {install_hint('chat')}"
|
|
168
|
+
) from exc
|
|
169
|
+
self._client = OpenAI(api_key=self.api_key)
|
|
170
|
+
return self._client
|
|
171
|
+
|
|
172
|
+
def create(self, **kwargs: Any) -> Any:
|
|
173
|
+
"""Non-streaming Responses API call with unified error handling.
|
|
174
|
+
|
|
175
|
+
Wraps ``client.responses.create()`` with the same exception
|
|
176
|
+
handling used by the streaming path, translating API and network
|
|
177
|
+
errors into :class:`LLMClientError`.
|
|
178
|
+
"""
|
|
179
|
+
try:
|
|
180
|
+
return self.client.responses.create(**kwargs)
|
|
181
|
+
except Exception as exc:
|
|
182
|
+
if _is_openai_api_error(exc):
|
|
183
|
+
raise LLMClientError(str(exc)) from exc
|
|
184
|
+
raise
|
|
185
|
+
|
|
186
|
+
def _messages_to_input(
|
|
187
|
+
self, messages: list[dict[str, Any]], incremental: bool
|
|
188
|
+
) -> list[dict[str, Any]]:
|
|
189
|
+
source_messages = (
|
|
190
|
+
messages[self._sent_message_count :] if incremental else messages
|
|
191
|
+
)
|
|
192
|
+
items: list[dict[str, Any]] = []
|
|
193
|
+
for message in source_messages:
|
|
194
|
+
role = message["role"]
|
|
195
|
+
if not incremental and (
|
|
196
|
+
role == "tool" or (role == "assistant" and message.get("tool_calls"))
|
|
197
|
+
):
|
|
198
|
+
raise LLMClientError(
|
|
199
|
+
"OpenAI client requires an unbroken previous_response_id chain for tool-use history."
|
|
200
|
+
)
|
|
201
|
+
if role in {"user", "assistant"}:
|
|
202
|
+
content = message.get("content")
|
|
203
|
+
if content:
|
|
204
|
+
items.append({"role": role, "content": content})
|
|
205
|
+
elif role == "tool":
|
|
206
|
+
items.append(
|
|
207
|
+
{
|
|
208
|
+
"type": "function_call_output",
|
|
209
|
+
"call_id": message["tool_call_id"],
|
|
210
|
+
"output": message["content"],
|
|
211
|
+
}
|
|
212
|
+
)
|
|
213
|
+
return items
|
|
214
|
+
|
|
215
|
+
def stream_with_tools(
|
|
216
|
+
self,
|
|
217
|
+
*,
|
|
218
|
+
messages: list[dict[str, Any]],
|
|
219
|
+
system_prompt: str,
|
|
220
|
+
tools: list[dict[str, Any]] | None = None,
|
|
221
|
+
) -> Iterator[StreamEvent]:
|
|
222
|
+
incremental = self._previous_response_id is not None
|
|
223
|
+
input_items = self._messages_to_input(messages, incremental=incremental)
|
|
224
|
+
if not input_items:
|
|
225
|
+
return
|
|
226
|
+
|
|
227
|
+
previous_response_id = self._previous_response_id
|
|
228
|
+
pending_response_id = previous_response_id
|
|
229
|
+
|
|
230
|
+
kwargs: dict[str, Any] = {
|
|
231
|
+
"model": self.model,
|
|
232
|
+
"instructions": system_prompt,
|
|
233
|
+
"input": input_items,
|
|
234
|
+
"tools": _normalize_openai_tools(tools),
|
|
235
|
+
"stream": True,
|
|
236
|
+
}
|
|
237
|
+
if self._previous_response_id:
|
|
238
|
+
kwargs["previous_response_id"] = self._previous_response_id
|
|
239
|
+
|
|
240
|
+
try:
|
|
241
|
+
stream = self.client.responses.create(**kwargs)
|
|
242
|
+
except Exception as exc:
|
|
243
|
+
if _is_openai_api_error(exc):
|
|
244
|
+
raise LLMClientError(str(exc)) from exc
|
|
245
|
+
raise
|
|
246
|
+
try:
|
|
247
|
+
# Keep OpenAI parsing inline here because previous_response_id tracking
|
|
248
|
+
# and rollback on stream failure are part of the same control flow.
|
|
249
|
+
for event in stream:
|
|
250
|
+
event_type = getattr(event, "type", "")
|
|
251
|
+
|
|
252
|
+
if event_type == "response.created":
|
|
253
|
+
pending_response_id = event.response.id
|
|
254
|
+
continue
|
|
255
|
+
|
|
256
|
+
if event_type == "response.output_text.delta":
|
|
257
|
+
yield ContentDelta(delta=event.delta)
|
|
258
|
+
continue
|
|
259
|
+
|
|
260
|
+
if event_type == "response.reasoning_summary_text.delta":
|
|
261
|
+
yield ThinkingStatus(status=event.delta)
|
|
262
|
+
continue
|
|
263
|
+
|
|
264
|
+
if event_type != "response.output_item.done":
|
|
265
|
+
continue
|
|
266
|
+
|
|
267
|
+
item = event.item
|
|
268
|
+
if item.type != "function_call":
|
|
269
|
+
continue
|
|
270
|
+
|
|
271
|
+
arguments = json.loads(item.arguments) if item.arguments else {}
|
|
272
|
+
yield ToolCallEvent(
|
|
273
|
+
id=item.call_id, name=item.name, arguments=arguments
|
|
274
|
+
)
|
|
275
|
+
except Exception as exc:
|
|
276
|
+
self._previous_response_id = previous_response_id
|
|
277
|
+
if _is_openai_api_error(exc):
|
|
278
|
+
raise LLMClientError(str(exc)) from exc
|
|
279
|
+
raise
|
|
280
|
+
|
|
281
|
+
self._previous_response_id = pending_response_id
|
|
282
|
+
self._sent_message_count = len(messages)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
class AnthropicClient:
|
|
286
|
+
"""Messages API client with tool-use support."""
|
|
287
|
+
|
|
288
|
+
provider = "anthropic"
|
|
289
|
+
|
|
290
|
+
def __init__(self, model: str | None = None, api_key: str | None = None) -> None:
|
|
291
|
+
self.model = _resolve_model(
|
|
292
|
+
model,
|
|
293
|
+
"ANTHROPIC_MODEL",
|
|
294
|
+
DEFAULT_ANTHROPIC_MODEL,
|
|
295
|
+
)
|
|
296
|
+
self.api_key = api_key or os.getenv("ANTHROPIC_API_KEY")
|
|
297
|
+
self._client: Any = None
|
|
298
|
+
|
|
299
|
+
@property
|
|
300
|
+
def client(self) -> Any:
|
|
301
|
+
if self._client is None:
|
|
302
|
+
try:
|
|
303
|
+
from anthropic import Anthropic
|
|
304
|
+
except ImportError as exc:
|
|
305
|
+
raise RuntimeError(
|
|
306
|
+
f"Anthropic client is not installed. Install with: {install_hint('chat')}"
|
|
307
|
+
) from exc
|
|
308
|
+
self._client = Anthropic(api_key=self.api_key)
|
|
309
|
+
return self._client
|
|
310
|
+
|
|
311
|
+
def _messages_to_input(
|
|
312
|
+
self, messages: list[dict[str, Any]]
|
|
313
|
+
) -> list[dict[str, Any]]:
|
|
314
|
+
converted: list[dict[str, Any]] = []
|
|
315
|
+
pending_tool_results: list[dict[str, Any]] = []
|
|
316
|
+
|
|
317
|
+
def flush_tool_results() -> None:
|
|
318
|
+
if pending_tool_results:
|
|
319
|
+
converted.append(
|
|
320
|
+
{"role": "user", "content": list(pending_tool_results)}
|
|
321
|
+
)
|
|
322
|
+
pending_tool_results.clear()
|
|
323
|
+
|
|
324
|
+
for message in messages:
|
|
325
|
+
role = message["role"]
|
|
326
|
+
if role == "tool":
|
|
327
|
+
pending_tool_results.append(
|
|
328
|
+
{
|
|
329
|
+
"type": "tool_result",
|
|
330
|
+
"tool_use_id": message["tool_call_id"],
|
|
331
|
+
"content": message["content"],
|
|
332
|
+
}
|
|
333
|
+
)
|
|
334
|
+
continue
|
|
335
|
+
|
|
336
|
+
flush_tool_results()
|
|
337
|
+
|
|
338
|
+
if role == "assistant" and message.get("tool_calls"):
|
|
339
|
+
blocks: list[dict[str, Any]] = []
|
|
340
|
+
if message.get("content"):
|
|
341
|
+
blocks.append({"type": "text", "text": message["content"]})
|
|
342
|
+
for tool_call in message["tool_calls"]:
|
|
343
|
+
blocks.append(
|
|
344
|
+
{
|
|
345
|
+
"type": "tool_use",
|
|
346
|
+
"id": tool_call["id"],
|
|
347
|
+
"name": tool_call["name"],
|
|
348
|
+
"input": tool_call["arguments"],
|
|
349
|
+
}
|
|
350
|
+
)
|
|
351
|
+
converted.append({"role": "assistant", "content": blocks})
|
|
352
|
+
continue
|
|
353
|
+
|
|
354
|
+
content = message.get("content")
|
|
355
|
+
if content:
|
|
356
|
+
converted.append(
|
|
357
|
+
{"role": role, "content": [{"type": "text", "text": content}]}
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
flush_tool_results()
|
|
361
|
+
return converted
|
|
362
|
+
|
|
363
|
+
def stream_with_tools(
|
|
364
|
+
self,
|
|
365
|
+
*,
|
|
366
|
+
messages: list[dict[str, Any]],
|
|
367
|
+
system_prompt: str,
|
|
368
|
+
tools: list[dict[str, Any]] | None = None,
|
|
369
|
+
) -> Iterator[StreamEvent]:
|
|
370
|
+
try:
|
|
371
|
+
yield from _iter_anthropic_stream(
|
|
372
|
+
self.client.messages.stream(
|
|
373
|
+
model=self.model,
|
|
374
|
+
system=system_prompt,
|
|
375
|
+
messages=self._messages_to_input(messages),
|
|
376
|
+
tools=_normalize_anthropic_tools(tools),
|
|
377
|
+
max_tokens=4096,
|
|
378
|
+
)
|
|
379
|
+
)
|
|
380
|
+
except Exception as exc:
|
|
381
|
+
if _is_anthropic_api_error(exc):
|
|
382
|
+
raise LLMClientError(str(exc)) from exc
|
|
383
|
+
raise
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def create_client(provider: str | None = None, model: str | None = None) -> LLMClient:
|
|
387
|
+
"""Create an LLM client from explicit provider or model naming."""
|
|
388
|
+
if (
|
|
389
|
+
not provider
|
|
390
|
+
and not model
|
|
391
|
+
and not os.getenv("OPENAI_API_KEY")
|
|
392
|
+
and not os.getenv("ANTHROPIC_API_KEY")
|
|
393
|
+
):
|
|
394
|
+
raise RuntimeError(
|
|
395
|
+
"No LLM API key found. Set OPENAI_API_KEY or ANTHROPIC_API_KEY "
|
|
396
|
+
"in the environment, or pass --model to select a provider explicitly."
|
|
397
|
+
)
|
|
398
|
+
resolved_provider = provider or infer_provider(model)
|
|
399
|
+
if resolved_provider == "anthropic":
|
|
400
|
+
return AnthropicClient(model=model)
|
|
401
|
+
if resolved_provider == "openai":
|
|
402
|
+
return OpenAIClient(model=model)
|
|
403
|
+
raise ValueError(f"Unsupported provider: {resolved_provider}")
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Dataface MCP (Model Context Protocol) Server.
|
|
2
|
+
|
|
3
|
+
This module provides an MCP server that enables AI assistants (Claude, Cursor,
|
|
4
|
+
ChatGPT, etc.) to interact with Dataface dashboards through a standardized
|
|
5
|
+
protocol.
|
|
6
|
+
|
|
7
|
+
Architecture:
|
|
8
|
+
Resources (read-only context):
|
|
9
|
+
- dataface://dashboards - List of dashboards in project
|
|
10
|
+
- dataface://dashboard/{path} - Dashboard content and structure
|
|
11
|
+
- dataface://docs/all - Whole DATAFACE_SYNTAX.md (full YAML reference)
|
|
12
|
+
- dataface://docs/{topic} - One H2 section of the YAML reference
|
|
13
|
+
- dataface://guide/dashboard-design - Dashboard design principles
|
|
14
|
+
- dataface://guide/report-design - Report design principles
|
|
15
|
+
- dataface://guide/dashboard-build - Build-test-iterate workflow
|
|
16
|
+
- dataface://guide/dashboard-review - Dashboard review (structural + visual)
|
|
17
|
+
|
|
18
|
+
Tools (actions):
|
|
19
|
+
- render_dashboard - Validate + render; pass as_link=true for URL-only (folds view_dashboard)
|
|
20
|
+
- execute_query - Run SQL against data sources
|
|
21
|
+
- query_face - Run one named query from a face YAML and return columns + rows
|
|
22
|
+
- schema - Drill the data hierarchy: source → schema → table → column
|
|
23
|
+
- search_dashboards - Search dashboards by keyword/structure
|
|
24
|
+
- docs - Browse Dataface YAML reference docs offline
|
|
25
|
+
|
|
26
|
+
Usage:
|
|
27
|
+
# Configure MCP for your AI client
|
|
28
|
+
dft init mcp cursor # or: vscode, claude, claude-code, codex, copilot, print
|
|
29
|
+
dft init mcp --all
|
|
30
|
+
|
|
31
|
+
# Start the MCP server (stdio mode)
|
|
32
|
+
dft mcp serve
|
|
33
|
+
|
|
34
|
+
# Or programmatically
|
|
35
|
+
from dataface.ai.mcp import create_server
|
|
36
|
+
server = create_server()
|
|
37
|
+
await server.run()
|
|
38
|
+
|
|
39
|
+
For more information about MCP, see:
|
|
40
|
+
https://modelcontextprotocol.io/
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
from dataface.ai.context import DatafaceAIContext
|
|
44
|
+
from dataface.ai.mcp.server import create_server, run_server
|
|
45
|
+
|
|
46
|
+
__all__ = [
|
|
47
|
+
# Server
|
|
48
|
+
"create_server",
|
|
49
|
+
"run_server",
|
|
50
|
+
"DatafaceAIContext",
|
|
51
|
+
]
|