qtype 0.1.12__py3-none-any.whl → 0.1.14__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/` +0 -0
- qtype/application/__init__.py +0 -2
- qtype/application/converters/tools_from_api.py +28 -22
- qtype/application/converters/tools_from_module.py +66 -32
- qtype/base/__init__.py +8 -2
- qtype/base/logging.py +0 -17
- qtype/base/resources.py +193 -0
- qtype/cli.py +5 -9
- qtype/commands/generate.py +95 -7
- qtype/commands/run.py +153 -54
- qtype/docs/.pages +8 -0
- {docs → qtype/docs}/Concepts/mental-model-and-philosophy.md +1 -1
- qtype/docs/Contributing/.pages +4 -0
- {docs → qtype/docs}/Contributing/index.md +8 -1
- {docs → qtype/docs}/Gallery/dataflow_pipelines.md +18 -4
- qtype/docs/Gallery/recipe_chatbot.md +103 -0
- qtype/docs/Gallery/recipe_chatbot.mermaid +62 -0
- qtype/docs/Gallery/recipe_chatbot.png +0 -0
- {docs → qtype/docs}/Gallery/research_assistant.md +4 -5
- {docs → qtype/docs}/Gallery/simple_chatbot.md +3 -1
- {docs → qtype/docs}/How To/Authentication/configure_aws_authentication.md +2 -2
- {docs → qtype/docs}/How To/Authentication/use_api_key_authentication.md +2 -2
- {docs → qtype/docs}/How To/Command Line Usage/load_multiple_inputs_from_files.md +24 -9
- {docs → qtype/docs}/How To/Command Line Usage/pass_inputs_on_the_cli.md +7 -4
- {docs → qtype/docs}/How To/Command Line Usage/serve_with_auto_reload.md +3 -2
- {docs → qtype/docs}/How To/Data Processing/adjust_concurrency.md +3 -4
- {docs → qtype/docs}/How To/Data Processing/cache_step_results.md +2 -2
- {docs → qtype/docs}/How To/Data Processing/decode_json_xml.md +1 -1
- {docs → qtype/docs}/How To/Data Processing/explode_collections.md +2 -2
- {docs → qtype/docs}/How To/Data Processing/gather_results.md +4 -4
- qtype/docs/How To/Data Processing/invoke_other_flows.md +71 -0
- qtype/docs/How To/Data Processing/load_data_from_athena.md +49 -0
- qtype/docs/How To/Data Processing/load_documents.md +74 -0
- qtype/docs/How To/Data Processing/read_data_from_files.md +61 -0
- {docs → qtype/docs}/How To/Data Processing/read_sql_databases.md +4 -3
- {docs → qtype/docs}/How To/Data Processing/write_data_to_file.md +1 -2
- {docs → qtype/docs}/How To/Invoke Models/call_large_language_models.md +1 -1
- {docs → qtype/docs}/How To/Invoke Models/create_embeddings.md +1 -1
- {docs → qtype/docs}/How To/Invoke Models/reuse_prompts_with_templates.md +2 -3
- {docs → qtype/docs}/How To/Language Features/include_raw_text_from_other_files.md +2 -1
- {docs → qtype/docs}/How To/Language Features/reference_entities_by_id.md +2 -2
- qtype/docs/How To/Language Features/use_agent_skills.md +29 -0
- {docs → qtype/docs}/How To/Language Features/use_environment_variables.md +2 -1
- qtype/docs/How To/Language Features/use_optional_variables.md +42 -0
- {docs → qtype/docs}/How To/Language Features/use_qtype_mcp.md +4 -4
- {docs → qtype/docs}/How To/Observability & Debugging/trace_calls_with_open_telemetry.md +1 -1
- {docs → qtype/docs}/How To/Observability & Debugging/validate_qtype_yaml.md +3 -2
- {docs → qtype/docs}/How To/Observability & Debugging/visualize_application_architecture.md +1 -1
- {docs → qtype/docs}/How To/Qtype Server/serve_flows_as_apis.md +3 -3
- {docs → qtype/docs}/How To/Qtype Server/serve_flows_as_ui.md +2 -3
- {docs → qtype/docs}/How To/Qtype Server/use_conversational_interfaces.md +1 -4
- {docs → qtype/docs}/How To/Qtype Server/use_variables_with_ui_hints.md +3 -2
- {docs → qtype/docs}/How To/Tools & Integration/bind_tool_inputs_and_outputs.md +1 -2
- {docs → qtype/docs}/How To/Tools & Integration/create_tools_from_openapi_specifications.md +10 -14
- {docs → qtype/docs}/How To/Tools & Integration/create_tools_from_python_modules.md +5 -8
- {docs → qtype/docs}/Reference/cli.md +16 -17
- qtype/docs/Tutorials/.pages +1 -0
- {docs → qtype/docs}/Tutorials/01-first-qtype-application.md +4 -3
- {docs → qtype/docs}/Tutorials/02-conversational-chatbot.md +3 -3
- {docs → qtype/docs}/Tutorials/03-structured-data.md +10 -11
- {docs → qtype/docs}/Tutorials/04-tools-and-function-calling.md +13 -20
- {docs → qtype/docs}/components/APITool.md +1 -1
- qtype/docs/components/Aggregate.md +7 -0
- qtype/docs/components/Collect.md +6 -0
- qtype/docs/components/Construct.md +6 -0
- {docs → qtype/docs}/components/DocumentEmbedder.md +0 -1
- {docs → qtype/docs}/components/DocumentSplitter.md +0 -1
- qtype/docs/components/Explode.md +5 -0
- {docs → qtype/docs}/components/FieldExtractor.md +2 -1
- qtype/docs/components/InvokeFlow.md +8 -0
- qtype/docs/components/InvokeTool.md +8 -0
- {docs → qtype/docs}/components/PrimitiveTypeEnum.md +0 -1
- {docs → qtype/docs}/components/Source.md +0 -1
- {docs → qtype/docs}/components/Step.md +0 -1
- {docs → qtype/docs}/components/Tool.md +2 -2
- {docs → qtype/docs}/components/Variable.md +2 -0
- qtype/docs/legacy_how_tos/.pages +6 -0
- qtype/docs/skills/architect/SKILL.md +188 -0
- qtype/docs/skills/architect/references/cheatsheet.md +198 -0
- qtype/docs/skills/architect/references/patterns.md +29 -0
- qtype/docs/stylesheets/extra.css +27 -0
- qtype/dsl/linker.py +8 -0
- qtype/dsl/model.py +177 -84
- qtype/examples/conversational_ai/simple_chatbot_with_auth.qtype.yaml +48 -0
- qtype/examples/data_processing/athena_query.qtype.yaml +56 -0
- qtype/examples/data_processing/batch_inputs.csv +5 -0
- qtype/examples/data_processing/create_sample_db.py +129 -0
- qtype/examples/data_processing/invoke_other_flows.qtype.yaml +98 -0
- qtype/examples/data_processing/load_documents.qtype.yaml +31 -0
- qtype/examples/data_processing/reviews.db +0 -0
- qtype/examples/data_processing/sample_article.txt +1 -0
- qtype/examples/data_processing/sample_documents.jsonl +5 -0
- qtype/examples/invoke_models/invoke_embedding_aws.qtype.yaml +45 -0
- qtype/examples/language_features/optional_variables.qtype.yaml +32 -0
- qtype/examples/language_features/story_prompt.txt +6 -0
- qtype/examples/legacy/data/customers.csv +6 -0
- qtype/examples/legacy/echo/readme.md +29 -0
- qtype/examples/legacy/qtype_plugin_example.py +51 -0
- qtype/examples/legacy/sample_data.txt +43 -0
- qtype/examples/legacy/vertex/README.md +11 -0
- qtype/examples/rag/recipe_chatbot.qtype.yaml +216 -0
- qtype/examples/research_assistant/tavily.qtype.yaml +216 -0
- {examples → qtype/examples}/tutorials/03_structured_data.qtype.yaml +2 -2
- {examples → qtype/examples}/tutorials/04_tools_and_function_calling.qtype.yaml +5 -5
- qtype/interpreter/auth/aws.py +94 -17
- qtype/interpreter/auth/generic.py +11 -12
- qtype/interpreter/base/secrets.py +4 -2
- qtype/interpreter/base/stream_emitter.py +19 -13
- qtype/interpreter/conversions.py +15 -14
- qtype/interpreter/converters.py +142 -26
- qtype/interpreter/executors/agent_executor.py +2 -3
- qtype/interpreter/executors/aggregate_executor.py +3 -4
- qtype/interpreter/executors/bedrock_reranker_executor.py +17 -28
- qtype/interpreter/executors/construct_executor.py +15 -15
- qtype/interpreter/executors/doc_to_text_executor.py +1 -3
- qtype/interpreter/executors/document_embedder_executor.py +1 -12
- qtype/interpreter/executors/field_extractor_executor.py +13 -12
- qtype/interpreter/executors/file_source_executor.py +18 -31
- qtype/interpreter/executors/invoke_embedding_executor.py +24 -37
- qtype/interpreter/executors/invoke_flow_executor.py +2 -2
- qtype/interpreter/executors/invoke_tool_executor.py +19 -18
- qtype/interpreter/executors/llm_inference_executor.py +18 -18
- qtype/interpreter/executors/prompt_template_executor.py +1 -3
- qtype/interpreter/executors/sql_source_executor.py +6 -2
- qtype/interpreter/flow.py +11 -1
- qtype/interpreter/tools/function_tool_helper.py +11 -10
- qtype/interpreter/types.py +89 -4
- qtype/interpreter/typing.py +31 -32
- qtype/mcp/server.py +194 -86
- {schema → qtype/schema}/qtype.schema.json +77 -79
- qtype/semantic/checker.py +19 -0
- qtype/semantic/generate.py +3 -6
- qtype/semantic/model.py +26 -33
- qtype/semantic/resolver.py +7 -0
- qtype/semantic/visualize.py +18 -6
- {qtype-0.1.12.dist-info → qtype-0.1.14.dist-info}/METADATA +47 -46
- qtype-0.1.14.dist-info/RECORD +361 -0
- {qtype-0.1.12.dist-info → qtype-0.1.14.dist-info}/WHEEL +1 -2
- docs/How To/Data Processing/read_data_from_files.md +0 -35
- docs/components/Aggregate.md +0 -8
- docs/components/InvokeFlow.md +0 -8
- docs/components/InvokeTool.md +0 -8
- docs/components/ToolParameter.md +0 -6
- examples/research_assistant/tavily.qtype.yaml +0 -289
- qtype/application/facade.py +0 -177
- qtype-0.1.12.dist-info/RECORD +0 -325
- qtype-0.1.12.dist-info/top_level.txt +0 -1
- {docs → qtype/docs}/Contributing/roadmap.md +0 -0
- {docs → qtype/docs}/Decisions/ADR-001-Chat-vs-Completion-Endpoint-Features.md +0 -0
- {docs → qtype/docs}/Gallery/dataflow_pipelines.mermaid +0 -0
- {docs → qtype/docs}/Gallery/research_assistant.mermaid +0 -0
- {docs → qtype/docs}/Gallery/simple_chatbot.mermaid +0 -0
- {docs → qtype/docs}/How To/Language Features/include_qtype_yaml.md +0 -0
- {docs → qtype/docs}/How To/Observability & Debugging/visualize_example.mermaid +0 -0
- {docs → qtype/docs}/How To/Qtype Server/flow_as_ui.png +0 -0
- {docs → qtype/docs}/Reference/plugins.md +0 -0
- {docs → qtype/docs}/Reference/semantic-validation-rules.md +0 -0
- {docs → qtype/docs}/Tutorials/example_chat.png +0 -0
- {docs → qtype/docs}/Tutorials/index.md +0 -0
- {docs → qtype/docs}/components/APIKeyAuthProvider.md +0 -0
- {docs → qtype/docs}/components/AWSAuthProvider.md +0 -0
- {docs → qtype/docs}/components/AWSSecretManager.md +0 -0
- {docs → qtype/docs}/components/Agent.md +0 -0
- {docs → qtype/docs}/components/AggregateStats.md +0 -0
- {docs → qtype/docs}/components/Application.md +0 -0
- {docs → qtype/docs}/components/AuthorizationProvider.md +0 -0
- {docs → qtype/docs}/components/AuthorizationProviderList.md +0 -0
- {docs → qtype/docs}/components/BearerTokenAuthProvider.md +0 -0
- {docs → qtype/docs}/components/BedrockReranker.md +0 -0
- {docs → qtype/docs}/components/ChatContent.md +0 -0
- {docs → qtype/docs}/components/ChatMessage.md +0 -0
- {docs → qtype/docs}/components/ConstantPath.md +0 -0
- {docs → qtype/docs}/components/CustomType.md +0 -0
- {docs → qtype/docs}/components/Decoder.md +0 -0
- {docs → qtype/docs}/components/DecoderFormat.md +0 -0
- {docs → qtype/docs}/components/DocToTextConverter.md +0 -0
- {docs → qtype/docs}/components/Document.md +0 -0
- {docs → qtype/docs}/components/DocumentIndex.md +0 -0
- {docs → qtype/docs}/components/DocumentSearch.md +0 -0
- {docs → qtype/docs}/components/DocumentSource.md +0 -0
- {docs → qtype/docs}/components/Echo.md +0 -0
- {docs → qtype/docs}/components/Embedding.md +0 -0
- {docs → qtype/docs}/components/EmbeddingModel.md +0 -0
- {docs → qtype/docs}/components/FileSource.md +0 -0
- {docs → qtype/docs}/components/FileWriter.md +0 -0
- {docs → qtype/docs}/components/Flow.md +0 -0
- {docs → qtype/docs}/components/FlowInterface.md +0 -0
- {docs → qtype/docs}/components/Index.md +0 -0
- {docs → qtype/docs}/components/IndexUpsert.md +0 -0
- {docs → qtype/docs}/components/InvokeEmbedding.md +0 -0
- {docs → qtype/docs}/components/LLMInference.md +0 -0
- {docs → qtype/docs}/components/ListType.md +0 -0
- {docs → qtype/docs}/components/Memory.md +0 -0
- {docs → qtype/docs}/components/MessageRole.md +0 -0
- {docs → qtype/docs}/components/Model.md +0 -0
- {docs → qtype/docs}/components/ModelList.md +0 -0
- {docs → qtype/docs}/components/OAuth2AuthProvider.md +0 -0
- {docs → qtype/docs}/components/PromptTemplate.md +0 -0
- {docs → qtype/docs}/components/PythonFunctionTool.md +0 -0
- {docs → qtype/docs}/components/RAGChunk.md +0 -0
- {docs → qtype/docs}/components/RAGDocument.md +0 -0
- {docs → qtype/docs}/components/RAGSearchResult.md +0 -0
- {docs → qtype/docs}/components/Reranker.md +0 -0
- {docs → qtype/docs}/components/SQLSource.md +0 -0
- {docs → qtype/docs}/components/Search.md +0 -0
- {docs → qtype/docs}/components/SearchResult.md +0 -0
- {docs → qtype/docs}/components/SecretManager.md +0 -0
- {docs → qtype/docs}/components/SecretReference.md +0 -0
- {docs → qtype/docs}/components/TelemetrySink.md +0 -0
- {docs → qtype/docs}/components/ToolList.md +0 -0
- {docs → qtype/docs}/components/TypeList.md +0 -0
- {docs → qtype/docs}/components/VariableList.md +0 -0
- {docs → qtype/docs}/components/VectorIndex.md +0 -0
- {docs → qtype/docs}/components/VectorSearch.md +0 -0
- {docs → qtype/docs}/components/VertexAuthProvider.md +0 -0
- {docs → qtype/docs}/components/Writer.md +0 -0
- {docs → qtype/docs}/example_ui.png +0 -0
- {docs → qtype/docs}/index.md +0 -0
- {docs → qtype/docs}/legacy_how_tos/Configuration/modular-yaml.md +0 -0
- {docs → qtype/docs}/legacy_how_tos/Configuration/phoenix_projects.png +0 -0
- {docs → qtype/docs}/legacy_how_tos/Configuration/phoenix_traces.png +0 -0
- {docs → qtype/docs}/legacy_how_tos/Configuration/reference-by-id.md +0 -0
- {docs → qtype/docs}/legacy_how_tos/Configuration/telemetry-setup.md +0 -0
- {docs → qtype/docs}/legacy_how_tos/Data Types/custom-types.md +0 -0
- {docs → qtype/docs}/legacy_how_tos/Data Types/domain-types.md +0 -0
- {docs → qtype/docs}/legacy_how_tos/Debugging/visualize-apps.md +0 -0
- {docs → qtype/docs}/legacy_how_tos/Tools/api-tools.md +0 -0
- {docs → qtype/docs}/legacy_how_tos/Tools/python-tools.md +0 -0
- {examples → qtype/examples}/authentication/aws_authentication.qtype.yaml +0 -0
- {examples → qtype/examples}/conversational_ai/hello_world_chat.qtype.yaml +0 -0
- {examples → qtype/examples}/conversational_ai/simple_chatbot.qtype.yaml +0 -0
- {examples → qtype/examples}/data_processing/batch_processing.qtype.yaml +0 -0
- {examples → qtype/examples}/data_processing/cache_step_results.qtype.yaml +0 -0
- {examples → qtype/examples}/data_processing/collect_results.qtype.yaml +0 -0
- {examples → qtype/examples}/data_processing/dataflow_pipelines.qtype.yaml +0 -0
- {examples → qtype/examples}/data_processing/decode_json.qtype.yaml +0 -0
- {examples → qtype/examples}/data_processing/explode_items.qtype.yaml +0 -0
- {examples → qtype/examples}/data_processing/read_file.qtype.yaml +0 -0
- {examples → qtype/examples}/invoke_models/create_embeddings.qtype.yaml +0 -0
- {examples → qtype/examples}/invoke_models/simple_llm_call.qtype.yaml +0 -0
- {examples → qtype/examples}/language_features/include_raw.qtype.yaml +0 -0
- {examples → qtype/examples}/language_features/ui_hints.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/bedrock/data_analysis_with_telemetry.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/bedrock/hello_world.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/bedrock/hello_world_chat.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/bedrock/hello_world_chat_with_telemetry.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/bedrock/hello_world_chat_with_thinking.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/bedrock/hello_world_completion.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/bedrock/hello_world_completion_with_auth.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/bedrock/simple_agent_chat.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/chat_with_langfuse.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/data_processor.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/echo/debug_example.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/echo/prompt.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/echo/test.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/echo/video.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/field_extractor_example.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/multi_flow_example.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/openai/hello_world_chat.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/openai/hello_world_chat_with_telemetry.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/rag.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/time_utilities.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/vertex/hello_world_chat.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/vertex/hello_world_completion.qtype.yaml +0 -0
- {examples → qtype/examples}/legacy/vertex/hello_world_completion_with_auth.qtype.yaml +0 -0
- {examples → qtype/examples}/observability_debugging/trace_with_opentelemetry.qtype.yaml +0 -0
- {examples → qtype/examples}/research_assistant/research_assistant.qtype.yaml +0 -0
- {examples → qtype/examples}/research_assistant/tavily.oas.yaml +0 -0
- {examples → qtype/examples}/tutorials/01_hello_world.qtype.yaml +0 -0
- {examples → qtype/examples}/tutorials/02_conversational_chat.qtype.yaml +0 -0
- {qtype-0.1.12.dist-info → qtype-0.1.14.dist-info}/entry_points.txt +0 -0
- {qtype-0.1.12.dist-info → qtype-0.1.14.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
from typing import AsyncIterator
|
|
2
3
|
|
|
3
4
|
from llama_cloud import MessageRole as LlamaMessageRole
|
|
@@ -85,6 +86,7 @@ class LLMInferenceExecutor(StepExecutor):
|
|
|
85
86
|
|
|
86
87
|
except Exception as e:
|
|
87
88
|
# Emit error event to stream so frontend can display it
|
|
89
|
+
logging.error(f"LLM Inference search failed: {e}", exc_info=True)
|
|
88
90
|
await self.stream_emitter.error(str(e))
|
|
89
91
|
yield message.copy_with_error(self.step.id, e)
|
|
90
92
|
|
|
@@ -109,7 +111,7 @@ class LLMInferenceExecutor(StepExecutor):
|
|
|
109
111
|
# Convert input variables to chat messages
|
|
110
112
|
inputs = []
|
|
111
113
|
for input_var in self.step.inputs:
|
|
112
|
-
value = message.
|
|
114
|
+
value = message.get_variable(input_var.id)
|
|
113
115
|
# Convert any value type to ChatMessage, then to LlamaChatMessage
|
|
114
116
|
chat_msg = variable_to_chat_message(value, input_var)
|
|
115
117
|
inputs.append(to_chat_message(chat_msg))
|
|
@@ -160,9 +162,14 @@ class LLMInferenceExecutor(StepExecutor):
|
|
|
160
162
|
if self.context.on_stream_event:
|
|
161
163
|
# Generate a unique stream ID for this inference
|
|
162
164
|
stream_id = f"llm-{self.step.id}-{id(message)}"
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
165
|
+
reasoning_stream_id = f"llm-{self.step.id}-{id(message)}-reasoning"
|
|
166
|
+
|
|
167
|
+
async with (
|
|
168
|
+
self.stream_emitter.reasoning_stream(
|
|
169
|
+
reasoning_stream_id
|
|
170
|
+
) as reasoning,
|
|
171
|
+
self.stream_emitter.text_stream(stream_id) as streamer,
|
|
172
|
+
):
|
|
166
173
|
generator = await model.astream_chat(
|
|
167
174
|
messages=inputs,
|
|
168
175
|
**(
|
|
@@ -171,26 +178,19 @@ class LLMInferenceExecutor(StepExecutor):
|
|
|
171
178
|
else {}
|
|
172
179
|
),
|
|
173
180
|
)
|
|
174
|
-
async for
|
|
181
|
+
async for chat_response in generator:
|
|
182
|
+
# Extract and emit reasoning if present
|
|
175
183
|
reasoning_text = self.__extract_stream_reasoning_(
|
|
176
|
-
|
|
184
|
+
chat_response
|
|
177
185
|
)
|
|
178
186
|
if reasoning_text:
|
|
179
187
|
await reasoning.delta(reasoning_text)
|
|
180
188
|
|
|
181
|
-
|
|
182
|
-
generator = await model.astream_chat(
|
|
183
|
-
messages=inputs,
|
|
184
|
-
**(
|
|
185
|
-
self.step.model.inference_params
|
|
186
|
-
if self.step.model.inference_params
|
|
187
|
-
else {}
|
|
188
|
-
),
|
|
189
|
-
)
|
|
190
|
-
async for chat_response in generator:
|
|
189
|
+
# Emit text delta
|
|
191
190
|
chat_text = chat_response.delta
|
|
192
|
-
if chat_text.strip() != "":
|
|
193
|
-
await streamer.delta(
|
|
191
|
+
if chat_text is not None and chat_text.strip() != "":
|
|
192
|
+
await streamer.delta(chat_text)
|
|
193
|
+
|
|
194
194
|
# Get the final result
|
|
195
195
|
chat_result = chat_response
|
|
196
196
|
else:
|
|
@@ -51,9 +51,7 @@ class PromptTemplateExecutor(StepExecutor):
|
|
|
51
51
|
input_map = {}
|
|
52
52
|
for var in self.step.inputs:
|
|
53
53
|
if var.id in format_args:
|
|
54
|
-
|
|
55
|
-
if value is not None:
|
|
56
|
-
input_map[var.id] = value
|
|
54
|
+
input_map[var.id] = message.get_variable(var.id)
|
|
57
55
|
|
|
58
56
|
missing = format_args - input_map.keys()
|
|
59
57
|
if missing:
|
|
@@ -42,8 +42,12 @@ class SQLSourceExecutor(StepExecutor):
|
|
|
42
42
|
connect_args = {}
|
|
43
43
|
if self.step.auth:
|
|
44
44
|
with auth(self.step.auth, self._secret_manager) as creds:
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
# For AWS auth, create a boto3 session from credentials
|
|
46
|
+
from qtype.interpreter.auth.aws import AWSCredentials
|
|
47
|
+
|
|
48
|
+
if isinstance(creds, AWSCredentials):
|
|
49
|
+
session = boto3.Session(**creds.as_kwargs())
|
|
50
|
+
connect_args["session"] = session
|
|
47
51
|
engine = create_engine(connection_string, connect_args=connect_args)
|
|
48
52
|
|
|
49
53
|
output_columns = {output.id for output in self.step.outputs}
|
qtype/interpreter/flow.py
CHANGED
|
@@ -17,7 +17,7 @@ from qtype.interpreter.base import factory
|
|
|
17
17
|
from qtype.interpreter.base.executor_context import ExecutorContext
|
|
18
18
|
from qtype.interpreter.logging_progress import LoggingProgressCallback
|
|
19
19
|
from qtype.interpreter.rich_progress import RichProgressCallback
|
|
20
|
-
from qtype.interpreter.types import FlowMessage, ProgressCallback
|
|
20
|
+
from qtype.interpreter.types import FlowMessage, ProgressCallback, Session
|
|
21
21
|
from qtype.semantic.model import Flow
|
|
22
22
|
|
|
23
23
|
logger = logging.getLogger(__name__)
|
|
@@ -106,6 +106,16 @@ async def run_flow(
|
|
|
106
106
|
initial = [initial]
|
|
107
107
|
|
|
108
108
|
if isinstance(initial, list):
|
|
109
|
+
# Handle empty list by creating a single empty message
|
|
110
|
+
if len(initial) == 0:
|
|
111
|
+
session_id = kwargs.get("session_id", "default")
|
|
112
|
+
initial = [
|
|
113
|
+
FlowMessage(
|
|
114
|
+
session=Session(session_id=session_id),
|
|
115
|
+
variables={},
|
|
116
|
+
)
|
|
117
|
+
]
|
|
118
|
+
|
|
109
119
|
span.set_attribute("flow.input_count", len(initial))
|
|
110
120
|
|
|
111
121
|
# convert to async iterator
|
|
@@ -14,7 +14,7 @@ from pydantic import create_model
|
|
|
14
14
|
from qtype.base.types import PrimitiveTypeEnum
|
|
15
15
|
from qtype.dsl.model import ListType
|
|
16
16
|
from qtype.dsl.types import PRIMITIVE_TO_PYTHON_TYPE
|
|
17
|
-
from qtype.semantic.model import APITool, PythonFunctionTool,
|
|
17
|
+
from qtype.semantic.model import APITool, PythonFunctionTool, Variable
|
|
18
18
|
|
|
19
19
|
logger = logging.getLogger(__name__)
|
|
20
20
|
|
|
@@ -29,9 +29,9 @@ class FunctionToolHelper:
|
|
|
29
29
|
|
|
30
30
|
@staticmethod
|
|
31
31
|
def _qtype_type_to_python_type(
|
|
32
|
-
param:
|
|
32
|
+
param: Variable,
|
|
33
33
|
) -> type:
|
|
34
|
-
"""Convert QType
|
|
34
|
+
"""Convert QType Variable type to Python type for Pydantic.
|
|
35
35
|
|
|
36
36
|
The param.type has already been resolved during semantic model
|
|
37
37
|
creation, so we just need to convert it to the appropriate Python
|
|
@@ -42,7 +42,7 @@ class FunctionToolHelper:
|
|
|
42
42
|
- Unknown → str
|
|
43
43
|
|
|
44
44
|
Args:
|
|
45
|
-
param: The QType
|
|
45
|
+
param: The QType Variable to convert.
|
|
46
46
|
|
|
47
47
|
Returns:
|
|
48
48
|
Python type suitable for Pydantic field annotation.
|
|
@@ -55,7 +55,8 @@ class FunctionToolHelper:
|
|
|
55
55
|
if isinstance(param.type, ListType):
|
|
56
56
|
# Create a mock parameter with the element type to recursively
|
|
57
57
|
# resolve it
|
|
58
|
-
element_param =
|
|
58
|
+
element_param = Variable(
|
|
59
|
+
id="temp",
|
|
59
60
|
type=param.type.element_type,
|
|
60
61
|
optional=False,
|
|
61
62
|
)
|
|
@@ -74,13 +75,13 @@ class FunctionToolHelper:
|
|
|
74
75
|
@staticmethod
|
|
75
76
|
def _create_fn_schema(
|
|
76
77
|
tool_name: str,
|
|
77
|
-
inputs:
|
|
78
|
+
inputs: list[Variable],
|
|
78
79
|
) -> type[BaseModel] | None:
|
|
79
80
|
"""Create a Pydantic model from QType tool input parameters.
|
|
80
81
|
|
|
81
82
|
Args:
|
|
82
83
|
tool_name: Name of the tool (used for model name).
|
|
83
|
-
inputs:
|
|
84
|
+
inputs: List of input Variables.
|
|
84
85
|
|
|
85
86
|
Returns:
|
|
86
87
|
Pydantic BaseModel class representing the tool's input schema.
|
|
@@ -91,17 +92,17 @@ class FunctionToolHelper:
|
|
|
91
92
|
# Each field is a tuple of (type_annotation, field_info)
|
|
92
93
|
field_definitions: dict[str, Any] = {}
|
|
93
94
|
|
|
94
|
-
for
|
|
95
|
+
for param in inputs:
|
|
95
96
|
python_type = FunctionToolHelper._qtype_type_to_python_type(param)
|
|
96
97
|
|
|
97
98
|
# Create field with optional annotation
|
|
98
99
|
if param.optional:
|
|
99
|
-
field_definitions[
|
|
100
|
+
field_definitions[param.id] = (
|
|
100
101
|
python_type | None, # type: ignore[valid-type]
|
|
101
102
|
PydanticField(default=None),
|
|
102
103
|
)
|
|
103
104
|
else:
|
|
104
|
-
field_definitions[
|
|
105
|
+
field_definitions[param.id] = (
|
|
105
106
|
python_type,
|
|
106
107
|
PydanticField(...),
|
|
107
108
|
)
|
qtype/interpreter/types.py
CHANGED
|
@@ -1,11 +1,38 @@
|
|
|
1
1
|
from typing import Any, Dict, Literal, Optional, Protocol, Union
|
|
2
2
|
|
|
3
|
-
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
from pydantic import BaseModel, ConfigDict, Field, model_serializer
|
|
4
4
|
|
|
5
5
|
from qtype.base.types import StrictBaseModel
|
|
6
6
|
from qtype.dsl.domain_types import ChatMessage
|
|
7
7
|
from qtype.semantic.model import Step
|
|
8
8
|
|
|
9
|
+
|
|
10
|
+
class _UnsetType:
|
|
11
|
+
"""Sentinel representing an unset variable.
|
|
12
|
+
|
|
13
|
+
Distinguishes between:
|
|
14
|
+
- Variable never mentioned (not in dict)
|
|
15
|
+
- Variable explicitly unset (UNSET value in dict)
|
|
16
|
+
- Variable set to None (None value in dict)
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
_instance = None
|
|
20
|
+
|
|
21
|
+
def __new__(cls):
|
|
22
|
+
if cls._instance is None:
|
|
23
|
+
cls._instance = super().__new__(cls)
|
|
24
|
+
return cls._instance
|
|
25
|
+
|
|
26
|
+
def __repr__(self) -> str:
|
|
27
|
+
return "UNSET"
|
|
28
|
+
|
|
29
|
+
def __bool__(self) -> bool:
|
|
30
|
+
return False
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
UNSET = _UnsetType()
|
|
34
|
+
|
|
35
|
+
|
|
9
36
|
# Stream Event Types (Discriminated Union)
|
|
10
37
|
# These events are emitted by executors during flow execution
|
|
11
38
|
# and can be converted to Vercel UI chunks for frontend display
|
|
@@ -293,8 +320,9 @@ class FlowMessage(BaseModel):
|
|
|
293
320
|
"""
|
|
294
321
|
|
|
295
322
|
model_config = ConfigDict(
|
|
296
|
-
frozen=True
|
|
297
|
-
|
|
323
|
+
frozen=True,
|
|
324
|
+
arbitrary_types_allowed=True, # Allow UNSET sentinel
|
|
325
|
+
)
|
|
298
326
|
|
|
299
327
|
session: Session
|
|
300
328
|
variables: Dict[str, Any] = Field(
|
|
@@ -307,6 +335,49 @@ class FlowMessage(BaseModel):
|
|
|
307
335
|
"""Checks if this state has encountered an error."""
|
|
308
336
|
return self.error is not None
|
|
309
337
|
|
|
338
|
+
def is_set(self, var_id: str) -> bool:
|
|
339
|
+
"""Check if a variable is set (not UNSET, may be None)."""
|
|
340
|
+
value = self.variables.get(var_id, UNSET)
|
|
341
|
+
return value is not UNSET
|
|
342
|
+
|
|
343
|
+
def get_variable(self, var_id: str, *, default: Any = UNSET) -> Any:
|
|
344
|
+
"""Get variable value, raising if unset and no default provided.
|
|
345
|
+
|
|
346
|
+
Args:
|
|
347
|
+
var_id: Variable identifier
|
|
348
|
+
default: Value to return if variable is unset. If not provided,
|
|
349
|
+
raises ValueError on unset variables.
|
|
350
|
+
|
|
351
|
+
Returns:
|
|
352
|
+
Variable value (may be None if explicitly set to None)
|
|
353
|
+
|
|
354
|
+
Raises:
|
|
355
|
+
ValueError: If variable is unset and no default provided
|
|
356
|
+
|
|
357
|
+
Examples:
|
|
358
|
+
# Required variable - throws if unset
|
|
359
|
+
value = message.get_variable("user_input")
|
|
360
|
+
|
|
361
|
+
# Optional variable - returns None if unset
|
|
362
|
+
value = message.get_variable("optional_field", default=None)
|
|
363
|
+
|
|
364
|
+
# Optional with custom default
|
|
365
|
+
value = message.get_variable("count", default=0)
|
|
366
|
+
"""
|
|
367
|
+
value = self.variables.get(var_id, UNSET)
|
|
368
|
+
|
|
369
|
+
if value is UNSET:
|
|
370
|
+
if default is UNSET:
|
|
371
|
+
raise ValueError(
|
|
372
|
+
(
|
|
373
|
+
f"Required variable '{var_id}' is not set. "
|
|
374
|
+
f"Available variables: {list(self.variables.keys())}"
|
|
375
|
+
)
|
|
376
|
+
)
|
|
377
|
+
return default
|
|
378
|
+
|
|
379
|
+
return value
|
|
380
|
+
|
|
310
381
|
def copy_with_error(self, step_id: str, exc: Exception) -> "FlowMessage":
|
|
311
382
|
"""Returns a copy of this state marked as failed."""
|
|
312
383
|
return self.model_copy(
|
|
@@ -319,15 +390,29 @@ class FlowMessage(BaseModel):
|
|
|
319
390
|
}
|
|
320
391
|
)
|
|
321
392
|
|
|
322
|
-
# It's useful to have copy-on-write style helpers
|
|
323
393
|
def copy_with_variables(
|
|
324
394
|
self, new_variables: dict[str, Any]
|
|
325
395
|
) -> "FlowMessage":
|
|
396
|
+
"""Create a new FlowMessage with updated variables.
|
|
397
|
+
|
|
398
|
+
Note: Can set variables to UNSET to explicitly mark them as unset.
|
|
399
|
+
"""
|
|
326
400
|
new_vars = self.variables.copy()
|
|
327
401
|
new_vars.update(new_variables)
|
|
328
402
|
new_state = self.model_copy(update={"variables": new_vars})
|
|
329
403
|
return new_state
|
|
330
404
|
|
|
405
|
+
@model_serializer
|
|
406
|
+
def serialize_model(self):
|
|
407
|
+
"""Custom serialization that excludes UNSET variables."""
|
|
408
|
+
return {
|
|
409
|
+
"session": self.session,
|
|
410
|
+
"variables": {
|
|
411
|
+
k: v for k, v in self.variables.items() if v is not UNSET
|
|
412
|
+
},
|
|
413
|
+
"error": self.error,
|
|
414
|
+
}
|
|
415
|
+
|
|
331
416
|
|
|
332
417
|
class InterpreterError(Exception):
|
|
333
418
|
"""Base exception class for ProtoGen interpreter errors."""
|
qtype/interpreter/typing.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import uuid
|
|
4
|
-
from typing import Any, Type
|
|
4
|
+
from typing import Any, Type
|
|
5
5
|
|
|
6
|
-
from pydantic import BaseModel, Field,
|
|
6
|
+
from pydantic import BaseModel, Field, create_model
|
|
7
7
|
|
|
8
8
|
from qtype.dsl.model import ListType, PrimitiveTypeEnum
|
|
9
9
|
from qtype.dsl.model import Variable as DSLVariable
|
|
@@ -138,37 +138,36 @@ def flow_results_to_output_container(
|
|
|
138
138
|
return output_container(outputs=outputs, errors=errors)
|
|
139
139
|
|
|
140
140
|
|
|
141
|
-
def
|
|
141
|
+
def convert_dict_to_typed_variables(
|
|
142
|
+
data: dict[str, Any], variables: list[Variable]
|
|
143
|
+
) -> dict[str, Any]:
|
|
142
144
|
"""
|
|
143
|
-
|
|
144
|
-
|
|
145
|
+
Convert a dictionary of raw values to properly typed variables.
|
|
146
|
+
|
|
147
|
+
Uses Pydantic model validation to convert all values at once based on
|
|
148
|
+
Variable type declarations. This is more efficient than converting each
|
|
149
|
+
field individually.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
data: Dictionary with raw values (e.g., from DataFrame row)
|
|
153
|
+
variables: List of Variable definitions with type information
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
Dictionary with values converted to their declared types
|
|
157
|
+
|
|
158
|
+
Raises:
|
|
159
|
+
ValidationError: If values cannot be converted to declared types
|
|
145
160
|
"""
|
|
146
|
-
|
|
161
|
+
# Create a Pydantic model from the variable definitions
|
|
162
|
+
model_class = create_model(
|
|
163
|
+
"TypedVariables",
|
|
164
|
+
__base__=BaseModel,
|
|
165
|
+
**_fields_from_variables(variables),
|
|
166
|
+
)
|
|
147
167
|
|
|
148
|
-
#
|
|
149
|
-
|
|
150
|
-
origin = get_origin(target_type)
|
|
168
|
+
# Validate and convert the data using Pydantic
|
|
169
|
+
validated = model_class.model_validate(data)
|
|
151
170
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
return value
|
|
156
|
-
else:
|
|
157
|
-
# It's a generic (list[str], etc.).
|
|
158
|
-
# We skip the identity check and let TypeAdapter handle it.
|
|
159
|
-
pass
|
|
160
|
-
|
|
161
|
-
# 2. Handle Pydantic Models (Custom/Domain Types)
|
|
162
|
-
if hasattr(target_type, "model_validate"):
|
|
163
|
-
return target_type.model_validate(value) # type: ignore[misc]
|
|
164
|
-
|
|
165
|
-
# 3. Handle Primitives & Complex Python Types (List, Optional, Union)
|
|
166
|
-
try:
|
|
167
|
-
# TypeAdapter is the "V2 way" to validate things that aren't
|
|
168
|
-
# full Pydantic models (like List[int] or Optional[str])
|
|
169
|
-
return TypeAdapter(target_type).validate_python(value)
|
|
170
|
-
except Exception:
|
|
171
|
-
# Fallback to your original manual cast if TypeAdapter is overkill
|
|
172
|
-
if isinstance(target_type, type):
|
|
173
|
-
return target_type(value)
|
|
174
|
-
raise ValueError(f"Unsupported target type: {target_type}")
|
|
171
|
+
# Return as dict but preserve actual typed instances (not serialized)
|
|
172
|
+
# Use __dict__ to get the actual field values without serialization
|
|
173
|
+
return dict(validated)
|