qtype 0.0.1__py3-none-any.whl
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/__init__.py +0 -0
- qtype/cli.py +73 -0
- qtype/commands/__init__.py +5 -0
- qtype/commands/convert.py +76 -0
- qtype/commands/generate.py +107 -0
- qtype/commands/run.py +200 -0
- qtype/commands/validate.py +83 -0
- qtype/commons/__init__.py +0 -0
- qtype/commons/generate.py +88 -0
- qtype/commons/tools.py +192 -0
- qtype/converters/__init__.py +0 -0
- qtype/converters/tools_from_api.py +24 -0
- qtype/converters/tools_from_module.py +326 -0
- qtype/converters/types.py +20 -0
- qtype/dsl/__init__.py +1 -0
- qtype/dsl/base_types.py +31 -0
- qtype/dsl/document.py +108 -0
- qtype/dsl/domain_types.py +56 -0
- qtype/dsl/model.py +685 -0
- qtype/dsl/validator.py +439 -0
- qtype/interpreter/__init__.py +1 -0
- qtype/interpreter/api.py +104 -0
- qtype/interpreter/conversions.py +148 -0
- qtype/interpreter/exceptions.py +10 -0
- qtype/interpreter/flow.py +37 -0
- qtype/interpreter/resource_cache.py +37 -0
- qtype/interpreter/step.py +67 -0
- qtype/interpreter/steps/__init__.py +0 -0
- qtype/interpreter/steps/agent.py +114 -0
- qtype/interpreter/steps/condition.py +36 -0
- qtype/interpreter/steps/decoder.py +84 -0
- qtype/interpreter/steps/llm_inference.py +127 -0
- qtype/interpreter/steps/prompt_template.py +54 -0
- qtype/interpreter/steps/search.py +24 -0
- qtype/interpreter/steps/tool.py +53 -0
- qtype/interpreter/telemetry.py +16 -0
- qtype/interpreter/typing.py +78 -0
- qtype/loader.py +341 -0
- qtype/semantic/__init__.py +0 -0
- qtype/semantic/errors.py +4 -0
- qtype/semantic/generate.py +383 -0
- qtype/semantic/model.py +354 -0
- qtype/semantic/resolver.py +97 -0
- qtype-0.0.1.dist-info/METADATA +120 -0
- qtype-0.0.1.dist-info/RECORD +49 -0
- qtype-0.0.1.dist-info/WHEEL +5 -0
- qtype-0.0.1.dist-info/entry_points.txt +2 -0
- qtype-0.0.1.dist-info/licenses/LICENSE +202 -0
- qtype-0.0.1.dist-info/top_level.txt +1 -0
qtype/semantic/model.py
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Semantic Intermediate Representation models.
|
|
3
|
+
|
|
4
|
+
This module contains the semantic models that represent a resolved QType
|
|
5
|
+
specification where all ID references have been replaced with actual object
|
|
6
|
+
references.
|
|
7
|
+
|
|
8
|
+
Generated automatically with command:
|
|
9
|
+
qtype generate semantic-model
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
17
|
+
|
|
18
|
+
# Import enums and type aliases from DSL
|
|
19
|
+
from qtype.dsl.model import VariableType # noqa: F401
|
|
20
|
+
from qtype.dsl.model import (
|
|
21
|
+
ArrayTypeDefinition,
|
|
22
|
+
DecoderFormat,
|
|
23
|
+
ObjectTypeDefinition,
|
|
24
|
+
StructuralTypeEnum,
|
|
25
|
+
)
|
|
26
|
+
from qtype.dsl.model import Variable as DSLVariable # noqa: F401
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class Variable(DSLVariable, BaseModel):
|
|
30
|
+
"""Semantic version of DSL Variable with ID references resolved."""
|
|
31
|
+
|
|
32
|
+
value: Any | None = Field(None, description="The value of the variable")
|
|
33
|
+
|
|
34
|
+
def is_set(self) -> bool:
|
|
35
|
+
return self.value is not None
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ImmutableModel(BaseModel):
|
|
39
|
+
"""Base model that can't be mutated but can be cached."""
|
|
40
|
+
|
|
41
|
+
id: str = Field(..., description="Unique ID of this model.")
|
|
42
|
+
|
|
43
|
+
model_config = ConfigDict(frozen=True)
|
|
44
|
+
|
|
45
|
+
def __hash__(self) -> int:
|
|
46
|
+
return hash(self.id) # Hash based on a hashable field
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class Application(BaseModel):
|
|
50
|
+
"""Defines a QType application that can include models, variables, and other components."""
|
|
51
|
+
|
|
52
|
+
id: str = Field(..., description="Unique ID of the application.")
|
|
53
|
+
description: str | None = Field(
|
|
54
|
+
None, description="Optional description of the application."
|
|
55
|
+
)
|
|
56
|
+
memories: list[Memory] = Field(
|
|
57
|
+
[], description="List of memory definitions used in this application."
|
|
58
|
+
)
|
|
59
|
+
models: list[Model] = Field(
|
|
60
|
+
[], description="List of models used in this application."
|
|
61
|
+
)
|
|
62
|
+
types: list[ObjectTypeDefinition | ArrayTypeDefinition] = Field(
|
|
63
|
+
[], description="List of custom types defined in this application."
|
|
64
|
+
)
|
|
65
|
+
variables: list[Variable] = Field(
|
|
66
|
+
[], description="List of variables used in this application."
|
|
67
|
+
)
|
|
68
|
+
flows: list[Flow] = Field(
|
|
69
|
+
[], description="List of flows defined in this application."
|
|
70
|
+
)
|
|
71
|
+
auths: list[AuthorizationProvider] = Field(
|
|
72
|
+
[], description="List of authorization providers used for API access."
|
|
73
|
+
)
|
|
74
|
+
tools: list[Tool] = Field(
|
|
75
|
+
[], description="List of tools available in this application."
|
|
76
|
+
)
|
|
77
|
+
indexes: list[Index] = Field(
|
|
78
|
+
[], description="List of indexes available for search operations."
|
|
79
|
+
)
|
|
80
|
+
telemetry: TelemetrySink | None = Field(
|
|
81
|
+
None, description="Optional telemetry sink for observability."
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class AuthorizationProvider(ImmutableModel):
|
|
86
|
+
"""Defines how tools or providers authenticate with APIs, such as OAuth2 or API keys."""
|
|
87
|
+
|
|
88
|
+
id: str = Field(
|
|
89
|
+
..., description="Unique ID of the authorization configuration."
|
|
90
|
+
)
|
|
91
|
+
api_key: str | None = Field(
|
|
92
|
+
None, description="API key if using token-based auth."
|
|
93
|
+
)
|
|
94
|
+
client_id: str | None = Field(None, description="OAuth2 client ID.")
|
|
95
|
+
client_secret: str | None = Field(
|
|
96
|
+
None, description="OAuth2 client secret."
|
|
97
|
+
)
|
|
98
|
+
host: str | None = Field(
|
|
99
|
+
None, description="Base URL or domain of the provider."
|
|
100
|
+
)
|
|
101
|
+
scopes: list[str] = Field([], description="OAuth2 scopes required.")
|
|
102
|
+
token_url: str | None = Field(None, description="Token endpoint URL.")
|
|
103
|
+
type: str = Field(
|
|
104
|
+
..., description="Authorization method, e.g., 'oauth2' or 'api_key'."
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class Step(BaseModel):
|
|
109
|
+
"""Base class for components that take inputs and produce outputs."""
|
|
110
|
+
|
|
111
|
+
id: str = Field(..., description="Unique ID of this component.")
|
|
112
|
+
inputs: list[Variable] = Field(
|
|
113
|
+
[], description="Input variables required by this step."
|
|
114
|
+
)
|
|
115
|
+
outputs: list[Variable] = Field(
|
|
116
|
+
[], description="Variable where output is stored."
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class Index(ImmutableModel):
|
|
121
|
+
"""Base class for searchable indexes that can be queried by search steps."""
|
|
122
|
+
|
|
123
|
+
id: str = Field(..., description="Unique ID of the index.")
|
|
124
|
+
args: dict[str, Any] = Field(
|
|
125
|
+
{},
|
|
126
|
+
description="Index-specific configuration and connection parameters.",
|
|
127
|
+
)
|
|
128
|
+
auth: AuthorizationProvider | None = Field(
|
|
129
|
+
None, description="AuthorizationProvider for accessing the index."
|
|
130
|
+
)
|
|
131
|
+
name: str = Field(..., description="Name of the index/collection/table.")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class Model(ImmutableModel):
|
|
135
|
+
"""Describes a generative model configuration, including provider and model ID."""
|
|
136
|
+
|
|
137
|
+
id: str = Field(..., description="Unique ID for the model.")
|
|
138
|
+
auth: AuthorizationProvider | None = Field(
|
|
139
|
+
None, description="AuthorizationProvider used for model access."
|
|
140
|
+
)
|
|
141
|
+
inference_params: dict[str, Any] = Field(
|
|
142
|
+
{},
|
|
143
|
+
description="Optional inference parameters like temperature or max_tokens.",
|
|
144
|
+
)
|
|
145
|
+
model_id: str | None = Field(
|
|
146
|
+
None,
|
|
147
|
+
description="The specific model name or ID for the provider. If None, id is used",
|
|
148
|
+
)
|
|
149
|
+
provider: str = Field(
|
|
150
|
+
..., description="Name of the provider, e.g., openai or anthropic."
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class Memory(ImmutableModel):
|
|
155
|
+
"""Session or persistent memory used to store relevant conversation or state data across steps or turns."""
|
|
156
|
+
|
|
157
|
+
id: str = Field(..., description="Unique ID of the memory block.")
|
|
158
|
+
token_limit: int = Field(
|
|
159
|
+
100000, description="Maximum number of tokens to store in memory."
|
|
160
|
+
)
|
|
161
|
+
chat_history_token_ratio: float = Field(
|
|
162
|
+
0.7, description="Ratio of chat history tokens to total memory tokens."
|
|
163
|
+
)
|
|
164
|
+
token_flush_size: int = Field(
|
|
165
|
+
3000,
|
|
166
|
+
description="Size of memory to flush when it exceeds the token limit.",
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class TelemetrySink(BaseModel):
|
|
171
|
+
"""Defines an observability endpoint for collecting telemetry data from the QType runtime."""
|
|
172
|
+
|
|
173
|
+
id: str = Field(
|
|
174
|
+
..., description="Unique ID of the telemetry sink configuration."
|
|
175
|
+
)
|
|
176
|
+
auth: AuthorizationProvider | None = Field(
|
|
177
|
+
None,
|
|
178
|
+
description="AuthorizationProvider used to authenticate telemetry data transmission.",
|
|
179
|
+
)
|
|
180
|
+
endpoint: str = Field(
|
|
181
|
+
..., description="URL endpoint where telemetry data will be sent."
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class TypeDefinitionBase(BaseModel):
|
|
186
|
+
"""Semantic version of TypeDefinitionBase."""
|
|
187
|
+
|
|
188
|
+
id: str = Field(
|
|
189
|
+
..., description="The unique identifier for this custom type."
|
|
190
|
+
)
|
|
191
|
+
kind: StructuralTypeEnum = Field(
|
|
192
|
+
...,
|
|
193
|
+
description="The kind of structure this type represents (object/array).",
|
|
194
|
+
)
|
|
195
|
+
description: str | None = Field(
|
|
196
|
+
None, description="A description of what this type represents."
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class Condition(Step):
|
|
201
|
+
"""Conditional logic gate within a flow. Supports branching logic for execution based on variable values."""
|
|
202
|
+
|
|
203
|
+
else_: Step | None = Field(
|
|
204
|
+
None,
|
|
205
|
+
description="Optional step to run if condition fails.",
|
|
206
|
+
alias="else",
|
|
207
|
+
)
|
|
208
|
+
equals: Variable | None = Field(
|
|
209
|
+
None, description="Match condition for equality check."
|
|
210
|
+
)
|
|
211
|
+
then: Step = Field(..., description="Step to run if condition matches.")
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
class Decoder(Step):
|
|
215
|
+
"""Defines a step that decodes string data into structured outputs.
|
|
216
|
+
|
|
217
|
+
If parsing fails, the step will raise an error and halt execution.
|
|
218
|
+
Use conditional logic in your flow to handle potential parsing errors.
|
|
219
|
+
"""
|
|
220
|
+
|
|
221
|
+
format: DecoderFormat = Field(
|
|
222
|
+
DecoderFormat.json,
|
|
223
|
+
description="Format in which the decoder processes data. Defaults to JSON.",
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
class Flow(Step):
|
|
228
|
+
"""Defines a flow of steps that can be executed in sequence or parallel.
|
|
229
|
+
If input or output variables are not specified, they are inferred from
|
|
230
|
+
the first and last step, respectively.
|
|
231
|
+
"""
|
|
232
|
+
|
|
233
|
+
steps: list[Step] = Field(..., description="List of steps or step IDs.")
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
class LLMInference(Step):
|
|
237
|
+
"""Defines a step that performs inference using a language model.
|
|
238
|
+
It can take input variables and produce output variables based on the model's response."""
|
|
239
|
+
|
|
240
|
+
memory: Memory | None = Field(
|
|
241
|
+
None,
|
|
242
|
+
description="Memory object to retain context across interactions.",
|
|
243
|
+
)
|
|
244
|
+
model: Model = Field(..., description="The model to use for inference.")
|
|
245
|
+
system_message: str | None = Field(
|
|
246
|
+
None,
|
|
247
|
+
description="Optional system message to set the context for the model.",
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
class PromptTemplate(Step):
|
|
252
|
+
"""Defines a prompt template with a string format and variable bindings.
|
|
253
|
+
This is used to generate prompts dynamically based on input variables."""
|
|
254
|
+
|
|
255
|
+
template: str = Field(
|
|
256
|
+
...,
|
|
257
|
+
description="String template for the prompt with variable placeholders.",
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
class Search(Step):
|
|
262
|
+
"""Base class for search operations against indexes."""
|
|
263
|
+
|
|
264
|
+
filters: dict[str, Any] = Field(
|
|
265
|
+
{}, description="Optional filters to apply during search."
|
|
266
|
+
)
|
|
267
|
+
index: Index = Field(
|
|
268
|
+
..., description="Index to search against (object or ID reference)."
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
class Tool(Step):
|
|
273
|
+
"""
|
|
274
|
+
Base class for callable functions or external operations available to the model or as a step in a flow.
|
|
275
|
+
"""
|
|
276
|
+
|
|
277
|
+
name: str = Field(..., description="Name of the tool function.")
|
|
278
|
+
description: str = Field(
|
|
279
|
+
..., description="Description of what the tool does."
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class DocumentIndex(Index):
|
|
284
|
+
"""Document search index for text-based search (e.g., Elasticsearch, OpenSearch)."""
|
|
285
|
+
|
|
286
|
+
pass
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
class VectorIndex(Index):
|
|
290
|
+
"""Vector database index for similarity search using embeddings."""
|
|
291
|
+
|
|
292
|
+
embedding_model: EmbeddingModel = Field(
|
|
293
|
+
...,
|
|
294
|
+
description="Embedding model used to vectorize queries and documents.",
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
class EmbeddingModel(Model):
|
|
299
|
+
"""Describes an embedding model configuration, extending the base Model class."""
|
|
300
|
+
|
|
301
|
+
dimensions: int = Field(
|
|
302
|
+
...,
|
|
303
|
+
description="Dimensionality of the embedding vectors produced by this model.",
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
class Agent(LLMInference):
|
|
308
|
+
"""Defines an agent that can perform tasks and make decisions based on user input and context."""
|
|
309
|
+
|
|
310
|
+
tools: list[Tool] = Field(
|
|
311
|
+
..., description="List of tools available to the agent."
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
class DocumentSearch(Search):
|
|
316
|
+
"""Performs document search against a document index."""
|
|
317
|
+
|
|
318
|
+
pass
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
class VectorSearch(Search):
|
|
322
|
+
"""Performs vector similarity search against a vector index."""
|
|
323
|
+
|
|
324
|
+
default_top_k: int | None = Field(
|
|
325
|
+
...,
|
|
326
|
+
description="Number of top results to retrieve if not provided in the inputs.",
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
class APITool(Tool):
|
|
331
|
+
"""Tool that invokes an API endpoint."""
|
|
332
|
+
|
|
333
|
+
endpoint: str = Field(..., description="API endpoint URL to call.")
|
|
334
|
+
method: str = Field(
|
|
335
|
+
"GET", description="HTTP method to use (GET, POST, PUT, DELETE, etc.)."
|
|
336
|
+
)
|
|
337
|
+
auth: AuthorizationProvider | None = Field(
|
|
338
|
+
None,
|
|
339
|
+
description="Optional AuthorizationProvider for API authentication.",
|
|
340
|
+
)
|
|
341
|
+
headers: dict[str, str] = Field(
|
|
342
|
+
{}, description="Optional HTTP headers to include in the request."
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
class PythonFunctionTool(Tool):
|
|
347
|
+
"""Tool that calls a Python function."""
|
|
348
|
+
|
|
349
|
+
function_name: str = Field(
|
|
350
|
+
..., description="Name of the Python function to call."
|
|
351
|
+
)
|
|
352
|
+
module_path: str = Field(
|
|
353
|
+
..., description="Optional module path where the function is defined."
|
|
354
|
+
)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Semantic resolution logic for QType.
|
|
3
|
+
|
|
4
|
+
This module contains functions to transform DSL QTypeSpec objects into their
|
|
5
|
+
semantic intermediate representation equivalents, where all ID references
|
|
6
|
+
are resolved to actual object references.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
import qtype.dsl.domain_types
|
|
13
|
+
import qtype.dsl.model as dsl
|
|
14
|
+
from qtype.dsl.validator import _is_dsl_type, _resolve_forward_ref
|
|
15
|
+
from qtype.semantic import model as ir
|
|
16
|
+
from qtype.semantic.errors import SemanticResolutionError
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
FIELDS_TO_IGNORE = {"Application.references"}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def to_semantic_ir(
|
|
24
|
+
dslobj: qtype.dsl.domain_types.StrictBaseModel,
|
|
25
|
+
symbol_table: dict[str, Any],
|
|
26
|
+
) -> Any:
|
|
27
|
+
"""
|
|
28
|
+
Convert a DSL QTypeSpec object to its semantic intermediate representation (IR).
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
dsl: The DSL QTypeSpec object to convert.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
ir.Application: The semantic IR representation of the DSL object.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
obj_id = getattr(dslobj, "id", None)
|
|
38
|
+
if obj_id and obj_id in symbol_table:
|
|
39
|
+
# If the object is already in the symbol table, return it.
|
|
40
|
+
return symbol_table[obj_id]
|
|
41
|
+
|
|
42
|
+
if isinstance(dslobj, list):
|
|
43
|
+
# If the object is a list, we will resolve each item in the list.
|
|
44
|
+
return [to_semantic_ir(item, symbol_table) for item in dslobj] # type: ignore
|
|
45
|
+
|
|
46
|
+
if isinstance(dslobj, dsl.Enum):
|
|
47
|
+
# if the variable is an enum, just return it. The semantic classes use the same class
|
|
48
|
+
return dslobj
|
|
49
|
+
|
|
50
|
+
if _is_dsl_type(_resolve_forward_ref(type(dslobj))):
|
|
51
|
+
# If the object is a DSL type, we will resolve it to its semantic IR.
|
|
52
|
+
# First get the constructor with the same class name. i.e., dsl.Application -> ir.Application
|
|
53
|
+
class_name = dslobj.__class__.__name__
|
|
54
|
+
ir_class = getattr(ir, class_name, None)
|
|
55
|
+
if not ir_class:
|
|
56
|
+
raise SemanticResolutionError(
|
|
57
|
+
f"Could not find Semantic class for DSL type: {class_name}"
|
|
58
|
+
)
|
|
59
|
+
# iterate over the parameters of the DSL object and convert them to their semantic IR equivalents.
|
|
60
|
+
params = {
|
|
61
|
+
name: to_semantic_ir(value, symbol_table)
|
|
62
|
+
for name, value in dslobj
|
|
63
|
+
if f"{class_name}.{name}" not in FIELDS_TO_IGNORE
|
|
64
|
+
}
|
|
65
|
+
ir.Variable.model_rebuild()
|
|
66
|
+
result = ir_class(**params)
|
|
67
|
+
symbol_table[obj_id] = result # type: ignore
|
|
68
|
+
return result
|
|
69
|
+
elif isinstance(dslobj, list):
|
|
70
|
+
return [to_semantic_ir(item, symbol_table) for item in dslobj] # type: ignore
|
|
71
|
+
else:
|
|
72
|
+
return dslobj
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def resolve(application: dsl.Application) -> ir.Application:
|
|
76
|
+
"""
|
|
77
|
+
Resolve a DSL Application into its semantic intermediate representation.
|
|
78
|
+
|
|
79
|
+
This function transforms the DSL Application into its IR equivalent,
|
|
80
|
+
resolving all ID references to actual object references.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
application: The DSL Application to transform
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
dsl.Application: The resolved IR application
|
|
87
|
+
"""
|
|
88
|
+
# Next, we'll build up the semantic representation.
|
|
89
|
+
# This will create a map of all objects by their ID, ensuring that we can resolve
|
|
90
|
+
# references to actual objects.
|
|
91
|
+
result = to_semantic_ir(application, {})
|
|
92
|
+
if not isinstance(result, ir.Application):
|
|
93
|
+
raise SemanticResolutionError(
|
|
94
|
+
"The root object must be an Application, but got: "
|
|
95
|
+
f"{type(result).__name__}"
|
|
96
|
+
)
|
|
97
|
+
return result
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: qtype
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: DSL for Generative AI Prototyping
|
|
5
|
+
Author-email: Lou Kratz <lou.kratz+qtype@bazaarvoice.com>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/bazaarvoice/qtype
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: jsonschema>=4.24.0
|
|
12
|
+
Requires-Dist: pydantic>=2.11.5
|
|
13
|
+
Requires-Dist: pyyaml>=6.0.2
|
|
14
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
15
|
+
Requires-Dist: openai>=1.93.0
|
|
16
|
+
Requires-Dist: fsspec>=2025.5.1
|
|
17
|
+
Requires-Dist: pydantic-yaml>=1.5.1
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# QType
|
|
21
|
+
|
|
22
|
+
**QType is a domain-specific language (DSL) for rapid prototyping of AI applications.**
|
|
23
|
+
It is designed to help developers define modular, composable AI systems using a structured YAML-based specification. QType supports models, prompts, tools, retrievers, and flow orchestration, and is extensible for code generation or live interpretation.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 🚀 Quick Start
|
|
28
|
+
|
|
29
|
+
Install QType:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install qtype[interpreter]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Create a file `hello_world.qtype.yaml` that executes a single chat question:
|
|
36
|
+
```yaml
|
|
37
|
+
id: hello_world
|
|
38
|
+
flows:
|
|
39
|
+
- id: simple_qa_flow
|
|
40
|
+
steps:
|
|
41
|
+
- id: llm_inference_step
|
|
42
|
+
model:
|
|
43
|
+
id: gpt-4o
|
|
44
|
+
provider: openai
|
|
45
|
+
auth:
|
|
46
|
+
id: openai_auth
|
|
47
|
+
type: api_key
|
|
48
|
+
api_key: ${OPENAI_KEY}
|
|
49
|
+
system_message: |
|
|
50
|
+
You are a helpful assistant.
|
|
51
|
+
inputs:
|
|
52
|
+
- id: prompt
|
|
53
|
+
type: text
|
|
54
|
+
outputs:
|
|
55
|
+
- id: response_message
|
|
56
|
+
type: text
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Put your openai api key into your `.env` file:
|
|
60
|
+
```
|
|
61
|
+
echo "OPENAI_KEY=sk...." >> .env
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Validate that the file matches the spec:
|
|
65
|
+
```
|
|
66
|
+
qtype validate hello_world.qtype.yaml
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
You should see:
|
|
70
|
+
```
|
|
71
|
+
INFO: ✅ Schema validation successful.
|
|
72
|
+
INFO: ✅ Model validation successful.
|
|
73
|
+
INFO: ✅ Language validation successful
|
|
74
|
+
INFO: ✅ Semantic validation successful
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Finally,execute the flow.
|
|
78
|
+
```
|
|
79
|
+
qtype run flow '{"prompt":"What is the airspeed of a laden swallow?"}' hello_world.qtype.yaml
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
You should see (something similar to):
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
INFO: Executing flow: simple_qa_flow
|
|
86
|
+
|
|
87
|
+
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.
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
See the [full docs](https://bazaarvoice.github.io/qtype/) for more examples and guides.
|
|
93
|
+
|
|
94
|
+
## 🤝 Contributing
|
|
95
|
+
|
|
96
|
+
Contributions welcome! Please follow the instructions in the [contribution guide](https://bazaarvoice.github.io/qtype/contributing/).
|
|
97
|
+
|
|
98
|
+
## 📄 License
|
|
99
|
+
|
|
100
|
+
This project is licensed under the **MIT License**.
|
|
101
|
+
See the [LICENSE](./LICENSE) file for details.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 🧠 Philosophy
|
|
106
|
+
|
|
107
|
+
QType is built around modularity, traceability, and rapid iteration. It aims to empower developers to quickly scaffold ideas into usable AI applications without sacrificing maintainability or control.
|
|
108
|
+
|
|
109
|
+
Stay tuned for upcoming features like:
|
|
110
|
+
- Integrated OpenTelemetry tracing
|
|
111
|
+
- Validation via LLM-as-a-judge
|
|
112
|
+
- UI hinting via input display types
|
|
113
|
+
- Flow state switching and conditional routing
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
Happy hacking with QType! 🛠️
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
[](https://github.com/bazaarvoice/qtype/actions/workflows/github_workflows_generate-schema.yml) [](https://github.com/bazaarvoice/qtype/actions/workflows/publish-pypi.yml)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
qtype/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
qtype/cli.py,sha256=TjqZ6N0RGRZAcFm8Q6WkzXS_oV6cvYvsmbFdP8x9a-o,2113
|
|
3
|
+
qtype/loader.py,sha256=4Ty5B0qWNQeehexh0anlP7hDmsso0bj7-IVt5VqnHWA,10992
|
|
4
|
+
qtype/commands/__init__.py,sha256=Qo4M07zm5I63r8STxDjvt5fhP1jygdXTsExNGELkefc,257
|
|
5
|
+
qtype/commands/convert.py,sha256=Mkk8BAJDOmZ_nPsa0YtzjdxxBMScWk-qeYye4ojWA0o,2453
|
|
6
|
+
qtype/commands/generate.py,sha256=G8Uk4QdBRCmPErjihFbI2T8hB-M_yqLoQiw3-y7P8Mo,3587
|
|
7
|
+
qtype/commands/run.py,sha256=iPg_fnmxx6mPr2I3l0rlJqFEciQCb6r52vKKO_BgW8w,5946
|
|
8
|
+
qtype/commands/validate.py,sha256=gJjpT9tSCedV2vIuvhPyYIUgNip6RYYXbVK6PKlCPXk,2573
|
|
9
|
+
qtype/commons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
qtype/commons/generate.py,sha256=UBuknsU3f1G-Hz1VhtLTNnDu02repJh8fkrlP4OHqqI,2831
|
|
11
|
+
qtype/commons/tools.py,sha256=pJFY5mPiFErXVFLw2GtiFoWnS8xCNaDVtk-opkoB-zs,5004
|
|
12
|
+
qtype/converters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
+
qtype/converters/tools_from_api.py,sha256=qsycjLGZDnawND8JtK97avAEJcpAm5FGs8nDgePXzbc,774
|
|
14
|
+
qtype/converters/tools_from_module.py,sha256=PQjISjj7Nqk_SPegA0fM0FPeKaVml9S15NuiTk-oCaQ,10270
|
|
15
|
+
qtype/converters/types.py,sha256=CG9H6yK8tH8kCed6Yw-v8IDMFBOT9GcRlqHz4inbzMI,861
|
|
16
|
+
qtype/dsl/__init__.py,sha256=FJ7T-bOEwfu96Vj5UuwHHTgYL5kGw1qyAk087DwRJFs,35
|
|
17
|
+
qtype/dsl/base_types.py,sha256=ZMX5mAAOducSG_89SxniJWUGCsit1MU3EKrrzvSPmB4,687
|
|
18
|
+
qtype/dsl/document.py,sha256=LzcDSV9DDfCAWpqm-mdxAwLNHmErb0_ypEPk5WnI5QU,3998
|
|
19
|
+
qtype/dsl/domain_types.py,sha256=VglaF7eTVjUmLvubQeNQo2ZA0pRooQXZ-OPJ6edQBIk,1539
|
|
20
|
+
qtype/dsl/model.py,sha256=mAgqfG1us1mT53nYd0gAIwOSgudLSDlwQjUlG5MDfRg,21169
|
|
21
|
+
qtype/dsl/validator.py,sha256=yuDFPHfErPTIpZXCIyBrwpZJAitMEW0jNL8867KixUA,17130
|
|
22
|
+
qtype/interpreter/__init__.py,sha256=IaRF90JLFbsTLKz9LTOMI_Pz4xwVaEyXPNaXV7sLou8,43
|
|
23
|
+
qtype/interpreter/api.py,sha256=DrBV0fF6f4HiGSgXzHE07FwOr5Qe7uBQ2yQ6UjDOUTU,3872
|
|
24
|
+
qtype/interpreter/conversions.py,sha256=17EKzKRSTKsGWlXemXdvHVdefZTonMyB0Ui6dIEtN7M,5584
|
|
25
|
+
qtype/interpreter/exceptions.py,sha256=Il8IF0UAtYWQXwvOVQCY-csfRzC1iOejHM1G-nF5EfY,288
|
|
26
|
+
qtype/interpreter/flow.py,sha256=2u1wRahNFQaRRklnU4uW7_UKSD73-uZe_WiYlKitXQg,1233
|
|
27
|
+
qtype/interpreter/resource_cache.py,sha256=XylIIh7RFHs4JdOZWx24a3P-sH0qjgqU9_vri9ztAXU,1014
|
|
28
|
+
qtype/interpreter/step.py,sha256=6rLznFCc8FT0edCbeA7mUYCz8NHhZzTIBpXTxrlG9eE,2084
|
|
29
|
+
qtype/interpreter/telemetry.py,sha256=p1nmup-V_TBM64giYySewpjJOF5_FZgK_KTE5ad38Uk,632
|
|
30
|
+
qtype/interpreter/typing.py,sha256=DdAgV78XurX2JnhBK5wHsYTtPyo9RjOytqxJJzDpwR4,2588
|
|
31
|
+
qtype/interpreter/steps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
32
|
+
qtype/interpreter/steps/agent.py,sha256=Yg56YjTlrwc4oJ-f7ZBazF4ii2oJX8zMhETHF0-ArAU,4008
|
|
33
|
+
qtype/interpreter/steps/condition.py,sha256=E86aRWQpjz18QuKwcGyoIPoOKAvTDZgnpg9qXw6xYas,1128
|
|
34
|
+
qtype/interpreter/steps/decoder.py,sha256=2cyb2NaQzl5NcrGxP6d68ZsVflm8ldkwJsazRxQArY0,2887
|
|
35
|
+
qtype/interpreter/steps/llm_inference.py,sha256=snariFHhvsDBixHeUpZLg8_V6BZIYOlSyVf6QsbRyd8,4358
|
|
36
|
+
qtype/interpreter/steps/prompt_template.py,sha256=Hs4ZANMqDViZVEPhD2v6JcUJ0DdMkahDJwnDfAXidak,1582
|
|
37
|
+
qtype/interpreter/steps/search.py,sha256=wyVFwg5wVXytsm2JyNPwkuBAWpxEunP-dAiqhDZyii4,660
|
|
38
|
+
qtype/interpreter/steps/tool.py,sha256=zAL9us_KRrcaw_sktD1z2pm0Z2W9ruMd3rrjqk7TI_k,1996
|
|
39
|
+
qtype/semantic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
40
|
+
qtype/semantic/errors.py,sha256=dmdxGkVHrTwfiEHj5RFu2q11dAtefsivpLdJd6QynK0,119
|
|
41
|
+
qtype/semantic/generate.py,sha256=JTQALEP0DCbx13HpuR7zsP5Nnk_XYkEAFpLutmRZmIQ,13299
|
|
42
|
+
qtype/semantic/model.py,sha256=XmPoEqFQFKXHKC0hj-p9aEiuzUM4Q0qCHHskly3X5CM,11308
|
|
43
|
+
qtype/semantic/resolver.py,sha256=D3CmRmr_ACL54ZCbc9HxXCuCZ37bNtSzlPLMpOeeOcw,3439
|
|
44
|
+
qtype-0.0.1.dist-info/licenses/LICENSE,sha256=1KA5EgYBSR0O6nCH2HEvk6Di53YKJ9r_VCR7G8G8qAY,11341
|
|
45
|
+
qtype-0.0.1.dist-info/METADATA,sha256=-qtCCCsTEA8veBIYr-z8yx4djIWdVlxSQzwUQsCp91w,4026
|
|
46
|
+
qtype-0.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
47
|
+
qtype-0.0.1.dist-info/entry_points.txt,sha256=5y4vj8RLvgl2tXSj-Hm7v5-Tn3kP4-UonjNoN-mfaQE,41
|
|
48
|
+
qtype-0.0.1.dist-info/top_level.txt,sha256=ONroH5B0mZ51jr7NSWCK0weFwwCO7wBLmyVS1YqNU14,6
|
|
49
|
+
qtype-0.0.1.dist-info/RECORD,,
|