pytrilogy 0.0.3.108__tar.gz → 0.0.3.110__tar.gz

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.

Potentially problematic release.


This version of pytrilogy might be problematic. Click here for more details.

Files changed (175) hide show
  1. {pytrilogy-0.0.3.108/pytrilogy.egg-info → pytrilogy-0.0.3.110}/PKG-INFO +70 -11
  2. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/README.md +66 -0
  3. pytrilogy-0.0.3.110/pyproject.toml +49 -0
  4. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110/pytrilogy.egg-info}/PKG-INFO +70 -11
  5. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/pytrilogy.egg-info/SOURCES.txt +14 -1
  6. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/pytrilogy.egg-info/requires.txt +3 -0
  7. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/pytrilogy.egg-info/top_level.txt +1 -0
  8. pytrilogy-0.0.3.110/requirements.txt +10 -0
  9. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/__init__.py +1 -1
  10. pytrilogy-0.0.3.110/trilogy/ai/__init__.py +19 -0
  11. pytrilogy-0.0.3.110/trilogy/ai/constants.py +92 -0
  12. pytrilogy-0.0.3.110/trilogy/ai/conversation.py +99 -0
  13. pytrilogy-0.0.3.110/trilogy/ai/enums.py +7 -0
  14. pytrilogy-0.0.3.110/trilogy/ai/execute.py +50 -0
  15. pytrilogy-0.0.3.110/trilogy/ai/models.py +34 -0
  16. pytrilogy-0.0.3.110/trilogy/ai/prompts.py +30 -0
  17. pytrilogy-0.0.3.110/trilogy/ai/providers/anthropic.py +105 -0
  18. pytrilogy-0.0.3.110/trilogy/ai/providers/base.py +22 -0
  19. pytrilogy-0.0.3.110/trilogy/ai/providers/google.py +142 -0
  20. pytrilogy-0.0.3.110/trilogy/ai/providers/openai.py +88 -0
  21. pytrilogy-0.0.3.110/trilogy/ai/providers/utils.py +68 -0
  22. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/dialect/base.py +11 -0
  23. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/dialect/common.py +2 -8
  24. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/dialect/duckdb.py +13 -1
  25. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/executor.py +35 -7
  26. pytrilogy-0.0.3.110/trilogy/std/__init__.py +0 -0
  27. pytrilogy-0.0.3.108/pyproject.toml +0 -11
  28. pytrilogy-0.0.3.108/setup.py +0 -62
  29. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/LICENSE.md +0 -0
  30. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/pytrilogy.egg-info/dependency_links.txt +0 -0
  31. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/pytrilogy.egg-info/entry_points.txt +0 -0
  32. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/setup.cfg +0 -0
  33. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_datatypes.py +0 -0
  34. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_declarations.py +0 -0
  35. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_derived_concepts.py +0 -0
  36. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_discovery_nodes.py +0 -0
  37. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_enums.py +0 -0
  38. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_environment.py +0 -0
  39. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_execute_models.py +0 -0
  40. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_executor.py +0 -0
  41. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_failure.py +0 -0
  42. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_functions.py +0 -0
  43. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_imports.py +0 -0
  44. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_metadata.py +0 -0
  45. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_models.py +0 -0
  46. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_multi_join_assignments.py +0 -0
  47. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_parse_engine.py +0 -0
  48. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_parsing.py +0 -0
  49. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_parsing_failures.py +0 -0
  50. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_partial_handling.py +0 -0
  51. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_query_processing.py +0 -0
  52. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_query_render.py +0 -0
  53. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_select.py +0 -0
  54. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_show.py +0 -0
  55. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_statements.py +0 -0
  56. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_typing.py +0 -0
  57. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_undefined_concept.py +0 -0
  58. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_user_functions.py +0 -0
  59. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_validators.py +0 -0
  60. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/tests/test_where_clause.py +0 -0
  61. {pytrilogy-0.0.3.108/trilogy/core → pytrilogy-0.0.3.110/trilogy/ai/providers}/__init__.py +0 -0
  62. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/authoring/__init__.py +0 -0
  63. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/constants.py +0 -0
  64. {pytrilogy-0.0.3.108/trilogy/core/models → pytrilogy-0.0.3.110/trilogy/core}/__init__.py +0 -0
  65. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/constants.py +0 -0
  66. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/enums.py +0 -0
  67. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/env_processor.py +0 -0
  68. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/environment_helpers.py +0 -0
  69. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/ergonomics.py +0 -0
  70. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/exceptions.py +0 -0
  71. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/functions.py +0 -0
  72. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/graph_models.py +0 -0
  73. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/internal.py +0 -0
  74. {pytrilogy-0.0.3.108/trilogy/core/processing → pytrilogy-0.0.3.110/trilogy/core/models}/__init__.py +0 -0
  75. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/models/author.py +0 -0
  76. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/models/build.py +0 -0
  77. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/models/build_environment.py +0 -0
  78. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/models/core.py +0 -0
  79. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/models/datasource.py +0 -0
  80. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/models/environment.py +0 -0
  81. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/models/execute.py +0 -0
  82. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/optimization.py +0 -0
  83. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/optimizations/__init__.py +0 -0
  84. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/optimizations/base_optimization.py +0 -0
  85. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/optimizations/hide_unused_concept.py +0 -0
  86. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/optimizations/inline_datasource.py +0 -0
  87. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
  88. {pytrilogy-0.0.3.108/trilogy/core/processing/node_generators/select_helpers → pytrilogy-0.0.3.110/trilogy/core/processing}/__init__.py +0 -0
  89. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/concept_strategies_v3.py +0 -0
  90. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/discovery_node_factory.py +0 -0
  91. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/discovery_utility.py +0 -0
  92. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/discovery_validation.py +0 -0
  93. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/graph_utils.py +0 -0
  94. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/node_generators/__init__.py +0 -0
  95. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/node_generators/basic_node.py +0 -0
  96. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/node_generators/common.py +0 -0
  97. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/node_generators/constant_node.py +0 -0
  98. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/node_generators/filter_node.py +0 -0
  99. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/node_generators/group_node.py +0 -0
  100. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
  101. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
  102. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
  103. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/node_generators/recursive_node.py +0 -0
  104. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
  105. {pytrilogy-0.0.3.108/trilogy/core/statements → pytrilogy-0.0.3.110/trilogy/core/processing/node_generators/select_helpers}/__init__.py +0 -0
  106. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
  107. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
  108. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/node_generators/select_node.py +0 -0
  109. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/node_generators/synonym_node.py +0 -0
  110. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/node_generators/union_node.py +0 -0
  111. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
  112. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/node_generators/window_node.py +0 -0
  113. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/nodes/__init__.py +0 -0
  114. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/nodes/base_node.py +0 -0
  115. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/nodes/filter_node.py +0 -0
  116. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/nodes/group_node.py +0 -0
  117. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/nodes/merge_node.py +0 -0
  118. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/nodes/recursive_node.py +0 -0
  119. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
  120. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/nodes/union_node.py +0 -0
  121. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/nodes/unnest_node.py +0 -0
  122. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/nodes/window_node.py +0 -0
  123. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/processing/utility.py +0 -0
  124. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/query_processor.py +0 -0
  125. {pytrilogy-0.0.3.108/trilogy/core/validation → pytrilogy-0.0.3.110/trilogy/core/statements}/__init__.py +0 -0
  126. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/statements/author.py +0 -0
  127. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/statements/build.py +0 -0
  128. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/statements/common.py +0 -0
  129. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/statements/execute.py +0 -0
  130. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/utility.py +0 -0
  131. {pytrilogy-0.0.3.108/trilogy/dialect → pytrilogy-0.0.3.110/trilogy/core/validation}/__init__.py +0 -0
  132. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/validation/common.py +0 -0
  133. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/validation/concept.py +0 -0
  134. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/validation/datasource.py +0 -0
  135. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/validation/environment.py +0 -0
  136. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/core/validation/fix.py +0 -0
  137. {pytrilogy-0.0.3.108/trilogy/metadata → pytrilogy-0.0.3.110/trilogy/dialect}/__init__.py +0 -0
  138. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/dialect/bigquery.py +0 -0
  139. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/dialect/config.py +0 -0
  140. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/dialect/dataframe.py +0 -0
  141. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/dialect/enums.py +0 -0
  142. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/dialect/metadata.py +0 -0
  143. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/dialect/postgres.py +0 -0
  144. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/dialect/presto.py +0 -0
  145. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/dialect/snowflake.py +0 -0
  146. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/dialect/sql_server.py +0 -0
  147. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/engine.py +0 -0
  148. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/hooks/__init__.py +0 -0
  149. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/hooks/base_hook.py +0 -0
  150. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/hooks/graph_hook.py +0 -0
  151. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/hooks/query_debugger.py +0 -0
  152. {pytrilogy-0.0.3.108/trilogy/parsing → pytrilogy-0.0.3.110/trilogy/metadata}/__init__.py +0 -0
  153. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/parser.py +0 -0
  154. {pytrilogy-0.0.3.108/trilogy/scripts → pytrilogy-0.0.3.110/trilogy/parsing}/__init__.py +0 -0
  155. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/parsing/common.py +0 -0
  156. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/parsing/config.py +0 -0
  157. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/parsing/exceptions.py +0 -0
  158. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/parsing/helpers.py +0 -0
  159. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/parsing/parse_engine.py +0 -0
  160. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/parsing/render.py +0 -0
  161. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/parsing/trilogy.lark +0 -0
  162. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/py.typed +0 -0
  163. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/render.py +0 -0
  164. {pytrilogy-0.0.3.108/trilogy/std → pytrilogy-0.0.3.110/trilogy/scripts}/__init__.py +0 -0
  165. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/scripts/trilogy.py +0 -0
  166. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/std/color.preql +0 -0
  167. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/std/date.preql +0 -0
  168. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/std/display.preql +0 -0
  169. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/std/geography.preql +0 -0
  170. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/std/metric.preql +0 -0
  171. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/std/money.preql +0 -0
  172. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/std/net.preql +0 -0
  173. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/std/ranking.preql +0 -0
  174. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/std/report.preql +0 -0
  175. {pytrilogy-0.0.3.108 → pytrilogy-0.0.3.110}/trilogy/utility.py +0 -0
