quantum-framework 0.9.0__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 (262) hide show
  1. quantum/__init__.py +1 -0
  2. quantum/cli/__init__.py +2 -0
  3. quantum/cli/commands/__init__.py +15 -0
  4. quantum/cli/commands/build.py +417 -0
  5. quantum/cli/commands/dev.py +185 -0
  6. quantum/cli/commands/docs.py +329 -0
  7. quantum/cli/commands/lint.py +523 -0
  8. quantum/cli/commands/migrate.py +527 -0
  9. quantum/cli/commands/new.py +622 -0
  10. quantum/cli/commands/serve.py +190 -0
  11. quantum/cli/commands/test.py +193 -0
  12. quantum/cli/deploy.py +810 -0
  13. quantum/cli/hot_reload.py +951 -0
  14. quantum/cli/jobs.py +356 -0
  15. quantum/cli/mq.py +582 -0
  16. quantum/cli/pkg.py +390 -0
  17. quantum/cli/runner.py +547 -0
  18. quantum/cli/server_process.py +159 -0
  19. quantum/cli/utils.py +334 -0
  20. quantum/compiler/__init__.py +30 -0
  21. quantum/compiler/base_generator.py +367 -0
  22. quantum/compiler/cli.py +295 -0
  23. quantum/compiler/expression_transformer.py +444 -0
  24. quantum/compiler/javascript/__init__.py +10 -0
  25. quantum/compiler/javascript/generator.py +659 -0
  26. quantum/compiler/optimizer.py +270 -0
  27. quantum/compiler/python/__init__.py +10 -0
  28. quantum/compiler/python/generator.py +883 -0
  29. quantum/compiler/python/runtime.py +863 -0
  30. quantum/compiler/transpiler.py +330 -0
  31. quantum/core/__init__.py +3 -0
  32. quantum/core/ast_nodes.py +2611 -0
  33. quantum/core/expression_diagnostics.py +87 -0
  34. quantum/core/expression_stdlib.py +148 -0
  35. quantum/core/expressions.py +591 -0
  36. quantum/core/features/agents/src/__init__.py +30 -0
  37. quantum/core/features/agents/src/ast_node.py +540 -0
  38. quantum/core/features/conditionals/src/__init__.py +8 -0
  39. quantum/core/features/conditionals/src/ast_node.py +68 -0
  40. quantum/core/features/data_fetching/src/__init__.py +21 -0
  41. quantum/core/features/data_fetching/src/ast_node.py +312 -0
  42. quantum/core/features/data_fetching/src/desktop_adapter.py +351 -0
  43. quantum/core/features/data_fetching/src/html_adapter.py +474 -0
  44. quantum/core/features/data_fetching/src/parser.py +225 -0
  45. quantum/core/features/data_import/src/__init__.py +0 -0
  46. quantum/core/features/data_import/src/ast_node.py +291 -0
  47. quantum/core/features/data_import/src/runtime.py +538 -0
  48. quantum/core/features/dump/src/__init__.py +12 -0
  49. quantum/core/features/dump/src/ast_node.py +106 -0
  50. quantum/core/features/dump/src/parser.py +61 -0
  51. quantum/core/features/dump/src/runtime.py +246 -0
  52. quantum/core/features/functions/src/__init__.py +8 -0
  53. quantum/core/features/functions/src/ast_node.py +149 -0
  54. quantum/core/features/game_engine_2d/src/__init__.py +19 -0
  55. quantum/core/features/game_engine_2d/src/ast_nodes.py +1719 -0
  56. quantum/core/features/game_engine_2d/src/parser.py +983 -0
  57. quantum/core/features/invocation/src/__init__.py +0 -0
  58. quantum/core/features/invocation/src/ast_node.py +146 -0
  59. quantum/core/features/invocation/src/runtime.py +327 -0
  60. quantum/core/features/knowledge_base/src/__init__.py +6 -0
  61. quantum/core/features/knowledge_base/src/ast_node.py +113 -0
  62. quantum/core/features/knowledge_base/src/parser.py +82 -0
  63. quantum/core/features/logging/src/__init__.py +12 -0
  64. quantum/core/features/logging/src/ast_node.py +111 -0
  65. quantum/core/features/logging/src/parser.py +50 -0
  66. quantum/core/features/logging/src/runtime.py +190 -0
  67. quantum/core/features/loops/src/__init__.py +8 -0
  68. quantum/core/features/loops/src/ast_node.py +60 -0
  69. quantum/core/features/query/src/__init__.py +0 -0
  70. quantum/core/features/query/src/database_service.py +322 -0
  71. quantum/core/features/query/src/query_validators.py +20 -0
  72. quantum/core/features/state_management/src/__init__.py +11 -0
  73. quantum/core/features/state_management/src/ast_node.py +228 -0
  74. quantum/core/features/terminal_engine/src/__init__.py +21 -0
  75. quantum/core/features/terminal_engine/src/ast_nodes.py +560 -0
  76. quantum/core/features/terminal_engine/src/parser.py +361 -0
  77. quantum/core/features/testing_engine/src/__init__.py +41 -0
  78. quantum/core/features/testing_engine/src/ast_nodes.py +1212 -0
  79. quantum/core/features/testing_engine/src/parser.py +604 -0
  80. quantum/core/features/theming/src/__init__.py +48 -0
  81. quantum/core/features/theming/src/ast_node.py +137 -0
  82. quantum/core/features/theming/src/presets.py +405 -0
  83. quantum/core/features/ui_engine/src/__init__.py +20 -0
  84. quantum/core/features/ui_engine/src/ast_nodes.py +1854 -0
  85. quantum/core/features/ui_engine/src/parser.py +1106 -0
  86. quantum/core/features/websocket/src/__init__.py +24 -0
  87. quantum/core/features/websocket/src/ast_node.py +247 -0
  88. quantum/core/html_compat.py +299 -0
  89. quantum/core/parser.py +1235 -0
  90. quantum/core/parser_registry.py +213 -0
  91. quantum/core/parsers/__init__.py +76 -0
  92. quantum/core/parsers/ai/__init__.py +12 -0
  93. quantum/core/parsers/ai/agent_parser.py +106 -0
  94. quantum/core/parsers/ai/knowledge_parser.py +86 -0
  95. quantum/core/parsers/ai/llm_parser.py +78 -0
  96. quantum/core/parsers/ai/team_parser.py +88 -0
  97. quantum/core/parsers/base.py +322 -0
  98. quantum/core/parsers/composition/__init__.py +10 -0
  99. quantum/core/parsers/composition/import_parser.py +50 -0
  100. quantum/core/parsers/composition/slot_parser.py +48 -0
  101. quantum/core/parsers/control_flow/__init__.py +11 -0
  102. quantum/core/parsers/control_flow/if_parser.py +68 -0
  103. quantum/core/parsers/control_flow/loop_parser.py +105 -0
  104. quantum/core/parsers/control_flow/set_parser.py +89 -0
  105. quantum/core/parsers/data/__init__.py +12 -0
  106. quantum/core/parsers/data/data_parser.py +217 -0
  107. quantum/core/parsers/data/invoke_parser.py +116 -0
  108. quantum/core/parsers/data/query_parser.py +188 -0
  109. quantum/core/parsers/data/transaction_parser.py +77 -0
  110. quantum/core/parsers/events/__init__.py +9 -0
  111. quantum/core/parsers/events/dispatch_event_parser.py +44 -0
  112. quantum/core/parsers/forms/__init__.py +11 -0
  113. quantum/core/parsers/forms/action_parser.py +54 -0
  114. quantum/core/parsers/forms/flash_parser.py +34 -0
  115. quantum/core/parsers/forms/redirect_parser.py +33 -0
  116. quantum/core/parsers/functions/__init__.py +11 -0
  117. quantum/core/parsers/functions/function_parser.py +137 -0
  118. quantum/core/parsers/functions/param_parser.py +66 -0
  119. quantum/core/parsers/functions/return_parser.py +31 -0
  120. quantum/core/parsers/html/__init__.py +10 -0
  121. quantum/core/parsers/html/component_call_parser.py +130 -0
  122. quantum/core/parsers/html/html_parser.py +115 -0
  123. quantum/core/parsers/jobs/__init__.py +11 -0
  124. quantum/core/parsers/jobs/job_parser.py +71 -0
  125. quantum/core/parsers/jobs/schedule_parser.py +62 -0
  126. quantum/core/parsers/jobs/thread_parser.py +57 -0
  127. quantum/core/parsers/messaging/__init__.py +17 -0
  128. quantum/core/parsers/messaging/message_ack_parser.py +30 -0
  129. quantum/core/parsers/messaging/message_nack_parser.py +30 -0
  130. quantum/core/parsers/messaging/message_parser.py +114 -0
  131. quantum/core/parsers/messaging/queue_parser.py +61 -0
  132. quantum/core/parsers/messaging/websocket_parser.py +121 -0
  133. quantum/core/parsers/persistence/__init__.py +9 -0
  134. quantum/core/parsers/persistence/persist_parser.py +64 -0
  135. quantum/core/parsers/routing/__init__.py +9 -0
  136. quantum/core/parsers/routing/route_parser.py +41 -0
  137. quantum/core/parsers/scripting/__init__.py +12 -0
  138. quantum/core/parsers/scripting/pyclass_parser.py +62 -0
  139. quantum/core/parsers/scripting/pydecorator_parser.py +68 -0
  140. quantum/core/parsers/scripting/pyimport_parser.py +52 -0
  141. quantum/core/parsers/scripting/python_parser.py +49 -0
  142. quantum/core/parsers/services/__init__.py +12 -0
  143. quantum/core/parsers/services/dump_parser.py +52 -0
  144. quantum/core/parsers/services/file_parser.py +48 -0
  145. quantum/core/parsers/services/log_parser.py +46 -0
  146. quantum/core/parsers/services/mail_parser.py +65 -0
  147. quantum/core/tiers.py +82 -0
  148. quantum/packages/__init__.py +28 -0
  149. quantum/packages/manager.py +413 -0
  150. quantum/packages/manifest.py +351 -0
  151. quantum/packages/registry.py +399 -0
  152. quantum/packages/resolver.py +336 -0
  153. quantum/plugins/__init__.py +33 -0
  154. quantum/plugins/hooks.py +329 -0
  155. quantum/plugins/loader.py +479 -0
  156. quantum/plugins/manifest.py +336 -0
  157. quantum/plugins/registry.py +371 -0
  158. quantum/runtime/__init__.py +28 -0
  159. quantum/runtime/action_handler.py +443 -0
  160. quantum/runtime/adapters/__init__.py +88 -0
  161. quantum/runtime/adapters/memory_adapter.py +690 -0
  162. quantum/runtime/adapters/rabbitmq_adapter.py +715 -0
  163. quantum/runtime/adapters/redis_adapter.py +582 -0
  164. quantum/runtime/adapters/sqlite_adapter.py +414 -0
  165. quantum/runtime/agent_service.py +1133 -0
  166. quantum/runtime/api_server.py +86 -0
  167. quantum/runtime/ast_cache.py +506 -0
  168. quantum/runtime/auth_service.py +267 -0
  169. quantum/runtime/component.py +990 -0
  170. quantum/runtime/component_composer.py +319 -0
  171. quantum/runtime/component_resolver.py +174 -0
  172. quantum/runtime/database_service.py +598 -0
  173. quantum/runtime/email_service.py +162 -0
  174. quantum/runtime/error_handler.py +295 -0
  175. quantum/runtime/execution_context.py +286 -0
  176. quantum/runtime/executor_registry.py +171 -0
  177. quantum/runtime/executors/__init__.py +71 -0
  178. quantum/runtime/executors/ai/__init__.py +12 -0
  179. quantum/runtime/executors/ai/agent_executor.py +217 -0
  180. quantum/runtime/executors/ai/knowledge_executor.py +114 -0
  181. quantum/runtime/executors/ai/llm_executor.py +153 -0
  182. quantum/runtime/executors/ai/team_executor.py +171 -0
  183. quantum/runtime/executors/base.py +262 -0
  184. quantum/runtime/executors/control_flow/__init__.py +11 -0
  185. quantum/runtime/executors/control_flow/if_executor.py +93 -0
  186. quantum/runtime/executors/control_flow/loop_executor.py +307 -0
  187. quantum/runtime/executors/control_flow/set_executor.py +412 -0
  188. quantum/runtime/executors/data/__init__.py +12 -0
  189. quantum/runtime/executors/data/data_executor.py +145 -0
  190. quantum/runtime/executors/data/invoke_executor.py +176 -0
  191. quantum/runtime/executors/data/query_executor.py +256 -0
  192. quantum/runtime/executors/data/transaction_executor.py +91 -0
  193. quantum/runtime/executors/jobs/__init__.py +11 -0
  194. quantum/runtime/executors/jobs/job_executor.py +190 -0
  195. quantum/runtime/executors/jobs/schedule_executor.py +132 -0
  196. quantum/runtime/executors/jobs/thread_executor.py +127 -0
  197. quantum/runtime/executors/messaging/__init__.py +17 -0
  198. quantum/runtime/executors/messaging/message_ack_executor.py +51 -0
  199. quantum/runtime/executors/messaging/message_executor.py +174 -0
  200. quantum/runtime/executors/messaging/queue_executor.py +103 -0
  201. quantum/runtime/executors/messaging/websocket_executor.py +197 -0
  202. quantum/runtime/executors/scripting/__init__.py +11 -0
  203. quantum/runtime/executors/scripting/pyclass_executor.py +90 -0
  204. quantum/runtime/executors/scripting/pyimport_executor.py +81 -0
  205. quantum/runtime/executors/scripting/python_executor.py +249 -0
  206. quantum/runtime/executors/services/__init__.py +12 -0
  207. quantum/runtime/executors/services/dump_executor.py +72 -0
  208. quantum/runtime/executors/services/file_executor.py +89 -0
  209. quantum/runtime/executors/services/log_executor.py +77 -0
  210. quantum/runtime/executors/services/mail_executor.py +81 -0
  211. quantum/runtime/expression_cache.py +498 -0
  212. quantum/runtime/file_upload_service.py +326 -0
  213. quantum/runtime/function_registry.py +118 -0
  214. quantum/runtime/game_builder.py +166 -0
  215. quantum/runtime/game_code_generator.py +2371 -0
  216. quantum/runtime/game_templates.py +2006 -0
  217. quantum/runtime/godot_code_generator.py +4681 -0
  218. quantum/runtime/godot_templates.py +1449 -0
  219. quantum/runtime/job_executor.py +1599 -0
  220. quantum/runtime/knowledge_service.py +500 -0
  221. quantum/runtime/llm_cache.py +100 -0
  222. quantum/runtime/llm_providers.py +704 -0
  223. quantum/runtime/llm_service.py +287 -0
  224. quantum/runtime/logging_setup.py +140 -0
  225. quantum/runtime/message_broker.py +364 -0
  226. quantum/runtime/message_queue_service.py +571 -0
  227. quantum/runtime/param_validation.py +184 -0
  228. quantum/runtime/pypy_compat.py +315 -0
  229. quantum/runtime/python_bridge.py +698 -0
  230. quantum/runtime/query_validators.py +304 -0
  231. quantum/runtime/renderer.py +733 -0
  232. quantum/runtime/service_container.py +444 -0
  233. quantum/runtime/terminal_builder.py +76 -0
  234. quantum/runtime/terminal_code_generator.py +607 -0
  235. quantum/runtime/terminal_templates.py +243 -0
  236. quantum/runtime/testing_builder.py +77 -0
  237. quantum/runtime/testing_code_generator.py +833 -0
  238. quantum/runtime/testing_templates.py +85 -0
  239. quantum/runtime/ui_builder.py +188 -0
  240. quantum/runtime/ui_desktop_adapter.py +1730 -0
  241. quantum/runtime/ui_desktop_templates.py +307 -0
  242. quantum/runtime/ui_html_adapter.py +2691 -0
  243. quantum/runtime/ui_html_templates.py +2297 -0
  244. quantum/runtime/ui_mobile_adapter.py +1832 -0
  245. quantum/runtime/ui_mobile_templates.py +1003 -0
  246. quantum/runtime/ui_textual_adapter.py +1866 -0
  247. quantum/runtime/ui_textual_templates.py +45 -0
  248. quantum/runtime/ui_tokens.py +465 -0
  249. quantum/runtime/ui_validator.py +365 -0
  250. quantum/runtime/validators.py +256 -0
  251. quantum/runtime/web_server.py +1766 -0
  252. quantum/runtime/websocket_adapter.py +501 -0
  253. quantum/runtime/websocket_service.py +585 -0
  254. quantum/runtime/websocket_transport.py +289 -0
  255. quantum/runtime/wsgi.py +101 -0
  256. quantum/utils/__init__.py +1 -0
  257. quantum_framework-0.9.0.dist-info/METADATA +244 -0
  258. quantum_framework-0.9.0.dist-info/RECORD +262 -0
  259. quantum_framework-0.9.0.dist-info/WHEEL +5 -0
  260. quantum_framework-0.9.0.dist-info/entry_points.txt +2 -0
  261. quantum_framework-0.9.0.dist-info/licenses/LICENSE +21 -0
  262. quantum_framework-0.9.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,213 @@
