qtype 0.1.0__tar.gz → 0.1.2__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 (143) hide show
  1. {qtype-0.1.0/qtype.egg-info → qtype-0.1.2}/PKG-INFO +12 -11
  2. {qtype-0.1.0 → qtype-0.1.2}/pyproject.toml +12 -11
  3. {qtype-0.1.0 → qtype-0.1.2}/qtype/application/facade.py +16 -17
  4. {qtype-0.1.0 → qtype-0.1.2}/qtype/cli.py +5 -1
  5. {qtype-0.1.0 → qtype-0.1.2}/qtype/commands/generate.py +1 -1
  6. {qtype-0.1.0 → qtype-0.1.2}/qtype/commands/run.py +28 -5
  7. {qtype-0.1.0 → qtype-0.1.2}/qtype/dsl/domain_types.py +24 -3
  8. {qtype-0.1.0 → qtype-0.1.2}/qtype/dsl/model.py +56 -3
  9. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/base/base_step_executor.py +8 -1
  10. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/base/executor_context.py +18 -1
  11. qtype-0.1.2/qtype/interpreter/base/factory.py +84 -0
  12. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/base/progress_tracker.py +35 -0
  13. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/base/step_cache.py +3 -2
  14. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/conversions.py +34 -19
  15. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/converters.py +19 -13
  16. qtype-0.1.2/qtype/interpreter/executors/bedrock_reranker_executor.py +195 -0
  17. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/executors/document_embedder_executor.py +36 -4
  18. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/executors/document_search_executor.py +37 -46
  19. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/executors/document_splitter_executor.py +1 -1
  20. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/executors/field_extractor_executor.py +10 -5
  21. qtype-0.1.2/qtype/interpreter/executors/index_upsert_executor.py +232 -0
  22. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/executors/invoke_embedding_executor.py +2 -2
  23. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/executors/invoke_tool_executor.py +6 -1
  24. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/flow.py +47 -32
  25. qtype-0.1.2/qtype/interpreter/rich_progress.py +225 -0
  26. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/types.py +2 -0
  27. {qtype-0.1.0 → qtype-0.1.2}/qtype/semantic/checker.py +79 -19
  28. {qtype-0.1.0 → qtype-0.1.2}/qtype/semantic/model.py +43 -3
  29. {qtype-0.1.0 → qtype-0.1.2}/qtype/semantic/resolver.py +4 -2
  30. {qtype-0.1.0 → qtype-0.1.2/qtype.egg-info}/PKG-INFO +12 -11
  31. {qtype-0.1.0 → qtype-0.1.2}/qtype.egg-info/SOURCES.txt +2 -0
  32. {qtype-0.1.0 → qtype-0.1.2}/qtype.egg-info/requires.txt +11 -10
  33. qtype-0.1.0/qtype/interpreter/base/factory.py +0 -117
  34. qtype-0.1.0/qtype/interpreter/executors/index_upsert_executor.py +0 -228
  35. {qtype-0.1.0 → qtype-0.1.2}/LICENSE +0 -0
  36. {qtype-0.1.0 → qtype-0.1.2}/README.md +0 -0
  37. {qtype-0.1.0 → qtype-0.1.2}/qtype/__init__.py +0 -0
  38. {qtype-0.1.0 → qtype-0.1.2}/qtype/application/__init__.py +0 -0
  39. {qtype-0.1.0 → qtype-0.1.2}/qtype/application/commons/__init__.py +0 -0
  40. {qtype-0.1.0 → qtype-0.1.2}/qtype/application/commons/tools.py +0 -0
  41. {qtype-0.1.0 → qtype-0.1.2}/qtype/application/converters/__init__.py +0 -0
  42. {qtype-0.1.0 → qtype-0.1.2}/qtype/application/converters/tools_from_api.py +0 -0
  43. {qtype-0.1.0 → qtype-0.1.2}/qtype/application/converters/tools_from_module.py +0 -0
  44. {qtype-0.1.0 → qtype-0.1.2}/qtype/application/converters/types.py +0 -0
  45. {qtype-0.1.0 → qtype-0.1.2}/qtype/application/documentation.py +0 -0
  46. {qtype-0.1.0 → qtype-0.1.2}/qtype/base/__init__.py +0 -0
  47. {qtype-0.1.0 → qtype-0.1.2}/qtype/base/exceptions.py +0 -0
  48. {qtype-0.1.0 → qtype-0.1.2}/qtype/base/logging.py +0 -0
  49. {qtype-0.1.0 → qtype-0.1.2}/qtype/base/types.py +0 -0
  50. {qtype-0.1.0 → qtype-0.1.2}/qtype/commands/__init__.py +0 -0
  51. {qtype-0.1.0 → qtype-0.1.2}/qtype/commands/convert.py +0 -0
  52. {qtype-0.1.0 → qtype-0.1.2}/qtype/commands/serve.py +0 -0
  53. {qtype-0.1.0 → qtype-0.1.2}/qtype/commands/validate.py +0 -0
  54. {qtype-0.1.0 → qtype-0.1.2}/qtype/commands/visualize.py +0 -0
  55. {qtype-0.1.0 → qtype-0.1.2}/qtype/dsl/__init__.py +0 -0
  56. {qtype-0.1.0 → qtype-0.1.2}/qtype/dsl/custom_types.py +0 -0
  57. {qtype-0.1.0 → qtype-0.1.2}/qtype/dsl/linker.py +0 -0
  58. {qtype-0.1.0 → qtype-0.1.2}/qtype/dsl/loader.py +0 -0
  59. {qtype-0.1.0 → qtype-0.1.2}/qtype/dsl/parser.py +0 -0
  60. {qtype-0.1.0 → qtype-0.1.2}/qtype/dsl/types.py +0 -0
  61. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/__init__.py +0 -0
  62. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/api.py +0 -0
  63. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/auth/__init__.py +0 -0
  64. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/auth/aws.py +0 -0
  65. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/auth/cache.py +0 -0
  66. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/auth/generic.py +0 -0
  67. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/base/batch_step_executor.py +0 -0
  68. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/base/exceptions.py +0 -0
  69. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/base/secrets.py +0 -0
  70. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/base/stream_emitter.py +0 -0
  71. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/endpoints.py +0 -0
  72. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/executors/agent_executor.py +0 -0
  73. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/executors/aggregate_executor.py +0 -0
  74. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/executors/decoder_executor.py +0 -0
  75. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/executors/doc_to_text_executor.py +0 -0
  76. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/executors/document_source_executor.py +0 -0
  77. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/executors/echo_executor.py +0 -0
  78. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/executors/file_source_executor.py +0 -0
  79. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/executors/file_writer_executor.py +0 -0
  80. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/executors/invoke_flow_executor.py +0 -0
  81. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/executors/llm_inference_executor.py +0 -0
  82. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/executors/prompt_template_executor.py +0 -0
  83. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/executors/sql_source_executor.py +0 -0
  84. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/executors/vector_search_executor.py +0 -0
  85. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/metadata_api.py +0 -0
  86. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/resource_cache.py +0 -0
  87. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/stream/chat/__init__.py +0 -0
  88. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/stream/chat/converter.py +0 -0
  89. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/stream/chat/file_conversions.py +0 -0
  90. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/stream/chat/ui_request_to_domain_type.py +0 -0
  91. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/stream/chat/vercel.py +0 -0
  92. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/stream/utils/__init__.py +0 -0
  93. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/stream/utils/build_vercel_ai_formatter.py +0 -0
  94. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/stream/utils/callback_to_stream.py +0 -0
  95. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/stream/utils/create_streaming_response.py +0 -0
  96. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/stream/utils/default_chat_extract_text.py +0 -0
  97. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/stream/utils/error_streaming_response.py +0 -0
  98. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/telemetry.py +0 -0
  99. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/tools/__init__.py +0 -0
  100. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/tools/function_tool_helper.py +0 -0
  101. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/typing.py +0 -0
  102. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/404/index.html +0 -0
  103. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/404.html +0 -0
  104. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/20HoJN6otZ_LyHLHpCPE6/_buildManifest.js +0 -0
  105. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/20HoJN6otZ_LyHLHpCPE6/_ssgManifest.js +0 -0
  106. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/chunks/434-b2112d19f25c44ff.js +0 -0
  107. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/chunks/4bd1b696-cf72ae8a39fa05aa.js +0 -0
  108. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/chunks/964-2b041321a01cbf56.js +0 -0
  109. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/chunks/app/_not-found/page-e110d2a9d0a83d82.js +0 -0
  110. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/chunks/app/layout-a05273ead5de2c41.js +0 -0
  111. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/chunks/app/page-8c67d16ac90d23cb.js +0 -0
  112. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/chunks/ba12c10f-546f2714ff8abc66.js +0 -0
  113. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/chunks/framework-7c95b8e5103c9e90.js +0 -0
  114. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/chunks/main-app-6fc6346bc8f7f163.js +0 -0
  115. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/chunks/main-e26b9cb206da2cac.js +0 -0
  116. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/chunks/pages/_app-0a0020ddd67f79cf.js +0 -0
  117. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/chunks/pages/_error-03529f2c21436739.js +0 -0
  118. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -0
  119. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/chunks/webpack-08642e441b39b6c2.js +0 -0
  120. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/css/8a8d1269e362fef7.css +0 -0
  121. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  122. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/media/747892c23ea88013-s.woff2 +0 -0
  123. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/media/8d697b304b401681-s.woff2 +0 -0
  124. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  125. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/media/9610d9e46709d722-s.woff2 +0 -0
  126. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/_next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  127. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/file.svg +0 -0
  128. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/globe.svg +0 -0
  129. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/icon.png +0 -0
  130. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/index.html +0 -0
  131. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/index.txt +0 -0
  132. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/next.svg +0 -0
  133. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/vercel.svg +0 -0
  134. {qtype-0.1.0 → qtype-0.1.2}/qtype/interpreter/ui/window.svg +0 -0
  135. {qtype-0.1.0 → qtype-0.1.2}/qtype/semantic/__init__.py +0 -0
  136. {qtype-0.1.0 → qtype-0.1.2}/qtype/semantic/base_types.py +0 -0
  137. {qtype-0.1.0 → qtype-0.1.2}/qtype/semantic/generate.py +0 -0
  138. {qtype-0.1.0 → qtype-0.1.2}/qtype/semantic/loader.py +0 -0
  139. {qtype-0.1.0 → qtype-0.1.2}/qtype/semantic/visualize.py +0 -0
  140. {qtype-0.1.0 → qtype-0.1.2}/qtype.egg-info/dependency_links.txt +0 -0
  141. {qtype-0.1.0 → qtype-0.1.2}/qtype.egg-info/entry_points.txt +0 -0
  142. {qtype-0.1.0 → qtype-0.1.2}/qtype.egg-info/top_level.txt +0 -0
  143. {qtype-0.1.0 → qtype-0.1.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qtype
3
- Version: 0.1.0
3
+ Version: 0.1.2
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
@@ -23,16 +23,26 @@ Provides-Extra: interpreter
23
23
  Requires-Dist: aiostream>=0.7.1; extra == "interpreter"
24
24
  Requires-Dist: arize-phoenix-otel>=0.12.1; extra == "interpreter"
25
25
  Requires-Dist: boto3>=1.34.0; extra == "interpreter"
26
+ Requires-Dist: datasets>=4.4.1; extra == "interpreter"
27
+ Requires-Dist: diskcache>=5.6.3; extra == "interpreter"
26
28
  Requires-Dist: docling>=2.55.1; extra == "interpreter"
27
- Requires-Dist: diskcache[interpreter]>=5.6.3; extra == "interpreter"
29
+ Requires-Dist: docx2txt>=0.9; extra == "interpreter"
28
30
  Requires-Dist: fastapi>=0.116.1; extra == "interpreter"
31
+ Requires-Dist: jsonpath-ng>=1.7.0; extra == "interpreter"
32
+ Requires-Dist: langfuse>=3.9.0; extra == "interpreter"
29
33
  Requires-Dist: llama-index-embeddings-bedrock>=0.5.2; extra == "interpreter"
30
34
  Requires-Dist: llama-index-embeddings-openai>=0.3.1; extra == "interpreter"
31
35
  Requires-Dist: llama-index-llms-bedrock-converse>=0.10.5; extra == "interpreter"
32
36
  Requires-Dist: llama-index-llms-bedrock>=0.3.8; extra == "interpreter"
37
+ Requires-Dist: llama-index-llms-vertex>=0.6.1; extra == "interpreter"
38
+ Requires-Dist: llama-index-postprocessor-bedrock-rerank>=0.5.1; extra == "interpreter"
39
+ Requires-Dist: llama-index-readers-huggingface-fs>=0.4.1; extra == "interpreter"
40
+ Requires-Dist: llama-index-vector-stores-qdrant>=0.8.6; extra == "interpreter"
33
41
  Requires-Dist: llama-index>=0.12.45; extra == "interpreter"
34
42
  Requires-Dist: openinference-instrumentation-llama-index>=4.3.4; extra == "interpreter"
35
43
  Requires-Dist: opensearch-py>=2.7.0; extra == "interpreter"
44
+ Requires-Dist: opentelemetry-exporter-otlp>=1.35.0; extra == "interpreter"
45
+ Requires-Dist: opentelemetry-sdk>=1.35.0; extra == "interpreter"
36
46
  Requires-Dist: pandas>=2.2.3; extra == "interpreter"
37
47
  Requires-Dist: psycopg2-binary>=2.9.10; extra == "interpreter"
38
48
  Requires-Dist: pyarrow>=21.0.0; extra == "interpreter"
@@ -41,15 +51,6 @@ Requires-Dist: python-magic>=0.4.27; extra == "interpreter"
41
51
  Requires-Dist: s3fs>=2025.7.0; extra == "interpreter"
42
52
  Requires-Dist: sqlalchemy>=2.0.42; extra == "interpreter"
43
53
  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"
53
54
  Dynamic: license-file
54
55
 
55
56
  # QType
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "qtype"
3
- version = "0.1.0"
3
+ version = "0.1.2"
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"
@@ -29,16 +29,26 @@ interpreter = [
29
29
  "aiostream>=0.7.1",
30
30
  "arize-phoenix-otel>=0.12.1",
31
31
  "boto3>=1.34.0",
32
+ "datasets>=4.4.1",
33
+ "diskcache>=5.6.3",
32
34
  "docling>=2.55.1",
33
- "diskcache[interpreter]>=5.6.3",
35
+ "docx2txt>=0.9",
34
36
  "fastapi>=0.116.1",
37
+ "jsonpath-ng>=1.7.0",
38
+ "langfuse>=3.9.0",
35
39
  "llama-index-embeddings-bedrock>=0.5.2",
36
40
  "llama-index-embeddings-openai>=0.3.1",
37
41
  "llama-index-llms-bedrock-converse>=0.10.5",
38
42
  "llama-index-llms-bedrock>=0.3.8",
43
+ "llama-index-llms-vertex>=0.6.1",
44
+ "llama-index-postprocessor-bedrock-rerank>=0.5.1",
45
+ "llama-index-readers-huggingface-fs>=0.4.1",
46
+ "llama-index-vector-stores-qdrant>=0.8.6",
39
47
  "llama-index>=0.12.45",
40
48
  "openinference-instrumentation-llama-index>=4.3.4",
41
49
  "opensearch-py>=2.7.0",
50
+ "opentelemetry-exporter-otlp>=1.35.0",
51
+ "opentelemetry-sdk>=1.35.0",
42
52
  "pandas>=2.2.3",
43
53
  "psycopg2-binary>=2.9.10",
44
54
  "pyarrow>=21.0.0",
@@ -47,15 +57,6 @@ interpreter = [
47
57
  "s3fs>=2025.7.0",
48
58
  "sqlalchemy>=2.0.42",
49
59
  "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",
59
60
  ]
60
61
 
61
62
  [dependency-groups]
@@ -2,10 +2,10 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import logging
5
6
  from pathlib import Path
6
7
  from typing import Any
7
8
 
8
- from qtype.base.logging import get_logger
9
9
  from qtype.base.types import PathLike
10
10
  from qtype.semantic.model import Application as SemanticApplication
11
11
  from qtype.semantic.model import DocumentType as SemanticDocumentType
@@ -14,7 +14,7 @@ from qtype.semantic.model import DocumentType as SemanticDocumentType
14
14
  # That's the whole point of this facade - to avoid importing optional
15
15
  # dependencies unless these methods are called.
16
16
 
17
- logger = get_logger("application.facade")
17
+ logger = logging.getLogger(__name__)
18
18
 
19
19
 
20
20
  class QTypeFacade:
@@ -27,13 +27,13 @@ class QTypeFacade:
27
27
  """
28
28
 
29
29
  def telemetry(self, spec: SemanticDocumentType) -> None:
30
+ from qtype.interpreter.telemetry import register
31
+
30
32
  if isinstance(spec, SemanticApplication) and spec.telemetry:
31
33
  logger.info(
32
34
  f"Telemetry enabled with endpoint: {spec.telemetry.endpoint}"
33
35
  )
34
36
  # Register telemetry if needed
35
- from qtype.interpreter.telemetry import register
36
-
37
37
  register(spec.telemetry, self.secret_manager(spec), spec.id)
38
38
 
39
39
  def secret_manager(self, spec: SemanticDocumentType):
@@ -75,11 +75,17 @@ class QTypeFacade:
75
75
  DataFrame with results (one row per input)
76
76
  """
77
77
  import pandas as pd
78
+ from opentelemetry import trace
78
79
 
80
+ from qtype.interpreter.base.executor_context import ExecutorContext
81
+ from qtype.interpreter.converters import (
82
+ dataframe_to_flow_messages,
83
+ flow_messages_to_dataframe,
84
+ )
85
+ from qtype.interpreter.flow import run_flow
86
+ from qtype.interpreter.types import Session
79
87
  from qtype.semantic.loader import load
80
88
 
81
- logger.info(f"Executing workflow from {path}")
82
-
83
89
  # Load the semantic application
84
90
  semantic_model, type_registry = load(Path(path))
85
91
  assert isinstance(semantic_model, SemanticApplication)
@@ -100,7 +106,10 @@ class QTypeFacade:
100
106
  else:
101
107
  raise ValueError("No flows found in application")
102
108
 
109
+ logger.info(f"Executing flow {target_flow.id} from {path}")
110
+
103
111
  # Convert inputs to DataFrame (normalize single dict to 1-row DataFrame)
112
+
104
113
  if isinstance(inputs, dict):
105
114
  input_df = pd.DataFrame([inputs])
106
115
  elif isinstance(inputs, pd.DataFrame):
@@ -111,12 +120,6 @@ class QTypeFacade:
111
120
  )
112
121
 
113
122
  # 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
123
  session = Session(
121
124
  session_id=kwargs.pop("session_id", "default"),
122
125
  conversation_history=kwargs.pop("conversation_history", []),
@@ -126,12 +129,8 @@ class QTypeFacade:
126
129
  initial_messages = dataframe_to_flow_messages(input_df, session)
127
130
 
128
131
  # 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
132
  secret_manager = self.secret_manager(semantic_model)
133
+
135
134
  context = ExecutorContext(
136
135
  secret_manager=secret_manager,
137
136
  tracer=trace.get_tracer(__name__),
@@ -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:
@@ -131,7 +135,7 @@ def main() -> None:
131
135
  # Set logging level based on user input
132
136
  logging.basicConfig(
133
137
  level=getattr(logging, args.log_level),
134
- format="%(levelname)s: %(message)s",
138
+ format="%(asctime)s - %(levelname)s: %(message)s",
135
139
  )
136
140
 
137
141
  # Dispatch to the selected subcommand
@@ -188,7 +188,7 @@ def parser(subparsers: argparse._SubParsersAction) -> None:
188
188
 
189
189
  has_semantic_deps = True
190
190
  except ImportError:
191
- logger.warning(
191
+ logger.debug(
192
192
  "NetworkX or Ruff is not installed. Skipping semantic model generation."
193
193
  )
194
194
  has_semantic_deps = False
@@ -7,10 +7,12 @@ from __future__ import annotations
7
7
  import argparse
8
8
  import json
9
9
  import logging
10
+ import warnings
10
11
  from pathlib import Path
11
12
  from typing import Any
12
13
 
13
14
  import pandas as pd
15
+ from pydantic.warnings import UnsupportedFieldAttributeWarning
14
16
 
15
17
  from qtype.application.facade import QTypeFacade
16
18
  from qtype.base.exceptions import InterpreterError, LoadError, ValidationError
@@ -18,6 +20,15 @@ from qtype.base.exceptions import InterpreterError, LoadError, ValidationError
18
20
  logger = logging.getLogger(__name__)
19
21
 
20
22
 
23
+ # Supress specific pydantic warnings that llamaindex needs to fix
24
+ warnings.filterwarnings("ignore", category=UnsupportedFieldAttributeWarning)
25
+
26
+
27
+ # supress qdrant logging
28
+ for name in ["httpx", "urllib3", "qdrant_client", "opensearch"]:
29
+ logging.getLogger(name).setLevel(logging.WARNING)
30
+
31
+
21
32
  def read_data_from_file(file_path: str) -> pd.DataFrame:
22
33
  """
23
34
  Reads a file into a pandas DataFrame based on its MIME type.
@@ -29,12 +40,16 @@ def read_data_from_file(file_path: str) -> pd.DataFrame:
29
40
  mime_type = magic.Magic(mime=True).from_file(file_path)
30
41
 
31
42
  if mime_type == "text/csv":
32
- return pd.read_csv(file_path)
43
+ # TODO: Restore na values and convert to optional once we support them https://github.com/bazaarvoice/qtype/issues/101
44
+ df = pd.read_csv(file_path)
45
+ return df.fillna("")
33
46
  elif mime_type == "text/plain":
34
47
  # For text/plain, use file extension to determine format
35
48
  file_ext = Path(file_path).suffix.lower()
36
49
  if file_ext == ".csv":
37
- return pd.read_csv(file_path)
50
+ # TODO: Restore na values and convert to optional once we support them https://github.com/bazaarvoice/qtype/issues/101
51
+ df = pd.read_csv(file_path)
52
+ return df.fillna("")
38
53
  elif file_ext == ".json":
39
54
  return pd.read_json(file_path)
40
55
  else:
@@ -87,7 +102,10 @@ def run_flow(args: Any) -> None:
87
102
  # Execute the workflow using the facade (now async, returns DataFrame)
88
103
  result_df = asyncio.run(
89
104
  facade.execute_workflow(
90
- spec_path, flow_name=args.flow, inputs=input
105
+ spec_path,
106
+ flow_name=args.flow,
107
+ inputs=input,
108
+ show_progress=args.progress,
91
109
  )
92
110
  )
93
111
 
@@ -95,7 +113,7 @@ def run_flow(args: Any) -> None:
95
113
 
96
114
  # Display results
97
115
  if len(result_df) > 0:
98
- logger.info(f"Processed {len(result_df)} input(s)")
116
+ logger.info(f"Processed {len(result_df)} em")
99
117
 
100
118
  # Remove 'row' and 'error' columns for display if all errors are None
101
119
  display_df = result_df.copy()
@@ -108,7 +126,7 @@ def run_flow(args: Any) -> None:
108
126
  display_df = display_df.drop(columns=["row"])
109
127
 
110
128
  if len(display_df) > 1:
111
- logger.info(f"\nResults:\n{display_df.to_string()}")
129
+ logger.info(f"\nResults:\n{display_df[0:10].to_string()}\n...")
112
130
  else:
113
131
  # Print the first row with column_name: value one per line
114
132
  fmt_str = []
@@ -172,6 +190,11 @@ def parser(subparsers: argparse._SubParsersAction) -> None:
172
190
  default=None,
173
191
  help="Path to save output data. If input is a DataFrame, output will be saved as parquet. If single result, saved as JSON.",
174
192
  )
193
+ cmd_parser.add_argument(
194
+ "--progress",
195
+ action="store_true",
196
+ help="Show progress bars during flow execution.",
197
+ )
175
198
 
176
199
  cmd_parser.add_argument(
177
200
  "spec", type=str, help="Path to the QType YAML spec file."
@@ -93,12 +93,33 @@ class RAGChunk(Embedding):
93
93
  )
94
94
 
95
95
 
96
- class RAGSearchResult(StrictBaseModel):
97
- """A standard, built-in representation of a search result from a RAG vector search."""
96
+ class SearchResult(StrictBaseModel):
97
+ """A standard, built-in representation of a search result."""
98
98
 
99
- chunk: RAGChunk = Field(
99
+ content: Any = Field(..., description="The content of the search result.")
100
+ doc_id: str = Field(
101
+ ...,
102
+ description="The identifier of the document from which the result was retrieved.",
103
+ )
104
+ score: float = Field(
105
+ ...,
106
+ description="The relevance score of the search result with respect to the query.",
107
+ )
108
+
109
+
110
+ class RAGSearchResult(SearchResult):
111
+ """A standard, built-in representation of a search result from a RAG vector search.
112
+
113
+ Note: doc_id is duplicated from content.document_id for convenience.
114
+ """
115
+
116
+ content: RAGChunk = Field(
100
117
  ..., description="The RAG chunk returned as a search result."
101
118
  )
119
+ doc_id: str = Field(
120
+ ...,
121
+ description="The document ID (duplicated from content.document_id).",
122
+ )
102
123
  score: float = Field(
103
124
  ...,
104
125
  description="The similarity score of the chunk with respect to the query.",
@@ -573,6 +573,10 @@ class FieldExtractor(Step):
573
573
  ...,
574
574
  description="JSONPath expression to extract data from the input. Uses jsonpath-ng syntax.",
575
575
  )
576
+ fail_on_missing: bool = Field(
577
+ default=True,
578
+ description="Whether to raise an error if the JSONPath matches no data. If False, returns None.",
579
+ )
576
580
 
577
581
 
578
582
  class InvokeTool(Step, ConcurrentStepMixin):
@@ -1077,6 +1081,14 @@ class DocumentIndex(Index):
1077
1081
  ...,
1078
1082
  description="URL endpoint for the search cluster (e.g., https://my-cluster.es.amazonaws.com).",
1079
1083
  )
1084
+ id_field: str | None = Field(
1085
+ default=None,
1086
+ description=(
1087
+ "Field name to use as document ID. "
1088
+ "If not specified, auto-detects from: _id, id, doc_id, document_id, or uuid. "
1089
+ "If all are missing, a UUID is generated."
1090
+ ),
1091
+ )
1080
1092
 
1081
1093
 
1082
1094
  class Search(Step, ABC):
@@ -1089,15 +1101,18 @@ class Search(Step, ABC):
1089
1101
  index: Reference[IndexType] | str = Field(
1090
1102
  ..., description="Index to search against (object or ID reference)."
1091
1103
  )
1104
+ default_top_k: int | None = Field(
1105
+ default=10,
1106
+ description="Number of top results to retrieve if not provided in the inputs.",
1107
+ )
1092
1108
 
1093
1109
 
1094
1110
  class VectorSearch(Search, BatchableStepMixin):
1095
1111
  """Performs vector similarity search against a vector index."""
1096
1112
 
1097
1113
  type: Literal["VectorSearch"] = "VectorSearch"
1098
- default_top_k: int | None = Field(
1099
- default=50,
1100
- description="Number of top results to retrieve if not provided in the inputs.",
1114
+ index: Reference[VectorIndex] | str = Field(
1115
+ ..., description="Index to search against (object or ID reference)."
1101
1116
  )
1102
1117
 
1103
1118
 
@@ -1105,6 +1120,43 @@ class DocumentSearch(Search, ConcurrentStepMixin):
1105
1120
  """Performs document search against a document index."""
1106
1121
 
1107
1122
  type: Literal["DocumentSearch"] = "DocumentSearch"
1123
+ index: Reference[DocumentIndex] | str = Field(
1124
+ ..., description="Index to search against (object or ID reference)."
1125
+ )
1126
+ query_args: dict[str, Any] = Field(
1127
+ default={
1128
+ "type": "best_fields",
1129
+ "fields": ["*"],
1130
+ },
1131
+ description="The arguments (other than 'query') to specify to the query shape (see https://docs.opensearch.org/latest/query-dsl/full-text/multi-match/).",
1132
+ )
1133
+
1134
+
1135
+ class Reranker(Step):
1136
+ """Reranks a list of documents based on relevance to a query using an LLM."""
1137
+
1138
+ type: Literal["Reranker"] = "Reranker"
1139
+
1140
+
1141
+ # TODO: create a reranker that supports llamaindex rerankers...
1142
+
1143
+
1144
+ class BedrockReranker(Reranker, ConcurrentStepMixin):
1145
+ """Reranks documents using an AWS Bedrock model."""
1146
+
1147
+ type: Literal["BedrockReranker"] = "BedrockReranker"
1148
+ auth: Reference[AWSAuthProvider] | str | None = Field(
1149
+ default=None,
1150
+ description="AWS authorization provider for Bedrock access.",
1151
+ )
1152
+ model_id: str = Field(
1153
+ ...,
1154
+ description="Bedrock model ID to use for reranking. See https://docs.aws.amazon.com/bedrock/latest/userguide/rerank-supported.html",
1155
+ )
1156
+ num_results: int | None = Field(
1157
+ default=None,
1158
+ description="Return this many results.",
1159
+ )
1108
1160
 
1109
1161
 
1110
1162
  # Create a union type for all tool types
@@ -1146,6 +1198,7 @@ StepType = Annotated[
1146
1198
  Union[
1147
1199
  Agent,
1148
1200
  Aggregate,
1201
+ BedrockReranker,
1149
1202
  Decoder,
1150
1203
  DocToTextConverter,
1151
1204
  DocumentEmbedder,
@@ -212,7 +212,6 @@ class StepExecutor(ABC):
212
212
  num_workers = (
213
213
  self.step.concurrency_config.num_workers # type: ignore[attr-defined]
214
214
  )
215
-
216
215
  span.set_attribute("step.concurrency", num_workers)
217
216
 
218
217
  # Prepare messages for processing (batching hook)
@@ -331,6 +330,11 @@ class StepExecutor(ABC):
331
330
  cached_result = self.cache.get(key)
332
331
  if cached_result is not None:
333
332
  result = [from_cache_value(d, message) for d in cached_result] # type: ignore
333
+ self.progress.increment_cache(
334
+ self.context.on_progress,
335
+ hit_delta=len(result),
336
+ miss_delta=0,
337
+ )
334
338
  # cache hit
335
339
  for msg in result:
336
340
  yield msg
@@ -341,6 +345,9 @@ class StepExecutor(ABC):
341
345
  buf.append(output_msg)
342
346
  yield output_msg
343
347
 
348
+ self.progress.increment_cache(
349
+ self.context.on_progress, hit_delta=0, miss_delta=len(buf)
350
+ )
344
351
  # store the results in the cache of there are no errors or if instructed to do so
345
352
  if (
346
353
  all(not msg.is_failed() for msg in buf)
@@ -7,7 +7,8 @@ concerns threaded through the execution pipeline.
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
- from dataclasses import dataclass
10
+ from concurrent.futures import ThreadPoolExecutor
11
+ from dataclasses import dataclass, field
11
12
 
12
13
  from opentelemetry.trace import Tracer
13
14
 
@@ -51,6 +52,9 @@ class ExecutorContext:
51
52
  on_progress: Optional callback for progress updates during execution.
52
53
  tracer: OpenTelemetry tracer for distributed tracing and observability.
53
54
  Defaults to a no-op tracer if telemetry is not configured.
55
+ thread_pool: Shared thread pool for running synchronous operations
56
+ in async contexts. Defaults to a pool with 100 threads to support
57
+ high concurrency workloads without thread exhaustion.
54
58
 
55
59
  Example:
56
60
  ```python
@@ -72,3 +76,16 @@ class ExecutorContext:
72
76
  on_stream_event: StreamingCallback | None = None
73
77
  on_progress: ProgressCallback | None = None
74
78
  tracer: Tracer | None = None
79
+ thread_pool: ThreadPoolExecutor = field(
80
+ default_factory=lambda: ThreadPoolExecutor(max_workers=100)
81
+ )
82
+
83
+ def cleanup(self) -> None:
84
+ """
85
+ Clean up resources held by the context.
86
+
87
+ This should be called when the context is no longer needed to ensure
88
+ proper cleanup of the thread pool and any other resources.
89
+ """
90
+ if self.thread_pool:
91
+ self.thread_pool.shutdown(wait=True)
@@ -0,0 +1,84 @@
1
+ from qtype.semantic.model import (
2
+ Agent,
3
+ Aggregate,
4
+ BedrockReranker,
5
+ Decoder,
6
+ DocToTextConverter,
7
+ DocumentEmbedder,
8
+ DocumentSearch,
9
+ DocumentSource,
10
+ DocumentSplitter,
11
+ Echo,
12
+ FieldExtractor,
13
+ FileSource,
14
+ FileWriter,
15
+ IndexUpsert,
16
+ InvokeEmbedding,
17
+ InvokeFlow,
18
+ InvokeTool,
19
+ LLMInference,
20
+ PromptTemplate,
21
+ SQLSource,
22
+ Step,
23
+ VectorSearch,
24
+ )
25
+
26
+ from .batch_step_executor import StepExecutor
27
+ from .executor_context import ExecutorContext
28
+
29
+ # Lazy-load executor classes only when needed
30
+ # This avoids importing heavy dependencies until actually required
31
+ EXECUTOR_REGISTRY = {
32
+ Agent: "qtype.interpreter.executors.agent_executor.AgentExecutor",
33
+ Aggregate: "qtype.interpreter.executors.aggregate_executor.AggregateExecutor",
34
+ BedrockReranker: "qtype.interpreter.executors.bedrock_reranker_executor.BedrockRerankerExecutor",
35
+ Decoder: "qtype.interpreter.executors.decoder_executor.DecoderExecutor",
36
+ DocToTextConverter: "qtype.interpreter.executors.doc_to_text_executor.DocToTextConverterExecutor",
37
+ DocumentEmbedder: "qtype.interpreter.executors.document_embedder_executor.DocumentEmbedderExecutor",
38
+ DocumentSearch: "qtype.interpreter.executors.document_search_executor.DocumentSearchExecutor",
39
+ DocumentSource: "qtype.interpreter.executors.document_source_executor.DocumentSourceExecutor",
40
+ DocumentSplitter: "qtype.interpreter.executors.document_splitter_executor.DocumentSplitterExecutor",
41
+ Echo: "qtype.interpreter.executors.echo_executor.EchoExecutor",
42
+ FieldExtractor: "qtype.interpreter.executors.field_extractor_executor.FieldExtractorExecutor",
43
+ FileSource: "qtype.interpreter.executors.file_source_executor.FileSourceExecutor",
44
+ FileWriter: "qtype.interpreter.executors.file_writer_executor.FileWriterExecutor",
45
+ IndexUpsert: "qtype.interpreter.executors.index_upsert_executor.IndexUpsertExecutor",
46
+ InvokeEmbedding: "qtype.interpreter.executors.invoke_embedding_executor.InvokeEmbeddingExecutor",
47
+ InvokeFlow: "qtype.interpreter.executors.invoke_flow_executor.InvokeFlowExecutor",
48
+ InvokeTool: "qtype.interpreter.executors.invoke_tool_executor.InvokeToolExecutor",
49
+ LLMInference: "qtype.interpreter.executors.llm_inference_executor.LLMInferenceExecutor",
50
+ PromptTemplate: "qtype.interpreter.executors.prompt_template_executor.PromptTemplateExecutor",
51
+ SQLSource: "qtype.interpreter.executors.sql_source_executor.SQLSourceExecutor",
52
+ VectorSearch: "qtype.interpreter.executors.vector_search_executor.VectorSearchExecutor",
53
+ }
54
+
55
+
56
+ def create_executor(
57
+ step: Step, context: ExecutorContext, **dependencies
58
+ ) -> StepExecutor:
59
+ """
60
+ Factory to create the appropriate executor for a given step.
61
+
62
+ Args:
63
+ step: The step to create an executor for
64
+ context: ExecutorContext containing cross-cutting concerns
65
+ **dependencies: Executor-specific dependencies
66
+
67
+ Returns:
68
+ StepExecutor: Configured executor instance
69
+ """
70
+ executor_path = EXECUTOR_REGISTRY.get(type(step))
71
+ if not executor_path:
72
+ raise ValueError(
73
+ f"No executor found for step type: {type(step).__name__}"
74
+ )
75
+
76
+ # Lazy-load the executor class
77
+ module_path, class_name = executor_path.rsplit(".", 1)
78
+ import importlib
79
+
80
+ module = importlib.import_module(module_path)
81
+ executor_class = getattr(module, class_name)
82
+
83
+ # This assumes the constructor takes the step, context, then dependencies
84
+ return executor_class(step, context, **dependencies)
@@ -20,6 +20,8 @@ class ProgressTracker:
20
20
  self.items_processed = 0
21
21
  self.items_in_error = 0
22
22
  self.total_items = total_items
23
+ self.cache_hits = None
24
+ self.cache_misses = None
23
25
 
24
26
  @property
25
27
  def items_succeeded(self) -> int:
@@ -36,6 +38,8 @@ class ProgressTracker:
36
38
  on_progress: ProgressCallback | None,
37
39
  processed_delta: int,
38
40
  error_delta: int,
41
+ hit_delta: int | None = None,
42
+ miss_delta: int | None = None,
39
43
  ) -> None:
40
44
  """
41
45
  Update progress counters and invoke the progress callback.
@@ -51,6 +55,19 @@ class ProgressTracker:
51
55
  self.items_processed += processed_delta
52
56
  self.items_in_error += error_delta
53
57
 
58
+ if hit_delta is not None:
59
+ self.cache_hits = (
60
+ self.cache_hits + hit_delta
61
+ if self.cache_hits is not None
62
+ else hit_delta
63
+ )
64
+ if miss_delta is not None:
65
+ self.cache_misses = (
66
+ self.cache_misses + miss_delta
67
+ if self.cache_misses is not None
68
+ else miss_delta
69
+ )
70
+
54
71
  if on_progress:
55
72
  on_progress(
56
73
  self.step_id,
@@ -58,6 +75,8 @@ class ProgressTracker:
58
75
  self.items_in_error,
59
76
  self.items_succeeded,
60
77
  self.total_items,
78
+ self.cache_hits,
79
+ self.cache_misses,
61
80
  )
62
81
 
63
82
  def update_for_message(
@@ -73,3 +92,19 @@ class ProgressTracker:
73
92
  on_progress: Optional callback to notify of progress updates
74
93
  """
75
94
  self.update(on_progress, 1, 1 if message.is_failed() else 0)
95
+
96
+ def increment_cache(
97
+ self,
98
+ on_progress: ProgressCallback | None,
99
+ hit_delta: int = 0,
100
+ miss_delta: int = 0,
101
+ ) -> None:
102
+ """
103
+ Increment cache hit/miss counters.
104
+
105
+ Args:
106
+ on_progress: Optional callback to notify of progress updates
107
+ hit_delta: Number of cache hits to add
108
+ miss_delta: Number of cache misses to add
109
+ """
110
+ self.update(on_progress, 0, 0, hit_delta, miss_delta)