@@ -1,16 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytrilogy
3
- Version: 0.0.3.108
3
+ Version: 0.0.3.110
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
- Home-page:
6
- Author:
7
- Author-email: preql-community@gmail.com
8
5
  Classifier: Programming Language :: Python
9
6
  Classifier: Programming Language :: Python :: 3
10
7
  Classifier: Programming Language :: Python :: 3.9
11
8
  Classifier: Programming Language :: Python :: 3.10
12
9
  Classifier: Programming Language :: Python :: 3.11
13
10
  Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
14
12
  Description-Content-Type: text/markdown
15
13
  License-File: LICENSE.md
16
14
  Requires-Dist: lark
@@ -28,14 +26,9 @@ Provides-Extra: bigquery
28
26
  Requires-Dist: sqlalchemy-bigquery; extra == "bigquery"
29
27
  Provides-Extra: snowflake
30
28
  Requires-Dist: snowflake-sqlalchemy; extra == "snowflake"
31
- Dynamic: author-email
32
- Dynamic: classifier
33
- Dynamic: description
34
- Dynamic: description-content-type
29
+ Provides-Extra: ai
30
+ Requires-Dist: httpx; extra == "ai"
35
31
  Dynamic: license-file
36
- Dynamic: provides-extra
37
- Dynamic: requires-dist
38
- Dynamic: summary
39
32
 
