qtype 0.0.10__tar.gz → 0.0.12__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 (134) hide show
  1. {qtype-0.0.10/qtype.egg-info → qtype-0.0.12}/PKG-INFO +5 -1
  2. {qtype-0.0.10 → qtype-0.0.12}/pyproject.toml +17 -6
  3. qtype-0.0.12/qtype/application/__init__.py +12 -0
  4. qtype-0.0.12/qtype/application/commons/__init__.py +7 -0
  5. {qtype-0.0.10/qtype → qtype-0.0.12/qtype/application}/converters/tools_from_module.py +2 -2
  6. qtype-0.0.12/qtype/application/converters/types.py +33 -0
  7. qtype-0.0.10/qtype/dsl/document.py → qtype-0.0.12/qtype/application/documentation.py +2 -0
  8. qtype-0.0.12/qtype/application/facade.py +160 -0
  9. qtype-0.0.12/qtype/base/__init__.py +14 -0
  10. qtype-0.0.12/qtype/base/exceptions.py +49 -0
  11. qtype-0.0.12/qtype/base/logging.py +39 -0
  12. qtype-0.0.12/qtype/base/types.py +29 -0
  13. qtype-0.0.12/qtype/commands/convert.py +104 -0
  14. {qtype-0.0.10 → qtype-0.0.12}/qtype/commands/generate.py +59 -4
  15. qtype-0.0.12/qtype/commands/run.py +160 -0
  16. qtype-0.0.12/qtype/commands/serve.py +87 -0
  17. qtype-0.0.12/qtype/commands/validate.py +76 -0
  18. qtype-0.0.12/qtype/commands/visualize.py +101 -0
  19. qtype-0.0.12/qtype/dsl/__init__.py +10 -0
  20. {qtype-0.0.10 → qtype-0.0.12}/qtype/dsl/base_types.py +8 -0
  21. {qtype-0.0.10 → qtype-0.0.12}/qtype/dsl/custom_types.py +6 -4
  22. {qtype-0.0.10 → qtype-0.0.12}/qtype/dsl/model.py +185 -50
  23. {qtype-0.0.10 → qtype-0.0.12}/qtype/dsl/validator.py +9 -4
  24. qtype-0.0.12/qtype/interpreter/api.py +196 -0
  25. qtype-0.0.12/qtype/interpreter/auth/__init__.py +3 -0
  26. qtype-0.0.12/qtype/interpreter/auth/aws.py +234 -0
  27. qtype-0.0.12/qtype/interpreter/auth/cache.py +67 -0
  28. qtype-0.0.12/qtype/interpreter/auth/generic.py +103 -0
  29. qtype-0.0.12/qtype/interpreter/batch/flow.py +95 -0
  30. qtype-0.0.12/qtype/interpreter/batch/sql_source.py +95 -0
  31. qtype-0.0.12/qtype/interpreter/batch/step.py +63 -0
  32. qtype-0.0.12/qtype/interpreter/batch/types.py +41 -0
  33. qtype-0.0.12/qtype/interpreter/batch/utils.py +179 -0
  34. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/conversions.py +21 -10
  35. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/resource_cache.py +4 -2
  36. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/steps/decoder.py +13 -9
  37. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/steps/llm_inference.py +7 -9
  38. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/steps/prompt_template.py +1 -1
  39. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/streaming_helpers.py +3 -3
  40. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/typing.py +47 -11
  41. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/404/index.html +1 -1
  42. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/404.html +1 -1
  43. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/index.html +1 -1
  44. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/index.txt +1 -1
  45. {qtype-0.0.10 → qtype-0.0.12}/qtype/loader.py +15 -16
  46. {qtype-0.0.10 → qtype-0.0.12}/qtype/semantic/generate.py +91 -39
  47. {qtype-0.0.10 → qtype-0.0.12}/qtype/semantic/model.py +183 -52
  48. {qtype-0.0.10 → qtype-0.0.12}/qtype/semantic/resolver.py +4 -4
  49. {qtype-0.0.10 → qtype-0.0.12/qtype.egg-info}/PKG-INFO +5 -1
  50. {qtype-0.0.10 → qtype-0.0.12}/qtype.egg-info/SOURCES.txt +36 -12
  51. {qtype-0.0.10 → qtype-0.0.12}/qtype.egg-info/requires.txt +4 -0
  52. qtype-0.0.12/tests/test_auth_cache.py +190 -0
  53. qtype-0.0.12/tests/test_aws_auth.py +401 -0
  54. qtype-0.0.12/tests/test_batch_flow.py +311 -0
  55. qtype-0.0.12/tests/test_batch_step.py +127 -0
  56. qtype-0.0.12/tests/test_batch_utils.py +254 -0
  57. qtype-0.0.12/tests/test_documentation.py +36 -0
  58. {qtype-0.0.10 → qtype-0.0.12}/tests/test_dsl_validation.py +3 -3
  59. qtype-0.0.12/tests/test_generic_auth.py +95 -0
  60. qtype-0.0.12/tests/test_semantic_generator.py +73 -0
  61. {qtype-0.0.10 → qtype-0.0.12}/tests/test_semantic_resolver.py +14 -16
  62. qtype-0.0.12/tests/test_sql_source.py +243 -0
  63. {qtype-0.0.10 → qtype-0.0.12}/tests/test_tools_from_module.py +1 -1
  64. qtype-0.0.12/tests/test_visualize.py +51 -0
  65. qtype-0.0.10/qtype/commands/convert.py +0 -89
  66. qtype-0.0.10/qtype/commands/run.py +0 -123
  67. qtype-0.0.10/qtype/commands/serve.py +0 -73
  68. qtype-0.0.10/qtype/commands/validate.py +0 -93
  69. qtype-0.0.10/qtype/commands/visualize.py +0 -87
  70. qtype-0.0.10/qtype/commons/generate.py +0 -93
  71. qtype-0.0.10/qtype/converters/types.py +0 -66
  72. qtype-0.0.10/qtype/dsl/__init__.py +0 -1
  73. qtype-0.0.10/qtype/interpreter/api.py +0 -140
  74. qtype-0.0.10/qtype/semantic/errors.py +0 -4
  75. {qtype-0.0.10 → qtype-0.0.12}/LICENSE +0 -0
  76. {qtype-0.0.10 → qtype-0.0.12}/README.md +0 -0
  77. {qtype-0.0.10 → qtype-0.0.12}/qtype/__init__.py +0 -0
  78. {qtype-0.0.10/qtype → qtype-0.0.12/qtype/application}/commons/tools.py +0 -0
  79. {qtype-0.0.10/qtype/commons → qtype-0.0.12/qtype/application/converters}/__init__.py +0 -0
  80. {qtype-0.0.10/qtype → qtype-0.0.12/qtype/application}/converters/tools_from_api.py +0 -0
  81. {qtype-0.0.10 → qtype-0.0.12}/qtype/cli.py +0 -0
  82. {qtype-0.0.10 → qtype-0.0.12}/qtype/commands/__init__.py +0 -0
  83. {qtype-0.0.10 → qtype-0.0.12}/qtype/dsl/domain_types.py +0 -0
  84. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/__init__.py +0 -0
  85. {qtype-0.0.10/qtype/converters → qtype-0.0.12/qtype/interpreter/batch}/__init__.py +0 -0
  86. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/chat/chat_api.py +0 -0
  87. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/chat/file_conversions.py +0 -0
  88. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/chat/vercel.py +0 -0
  89. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/exceptions.py +0 -0
  90. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/flow.py +0 -0
  91. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/step.py +0 -0
  92. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/steps/__init__.py +0 -0
  93. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/steps/agent.py +0 -0
  94. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/steps/condition.py +0 -0
  95. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/steps/search.py +0 -0
  96. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/steps/tool.py +0 -0
  97. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/telemetry.py +0 -0
  98. {qtype-0.0.10/qtype/interpreter/ui/_next/static/Jb2murBlt2XkN6punrQbE → qtype-0.0.12/qtype/interpreter/ui/_next/static/OT8QJQW3J70VbDWWfrEMT}/_buildManifest.js +0 -0
  99. {qtype-0.0.10/qtype/interpreter/ui/_next/static/Jb2murBlt2XkN6punrQbE → qtype-0.0.12/qtype/interpreter/ui/_next/static/OT8QJQW3J70VbDWWfrEMT}/_ssgManifest.js +0 -0
  100. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/chunks/4bd1b696-cf72ae8a39fa05aa.js +0 -0
  101. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/chunks/736-7fc606e244fedcb1.js +0 -0
  102. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/chunks/964-ed4ab073db645007.js +0 -0
  103. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/chunks/app/_not-found/page-e110d2a9d0a83d82.js +0 -0
  104. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/chunks/app/layout-5ccbc44fd528d089.js +0 -0
  105. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/chunks/app/page-c72e847e888e549d.js +0 -0
  106. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/chunks/ba12c10f-22556063851a6df2.js +0 -0
  107. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/chunks/framework-7c95b8e5103c9e90.js +0 -0
  108. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/chunks/main-6d261b6c5d6fb6c2.js +0 -0
  109. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/chunks/main-app-6fc6346bc8f7f163.js +0 -0
  110. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/chunks/pages/_app-0a0020ddd67f79cf.js +0 -0
  111. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/chunks/pages/_error-03529f2c21436739.js +0 -0
  112. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -0
  113. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/chunks/webpack-8289c17c67827f22.js +0 -0
  114. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/css/a262c53826df929b.css +0 -0
  115. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/media/569ce4b8f30dc480-s.p.woff2 +0 -0
  116. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/media/747892c23ea88013-s.woff2 +0 -0
  117. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/media/8d697b304b401681-s.woff2 +0 -0
  118. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  119. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/media/9610d9e46709d722-s.woff2 +0 -0
  120. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/_next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  121. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/favicon.ico +0 -0
  122. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/file.svg +0 -0
  123. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/globe.svg +0 -0
  124. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/next.svg +0 -0
  125. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/vercel.svg +0 -0
  126. {qtype-0.0.10 → qtype-0.0.12}/qtype/interpreter/ui/window.svg +0 -0
  127. {qtype-0.0.10 → qtype-0.0.12}/qtype/semantic/__init__.py +0 -0
  128. {qtype-0.0.10 → qtype-0.0.12}/qtype/semantic/base_types.py +0 -0
  129. {qtype-0.0.10 → qtype-0.0.12}/qtype/semantic/visualize.py +0 -0
  130. {qtype-0.0.10 → qtype-0.0.12}/qtype.egg-info/dependency_links.txt +0 -0
  131. {qtype-0.0.10 → qtype-0.0.12}/qtype.egg-info/entry_points.txt +0 -0
  132. {qtype-0.0.10 → qtype-0.0.12}/qtype.egg-info/top_level.txt +0 -0
  133. {qtype-0.0.10 → qtype-0.0.12}/setup.cfg +0 -0
  134. {qtype-0.0.10 → qtype-0.0.12}/tests/test_dsl_loader.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qtype
