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.
Files changed (455) hide show
  1. d3_format/__init__.py +14 -0
  2. d3_format/errors.py +19 -0
  3. d3_format/format.py +551 -0
  4. d3_format/spec.py +159 -0
  5. dataface/DATAFACE_SYNTAX.md +1135 -0
  6. dataface/__init__.py +93 -0
  7. dataface/_docs_site.py +20 -0
  8. dataface/_install_hint.py +26 -0
  9. dataface/agent_api/__init__.py +79 -0
  10. dataface/agent_api/_init_templates/__init__.py +0 -0
  11. dataface/agent_api/_init_templates/agents_dft_snippet.md +26 -0
  12. dataface/agent_api/_init_templates/dataface.yml +15 -0
  13. dataface/agent_api/_init_templates/faces-dataface.yml +144 -0
  14. dataface/agent_api/_init_templates/index.md +24 -0
  15. dataface/agent_api/_paths.py +118 -0
  16. dataface/agent_api/_project_agents_md.py +43 -0
  17. dataface/agent_api/_session_store.py +486 -0
  18. dataface/agent_api/_state.py +28 -0
  19. dataface/agent_api/chat.py +221 -0
  20. dataface/agent_api/dashboards.py +257 -0
  21. dataface/agent_api/describe.py +366 -0
  22. dataface/agent_api/describe_query.py +120 -0
  23. dataface/agent_api/docs/__init__.py +25 -0
  24. dataface/agent_api/docs/_loader.py +292 -0
  25. dataface/agent_api/docs/yaml-reference.md +2757 -0
  26. dataface/agent_api/file_refs.py +118 -0
  27. dataface/agent_api/init.py +126 -0
  28. dataface/agent_api/inspect.py +128 -0
  29. dataface/agent_api/mcp_install.py +170 -0
  30. dataface/agent_api/query.py +274 -0
  31. dataface/agent_api/schema.py +658 -0
  32. dataface/agent_api/schema_search.py +284 -0
  33. dataface/agent_api/search.py +270 -0
  34. dataface/agent_api/skill_install.py +141 -0
  35. dataface/agent_api/skill_render.py +90 -0
  36. dataface/agent_api/skills.py +293 -0
  37. dataface/agent_api/surface_aliases.yaml +128 -0
  38. dataface/agent_api/validate.py +175 -0
  39. dataface/agent_api/validate_query.py +84 -0
  40. dataface/ai/__init__.py +39 -0
  41. dataface/ai/agent.py +139 -0
  42. dataface/ai/context.py +45 -0
  43. dataface/ai/events.py +62 -0
  44. dataface/ai/external_mcp.py +610 -0
  45. dataface/ai/generate_sql.py +96 -0
  46. dataface/ai/llm.py +403 -0
  47. dataface/ai/mcp/__init__.py +51 -0
  48. dataface/ai/mcp/server.py +289 -0
  49. dataface/ai/memories.py +85 -0
  50. dataface/ai/prompts.py +177 -0
  51. dataface/ai/schema_context.py +138 -0
  52. dataface/ai/skills/before-after-comparison/SKILL.md +102 -0
  53. dataface/ai/skills/before-after-comparison/examples/before-after-comparison.yml +24 -0
  54. dataface/ai/skills/dashboard-build/SKILL.md +212 -0
  55. dataface/ai/skills/dashboard-build/examples/_smoke.yml +15 -0
  56. dataface/ai/skills/dashboard-design/SKILL.md +182 -0
  57. dataface/ai/skills/dashboard-review/SKILL.md +113 -0
  58. dataface/ai/skills/dashboard-structural-review/SKILL.md +173 -0
  59. dataface/ai/skills/dashboard-visual-review/SKILL.md +139 -0
  60. dataface/ai/skills/dataface-mcp-setup/SKILL.md +177 -0
  61. dataface/ai/skills/dataface-troubleshooting/SKILL.md +225 -0
  62. dataface/ai/skills/drill-down-link/SKILL.md +112 -0
  63. dataface/ai/skills/drill-down-link/examples/drill-down-link.yml +27 -0
  64. dataface/ai/skills/faceted-small-multiples/SKILL.md +116 -0
  65. dataface/ai/skills/faceted-small-multiples/examples/faceted-small-multiples.yml +33 -0
  66. dataface/ai/skills/filter-bar-with-variables/SKILL.md +105 -0
  67. dataface/ai/skills/filter-bar-with-variables/examples/filter-bar-with-variables.yml +49 -0
  68. dataface/ai/skills/kpi-row/SKILL.md +101 -0
  69. dataface/ai/skills/kpi-row/examples/kpi-row.yml +55 -0
  70. dataface/ai/skills/report-design/SKILL.md +184 -0
  71. dataface/ai/skills/single-metric-bignum/SKILL.md +90 -0
  72. dataface/ai/skills/single-metric-bignum/examples/single-metric-bignum.yml +27 -0
  73. dataface/ai/skills/table-heavy-ops-dashboard/SKILL.md +114 -0
  74. dataface/ai/skills/table-heavy-ops-dashboard/examples/table-heavy-ops-dashboard.yml +48 -0
  75. dataface/ai/skills/time-series-trend/SKILL.md +93 -0
  76. dataface/ai/skills/time-series-trend/examples/time-series-trend.yml +26 -0
  77. dataface/ai/skills/top-n-with-detail/SKILL.md +98 -0
  78. dataface/ai/skills/top-n-with-detail/examples/top-n-with-detail.yml +45 -0
  79. dataface/ai/skills/two-by-two-grid-overview/SKILL.md +78 -0
  80. dataface/ai/skills/two-by-two-grid-overview/examples/two-by-two-grid-overview.yml +64 -0
  81. dataface/ai/tool_schemas.py +132 -0
  82. dataface/ai/tools/__init__.py +312 -0
  83. dataface/ai/yaml_utils.py +57 -0
  84. dataface/cli/__init__.py +3 -0
  85. dataface/cli/_console.py +48 -0
  86. dataface/cli/_error_format.py +83 -0
  87. dataface/cli/_extras.py +190 -0
  88. dataface/cli/_json_output.py +8 -0
  89. dataface/cli/_parsing.py +17 -0
  90. dataface/cli/_version_info.py +56 -0
  91. dataface/cli/commands/__init__.py +3 -0
  92. dataface/cli/commands/_agent_input.py +205 -0
  93. dataface/cli/commands/_agent_server.py +115 -0
  94. dataface/cli/commands/chat.py +645 -0
  95. dataface/cli/commands/describe.py +107 -0
  96. dataface/cli/commands/docs.py +131 -0
  97. dataface/cli/commands/extension.py +179 -0
  98. dataface/cli/commands/init.py +240 -0
  99. dataface/cli/commands/inspect.py +94 -0
  100. dataface/cli/commands/mcp_init.py +167 -0
  101. dataface/cli/commands/query.py +386 -0
  102. dataface/cli/commands/render.py +291 -0
  103. dataface/cli/commands/schema.py +411 -0
  104. dataface/cli/commands/search.py +49 -0
  105. dataface/cli/commands/serve.py +114 -0
  106. dataface/cli/commands/skills.py +133 -0
  107. dataface/cli/commands/skills_init.py +161 -0
  108. dataface/cli/commands/validate.py +63 -0
  109. dataface/cli/main.py +1501 -0
  110. dataface/core/__init__.py +75 -0
  111. dataface/core/compile/__init__.py +244 -0
  112. dataface/core/compile/_jinja_helpers.py +78 -0
  113. dataface/core/compile/channel.py +222 -0
  114. dataface/core/compile/chart_focus.py +101 -0
  115. dataface/core/compile/chart_resolved.py +169 -0
  116. dataface/core/compile/chart_type_detection.py +489 -0
  117. dataface/core/compile/chart_update.py +261 -0
  118. dataface/core/compile/colors.py +64 -0
  119. dataface/core/compile/compiler.py +904 -0
  120. dataface/core/compile/config.py +823 -0
  121. dataface/core/compile/custom_chart_types.py +208 -0
  122. dataface/core/compile/data_table_attachment.py +1287 -0
  123. dataface/core/compile/detect.py +110 -0
  124. dataface/core/compile/errors.py +302 -0
  125. dataface/core/compile/filter_injection.py +319 -0
  126. dataface/core/compile/introspection.py +527 -0
  127. dataface/core/compile/jinja.py +511 -0
  128. dataface/core/compile/labels_env.py +52 -0
  129. dataface/core/compile/markdown.py +154 -0
  130. dataface/core/compile/meta.py +388 -0
  131. dataface/core/compile/models/__init__.py +0 -0
  132. dataface/core/compile/models/chart/__init__.py +0 -0
  133. dataface/core/compile/models/chart/authored.py +2137 -0
  134. dataface/core/compile/models/chart/compiled.py +398 -0
  135. dataface/core/compile/models/config.py +347 -0
  136. dataface/core/compile/models/face/__init__.py +0 -0
  137. dataface/core/compile/models/face/authored.py +659 -0
  138. dataface/core/compile/models/face/compiled.py +522 -0
  139. dataface/core/compile/models/factories.py +201 -0
  140. dataface/core/compile/models/markers.py +40 -0
  141. dataface/core/compile/models/palette.py +36 -0
  142. dataface/core/compile/models/primitives.py +415 -0
  143. dataface/core/compile/models/query/__init__.py +0 -0
  144. dataface/core/compile/models/query/authored.py +246 -0
  145. dataface/core/compile/models/query/compiled.py +710 -0
  146. dataface/core/compile/models/refs.py +137 -0
  147. dataface/core/compile/models/source.py +611 -0
  148. dataface/core/compile/models/style/__init__.py +0 -0
  149. dataface/core/compile/models/style/authored.py +481 -0
  150. dataface/core/compile/models/style/compiled.py +3399 -0
  151. dataface/core/compile/models/style/merged.py +1682 -0
  152. dataface/core/compile/models/theme.py +362 -0
  153. dataface/core/compile/models/variable/__init__.py +0 -0
  154. dataface/core/compile/models/variable/authored.py +254 -0
  155. dataface/core/compile/models/vega_lite/__init__.py +0 -0
  156. dataface/core/compile/models/vega_lite/config.py +510 -0
  157. dataface/core/compile/models/vega_lite/contracts.py +171 -0
  158. dataface/core/compile/normalize_charts.py +494 -0
  159. dataface/core/compile/normalize_layout.py +1000 -0
  160. dataface/core/compile/normalize_queries.py +297 -0
  161. dataface/core/compile/normalize_variables.py +489 -0
  162. dataface/core/compile/normalizer.py +543 -0
  163. dataface/core/compile/palette.py +1100 -0
  164. dataface/core/compile/parameterized.py +658 -0
  165. dataface/core/compile/parser.py +228 -0
  166. dataface/core/compile/schema.py +20 -0
  167. dataface/core/compile/schema_renderers/__init__.py +0 -0
  168. dataface/core/compile/schema_renderers/json_schema.py +163 -0
  169. dataface/core/compile/schema_renderers/prompt.py +152 -0
  170. dataface/core/compile/schema_renderers/vscode_schema.py +301 -0
  171. dataface/core/compile/sizing.py +2126 -0
  172. dataface/core/compile/sources.py +518 -0
  173. dataface/core/compile/sql_authoring_lint.py +56 -0
  174. dataface/core/compile/style_cascade.py +471 -0
  175. dataface/core/compile/typography.py +299 -0
  176. dataface/core/compile/validator.py +301 -0
  177. dataface/core/compile/variables.py +53 -0
  178. dataface/core/compile/vega_config.py +98 -0
  179. dataface/core/compile/vega_lite/__init__.py +6 -0
  180. dataface/core/compile/vega_lite/validation.py +95 -0
  181. dataface/core/compile/yaml_error_formatter.py +838 -0
  182. dataface/core/connections.py +38 -0
  183. dataface/core/dashboard.py +358 -0
  184. dataface/core/defaults/default_config.yml +101 -0
  185. dataface/core/defaults/palettes/categorical/category-10-dark.yml +32 -0
  186. dataface/core/defaults/palettes/categorical/category-10-light.yml +43 -0
  187. dataface/core/defaults/palettes/categorical/category-10.yml +31 -0
  188. dataface/core/defaults/palettes/categorical/category-6-tonal-blue.yml +22 -0
  189. dataface/core/defaults/palettes/categorical/category-6-tonal-brown.yml +29 -0
  190. dataface/core/defaults/palettes/categorical/category-6-tonal-green.yml +20 -0
  191. dataface/core/defaults/palettes/categorical/category-6-tonal-orange.yml +21 -0
  192. dataface/core/defaults/palettes/categorical/category-6-tonal-purple.yml +20 -0
  193. dataface/core/defaults/palettes/categorical/editorial-10-dark.yml +32 -0
  194. dataface/core/defaults/palettes/categorical/editorial-10.yml +40 -0
  195. dataface/core/defaults/palettes/categorical/hero-6.yml +17 -0
  196. dataface/core/defaults/palettes/categorical/single-blue.yml +11 -0
  197. dataface/core/defaults/palettes/categorical/tableau.yml +20 -0
  198. dataface/core/defaults/palettes/data/xkcd_colors.json +3803 -0
  199. dataface/core/defaults/palettes/diverging/blue-red.yml +25 -0
  200. dataface/core/defaults/palettes/diverging/coolwarm.yml +24 -0
  201. dataface/core/defaults/palettes/diverging/crimson-green.yml +23 -0
  202. dataface/core/defaults/palettes/diverging/orange-teal.yml +23 -0
  203. dataface/core/defaults/palettes/diverging/sunset.yml +24 -0
  204. dataface/core/defaults/palettes/scaffold/dft-creams.yml +38 -0
  205. dataface/core/defaults/palettes/scaffold/dft-grays.yml +53 -0
  206. dataface/core/defaults/palettes/sequential/amber.yml +22 -0
  207. dataface/core/defaults/palettes/sequential/blue.yml +22 -0
  208. dataface/core/defaults/palettes/sequential/brown.yml +22 -0
  209. dataface/core/defaults/palettes/sequential/gray.yml +22 -0
  210. dataface/core/defaults/palettes/sequential/green.yml +22 -0
  211. dataface/core/defaults/palettes/sequential/purple.yml +22 -0
  212. dataface/core/defaults/palettes/sequential/rust.yml +22 -0
  213. dataface/core/defaults/palettes/sequential/teal.yml +22 -0
  214. dataface/core/defaults/palettes/tone/negative.yml +32 -0
  215. dataface/core/defaults/palettes/tone/positive.yml +22 -0
  216. dataface/core/defaults/palettes/tone/warning.yml +22 -0
  217. dataface/core/defaults/themes/_base.yaml +786 -0
  218. dataface/core/defaults/themes/bi.yaml +16 -0
  219. dataface/core/defaults/themes/carbong100.yaml +41 -0
  220. dataface/core/defaults/themes/cream.yaml +122 -0
  221. dataface/core/defaults/themes/dark.yaml +40 -0
  222. dataface/core/defaults/themes/diagnostics-title-angle-extreme.yaml +9 -0
  223. dataface/core/defaults/themes/diagnostics-title-baseline-extreme.yaml +9 -0
  224. dataface/core/defaults/themes/diagnostics-title-baseline.yaml +24 -0
  225. dataface/core/defaults/themes/diagnostics-title-center.yaml +8 -0
  226. dataface/core/defaults/themes/diagnostics-title-color-extreme.yaml +24 -0
  227. dataface/core/defaults/themes/diagnostics-title-font-extreme.yaml +25 -0
  228. dataface/core/defaults/themes/diagnostics-title-left.yaml +8 -0
  229. dataface/core/defaults/themes/diagnostics-title-offset-extreme.yaml +9 -0
  230. dataface/core/defaults/themes/diagnostics-title-size-extreme.yaml +24 -0
  231. dataface/core/defaults/themes/diagnostics-title-weight-extreme.yaml +24 -0
  232. dataface/core/defaults/themes/editorial.yaml +147 -0
  233. dataface/core/defaults/themes/light.yaml +30 -0
  234. dataface/core/defaults/themes/looker.yaml +17 -0
  235. dataface/core/defaults/themes/stark.yaml +134 -0
  236. dataface/core/errors/__init__.py +67 -0
  237. dataface/core/errors/codes_compile.py +56 -0
  238. dataface/core/errors/codes_execute.py +177 -0
  239. dataface/core/errors/codes_render.py +106 -0
  240. dataface/core/errors/codes_unknown.py +15 -0
  241. dataface/core/errors/hints.py +74 -0
  242. dataface/core/errors/registry.py +42 -0
  243. dataface/core/errors/structured.py +92 -0
  244. dataface/core/execute/__init__.py +91 -0
  245. dataface/core/execute/adapters/__init__.py +49 -0
  246. dataface/core/execute/adapters/adapter_registry.py +400 -0
  247. dataface/core/execute/adapters/base.py +245 -0
  248. dataface/core/execute/adapters/csv_adapter.py +239 -0
  249. dataface/core/execute/adapters/dbt_adapter.py +283 -0
  250. dataface/core/execute/adapters/dbt_adapter_factory.py +212 -0
  251. dataface/core/execute/adapters/dbt_macro_loader.py +95 -0
  252. dataface/core/execute/adapters/dbt_utils.py +150 -0
  253. dataface/core/execute/adapters/http_adapter.py +224 -0
  254. dataface/core/execute/adapters/metricflow_adapter.py +94 -0
  255. dataface/core/execute/adapters/schema_resolver_adapter.py +144 -0
  256. dataface/core/execute/adapters/sql_adapter.py +710 -0
  257. dataface/core/execute/adapters/values_adapter.py +58 -0
  258. dataface/core/execute/batch.py +744 -0
  259. dataface/core/execute/cache_backend.py +135 -0
  260. dataface/core/execute/cache_keys.py +66 -0
  261. dataface/core/execute/dbt_jinja.py +21 -0
  262. dataface/core/execute/dialects/__init__.py +121 -0
  263. dataface/core/execute/dialects/athena.py +75 -0
  264. dataface/core/execute/dialects/base.py +302 -0
  265. dataface/core/execute/dialects/bigquery.py +38 -0
  266. dataface/core/execute/dialects/databricks.py +68 -0
  267. dataface/core/execute/dialects/duckdb.py +35 -0
  268. dataface/core/execute/dialects/mysql.py +68 -0
  269. dataface/core/execute/dialects/postgres.py +39 -0
  270. dataface/core/execute/dialects/redshift.py +12 -0
  271. dataface/core/execute/dialects/snowflake.py +51 -0
  272. dataface/core/execute/dialects/sqlserver.py +92 -0
  273. dataface/core/execute/duckdb_cache.py +712 -0
  274. dataface/core/execute/duckdb_config.py +26 -0
  275. dataface/core/execute/errors.py +213 -0
  276. dataface/core/execute/executor.py +1249 -0
  277. dataface/core/execute/parallel.py +162 -0
  278. dataface/core/execute/setup_sql.py +58 -0
  279. dataface/core/execute/source_registry.py +72 -0
  280. dataface/core/execute/source_resolver.py +255 -0
  281. dataface/core/execute/sql_guard.py +387 -0
  282. dataface/core/execute/sql_literals.py +199 -0
  283. dataface/core/fonts.py +52 -0
  284. dataface/core/inspect/__init__.py +32 -0
  285. dataface/core/inspect/cache_factory.py +98 -0
  286. dataface/core/inspect/db_types.py +162 -0
  287. dataface/core/inspect/dbt_schema.py +96 -0
  288. dataface/core/inspect/defaults.yml +37 -0
  289. dataface/core/inspect/fanout_risk.py +109 -0
  290. dataface/core/inspect/manifest_utils.py +77 -0
  291. dataface/core/inspect/partials/categorical.yml +40 -0
  292. dataface/core/inspect/partials/date.yml +40 -0
  293. dataface/core/inspect/partials/numeric.yml +55 -0
  294. dataface/core/inspect/partition_types.py +38 -0
  295. dataface/core/inspect/query_validator.py +975 -0
  296. dataface/core/inspect/renderer.py +354 -0
  297. dataface/core/inspect/resolver.py +808 -0
  298. dataface/core/inspect/search.py +461 -0
  299. dataface/core/inspect/sources/__init__.py +32 -0
  300. dataface/core/inspect/sources/dbt.py +738 -0
  301. dataface/core/inspect/sources/duckdb_utils.py +66 -0
  302. dataface/core/inspect/templates/__init__.py +1 -0
  303. dataface/core/inspect/templates/categorical_column.yml +196 -0
  304. dataface/core/inspect/templates/charts.yml +109 -0
  305. dataface/core/inspect/templates/date_column.yml +248 -0
  306. dataface/core/inspect/templates/model.yml +138 -0
  307. dataface/core/inspect/templates/numeric_column.yml +261 -0
  308. dataface/core/inspect/templates/quality.yml +80 -0
  309. dataface/core/inspect/templates/string_column.yml +263 -0
  310. dataface/core/project_roots.py +165 -0
  311. dataface/core/render/__init__.py +87 -0
  312. dataface/core/render/board_links.py +176 -0
  313. dataface/core/render/chart/__init__.py +27 -0
  314. dataface/core/render/chart/arc_attached_table.py +251 -0
  315. dataface/core/render/chart/artifacts.py +16 -0
  316. dataface/core/render/chart/callout.py +225 -0
  317. dataface/core/render/chart/decisions.py +358 -0
  318. dataface/core/render/chart/geo.py +700 -0
  319. dataface/core/render/chart/kpi.py +916 -0
  320. dataface/core/render/chart/labels.py +76 -0
  321. dataface/core/render/chart/pipeline.py +818 -0
  322. dataface/core/render/chart/presentation.py +36 -0
  323. dataface/core/render/chart/profile.py +3438 -0
  324. dataface/core/render/chart/render_single.py +347 -0
  325. dataface/core/render/chart/renderers.py +193 -0
  326. dataface/core/render/chart/rendering.py +565 -0
  327. dataface/core/render/chart/serialization.py +90 -0
  328. dataface/core/render/chart/spark.py +496 -0
  329. dataface/core/render/chart/spark_bar.py +370 -0
  330. dataface/core/render/chart/spec_builders.py +154 -0
  331. dataface/core/render/chart/standard_renderer.py +2645 -0
  332. dataface/core/render/chart/table.py +2957 -0
  333. dataface/core/render/chart/table_support.py +1452 -0
  334. dataface/core/render/chart/tick_values.py +66 -0
  335. dataface/core/render/chart/time_unit_detect.py +809 -0
  336. dataface/core/render/chart/title_overflow.py +157 -0
  337. dataface/core/render/chart/type_inference.py +122 -0
  338. dataface/core/render/chart/validation.py +99 -0
  339. dataface/core/render/chart/vega_lite.py +125 -0
  340. dataface/core/render/chart/vega_lite_types.py +268 -0
  341. dataface/core/render/chart/vl_field_maps.py +346 -0
  342. dataface/core/render/chart_interactivity.py +24 -0
  343. dataface/core/render/control_registry.py +287 -0
  344. dataface/core/render/converters/__init__.py +24 -0
  345. dataface/core/render/converters/chart.py +276 -0
  346. dataface/core/render/converters/html.py +98 -0
  347. dataface/core/render/converters/pdf.py +40 -0
  348. dataface/core/render/converters/png.py +41 -0
  349. dataface/core/render/errors.py +144 -0
  350. dataface/core/render/face_api.py +160 -0
  351. dataface/core/render/faces.py +1194 -0
  352. dataface/core/render/font_measurement.py +48 -0
  353. dataface/core/render/font_support.py +197 -0
  354. dataface/core/render/fonts/DFTSansTabular-Regular.ttf +0 -0
  355. dataface/core/render/fonts/DFTSansTabular-Regular.woff2 +0 -0
  356. dataface/core/render/fonts/DFTSerifOldstyleProportional-Regular.ttf +0 -0
  357. dataface/core/render/fonts/DFTSerifOldstyleTabular-Regular.ttf +0 -0
  358. dataface/core/render/fonts/InterVariable.ttf +0 -0
  359. dataface/core/render/fonts/InterVariable.woff2 +0 -0
  360. dataface/core/render/fonts/NOTO_COLOR_EMOJI_LICENSE.txt +93 -0
  361. dataface/core/render/fonts/NOTO_EMOJI_LICENSE.txt +93 -0
  362. dataface/core/render/fonts/NotoColorEmoji-Regular.ttf +0 -0
  363. dataface/core/render/fonts/NotoColorEmoji-Regular.woff2 +0 -0
  364. dataface/core/render/fonts/NotoEmoji-Regular.ttf +0 -0
  365. dataface/core/render/fonts/NotoEmoji-Regular.woff2 +0 -0
  366. dataface/core/render/fonts/SOURCE_CODE_PRO_LICENSE.txt +93 -0
  367. dataface/core/render/fonts/SOURCE_SERIF_4_LICENSE.txt +98 -0
  368. dataface/core/render/fonts/SourceCodePro-Regular.ttf +0 -0
  369. dataface/core/render/fonts/SourceSerif4-Regular.ttf +0 -0
  370. dataface/core/render/fonts/_emoji_font_face.css +43 -0
  371. dataface/core/render/fonts/source-serif-4-variable-latin.woff2 +0 -0
  372. dataface/core/render/format_utils.py +329 -0
  373. dataface/core/render/geo_defaults.yml +28 -0
  374. dataface/core/render/json_format.py +146 -0
  375. dataface/core/render/layout_sizing.py +865 -0
  376. dataface/core/render/layouts.py +541 -0
  377. dataface/core/render/markdown_defaults.yml +16 -0
  378. dataface/core/render/missing_vars_prompt.py +79 -0
  379. dataface/core/render/placeholder.py +389 -0
  380. dataface/core/render/render_result.py +14 -0
  381. dataface/core/render/renderer.py +467 -0
  382. dataface/core/render/script_embedding.py +16 -0
  383. dataface/core/render/svg_utils.py +212 -0
  384. dataface/core/render/template_loader.py +69 -0
  385. dataface/core/render/templates/controls/_styles.css +606 -0
  386. dataface/core/render/templates/controls/checkbox.html +16 -0
  387. dataface/core/render/templates/controls/date.html +16 -0
  388. dataface/core/render/templates/controls/number.html +19 -0
  389. dataface/core/render/templates/controls/readonly.html +9 -0
  390. dataface/core/render/templates/controls/select.html +21 -0
  391. dataface/core/render/templates/controls/slider.html +22 -0
  392. dataface/core/render/templates/controls/text.html +16 -0
  393. dataface/core/render/templates/scripts/chart_interactivity.js +191 -0
  394. dataface/core/render/templates/scripts/variables.js +976 -0
  395. dataface/core/render/templates/svg/grid_pattern.svg +3 -0
  396. dataface/core/render/templates/svg/styles.css +51 -0
  397. dataface/core/render/terminal.py +311 -0
  398. dataface/core/render/terminal_charts.py +563 -0
  399. dataface/core/render/terminal_defaults.yml +2 -0
  400. dataface/core/render/terminal_layouts.py +299 -0
  401. dataface/core/render/terminal_text.py +31 -0
  402. dataface/core/render/text/__init__.py +1 -0
  403. dataface/core/render/text/case.py +113 -0
  404. dataface/core/render/text_format.py +129 -0
  405. dataface/core/render/utils.py +106 -0
  406. dataface/core/render/variable_controls.py +946 -0
  407. dataface/core/render/variable_input_refinement.py +140 -0
  408. dataface/core/render/warnings/__init__.py +15 -0
  409. dataface/core/render/warnings/bar_color_1_to_1_with_x.py +80 -0
  410. dataface/core/render/warnings/base.py +44 -0
  411. dataface/core/render/warnings/fanout_risk.py +15 -0
  412. dataface/core/render/warnings/from_query_diagnostic.py +56 -0
  413. dataface/core/render/warnings/missing_join_predicate.py +13 -0
  414. dataface/core/render/warnings/query_parse_error.py +14 -0
  415. dataface/core/render/warnings/query_returned_zero_rows.py +42 -0
  416. dataface/core/render/warnings/reaggregation.py +14 -0
  417. dataface/core/render/warnings/registry.py +45 -0
  418. dataface/core/render/warnings/suppression.py +46 -0
  419. dataface/core/render/warnings/temporal_single_point.py +63 -0
  420. dataface/core/render/warnings/unreferenced_chart.py +15 -0
  421. dataface/core/render/warnings/y_encoding_mostly_null.py +76 -0
  422. dataface/core/render/yaml_format.py +167 -0
  423. dataface/core/resolve_face.py +195 -0
  424. dataface/core/schema/__init__.py +0 -0
  425. dataface/core/schema/guidance.py +151 -0
  426. dataface/core/scoped_paths.py +59 -0
  427. dataface/core/serve/__init__.py +14 -0
  428. dataface/core/serve/bootstrap.py +39 -0
  429. dataface/core/serve/embedded.py +57 -0
  430. dataface/core/serve/port.py +129 -0
  431. dataface/core/serve/server.py +938 -0
  432. dataface/core/serve/templates/__init__.py +0 -0
  433. dataface/core/serve/templates/directory.yml +6 -0
  434. dataface/core/serve/templates/error.html.j2 +217 -0
  435. dataface/core/utils.py +121 -0
  436. dataface/core/validate.py +64 -0
  437. dataface/integrations/__init__.py +0 -0
  438. dataface/integrations/highlighting.py +351 -0
  439. dataface/integrations/markdown.py +537 -0
  440. dataface/py.typed +0 -0
  441. dataface-0.1.2.dist-info/METADATA +375 -0
  442. dataface-0.1.2.dist-info/RECORD +455 -0
  443. dataface-0.1.2.dist-info/WHEEL +4 -0
  444. dataface-0.1.2.dist-info/entry_points.txt +2 -0
  445. dataface-0.1.2.dist-info/licenses/LICENSE +202 -0
  446. mdsvg/__init__.py +168 -0
  447. mdsvg/fonts.py +656 -0
  448. mdsvg/images.py +299 -0
  449. mdsvg/parser.py +629 -0
  450. mdsvg/playground.py +284 -0
  451. mdsvg/py.typed +2 -0
  452. mdsvg/renderer.py +1623 -0
  453. mdsvg/style.py +355 -0
  454. mdsvg/types.py +200 -0
  455. 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
+ }