qtype 0.1.1__tar.gz → 0.1.3__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 (144) hide show
  1. {qtype-0.1.1/qtype.egg-info → qtype-0.1.3}/PKG-INFO +12 -11
  2. {qtype-0.1.1 → qtype-0.1.3}/pyproject.toml +12 -11
  3. {qtype-0.1.1 → qtype-0.1.3}/qtype/application/facade.py +14 -15
  4. {qtype-0.1.1 → qtype-0.1.3}/qtype/cli.py +1 -1
  5. {qtype-0.1.1 → qtype-0.1.3}/qtype/commands/generate.py +1 -1
  6. {qtype-0.1.1 → qtype-0.1.3}/qtype/commands/run.py +7 -3
  7. {qtype-0.1.1 → qtype-0.1.3}/qtype/dsl/domain_types.py +24 -3
  8. {qtype-0.1.1 → qtype-0.1.3}/qtype/dsl/model.py +56 -3
  9. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/base/base_step_executor.py +1 -1
  10. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/base/executor_context.py +18 -1
  11. qtype-0.1.3/qtype/interpreter/base/factory.py +84 -0
  12. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/conversions.py +15 -6
  13. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/converters.py +14 -12
  14. qtype-0.1.3/qtype/interpreter/executors/bedrock_reranker_executor.py +195 -0
  15. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/executors/document_search_executor.py +37 -46
  16. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/executors/document_splitter_executor.py +1 -1
  17. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/executors/field_extractor_executor.py +10 -5
  18. qtype-0.1.3/qtype/interpreter/executors/index_upsert_executor.py +232 -0
  19. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/flow.py +47 -33
  20. qtype-0.1.3/qtype/interpreter/logging_progress.py +61 -0
  21. {qtype-0.1.1 → qtype-0.1.3}/qtype/semantic/checker.py +79 -19
  22. {qtype-0.1.1 → qtype-0.1.3}/qtype/semantic/model.py +43 -3
  23. {qtype-0.1.1 → qtype-0.1.3/qtype.egg-info}/PKG-INFO +12 -11
  24. {qtype-0.1.1 → qtype-0.1.3}/qtype.egg-info/SOURCES.txt +2 -0
  25. {qtype-0.1.1 → qtype-0.1.3}/qtype.egg-info/requires.txt +11 -10
  26. qtype-0.1.1/qtype/interpreter/base/factory.py +0 -117
  27. qtype-0.1.1/qtype/interpreter/executors/index_upsert_executor.py +0 -228
  28. {qtype-0.1.1 → qtype-0.1.3}/LICENSE +0 -0
  29. {qtype-0.1.1 → qtype-0.1.3}/README.md +0 -0
  30. {qtype-0.1.1 → qtype-0.1.3}/qtype/__init__.py +0 -0
  31. {qtype-0.1.1 → qtype-0.1.3}/qtype/application/__init__.py +0 -0
  32. {qtype-0.1.1 → qtype-0.1.3}/qtype/application/commons/__init__.py +0 -0
  33. {qtype-0.1.1 → qtype-0.1.3}/qtype/application/commons/tools.py +0 -0
  34. {qtype-0.1.1 → qtype-0.1.3}/qtype/application/converters/__init__.py +0 -0
  35. {qtype-0.1.1 → qtype-0.1.3}/qtype/application/converters/tools_from_api.py +0 -0
  36. {qtype-0.1.1 → qtype-0.1.3}/qtype/application/converters/tools_from_module.py +0 -0
  37. {qtype-0.1.1 → qtype-0.1.3}/qtype/application/converters/types.py +0 -0
  38. {qtype-0.1.1 → qtype-0.1.3}/qtype/application/documentation.py +0 -0
  39. {qtype-0.1.1 → qtype-0.1.3}/qtype/base/__init__.py +0 -0
  40. {qtype-0.1.1 → qtype-0.1.3}/qtype/base/exceptions.py +0 -0
  41. {qtype-0.1.1 → qtype-0.1.3}/qtype/base/logging.py +0 -0
  42. {qtype-0.1.1 → qtype-0.1.3}/qtype/base/types.py +0 -0
  43. {qtype-0.1.1 → qtype-0.1.3}/qtype/commands/__init__.py +0 -0
  44. {qtype-0.1.1 → qtype-0.1.3}/qtype/commands/convert.py +0 -0
  45. {qtype-0.1.1 → qtype-0.1.3}/qtype/commands/serve.py +0 -0
  46. {qtype-0.1.1 → qtype-0.1.3}/qtype/commands/validate.py +0 -0
  47. {qtype-0.1.1 → qtype-0.1.3}/qtype/commands/visualize.py +0 -0
  48. {qtype-0.1.1 → qtype-0.1.3}/qtype/dsl/__init__.py +0 -0
  49. {qtype-0.1.1 → qtype-0.1.3}/qtype/dsl/custom_types.py +0 -0
  50. {qtype-0.1.1 → qtype-0.1.3}/qtype/dsl/linker.py +0 -0
  51. {qtype-0.1.1 → qtype-0.1.3}/qtype/dsl/loader.py +0 -0
  52. {qtype-0.1.1 → qtype-0.1.3}/qtype/dsl/parser.py +0 -0
  53. {qtype-0.1.1 → qtype-0.1.3}/qtype/dsl/types.py +0 -0
  54. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/__init__.py +0 -0
  55. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/api.py +0 -0
  56. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/auth/__init__.py +0 -0
  57. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/auth/aws.py +0 -0
  58. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/auth/cache.py +0 -0
  59. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/auth/generic.py +0 -0
  60. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/base/batch_step_executor.py +0 -0
  61. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/base/exceptions.py +0 -0
  62. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/base/progress_tracker.py +0 -0
  63. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/base/secrets.py +0 -0
  64. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/base/step_cache.py +0 -0
  65. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/base/stream_emitter.py +0 -0
  66. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/endpoints.py +0 -0
  67. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/executors/agent_executor.py +0 -0
  68. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/executors/aggregate_executor.py +0 -0
  69. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/executors/decoder_executor.py +0 -0
  70. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/executors/doc_to_text_executor.py +0 -0
  71. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/executors/document_embedder_executor.py +0 -0
  72. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/executors/document_source_executor.py +0 -0
  73. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/executors/echo_executor.py +0 -0
  74. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/executors/file_source_executor.py +0 -0
  75. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/executors/file_writer_executor.py +0 -0
  76. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/executors/invoke_embedding_executor.py +0 -0
  77. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/executors/invoke_flow_executor.py +0 -0
  78. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/executors/invoke_tool_executor.py +0 -0
  79. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/executors/llm_inference_executor.py +0 -0
  80. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/executors/prompt_template_executor.py +0 -0
  81. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/executors/sql_source_executor.py +0 -0
  82. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/executors/vector_search_executor.py +0 -0
  83. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/metadata_api.py +0 -0
  84. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/resource_cache.py +0 -0
  85. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/rich_progress.py +0 -0
  86. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/stream/chat/__init__.py +0 -0
  87. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/stream/chat/converter.py +0 -0
  88. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/stream/chat/file_conversions.py +0 -0
  89. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/stream/chat/ui_request_to_domain_type.py +0 -0
  90. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/stream/chat/vercel.py +0 -0
  91. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/stream/utils/__init__.py +0 -0
  92. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/stream/utils/build_vercel_ai_formatter.py +0 -0
  93. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/stream/utils/callback_to_stream.py +0 -0
  94. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/stream/utils/create_streaming_response.py +0 -0
  95. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/stream/utils/default_chat_extract_text.py +0 -0
  96. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/stream/utils/error_streaming_response.py +0 -0
  97. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/telemetry.py +0 -0
  98. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/tools/__init__.py +0 -0
  99. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/tools/function_tool_helper.py +0 -0
  100. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/types.py +0 -0
  101. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/typing.py +0 -0
  102. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/404/index.html +0 -0
  103. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/404.html +0 -0
  104. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/20HoJN6otZ_LyHLHpCPE6/_buildManifest.js +0 -0
  105. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/20HoJN6otZ_LyHLHpCPE6/_ssgManifest.js +0 -0
  106. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/chunks/434-b2112d19f25c44ff.js +0 -0
  107. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/chunks/4bd1b696-cf72ae8a39fa05aa.js +0 -0
  108. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/chunks/964-2b041321a01cbf56.js +0 -0
  109. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/chunks/app/_not-found/page-e110d2a9d0a83d82.js +0 -0
  110. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/chunks/app/layout-a05273ead5de2c41.js +0 -0
  111. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/chunks/app/page-8c67d16ac90d23cb.js +0 -0
  112. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/chunks/ba12c10f-546f2714ff8abc66.js +0 -0
  113. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/chunks/framework-7c95b8e5103c9e90.js +0 -0
  114. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/chunks/main-app-6fc6346bc8f7f163.js +0 -0
  115. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/chunks/main-e26b9cb206da2cac.js +0 -0
  116. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/chunks/pages/_app-0a0020ddd67f79cf.js +0 -0
  117. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/chunks/pages/_error-03529f2c21436739.js +0 -0
  118. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -0
  119. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/chunks/webpack-08642e441b39b6c2.js +0 -0
  120. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/css/8a8d1269e362fef7.css +0 -0
  121. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  122. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/media/747892c23ea88013-s.woff2 +0 -0
  123. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/media/8d697b304b401681-s.woff2 +0 -0
  124. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  125. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/media/9610d9e46709d722-s.woff2 +0 -0
  126. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/_next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  127. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/file.svg +0 -0
  128. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/globe.svg +0 -0
  129. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/icon.png +0 -0
  130. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/index.html +0 -0
  131. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/index.txt +0 -0
  132. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/next.svg +0 -0
  133. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/vercel.svg +0 -0
  134. {qtype-0.1.1 → qtype-0.1.3}/qtype/interpreter/ui/window.svg +0 -0
  135. {qtype-0.1.1 → qtype-0.1.3}/qtype/semantic/__init__.py +0 -0
  136. {qtype-0.1.1 → qtype-0.1.3}/qtype/semantic/base_types.py +0 -0
  137. {qtype-0.1.1 → qtype-0.1.3}/qtype/semantic/generate.py +0 -0
  138. {qtype-0.1.1 → qtype-0.1.3}/qtype/semantic/loader.py +0 -0
  139. {qtype-0.1.1 → qtype-0.1.3}/qtype/semantic/resolver.py +0 -0
  140. {qtype-0.1.1 → qtype-0.1.3}/qtype/semantic/visualize.py +0 -0
  141. {qtype-0.1.1 → qtype-0.1.3}/qtype.egg-info/dependency_links.txt +0 -0
  142. {qtype-0.1.1 → qtype-0.1.3}/qtype.egg-info/entry_points.txt +0 -0
  143. {qtype-0.1.1 → qtype-0.1.3}/qtype.egg-info/top_level.txt +0 -0
  144. {qtype-0.1.1 → qtype-0.1.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qtype
3
- Version: 0.1.1
3
+ Version: 0.1.3
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.1"
3
+ version = "0.1.3"
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]
@@ -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__),
@@ -135,7 +135,7 @@ def main() -> None:
135
135
  # Set logging level based on user input