3
- Version: 0.0.10
3
+ Version: 0.0.12
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
@@ -17,6 +17,7 @@ Requires-Dist: fsspec>=2025.5.1
17
17
  Requires-Dist: pydantic-yaml>=1.5.1
18
18
  Requires-Dist: mkdocs-awesome-pages-plugin>=2.10.1
19
19
  Requires-Dist: mermaid-py>=0.8.0
20
+ Requires-Dist: pip-system-certs>=5.2
20
21
  Provides-Extra: interpreter
21
22
  Requires-Dist: arize-phoenix-otel>=0.12.1; extra == "interpreter"
22
23
  Requires-Dist: boto3>=1.34.0; extra == "interpreter"
@@ -27,8 +28,11 @@ Requires-Dist: llama-index-llms-bedrock-converse>=0.7.4; extra == "interpreter"
27
28
  Requires-Dist: llama-index-llms-bedrock>=0.3.8; extra == "interpreter"
28
29
  Requires-Dist: llama-index>=0.12.45; extra == "interpreter"
29
30
  Requires-Dist: openinference-instrumentation-llama-index>=4.3.4; extra == "interpreter"
31
+ Requires-Dist: pandas>=2.2.3; extra == "interpreter"
30
32
  Requires-Dist: psycopg2-binary>=2.9.10; extra == "interpreter"