40
33
  # Trilogy
41
34
  **SQL with superpowers for analytics**
@@ -113,6 +106,31 @@ ORDER BY
113
106
  LIMIT 10;
114
107
  ```
115
108
 
109
+ ## Trilogy is Easy to Write
110
+ For humans *and* AI. Enjoy flexible, one-shot query generation without any DB access or security risks.
111
+
112
+ (full code in the python API section.)
113
+
114
+ ```python
115
+ query = text_to_query(
116
+ executor.environment,
117
+ "number of flights by month in 2005",
118
+ Provider.OPENAI,
119
+ "gpt-5-chat-latest",
120
+ api_key,
121
+ )
122
+
123
+ # get a ready to run query
124
+ print(query)
125
+ # typical output
126
+ '''where local.dep_time.year = 2020
127
+ select
128
+ local.dep_time.month,
129
+ count(local.id2) as number_of_flights
130
+ order by
131
+ local.dep_time.month asc;'''
132
+ ```
133
+
116
134
  ## Goals
117
135
 
118
136
  Versus SQL, Trilogy aims to:
@@ -264,6 +282,47 @@ for row in results:
264
282
  print(x)
265
283
  ```
266
284
 
285
+ ### LLM Usage
286
+
287
+ Connect to your favorite provider and generate queries with confidence and high accuracy.
288
+
289
+ ```python
290
+ from trilogy import Environment, Dialects
291
+ from trilogy.ai import Provider, text_to_query
292
+ import os
293
+
294
+ executor = Dialects.DUCK_DB.default_executor(
295
+ environment=Environment(working_path=Path(__file__).parent)
296
+ )
297
+
298
+ api_key = os.environ.get(OPENAI_API_KEY)
299
+ if not api_key:
300
+ raise ValueError("OPENAI_API_KEY required for gpt generation")
301
+ # load a model
302
+ executor.parse_file("flight.preql")
303
+ # create tables in the DB if needed
304
+ executor.execute_file("setup.sql")
305
+ # generate a query
306
+ query = text_to_query(
307
+ executor.environment,
308
+ "number of flights by month in 2005",
309
+ Provider.OPENAI,
310
+ "gpt-5-chat-latest",
311
+ api_key,
312
+ )
313
+
314
+ # print the generated trilogy query
315
+ print(query)
316
+ # run it
317
+ results = executor.execute_text(query)[-1].fetchall()
318
+ assert len(results) == 12
319
+
320
+ for row in results:
321
+ # all monthly flights are between 5000 and 7000
322
+ assert row[1] > 5000 and row[1] < 7000, row
323
+
324
+ ```
325
+
267
326
  ### CLI Usage
