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
qtype/mcp/server.py
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
-
import
|
|
4
|
+
import tempfile
|
|
5
5
|
from functools import lru_cache
|
|
6
6
|
from importlib.resources import files
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from typing import Any
|
|
9
9
|
|
|
10
|
+
import tantivy
|
|
10
11
|
from mcp.server.fastmcp import FastMCP
|
|
11
12
|
from pydantic import BaseModel
|
|
12
13
|
|
|
14
|
+
from qtype.base.resources import get_docs_resource, get_examples_resource
|
|
13
15
|
from qtype.commands.convert import convert_to_yaml
|
|
14
16
|
|
|
15
17
|
# Initialize FastMCP server
|
|
16
18
|
mcp = FastMCP("qtype", host="0.0.0.0")
|
|
17
19
|
|
|
18
|
-
#
|
|
19
|
-
|
|
20
|
+
# Get resource directories from base layer
|
|
21
|
+
_docs_resource = get_docs_resource()
|
|
22
|
+
_examples_resource = get_examples_resource()
|
|
20
23
|
|
|
21
24
|
|
|
22
25
|
# ============================================================================
|
|
@@ -24,24 +27,6 @@ SNIPPET_REGEX = re.compile(r'--8<--\s+"([^"]+)"')
|
|
|
24
27
|
# ============================================================================
|
|
25
28
|
|
|
26
29
|
|
|
27
|
-
def _get_docs_path() -> Path:
|
|
28
|
-
"""Get the path to the documentation directory.
|
|
29
|
-
|
|
30
|
-
Returns:
|
|
31
|
-
Path to the docs directory, trying installed package first,
|
|
32
|
-
then falling back to development path.
|
|
33
|
-
"""
|
|
34
|
-
try:
|
|
35
|
-
# Try to get from installed package
|
|
36
|
-
docs_root = files("qtype") / "docs"
|
|
37
|
-
# Check if it exists by trying to iterate
|
|
38
|
-
list(docs_root.iterdir())
|
|
39
|
-
return Path(str(docs_root))
|
|
40
|
-
except (FileNotFoundError, AttributeError, TypeError):
|
|
41
|
-
# Fall back to development path
|
|
42
|
-
return Path(__file__).parent.parent.parent / "docs"
|
|
43
|
-
|
|
44
|
-
|
|
45
30
|
@lru_cache(maxsize=1)
|
|
46
31
|
def _load_schema() -> dict[str, Any]:
|
|
47
32
|
"""Load the QType schema JSON file once and cache it.
|
|
@@ -55,7 +40,7 @@ def _load_schema() -> dict[str, Any]:
|
|
|
55
40
|
"""
|
|
56
41
|
# Try to load from installed package data first
|
|
57
42
|
try:
|
|
58
|
-
schema_file = files("qtype") / "qtype.schema.json"
|
|
43
|
+
schema_file = files("qtype") / "schema" / "qtype.schema.json"
|
|
59
44
|
schema_text = schema_file.read_text(encoding="utf-8")
|
|
60
45
|
return json.loads(schema_text)
|
|
61
46
|
except (FileNotFoundError, AttributeError):
|
|
@@ -67,38 +52,88 @@ def _load_schema() -> dict[str, Any]:
|
|
|
67
52
|
return json.load(f)
|
|
68
53
|
|
|
69
54
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
Mimics the behavior of pymdownx.snippets.
|
|
55
|
+
@lru_cache(maxsize=1)
|
|
56
|
+
def _build_search_index() -> tantivy.Index:
|
|
57
|
+
"""Build and cache a Tantivy search index for docs and examples.
|
|
74
58
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
59
|
+
Returns:
|
|
60
|
+
A Tantivy Index containing all documentation markdown files
|
|
61
|
+
and example YAML files.
|
|
62
|
+
|
|
63
|
+
Raises:
|
|
64
|
+
Exception: If index building fails.
|
|
78
65
|
"""
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
66
|
+
docs_path = _docs_resource.get_path()
|
|
67
|
+
examples_path = _examples_resource.get_path()
|
|
68
|
+
|
|
69
|
+
# Create schema with fields for title, path, and content
|
|
70
|
+
schema_builder = tantivy.SchemaBuilder()
|
|
71
|
+
schema_builder.add_text_field("title", stored=True)
|
|
72
|
+
schema_builder.add_text_field("path", stored=True)
|
|
73
|
+
schema_builder.add_text_field("content", stored=True)
|
|
74
|
+
schema_builder.add_text_field("type", stored=True)
|
|
75
|
+
schema = schema_builder.build()
|
|
76
|
+
|
|
77
|
+
# Create index in temporary directory
|
|
78
|
+
index = tantivy.Index(schema, path=tempfile.mkdtemp())
|
|
79
|
+
writer = index.writer()
|
|
80
|
+
|
|
81
|
+
# Helper to index files
|
|
82
|
+
def index_files(
|
|
83
|
+
root_path: Path,
|
|
84
|
+
pattern: str,
|
|
85
|
+
type_label: str,
|
|
86
|
+
path_prefix: str,
|
|
87
|
+
process_content=None,
|
|
88
|
+
extract_title=None,
|
|
89
|
+
):
|
|
90
|
+
for file_path in root_path.rglob(pattern):
|
|
91
|
+
content = file_path.read_text(encoding="utf-8")
|
|
92
|
+
if process_content:
|
|
93
|
+
content = process_content(content, file_path)
|
|
94
|
+
|
|
95
|
+
rel_path = str(file_path.relative_to(root_path))
|
|
96
|
+
title = (
|
|
97
|
+
extract_title(content, file_path)
|
|
98
|
+
if extract_title
|
|
99
|
+
else file_path.stem
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
writer.add_document(
|
|
103
|
+
tantivy.Document(
|
|
104
|
+
title=title,
|
|
105
|
+
path=f"{path_prefix}/{rel_path}",
|
|
106
|
+
content=content,
|
|
107
|
+
type=type_label,
|
|
97
108
|
)
|
|
109
|
+
)
|
|
98
110
|
|
|
99
|
-
|
|
111
|
+
# Extract title from markdown first heading
|
|
112
|
+
def extract_md_title(content: str, file_path: Path) -> str:
|
|
113
|
+
for line in content.split("\n"):
|
|
114
|
+
if line.startswith("# "):
|
|
115
|
+
return line[2:].strip()
|
|
116
|
+
return file_path.stem
|
|
117
|
+
|
|
118
|
+
# For snippet resolution in search indexing
|
|
119
|
+
def resolve_for_indexing(content: str, file_path: Path) -> str:
|
|
120
|
+
from qtype.base.resources import _resolve_snippets
|
|
121
|
+
|
|
122
|
+
return _resolve_snippets(content, file_path, _docs_resource)
|
|
123
|
+
|
|
124
|
+
# Index documentation and examples
|
|
125
|
+
index_files(
|
|
126
|
+
docs_path,
|
|
127
|
+
"*.md",
|
|
128
|
+
"documentation",
|
|
129
|
+
"docs",
|
|
130
|
+
process_content=resolve_for_indexing,
|
|
131
|
+
extract_title=extract_md_title,
|
|
132
|
+
)
|
|
133
|
+
index_files(examples_path, "*.yaml", "example", "examples")
|
|
100
134
|
|
|
101
|
-
|
|
135
|
+
writer.commit()
|
|
136
|
+
return index
|
|
102
137
|
|
|
103
138
|
|
|
104
139
|
# ============================================================================
|
|
@@ -122,6 +157,10 @@ class MermaidVisualizationResult(BaseModel):
|
|
|
122
157
|
preview_instructions: str
|
|
123
158
|
|
|
124
159
|
|
|
160
|
+
# Rebuild model after nested dependency is defined
|
|
161
|
+
MermaidVisualizationResult.model_rebuild()
|
|
162
|
+
|
|
163
|
+
|
|
125
164
|
@mcp.tool(
|
|
126
165
|
title="Convert API Specification to QType Tools",
|
|
127
166
|
description=(
|
|
@@ -287,36 +326,13 @@ def get_documentation(file_path: str) -> str:
|
|
|
287
326
|
Use list_documentation to see all available files.
|
|
288
327
|
|
|
289
328
|
Returns:
|
|
290
|
-
The full markdown content of the documentation file.
|
|
329
|
+
The full markdown content of the documentation file with snippets resolved.
|
|
291
330
|
|
|
292
331
|
Raises:
|
|
293
332
|
FileNotFoundError: If the specified file doesn't exist.
|
|
294
333
|
ValueError: If the path tries to access files outside the docs directory.
|
|
295
334
|
"""
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
# Resolve the requested file path
|
|
299
|
-
requested_file = (docs_path / file_path).resolve()
|
|
300
|
-
|
|
301
|
-
# Security check: ensure the resolved path is within docs directory
|
|
302
|
-
try:
|
|
303
|
-
requested_file.relative_to(docs_path.resolve())
|
|
304
|
-
except ValueError:
|
|
305
|
-
raise ValueError(
|
|
306
|
-
f"Invalid path: '{file_path}' is outside documentation directory"
|
|
307
|
-
)
|
|
308
|
-
|
|
309
|
-
if not requested_file.exists():
|
|
310
|
-
raise FileNotFoundError(
|
|
311
|
-
f"Documentation file not found: '{file_path}'. "
|
|
312
|
-
"Use list_documentation to see available files."
|
|
313
|
-
)
|
|
314
|
-
|
|
315
|
-
if not requested_file.is_file():
|
|
316
|
-
raise ValueError(f"Path is not a file: '{file_path}'")
|
|
317
|
-
|
|
318
|
-
content = requested_file.read_text(encoding="utf-8")
|
|
319
|
-
return resolve_snippets(content, requested_file)
|
|
335
|
+
return _docs_resource.get_file(file_path)
|
|
320
336
|
|
|
321
337
|
|
|
322
338
|
@mcp.tool(
|
|
@@ -363,21 +379,113 @@ def list_documentation() -> list[str]:
|
|
|
363
379
|
Paths are relative to the docs root (e.g., "components/Flow.md",
|
|
364
380
|
"Tutorials/getting_started.md").
|
|
365
381
|
"""
|
|
366
|
-
|
|
382
|
+
return _docs_resource.list_files()
|
|
367
383
|
|
|
368
|
-
if not docs_path.exists():
|
|
369
|
-
raise FileNotFoundError(
|
|
370
|
-
f"Documentation directory not found: {docs_path}"
|
|
371
|
-
)
|
|
372
384
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
385
|
+
@mcp.tool(
|
|
386
|
+
title="Get QType Example",
|
|
387
|
+
description=(
|
|
388
|
+
"Returns the content of a specific example YAML file. "
|
|
389
|
+
"Use list_examples first to see available files. "
|
|
390
|
+
"Provide the relative path (e.g., 'conversational_ai/simple_chatbot.qtype.yaml', "
|
|
391
|
+
"'data_processing/csv_processor.qtype.yaml')."
|
|
392
|
+
),
|
|
393
|
+
)
|
|
394
|
+
def get_example(file_path: str) -> str:
|
|
395
|
+
"""Get the content of a specific example file.
|
|
396
|
+
|
|
397
|
+
Args:
|
|
398
|
+
file_path: Relative path to the example file from the examples root.
|
|
399
|
+
Example: "conversational_ai/simple_chatbot.qtype.yaml",
|
|
400
|
+
"data_processing/csv_processor.qtype.yaml".
|
|
401
|
+
Use list_examples to see all available files.
|
|
402
|
+
|
|
403
|
+
Returns:
|
|
404
|
+
The full YAML content of the example file.
|
|
405
|
+
|
|
406
|
+
Raises:
|
|
407
|
+
FileNotFoundError: If the specified file doesn't exist.
|
|
408
|
+
ValueError: If the path tries to access files outside the examples directory.
|
|
409
|
+
"""
|
|
410
|
+
return _examples_resource.get_file(file_path)
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
@mcp.tool(
|
|
414
|
+
title="List QType Examples",
|
|
415
|
+
description=(
|
|
416
|
+
"Returns a list of all available example YAML files. "
|
|
417
|
+
"Use this to discover what examples exist, then retrieve "
|
|
418
|
+
"specific files with get_example. Examples are organized by category: "
|
|
419
|
+
"conversational_ai/ (chatbots and agents), data_processing/ (ETL and transformations), "
|
|
420
|
+
"invoke_models/ (LLM usage), language_features/ (QType syntax examples), etc."
|
|
421
|
+
),
|
|
422
|
+
structured_output=True,
|
|
423
|
+
)
|
|
424
|
+
def list_examples() -> list[str]:
|
|
425
|
+
"""List all available example YAML files.
|
|
426
|
+
|
|
427
|
+
Returns:
|
|
428
|
+
Sorted list of relative paths to all .yaml example files.
|
|
429
|
+
Paths are relative to the examples root (e.g.,
|
|
430
|
+
"conversational_ai/simple_chatbot.qtype.yaml",
|
|
431
|
+
"data_processing/csv_processor.qtype.yaml").
|
|
432
|
+
"""
|
|
433
|
+
return _examples_resource.list_files()
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
@mcp.tool(
|
|
437
|
+
title="Search QType Library",
|
|
438
|
+
description=(
|
|
439
|
+
"Full-text search across all QType documentation and examples. "
|
|
440
|
+
"Returns matching documents and example YAML files ranked by relevance. "
|
|
441
|
+
"Use this to find documentation about specific topics, features, or components, "
|
|
442
|
+
"or to discover example implementations. Doc paths can be used with get_documentation."
|
|
443
|
+
),
|
|
444
|
+
structured_output=True,
|
|
445
|
+
)
|
|
446
|
+
def search_library(query: str, limit: int = 10) -> list[dict[str, Any]]:
|
|
447
|
+
"""Search library using full-text search.
|
|
448
|
+
|
|
449
|
+
Args:
|
|
450
|
+
query: Search query string. Can include multiple words, phrases,
|
|
451
|
+
or boolean operators (AND, OR, NOT).
|
|
452
|
+
limit: Maximum number of results to return (default: 10, max: 50).
|
|
453
|
+
|
|
454
|
+
Returns:
|
|
455
|
+
List of matching items with:
|
|
456
|
+
- title: Item title
|
|
457
|
+
- path: Relative path (docs/ or examples/ prefix)
|
|
458
|
+
- type: Either "documentation" or "example"
|
|
459
|
+
- score: Relevance score (higher is more relevant)
|
|
460
|
+
|
|
461
|
+
Examples:
|
|
462
|
+
search_library("flow execution") # Find docs/examples about flows
|
|
463
|
+
search_library("DocumentSource") # Find component docs
|
|
464
|
+
search_library("authentication AND API") # Boolean search
|
|
465
|
+
"""
|
|
466
|
+
# Clamp limit to reasonable range
|
|
467
|
+
limit = max(1, min(limit, 50))
|
|
468
|
+
|
|
469
|
+
index = _build_search_index()
|
|
470
|
+
index.reload()
|
|
471
|
+
searcher = index.searcher()
|
|
472
|
+
tantivy_query = index.parse_query(query, ["title", "content"])
|
|
473
|
+
|
|
474
|
+
search_results = searcher.search(tantivy_query, limit)
|
|
475
|
+
|
|
476
|
+
results = []
|
|
477
|
+
for score, doc_address in search_results.hits:
|
|
478
|
+
doc = searcher.doc(doc_address)
|
|
479
|
+
results.append(
|
|
480
|
+
{
|
|
481
|
+
"title": doc["title"][0],
|
|
482
|
+
"path": doc["path"][0],
|
|
483
|
+
"type": doc["type"][0],
|
|
484
|
+
"score": score,
|
|
485
|
+
}
|
|
486
|
+
)
|
|
379
487
|
|
|
380
|
-
return
|
|
488
|
+
return results
|
|
381
489
|
|
|
382
490
|
|
|
383
491
|
@mcp.tool(
|
|
@@ -68,20 +68,20 @@
|
|
|
68
68
|
"type": "string"
|
|
69
69
|
},
|
|
70
70
|
"inputs": {
|
|
71
|
-
"additionalProperties": {
|
|
72
|
-
"$ref": "#/$defs/ToolParameter"
|
|
73
|
-
},
|
|
74
71
|
"description": "Input parameters required by this tool.",
|
|
72
|
+
"items": {
|
|
73
|
+
"$ref": "#/$defs/Variable"
|
|
74
|
+
},
|
|
75
75
|
"title": "Inputs",
|
|
76
|
-
"type": "
|
|
76
|
+
"type": "array"
|
|
77
77
|
},
|
|
78
78
|
"outputs": {
|
|
79
|
-
"additionalProperties": {
|
|
80
|
-
"$ref": "#/$defs/ToolParameter"
|
|
81
|
-
},
|
|
82
79
|
"description": "Output parameters produced by this tool.",
|
|
80
|
+
"items": {
|
|
81
|
+
"$ref": "#/$defs/Variable"
|
|
82
|
+
},
|
|
83
83
|
"title": "Outputs",
|
|
84
|
-
"type": "
|
|
84
|
+
"type": "array"
|
|
85
85
|
},
|
|
86
86
|
"type": {
|
|
87
87
|
"const": "APITool",
|
|
@@ -125,12 +125,12 @@
|
|
|
125
125
|
"type": "object"
|
|
126
126
|
},
|
|
127
127
|
"parameters": {
|
|
128
|
-
"
|
|
129
|
-
|
|
128
|
+
"description": "Path and query parameters for the API call.",
|
|
129
|
+
"items": {
|
|
130
|
+
"$ref": "#/$defs/Variable"
|
|
130
131
|
},
|
|
131
|
-
"description": "Output parameters produced by this tool.",
|
|
132
132
|
"title": "Parameters",
|
|
133
|
-
"type": "
|
|
133
|
+
"type": "array"
|
|
134
134
|
}
|
|
135
135
|
},
|
|
136
136
|
"required": [
|
|
@@ -439,7 +439,7 @@
|
|
|
439
439
|
},
|
|
440
440
|
"Aggregate": {
|
|
441
441
|
"additionalProperties": false,
|
|
442
|
-
"description": "A
|
|
442
|
+
"description": "A step that, after all messages have been processed,\nreturns a single message containing the counts of successful and failed\nmessages. Other messages are passed through unchanged.",
|
|
443
443
|
"properties": {
|
|
444
444
|
"cache_config": {
|
|
445
445
|
"anyOf": [
|
|
@@ -480,7 +480,7 @@
|
|
|
480
480
|
"type": "array"
|
|
481
481
|
},
|
|
482
482
|
"outputs": {
|
|
483
|
-
"description": "References to the variables
|
|
483
|
+
"description": "References to the variables where output is stored.",
|
|
484
484
|
"items": {
|
|
485
485
|
"anyOf": [
|
|
486
486
|
{
|
|
@@ -1084,18 +1084,25 @@
|
|
|
1084
1084
|
"title": "Outputs",
|
|
1085
1085
|
"type": "array"
|
|
1086
1086
|
},
|
|
1087
|
-
"
|
|
1087
|
+
"field_bindings": {
|
|
1088
1088
|
"additionalProperties": {
|
|
1089
|
-
"
|
|
1089
|
+
"anyOf": [
|
|
1090
|
+
{
|
|
1091
|
+
"$ref": "#/$defs/Reference_Variable_"
|
|
1092
|
+
},
|
|
1093
|
+
{
|
|
1094
|
+
"type": "string"
|
|
1095
|
+
}
|
|
1096
|
+
]
|
|
1090
1097
|
},
|
|
1091
|
-
"description": "Mapping
|
|
1092
|
-
"title": "Field
|
|
1098
|
+
"description": "Mapping from type field names to flow variable names.",
|
|
1099
|
+
"title": "Field Bindings",
|
|
1093
1100
|
"type": "object"
|
|
1094
1101
|
}
|
|
1095
1102
|
},
|
|
1096
1103
|
"required": [
|
|
1097
1104
|
"id",
|
|
1098
|
-
"
|
|
1105
|
+
"field_bindings"
|
|
1099
1106
|
],
|
|
1100
1107
|
"title": "Construct",
|
|
1101
1108
|
"type": "object"
|
|
@@ -1962,7 +1969,7 @@
|
|
|
1962
1969
|
},
|
|
1963
1970
|
"FieldExtractor": {
|
|
1964
1971
|
"additionalProperties": false,
|
|
1965
|
-
"description": "Extracts specific fields from input data using JSONPath expressions.\n\nThis step uses JSONPath syntax to extract data from structured inputs\n(Pydantic models, dicts, lists). The input is first converted to a dict\nusing model_dump() if it's a Pydantic model, then the JSONPath expression\nis evaluated.\n\nIf the JSONPath matches multiple values, the step yields multiple output\nmessages (1-to-many cardinality). If it matches a single value, it yields\none output message. If it matches nothing, it raises an error.\n\nThe extracted data is used to construct the output variable by passing it\nas keyword arguments to the output type's constructor.\n\nExample JSONPath expressions:\n- `$.field_name` - Extract a single field\n- `$.items[*]` - Extract all items from a list\n- `$.items[?(@.price > 10)]` - Filter items by condition",
|
|
1972
|
+
"description": "Extracts specific fields from input data using JSONPath expressions.\n\nThis step uses JSONPath syntax to extract data from structured inputs\n(Pydantic models, dicts, lists). The input is first converted to a dict\nusing model_dump() if it's a Pydantic model, then the JSONPath expression\nis evaluated.\n\nIf the JSONPath matches multiple values, the step yields multiple output\nmessages (1-to-many cardinality). If it matches a single value, it yields\none output message. If it matches nothing, it raises an error.\n\nThe extracted data is used to construct the output variable by passing it\nas keyword arguments to the output type's constructor.\n\nIf there is no match and the output variable is optional, it is set to None.\nIf there is no match and the output variable is required, an error is raised.\n\nExample JSONPath expressions:\n- `$.field_name` - Extract a single field\n- `$.items[*]` - Extract all items from a list\n- `$.items[?(@.price > 10)]` - Filter items by condition",
|
|
1966
1973
|
"properties": {
|
|
1967
1974
|
"cache_config": {
|
|
1968
1975
|
"anyOf": [
|
|
@@ -2021,12 +2028,6 @@
|
|
|
2021
2028
|
"description": "JSONPath expression to extract data from the input. Uses jsonpath-ng syntax.",
|
|
2022
2029
|
"title": "Json Path",
|
|
2023
2030
|
"type": "string"
|
|
2024
|
-
},
|
|
2025
|
-
"fail_on_missing": {
|
|
2026
|
-
"default": true,
|
|
2027
|
-
"description": "Whether to raise an error if the JSONPath matches no data. If False, returns None.",
|
|
2028
|
-
"title": "Fail On Missing",
|
|
2029
|
-
"type": "boolean"
|
|
2030
2031
|
}
|
|
2031
2032
|
},
|
|
2032
2033
|
"required": [
|
|
@@ -2678,23 +2679,31 @@
|
|
|
2678
2679
|
},
|
|
2679
2680
|
"input_bindings": {
|
|
2680
2681
|
"additionalProperties": {
|
|
2681
|
-
"
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2682
|
+
"anyOf": [
|
|
2683
|
+
{
|
|
2684
|
+
"$ref": "#/$defs/Reference_Variable_"
|
|
2685
|
+
},
|
|
2686
|
+
{
|
|
2687
|
+
"type": "string"
|
|
2688
|
+
}
|
|
2689
|
+
]
|
|
2686
2690
|
},
|
|
2691
|
+
"description": "Mapping from flow input variable IDs to step variable names.",
|
|
2687
2692
|
"title": "Input Bindings",
|
|
2688
2693
|
"type": "object"
|
|
2689
2694
|
},
|
|
2690
2695
|
"output_bindings": {
|
|
2691
2696
|
"additionalProperties": {
|
|
2692
|
-
"
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
+
"anyOf": [
|
|
2698
|
+
{
|
|
2699
|
+
"$ref": "#/$defs/Reference_Variable_"
|
|
2700
|
+
},
|
|
2701
|
+
{
|
|
2702
|
+
"type": "string"
|
|
2703
|
+
}
|
|
2704
|
+
]
|
|
2697
2705
|
},
|
|
2706
|
+
"description": "Mapping from flow output variable IDs to step variable names.",
|
|
2698
2707
|
"title": "Output Bindings",
|
|
2699
2708
|
"type": "object"
|
|
2700
2709
|
}
|
|
@@ -2783,17 +2792,31 @@
|
|
|
2783
2792
|
},
|
|
2784
2793
|
"input_bindings": {
|
|
2785
2794
|
"additionalProperties": {
|
|
2786
|
-
"
|
|
2795
|
+
"anyOf": [
|
|
2796
|
+
{
|
|
2797
|
+
"$ref": "#/$defs/Reference_Variable_"
|
|
2798
|
+
},
|
|
2799
|
+
{
|
|
2800
|
+
"type": "string"
|
|
2801
|
+
}
|
|
2802
|
+
]
|
|
2787
2803
|
},
|
|
2788
|
-
"description": "Mapping from
|
|
2804
|
+
"description": "Mapping from tool parameter names to flow variable names.",
|
|
2789
2805
|
"title": "Input Bindings",
|
|
2790
2806
|
"type": "object"
|
|
2791
2807
|
},
|
|
2792
2808
|
"output_bindings": {
|
|
2793
2809
|
"additionalProperties": {
|
|
2794
|
-
"
|
|
2810
|
+
"anyOf": [
|
|
2811
|
+
{
|
|
2812
|
+
"$ref": "#/$defs/Reference_Variable_"
|
|
2813
|
+
},
|
|
2814
|
+
{
|
|
2815
|
+
"type": "string"
|
|
2816
|
+
}
|
|
2817
|
+
]
|
|
2795
2818
|
},
|
|
2796
|
-
"description": "Mapping from
|
|
2819
|
+
"description": "Mapping from tool output names to flow variable names.",
|
|
2797
2820
|
"title": "Output Bindings",
|
|
2798
2821
|
"type": "object"
|
|
2799
2822
|
}
|
|
@@ -3230,20 +3253,20 @@
|
|
|
3230
3253
|
"type": "string"
|
|
3231
3254
|
},
|
|
3232
3255
|
"inputs": {
|
|
3233
|
-
"additionalProperties": {
|
|
3234
|
-
"$ref": "#/$defs/ToolParameter"
|
|
3235
|
-
},
|
|
3236
3256
|
"description": "Input parameters required by this tool.",
|
|
3257
|
+
"items": {
|
|
3258
|
+
"$ref": "#/$defs/Variable"
|
|
3259
|
+
},
|
|
3237
3260
|
"title": "Inputs",
|
|
3238
|
-
"type": "
|
|
3261
|
+
"type": "array"
|
|
3239
3262
|
},
|
|
3240
3263
|
"outputs": {
|
|
3241
|
-
"additionalProperties": {
|
|
3242
|
-
"$ref": "#/$defs/ToolParameter"
|
|
3243
|
-
},
|
|
3244
3264
|
"description": "Output parameters produced by this tool.",
|
|
3265
|
+
"items": {
|
|
3266
|
+
"$ref": "#/$defs/Variable"
|
|
3267
|
+
},
|
|
3245
3268
|
"title": "Outputs",
|
|
3246
|
-
"type": "
|
|
3269
|
+
"type": "array"
|
|
3247
3270
|
},
|
|
3248
3271
|
"type": {
|
|
3249
3272
|
"const": "PythonFunctionTool",
|
|
@@ -3658,37 +3681,6 @@
|
|
|
3658
3681
|
"title": "ToolList",
|
|
3659
3682
|
"type": "array"
|
|
3660
3683
|
},
|
|
3661
|
-
"ToolParameter": {
|
|
3662
|
-
"description": "Defines a tool input or output parameter with type and optional flag.",
|
|
3663
|
-
"properties": {
|
|
3664
|
-
"type": {
|
|
3665
|
-
"anyOf": [
|
|
3666
|
-
{
|
|
3667
|
-
"$ref": "#/$defs/PrimitiveTypeEnum"
|
|
3668
|
-
},
|
|
3669
|
-
{},
|
|
3670
|
-
{
|
|
3671
|
-
"$ref": "#/$defs/ListType"
|
|
3672
|
-
},
|
|
3673
|
-
{
|
|
3674
|
-
"type": "string"
|
|
3675
|
-
}
|
|
3676
|
-
],
|
|
3677
|
-
"title": "Type"
|
|
3678
|
-
},
|
|
3679
|
-
"optional": {
|
|
3680
|
-
"default": false,
|
|
3681
|
-
"description": "Whether this parameter is optional",
|
|
3682
|
-
"title": "Optional",
|
|
3683
|
-
"type": "boolean"
|
|
3684
|
-
}
|
|
3685
|
-
},
|
|
3686
|
-
"required": [
|
|
3687
|
-
"type"
|
|
3688
|
-
],
|
|
3689
|
-
"title": "ToolParameter",
|
|
3690
|
-
"type": "object"
|
|
3691
|
-
},
|
|
3692
3684
|
"TypeList": {
|
|
3693
3685
|
"description": "Schema for a standalone list of type definitions.",
|
|
3694
3686
|
"items": {
|
|
@@ -3722,6 +3714,12 @@
|
|
|
3722
3714
|
"description": "Type of data expected or produced. Either a CustomType or domain specific type.",
|
|
3723
3715
|
"title": "Type"
|
|
3724
3716
|
},
|
|
3717
|
+
"optional": {
|
|
3718
|
+
"default": false,
|
|
3719
|
+
"description": "Whether this variable can be unset or None. Use '?' suffix in type string as shorthand (e.g., 'text?').",
|
|
3720
|
+
"title": "Optional",
|
|
3721
|
+
"type": "boolean"
|
|
3722
|
+
},
|
|
3725
3723
|
"ui": {
|
|
3726
3724
|
"anyOf": [
|
|
3727
3725
|
{
|
qtype/semantic/checker.py
CHANGED
|
@@ -50,6 +50,10 @@ class FlowHasNoStepsError(QTypeValidationError):
|
|
|
50
50
|
# Alias for backward compatibility and semantic clarity
|
|
51
51
|
QTypeSemanticError = SemanticError
|
|
52
52
|
|
|
53
|
+
# Step types that support text streaming
|
|
54
|
+
# These are the only step types that can produce streaming text output
|
|
55
|
+
STREAMING_STEP_TYPES = (LLMInference, Agent)
|
|
56
|
+
|
|
53
57
|
|
|
54
58
|
# ---- Helper Functions for Common Validation Patterns ----
|
|
55
59
|
|
|
@@ -543,6 +547,21 @@ def _validate_flow(flow: Flow) -> None:
|
|
|
543
547
|
f"Flow {flow.id} has a Complete interface but {len(text_outputs)} text outputs -- there should be 1."
|
|
544
548
|
)
|
|
545
549
|
|
|
550
|
+
# Ensure the final step supports streaming for Complete interface
|
|
551
|
+
if flow.steps:
|
|
552
|
+
final_step = flow.steps[-1]
|
|
553
|
+
if not isinstance(final_step, STREAMING_STEP_TYPES):
|
|
554
|
+
streaming_type_names = ", ".join(
|
|
555
|
+
t.__name__ for t in STREAMING_STEP_TYPES
|
|
556
|
+
)
|
|
557
|
+
raise QTypeSemanticError(
|
|
558
|
+
(
|
|
559
|
+
f"Flow {flow.id} has a Complete interface which requires streaming output, "
|
|
560
|
+
f"but the final step '{final_step.id}' is of type '{final_step.type}' which does not support streaming. "
|
|
561
|
+
f"The final step must be one of: {streaming_type_names}."
|
|
562
|
+
)
|
|
563
|
+
)
|
|
564
|
+
|
|
546
565
|
|
|
547
566
|
def _has_secret_reference(obj: Any) -> bool:
|
|
548
567
|
"""
|