33
+ Requires-Dist: pyathena[sqlalchemy]>=3.18.0; extra == "interpreter"
31
34
  Requires-Dist: python-magic>=0.4.27; extra == "interpreter"
35
+ Requires-Dist: sqlalchemy>=2.0.42; extra == "interpreter"
32
36
  Requires-Dist: uvicorn[standard]>=0.35.0; extra == "interpreter"
33
37
  Dynamic: license-file
34
38
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "qtype"
3
- version = "0.0.10"
3
+ version = "0.0.12"
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"
@@ -15,6 +15,7 @@ dependencies = [
15
15
  "pydantic-yaml>=1.5.1",
16
16
  "mkdocs-awesome-pages-plugin>=2.10.1",
17
17
  "mermaid-py>=0.8.0",
18
+ "pip-system-certs>=5.2",
18
19
  ]
19
20
  license = "APACHE-2.0"
20
21
  license-files = ["LICEN[CS]E*"]
@@ -33,8 +34,11 @@ interpreter = [
33
34
  "llama-index-llms-bedrock>=0.3.8",
34
35
  "llama-index>=0.12.45",
35
36
  "openinference-instrumentation-llama-index>=4.3.4",
37
+ "pandas>=2.2.3",
36
38
  "psycopg2-binary>=2.9.10",
39
+ "pyathena[sqlalchemy]>=3.18.0",
37
40
  "python-magic>=0.4.27",
41
+ "sqlalchemy>=2.0.42",
38
42
  "uvicorn[standard]>=0.35.0",
39
43
  ]