268
327
 
269
328
  Trilogy can be run through a CLI tool, also named 'trilogy'.
@@ -74,6 +74,31 @@ ORDER BY
74
74
  LIMIT 10;
75
75
  ```
76
76
 
77
+ ## Trilogy is Easy to Write
78
+ For humans *and* AI. Enjoy flexible, one-shot query generation without any DB access or security risks.
79
+
80
+ (full code in the python API section.)
81
+
82
+ ```python
83
+ query = text_to_query(
84
+ executor.environment,
85
+ "number of flights by month in 2005",
86
+ Provider.OPENAI,
87
+ "gpt-5-chat-latest",
88
+ api_key,
89
+ )
90
+
91
+ # get a ready to run query
92
+ print(query)
93
+ # typical output
94
+ '''where local.dep_time.year = 2020
95
+ select
96
+ local.dep_time.month,
97
+ count(local.id2) as number_of_flights
98
+ order by
99
+ local.dep_time.month asc;'''
100
+ ```
101
+
77
102
  ## Goals
78
103
 
79
104
  Versus SQL, Trilogy aims to:
@@ -225,6 +250,47 @@ for row in results:
225
250
  print(x)
226
251
  ```
227
252
 
253
+ ### LLM Usage
254
+
255
+ Connect to your favorite provider and generate queries with confidence and high accuracy.
256
+
257
+ ```python
258
+ from trilogy import Environment, Dialects
259
+ from trilogy.ai import Provider, text_to_query
260
+ import os
261
+
262
+ executor = Dialects.DUCK_DB.default_executor(
263
+ environment=Environment(working_path=Path(__file__).parent)
264
+ )
265
+
266
+ api_key = os.environ.get(OPENAI_API_KEY)
267
+ if not api_key:
268
+ raise ValueError("OPENAI_API_KEY required for gpt generation")
269
+ # load a model
270
+ executor.parse_file("flight.preql")
271
+ # create tables in the DB if needed
272
+ executor.execute_file("setup.sql")
273
+ # generate a query
274
+ query = text_to_query(
275
+ executor.environment,
276
+ "number of flights by month in 2005",
277
+ Provider.OPENAI,
278
+ "gpt-5-chat-latest",
279
+ api_key,
280
+ )
281
+
282
+ # print the generated trilogy query
283
+ print(query)
284
+ # run it
285
+ results = executor.execute_text(query)[-1].fetchall()
286
+ assert len(results) == 12
287
+
288
+ for row in results:
289
+ # all monthly flights are between 5000 and 7000
290
+ assert row[1] > 5000 and row[1] < 7000, row
291
+
292
+ ```
293
+
228
294
  ### CLI Usage
229
295
 
230
296
  Trilogy can be run through a CLI tool, also named 'trilogy'.