136
136
  logging.basicConfig(
137
137
  level=getattr(logging, args.log_level),
138
- format="%(levelname)s: %(message)s",
138
+ format="%(asctime)s - %(levelname)s: %(message)s",
139
139
  )
140
140
 
141
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
@@ -25,7 +25,7 @@ warnings.filterwarnings("ignore", category=UnsupportedFieldAttributeWarning)
25
25
 
26
26
 
27
27
  # supress qdrant logging
28
- for name in ["httpx", "urllib3", "qdrant_client"]:
28
+ for name in ["httpx", "urllib3", "qdrant_client", "opensearch"]:
29
29
  logging.getLogger(name).setLevel(logging.WARNING)
30
30
 
31
31
 
@@ -40,12 +40,16 @@ def read_data_from_file(file_path: str) -> pd.DataFrame:
40
40
  mime_type = magic.Magic(mime=True).from_file(file_path)
41
41
 
42
42
  if mime_type == "text/csv":
43
- 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("")
44
46
  elif mime_type == "text/plain":
45
47
  # For text/plain, use file extension to determine format
46
48
  file_ext = Path(file_path).suffix.lower()
47
49
  if file_ext == ".csv":
48
- 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("")
49
53
  elif file_ext == ".json":
50
54
  return pd.read_json(file_path)