1
+ """
2
+ Parser Registry - Central dispatch for tag parsing
3
+
4
+ Replaces the large if-elif chain in parser.py with a tag-based lookup.
5
+ Parsers register themselves for specific tag names, and the registry
6
+ dispatches parsing to the correct parser.
7
+ """
8
+
9
+ from typing import Dict, Optional, List, TYPE_CHECKING
10
+ from xml.etree import ElementTree as ET
11
+ import logging
12
+
13
+ if TYPE_CHECKING:
14
+ from quantum.core.parsers.base import BaseTagParser
15
+ from quantum.core.ast_nodes import QuantumNode
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ class ParserNotFoundError(Exception):
21
+ """Raised when no parser is registered for a tag"""
22
+ pass
23
+
24
+
25
+ class ParserRegistry:
26
+ """
27
+ Registry for tag parsers.
28
+
29
+ Maps XML tag names to their parsers and dispatches parsing.
30
+
31
+ Example:
32
+ registry = ParserRegistry()
33
+ registry.register(LoopParser(main_parser))
34
+ registry.register(IfParser(main_parser))
35
+
36
+ # Later, parse any element
37
+ node = registry.parse(element, 'loop')
38
+ """
39
+
40
+ def __init__(self):
41
+ """Initialize empty registry"""
42
+ self._parsers: Dict[str, 'BaseTagParser'] = {}
43
+ self._html_parser: Optional['BaseTagParser'] = None
44
+ self._component_call_parser: Optional['BaseTagParser'] = None
45
+
46
+ def register(self, parser: 'BaseTagParser') -> 'ParserRegistry':
47
+ """
48
+ Register a parser for its handled tags.
49
+
50
+ Args:
51
+ parser: Parser instance to register
52
+
53
+ Returns:
54
+ Self for chaining
55
+ """
56
+ for tag_name in parser.tag_names:
57
+ if tag_name in self._parsers:
58
+ logger.warning(
59
+ f"Overwriting parser for '{tag_name}': "
60
+ f"{self._parsers[tag_name].__class__.__name__} -> "
61
+ f"{parser.__class__.__name__}"
62
+ )
63
+ self._parsers[tag_name] = parser
64
+ logger.debug(f"Registered {parser.__class__.__name__} for '{tag_name}'")
65
+
66
+ return self
67
+
68
+ def register_all(self, parsers: List['BaseTagParser']) -> 'ParserRegistry':
69
+ """
70
+ Register multiple parsers at once.
71
+
72
+ Args:
73
+ parsers: List of parser instances
74
+
75
+ Returns:
76
+ Self for chaining
77
+ """
78
+ for parser in parsers:
79
+ self.register(parser)
80
+ return self
81
+
82
+ def register_html_parser(self, parser: 'BaseTagParser') -> 'ParserRegistry':
83
+ """
84
+ Register the HTML element parser.
85
+
86
+ Args:
87
+ parser: HTML parser instance
88
+
89
+ Returns:
90
+ Self for chaining
91
+ """
92
+ self._html_parser = parser
93
+ logger.debug(f"Registered HTML parser: {parser.__class__.__name__}")
94
+ return self
95
+
96
+ def register_component_call_parser(self, parser: 'BaseTagParser') -> 'ParserRegistry':
97
+ """
98
+ Register the component call parser (for uppercase tags).
99
+
100
+ Args:
101
+ parser: Component call parser instance
102
+
103
+ Returns:
104
+ Self for chaining
105
+ """
106
+ self._component_call_parser = parser
107
+ logger.debug(f"Registered component call parser: {parser.__class__.__name__}")
108
+ return self
109
+
110
+ def get_parser(self, tag_name: str) -> Optional['BaseTagParser']:
111
+ """
112
+ Get the parser for a tag name.
113
+
114
+ Args:
115
+ tag_name: Tag name (without q: prefix)
116
+
117
+ Returns:
118
+ Parser instance or None if not found
119
+ """
120
+ return self._parsers.get(tag_name)
121
+
122
+ def has_parser(self, tag_name: str) -> bool:
123
+ """
124
+ Check if a parser is registered for a tag.
125
+
126
+ Args:
127
+ tag_name: Tag name
128
+
129
+ Returns:
130
+ True if parser exists
131
+ """
132
+ return tag_name in self._parsers
133
+
134
+ def parse(self, element: ET.Element, tag_name: str) -> Optional['QuantumNode']:
135
+ """
136
+ Parse an element using its registered parser.
137
+
138
+ Args:
139
+ element: XML element to parse
140
+ tag_name: Tag name (without q: prefix)
141
+
142
+ Returns:
143
+ AST node or None
144
+
145
+ Raises:
146
+ ParserNotFoundError: If no parser is registered for the tag
147
+ """
148
+ parser = self._parsers.get(tag_name)
149
+
150
+ if parser is not None:
151
+ # One-time notice if this tag is outside the supported surface
152
+ # (PRODUCTION_READINESS.md Fase 0). Experimental tags still parse
153
+ # and run; the operator just gets told, once, that they are
154
+ # leaning on something unsupported.
155
+ from quantum.core.tiers import warn_if_unsupported
156
+ warn_if_unsupported(tag_name)
157
+ return parser.parse(element)
158
+
159
+ return None
160
+
161
+ def parse_html(self, element: ET.Element) -> Optional['QuantumNode']:
162
+ """
163
+ Parse an HTML element.
164
+
165
+ Args:
166
+ element: HTML element to parse
167
+
168
+ Returns:
169
+ AST node or None
170
+ """
171
+ if self._html_parser is not None:
172
+ return self._html_parser.parse(element)
173
+ return None
174
+
175
+ def parse_component_call(self, element: ET.Element) -> Optional['QuantumNode']:
176
+ """
177
+ Parse a component call (uppercase tag).
178
+
179
+ Args:
180
+ element: Component call element
181
+
182
+ Returns:
183
+ AST node or None
184
+ """
185
+ if self._component_call_parser is not None:
186
+ return self._component_call_parser.parse(element)
187
+ return None
188
+
189
+ def is_uppercase(self, tag_name: str) -> bool:
190
+ """
191
+ Check if tag is a component call (uppercase first letter).
192
+
193
+ Args:
194
+ tag_name: Tag name
195
+
196
+ Returns:
197
+ True if uppercase
198
+ """
199
+ return bool(tag_name and tag_name[0].isupper())
200
+
201
+ @property
202
+ def registered_tags(self) -> List[str]:
203
+ """Get list of all registered tag names"""
204
+ return list(self._parsers.keys())
205
+
206
+ @property
207
+ def parser_count(self) -> int:
208
+ """Get number of registered parsers (unique)"""
209
+ return len(set(self._parsers.values()))
210
+
211
+ def __repr__(self) -> str:
212
+ tags = list(self._parsers.keys())
213
+ return f"ParserRegistry({len(tags)} tags: {tags[:5]}{'...' if len(tags) > 5 else ''})"
@@ -0,0 +1,76 @@
1
+ """
2
+ Quantum Parsers Package
3
+
4
+ Modular parsers for XML tag parsing. Each parser handles specific tag types.
5
+
6
+ Categories:
7
+ - control_flow: if, loop, set
8
+ - data: query, invoke, data, transaction
9
+ - services: log, dump, file, mail
10
+ - ai: llm, agent, team, knowledge
11
+ - messaging: websocket, message, subscribe, queue
12
+ - jobs: schedule, thread, job
13
+ - scripting: python, pyimport, pyclass
14
+ """
15
+
16
+ from .base import BaseTagParser, ParserError
17
+
18
+ # Control flow parsers
19
+ from .control_flow import IfParser, LoopParser, SetParser
20
+
21
+ # Data parsers
22
+ from .data import QueryParser, InvokeParser, DataParser, TransactionParser
23
+
24
+ # Service parsers
25
+ from .services import LogParser, DumpParser, FileParser, MailParser
26
+
27
+ # AI parsers
28
+ from .ai import LLMParser, AgentParser, TeamParser, KnowledgeParser
29
+
30
+ # Messaging parsers
31
+ from .messaging import (
32
+ WebSocketParser, WebSocketSendParser, WebSocketCloseParser,
33
+ MessageParser, SubscribeParser, QueueParser
34
+ )
35
+
36
+ # Jobs parsers
37
+ from .jobs import ScheduleParser, ThreadParser, JobParser
38
+
39
+ # Scripting parsers
40
+ from .scripting import PythonParser, PyImportParser, PyClassParser
41
+
42
+ # HTML parsers
43
+ from .html import HTMLParser, ComponentCallParser
44
+
45
+
46
+ __all__ = [
47
+ # Base
48
+ 'BaseTagParser', 'ParserError',
49
+
50
+ # Control flow
51
+ 'IfParser', 'LoopParser', 'SetParser',
52
+
53
+ # Data
54
+ 'QueryParser', 'InvokeParser', 'DataParser', 'TransactionParser',
55
+
56
+ # Services
57
+ 'LogParser', 'DumpParser', 'FileParser', 'MailParser',
58
+
59
+ # AI
60
+ 'LLMParser', 'AgentParser', 'TeamParser', 'KnowledgeParser',
61
+
62
+ # Messaging
63
+ 'WebSocketParser', 'WebSocketSendParser', 'WebSocketCloseParser',
64
+ 'MessageParser', 'SubscribeParser', 'QueueParser',
65
+
66
+ # Jobs
67
+ 'ScheduleParser', 'ThreadParser', 'JobParser',
68
+
69
+ # Scripting
70
+ 'PythonParser', 'PyImportParser', 'PyClassParser',
71
+
72
+ # HTML
73
+ 'HTMLParser', 'ComponentCallParser',
74
+ ]
75
+
76
+ __version__ = '1.0.0'
@@ -0,0 +1,12 @@
1
+ """
2
+ AI Parsers
3
+
4
+ Parsers for AI operations: llm, agent, team, knowledge.
5
+ """
6
+
7
+ from .llm_parser import LLMParser
8
+ from .agent_parser import AgentParser
9
+ from .team_parser import TeamParser
10
+ from .knowledge_parser import KnowledgeParser
11
+
12
+ __all__ = ['LLMParser', 'AgentParser', 'TeamParser', 'KnowledgeParser']
@@ -0,0 +1,106 @@
1
+ """
2
+ Agent Parser - Parse q:agent statements
3
+
4
+ Handles AI agent configuration with tools.
5
+ """
6
+
7
+ from typing import List
8
+ from xml.etree import ElementTree as ET
9
+ from quantum.core.parsers.base import BaseTagParser, ParserError
10
+ from quantum.core.features.agents.src.ast_node import (
11
+ AgentNode, AgentToolNode, AgentToolParamNode,
12
+ AgentInstructionNode, AgentExecuteNode
13
+ )
14
+
15
+
16
+ class AgentParser(BaseTagParser):
17
+ """
18
+ Parser for q:agent statements.
19
+
20
+ Supports:
21
+ - Tool definitions
22
+ - System instructions
23
+ - Execute configuration
24
+ - Multiple providers
25
+ """
26
+
27
+ @property
28
+ def tag_names(self) -> List[str]:
29
+ return ['agent']
30
+
31
+ def parse(self, element: ET.Element) -> AgentNode:
32
+ """
33
+ Parse q:agent statement.
34
+
35
+ Args:
36
+ element: XML element for q:agent
37
+
38
+ Returns:
39
+ AgentNode AST node
40
+ """
41
+ name = self.get_attr(element, 'name')
42
+
43
+ if not name:
44
+ raise ParserError("Agent requires 'name' attribute")
45
+
46
+ agent_node = AgentNode(
47
+ name=name,
48
+ model=self.get_attr(element, 'model', 'phi3'),
49
+ endpoint=self.get_attr(element, 'endpoint', ''),
50
+ provider=self.get_attr(element, 'provider', 'auto'),
51
+ api_key=self.get_attr(element, 'apiKey', ''),
52
+ max_iterations=self.get_int_attr(element, 'maxIterations', 10),
53
+ timeout=self.get_int_attr(element, 'timeout', 60000)
54
+ )
55
+
56
+ # Parse children
57
+ for child in element:
58
+ child_type = self.get_element_name(child)
59
+
60
+ if child_type == 'instruction':
61
+ agent_node.instruction = AgentInstructionNode(
62
+ content=self.get_text(child)
63
+ )
64
+ elif child_type == 'tool':
65
+ tool = self._parse_tool(child)
66
+ agent_node.tools.append(tool)
67
+ elif child_type == 'execute':
68
+ agent_node.execute = AgentExecuteNode(
69
+ task=self.get_attr(child, 'task', self.get_text(child)),
70
+ context=self.get_attr(child, 'context', ''),
71
+ entry=self.get_attr(child, 'entry', '')
72
+ )
73
+
74
+ return agent_node
75
+
76
+ def _parse_tool(self, element: ET.Element) -> AgentToolNode:
77
+ """Parse q:tool within q:agent."""
78
+ name = self.get_attr(element, 'name')
79
+ description = self.get_attr(element, 'description', '')
80
+ builtin = self.get_bool_attr(element, 'builtin', False)
81
+
82
+ tool = AgentToolNode(
83
+ name=name,
84
+ description=description,
85
+ builtin=builtin
86
+ )
87
+
88
+ # Parse params and body
89
+ for child in element:
90
+ child_type = self.get_element_name(child)
91
+
92
+ if child_type == 'param':
93
+ param = AgentToolParamNode(
94
+ name=self.get_attr(child, 'name', ''),
95
+ type=self.get_attr(child, 'type', 'string'),
96
+ required=self.get_bool_attr(child, 'required', False),
97
+ description=self.get_attr(child, 'description', '')
98
+ )
99
+ tool.params.append(param)
100
+ else:
101
+ # Tool body statement
102
+ statement = self.parse_statement(child)
103
+ if statement:
104
+ tool.body.append(statement)
105
+
106
+ return tool
@@ -0,0 +1,86 @@
1
+ """
2
+ Knowledge Parser - Parse q:knowledge statements
3
+
4
+ Handles knowledge base configuration for RAG.
5
+ """
6
+
7
+ from typing import List
8
+ from xml.etree import ElementTree as ET
9
+ from quantum.core.parsers.base import BaseTagParser, ParserError
10
+ from quantum.core.features.knowledge_base.src.ast_node import KnowledgeNode, KnowledgeSourceNode
11
+
12
+
13
+ class KnowledgeParser(BaseTagParser):
14
+ """
15
+ Parser for q:knowledge statements.
16
+
17
+ Supports:
18
+ - Multiple source types
19
+ - Embedding configuration
20
+ - Persistence options
21
+ """
22
+
23
+ @property
24
+ def tag_names(self) -> List[str]:
25
+ return ['knowledge']
26
+
27
+ def parse(self, element: ET.Element) -> KnowledgeNode:
28
+ """
29
+ Parse q:knowledge statement.
30
+
31
+ Args:
32
+ element: XML element for q:knowledge
33
+
34
+ Returns:
35
+ KnowledgeNode AST node
36
+ """
37
+ name = self.get_attr(element, 'name')
38
+
39
+ if not name:
40
+ raise ParserError("Knowledge requires 'name' attribute")
41
+
42
+ knowledge_node = KnowledgeNode(
43
+ name=name,
44
+ model=self.get_attr(element, 'model'),
45
+ embed_model=self.get_attr(element, 'embedModel', 'nomic-embed-text'),
46
+ chunk_size=self.get_int_attr(element, 'chunkSize', 500),
47
+ chunk_overlap=self.get_int_attr(element, 'chunkOverlap', 50),
48
+ # Persist by default: re-embedding an unchanged corpus on every
49
+ # boot costs minutes of API calls and buys nothing. Opt out with
50
+ # persist="false" for throwaway/in-memory bases.
51
+ persist=self.get_bool_attr(element, 'persist', True),
52
+ persist_path=self.get_attr(element, 'persistPath', './.quantum/knowledge'),
53
+ rebuild=self.get_bool_attr(element, 'rebuild', False)
54
+ )
55
+
56
+ # Parse sources
57
+ for child in element:
58
+ child_type = self.get_element_name(child)
59
+
60
+ if child_type == 'source':
61
+ source = self._parse_source(child)
62
+ knowledge_node.add_source(source)
63
+
64
+ return knowledge_node
65
+
66
+ def _parse_source(self, element: ET.Element) -> KnowledgeSourceNode:
67
+ """Parse q:source within q:knowledge."""
68
+ source_type = self.get_attr(element, 'type', 'text')
69
+
70
+ source = KnowledgeSourceNode(
71
+ source_type=source_type,
72
+ path=self.get_attr(element, 'path'),
73
+ pattern=self.get_attr(element, 'pattern'),
74
+ url=self.get_attr(element, 'url'),
75
+ datasource=self.get_attr(element, 'datasource'),
76
+ chunk_size=self.get_int_attr(element, 'chunkSize', 0) or None,
77
+ chunk_overlap=self.get_int_attr(element, 'chunkOverlap', 0) or None
78
+ )
79
+
80
+ # Get content for text source
81
+ if source_type == 'text':
82
+ source.content = self.get_text(element)
83
+ elif source_type == 'query':
84
+ source.sql = self.get_text(element)
85
+
86
+ return source
@@ -0,0 +1,78 @@
1
+ """
2
+ LLM Parser - Parse q:llm statements
3
+
4
+ Handles LLM invocation configuration.
5
+ """
6
+
7
+ from typing import List
8
+ from xml.etree import ElementTree as ET
9
+ from quantum.core.parsers.base import BaseTagParser, ParserError
10
+ from quantum.core.ast_nodes import LLMNode, LLMMessageNode
11
+
12
+
13
+ class LLMParser(BaseTagParser):
14
+ """
15
+ Parser for q:llm statements.
16
+
17
+ Supports:
18
+ - Completion mode (prompt)
19
+ - Chat mode (messages)
20
+ - Temperature/token configuration
21
+ - Response formatting
22
+ """
23
+
24
+ @property
25
+ def tag_names(self) -> List[str]:
26
+ return ['llm']
27
+
28
+ def parse(self, element: ET.Element) -> LLMNode:
29
+ """
30
+ Parse q:llm statement.
31
+
32
+ Args:
33
+ element: XML element for q:llm
34
+
35
+ Returns:
36
+ LLMNode AST node
37
+ """
38
+ name = self.get_attr(element, 'name')
39
+
40
+ if not name:
41
+ raise ParserError("LLM requires 'name' attribute")
42
+
43
+ llm_node = LLMNode(name)
44
+ llm_node.model = self.get_attr(element, 'model')
45
+ llm_node.endpoint = self.get_attr(element, 'endpoint')
46
+
47
+ # Temperature and tokens
48
+ temp = self.get_attr(element, 'temperature')
49
+ if temp:
50
+ try:
51
+ llm_node.temperature = float(temp)
52
+ except ValueError:
53
+ pass
54
+
55
+ llm_node.max_tokens = self.get_int_attr(element, 'maxTokens', 0) or None
56
+ llm_node.response_format = self.get_attr(element, 'responseFormat')
57
+ llm_node.cache = self.get_bool_attr(element, 'cache', False)
58
+ llm_node.ttl = self.get_int_attr(element, 'ttl', 0) or None
59
+ # q:llm spoke only Ollama while q:agent was already multi-provider;
60
+ # same attributes now work on both tags.
61
+ llm_node.provider = self.get_attr(element, 'provider')
62
+ llm_node.api_key = self.get_attr(element, 'apiKey')
63
+ llm_node.timeout = self.get_int_attr(element, 'timeout', 30)
64
+
65
+ # Parse children
66
+ for child in element:
67
+ child_type = self.get_element_name(child)
68
+
69
+ if child_type == 'prompt':
70
+ llm_node.prompt = self.get_text(child)
71
+ elif child_type == 'system':
72
+ llm_node.system = self.get_text(child)
73
+ elif child_type == 'message':
74
+ role = self.get_attr(child, 'role', 'user')
75
+ content = self.get_text(child)
76
+ llm_node.messages.append(LLMMessageNode(role, content))
77
+
78
+ return llm_node
@@ -0,0 +1,88 @@
1
+ """
2
+ Team Parser - Parse q:team statements
3
+
4
+ Handles multi-agent team configuration.
5
+ """
6
+
7
+ from typing import List
8
+ from xml.etree import ElementTree as ET
9
+ from quantum.core.parsers.base import BaseTagParser, ParserError
10
+ from quantum.core.features.agents.src.ast_node import AgentTeamNode, AgentExecuteNode
11
+
12
+
13
+ class TeamParser(BaseTagParser):
14
+ """
15
+ Parser for q:team statements.
16
+
17
+ Supports:
18
+ - Multiple agent definitions
19
+ - Shared context
20
+ - Supervisor/entry configuration
21
+ """
22
+
23
+ @property
24
+ def tag_names(self) -> List[str]:
25
+ return ['team']
26
+
27
+ def parse(self, element: ET.Element) -> AgentTeamNode:
28
+ """
29
+ Parse q:team statement.
30
+
31
+ Args:
32
+ element: XML element for q:team
33
+
34
+ Returns:
35
+ AgentTeamNode AST node
36
+ """
37
+ name = self.get_attr(element, 'name')
38
+
39
+ if not name:
40
+ raise ParserError("Team requires 'name' attribute")
41
+
42
+ # Create team node with defaults (matching legacy behavior)
43
+ team_node = AgentTeamNode(name=name)
44
+
45
+ # Parse attributes (support both snake_case and camelCase)
46
+ team_node.supervisor = self.get_attr(element, 'supervisor', '')
47
+
48
+ max_handoffs = self.get_attr(element, 'max_handoffs') or self.get_attr(element, 'maxHandoffs')
49
+ if max_handoffs:
50
+ try:
51
+ team_node.max_handoffs = int(max_handoffs)
52
+ except ValueError:
53
+ pass
54
+
55
+ max_iterations = self.get_attr(element, 'max_total_iterations') or self.get_attr(element, 'maxTotalIterations')
56
+ if max_iterations:
57
+ try:
58
+ team_node.max_total_iterations = int(max_iterations)
59
+ except ValueError:
60
+ pass
61
+
62
+ # Parse children
63
+ for child in element:
64
+ child_type = self.get_element_name(child)
65
+
66
+ if child_type == 'shared':
67
+ # Parse shared context (q:set nodes)
68
+ for shared_child in child:
69
+ statement = self.parse_statement(shared_child)
70
+ if statement:
71
+ team_node.shared.append(statement)
72
+ elif child_type == 'agent':
73
+ # Parse agent using main parser
74
+ agent = self.parse_statement(child)
75
+ if agent:
76
+ # Team members are driven by the team's <q:execute>, not
77
+ # one of their own — mark them so validate() doesn't
78
+ # reject the whole component.
79
+ agent.in_team = True
80
+ team_node.agents.append(agent)
81
+ elif child_type == 'execute':
82
+ team_node.execute = AgentExecuteNode(
83
+ task=self.get_attr(child, 'task', self.get_text(child)),
84
+ context=self.get_attr(child, 'context', ''),
85
+ entry=self.get_attr(child, 'entry', '')
86
+ )
87
+
88
+ return team_node