qtype 0.0.5__tar.gz → 0.0.7__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.
- {qtype-0.0.5/qtype.egg-info → qtype-0.0.7}/PKG-INFO +28 -20
- {qtype-0.0.5 → qtype-0.0.7}/README.md +23 -18
- {qtype-0.0.5 → qtype-0.0.7}/pyproject.toml +10 -4
- {qtype-0.0.5 → qtype-0.0.7}/qtype/commands/convert.py +18 -5
- {qtype-0.0.5 → qtype-0.0.7}/qtype/commands/generate.py +16 -8
- {qtype-0.0.5 → qtype-0.0.7}/qtype/commands/run.py +6 -83
- qtype-0.0.7/qtype/commands/serve.py +73 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/commands/validate.py +18 -8
- qtype-0.0.7/qtype/commands/visualize.py +87 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/commons/generate.py +9 -4
- qtype-0.0.7/qtype/converters/tools_from_module.py +261 -0
- qtype-0.0.7/qtype/converters/types.py +66 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/dsl/base_types.py +0 -1
- qtype-0.0.7/qtype/dsl/custom_types.py +73 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/dsl/document.py +27 -3
- {qtype-0.0.5 → qtype-0.0.7}/qtype/dsl/domain_types.py +3 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/dsl/model.py +60 -73
- {qtype-0.0.5 → qtype-0.0.7}/qtype/dsl/validator.py +20 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/interpreter/api.py +45 -12
- qtype-0.0.7/qtype/interpreter/chat/chat_api.py +237 -0
- qtype-0.0.7/qtype/interpreter/chat/file_conversions.py +57 -0
- qtype-0.0.7/qtype/interpreter/chat/vercel.py +314 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/interpreter/conversions.py +2 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/interpreter/steps/llm_inference.py +44 -19
- qtype-0.0.7/qtype/interpreter/streaming_helpers.py +123 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/interpreter/typing.py +29 -10
- qtype-0.0.7/qtype/interpreter/ui/404/index.html +1 -0
- qtype-0.0.7/qtype/interpreter/ui/404.html +1 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/chunks/4bd1b696-cf72ae8a39fa05aa.js +1 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/chunks/736-7fc606e244fedcb1.js +36 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/chunks/964-ed4ab073db645007.js +1 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/chunks/app/_not-found/page-e110d2a9d0a83d82.js +1 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/chunks/app/layout-f8f02d19bf177f87.js +1 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/chunks/app/page-c72e847e888e549d.js +1 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/chunks/ba12c10f-22556063851a6df2.js +1 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/chunks/framework-7c95b8e5103c9e90.js +1 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/chunks/main-6d261b6c5d6fb6c2.js +1 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/chunks/main-app-6fc6346bc8f7f163.js +1 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/chunks/pages/_app-0a0020ddd67f79cf.js +1 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/chunks/pages/_error-03529f2c21436739.js +1 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/chunks/webpack-ebad980006f664ca.js +1 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/css/cd7a636f069c2cbd.css +3 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/media/569ce4b8f30dc480-s.p.woff2 +0 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/media/747892c23ea88013-s.woff2 +0 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/media/8d697b304b401681-s.woff2 +0 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/media/9610d9e46709d722-s.woff2 +0 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/qlZrsNT9fTEe92CsYpHBB/_buildManifest.js +1 -0
- qtype-0.0.7/qtype/interpreter/ui/_next/static/qlZrsNT9fTEe92CsYpHBB/_ssgManifest.js +1 -0
- qtype-0.0.7/qtype/interpreter/ui/favicon.ico +0 -0
- qtype-0.0.7/qtype/interpreter/ui/file.svg +1 -0
- qtype-0.0.7/qtype/interpreter/ui/globe.svg +1 -0
- qtype-0.0.7/qtype/interpreter/ui/index.html +1 -0
- qtype-0.0.7/qtype/interpreter/ui/index.txt +22 -0
- qtype-0.0.7/qtype/interpreter/ui/next.svg +1 -0
- qtype-0.0.7/qtype/interpreter/ui/vercel.svg +1 -0
- qtype-0.0.7/qtype/interpreter/ui/window.svg +1 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/loader.py +57 -8
- {qtype-0.0.5 → qtype-0.0.7}/qtype/semantic/generate.py +17 -5
- {qtype-0.0.5 → qtype-0.0.7}/qtype/semantic/model.py +16 -24
- qtype-0.0.7/qtype/semantic/visualize.py +485 -0
- {qtype-0.0.5 → qtype-0.0.7/qtype.egg-info}/PKG-INFO +28 -20
- qtype-0.0.7/qtype.egg-info/SOURCES.txt +98 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype.egg-info/requires.txt +4 -1
- {qtype-0.0.5 → qtype-0.0.7}/tests/test_dsl_validation.py +9 -5
- {qtype-0.0.5 → qtype-0.0.7}/tests/test_semantic_resolver.py +1 -1
- qtype-0.0.7/tests/test_tools_from_module.py +296 -0
- qtype-0.0.5/qtype/converters/tools_from_module.py +0 -326
- qtype-0.0.5/qtype/converters/types.py +0 -20
- qtype-0.0.5/qtype.egg-info/SOURCES.txt +0 -57
- qtype-0.0.5/tests/test_tool_provider_python_module.py +0 -769
- {qtype-0.0.5 → qtype-0.0.7}/LICENSE +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/__init__.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/cli.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/commands/__init__.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/commons/__init__.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/commons/tools.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/converters/__init__.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/converters/tools_from_api.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/dsl/__init__.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/interpreter/__init__.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/interpreter/exceptions.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/interpreter/flow.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/interpreter/resource_cache.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/interpreter/step.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/interpreter/steps/__init__.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/interpreter/steps/agent.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/interpreter/steps/condition.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/interpreter/steps/decoder.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/interpreter/steps/prompt_template.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/interpreter/steps/search.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/interpreter/steps/tool.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/interpreter/telemetry.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/semantic/__init__.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/semantic/base_types.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/semantic/errors.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype/semantic/resolver.py +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype.egg-info/dependency_links.txt +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype.egg-info/entry_points.txt +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/qtype.egg-info/top_level.txt +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/setup.cfg +0 -0
- {qtype-0.0.5 → qtype-0.0.7}/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.
|
|
3
|
+
Version: 0.0.7
|
|
4
4
|
Summary: DSL for Generative AI Prototyping
|
|
5
5
|
Author-email: Lou Kratz <lou.kratz+qtype@bazaarvoice.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -15,6 +15,8 @@ Requires-Dist: python-dotenv>=1.0.0
|
|
|
15
15
|
Requires-Dist: openai>=1.93.0
|
|
16
16
|
Requires-Dist: fsspec>=2025.5.1
|
|
17
17
|
Requires-Dist: pydantic-yaml>=1.5.1
|
|
18
|
+
Requires-Dist: mkdocs-awesome-pages-plugin>=2.10.1
|
|
19
|
+
Requires-Dist: mermaid-py>=0.8.0
|
|
18
20
|
Provides-Extra: interpreter
|
|
19
21
|
Requires-Dist: arize-phoenix-otel>=0.12.1; extra == "interpreter"
|
|
20
22
|
Requires-Dist: boto3>=1.34.0; extra == "interpreter"
|
|
@@ -24,8 +26,9 @@ Requires-Dist: llama-index-embeddings-openai>=0.3.1; extra == "interpreter"
|
|
|
24
26
|
Requires-Dist: llama-index-llms-bedrock-converse>=0.7.4; extra == "interpreter"
|
|
25
27
|
Requires-Dist: llama-index-llms-bedrock>=0.3.8; extra == "interpreter"
|
|
26
28
|
Requires-Dist: llama-index>=0.12.45; extra == "interpreter"
|
|
27
|
-
Requires-Dist: openinference-instrumentation-llama-index>=4.3.
|
|
29
|
+
Requires-Dist: openinference-instrumentation-llama-index>=4.3.4; extra == "interpreter"
|
|
28
30
|
Requires-Dist: psycopg2-binary>=2.9.10; extra == "interpreter"
|
|
31
|
+
Requires-Dist: python-magic>=0.4.27; extra == "interpreter"
|
|
29
32
|
Requires-Dist: uvicorn[standard]>=0.35.0; extra == "interpreter"
|
|
30
33
|
Dynamic: license-file
|
|
31
34
|
|
|
@@ -44,15 +47,17 @@ Install QType:
|
|
|
44
47
|
pip install qtype[interpreter]
|
|
45
48
|
```
|
|
46
49
|
|
|
47
|
-
Create a file `hello_world.qtype.yaml` that
|
|
50
|
+
Create a file `hello_world.qtype.yaml` that answers a question:
|
|
48
51
|
```yaml
|
|
49
52
|
id: hello_world
|
|
50
53
|
flows:
|
|
51
|
-
- id:
|
|
54
|
+
- id: chat_example
|
|
55
|
+
description: A simple chat flow with OpenAI
|
|
56
|
+
mode: Chat
|
|
52
57
|
steps:
|
|
53
58
|
- id: llm_inference_step
|
|
54
59
|
model:
|
|
55
|
-
id: gpt-
|
|
60
|
+
id: gpt-4
|
|
56
61
|
provider: openai
|
|
57
62
|
auth:
|
|
58
63
|
id: openai_auth
|
|
@@ -61,11 +66,11 @@ flows:
|
|
|
61
66
|
system_message: |
|
|
62
67
|
You are a helpful assistant.
|
|
63
68
|
inputs:
|
|
64
|
-
- id:
|
|
65
|
-
type:
|
|
69
|
+
- id: user_message
|
|
70
|
+
type: ChatMessage
|
|
66
71
|
outputs:
|
|
67
|
-
- id:
|
|
68
|
-
type:
|
|
72
|
+
- id: response
|
|
73
|
+
type: ChatMessage
|
|
69
74
|
```
|
|
70
75
|
|
|
71
76
|
Put your openai api key into your `.env` file:
|
|
@@ -73,12 +78,14 @@ Put your openai api key into your `.env` file:
|
|
|
73
78
|
echo "OPENAI_KEY=sk...." >> .env
|
|
74
79
|
```
|
|
75
80
|
|
|
76
|
-
Validate
|
|
77
|
-
|
|
78
|
-
|
|
81
|
+
Validate it's semantic correctness:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
qtype validate hello_world.qtype.yaml
|
|
79
85
|
```
|
|
80
86
|
|
|
81
87
|
You should see:
|
|
88
|
+
|
|
82
89
|
```
|
|
83
90
|
INFO: ✅ Schema validation successful.
|
|
84
91
|
INFO: ✅ Model validation successful.
|
|
@@ -86,23 +93,24 @@ INFO: ✅ Language validation successful
|
|
|
86
93
|
INFO: ✅ Semantic validation successful
|
|
87
94
|
```
|
|
88
95
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
96
|
+
Launch the interpreter:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
qtype serve hello_world.qtype.yaml`
|
|
92
100
|
```
|
|
93
101
|
|
|
94
|
-
You should see (something similar to):
|
|
95
102
|
|
|
96
|
-
|
|
97
|
-
|
|
103
|
+
And go to [http://localhost:8000/ui](http://localhost:8000/ui) to see the user interface for your application:
|
|
104
|
+
|
|
105
|
+

|
|
98
106
|
|
|
99
|
-
The airspeed of a laden swallow is a humorous reference from the movie "Monty Python and the Holy Grail." In the film, the question is posed as "What is the airspeed velocity of an unladen swallow?" The joke revolves around the absurdity and specificity of the question, and it doesn't have a straightforward answer. However, if you're curious about the real-life airspeed of a swallow, the European Swallow (Hirundo rustica) typically flies at around 11 meters per second, or 24 miles per hour, when unladen. The concept of a "laden" swallow is part of the humor, as it would depend on what the swallow is carrying and is not a standard measurement.
|
|
100
|
-
```
|
|
101
107
|
|
|
102
108
|
---
|
|
103
109
|
|
|
104
110
|
See the [full docs](https://bazaarvoice.github.io/qtype/) for more examples and guides.
|
|
105
111
|
|
|
112
|
+
|
|
113
|
+
|
|
106
114
|
## 🤝 Contributing
|
|
107
115
|
|
|
108
116
|
Contributions welcome! Please follow the instructions in the [contribution guide](https://bazaarvoice.github.io/qtype/contributing/).
|
|
@@ -13,15 +13,17 @@ Install QType:
|
|
|
13
13
|
pip install qtype[interpreter]
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
Create a file `hello_world.qtype.yaml` that
|
|
16
|
+
Create a file `hello_world.qtype.yaml` that answers a question:
|
|
17
17
|
```yaml
|
|
18
18
|
id: hello_world
|
|
19
19
|
flows:
|
|
20
|
-
- id:
|
|
20
|
+
- id: chat_example
|
|
21
|
+
description: A simple chat flow with OpenAI
|
|
22
|
+
mode: Chat
|
|
21
23
|
steps:
|
|
22
24
|
- id: llm_inference_step
|
|
23
25
|
model:
|
|
24
|
-
id: gpt-
|
|
26
|
+
id: gpt-4
|
|
25
27
|
provider: openai
|
|
26
28
|
auth:
|
|
27
29
|
id: openai_auth
|
|
@@ -30,11 +32,11 @@ flows:
|
|
|
30
32
|
system_message: |
|
|
31
33
|
You are a helpful assistant.
|
|
32
34
|
inputs:
|
|
33
|
-
- id:
|
|
34
|
-
type:
|
|
35
|
+
- id: user_message
|
|
36
|
+
type: ChatMessage
|
|
35
37
|
outputs:
|
|
36
|
-
- id:
|
|
37
|
-
type:
|
|
38
|
+
- id: response
|
|
39
|
+
type: ChatMessage
|
|
38
40
|
```
|
|
39
41
|
|
|
40
42
|
Put your openai api key into your `.env` file:
|
|
@@ -42,12 +44,14 @@ Put your openai api key into your `.env` file:
|
|
|
42
44
|
echo "OPENAI_KEY=sk...." >> .env
|
|
43
45
|
```
|
|
44
46
|
|
|
45
|
-
Validate
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
Validate it's semantic correctness:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
qtype validate hello_world.qtype.yaml
|
|
48
51
|
```
|
|
49
52
|
|
|
50
53
|
You should see:
|
|
54
|
+
|
|
51
55
|
```
|
|
52
56
|
INFO: ✅ Schema validation successful.
|
|
53
57
|
INFO: ✅ Model validation successful.
|
|
@@ -55,23 +59,24 @@ INFO: ✅ Language validation successful
|
|
|
55
59
|
INFO: ✅ Semantic validation successful
|
|
56
60
|
```
|
|
57
61
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
Launch the interpreter:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
qtype serve hello_world.qtype.yaml`
|
|
61
66
|
```
|
|
62
67
|
|
|
63
|
-
You should see (something similar to):
|
|
64
68
|
|
|
65
|
-
|
|
66
|
-
|
|
69
|
+
And go to [http://localhost:8000/ui](http://localhost:8000/ui) to see the user interface for your application:
|
|
70
|
+
|
|
71
|
+

|
|
67
72
|
|
|
68
|
-
The airspeed of a laden swallow is a humorous reference from the movie "Monty Python and the Holy Grail." In the film, the question is posed as "What is the airspeed velocity of an unladen swallow?" The joke revolves around the absurdity and specificity of the question, and it doesn't have a straightforward answer. However, if you're curious about the real-life airspeed of a swallow, the European Swallow (Hirundo rustica) typically flies at around 11 meters per second, or 24 miles per hour, when unladen. The concept of a "laden" swallow is part of the humor, as it would depend on what the swallow is carrying and is not a standard measurement.
|
|
69
|
-
```
|
|
70
73
|
|
|
71
74
|
---
|
|
72
75
|
|
|
73
76
|
See the [full docs](https://bazaarvoice.github.io/qtype/) for more examples and guides.
|
|
74
77
|
|
|
78
|
+
|
|
79
|
+
|
|
75
80
|
## 🤝 Contributing
|
|
76
81
|
|
|
77
82
|
Contributions welcome! Please follow the instructions in the [contribution guide](https://bazaarvoice.github.io/qtype/contributing/).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "qtype"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.7"
|
|
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"
|
|
@@ -12,7 +12,9 @@ dependencies = [
|
|
|
12
12
|
"python-dotenv>=1.0.0",
|
|
13
13
|
"openai>=1.93.0",
|
|
14
14
|
"fsspec>=2025.5.1",
|
|
15
|
-
"pydantic-yaml>=1.5.1"
|
|
15
|
+
"pydantic-yaml>=1.5.1",
|
|
16
|
+
"mkdocs-awesome-pages-plugin>=2.10.1",
|
|
17
|
+
"mermaid-py>=0.8.0",
|
|
16
18
|
]
|
|
17
19
|
license = "APACHE-2.0"
|
|
18
20
|
license-files = ["LICEN[CS]E*"]
|
|
@@ -30,8 +32,9 @@ interpreter = [
|
|
|
30
32
|
"llama-index-llms-bedrock-converse>=0.7.4",
|
|
31
33
|
"llama-index-llms-bedrock>=0.3.8",
|
|
32
34
|
"llama-index>=0.12.45",
|
|
33
|
-
"openinference-instrumentation-llama-index>=4.3.
|
|
35
|
+
"openinference-instrumentation-llama-index>=4.3.4",
|
|
34
36
|
"psycopg2-binary>=2.9.10",
|
|
37
|
+
"python-magic>=0.4.27",
|
|
35
38
|
"uvicorn[standard]>=0.35.0",
|
|
36
39
|
]
|
|
37
40
|
|
|
@@ -42,7 +45,7 @@ dev = [
|
|
|
42
45
|
"coverage>=7.0.0",
|
|
43
46
|
"ipython>=8.37.0",
|
|
44
47
|
"isort>=5.13.0",
|
|
45
|
-
"mkdocs-
|
|
48
|
+
"mkdocs-awesome-pages-plugin>=2.10.1",
|
|
46
49
|
"mkdocs-material>=9.6.15",
|
|
47
50
|
"mkdocs>=1.6.1",
|
|
48
51
|
"mkdocstrings-python>=1.16.12",
|
|
@@ -77,6 +80,9 @@ qtype = "qtype.cli:main"
|
|
|
77
80
|
include = ["qtype*"]
|
|
78
81
|
exclude = ["tests*"]
|
|
79
82
|
|
|
83
|
+
[tool.setuptools.package-data]
|
|
84
|
+
"qtype.interpreter" = ["ui/**/*"]
|
|
85
|
+
|
|
80
86
|
# Tool configurations
|
|
81
87
|
[tool.ruff]
|
|
82
88
|
line-length = 79
|
|
@@ -3,9 +3,7 @@ import logging
|
|
|
3
3
|
|
|
4
4
|
from pydantic_yaml import to_yaml_str
|
|
5
5
|
|
|
6
|
-
from qtype.
|
|
7
|
-
from qtype.converters.tools_from_module import tools_from_module
|
|
8
|
-
from qtype.dsl.model import ToolList
|
|
6
|
+
from qtype.dsl.model import Application
|
|
9
7
|
|
|
10
8
|
logger = logging.getLogger(__name__)
|
|
11
9
|
|
|
@@ -16,12 +14,27 @@ def convert_api(args: argparse.Namespace) -> None:
|
|
|
16
14
|
|
|
17
15
|
def convert_module(args: argparse.Namespace) -> None:
|
|
18
16
|
"""Convert Python module tools to qtype format."""
|
|
19
|
-
|
|
17
|
+
|
|
18
|
+
from qtype.commons.generate import _write_yaml_file
|
|
19
|
+
from qtype.converters.tools_from_module import tools_from_module
|
|
20
|
+
from qtype.dsl.model import ToolList
|
|
21
|
+
|
|
22
|
+
tools, types = tools_from_module(args.module_path) # type: ignore
|
|
20
23
|
if not tools:
|
|
21
24
|
raise ValueError(f"No tools found in the module: {args.module_path}")
|
|
25
|
+
|
|
26
|
+
if types:
|
|
27
|
+
doc = Application(
|
|
28
|
+
id=args.module_path,
|
|
29
|
+
description=f"Tools created from Python module {args.module_path}",
|
|
30
|
+
tools=list(tools),
|
|
31
|
+
types=types,
|
|
32
|
+
)
|
|
33
|
+
else:
|
|
34
|
+
doc = ToolList(root=list(tools))
|
|
22
35
|
|
|
23
36
|
if args.output:
|
|
24
|
-
_write_yaml_file(
|
|
37
|
+
_write_yaml_file(doc, args.output)
|
|
25
38
|
logger.info("Resulting yaml written to %s", args.output)
|
|
26
39
|
else:
|
|
27
40
|
logger.info(
|
|
@@ -4,13 +4,23 @@ import logging
|
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
from typing import Optional
|
|
6
6
|
|
|
7
|
-
from qtype.commons.generate import dump_commons_library
|
|
8
|
-
from qtype.dsl.document import generate_documentation
|
|
9
7
|
from qtype.dsl.model import Document
|
|
10
8
|
|
|
11
9
|
logger = logging.getLogger(__name__)
|
|
12
10
|
|
|
13
11
|
|
|
12
|
+
def run_dump_commons_library(args: argparse.Namespace) -> None:
|
|
13
|
+
from qtype.commons.generate import dump_commons_library
|
|
14
|
+
|
|
15
|
+
dump_commons_library(args)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def run_generate_documentation(args: argparse.Namespace) -> None:
|
|
19
|
+
from qtype.dsl.document import generate_documentation
|
|
20
|
+
|
|
21
|
+
generate_documentation(Path(args.output))
|
|
22
|
+
|
|
23
|
+
|
|
14
24
|
def generate_schema(args: argparse.Namespace) -> None:
|
|
15
25
|
"""Generate and output the JSON schema for Document.
|
|
16
26
|
|
|
@@ -51,7 +61,7 @@ def parser(subparsers: argparse._SubParsersAction) -> None:
|
|
|
51
61
|
default="./common/",
|
|
52
62
|
help="Output prefix for the YAML file (default: ./common/)",
|
|
53
63
|
)
|
|
54
|
-
commons_parser.set_defaults(func=
|
|
64
|
+
commons_parser.set_defaults(func=run_dump_commons_library)
|
|
55
65
|
|
|
56
66
|
# Parser for generating the json schema
|
|
57
67
|
schema_parser = generate_subparsers.add_parser(
|
|
@@ -74,12 +84,10 @@ def parser(subparsers: argparse._SubParsersAction) -> None:
|
|
|
74
84
|
"-o",
|
|
75
85
|
"--output",
|
|
76
86
|
type=str,
|
|
77
|
-
default="docs/
|
|
78
|
-
help="Output directory for the DSL documentation (default: docs/
|
|
79
|
-
)
|
|
80
|
-
dsl_parser.set_defaults(
|
|
81
|
-
func=lambda args: generate_documentation(Path(args.output))
|
|
87
|
+
default="docs/components/",
|
|
88
|
+
help="Output directory for the DSL documentation (default: docs/components/)",
|
|
82
89
|
)
|
|
90
|
+
dsl_parser.set_defaults(func=run_generate_documentation)
|
|
83
91
|
|
|
84
92
|
# Parser for generating the semantic model
|
|
85
93
|
# only add this if networkx and ruff are installed
|
|
@@ -47,46 +47,13 @@ def _telemetry(spec: Application) -> None:
|
|
|
47
47
|
register(spec.telemetry, spec.id)
|
|
48
48
|
|
|
49
49
|
|
|
50
|
-
def run_api(args: Any) -> None:
|
|
51
|
-
"""Run a QType YAML spec file as an API.
|
|
52
|
-
|
|
53
|
-
Args:
|
|
54
|
-
args: Arguments passed from the command line or calling context.
|
|
55
|
-
"""
|
|
56
|
-
spec = load(args.spec)
|
|
57
|
-
logger.info(f"Running API for spec: {args.spec}")
|
|
58
|
-
from qtype.interpreter.api import APIExecutor
|
|
59
|
-
|
|
60
|
-
# Get the name from the spec filename.
|
|
61
|
-
# so if filename is tests/specs/full_application_test.qtype.yaml, name should be "Full Application Test"
|
|
62
|
-
name = (
|
|
63
|
-
args.spec.split("/")[-1]
|
|
64
|
-
.replace(".qtype.yaml", "")
|
|
65
|
-
.replace("_", " ")
|
|
66
|
-
.title()
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
_telemetry(spec)
|
|
70
|
-
api_executor = APIExecutor(spec)
|
|
71
|
-
fastapi_app = api_executor.create_app(name=name)
|
|
72
|
-
|
|
73
|
-
import uvicorn
|
|
74
|
-
|
|
75
|
-
uvicorn.run(
|
|
76
|
-
fastapi_app,
|
|
77
|
-
host=args.host,
|
|
78
|
-
port=args.port,
|
|
79
|
-
log_level="info",
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
|
|
83
50
|
def run_flow(args: Any) -> None:
|
|
84
51
|
"""Run a QType YAML spec file by executing its flows.
|
|
85
52
|
|
|
86
53
|
Args:
|
|
87
54
|
args: Arguments passed from the command line or calling context.
|
|
88
55
|
"""
|
|
89
|
-
spec = load(args.spec)
|
|
56
|
+
spec, _ = load(args.spec)
|
|
90
57
|
|
|
91
58
|
flow = _get_flow(spec, args.flow)
|
|
92
59
|
logger.info(f"Executing flow: {flow.id}")
|
|
@@ -127,17 +94,6 @@ def run_flow(args: Any) -> None:
|
|
|
127
94
|
print("\n")
|
|
128
95
|
|
|
129
96
|
|
|
130
|
-
def run_ui(args: Any) -> None:
|
|
131
|
-
"""Run a QType YAML spec file by executing its flows in a UI.
|
|
132
|
-
|
|
133
|
-
Args:
|
|
134
|
-
args: Arguments passed from the command line or calling context.
|
|
135
|
-
"""
|
|
136
|
-
# Placeholder for actual implementation
|
|
137
|
-
logger.info(f"Running UI for spec: {args.spec}")
|
|
138
|
-
# Here you would implement the logic to run the flow in a UI context
|
|
139
|
-
|
|
140
|
-
|
|
141
97
|
def parser(subparsers: argparse._SubParsersAction) -> None:
|
|
142
98
|
"""Set up the run subcommand parser.
|
|
143
99
|
|
|
@@ -145,56 +101,23 @@ def parser(subparsers: argparse._SubParsersAction) -> None:
|
|
|
145
101
|
subparsers: The subparsers object to add the command to.
|
|
146
102
|
"""
|
|
147
103
|
cmd_parser = subparsers.add_parser(
|
|
148
|
-
"run", help="
|
|
104
|
+
"run", help="Executes a QType Application locally"
|
|
149
105
|
)
|
|
150
|
-
|
|
151
|
-
run_subparsers = cmd_parser.add_subparsers(
|
|
152
|
-
dest="run_method", required=True
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
# Parse for generating API runner
|
|
156
|
-
api_runner_parser = run_subparsers.add_parser(
|
|
157
|
-
"api", help="Serves the qtype file as an API."
|
|
158
|
-
)
|
|
159
|
-
api_runner_parser.add_argument(
|
|
160
|
-
"-H", "--host", type=str, default="localhost"
|
|
161
|
-
)
|
|
162
|
-
api_runner_parser.add_argument("-p", "--port", type=int, default=8000)
|
|
163
|
-
api_runner_parser.set_defaults(func=run_api)
|
|
164
|
-
|
|
165
|
-
# Parse for running a flow
|
|
166
|
-
flow_parser = run_subparsers.add_parser(
|
|
167
|
-
"flow", help="Runs a QType YAML spec file by executing its flows."
|
|
168
|
-
)
|
|
169
|
-
flow_parser.add_argument(
|
|
106
|
+
cmd_parser.add_argument(
|
|
170
107
|
"-f",
|
|
171
108
|
"--flow",
|
|
172
109
|
type=str,
|
|
173
110
|
default=None,
|
|
174
111
|
help="The name of the flow to run. If not specified, runs the first flow found.",
|
|
175
112
|
)
|
|
176
|
-
|
|
113
|
+
cmd_parser.add_argument(
|
|
177
114
|
"input",
|
|
178
115
|
type=str,
|
|
179
116
|
help="JSON blob of input values for the flow.",
|
|
180
117
|
)
|
|
181
118
|
|
|
182
|
-
flow_parser.set_defaults(func=run_flow)
|
|
183
|
-
|
|
184
|
-
# Run a user interface for the spec
|
|
185
|
-
ui_parser = run_subparsers.add_parser(
|
|
186
|
-
"ui",
|
|
187
|
-
help="Runs a QType YAML spec file by executing its flows in a UI.",
|
|
188
|
-
)
|
|
189
|
-
ui_parser.add_argument(
|
|
190
|
-
"-f",
|
|
191
|
-
"--flow",
|
|
192
|
-
type=str,
|
|
193
|
-
default=None,
|
|
194
|
-
help="The name of the flow to run in the UI. If not specified, runs the first flow found.",
|
|
195
|
-
)
|
|
196
|
-
ui_parser.set_defaults(func=run_ui)
|
|
197
|
-
|
|
198
119
|
cmd_parser.add_argument(
|
|
199
120
|
"spec", type=str, help="Path to the QType YAML spec file."
|
|
200
121
|
)
|
|
122
|
+
|
|
123
|
+
cmd_parser.set_defaults(func=run_flow)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Command-line interface for running QType YAML spec files.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
import logging
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
import uvicorn
|
|
12
|
+
|
|
13
|
+
from qtype.commands.run import _telemetry
|
|
14
|
+
from qtype.loader import load
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def serve(args: Any) -> None:
|
|
20
|
+
"""Run a QType YAML spec file as an API.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
args: Arguments passed from the command line or calling context.
|
|
24
|
+
"""
|
|
25
|
+
spec, _ = load(args.spec)
|
|
26
|
+
logger.info(f"Running API for spec: {args.spec}")
|
|
27
|
+
from qtype.interpreter.api import APIExecutor
|
|
28
|
+
|
|
29
|
+
# Get the name from the spec filename.
|
|
30
|
+
# so if filename is tests/specs/full_application_test.qtype.yaml, name should be "Full Application Test"
|
|
31
|
+
name = (
|
|
32
|
+
args.spec.split("/")[-1]
|
|
33
|
+
.replace(".qtype.yaml", "")
|
|
34
|
+
.replace("_", " ")
|
|
35
|
+
.title()
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
_telemetry(spec)
|
|
39
|
+
api_executor = APIExecutor(spec)
|
|
40
|
+
fastapi_app = api_executor.create_app(
|
|
41
|
+
name=name, ui_enabled=not args.disable_ui
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
uvicorn.run(
|
|
45
|
+
fastapi_app,
|
|
46
|
+
host=args.host,
|
|
47
|
+
port=args.port,
|
|
48
|
+
log_level="info",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def parser(subparsers: argparse._SubParsersAction) -> None:
|
|
53
|
+
"""Set up the run subcommand parser.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
subparsers: The subparsers object to add the command to.
|
|
57
|
+
"""
|
|
58
|
+
cmd_parser = subparsers.add_parser(
|
|
59
|
+
"serve", help="Serve a web experience for a QType application"
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
cmd_parser.add_argument("-p", "--port", type=int, default=8000)
|
|
63
|
+
cmd_parser.add_argument("-H", "--host", type=str, default="localhost")
|
|
64
|
+
cmd_parser.add_argument(
|
|
65
|
+
"--disable-ui",
|
|
66
|
+
action="store_true",
|
|
67
|
+
help="Disable the UI for the QType application.",
|
|
68
|
+
)
|
|
69
|
+
cmd_parser.set_defaults(func=serve)
|
|
70
|
+
|
|
71
|
+
cmd_parser.add_argument(
|
|
72
|
+
"spec", type=str, help="Path to the QType YAML spec file."
|
|
73
|
+
)
|
|
@@ -10,8 +10,13 @@ from typing import Any
|
|
|
10
10
|
from pydantic import ValidationError
|
|
11
11
|
|
|
12
12
|
from qtype import dsl
|
|
13
|
+
from qtype.dsl.custom_types import build_dynamic_types
|
|
13
14
|
from qtype.dsl.validator import QTypeValidationError, validate
|
|
14
|
-
from qtype.loader import
|
|
15
|
+
from qtype.loader import (
|
|
16
|
+
_list_dynamic_types_from_document,
|
|
17
|
+
_resolve_root,
|
|
18
|
+
load_yaml,
|
|
19
|
+
)
|
|
15
20
|
from qtype.semantic.errors import SemanticResolutionError
|
|
16
21
|
from qtype.semantic.resolver import resolve
|
|
17
22
|
|
|
@@ -30,29 +35,34 @@ def main(args: Any) -> None:
|
|
|
30
35
|
"""
|
|
31
36
|
try:
|
|
32
37
|
yaml_data = load_yaml(args.spec)
|
|
38
|
+
dynamic_types_lists = _list_dynamic_types_from_document(yaml_data)
|
|
39
|
+
dynamic_types_registry = build_dynamic_types(dynamic_types_lists)
|
|
33
40
|
logging.info("✅ Schema validation successful.")
|
|
34
|
-
|
|
41
|
+
|
|
42
|
+
document = dsl.Document.model_validate(
|
|
43
|
+
yaml_data, context={"custom_types": dynamic_types_registry}
|
|
44
|
+
)
|
|
35
45
|
logging.info("✅ Model validation successful.")
|
|
36
|
-
|
|
37
|
-
if not isinstance(
|
|
46
|
+
root = _resolve_root(document)
|
|
47
|
+
if not isinstance(root, dsl.Application):
|
|
38
48
|
logging.warning(
|
|
39
49
|
"🟨 Spec is not an Application, skipping semantic resolution."
|
|
40
50
|
)
|
|
41
51
|
else:
|
|
42
|
-
|
|
52
|
+
root = validate(root)
|
|
43
53
|
logger.info("✅ Language validation successful")
|
|
44
|
-
|
|
54
|
+
app = resolve(root)
|
|
45
55
|
logger.info("✅ Semantic validation successful")
|
|
46
56
|
if args.print:
|
|
47
57
|
logger.info(
|
|
48
|
-
|
|
58
|
+
(app if "app" in locals() else root).model_dump_json( # type: ignore
|
|
49
59
|
indent=2,
|
|
50
60
|
exclude_none=True,
|
|
51
61
|
)
|
|
52
62
|
)
|
|
53
63
|
|
|
54
64
|
except ValidationError as exc:
|
|
55
|
-
logger.error("❌
|
|
65
|
+
logger.error("❌ Validation failed:\n%s", exc)
|
|
56
66
|
sys.exit(1)
|
|
57
67
|
except QTypeValidationError as exc:
|
|
58
68
|
logger.error("❌ DSL validation failed:\n%s", exc)
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Command-line interface for visualizing QType YAML spec files.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import logging
|
|
7
|
+
import tempfile
|
|
8
|
+
import webbrowser
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from qtype.loader import load
|
|
12
|
+
from qtype.semantic.visualize import visualize_application
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def main(args: Any) -> None:
|
|
18
|
+
"""
|
|
19
|
+
visualize a QType YAML spec file against the QTypeSpec schema and semantics.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
args: Arguments passed from the command line or calling context.
|
|
23
|
+
|
|
24
|
+
Exits:
|
|
25
|
+
Exits with code 1 if validation fails.
|
|
26
|
+
"""
|
|
27
|
+
import mermaid as md
|
|
28
|
+
|
|
29
|
+
application, _ = load(args.spec)
|
|
30
|
+
|
|
31
|
+
diagram = visualize_application(application)
|
|
32
|
+
|
|
33
|
+
render = None
|
|
34
|
+
if args.output:
|
|
35
|
+
if args.output.endswith(".mmd") or args.output.endswith(".mermaid"):
|
|
36
|
+
with open(args.output, "w") as f:
|
|
37
|
+
f.write(diagram)
|
|
38
|
+
logger.info(f"Mermaid diagram written to {args.output}")
|
|
39
|
+
elif args.output.endswith(".svg"):
|
|
40
|
+
render = md.Mermaid(diagram)
|
|
41
|
+
render.to_svg(args.output)
|
|
42
|
+
logger.info(f"SVG diagram written to {args.output}")
|
|
43
|
+
|
|
44
|
+
elif args.output.endswith(".png"):
|
|
45
|
+
render = md.Mermaid(diagram)
|
|
46
|
+
render.to_png(args.output)
|
|
47
|
+
logger.info(f"PNG diagram written to {args.output}")
|
|
48
|
+
|
|
49
|
+
if not args.no_display:
|
|
50
|
+
if not render:
|
|
51
|
+
render = md.Mermaid(diagram)
|
|
52
|
+
|
|
53
|
+
html_content = render._repr_html_()
|
|
54
|
+
# Create a temporary HTML file to display the diagram
|
|
55
|
+
with tempfile.NamedTemporaryFile(
|
|
56
|
+
delete=False, suffix=".html"
|
|
57
|
+
) as temp_file:
|
|
58
|
+
temp_file.write(html_content.encode("utf-8"))
|
|
59
|
+
webbrowser.open(temp_file.name)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def parser(subparsers: argparse._SubParsersAction) -> None:
|
|
63
|
+
"""Set up the visualize subcommand parser.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
subparsers: The subparsers object to add the command to.
|
|
67
|
+
"""
|
|
68
|
+
cmd_parser = subparsers.add_parser(
|
|
69
|
+
"visualize", help="Visualize a QType Application."
|
|
70
|
+
)
|
|
71
|
+
cmd_parser.add_argument(
|
|
72
|
+
"spec", type=str, help="Path to the QType YAML file."
|
|
73
|
+
)
|
|
74
|
+
cmd_parser.add_argument(
|
|
75
|
+
"-o",
|
|
76
|
+
"--output",
|
|
77
|
+
type=str,
|
|
78
|
+
default=None,
|
|
79
|
+
help="If provided, write the mermaid diagram to this file.",
|
|
80
|
+
)
|
|
81
|
+
cmd_parser.add_argument(
|
|
82
|
+
"-nd",
|
|
83
|
+
"--no-display",
|
|
84
|
+
action="store_true",
|
|
85
|
+
help="If set don't display the diagram in a browser (default: False).",
|
|
86
|
+
)
|
|
87
|
+
cmd_parser.set_defaults(func=main)
|