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.
Files changed (272) hide show
  1. qtype/` +0 -0
  2. qtype/application/__init__.py +0 -2
  3. qtype/application/converters/tools_from_api.py +28 -22
  4. qtype/application/converters/tools_from_module.py +66 -32
  5. qtype/base/__init__.py +8 -2
  6. qtype/base/logging.py +0 -17
  7. qtype/base/resources.py +193 -0
  8. qtype/cli.py +5 -9
  9. qtype/commands/generate.py +95 -7
  10. qtype/commands/run.py +153 -54
  11. qtype/docs/.pages +8 -0
  12. {docs → qtype/docs}/Concepts/mental-model-and-philosophy.md +1 -1
  13. qtype/docs/Contributing/.pages +4 -0
  14. {docs → qtype/docs}/Contributing/index.md +8 -1
  15. {docs → qtype/docs}/Gallery/dataflow_pipelines.md +18 -4
  16. qtype/docs/Gallery/recipe_chatbot.md +103 -0
  17. qtype/docs/Gallery/recipe_chatbot.mermaid +62 -0
  18. qtype/docs/Gallery/recipe_chatbot.png +0 -0
  19. {docs → qtype/docs}/Gallery/research_assistant.md +4 -5
  20. {docs → qtype/docs}/Gallery/simple_chatbot.md +3 -1
  21. {docs → qtype/docs}/How To/Authentication/configure_aws_authentication.md +2 -2
  22. {docs → qtype/docs}/How To/Authentication/use_api_key_authentication.md +2 -2
  23. {docs → qtype/docs}/How To/Command Line Usage/load_multiple_inputs_from_files.md +24 -9
  24. {docs → qtype/docs}/How To/Command Line Usage/pass_inputs_on_the_cli.md +7 -4
  25. {docs → qtype/docs}/How To/Command Line Usage/serve_with_auto_reload.md +3 -2
  26. {docs → qtype/docs}/How To/Data Processing/adjust_concurrency.md +3 -4
  27. {docs → qtype/docs}/How To/Data Processing/cache_step_results.md +2 -2
  28. {docs → qtype/docs}/How To/Data Processing/decode_json_xml.md +1 -1
  29. {docs → qtype/docs}/How To/Data Processing/explode_collections.md +2 -2
  30. {docs → qtype/docs}/How To/Data Processing/gather_results.md +4 -4
  31. qtype/docs/How To/Data Processing/invoke_other_flows.md +71 -0
  32. qtype/docs/How To/Data Processing/load_data_from_athena.md +49 -0
  33. qtype/docs/How To/Data Processing/load_documents.md +74 -0
  34. qtype/docs/How To/Data Processing/read_data_from_files.md +61 -0
  35. {docs → qtype/docs}/How To/Data Processing/read_sql_databases.md +4 -3
  36. {docs → qtype/docs}/How To/Data Processing/write_data_to_file.md +1 -2
  37. {docs → qtype/docs}/How To/Invoke Models/call_large_language_models.md +1 -1
  38. {docs → qtype/docs}/How To/Invoke Models/create_embeddings.md +1 -1
  39. {docs → qtype/docs}/How To/Invoke Models/reuse_prompts_with_templates.md +2 -3
  40. {docs → qtype/docs}/How To/Language Features/include_raw_text_from_other_files.md +2 -1
  41. {docs → qtype/docs}/How To/Language Features/reference_entities_by_id.md +2 -2
  42. qtype/docs/How To/Language Features/use_agent_skills.md +29 -0
  43. {docs → qtype/docs}/How To/Language Features/use_environment_variables.md +2 -1
  44. qtype/docs/How To/Language Features/use_optional_variables.md +42 -0
  45. {docs → qtype/docs}/How To/Language Features/use_qtype_mcp.md +4 -4
  46. {docs → qtype/docs}/How To/Observability & Debugging/trace_calls_with_open_telemetry.md +1 -1
  47. {docs → qtype/docs}/How To/Observability & Debugging/validate_qtype_yaml.md +3 -2
  48. {docs → qtype/docs}/How To/Observability & Debugging/visualize_application_architecture.md +1 -1
  49. {docs → qtype/docs}/How To/Qtype Server/serve_flows_as_apis.md +3 -3
  50. {docs → qtype/docs}/How To/Qtype Server/serve_flows_as_ui.md +2 -3
  51. {docs → qtype/docs}/How To/Qtype Server/use_conversational_interfaces.md +1 -4
  52. {docs → qtype/docs}/How To/Qtype Server/use_variables_with_ui_hints.md +3 -2
  53. {docs → qtype/docs}/How To/Tools & Integration/bind_tool_inputs_and_outputs.md +1 -2
  54. {docs → qtype/docs}/How To/Tools & Integration/create_tools_from_openapi_specifications.md +10 -14
  55. {docs → qtype/docs}/How To/Tools & Integration/create_tools_from_python_modules.md +5 -8
  56. {docs → qtype/docs}/Reference/cli.md +16 -17
  57. qtype/docs/Tutorials/.pages +1 -0
  58. {docs → qtype/docs}/Tutorials/01-first-qtype-application.md +4 -3
  59. {docs → qtype/docs}/Tutorials/02-conversational-chatbot.md +3 -3
  60. {docs → qtype/docs}/Tutorials/03-structured-data.md +10 -11
  61. {docs → qtype/docs}/Tutorials/04-tools-and-function-calling.md +13 -20
  62. {docs → qtype/docs}/components/APITool.md +1 -1
  63. qtype/docs/components/Aggregate.md +7 -0
  64. qtype/docs/components/Collect.md +6 -0
  65. qtype/docs/components/Construct.md +6 -0
  66. {docs → qtype/docs}/components/DocumentEmbedder.md +0 -1
  67. {docs → qtype/docs}/components/DocumentSplitter.md +0 -1
  68. qtype/docs/components/Explode.md +5 -0
  69. {docs → qtype/docs}/components/FieldExtractor.md +2 -1
  70. qtype/docs/components/InvokeFlow.md +8 -0
  71. qtype/docs/components/InvokeTool.md +8 -0
  72. {docs → qtype/docs}/components/PrimitiveTypeEnum.md +0 -1
  73. {docs → qtype/docs}/components/Source.md +0 -1
  74. {docs → qtype/docs}/components/Step.md +0 -1
  75. {docs → qtype/docs}/components/Tool.md +2 -2
  76. {docs → qtype/docs}/components/Variable.md +2 -0
  77. qtype/docs/legacy_how_tos/.pages +6 -0
  78. qtype/docs/skills/architect/SKILL.md +188 -0
  79. qtype/docs/skills/architect/references/cheatsheet.md +198 -0
  80. qtype/docs/skills/architect/references/patterns.md +29 -0
  81. qtype/docs/stylesheets/extra.css +27 -0
  82. qtype/dsl/linker.py +8 -0
  83. qtype/dsl/model.py +177 -84
  84. qtype/examples/conversational_ai/simple_chatbot_with_auth.qtype.yaml +48 -0
  85. qtype/examples/data_processing/athena_query.qtype.yaml +56 -0
  86. qtype/examples/data_processing/batch_inputs.csv +5 -0
  87. qtype/examples/data_processing/create_sample_db.py +129 -0
  88. qtype/examples/data_processing/invoke_other_flows.qtype.yaml +98 -0
  89. qtype/examples/data_processing/load_documents.qtype.yaml +31 -0
  90. qtype/examples/data_processing/reviews.db +0 -0
  91. qtype/examples/data_processing/sample_article.txt +1 -0
  92. qtype/examples/data_processing/sample_documents.jsonl +5 -0
  93. qtype/examples/invoke_models/invoke_embedding_aws.qtype.yaml +45 -0
  94. qtype/examples/language_features/optional_variables.qtype.yaml +32 -0
  95. qtype/examples/language_features/story_prompt.txt +6 -0
  96. qtype/examples/legacy/data/customers.csv +6 -0
  97. qtype/examples/legacy/echo/readme.md +29 -0
  98. qtype/examples/legacy/qtype_plugin_example.py +51 -0
  99. qtype/examples/legacy/sample_data.txt +43 -0
  100. qtype/examples/legacy/vertex/README.md +11 -0
  101. qtype/examples/rag/recipe_chatbot.qtype.yaml +216 -0
  102. qtype/examples/research_assistant/tavily.qtype.yaml +216 -0
  103. {examples → qtype/examples}/tutorials/03_structured_data.qtype.yaml +2 -2
  104. {examples → qtype/examples}/tutorials/04_tools_and_function_calling.qtype.yaml +5 -5
  105. qtype/interpreter/auth/aws.py +94 -17
  106. qtype/interpreter/auth/generic.py +11 -12
  107. qtype/interpreter/base/secrets.py +4 -2
  108. qtype/interpreter/base/stream_emitter.py +19 -13
  109. qtype/interpreter/conversions.py +15 -14
  110. qtype/interpreter/converters.py +142 -26
  111. qtype/interpreter/executors/agent_executor.py +2 -3
  112. qtype/interpreter/executors/aggregate_executor.py +3 -4
  113. qtype/interpreter/executors/bedrock_reranker_executor.py +17 -28
  114. qtype/interpreter/executors/construct_executor.py +15 -15
  115. qtype/interpreter/executors/doc_to_text_executor.py +1 -3
  116. qtype/interpreter/executors/document_embedder_executor.py +1 -12
  117. qtype/interpreter/executors/field_extractor_executor.py +13 -12
  118. qtype/interpreter/executors/file_source_executor.py +18 -31
  119. qtype/interpreter/executors/invoke_embedding_executor.py +24 -37
  120. qtype/interpreter/executors/invoke_flow_executor.py +2 -2
  121. qtype/interpreter/executors/invoke_tool_executor.py +19 -18
  122. qtype/interpreter/executors/llm_inference_executor.py +18 -18
  123. qtype/interpreter/executors/prompt_template_executor.py +1 -3
  124. qtype/interpreter/executors/sql_source_executor.py +6 -2
  125. qtype/interpreter/flow.py +11 -1
  126. qtype/interpreter/tools/function_tool_helper.py +11 -10
  127. qtype/interpreter/types.py +89 -4
  128. qtype/interpreter/typing.py +31 -32
  129. qtype/mcp/server.py +194 -86
  130. {schema → qtype/schema}/qtype.schema.json +77 -79
  131. qtype/semantic/checker.py +19 -0
  132. qtype/semantic/generate.py +3 -6
  133. qtype/semantic/model.py +26 -33
  134. qtype/semantic/resolver.py +7 -0
  135. qtype/semantic/visualize.py +18 -6
  136. {qtype-0.1.12.dist-info → qtype-0.1.14.dist-info}/METADATA +47 -46
  137. qtype-0.1.14.dist-info/RECORD +361 -0
  138. {qtype-0.1.12.dist-info → qtype-0.1.14.dist-info}/WHEEL +1 -2
  139. docs/How To/Data Processing/read_data_from_files.md +0 -35
  140. docs/components/Aggregate.md +0 -8
  141. docs/components/InvokeFlow.md +0 -8
  142. docs/components/InvokeTool.md +0 -8
  143. docs/components/ToolParameter.md +0 -6
  144. examples/research_assistant/tavily.qtype.yaml +0 -289
  145. qtype/application/facade.py +0 -177
  146. qtype-0.1.12.dist-info/RECORD +0 -325
  147. qtype-0.1.12.dist-info/top_level.txt +0 -1
  148. {docs → qtype/docs}/Contributing/roadmap.md +0 -0
  149. {docs → qtype/docs}/Decisions/ADR-001-Chat-vs-Completion-Endpoint-Features.md +0 -0
  150. {docs → qtype/docs}/Gallery/dataflow_pipelines.mermaid +0 -0
  151. {docs → qtype/docs}/Gallery/research_assistant.mermaid +0 -0
  152. {docs → qtype/docs}/Gallery/simple_chatbot.mermaid +0 -0
  153. {docs → qtype/docs}/How To/Language Features/include_qtype_yaml.md +0 -0
  154. {docs → qtype/docs}/How To/Observability & Debugging/visualize_example.mermaid +0 -0
  155. {docs → qtype/docs}/How To/Qtype Server/flow_as_ui.png +0 -0
  156. {docs → qtype/docs}/Reference/plugins.md +0 -0
  157. {docs → qtype/docs}/Reference/semantic-validation-rules.md +0 -0
  158. {docs → qtype/docs}/Tutorials/example_chat.png +0 -0
  159. {docs → qtype/docs}/Tutorials/index.md +0 -0
  160. {docs → qtype/docs}/components/APIKeyAuthProvider.md +0 -0
  161. {docs → qtype/docs}/components/AWSAuthProvider.md +0 -0
  162. {docs → qtype/docs}/components/AWSSecretManager.md +0 -0
  163. {docs → qtype/docs}/components/Agent.md +0 -0
  164. {docs → qtype/docs}/components/AggregateStats.md +0 -0
  165. {docs → qtype/docs}/components/Application.md +0 -0
  166. {docs → qtype/docs}/components/AuthorizationProvider.md +0 -0
  167. {docs → qtype/docs}/components/AuthorizationProviderList.md +0 -0
  168. {docs → qtype/docs}/components/BearerTokenAuthProvider.md +0 -0
  169. {docs → qtype/docs}/components/BedrockReranker.md +0 -0
  170. {docs → qtype/docs}/components/ChatContent.md +0 -0
  171. {docs → qtype/docs}/components/ChatMessage.md +0 -0
  172. {docs → qtype/docs}/components/ConstantPath.md +0 -0
  173. {docs → qtype/docs}/components/CustomType.md +0 -0
  174. {docs → qtype/docs}/components/Decoder.md +0 -0
  175. {docs → qtype/docs}/components/DecoderFormat.md +0 -0
  176. {docs → qtype/docs}/components/DocToTextConverter.md +0 -0
  177. {docs → qtype/docs}/components/Document.md +0 -0
  178. {docs → qtype/docs}/components/DocumentIndex.md +0 -0
  179. {docs → qtype/docs}/components/DocumentSearch.md +0 -0
  180. {docs → qtype/docs}/components/DocumentSource.md +0 -0
  181. {docs → qtype/docs}/components/Echo.md +0 -0
  182. {docs → qtype/docs}/components/Embedding.md +0 -0
  183. {docs → qtype/docs}/components/EmbeddingModel.md +0 -0
  184. {docs → qtype/docs}/components/FileSource.md +0 -0
  185. {docs → qtype/docs}/components/FileWriter.md +0 -0
  186. {docs → qtype/docs}/components/Flow.md +0 -0
  187. {docs → qtype/docs}/components/FlowInterface.md +0 -0
  188. {docs → qtype/docs}/components/Index.md +0 -0
  189. {docs → qtype/docs}/components/IndexUpsert.md +0 -0
  190. {docs → qtype/docs}/components/InvokeEmbedding.md +0 -0
  191. {docs → qtype/docs}/components/LLMInference.md +0 -0
  192. {docs → qtype/docs}/components/ListType.md +0 -0
  193. {docs → qtype/docs}/components/Memory.md +0 -0
  194. {docs → qtype/docs}/components/MessageRole.md +0 -0
  195. {docs → qtype/docs}/components/Model.md +0 -0
  196. {docs → qtype/docs}/components/ModelList.md +0 -0
  197. {docs → qtype/docs}/components/OAuth2AuthProvider.md +0 -0
  198. {docs → qtype/docs}/components/PromptTemplate.md +0 -0
  199. {docs → qtype/docs}/components/PythonFunctionTool.md +0 -0
  200. {docs → qtype/docs}/components/RAGChunk.md +0 -0
  201. {docs → qtype/docs}/components/RAGDocument.md +0 -0
  202. {docs → qtype/docs}/components/RAGSearchResult.md +0 -0
  203. {docs → qtype/docs}/components/Reranker.md +0 -0
  204. {docs → qtype/docs}/components/SQLSource.md +0 -0
  205. {docs → qtype/docs}/components/Search.md +0 -0
  206. {docs → qtype/docs}/components/SearchResult.md +0 -0
  207. {docs → qtype/docs}/components/SecretManager.md +0 -0
  208. {docs → qtype/docs}/components/SecretReference.md +0 -0
  209. {docs → qtype/docs}/components/TelemetrySink.md +0 -0
  210. {docs → qtype/docs}/components/ToolList.md +0 -0
  211. {docs → qtype/docs}/components/TypeList.md +0 -0
  212. {docs → qtype/docs}/components/VariableList.md +0 -0
  213. {docs → qtype/docs}/components/VectorIndex.md +0 -0
  214. {docs → qtype/docs}/components/VectorSearch.md +0 -0
  215. {docs → qtype/docs}/components/VertexAuthProvider.md +0 -0
  216. {docs → qtype/docs}/components/Writer.md +0 -0
  217. {docs → qtype/docs}/example_ui.png +0 -0
  218. {docs → qtype/docs}/index.md +0 -0
  219. {docs → qtype/docs}/legacy_how_tos/Configuration/modular-yaml.md +0 -0
  220. {docs → qtype/docs}/legacy_how_tos/Configuration/phoenix_projects.png +0 -0
  221. {docs → qtype/docs}/legacy_how_tos/Configuration/phoenix_traces.png +0 -0
  222. {docs → qtype/docs}/legacy_how_tos/Configuration/reference-by-id.md +0 -0
  223. {docs → qtype/docs}/legacy_how_tos/Configuration/telemetry-setup.md +0 -0
  224. {docs → qtype/docs}/legacy_how_tos/Data Types/custom-types.md +0 -0
  225. {docs → qtype/docs}/legacy_how_tos/Data Types/domain-types.md +0 -0
  226. {docs → qtype/docs}/legacy_how_tos/Debugging/visualize-apps.md +0 -0
  227. {docs → qtype/docs}/legacy_how_tos/Tools/api-tools.md +0 -0
  228. {docs → qtype/docs}/legacy_how_tos/Tools/python-tools.md +0 -0
  229. {examples → qtype/examples}/authentication/aws_authentication.qtype.yaml +0 -0
  230. {examples → qtype/examples}/conversational_ai/hello_world_chat.qtype.yaml +0 -0
  231. {examples → qtype/examples}/conversational_ai/simple_chatbot.qtype.yaml +0 -0
  232. {examples → qtype/examples}/data_processing/batch_processing.qtype.yaml +0 -0
  233. {examples → qtype/examples}/data_processing/cache_step_results.qtype.yaml +0 -0
  234. {examples → qtype/examples}/data_processing/collect_results.qtype.yaml +0 -0
  235. {examples → qtype/examples}/data_processing/dataflow_pipelines.qtype.yaml +0 -0
  236. {examples → qtype/examples}/data_processing/decode_json.qtype.yaml +0 -0
  237. {examples → qtype/examples}/data_processing/explode_items.qtype.yaml +0 -0
  238. {examples → qtype/examples}/data_processing/read_file.qtype.yaml +0 -0
  239. {examples → qtype/examples}/invoke_models/create_embeddings.qtype.yaml +0 -0
  240. {examples → qtype/examples}/invoke_models/simple_llm_call.qtype.yaml +0 -0
  241. {examples → qtype/examples}/language_features/include_raw.qtype.yaml +0 -0
  242. {examples → qtype/examples}/language_features/ui_hints.qtype.yaml +0 -0
  243. {examples → qtype/examples}/legacy/bedrock/data_analysis_with_telemetry.qtype.yaml +0 -0
  244. {examples → qtype/examples}/legacy/bedrock/hello_world.qtype.yaml +0 -0
  245. {examples → qtype/examples}/legacy/bedrock/hello_world_chat.qtype.yaml +0 -0
  246. {examples → qtype/examples}/legacy/bedrock/hello_world_chat_with_telemetry.qtype.yaml +0 -0
  247. {examples → qtype/examples}/legacy/bedrock/hello_world_chat_with_thinking.qtype.yaml +0 -0
  248. {examples → qtype/examples}/legacy/bedrock/hello_world_completion.qtype.yaml +0 -0
  249. {examples → qtype/examples}/legacy/bedrock/hello_world_completion_with_auth.qtype.yaml +0 -0
  250. {examples → qtype/examples}/legacy/bedrock/simple_agent_chat.qtype.yaml +0 -0
  251. {examples → qtype/examples}/legacy/chat_with_langfuse.qtype.yaml +0 -0
  252. {examples → qtype/examples}/legacy/data_processor.qtype.yaml +0 -0
  253. {examples → qtype/examples}/legacy/echo/debug_example.qtype.yaml +0 -0
  254. {examples → qtype/examples}/legacy/echo/prompt.qtype.yaml +0 -0
  255. {examples → qtype/examples}/legacy/echo/test.qtype.yaml +0 -0
  256. {examples → qtype/examples}/legacy/echo/video.qtype.yaml +0 -0
  257. {examples → qtype/examples}/legacy/field_extractor_example.qtype.yaml +0 -0
  258. {examples → qtype/examples}/legacy/multi_flow_example.qtype.yaml +0 -0
  259. {examples → qtype/examples}/legacy/openai/hello_world_chat.qtype.yaml +0 -0
  260. {examples → qtype/examples}/legacy/openai/hello_world_chat_with_telemetry.qtype.yaml +0 -0
  261. {examples → qtype/examples}/legacy/rag.qtype.yaml +0 -0
  262. {examples → qtype/examples}/legacy/time_utilities.qtype.yaml +0 -0
  263. {examples → qtype/examples}/legacy/vertex/hello_world_chat.qtype.yaml +0 -0
  264. {examples → qtype/examples}/legacy/vertex/hello_world_completion.qtype.yaml +0 -0
  265. {examples → qtype/examples}/legacy/vertex/hello_world_completion_with_auth.qtype.yaml +0 -0
  266. {examples → qtype/examples}/observability_debugging/trace_with_opentelemetry.qtype.yaml +0 -0
  267. {examples → qtype/examples}/research_assistant/research_assistant.qtype.yaml +0 -0
  268. {examples → qtype/examples}/research_assistant/tavily.oas.yaml +0 -0
  269. {examples → qtype/examples}/tutorials/01_hello_world.qtype.yaml +0 -0
  270. {examples → qtype/examples}/tutorials/02_conversational_chat.qtype.yaml +0 -0
  271. {qtype-0.1.12.dist-info → qtype-0.1.14.dist-info}/entry_points.txt +0 -0
  272. {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 re
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
- # Regex for pymdownx snippets: --8<-- "path/to/file"
19
- SNIPPET_REGEX = re.compile(r'--8<--\s+"([^"]+)"')
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
- def resolve_snippets(content: str, base_path: Path) -> str:
71
- """
72
- Recursively finds and replaces MkDocs snippets in markdown content.
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
- Args:
76
- content: The markdown content to process
77
- base_path: Path to the file being processed (used to resolve relative paths)
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
- docs_root = _get_docs_path()
80
- project_root = docs_root.parent
81
-
82
- def replace_match(match):
83
- snippet_path = match.group(1)
84
-
85
- # pymdownx logic: try relative to current file, then relative to docs, then project root
86
- candidates = [
87
- base_path.parent / snippet_path, # Relative to the doc file
88
- docs_root / snippet_path, # Relative to docs root
89
- project_root / snippet_path, # Relative to project root
90
- ]
91
-
92
- for candidate in candidates:
93
- if candidate.exists() and candidate.is_file():
94
- # Recursively resolve snippets inside the included file
95
- return resolve_snippets(
96
- candidate.read_text(encoding="utf-8"), candidate
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
- return f"> [!WARNING] Could not resolve snippet: {snippet_path}"
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
- return SNIPPET_REGEX.sub(replace_match, content)
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
- docs_path = _get_docs_path()
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
- docs_path = _get_docs_path()
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
- # Find all markdown files
374
- md_files = []
375
- for md_file in docs_path.rglob("*.md"):
376
- # Get relative path from docs root
377
- rel_path = md_file.relative_to(docs_path)
378
- md_files.append(str(rel_path))
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 sorted(md_files)
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": "object"
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": "object"
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
- "additionalProperties": {
129
- "$ref": "#/$defs/ToolParameter"
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": "object"
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 terminal step that consumes an entire input stream and produces a single\nsummary message with success/error counts.",
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 for the output. There should be one and only one output with type AggregateStats",
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
- "field_mapping": {
1087
+ "field_bindings": {
1088
1088
  "additionalProperties": {
1089
- "type": "string"
1089
+ "anyOf": [
1090
+ {
1091
+ "$ref": "#/$defs/Reference_Variable_"
1092
+ },
1093
+ {
1094
+ "type": "string"
1095
+ }
1096
+ ]
1090
1097
  },
1091
- "description": "Mapping of type inputs to variable names, if needed.",
1092
- "title": "Field Mapping",
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
- "field_mapping"
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
- "type": "string"
2682
- },
2683
- "description": "Mapping from variable references to flow input variable IDs.",
2684
- "propertyNames": {
2685
- "$ref": "#/$defs/Reference_Variable_"
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
- "type": "string"
2693
- },
2694
- "description": "Mapping from variable references to flow output variable IDs.",
2695
- "propertyNames": {
2696
- "$ref": "#/$defs/Reference_Variable_"
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
- "type": "string"
2795
+ "anyOf": [
2796
+ {
2797
+ "$ref": "#/$defs/Reference_Variable_"
2798
+ },
2799
+ {
2800
+ "type": "string"
2801
+ }
2802
+ ]
2787
2803
  },
2788
- "description": "Mapping from variable references to tool input parameter names.",
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
- "type": "string"
2810
+ "anyOf": [
2811
+ {
2812
+ "$ref": "#/$defs/Reference_Variable_"
2813
+ },
2814
+ {
2815
+ "type": "string"
2816
+ }
2817
+ ]
2795
2818
  },
2796
- "description": "Mapping from variable references to tool output parameter names.",
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": "object"
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": "object"
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
  """