@@ -0,0 +1,49 @@
1
+ [tool.pytest.ini_options]
2
+ markers = [
3
+ "adventureworks",
4
+ "adventureworks_execution",
5
+ ]
6
+ log_cli_level="INFO"
7
+
8
+ [tool.ruff]
9
+ # Allow lines to be as long as 200 characters.
10
+ line-length = 200
11
+ lint.extend-select = ["I"]
12
+
13
+ [project]
14
+ name = "pytrilogy"
15
+ description = "Declarative, typed query language that compiles to SQL."
16
+ dynamic = ["version", "dependencies"]
17
+ readme = {file = "README.md", content-type = "text/markdown"}
18
+ classifiers = [
19
+ "Programming Language :: Python",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.9",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ ]
27
+
28
+ [project.scripts]
29
+ trilogy = "trilogy.scripts.trilogy:cli"
30
+
31
+ [project.optional-dependencies]
32
+ postgres = ["psycopg2-binary"]
33
+ bigquery = ["sqlalchemy-bigquery"]
34
+ snowflake = ["snowflake-sqlalchemy"]
35
+ ai = ["httpx"]
36
+
37
+ [tool.setuptools.dynamic]
38
+ version = {attr = "trilogy.__version__"}
39
+ dependencies = {file = ["requirements.txt"]}
40
+
41
+ [tool.setuptools]
42
+ packages = {find = {exclude = ["dist", "build", "*.tests", "*.tests.*", "tests.*", "tests", "docs", ".github", "examples"]}}
43
+
44
+ [tool.setuptools.package-data]
45
+ "*" = ["*.tf", "*.jinja", "py.typed", "*.lark", "*.preql"]
46
+
47
+ [build-system]
48
+ requires = ["setuptools>=61.0", "wheel"]
49
+ build-backend = "setuptools.build_meta"
@@ -1,16 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytrilogy
3
- Version: 0.0.3.108
3
+ Version: 0.0.3.110
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
- Home-page:
6
- Author:
7
- Author-email: preql-community@gmail.com
8
5
  Classifier: Programming Language :: Python
9
6
  Classifier: Programming Language :: Python :: 3
10
7
  Classifier: Programming Language :: Python :: 3.9
11
8
  Classifier: Programming Language :: Python :: 3.10
12
9
  Classifier: Programming Language :: Python :: 3.11
13
10
  Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
14
12
  Description-Content-Type: text/markdown
15
13
  License-File: LICENSE.md
16
14
  Requires-Dist: lark
@@ -28,14 +26,9 @@ Provides-Extra: bigquery
28
26
  Requires-Dist: sqlalchemy-bigquery; extra == "bigquery"
29
27
  Provides-Extra: snowflake
30
28
  Requires-Dist: snowflake-sqlalchemy; extra == "snowflake"
31
- Dynamic: author-email
32
- Dynamic: classifier
33
- Dynamic: description
34
- Dynamic: description-content-type
29
+ Provides-Extra: ai
30
+ Requires-Dist: httpx; extra == "ai"
35
31
  Dynamic: license-file
36
- Dynamic: provides-extra
37
- Dynamic: requires-dist
38
- Dynamic: summary
39
32
 
40
33
  # Trilogy
41
34
  **SQL with superpowers for analytics**
@@ -113,6 +106,31 @@ ORDER BY
113
106
  LIMIT 10;
114
107
  ```
115
108
 
109
+ ## Trilogy is Easy to Write
110
+ For humans *and* AI. Enjoy flexible, one-shot query generation without any DB access or security risks.
111
+
112
+ (full code in the python API section.)
113
+
114
+ ```python
115
+ query = text_to_query(
116
+ executor.environment,
117
+ "number of flights by month in 2005",
118
+ Provider.OPENAI,
119
+ "gpt-5-chat-latest",
120
+ api_key,
121
+ )
122
+
123
+ # get a ready to run query
124
+ print(query)
125
+ # typical output
126
+ '''where local.dep_time.year = 2020
127
+ select
128
+ local.dep_time.month,
129
+ count(local.id2) as number_of_flights
130
+ order by
131
+ local.dep_time.month asc;'''
132
+ ```
133
+
116
134
  ## Goals
117
135
 
118
136
  Versus SQL, Trilogy aims to:
@@ -264,6 +282,47 @@ for row in results:
264
282
  print(x)
265
283
  ```
266
284
 
285
+ ### LLM Usage
286
+
287
+ Connect to your favorite provider and generate queries with confidence and high accuracy.
288
+
289
+ ```python
290
+ from trilogy import Environment, Dialects
291
+ from trilogy.ai import Provider, text_to_query
292
+ import os
293
+
294
+ executor = Dialects.DUCK_DB.default_executor(
295
+ environment=Environment(working_path=Path(__file__).parent)
296
+ )
297
+
298
+ api_key = os.environ.get(OPENAI_API_KEY)
299
+ if not api_key:
300
+ raise ValueError("OPENAI_API_KEY required for gpt generation")
301
+ # load a model
302
+ executor.parse_file("flight.preql")
303
+ # create tables in the DB if needed
304
+ executor.execute_file("setup.sql")
305
+ # generate a query
306
+ query = text_to_query(
307
+ executor.environment,
308
+ "number of flights by month in 2005",
309
+ Provider.OPENAI,
310
+ "gpt-5-chat-latest",
311
+ api_key,
312
+ )
313
+
314
+ # print the generated trilogy query
315
+ print(query)
316
+ # run it
317
+ results = executor.execute_text(query)[-1].fetchall()
318
+ assert len(results) == 12
319
+
320
+ for row in results:
321
+ # all monthly flights are between 5000 and 7000
322
+ assert row[1] > 5000 and row[1] < 7000, row
323
+
324
+ ```
325
+
267
326
  ### CLI Usage
268
327
 
269
328
  Trilogy can be run through a CLI tool, also named 'trilogy'.
@@ -1,7 +1,7 @@
1
1
  LICENSE.md
2
2
  README.md
3
3
  pyproject.toml
4
- setup.py
4
+ requirements.txt
5
5
  pytrilogy.egg-info/PKG-INFO
6
6
  pytrilogy.egg-info/SOURCES.txt
7
7
  pytrilogy.egg-info/dependency_links.txt
@@ -44,6 +44,19 @@ trilogy/parser.py
44
44
  trilogy/py.typed
45
45
  trilogy/render.py
46
46
  trilogy/utility.py
47
+ trilogy/ai/__init__.py
48
+ trilogy/ai/constants.py
49
+ trilogy/ai/conversation.py
50
+ trilogy/ai/enums.py
51
+ trilogy/ai/execute.py
52
+ trilogy/ai/models.py
53
+ trilogy/ai/prompts.py
54
+ trilogy/ai/providers/__init__.py
55
+ trilogy/ai/providers/anthropic.py
56
+ trilogy/ai/providers/base.py
57
+ trilogy/ai/providers/google.py
58
+ trilogy/ai/providers/openai.py
59
+ trilogy/ai/providers/utils.py
47
60
  trilogy/authoring/__init__.py
48
61
  trilogy/core/__init__.py
49
62
  trilogy/core/constants.py
@@ -8,6 +8,9 @@ duckdb<1.4.0
8
8
  duckdb-engine
9
9
  click
10
10
 
11
+ [ai]
12
+ httpx
13
+
11
14
  [bigquery]
12
15
  sqlalchemy-bigquery
13
16
 
@@ -0,0 +1,10 @@
1
+ lark
2
+ jinja2
3
+ sqlalchemy<2.0.0
4
+ networkx
5
+ pyodbc
6
+ pydantic
7
+ #https://github.com/Mause/duckdb_engine/issues/1338 - remove as soon as fixed
8
+ duckdb<1.4.0
9
+ duckdb-engine
10
+ click
@@ -4,6 +4,6 @@ from trilogy.dialect.enums import Dialects
4
4
  from trilogy.executor import Executor
5
5
  from trilogy.parser import parse
6
6
 
7
- __version__ = "0.0.3.108"
7
+ __version__ = "0.0.3.110"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
@@ -0,0 +1,19 @@
1
+ from trilogy.ai.conversation import Conversation
2
+ from trilogy.ai.enums import Provider
3
+ from trilogy.ai.execute import text_to_query
4
+ from trilogy.ai.models import LLMMessage
5
+ from trilogy.ai.prompts import create_query_prompt
6
+ from trilogy.ai.providers.anthropic import AnthropicProvider
7
+ from trilogy.ai.providers.google import GoogleProvider
8
+ from trilogy.ai.providers.openai import OpenAIProvider
9
+
10
+ __all__ = [
11
+ "Conversation",
12
+ "LLMMessage",
13
+ "OpenAIProvider",
14
+ "GoogleProvider",
15
+ "AnthropicProvider",
16
+ "create_query_prompt",
17
+ "text_to_query",
18
+ "Provider",
19
+ ]
@@ -0,0 +1,92 @@
1
+ from trilogy.core.enums import FunctionClass, FunctionType
2
+ from trilogy.core.functions import FUNCTION_REGISTRY
3
+
4
+ RULE_PROMPT = """Trilogy statements define a semantic model or query. If a user is asking for data, they want a SELECT.
5
+ Semantic model statements:
6
+ - import <> imports a model to reuse. The output of imports will be visible in fields available to use.
7
+ - key|property|auto|metric defines fields locally. The output will also be visible in fields available to use, so you generally don't need to edit these unless requested.
8
+ - datasource statements define a datasource, which is a mapping of fields to a SQL database table. The left side is the SQL column name, the right side is the field name.
9
+
10
+ SELECT RULES:
11
+ - No FROM, JOIN, GROUP BY, SUB SELECTS, DISTINCT, UNION, or SELECT *.
12
+ - All fields exist in a global namespace; field paths look like `order.product.id`. Always use the full path. NEVER include a from clause.
13
+ - If a field has a grain defined, and that grain is not in the query output, aggregate it to get desired result.
14
+ - If a field has a 'alias_for' defined, it is shorthand for that calculation. Use the field name instead of the calculation in your query to be concise.
15
+ - Newly created fields at the output of the select must be aliased with as (e.g. `sum(births) as all_births`).
16
+ - Aliases cannot happen inside calculations or in the where/having/order clause. Never alias fields with existing names. 'sum(revenue) as total_revenue' is valid, but '(sum(births) as total_revenue) +1 as revenue_plus_one' is not.
17
+ - Implicit grouping: NEVER include a group by clause. Grouping is by non-aggregated fields in the SELECT clause.
18
+ - You can dynamically group inline to get groups at different grains - ex: `sum(metric) by dim1, dim2 as sum_by_dim1_dm2` for alternate grouping. If you are grouping a defined aggregate
19
+ - Count must specify a field (no `count(*)`) Counts are automatically deduplicated. Do not ever use DISTINCT.
20
+ - Since there are no underlying tables, sum/count of a constant should always specify a grain field (e.g. `sum(1) by x as count`).
21
+ - Aggregates in SELECT must be filtered via HAVING. Use WHERE for pre-aggregation filters.
22
+ - Use `field ? condition` for inline filters (e.g. `sum(x ? x > 0)`).
23
+ - Always use a reasonable `LIMIT` for final queries unless the request is for a time series or line chart.
24
+ - Window functions: `rank entity [optional over group] by field desc` (e.g. `rank name over state by sum(births) desc as top_name`) Do not use parentheses for over.
25
+ - Functions. All function names have parenthese (e.g. `sum(births)`, `date_part('year', dep_time)`). For no arguments, use empty parentheses (e.g. `current_date()`).
26
+ - For lag/lead, offset is first: lag/lead offset field order by expr asc/desc.
27
+ - For lag/lead with a window clause: lag/lead offset field by window_clause order by expr asc/desc.
28
+ - Use `::type` casting, e.g., `"2020-01-01"::date`.
29
+ - Date_parts have no quotes; use `date_part(order_date, year)` instead of `date_part(order_date, 'year')`.
30
+ - Comments use `#` only, per line.
31
+ - Two example queries: "where year between 1940 and 1950
32
+ select
33
+ name,
34
+ state,
35
+ sum(births) AS all_births,
36
+ sum(births ? state = 'VT') AS vermont_births,
37
+ rank name over state by all_births desc AS state_rank,
38
+ rank name by sum(births) by name desc AS all_rank
39
+ having
40
+ all_rank<11
41
+ and state = 'ID'
42
+ order by
43
+ all_rank asc
44
+ limit 5;", "where dep_time between '2002-01-01'::datetime and '2010-01-31'::datetime
45
+ select
46
+ carrier.name,
47
+ count(id2) AS total_flights,
48
+ total_flights / date_diff(min(dep_time.date), max(dep_time.date), DAY) AS average_daily_flights
49
+ order by
50
+ total_flights desc;"""
51
+
52
+
53
+ def render_function(function_type: FunctionType, example: str | None = None):
54
+ info = FUNCTION_REGISTRY[function_type]
55
+
56
+ if info.arg_count == -1:
57
+ # Infinite/variable number of arguments
58
+ base = f"{function_type.value}(<arg1>, <arg2>, ..., <argN>)"
59
+ elif info.arg_count == 0:
60
+ # No arguments
61
+ base = f"{function_type.value}()"
62
+ else:
63
+ # Fixed number of arguments
64
+ base = f"{function_type.value}({', '.join([f'<arg{p}>' for p in range(1, info.arg_count + 1)])})"
65
+
66
+ if example:
67
+ base += f" e.g. {example}"
68
+ return base
69
+
70
+
71
+ FUNCTION_EXAMPLES = {
72
+ FunctionType.DATE_ADD: "date_add('2020-01-01'::date, month, 1)",
73
+ FunctionType.DATE_DIFF: "date_diff('2020-01-01'::date, '2020-01-02'::date, day)",
74
+ FunctionType.DATE_PART: "date_part('2020-01-01'::date, year)",
75
+ FunctionType.DATE_SUB: "date_sub('2020-01-01'::date, day, 1)",
76
+ FunctionType.DATE_TRUNCATE: "date_trunc('2020-01-01'::date, month)",
77
+ FunctionType.CURRENT_TIMESTAMP: "now()",
78
+ }
79
+
80
+ FUNCTIONS = "\n".join(
81
+ [
82
+ render_function(v, example=FUNCTION_EXAMPLES.get(v))
83
+ for x, v in FunctionType.__members__.items()
84
+ if v in FUNCTION_REGISTRY
85
+ ]
86
+ )
87
+
88
+ AGGREGATE_FUNCTIONS = [
89
+ x
90
+ for x, info in FunctionType.__members__.items()
91
+ if x in FunctionClass.AGGREGATE_FUNCTIONS.value
92
+ ]
@@ -0,0 +1,99 @@
1
+ from dataclasses import dataclass
2
+ from typing import Literal, Union
3
+
4
+ from trilogy import Environment
5
+ from trilogy.ai.models import LLMMessage, LLMRequestOptions
6
+ from trilogy.ai.prompts import TRILOGY_LEAD_IN, create_query_prompt
7
+ from trilogy.ai.providers.base import LLMProvider
8
+ from trilogy.core.exceptions import (
9
+ InvalidSyntaxException,
10
+ NoDatasourceException,
11
+ UndefinedConceptException,
12
+ UnresolvableQueryException,
13
+ )
14
+ from trilogy.core.query_processor import process_query
15
+
16
+
17
+ @dataclass
18
+ class Conversation:
19
+
20
+ messages: list[LLMMessage]
21
+ provider: LLMProvider
22
+ id: str | None = None
23
+
24
+ @classmethod
25
+ def create(
26
+ cls,
27
+ provider: LLMProvider,
28
+ model_prompt: str = TRILOGY_LEAD_IN,
29
+ id: str | None = None,
30
+ ) -> "Conversation":
31
+ system_message = LLMMessage(role="system", content=model_prompt)
32
+ messages = [system_message]
33
+ return cls(id=id, messages=messages, provider=provider)
34
+
35
+ def add_message(
36
+ self,
37
+ message: Union[LLMMessage, str],
38
+ role: Literal["user", "assistant"] = "user",
39
+ ) -> None:
40
+ """
41
+ Add a message to the conversation.
42
+
43
+ Args:
44
+ message: Either an LLMMessage object or a string content
45
+ role: The role for the message if a string is provided (default: 'user')
46
+ """
47
+ if isinstance(message, str):
48
+ message = LLMMessage(role=role, content=message)
49
+ self.messages.append(message)
50
+
51
+ def get_response(self) -> LLMMessage:
52
+ options = LLMRequestOptions()
53
+ response = self.provider.generate_completion(options, history=self.messages)
54
+ response_message = LLMMessage(role="assistant", content=response.text)
55
+ self.add_message(response_message)
56
+ return response_message
57
+
58
+ def extract_response(self, content: str) -> str:
59
+ # get contents in triple backticks
60
+ content = content.replace('"""', "```")
61
+ if "```" in content:
62
+ parts = content.split("```")
63
+ if len(parts) >= 3:
64
+ return parts[1].strip()
65
+ return content
66
+
67
+ def generate_query(
68
+ self, user_input: str, environment: Environment, attempts: int = 4
69
+ ) -> str:
70
+ attempts = 0
71
+ self.add_message(create_query_prompt(user_input, environment), role="user")
72
+ e = None
73
+ while attempts < 4:
74
+ attempts += 1
75
+
76
+ response_message = self.get_response()
77
+ response = self.extract_response(response_message.content)
78
+ if not response.strip()[-1] == ";":
79
+ response += ";"
80
+ try:
81
+ env, raw = environment.parse(response)
82
+ process_query(statement=raw[-1], environment=environment)
83
+ return response
84
+ except (
85
+ InvalidSyntaxException,
86
+ NoDatasourceException,
87
+ UnresolvableQueryException,
88
+ UndefinedConceptException,
89
+ SyntaxError,
90
+ ) as e2:
91
+ e = e2
92
+ self.add_message(
93
+ f"The previous response could not be parsed due to the error: {str(e)}. Please generate a new query with the issues fixed. Use the same response format.",
94
+ role="user",
95
+ )
96
+
97
+ raise Exception(
98
+ f"Failed to generate a valid query after {attempts} attempts. Last error: {str(e)}. Full conversation: {self.messages}"
99
+ )
@@ -0,0 +1,7 @@
1
+ from enum import Enum
2
+
3
+
4
+ class Provider(Enum):
5
+ OPENAI = "openai"
6
+ ANTHROPIC = "anthropic"
7
+ GOOGLE = "google"
@@ -0,0 +1,50 @@
1
+ from trilogy import Environment
2
+ from trilogy.ai.conversation import Conversation
3
+ from trilogy.ai.enums import Provider
4
+ from trilogy.ai.providers.base import LLMProvider
5
+
6
+
7
+ def text_to_query(
8
+ environment: Environment,
9
+ user_input: str,
10
+ provider: Provider,
11
+ model: str,
12
+ secret: str | None = None,
13
+ ) -> str:
14
+ llm_provider: LLMProvider
15
+
16
+ if provider == Provider.OPENAI:
17
+ from trilogy.ai.providers.openai import OpenAIProvider
18
+
19
+ llm_provider = OpenAIProvider(
20
+ name="openai",
21
+ api_key=secret,
22
+ model=model,
23
+ )
24
+ elif provider == Provider.ANTHROPIC:
25
+ from trilogy.ai.providers.anthropic import AnthropicProvider
26
+
27
+ llm_provider = AnthropicProvider(
28
+ name="anthropic",
29
+ api_key=secret,
30
+ model=model,
31
+ )
32
+ elif provider == Provider.GOOGLE:
33
+ from trilogy.ai.providers.google import GoogleProvider
34
+
35
+ llm_provider = GoogleProvider(
36
+ name="google",
37
+ api_key=secret,
38
+ model=model,
39
+ )
40
+ else:
41
+ raise ValueError(f"Unsupported provider: {provider}")
42
+ conversation = Conversation.create(
43
+ provider=llm_provider,
44
+ )
45
+
46
+ response = conversation.generate_query(
47
+ user_input=user_input, environment=environment
48
+ )
49
+
50
+ return response