51
55
  else:
@@ -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,
@@ -241,7 +241,7 @@ class StepExecutor(ABC):
241
241
 
242
242
  # Track message counts for telemetry
243
243
  message_count = 0
244
- error_count = len(failed_messages)
244
+ error_count = 0
245
245
 
246
246
  # Stream results and track progress
247
247
  async with all_results.stream() as streamer:
@@ -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)
@@ -18,10 +18,15 @@ from llama_index.core.base.llms.types import (
18
18
  from llama_index.core.memory import Memory as LlamaMemory
19
19
  from llama_index.core.schema import Document as LlamaDocument
20
20
  from llama_index.core.vector_stores.types import BasePydanticVectorStore
21
- from opensearchpy import AWSV4SignerAuth, OpenSearch
21
+ from opensearchpy import AsyncOpenSearch, AWSV4SignerAuth
22
22
 
23
23
  from qtype.base.types import PrimitiveTypeEnum
24
- from qtype.dsl.domain_types import ChatContent, ChatMessage, RAGDocument
24
+ from qtype.dsl.domain_types import (
25
+ ChatContent,
26
+ ChatMessage,
27
+ RAGDocument,
28
+ RAGSearchResult,
29
+ )
25
30
  from qtype.dsl.model import Memory
26
31
  from qtype.interpreter.auth.aws import aws
27
32
  from qtype.interpreter.auth.generic import auth
@@ -328,7 +333,7 @@ def to_embedding_model(model: Model) -> BaseEmbedding:
328
333
  @cached_resource
329
334
  def to_opensearch_client(
330
335
  index: DocumentIndex, secret_manager: SecretManagerBase
331
- ) -> OpenSearch:
336
+ ) -> AsyncOpenSearch:
332
337
  """
333
338
  Convert a DocumentIndex to an OpenSearch/Elasticsearch client.
334
339
 
@@ -377,7 +382,7 @@ def to_opensearch_client(
377
382
  f"Unsupported authentication type for DocumentIndex: {type(index.auth)}"
378
383
  )
379
384
 
380
- return OpenSearch(**client_kwargs)
385
+ return AsyncOpenSearch(**client_kwargs)
381
386
 
382
387
 
383
388
  def to_content_block(content: ChatContent) -> ContentBlock:
@@ -575,7 +580,7 @@ def to_llama_vector_store_and_retriever(
575
580
  return vector_store, retriever
576
581
 
577
582
 
578
- def from_node_with_score(node_with_score) -> Any:
583
+ def from_node_with_score(node_with_score) -> RAGSearchResult:
579
584
  """Convert a LlamaIndex NodeWithScore to a RAGSearchResult.
580
585
 
581
586
  Args:
@@ -603,4 +608,8 @@ def from_node_with_score(node_with_score) -> Any:
603
608
  )
604
609
 
605
610
  # Wrap in RAGSearchResult with score
606
- return RAGSearchResult(chunk=chunk, score=node_with_score.score or 0.0)
611
+ return RAGSearchResult(
612
+ content=chunk,
613
+ doc_id=chunk.document_id,
614
+ score=node_with_score.score or 0.0,
615
+ )
@@ -2,6 +2,9 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from collections.abc import AsyncIterator
6
+ from typing import Any, cast
7
+
5
8
  import pandas as pd
6
9
  from pydantic import BaseModel
7
10
 
@@ -9,11 +12,11 @@ from qtype.interpreter.types import FlowMessage, Session
9
12
  from qtype.semantic.model import Flow
10
13
 
11
14
 
12
- def dataframe_to_flow_messages(
15
+ async def dataframe_to_flow_messages(
13
16
  df: pd.DataFrame, session: Session
14
- ) -> list[FlowMessage]:
17
+ ) -> AsyncIterator[FlowMessage]:
15
18
  """
16
- Convert a DataFrame to a list of FlowMessages.
19
+ Convert a DataFrame to an async generator of FlowMessages.
17
20
 
18
21
  Each row in the DataFrame becomes a FlowMessage with the same session.
19
22
 
@@ -21,14 +24,15 @@ def dataframe_to_flow_messages(
21
24
  df: DataFrame where each row represents one set of inputs
22
25
  session: Session object to use for all messages
23
26
 
24
- Returns:
25
- List of FlowMessages, one per DataFrame row
27
+ Yields:
28
+ FlowMessages, one per DataFrame row
26
29
  """
27
- messages = []
28
- for _, row in df.iterrows():
29
- variables = row.to_dict()
30
- messages.append(FlowMessage(session=session, variables=variables))
31
- return messages
30
+ # Use to_dict with orient='records' - much faster than iterrows
31
+ # This returns a list of dicts directly without Series overhead
32
+ records = cast(list[dict[str, Any]], df.to_dict(orient="records"))
33
+
34
+ for record in records:
35
+ yield FlowMessage(session=session, variables=record)
32
36
 
33
37
 
34
38
  def flow_messages_to_dataframe(
@@ -46,8 +50,6 @@ def flow_messages_to_dataframe(
46
50
  Returns:
47
51
  DataFrame with one row per message, columns for each output variable
48
52
  """
49
- from typing import Any
50
-
51
53
  results = []
52
54
  for idx, message in enumerate(messages):
53
55
  row_data: dict[str, Any] = {"row": idx}