40
44
 
@@ -52,13 +56,17 @@ dev = [
52
56
  "mkdocstrings>=0.30.0",
53
57
  "mypy>=1.8.0",
54
58
  "networkx>=3.4.2",
59
+ "pandas-stubs>=2.3.2.250827",
55
60
  "pkginfo>=1.12.1.2",
56
61
  "pre-commit>=3.6.0",
57
62
  "pymdown-extensions>=10.16",
58
63
  "pytest-cov>=6.0.0",
59
64
  "pytest>=8.4.1",
60
65
  "ruff>=0.1.0",
66
+ "types-cachetools>=6.2.0.20250827",
67
+ "types-networkx>=3.5.0.20250901",
61
68
  "types-PyYAML>=6.0.2",
69
+ "types-requests>=2.32.4.20250809",
62
70
  ]
63
71
  docs = [
64
72
  "mkdocs>=1.5.0",
@@ -110,12 +118,17 @@ python_version = "3.10"
110
118
  warn_return_any = true
111
119
  warn_unused_configs = true
112
120
  disallow_untyped_defs = true
121
+ explicit_package_bases = true
113
122
  plugins = ["pydantic.mypy"]
114
123
 
115
124
  [[tool.mypy.overrides]]
116
125
  module = "tests.*"
117
126
  disallow_untyped_defs = false
118
127
 
128
+ [[tool.mypy.overrides]]
129
+ module = "qtype.semantic.model"
130
+ ignore_errors = true
131
+
119
132
  [tool.pydantic-mypy]
120
133
  init_forbid_extra = true
121
134
  init_typed = true
@@ -124,11 +137,9 @@ warn_required_dynamic_aliases = true
124
137
  [tool.coverage.run]
125
138
  source = ["qtype"]
126
139
  omit = [
127
- "*/tests/*",
128
- "*/test_*",
129
- "*/__pycache__/*",
130
- "*/venv/*",
131
- "*/.venv/*",
140
+ "qtype/commands/*",
141
+ "qtype/interpreter/*", # TODO: expand coverage here.
142
+ "qtype/*.py",
132
143
  ]
133
144
 
134
145
  [tool.coverage.report]
@@ -0,0 +1,12 @@
1
+ """Application layer for orchestrating qtype operations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from . import commons, converters
6
+ from .facade import QTypeFacade
7
+
8
+ __all__ = [
9
+ "QTypeFacade",
10
+ "converters",
11
+ "commons",
12
+ ]
@@ -0,0 +1,7 @@
1
+ """Common tools and utilities for qtype applications."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from . import tools
6
+
7
+ __all__ = ["tools"]
@@ -4,7 +4,7 @@ from typing import Any, Type, Union, get_args, get_origin
4
4
 
5
5
  from pydantic import BaseModel
6
6
 
7
- from qtype.converters.types import PYTHON_TYPE_TO_PRIMITIVE_TYPE
7
+ from qtype.application.converters.types import PYTHON_TYPE_TO_PRIMITIVE_TYPE
8
8
  from qtype.dsl.base_types import PrimitiveTypeEnum
9
9
  from qtype.dsl.model import (
10
10
  CustomType,
@@ -239,7 +239,7 @@ def _map_python_type_to_variable_type(
239
239
  return PYTHON_TYPE_TO_PRIMITIVE_TYPE[python_type]
240
240
  elif python_type in get_args(VariableType):
241
241
  # If it's a domain type, return its name
242
- return python_type
242
+ return python_type # type: ignore[no-any-return]
243
243
  elif inspect.isclass(python_type) and issubclass(python_type, BaseModel):
244
244
  # If it's a Pydantic model, create or retrieve its CustomType definition
245
245
  return _pydantic_to_custom_types(python_type, custom_types)
@@ -0,0 +1,33 @@
1
+ from datetime import date, datetime, time
2
+
3
+ from qtype.dsl.base_types import PrimitiveTypeEnum
4
+
5
+ """
6
+ Mapping of QType primitive types to Python types for internal representations.
7
+ """
8
+ PRIMITIVE_TO_PYTHON_TYPE = {
9
+ PrimitiveTypeEnum.audio: bytes,
10
+ PrimitiveTypeEnum.boolean: bool,
11
+ PrimitiveTypeEnum.bytes: bytes,
12
+ PrimitiveTypeEnum.date: date,
13
+ PrimitiveTypeEnum.datetime: datetime,
14
+ PrimitiveTypeEnum.int: int,
15
+ PrimitiveTypeEnum.file: bytes, # Use bytes for file content
16
+ PrimitiveTypeEnum.float: float,
17
+ PrimitiveTypeEnum.image: bytes, # Use bytes for image data
18
+ PrimitiveTypeEnum.text: str,
19
+ PrimitiveTypeEnum.time: time, # Use time for time representation
20
+ PrimitiveTypeEnum.video: bytes, # Use bytes for video data
21
+ }
22
+
23
+ PYTHON_TYPE_TO_PRIMITIVE_TYPE = {
24
+ bytes: PrimitiveTypeEnum.file,
25
+ bool: PrimitiveTypeEnum.boolean,
26
+ str: PrimitiveTypeEnum.text,
27
+ int: PrimitiveTypeEnum.int,
28
+ float: PrimitiveTypeEnum.float,
29
+ date: PrimitiveTypeEnum.date,
30
+ datetime: PrimitiveTypeEnum.datetime,
31
+ time: PrimitiveTypeEnum.time,
32
+ # TODO: decide on internal representation for images, video, and audio, or use annotation/hinting
33
+ }
@@ -1,3 +1,5 @@
1
+ """Documentation generation utilities for DSL classes."""
2
+
1
3
  import inspect
2
4
  from pathlib import Path
3
5
  from typing import Any, Type, Union, get_args, get_origin
@@ -0,0 +1,160 @@
1
+ """Main facade for qtype operations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import Any
7
+
8
+ import pandas as pd
9
+ from pydantic import BaseModel
10
+
11
+ from qtype.base.logging import get_logger
12
+ from qtype.base.types import CustomTypeRegistry, DocumentRootType, PathLike
13
+ from qtype.dsl.base_types import StepCardinality
14
+ from qtype.dsl.model import Application as DSLApplication
15
+ from qtype.dsl.model import DocumentType
16
+ from qtype.interpreter.batch.types import BatchConfig
17
+ from qtype.semantic.model import Application as SemanticApplication
18
+ from qtype.semantic.model import Variable
19
+
20
+ logger = get_logger("application.facade")
21
+
22
+
23
+ class QTypeFacade:
24
+ """
25
+ Simplified interface for all qtype operations.
26
+
27
+ This facade hides the complexity of coordinating between DSL, semantic,
28
+ and interpreter layers, providing a clean API for common operations.
29
+ """
30
+
31
+ def load_dsl_document(
32
+ self, path: PathLike
33
+ ) -> tuple[DocumentRootType, CustomTypeRegistry]:
34
+ from qtype.loader import load_document
35
+
36
+ return load_document(Path(path).read_text(encoding="utf-8"))
37
+
38
+ def load_and_validate(self, path: PathLike) -> DocumentRootType:
39
+ """Load and validate a document."""
40
+ logger.info("Document loaded, proceeding to validation")
41
+ root, _ = self.load_dsl_document(path)
42
+ return root
43
+
44
+ def load_semantic_model(
45
+ self, path: PathLike
46
+ ) -> tuple[SemanticApplication, CustomTypeRegistry]:
47
+ """Load a document and return the resolved semantic model."""
48
+ from qtype.loader import load
49
+
50
+ content = Path(path).read_text(encoding="utf-8")
51
+ return load(content)
52
+
53
+ def execute_workflow(
54
+ self,
55
+ path: PathLike,
56
+ inputs: dict | pd.DataFrame,
57
+ flow_name: str | None = None,
58
+ batch_config: BatchConfig | None = None,
59
+ **kwargs: Any,
60
+ ) -> pd.DataFrame | list[Variable]:
61
+ """Execute a complete workflow from document to results."""
62
+ logger.info(f"Executing workflow from {path}")
63
+
64
+ # Load the semantic application
65
+ semantic_model, type_registry = self.load_semantic_model(path)
66
+
67
+ # Find the flow to execute (inlined from _find_flow)
68
+ if flow_name:
69
+ target_flow = None
70
+ for flow in semantic_model.flows:
71
+ if flow.id == flow_name:
72
+ target_flow = flow
73
+ break
74
+ if target_flow is None:
75
+ raise ValueError(f"Flow '{flow_name}' not found")
76
+ else:
77
+ if semantic_model.flows:
78
+ target_flow = semantic_model.flows[0]
79
+ else:
80
+ raise ValueError("No flows found in application")
81
+ if target_flow.cardinality == StepCardinality.many:
82
+ if isinstance(inputs, dict):
83
+ inputs = pd.DataFrame([inputs])
84
+ if not isinstance(inputs, pd.DataFrame):
85
+ raise ValueError(
86
+ "Input must be a DataFrame for flows with 'many' cardinality"
87
+ )
88
+ from qtype.interpreter.batch.flow import batch_execute_flow
89
+
90
+ batch_config = batch_config or BatchConfig()
91
+ results, errors = batch_execute_flow(
92
+ target_flow, inputs, batch_config, **kwargs
93
+ ) # type: ignore
94
+ return results
95
+ else:
96
+ from qtype.interpreter.flow import execute_flow
97
+
98
+ args = {**kwargs, **inputs}
99
+ return execute_flow(target_flow, **args)
100
+
101
+ def visualize_application(self, path: PathLike) -> str:
102
+ """Visualize an application as Mermaid diagram."""
103
+ from qtype.semantic.visualize import visualize_application
104
+
105
+ semantic_model, _ = self.load_semantic_model(path)
106
+ return visualize_application(semantic_model)
107
+
108
+ def convert_document(self, document: DocumentType) -> str:
109
+ """Convert a document to YAML format."""
110
+ # Wrap DSLApplication in Document if needed
111
+ wrapped_document: BaseModel = document
112
+ if isinstance(document, DSLApplication):
113
+ from qtype.dsl.model import Document
114
+
115
+ wrapped_document = Document(root=document)
116
+
117
+ # Try to use pydantic_yaml first
118
+ try:
119
+ from pydantic_yaml import to_yaml_str
120
+
121
+ return to_yaml_str(
122
+ wrapped_document, exclude_unset=True, exclude_none=True
123
+ )
124
+ except ImportError:
125
+ # Fallback to basic YAML if pydantic_yaml is not available
126
+ import yaml
127
+
128
+ document_dict = wrapped_document.model_dump(
129
+ exclude_unset=True, exclude_none=True
130
+ )
131
+ return yaml.dump(document_dict, default_flow_style=False)
132
+
133
+ def generate_aws_bedrock_models(self) -> list[dict[str, Any]]:
134
+ """
135
+ Generate AWS Bedrock model definitions.
136
+
137
+ Returns:
138
+ List of model definitions for AWS Bedrock models.
139
+
140
+ Raises:
141
+ ImportError: If boto3 is not installed.
142
+ Exception: If AWS API call fails.
143
+ """
144
+ import boto3 # type: ignore[import-untyped]
145
+
146
+ logger.info("Discovering AWS Bedrock models...")
147
+ client = boto3.client("bedrock")
148
+ models = client.list_foundation_models()
149
+
150
+ model_definitions = []
151
+ for model_summary in models.get("modelSummaries", []):
152
+ model_definitions.append(
153
+ {
154
+ "id": model_summary["modelId"],
155
+ "provider": "aws-bedrock",
156
+ }
157
+ )
158
+
159
+ logger.info(f"Discovered {len(model_definitions)} AWS Bedrock models")
160
+ return model_definitions
@@ -0,0 +1,14 @@
1
+ """Base utilities and types for qtype."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from .exceptions import QTypeError, ValidationError
6
+ from .logging import get_logger
7
+ from .types import JSONValue
8
+
9
+ __all__ = [
10
+ "QTypeError",
11
+ "ValidationError",
12
+ "get_logger",
13
+ "JSONValue",
14
+ ]
@@ -0,0 +1,49 @@
1
+ """Base exceptions for qtype."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+
8
+ class QTypeError(Exception):
9
+ """Base exception for all qtype errors."""
10
+
11
+ def __init__(
12
+ self, message: str, details: dict[str, Any] | None = None
13
+ ) -> None:
14
+ """Initialize the exception with message and optional details."""
15
+ super().__init__(message)
16
+ self.message = message
17
+ self.details = details or {}
18
+
19
+
20
+ class ValidationError(QTypeError):
21
+ """Exception raised when validation fails."""
22
+
23
+ def __init__(
24
+ self,
25
+ message: str,
26
+ errors: list[str] | None = None,
27
+ details: dict[str, Any] | None = None,
28
+ ) -> None:
29
+ """Initialize validation error with list of error messages."""
30
+ super().__init__(message, details)
31
+ self.errors = errors or []
32
+
33
+
34
+ class LoadError(QTypeError):
35
+ """Exception raised when loading documents fails."""
36
+
37
+ pass
38
+
39
+
40
+ class SemanticError(QTypeError):
41
+ """Exception raised when semantic processing fails."""
42
+
43
+ pass
44
+
45
+
46
+ class InterpreterError(QTypeError):
47
+ """Exception raised when interpretation/execution fails."""
48
+
49
+ pass
@@ -0,0 +1,39 @@
1
+ """Logging utilities for qtype."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+
7
+
8
+ def get_logger(name: str) -> logging.Logger:
9
+ """Get a logger with the given name and consistent formatting."""
10
+ logger = logging.getLogger(f"qtype.{name}")
11
+
12
+ # Only configure if not already configured
13
+ if not logger.handlers:
14
+ handler = logging.StreamHandler()
15
+ formatter = logging.Formatter(
16
+ "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
17
+ )
18
+ handler.setFormatter(formatter)
19
+ logger.addHandler(handler)
20
+ logger.setLevel(logging.INFO)
21
+
22
+ return logger
23
+
24
+
25
+ def configure_logging(
26
+ level: str = "INFO", format_string: str | None = None
27
+ ) -> None:
28
+ """Configure root logging for qtype."""
29
+ numeric_level = getattr(logging, level.upper(), logging.INFO)
30
+
31
+ format_str = (
32
+ format_string or "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
33
+ )
34
+
35
+ logging.basicConfig(
36
+ level=numeric_level,
37
+ format=format_str,
38
+ force=True, # Override any existing configuration
39
+ )
@@ -0,0 +1,29 @@
1
+ """Common type definitions for qtype."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import pathlib
6
+ from typing import Any, Type, Union
7
+
8
+ from pydantic import BaseModel
9
+
10
+ from qtype.dsl import model as dsl
11
+
12
+ # JSON-serializable value types
13
+ JSONValue = Union[
14
+ str,
15
+ int,
16
+ float,
17
+ bool,
18
+ None,
19
+ dict[str, "JSONValue"],
20
+ list["JSONValue"],
21
+ ]
22
+
23
+ # Configuration dictionary type
24
+ ConfigDict = dict[str, Any]
25
+
26
+ # Path-like type (string or Path object)
27
+ PathLike = Union[str, pathlib.Path]
28
+ CustomTypeRegistry = dict[str, Type[BaseModel]]
29
+ DocumentRootType = dsl.Agent | dsl.Application | dsl.Flow | list
@@ -0,0 +1,104 @@
1
+ """
2
+ Command-line interface for converting tools and APIs to qtype format.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ import argparse
8
+ import logging
9
+ from pathlib import Path
10
+
11
+ from qtype.application.facade import QTypeFacade
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ def convert_api(args: argparse.Namespace) -> None:
17
+ """Convert API specification to qtype format."""
18
+ raise NotImplementedError("API conversion is not implemented yet.")
19
+
20
+
21
+ def convert_module(args: argparse.Namespace) -> None:
22
+ """Convert Python module tools to qtype format."""
23
+ from qtype.application.converters.tools_from_module import (
24
+ tools_from_module,
25
+ )
26
+ from qtype.dsl.model import Application, ToolList
27
+
28
+ try:
29
+ tools, types = tools_from_module(args.module_path)
30
+ if not tools:
31
+ raise ValueError(
32
+ f"No tools found in the module: {args.module_path}"
33
+ )
34
+
35
+ # Create application document
36
+ if types:
37
+ doc: Application | ToolList = Application(
38
+ id=args.module_path,
39
+ description=f"Tools created from Python module {args.module_path}",
40
+ tools=list(tools),
41
+ types=types,
42
+ )
43
+ else:
44
+ doc = ToolList(
45
+ root=list(tools),
46
+ )
47
+
48
+ # Use facade to convert to YAML format
49
+ facade = QTypeFacade()
50
+ content = facade.convert_document(doc)
51
+
52
+ # Write to file or stdout
53
+ if args.output:
54
+ output_path = Path(args.output)
55
+ output_path.write_text(content, encoding="utf-8")
56
+ logger.info(f"✅ Converted tools saved to {output_path}")
57
+ else:
58
+ print(content)
59
+
60
+ except Exception as e:
61
+ logger.error(f"❌ Conversion failed: {e}")
62
+ raise
63
+
64
+
65
+ def parser(subparsers: argparse._SubParsersAction) -> None:
66
+ """Set up the converter subcommand parser."""
67
+ cmd_parser = subparsers.add_parser(
68
+ "convert", help="Creates qtype files from different sources."
69
+ )
70
+
71
+ # Create a new subparser for "convert api", "convert module", etc.
72
+ convert_subparsers = cmd_parser.add_subparsers(
73
+ dest="convert_command", required=True
74
+ )
75
+
76
+ # Convert from Python module
77
+ module_parser = convert_subparsers.add_parser(
78
+ "module", help="Convert a Python module to qtype tools format."
79
+ )
80
+ module_parser.add_argument(
81
+ "module_path", type=str, help="Path to the Python module to convert."
82
+ )
83
+ module_parser.add_argument(
84
+ "-o",
85
+ "--output",
86
+ type=str,
87
+ help="Output file path. If not specified, prints to stdout.",
88
+ )
89
+ module_parser.set_defaults(func=convert_module)
90
+
91
+ # Convert from API specification
92
+ api_parser = convert_subparsers.add_parser(
93
+ "api", help="Convert an API specification to qtype format."
94
+ )
95
+ api_parser.add_argument(
96
+ "api_spec", type=str, help="Path to the API specification file."
97
+ )
98
+ api_parser.add_argument(
99
+ "-o",
100
+ "--output",
101
+ type=str,
102
+ help="Output file path. If not specified, prints to stdout.",
103
+ )
104
+ api_parser.set_defaults(func=convert_api)
@@ -10,13 +10,68 @@ logger = logging.getLogger(__name__)
10
10
 
11
11
 
12
12
  def run_dump_commons_library(args: argparse.Namespace) -> None:
13
- from qtype.commons.generate import dump_commons_library
13
+ """Generate commons library tools and AWS Bedrock models."""
14
+ import logging
15
+ from pathlib import Path
14
16
 
15
- dump_commons_library(args)
17
+ from qtype.application.facade import QTypeFacade
18
+ from qtype.dsl.model import Model, ModelList
19
+
20
+ logger = logging.getLogger(__name__)
21
+ facade = QTypeFacade()
22
+
23
+ try:
24
+ # Generate common tools using convert module functionality
25
+ logger.info("Generating common tools...")
26
+
27
+ # Create a mock args object for convert_module
28
+ import argparse
29
+
30
+ from qtype.commands.convert import convert_module
31
+
32
+ convert_args = argparse.Namespace(
33
+ module_path="qtype.application.commons.tools",
34
+ output=f"{args.prefix}/tools.qtype.yaml",
35
+ )
36
+ convert_module(convert_args)
37
+
38
+ # Generate AWS Bedrock models
39
+ logger.info("Generating AWS Bedrock models...")
40
+ try:
41
+ model_definitions = facade.generate_aws_bedrock_models()
42
+
43
+ model_list = ModelList(
44
+ root=[
45
+ Model(
46
+ id=model_def["id"],
47
+ provider=model_def["provider"],
48
+ )
49
+ for model_def in model_definitions
50
+ ]
51
+ )
52
+
53
+ # Convert to YAML and save
54
+ content = facade.convert_document(model_list)
55
+ output_path = Path(f"{args.prefix}/aws.bedrock.models.qtype.yaml")
56
+ output_path.write_text(content, encoding="utf-8")
57
+ logger.info(f"AWS Bedrock models exported to {output_path}")
58
+
59
+ except ImportError:
60
+ logger.warning(
61
+ "boto3 not available. Skipping AWS Bedrock model generation."
62
+ )
63
+ except Exception as e:
64
+ logger.error(f"Failed to generate AWS Bedrock models: {e}")
65
+
66
+ logger.info("Commons library generation complete.")
67
+
68
+ except Exception as e:
69
+ logger.error(f"Failed to generate commons library: {e}")
70
+ raise
16
71
 
17
72
 
18
73
  def run_generate_documentation(args: argparse.Namespace) -> None:
19
- from qtype.dsl.document import generate_documentation
74
+ from qtype.application.documentation import generate_documentation
20
75
 
21
76
  generate_documentation(Path(args.output))
22
77
 
@@ -93,7 +148,7 @@ def parser(subparsers: argparse._SubParsersAction) -> None:
93
148
  # only add this if networkx and ruff are installed
94
149
  try:
95
150
  import networkx # noqa: F401
96
- import ruff # noqa: F401
151
+ import ruff # type: ignore[import-untyped] # noqa: F401
97
152
 
98
153
  from qtype.semantic.generate import generate_semantic_model
99
154