qtype 0.0.16__tar.gz → 0.1.1__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.
Files changed (200) hide show
  1. {qtype-0.0.16/qtype.egg-info → qtype-0.1.1}/PKG-INFO +16 -3
  2. {qtype-0.0.16 → qtype-0.1.1}/pyproject.toml +23 -3
  3. {qtype-0.0.16 → qtype-0.1.1}/qtype/application/commons/tools.py +1 -1
  4. {qtype-0.0.16 → qtype-0.1.1}/qtype/application/converters/tools_from_api.py +5 -5
  5. {qtype-0.0.16 → qtype-0.1.1}/qtype/application/converters/tools_from_module.py +2 -2
  6. qtype-0.1.1/qtype/application/converters/types.py +18 -0
  7. {qtype-0.0.16 → qtype-0.1.1}/qtype/application/documentation.py +1 -1
  8. qtype-0.1.1/qtype/application/facade.py +178 -0
  9. qtype-0.1.1/qtype/base/types.py +249 -0
  10. {qtype-0.0.16 → qtype-0.1.1}/qtype/cli.py +4 -0
  11. {qtype-0.0.16 → qtype-0.1.1}/qtype/commands/convert.py +20 -8
  12. {qtype-0.0.16 → qtype-0.1.1}/qtype/commands/generate.py +19 -27
  13. {qtype-0.0.16 → qtype-0.1.1}/qtype/commands/run.py +73 -36
  14. qtype-0.1.1/qtype/commands/serve.py +117 -0
  15. {qtype-0.0.16 → qtype-0.1.1}/qtype/commands/validate.py +34 -8
  16. {qtype-0.0.16 → qtype-0.1.1}/qtype/commands/visualize.py +46 -22
  17. qtype-0.1.1/qtype/dsl/__init__.py +11 -0
  18. {qtype-0.0.16 → qtype-0.1.1}/qtype/dsl/custom_types.py +1 -1
  19. qtype-0.1.1/qtype/dsl/domain_types.py +119 -0
  20. qtype-0.1.1/qtype/dsl/linker.py +384 -0
  21. qtype-0.1.1/qtype/dsl/loader.py +315 -0
  22. qtype-0.1.1/qtype/dsl/model.py +1242 -0
  23. qtype-0.1.1/qtype/dsl/parser.py +200 -0
  24. {qtype-0.0.16/qtype/application/converters → qtype-0.1.1/qtype/dsl}/types.py +8 -5
  25. qtype-0.1.1/qtype/interpreter/api.py +123 -0
  26. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/auth/aws.py +19 -9
  27. qtype-0.1.1/qtype/interpreter/auth/generic.py +180 -0
  28. qtype-0.1.1/qtype/interpreter/base/base_step_executor.py +436 -0
  29. qtype-0.1.1/qtype/interpreter/base/batch_step_executor.py +171 -0
  30. qtype-0.1.1/qtype/interpreter/base/exceptions.py +50 -0
  31. qtype-0.1.1/qtype/interpreter/base/executor_context.py +74 -0
  32. qtype-0.1.1/qtype/interpreter/base/factory.py +117 -0
  33. qtype-0.1.1/qtype/interpreter/base/progress_tracker.py +110 -0
  34. qtype-0.1.1/qtype/interpreter/base/secrets.py +339 -0
  35. qtype-0.1.1/qtype/interpreter/base/step_cache.py +74 -0
  36. qtype-0.1.1/qtype/interpreter/base/stream_emitter.py +469 -0
  37. qtype-0.1.1/qtype/interpreter/conversions.py +606 -0
  38. qtype-0.1.1/qtype/interpreter/converters.py +77 -0
  39. qtype-0.1.1/qtype/interpreter/endpoints.py +355 -0
  40. qtype-0.1.1/qtype/interpreter/executors/agent_executor.py +242 -0
  41. qtype-0.1.1/qtype/interpreter/executors/aggregate_executor.py +93 -0
  42. qtype-0.1.1/qtype/interpreter/executors/decoder_executor.py +163 -0
  43. qtype-0.1.1/qtype/interpreter/executors/doc_to_text_executor.py +112 -0
  44. qtype-0.1.1/qtype/interpreter/executors/document_embedder_executor.py +107 -0
  45. qtype-0.1.1/qtype/interpreter/executors/document_search_executor.py +122 -0
  46. qtype-0.1.1/qtype/interpreter/executors/document_source_executor.py +118 -0
  47. qtype-0.1.1/qtype/interpreter/executors/document_splitter_executor.py +105 -0
  48. qtype-0.1.1/qtype/interpreter/executors/echo_executor.py +63 -0
  49. qtype-0.1.1/qtype/interpreter/executors/field_extractor_executor.py +160 -0
  50. qtype-0.1.1/qtype/interpreter/executors/file_source_executor.py +101 -0
  51. qtype-0.1.1/qtype/interpreter/executors/file_writer_executor.py +110 -0
  52. qtype-0.1.1/qtype/interpreter/executors/index_upsert_executor.py +228 -0
  53. qtype-0.1.1/qtype/interpreter/executors/invoke_embedding_executor.py +92 -0
  54. qtype-0.1.1/qtype/interpreter/executors/invoke_flow_executor.py +51 -0
  55. qtype-0.1.1/qtype/interpreter/executors/invoke_tool_executor.py +358 -0
  56. qtype-0.1.1/qtype/interpreter/executors/llm_inference_executor.py +272 -0
  57. qtype-0.1.1/qtype/interpreter/executors/prompt_template_executor.py +78 -0
  58. qtype-0.1.1/qtype/interpreter/executors/sql_source_executor.py +106 -0
  59. qtype-0.1.1/qtype/interpreter/executors/vector_search_executor.py +91 -0
  60. qtype-0.1.1/qtype/interpreter/flow.py +174 -0
  61. qtype-0.1.1/qtype/interpreter/metadata_api.py +115 -0
  62. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/resource_cache.py +5 -4
  63. qtype-0.1.1/qtype/interpreter/rich_progress.py +225 -0
  64. qtype-0.1.1/qtype/interpreter/stream/chat/__init__.py +15 -0
  65. qtype-0.1.1/qtype/interpreter/stream/chat/converter.py +391 -0
  66. {qtype-0.0.16/qtype/interpreter → qtype-0.1.1/qtype/interpreter/stream}/chat/file_conversions.py +2 -2
  67. qtype-0.1.1/qtype/interpreter/stream/chat/ui_request_to_domain_type.py +140 -0
  68. qtype-0.1.1/qtype/interpreter/stream/chat/vercel.py +609 -0
  69. qtype-0.1.1/qtype/interpreter/stream/utils/__init__.py +15 -0
  70. qtype-0.1.1/qtype/interpreter/stream/utils/build_vercel_ai_formatter.py +74 -0
  71. qtype-0.1.1/qtype/interpreter/stream/utils/callback_to_stream.py +66 -0
  72. qtype-0.1.1/qtype/interpreter/stream/utils/create_streaming_response.py +18 -0
  73. qtype-0.1.1/qtype/interpreter/stream/utils/default_chat_extract_text.py +20 -0
  74. qtype-0.1.1/qtype/interpreter/stream/utils/error_streaming_response.py +20 -0
  75. qtype-0.1.1/qtype/interpreter/telemetry.py +143 -0
  76. qtype-0.1.1/qtype/interpreter/tools/__init__.py +5 -0
  77. qtype-0.1.1/qtype/interpreter/tools/function_tool_helper.py +265 -0
  78. qtype-0.1.1/qtype/interpreter/types.py +330 -0
  79. qtype-0.1.1/qtype/interpreter/typing.py +127 -0
  80. qtype-0.1.1/qtype/interpreter/ui/404/index.html +1 -0
  81. qtype-0.1.1/qtype/interpreter/ui/404.html +1 -0
  82. {qtype-0.0.16/qtype/interpreter/ui/_next/static/nUaw6_IwRwPqkzwe5s725 → qtype-0.1.1/qtype/interpreter/ui/_next/static/20HoJN6otZ_LyHLHpCPE6}/_buildManifest.js +1 -1
  83. qtype-0.0.16/qtype/interpreter/ui/_next/static/chunks/393-8fd474427f8e19ce.js → qtype-0.1.1/qtype/interpreter/ui/_next/static/chunks/434-b2112d19f25c44ff.js +3 -3
  84. qtype-0.1.1/qtype/interpreter/ui/_next/static/chunks/app/page-8c67d16ac90d23cb.js +1 -0
  85. qtype-0.1.1/qtype/interpreter/ui/_next/static/chunks/ba12c10f-546f2714ff8abc66.js +1 -0
  86. qtype-0.1.1/qtype/interpreter/ui/_next/static/css/8a8d1269e362fef7.css +3 -0
  87. qtype-0.1.1/qtype/interpreter/ui/icon.png +0 -0
  88. qtype-0.1.1/qtype/interpreter/ui/index.html +1 -0
  89. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/index.txt +4 -4
  90. qtype-0.1.1/qtype/semantic/checker.py +583 -0
  91. {qtype-0.0.16 → qtype-0.1.1}/qtype/semantic/generate.py +262 -83
  92. qtype-0.1.1/qtype/semantic/loader.py +95 -0
  93. qtype-0.1.1/qtype/semantic/model.py +799 -0
  94. qtype-0.1.1/qtype/semantic/resolver.py +141 -0
  95. {qtype-0.0.16 → qtype-0.1.1}/qtype/semantic/visualize.py +28 -31
  96. {qtype-0.0.16 → qtype-0.1.1/qtype.egg-info}/PKG-INFO +16 -3
  97. {qtype-0.0.16 → qtype-0.1.1}/qtype.egg-info/SOURCES.txt +61 -48
  98. {qtype-0.0.16 → qtype-0.1.1}/qtype.egg-info/requires.txt +15 -2
  99. qtype-0.0.16/qtype/application/facade.py +0 -157
  100. qtype-0.0.16/qtype/base/types.py +0 -29
  101. qtype-0.0.16/qtype/commands/serve.py +0 -97
  102. qtype-0.0.16/qtype/dsl/__init__.py +0 -10
  103. qtype-0.0.16/qtype/dsl/base_types.py +0 -38
  104. qtype-0.0.16/qtype/dsl/domain_types.py +0 -59
  105. qtype-0.0.16/qtype/dsl/model.py +0 -993
  106. qtype-0.0.16/qtype/dsl/validator.py +0 -465
  107. qtype-0.0.16/qtype/interpreter/api.py +0 -202
  108. qtype-0.0.16/qtype/interpreter/auth/generic.py +0 -103
  109. qtype-0.0.16/qtype/interpreter/batch/file_sink_source.py +0 -162
  110. qtype-0.0.16/qtype/interpreter/batch/flow.py +0 -95
  111. qtype-0.0.16/qtype/interpreter/batch/sql_source.py +0 -92
  112. qtype-0.0.16/qtype/interpreter/batch/step.py +0 -74
  113. qtype-0.0.16/qtype/interpreter/batch/types.py +0 -41
  114. qtype-0.0.16/qtype/interpreter/batch/utils.py +0 -178
  115. qtype-0.0.16/qtype/interpreter/chat/chat_api.py +0 -237
  116. qtype-0.0.16/qtype/interpreter/chat/vercel.py +0 -314
  117. qtype-0.0.16/qtype/interpreter/conversions.py +0 -166
  118. qtype-0.0.16/qtype/interpreter/exceptions.py +0 -10
  119. qtype-0.0.16/qtype/interpreter/flow.py +0 -37
  120. qtype-0.0.16/qtype/interpreter/step.py +0 -67
  121. qtype-0.0.16/qtype/interpreter/steps/__init__.py +0 -0
  122. qtype-0.0.16/qtype/interpreter/steps/agent.py +0 -114
  123. qtype-0.0.16/qtype/interpreter/steps/condition.py +0 -36
  124. qtype-0.0.16/qtype/interpreter/steps/decoder.py +0 -88
  125. qtype-0.0.16/qtype/interpreter/steps/llm_inference.py +0 -171
  126. qtype-0.0.16/qtype/interpreter/steps/prompt_template.py +0 -54
  127. qtype-0.0.16/qtype/interpreter/steps/search.py +0 -24
  128. qtype-0.0.16/qtype/interpreter/steps/tool.py +0 -219
  129. qtype-0.0.16/qtype/interpreter/streaming_helpers.py +0 -123
  130. qtype-0.0.16/qtype/interpreter/telemetry.py +0 -16
  131. qtype-0.0.16/qtype/interpreter/typing.py +0 -133
  132. qtype-0.0.16/qtype/interpreter/ui/404/index.html +0 -1
  133. qtype-0.0.16/qtype/interpreter/ui/404.html +0 -1
  134. qtype-0.0.16/qtype/interpreter/ui/_next/static/chunks/app/page-7e26b6156cfb55d3.js +0 -1
  135. qtype-0.0.16/qtype/interpreter/ui/_next/static/chunks/ba12c10f-22556063851a6df2.js +0 -1
  136. qtype-0.0.16/qtype/interpreter/ui/_next/static/css/b40532b0db09cce3.css +0 -3
  137. qtype-0.0.16/qtype/interpreter/ui/favicon.ico +0 -0
  138. qtype-0.0.16/qtype/interpreter/ui/index.html +0 -1
  139. qtype-0.0.16/qtype/loader.py +0 -390
  140. qtype-0.0.16/qtype/semantic/__init__.py +0 -0
  141. qtype-0.0.16/qtype/semantic/model.py +0 -522
  142. qtype-0.0.16/qtype/semantic/resolver.py +0 -97
  143. qtype-0.0.16/tests/test_auth_cache.py +0 -190
  144. qtype-0.0.16/tests/test_aws_auth.py +0 -401
  145. qtype-0.0.16/tests/test_batch_flow.py +0 -311
  146. qtype-0.0.16/tests/test_batch_step.py +0 -127
  147. qtype-0.0.16/tests/test_batch_utils.py +0 -251
  148. qtype-0.0.16/tests/test_documentation.py +0 -36
  149. qtype-0.0.16/tests/test_dsl_loader.py +0 -706
  150. qtype-0.0.16/tests/test_dsl_validation.py +0 -165
  151. qtype-0.0.16/tests/test_file_sink_source.py +0 -287
  152. qtype-0.0.16/tests/test_generic_auth.py +0 -95
  153. qtype-0.0.16/tests/test_list_type.py +0 -166
  154. qtype-0.0.16/tests/test_semantic_generator.py +0 -73
  155. qtype-0.0.16/tests/test_semantic_resolver.py +0 -82
  156. qtype-0.0.16/tests/test_sql_source.py +0 -301
  157. qtype-0.0.16/tests/test_tools_from_module.py +0 -317
  158. qtype-0.0.16/tests/test_visualize.py +0 -51
  159. {qtype-0.0.16 → qtype-0.1.1}/LICENSE +0 -0
  160. {qtype-0.0.16 → qtype-0.1.1}/README.md +0 -0
  161. {qtype-0.0.16 → qtype-0.1.1}/qtype/__init__.py +0 -0
  162. {qtype-0.0.16 → qtype-0.1.1}/qtype/application/__init__.py +0 -0
  163. {qtype-0.0.16 → qtype-0.1.1}/qtype/application/commons/__init__.py +0 -0
  164. {qtype-0.0.16 → qtype-0.1.1}/qtype/application/converters/__init__.py +0 -0
  165. {qtype-0.0.16 → qtype-0.1.1}/qtype/base/__init__.py +0 -0
  166. {qtype-0.0.16 → qtype-0.1.1}/qtype/base/exceptions.py +0 -0
  167. {qtype-0.0.16 → qtype-0.1.1}/qtype/base/logging.py +0 -0
  168. {qtype-0.0.16 → qtype-0.1.1}/qtype/commands/__init__.py +0 -0
  169. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/__init__.py +0 -0
  170. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/auth/__init__.py +0 -0
  171. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/auth/cache.py +0 -0
  172. {qtype-0.0.16/qtype/interpreter/ui/_next/static/nUaw6_IwRwPqkzwe5s725 → qtype-0.1.1/qtype/interpreter/ui/_next/static/20HoJN6otZ_LyHLHpCPE6}/_ssgManifest.js +0 -0
  173. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/_next/static/chunks/4bd1b696-cf72ae8a39fa05aa.js +0 -0
  174. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/_next/static/chunks/964-2b041321a01cbf56.js +0 -0
  175. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/_next/static/chunks/app/_not-found/page-e110d2a9d0a83d82.js +0 -0
  176. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/_next/static/chunks/app/layout-a05273ead5de2c41.js +0 -0
  177. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/_next/static/chunks/framework-7c95b8e5103c9e90.js +0 -0
  178. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/_next/static/chunks/main-app-6fc6346bc8f7f163.js +0 -0
  179. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/_next/static/chunks/main-e26b9cb206da2cac.js +0 -0
  180. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/_next/static/chunks/pages/_app-0a0020ddd67f79cf.js +0 -0
  181. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/_next/static/chunks/pages/_error-03529f2c21436739.js +0 -0
  182. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -0
  183. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/_next/static/chunks/webpack-08642e441b39b6c2.js +0 -0
  184. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/_next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  185. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/_next/static/media/747892c23ea88013-s.woff2 +0 -0
  186. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/_next/static/media/8d697b304b401681-s.woff2 +0 -0
  187. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/_next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  188. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/_next/static/media/9610d9e46709d722-s.woff2 +0 -0
  189. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/_next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  190. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/file.svg +0 -0
  191. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/globe.svg +0 -0
  192. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/next.svg +0 -0
  193. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/vercel.svg +0 -0
  194. {qtype-0.0.16 → qtype-0.1.1}/qtype/interpreter/ui/window.svg +0 -0
  195. {qtype-0.0.16/qtype/interpreter/batch → qtype-0.1.1/qtype/semantic}/__init__.py +0 -0
  196. {qtype-0.0.16 → qtype-0.1.1}/qtype/semantic/base_types.py +0 -0
  197. {qtype-0.0.16 → qtype-0.1.1}/qtype.egg-info/dependency_links.txt +0 -0
  198. {qtype-0.0.16 → qtype-0.1.1}/qtype.egg-info/entry_points.txt +0 -0
  199. {qtype-0.0.16 → qtype-0.1.1}/qtype.egg-info/top_level.txt +0 -0
  200. {qtype-0.0.16 → qtype-0.1.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qtype
3
- Version: 0.0.16
3
+ Version: 0.1.1
4
4
  Summary: DSL for Generative AI Prototyping
5
5
  Author-email: Lou Kratz <lou.kratz+qtype@bazaarvoice.com>
6
6
  License-Expression: Apache-2.0
@@ -15,20 +15,24 @@ Requires-Dist: python-dotenv>=1.0.0
15
15
  Requires-Dist: openai>=1.93.0
16
16
  Requires-Dist: fsspec>=2025.5.1
17
17
  Requires-Dist: mkdocs-awesome-pages-plugin>=2.10.1
18
- Requires-Dist: mermaid-py>=0.8.0
19
18
  Requires-Dist: pip-system-certs>=5.2
20
19
  Requires-Dist: openapi3-parser>=1.1.21
21
20
  Requires-Dist: pydantic-yaml>=1.6.0
21
+ Requires-Dist: google-cloud-aiplatform>=1.120.0
22
22
  Provides-Extra: interpreter
23
+ Requires-Dist: aiostream>=0.7.1; extra == "interpreter"
23
24
  Requires-Dist: arize-phoenix-otel>=0.12.1; extra == "interpreter"
24
25
  Requires-Dist: boto3>=1.34.0; extra == "interpreter"
26
+ Requires-Dist: docling>=2.55.1; extra == "interpreter"
27
+ Requires-Dist: diskcache[interpreter]>=5.6.3; extra == "interpreter"
25
28
  Requires-Dist: fastapi>=0.116.1; extra == "interpreter"
26
29
  Requires-Dist: llama-index-embeddings-bedrock>=0.5.2; extra == "interpreter"
27
30
  Requires-Dist: llama-index-embeddings-openai>=0.3.1; extra == "interpreter"
28
- Requires-Dist: llama-index-llms-bedrock-converse>=0.7.4; extra == "interpreter"
31
+ Requires-Dist: llama-index-llms-bedrock-converse>=0.10.5; extra == "interpreter"
29
32
  Requires-Dist: llama-index-llms-bedrock>=0.3.8; extra == "interpreter"
30
33
  Requires-Dist: llama-index>=0.12.45; extra == "interpreter"
31
34
  Requires-Dist: openinference-instrumentation-llama-index>=4.3.4; extra == "interpreter"
35
+ Requires-Dist: opensearch-py>=2.7.0; extra == "interpreter"
32
36
  Requires-Dist: pandas>=2.2.3; extra == "interpreter"
33
37
  Requires-Dist: psycopg2-binary>=2.9.10; extra == "interpreter"
34
38
  Requires-Dist: pyarrow>=21.0.0; extra == "interpreter"
@@ -37,6 +41,15 @@ Requires-Dist: python-magic>=0.4.27; extra == "interpreter"
37
41
  Requires-Dist: s3fs>=2025.7.0; extra == "interpreter"
38
42
  Requires-Dist: sqlalchemy>=2.0.42; extra == "interpreter"
39
43
  Requires-Dist: uvicorn[standard]>=0.35.0; extra == "interpreter"
44
+ Requires-Dist: llama-index-llms-vertex>=0.6.1; extra == "interpreter"
45
+ Requires-Dist: langfuse>=3.9.0; extra == "interpreter"
46
+ Requires-Dist: opentelemetry-exporter-otlp>=1.35.0; extra == "interpreter"
47
+ Requires-Dist: opentelemetry-sdk>=1.35.0; extra == "interpreter"
48
+ Requires-Dist: docx2txt>=0.9; extra == "interpreter"
49
+ Requires-Dist: llama-index-vector-stores-qdrant>=0.8.6; extra == "interpreter"
50
+ Requires-Dist: jsonpath-ng>=1.7.0; extra == "interpreter"
51
+ Requires-Dist: llama-index-readers-huggingface-fs>=0.4.1; extra == "interpreter"
52
+ Requires-Dist: datasets>=4.4.1; extra == "interpreter"
40
53
  Dynamic: license-file
41
54
 
42
55
  # QType
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "qtype"
3
- version = "0.0.16"
3
+ version = "0.1.1"
4
4
  description = "DSL for Generative AI Prototyping"
5
5
  authors = [{ name="Lou Kratz", email="lou.kratz+qtype@bazaarvoice.com" }]
6
6
  readme = "README.md"
@@ -13,10 +13,10 @@ dependencies = [
13
13
  "openai>=1.93.0",
14
14
  "fsspec>=2025.5.1",
15
15
  "mkdocs-awesome-pages-plugin>=2.10.1",
16
- "mermaid-py>=0.8.0",
17
16
  "pip-system-certs>=5.2",
18
17
  "openapi3-parser>=1.1.21",
19
18
  "pydantic-yaml>=1.6.0",
19
+ "google-cloud-aiplatform>=1.120.0",
20
20
  ]
21
21
  license = "APACHE-2.0"
22
22
  license-files = ["LICEN[CS]E*"]
@@ -26,15 +26,19 @@ Homepage = "https://github.com/bazaarvoice/qtype"
26
26
 
27
27
  [project.optional-dependencies]
28
28
  interpreter = [
29
+ "aiostream>=0.7.1",
29
30
  "arize-phoenix-otel>=0.12.1",
30
31
  "boto3>=1.34.0",
32
+ "docling>=2.55.1",
33
+ "diskcache[interpreter]>=5.6.3",
31
34
  "fastapi>=0.116.1",
32
35
  "llama-index-embeddings-bedrock>=0.5.2",
33
36
  "llama-index-embeddings-openai>=0.3.1",
34
- "llama-index-llms-bedrock-converse>=0.7.4",
37
+ "llama-index-llms-bedrock-converse>=0.10.5",
35
38
  "llama-index-llms-bedrock>=0.3.8",
36
39
  "llama-index>=0.12.45",
37
40
  "openinference-instrumentation-llama-index>=4.3.4",
41
+ "opensearch-py>=2.7.0",
38
42
  "pandas>=2.2.3",
39
43
  "psycopg2-binary>=2.9.10",
40
44
  "pyarrow>=21.0.0",
@@ -43,6 +47,15 @@ interpreter = [
43
47
  "s3fs>=2025.7.0",
44
48
  "sqlalchemy>=2.0.42",
45
49
  "uvicorn[standard]>=0.35.0",
50
+ "llama-index-llms-vertex>=0.6.1",
51
+ "langfuse>=3.9.0",
52
+ "opentelemetry-exporter-otlp>=1.35.0",
53
+ "opentelemetry-sdk>=1.35.0",
54
+ "docx2txt>=0.9",
55
+ "llama-index-vector-stores-qdrant>=0.8.6",
56
+ "jsonpath-ng>=1.7.0",
57
+ "llama-index-readers-huggingface-fs>=0.4.1",
58
+ "datasets>=4.4.1",
46
59
  ]
47
60
 
48
61
  [dependency-groups]
@@ -52,6 +65,7 @@ dev = [
52
65
  "coverage>=7.0.0",
53
66
  "ipython>=8.37.0",
54
67
  "isort>=5.13.0",
68
+ "mermaid-py>=0.8.0",
55
69
  "mkdocs-awesome-pages-plugin>=2.10.1",
56
70
  "mkdocs-material>=9.6.15",
57
71
  "mkdocs>=1.6.1",
@@ -63,6 +77,7 @@ dev = [
63
77
  "pkginfo>=1.12.1.2",
64
78
  "pre-commit>=3.6.0",
65
79
  "pymdown-extensions>=10.16",
80
+ "pytest-asyncio>=1.2.0",
66
81
  "pytest-cov>=6.0.0",
67
82
  "pytest>=8.4.1",
68
83
  "ruff>=0.1.0",
@@ -79,6 +94,8 @@ docs = [
79
94
  [tool.uv]
80
95
  # Install dev dependencies by default when running uv sync
81
96
  default-groups = ["dev"]
97
+ # Install the package itself in editable mode
98
+ package = true
82
99
  # Use highest resolution strategy for dependencies
83
100
  resolution = "highest"
84
101
  # Compile bytecode for faster subsequent runs
@@ -183,4 +200,7 @@ filterwarnings = [
183
200
  markers = [
184
201
  "slow: marks tests as slow (deselect with '-m \"not slow\"')",
185
202
  "network: marks tests as requiring network access",
203
+ "asyncio: marks tests as async tests using asyncio",
186
204
  ]
205
+ # Configure pytest-asyncio to automatically detect async tests
206
+ asyncio_mode = "auto"
@@ -180,7 +180,7 @@ def parse_duration_string(duration: str) -> int:
180
180
 
181
181
  def format_datetime(timestamp: datetime, format_string: str) -> str:
182
182
  """
183
- Format a timestamp using a custom format string.
183
+ Format a timestamp using a custom format string that can be passed to strftime.
184
184
 
185
185
  Args:
186
186
  timestamp: Datetime object to format.
@@ -17,7 +17,7 @@ from openapi_parser.specification import (
17
17
  Security,
18
18
  )
19
19
 
20
- from qtype.dsl.base_types import PrimitiveTypeEnum
20
+ from qtype.base.types import PrimitiveTypeEnum
21
21
  from qtype.dsl.model import (
22
22
  APIKeyAuthProvider,
23
23
  APITool,
@@ -344,9 +344,9 @@ def to_api_tool(
344
344
  endpoint=endpoint,
345
345
  method=operation.method.value.upper(),
346
346
  auth=auth.id if auth else None, # Use auth ID string instead of object
347
- inputs=inputs if inputs else None,
348
- outputs=outputs if outputs else None,
349
- parameters=parameters if parameters else None,
347
+ inputs=inputs,
348
+ outputs=outputs,
349
+ parameters=parameters,
350
350
  )
351
351
 
352
352
 
@@ -394,7 +394,7 @@ def to_authorization_provider(
394
394
  }
395
395
  )
396
396
  if any(flow.scopes for flow in security.flows.values())
397
- else None,
397
+ else [],
398
398
  )
399
399
  case _:
400
400
  raise ValueError(
@@ -5,7 +5,7 @@ from typing import Any, Type, Union, get_args, get_origin
5
5
  from pydantic import BaseModel
6
6
 
7
7
  from qtype.application.converters.types import PYTHON_TYPE_TO_PRIMITIVE_TYPE
8
- from qtype.dsl.base_types import PrimitiveTypeEnum
8
+ from qtype.base.types import PrimitiveTypeEnum
9
9
  from qtype.dsl.model import (
10
10
  CustomType,
11
11
  ListType,
@@ -159,7 +159,7 @@ def _create_tool_from_function(
159
159
  module_path=func_info["module"],
160
160
  function_name=func_name,
161
161
  description=description,
162
- inputs=inputs if inputs else None,
162
+ inputs=inputs,
163
163
  outputs=outputs,
164
164
  )
165
165
 
@@ -0,0 +1,18 @@
1
+ """
2
+ Re-export type mappings from DSL layer for backward compatibility.
3
+
4
+ This module maintains the application layer's interface while delegating
5
+ to the DSL layer where these mappings are now defined.
6
+ """
7
+
8
+ from qtype.dsl.types import (
9
+ PRIMITIVE_TO_PYTHON_TYPE,
10
+ PYTHON_TYPE_TO_PRIMITIVE_TYPE,
11
+ python_type_for_list,
12
+ )
13
+
14
+ __all__ = [
15
+ "PRIMITIVE_TO_PYTHON_TYPE",
16
+ "PYTHON_TYPE_TO_PRIMITIVE_TYPE",
17
+ "python_type_for_list",
18
+ ]
@@ -5,7 +5,7 @@ from pathlib import Path
5
5
  from typing import Any, Type, Union, get_args, get_origin
6
6
 
7
7
  import qtype.dsl.model as dsl
8
- from qtype.dsl.base_types import PrimitiveTypeEnum
8
+ from qtype.base.types import PrimitiveTypeEnum
9
9
 
10
10
 
11
11
  def _format_type_name(field_type: Any) -> str:
@@ -0,0 +1,178 @@
1
+ """Main facade for qtype operations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ from qtype.base.types import PathLike
10
+ from qtype.semantic.model import Application as SemanticApplication
11
+ from qtype.semantic.model import DocumentType as SemanticDocumentType
12
+
13
+ # Note: There should be _zero_ imports here at the top that import qtype.interpreter.
14
+ # That's the whole point of this facade - to avoid importing optional
15
+ # dependencies unless these methods are called.
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ class QTypeFacade:
21
+ """
22
+ Simplified interface for qtype operations.
23
+
24
+ This facade provides lazy-loading wrappers for operations that require
25
+ optional dependencies (interpreter package), allowing base qtype to work
26
+ without those dependencies installed.
27
+ """
28
+
29
+ def telemetry(self, spec: SemanticDocumentType) -> None:
30
+ if isinstance(spec, SemanticApplication) and spec.telemetry:
31
+ logger.info(
32
+ f"Telemetry enabled with endpoint: {spec.telemetry.endpoint}"
33
+ )
34
+ # Register telemetry if needed
35
+ from qtype.interpreter.telemetry import register
36
+
37
+ register(spec.telemetry, self.secret_manager(spec), spec.id)
38
+
39
+ def secret_manager(self, spec: SemanticDocumentType):
40
+ """
41
+ Create a secret manager based on the specification.
42
+
43
+ Args:
44
+ spec: SemanticDocumentType specification
45
+
46
+ Returns:
47
+ Secret manager instance
48
+ """
49
+ from qtype.interpreter.base.secrets import create_secret_manager
50
+
51
+ if isinstance(spec, SemanticApplication):
52
+ return create_secret_manager(spec.secret_manager)
53
+ else:
54
+ raise ValueError(
55
+ "Can't create secret manager for non-Application spec"
56
+ )
57
+
58
+ async def execute_workflow(
59
+ self,
60
+ path: PathLike,
61
+ inputs: dict | Any,
62
+ flow_name: str | None = None,
63
+ **kwargs: Any,
64
+ ) -> Any:
65
+ """
66
+ Execute a complete workflow from document to results.
67
+
68
+ Args:
69
+ path: Path to the QType specification file
70
+ inputs: Dictionary of input values or DataFrame for batch
71
+ flow_name: Optional name of flow to execute
72
+ **kwargs: Additional dependencies for execution
73
+
74
+ Returns:
75
+ DataFrame with results (one row per input)
76
+ """
77
+ import pandas as pd
78
+
79
+ from qtype.semantic.loader import load
80
+
81
+ logger.info(f"Executing workflow from {path}")
82
+
83
+ # Load the semantic application
84
+ semantic_model, type_registry = load(Path(path))
85
+ assert isinstance(semantic_model, SemanticApplication)
86
+ self.telemetry(semantic_model)
87
+
88
+ # Find the flow to execute
89
+ if flow_name:
90
+ target_flow = None
91
+ for flow in semantic_model.flows:
92
+ if flow.id == flow_name:
93
+ target_flow = flow
94
+ break
95
+ if target_flow is None:
96
+ raise ValueError(f"Flow '{flow_name}' not found")
97
+ else:
98
+ if semantic_model.flows:
99
+ target_flow = semantic_model.flows[0]
100
+ else:
101
+ raise ValueError("No flows found in application")
102
+
103
+ # Convert inputs to DataFrame (normalize single dict to 1-row DataFrame)
104
+ if isinstance(inputs, dict):
105
+ input_df = pd.DataFrame([inputs])
106
+ elif isinstance(inputs, pd.DataFrame):
107
+ input_df = inputs
108
+ else:
109
+ raise ValueError(
110
+ f"Inputs must be dict or DataFrame, got {type(inputs)}"
111
+ )
112
+
113
+ # Create session
114
+ from qtype.interpreter.converters import (
115
+ dataframe_to_flow_messages,
116
+ flow_messages_to_dataframe,
117
+ )
118
+ from qtype.interpreter.types import Session
119
+
120
+ session = Session(
121
+ session_id=kwargs.pop("session_id", "default"),
122
+ conversation_history=kwargs.pop("conversation_history", []),
123
+ )
124
+
125
+ # Convert DataFrame to FlowMessages
126
+ initial_messages = dataframe_to_flow_messages(input_df, session)
127
+
128
+ # Execute the flow
129
+ from opentelemetry import trace
130
+
131
+ from qtype.interpreter.base.executor_context import ExecutorContext
132
+ from qtype.interpreter.flow import run_flow
133
+
134
+ secret_manager = self.secret_manager(semantic_model)
135
+ context = ExecutorContext(
136
+ secret_manager=secret_manager,
137
+ tracer=trace.get_tracer(__name__),
138
+ )
139
+ results = await run_flow(
140
+ target_flow,
141
+ initial_messages,
142
+ context=context,
143
+ **kwargs,
144
+ )
145
+
146
+ # Convert results back to DataFrame
147
+ results_df = flow_messages_to_dataframe(results, target_flow)
148
+
149
+ return results_df
150
+
151
+ def generate_aws_bedrock_models(self) -> list[dict[str, Any]]:
152
+ """
153
+ Generate AWS Bedrock model definitions.
154
+
155
+ Returns:
156
+ List of model definitions for AWS Bedrock models.
157
+
158
+ Raises:
159
+ ImportError: If boto3 is not installed.
160
+ Exception: If AWS API call fails.
161
+ """
162
+ import boto3 # type: ignore[import-untyped]
163
+
164
+ logger.info("Discovering AWS Bedrock models...")
165
+ client = boto3.client("bedrock")
166
+ models = client.list_foundation_models()
167
+
168
+ model_definitions = []
169
+ for model_summary in models.get("modelSummaries", []):
170
+ model_definitions.append(
171
+ {
172
+ "id": model_summary["modelId"],
173
+ "provider": "aws-bedrock",
174
+ }
175
+ )
176
+
177
+ logger.info(f"Discovered {len(model_definitions)} AWS Bedrock models")
178
+ return model_definitions
@@ -0,0 +1,249 @@
1
+ """Common type definitions for qtype."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import pathlib
6
+ import types
7
+ import typing
8
+ from enum import Enum
9
+ from typing import (
10
+ Any,
11
+ Generic,
12
+ Literal,
13
+ Optional,
14
+ Type,
15
+ TypeVar,
16
+ Union,
17
+ get_args,
18
+ get_origin,
19
+ )
20
+
21
+ from pydantic import BaseModel
22
+ from pydantic import ConfigDict as PydanticConfigDict
23
+ from pydantic import Field, model_validator
24
+
25
+ # JSON-serializable value types
26
+ JSONValue = Union[
27
+ str,
28
+ int,
29
+ float,
30
+ bool,
31
+ None,
32
+ dict[str, "JSONValue"],
33
+ list["JSONValue"],
34
+ ]
35
+
36
+ # Path-like type (string or Path object)
37
+ PathLike = Union[str, pathlib.Path]
38
+
39
+ CustomTypeRegistry = dict[str, Type[BaseModel]]
40
+ # Configuration dictionary type
41
+ ConfigDict = dict[str, Any]
42
+
43
+
44
+ # ---------------- Shared Base Types and Enums ----------------
45
+
46
+
47
+ class PrimitiveTypeEnum(str, Enum):
48
+ """Represents the type of data a user or system input can accept within the DSL."""
49
+
50
+ audio = "audio"
51
+ boolean = "boolean"
52
+ bytes = "bytes"
53
+ citation_document = "citation_document"
54
+ citation_url = "citation_url"
55
+ date = "date"
56
+ datetime = "datetime"
57
+ int = "int"
58
+ file = "file"
59
+ float = "float"
60
+ image = "image"
61
+ text = "text"
62
+ time = "time"
63
+ video = "video"
64
+ thinking = "thinking"
65
+
66
+
67
+ class StepCardinality(str, Enum):
68
+ """Does this step emit 1 (one) or 0...N (many) items?"""
69
+
70
+ one = "one"
71
+ many = "many"
72
+
73
+
74
+ ReferenceT = TypeVar("ReferenceT")
75
+
76
+
77
+ class Reference(BaseModel, Generic[ReferenceT]):
78
+ """Represents a reference to another component by its ID."""
79
+
80
+ # model_config = PydanticConfigDict(extra="forbid")
81
+
82
+ ref: str = Field(..., alias="$ref")
83
+
84
+
85
+ def _contains_reference_and_str(type_hint: Any) -> bool:
86
+ """Check if type contains both Reference and str in a union."""
87
+ # Get union args (handles Union, | syntax, and Optional)
88
+ origin = get_origin(type_hint)
89
+ if origin not in (Union, None) and not isinstance(
90
+ type_hint, types.UnionType
91
+ ):
92
+ return False
93
+
94
+ args = get_args(type_hint)
95
+ if not args:
96
+ return False
97
+
98
+ has_str = str in args
99
+ has_ref = any(
100
+ get_origin(arg) is Reference
101
+ or (hasattr(arg, "__mro__") and Reference in arg.__mro__)
102
+ for arg in args
103
+ )
104
+ return has_str and has_ref
105
+
106
+
107
+ def _should_transform_field(type_hint: Any) -> tuple[bool, bool]:
108
+ """
109
+ Check if field should be transformed.
110
+ Returns: (should_transform, is_list)
111
+ """
112
+ # Check direct union: Reference[T] | str
113
+ if _contains_reference_and_str(type_hint):
114
+ return True, False
115
+
116
+ # Check list of union: list[Reference[T] | str]
117
+ origin = get_origin(type_hint)
118
+ if origin is list:
119
+ args = get_args(type_hint)
120
+ if args and _contains_reference_and_str(args[0]):
121
+ return True, True
122
+
123
+ # Check optional list: list[Reference[T] | str] | None
124
+ if origin is Union or isinstance(type_hint, types.UnionType):
125
+ for arg in get_args(type_hint):
126
+ if get_origin(arg) is list:
127
+ inner_args = get_args(arg)
128
+ if inner_args and _contains_reference_and_str(inner_args[0]):
129
+ return True, True
130
+
131
+ return False, False
132
+
133
+
134
+ class StrictBaseModel(BaseModel):
135
+ """Base model with extra fields forbidden."""
136
+
137
+ model_config = PydanticConfigDict(extra="forbid")
138
+
139
+ @model_validator(mode="before")
140
+ @classmethod
141
+ def normalize_string_references(cls, data: Any) -> Any:
142
+ """
143
+ Normalize string references to Reference objects before validation.
144
+
145
+ Transforms:
146
+ - `field: "ref_id"` -> `field: {"$ref": "ref_id"}`
147
+ - `field: ["ref1", "ref2"]` -> `field: [{"$ref": "ref1"}, {"$ref": "ref2"}]`
148
+
149
+ Only applies to fields typed as `Reference[T] | str` or `list[Reference[T] | str]`.
150
+ """
151
+ if not isinstance(data, dict):
152
+ return data
153
+
154
+ # Get type hints (evaluates ForwardRefs)
155
+ hints = typing.get_type_hints(cls)
156
+
157
+ # Transform fields
158
+ for field_name, field_value in data.items():
159
+ if field_name == "type" or field_name not in hints:
160
+ continue
161
+
162
+ should_transform, is_list = _should_transform_field(
163
+ hints[field_name]
164
+ )
165
+ if not should_transform:
166
+ continue
167
+
168
+ if is_list and isinstance(field_value, list):
169
+ data[field_name] = [
170
+ {"$ref": item} if isinstance(item, str) else item
171
+ for item in field_value
172
+ ]
173
+ elif not is_list and isinstance(field_value, str):
174
+ data[field_name] = {"$ref": field_value}
175
+
176
+ return data
177
+
178
+
179
+ class BatchConfig(BaseModel):
180
+ """Configuration for batch execution.
181
+
182
+ Attributes:
183
+ num_workers: Number of async workers for batch operations.
184
+ """
185
+
186
+ batch_size: int = Field(
187
+ default=25,
188
+ description="Max number of rows to send to a step at a time",
189
+ gt=0,
190
+ )
191
+
192
+
193
+ class ConcurrencyConfig(BaseModel):
194
+ """Configuration for concurrent processing.
195
+
196
+ Attributes:
197
+ num_workers: Number of async workers for batch operations.
198
+ """
199
+
200
+ num_workers: int = Field(
201
+ default=1,
202
+ description="Number of async workers for batch operations",
203
+ gt=0,
204
+ )
205
+
206
+
207
+ class BatchableStepMixin(BaseModel):
208
+ """A mixin for steps that support concurrent batch processing."""
209
+
210
+ batch_config: BatchConfig = Field(
211
+ default_factory=BatchConfig,
212
+ description="Configuration for processing the input stream in batches. If omitted, the step processes items one by one.",
213
+ )
214
+
215
+
216
+ class CacheConfig(BaseModel):
217
+ directory: PathLike = Field(
218
+ default=pathlib.Path("./.qtype-cache"),
219
+ description="Base cache directory.",
220
+ )
221
+ namespace: Optional[str] = Field(
222
+ default=None, description="Logical namespace for cache keys."
223
+ )
224
+ on_error: Literal["Cache", "Drop"] = "Drop"
225
+ version: str = Field(
226
+ default="1.0", description="Bump to invalidate old cache."
227
+ )
228
+ compress: bool = Field(default=False, description="Compress stored data.")
229
+ ttl: Optional[int] = Field(
230
+ default=None, description="Optional time-to-live in seconds."
231
+ )
232
+
233
+
234
+ class CachedStepMixin(BaseModel):
235
+ """A mixin for steps that support caching."""
236
+
237
+ cache_config: CacheConfig | None = Field(
238
+ default=None,
239
+ description="Configuration for caching step outputs. If omitted, caching is disabled.",
240
+ )
241
+
242
+
243
+ class ConcurrentStepMixin(BaseModel):
244
+ """A mixin for steps that support concurrent processing."""
245
+
246
+ concurrency_config: ConcurrencyConfig = Field(
247
+ default_factory=ConcurrencyConfig,
248
+ description="Configuration for processing the input stream concurrently. If omitted, the step processes items sequentially.",
249
+ )
@@ -7,6 +7,10 @@ import importlib
7
7
  import logging
8
8
  from pathlib import Path
9
9
 
10
+ from qtype.base.logging import get_logger
11
+
12
+ logger = get_logger("application.facade")
13
+
10
14
  try:
11
15
  from importlib.metadata import entry_points
12
16
  except ImportError: