quantum-framework 0.19.0__tar.gz → 0.20.0__tar.gz
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.
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/PKG-INFO +2 -2
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/README.md +1 -1
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/pyproject.toml +1 -1
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/ast_nodes.py +5 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/expression_stdlib.py +7 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/agents/src/ast_node.py +2 -1
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/knowledge_base/src/ast_node.py +1 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/ui_engine/src/ast_nodes.py +16 -1
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/ui_engine/src/parser.py +10 -1
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parser.py +28 -1
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/ai/agent_parser.py +11 -1
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/ai/knowledge_parser.py +10 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/ai/llm_parser.py +15 -1
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/data/query_parser.py +6 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/agent_service.py +8 -2
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/component.py +4 -19
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/ai/agent_executor.py +11 -5
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/ai/knowledge_executor.py +6 -4
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/ai/llm_executor.py +98 -4
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/data/query_executor.py +7 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/knowledge_service.py +40 -40
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/llm_providers.py +60 -7
- quantum_framework-0.20.0/quantum/runtime/llm_stream.py +103 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/ui_console.py +30 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/ui_page_renderer.py +38 -1
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/ui_view.py +8 -1
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/web_server.py +13 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_framework.egg-info/PKG-INFO +2 -2
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_framework.egg-info/SOURCES.txt +1 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_agent.py +1 -1
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/LICENSE +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/admin.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/check.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/commands/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/commands/build.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/commands/dev.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/commands/docs.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/commands/lint.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/commands/migrate.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/commands/new.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/commands/serve.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/commands/test.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/deploy.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/hot_reload.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/jobs.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/mq.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/pkg.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/runner.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/schema_plan.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/server_process.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/cli/utils.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/compiler/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/compiler/base_generator.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/compiler/cli.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/compiler/expression_transformer.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/compiler/javascript/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/compiler/javascript/generator.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/compiler/optimizer.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/compiler/python/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/compiler/python/generator.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/compiler/python/runtime.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/compiler/transpiler.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/config_env.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/docs_links.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/expression_diagnostics.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/expressions.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/agents/src/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/conditionals/src/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/conditionals/src/ast_node.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/data_import/src/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/data_import/src/ast_node.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/data_import/src/runtime.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/dump/src/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/dump/src/ast_node.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/dump/src/parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/dump/src/runtime.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/functions/src/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/functions/src/ast_node.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/game_engine_2d/src/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/game_engine_2d/src/ast_nodes.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/game_engine_2d/src/parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/invocation/src/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/invocation/src/ast_node.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/invocation/src/runtime.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/knowledge_base/src/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/knowledge_base/src/parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/logging/src/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/logging/src/ast_node.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/logging/src/parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/logging/src/runtime.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/loops/src/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/loops/src/ast_node.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/query/src/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/query/src/query_validators.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/state_management/src/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/state_management/src/ast_node.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/terminal_engine/src/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/terminal_engine/src/ast_nodes.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/terminal_engine/src/parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/testing_engine/src/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/testing_engine/src/ast_nodes.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/testing_engine/src/parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/theming/src/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/theming/src/ast_node.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/theming/src/presets.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/ui_engine/src/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/websocket/src/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/websocket/src/ast_node.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/guards.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/html_compat.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parser_registry.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/ai/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/ai/team_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/base.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/composition/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/composition/import_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/composition/slot_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/control_flow/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/control_flow/if_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/control_flow/loop_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/control_flow/set_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/data/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/data/data_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/data/invoke_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/data/transaction_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/events/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/events/dispatch_event_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/forms/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/forms/action_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/forms/flash_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/forms/redirect_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/functions/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/functions/function_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/functions/param_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/functions/return_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/html/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/html/component_call_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/html/html_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/jobs/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/jobs/job_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/jobs/schedule_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/jobs/thread_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/messaging/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/messaging/message_ack_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/messaging/message_nack_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/messaging/message_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/messaging/queue_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/messaging/websocket_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/routing/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/routing/route_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/scripting/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/scripting/pyclass_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/scripting/pydecorator_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/scripting/pyimport_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/scripting/python_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/services/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/services/dump_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/services/file_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/services/log_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/services/mail_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/tiers.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/xml_lines.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/packages/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/packages/manager.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/packages/manifest.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/packages/registry.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/packages/resolver.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/plugins/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/plugins/hooks.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/plugins/loader.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/plugins/manifest.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/plugins/registry.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/action_handler.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/adapters/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/adapters/memory_adapter.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/adapters/rabbitmq_adapter.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/adapters/redis_adapter.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/adapters/sqlite_adapter.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/ast_cache.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/auth_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/component_composer.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/component_resolver.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/conditions.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/database_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/db_schema.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/dev_panel.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/email_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/error_handler.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/execution_context.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executor_registry.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/ai/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/ai/team_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/base.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/control_flow/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/control_flow/if_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/control_flow/loop_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/control_flow/redirect_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/control_flow/set_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/data/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/data/data_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/data/invoke_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/data/transaction_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/jobs/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/jobs/job_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/jobs/schedule_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/jobs/thread_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/messaging/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/messaging/message_ack_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/messaging/message_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/messaging/queue_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/messaging/websocket_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/scripting/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/scripting/pyclass_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/scripting/pyimport_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/scripting/python_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/services/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/services/dump_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/services/file_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/services/log_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/services/mail_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/expression_cache.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/file_upload_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/function_registry.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/game_builder.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/game_code_generator.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/game_templates.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/godot_code_generator.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/godot_templates.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/history.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/job_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/llm_cache.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/llm_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/local_server.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/logging_setup.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/message_broker.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/message_queue_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/param_validation.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/pypy_compat.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/python_bridge.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/query_validators.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/renderer.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/service_container.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/table_params.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/terminal_builder.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/terminal_code_generator.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/terminal_templates.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/testing_builder.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/testing_code_generator.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/testing_templates.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/ui_builder.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/ui_desktop.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/ui_form_rules.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/ui_html_adapter.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/ui_html_templates.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/ui_mobile_adapter.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/ui_mobile_templates.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/ui_pager.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/ui_table_edit.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/ui_textual_adapter.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/ui_textual_templates.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/ui_tokens.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/ui_validator.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/validators.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/websocket_adapter.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/websocket_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/websocket_transport.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/wsgi.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/services.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/utils/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/assets/quantum-admin-connectors.js +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/assets/quantum-admin.css +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/assets/quantum-source-highlight.js +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/audit_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/auth_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/component_discovery.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/config_generator.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/connector_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/crud.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/database.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/db_setup_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/deploy_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/docker_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/environment_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/git_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/health_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/job_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/log_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/main.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/models.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/pipeline_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/resource_manager.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/schemas.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/secret_manager.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/settings_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/template_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/test_execution_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/test_generator.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/webhook_service.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/backend/websocket_manager.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/components/admin/_layout/AdminShell.q +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/components/admin/agents.q +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/components/admin/app/[name].q +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/components/admin/applications.q +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/components/admin/component/[...path].q +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/components/admin/components.q +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/components/admin/connectors.q +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/components/admin/dashboard.q +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/components/admin/database.q +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/components/admin/features.q +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/components/admin/index.q +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/components/admin/jobs.q +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/components/admin/login.q +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/components/admin/logout.q +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/components/admin/settings.q +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/components/admin/source.q +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/components/admin/tests.q +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/run.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/services/__init__.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/services/_base.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/services/_component_test_generator.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/services/_yaml_editor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/services/apps.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/services/auth.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/services/components.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/services/connectors.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/services/projects.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/services/repository.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/services/settings.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_admin/services/yaml_import.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_framework.egg-info/dependency_links.txt +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_framework.egg-info/entry_points.txt +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_framework.egg-info/requires.txt +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum_framework.egg-info/top_level.txt +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/setup.cfg +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_animations.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_ast_cache.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_cli_commands.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_component_library.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_expression_cache.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_form_validation.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_game_codegen.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_game_e2e.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_game_engine.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_game_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_godot_codegen.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_job_executor.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_llm_providers.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_message_broker.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_message_queue.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_mobile_target.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_multi_agent.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_packages.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_plugins.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_pypy_compat.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_python_scripting.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_terminal_codegen.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_terminal_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_testing_codegen.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_testing_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_theming.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_ui_html_adapter.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_ui_parity.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_ui_parser.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_ui_textual_adapter.py +0 -0
- {quantum_framework-0.19.0 → quantum_framework-0.20.0}/tests/test_websocket.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quantum-framework
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.20.0
|
|
4
4
|
Summary: Full-stack declarative framework for building web, desktop, and mobile applications
|
|
5
5
|
Author-email: Daniel Gregorio <danielgregorio2611@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -94,7 +94,7 @@ and asks the model — in the markup. There is no Python file behind it.
|
|
|
94
94
|
An agent with its own tools, same idea:
|
|
95
95
|
|
|
96
96
|
```xml
|
|
97
|
-
<q:agent name="calc" model="phi3"
|
|
97
|
+
<q:agent name="calc" model="phi3" maxIterations="4">
|
|
98
98
|
<q:instruction>Use the add tool, then answer.</q:instruction>
|
|
99
99
|
|
|
100
100
|
<q:tool name="add" description="Add two numbers">
|
|
@@ -44,7 +44,7 @@ and asks the model — in the markup. There is no Python file behind it.
|
|
|
44
44
|
An agent with its own tools, same idea:
|
|
45
45
|
|
|
46
46
|
```xml
|
|
47
|
-
<q:agent name="calc" model="phi3"
|
|
47
|
+
<q:agent name="calc" model="phi3" maxIterations="4">
|
|
48
48
|
<q:instruction>Use the add tool, then answer.</q:instruction>
|
|
49
49
|
|
|
50
50
|
<q:tool name="add" description="Add two numbers">
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "quantum-framework"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.20.0"
|
|
8
8
|
description = "Full-stack declarative framework for building web, desktop, and mobile applications"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -699,6 +699,7 @@ class QueryNode(QuantumNode):
|
|
|
699
699
|
self.paginate = False # Enable automatic pagination
|
|
700
700
|
self.page = None
|
|
701
701
|
self.page_expr = None # DB-9: page as an expression (default {query.page})
|
|
702
|
+
self.on_error = 'fail' # IA-5: 'continue' hands a failure to <name>_result
|
|
702
703
|
self.sortable = False # UI-13: ORDER BY the URL's ?sort=/&dir=
|
|
703
704
|
self.page_size = 20
|
|
704
705
|
self.timeout = None
|
|
@@ -1478,6 +1479,10 @@ class LLMNode(QuantumNode):
|
|
|
1478
1479
|
self.prompt = None # Prompt text (with databinding)
|
|
1479
1480
|
self.system = None # System prompt (optional)
|
|
1480
1481
|
self.messages: List[LLMMessageNode] = [] # Chat mode messages
|
|
1482
|
+
self.on_error = 'fail' # IA-5: 'continue' hands a failure to <name>_result
|
|
1483
|
+
self.knowledge = None # IA-6: answer from this knowledge base, citing sources
|
|
1484
|
+
self.top = 4 # IA-6: how many sources to retrieve
|
|
1485
|
+
self.stream = False # IA-7: stream the answer to <ui:stream> (web requests)
|
|
1481
1486
|
self.temperature = None # 0.0-2.0
|
|
1482
1487
|
self.max_tokens = None # Token limit
|
|
1483
1488
|
self.response_format = None # "text" or "json"
|
|
@@ -172,6 +172,12 @@ def verify_password(password: Any, hashed: Any) -> bool:
|
|
|
172
172
|
return False
|
|
173
173
|
|
|
174
174
|
|
|
175
|
+
def _urlencode(v) -> str:
|
|
176
|
+
"""EXPR-12: a value made safe to put in a URL — `q:redirect url="/?q={urlencode(q)}"`."""
|
|
177
|
+
from urllib.parse import quote_plus
|
|
178
|
+
return quote_plus('' if v is None else str(v))
|
|
179
|
+
|
|
180
|
+
|
|
175
181
|
STDLIB = {
|
|
176
182
|
# passwords
|
|
177
183
|
'hashPassword': hash_password,
|
|
@@ -189,6 +195,7 @@ STDLIB = {
|
|
|
189
195
|
'split': _split,
|
|
190
196
|
'contains': _contains,
|
|
191
197
|
'slugify': _slugify,
|
|
198
|
+
'urlencode': _urlencode,
|
|
192
199
|
# collections
|
|
193
200
|
'len': _len,
|
|
194
201
|
'first': _first,
|
{quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/agents/src/ast_node.py
RENAMED
|
@@ -290,7 +290,7 @@ class AgentNode(QuantumNode):
|
|
|
290
290
|
|
|
291
291
|
Example:
|
|
292
292
|
<!-- Using Ollama (default) -->
|
|
293
|
-
<q:agent name="support" model="phi3"
|
|
293
|
+
<q:agent name="support" model="phi3" maxIterations="5">
|
|
294
294
|
...
|
|
295
295
|
</q:agent>
|
|
296
296
|
|
|
@@ -319,6 +319,7 @@ class AgentNode(QuantumNode):
|
|
|
319
319
|
api_key: str = "" # For cloud providers
|
|
320
320
|
max_iterations: int = 10
|
|
321
321
|
timeout: int = 60000 # milliseconds
|
|
322
|
+
on_error: str = "fail" # IA-5: "continue" hands a failure to the page
|
|
322
323
|
|
|
323
324
|
instruction: Optional[AgentInstructionNode] = None
|
|
324
325
|
tools: List[AgentToolNode] = field(default_factory=list)
|
|
@@ -82,6 +82,7 @@ class KnowledgeNode(QuantumNode):
|
|
|
82
82
|
persist: bool = False # Persist ChromaDB to disk
|
|
83
83
|
persist_path: Optional[str] = None # ChromaDB persistence path
|
|
84
84
|
rebuild: bool = False # Force reindex
|
|
85
|
+
on_error: str = 'fail' # IA-5: 'continue' hands a failure to <name>_info
|
|
85
86
|
|
|
86
87
|
def add_source(self, source: KnowledgeSourceNode):
|
|
87
88
|
self.sources.append(source)
|
|
@@ -1896,6 +1896,21 @@ class UIPagerNode(QuantumNode, UILayoutMixin):
|
|
|
1896
1896
|
return [] if self.for_query else ["ui:pager needs for="]
|
|
1897
1897
|
|
|
1898
1898
|
|
|
1899
|
+
class UIStreamNode(QuantumNode, UILayoutMixin):
|
|
1900
|
+
"""<ui:stream for="answer"> — a q:llm answer, arriving as it is written (IA-7)."""
|
|
1901
|
+
|
|
1902
|
+
def __init__(self):
|
|
1903
|
+
self.for_llm: Optional[str] = None
|
|
1904
|
+
self.children: List[QuantumNode] = []
|
|
1905
|
+
self._init_layout_attrs()
|
|
1906
|
+
|
|
1907
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
1908
|
+
return {"type": "ui_stream", "for": self.for_llm}
|
|
1909
|
+
|
|
1910
|
+
def validate(self) -> List[str]:
|
|
1911
|
+
return []
|
|
1912
|
+
|
|
1913
|
+
|
|
1899
1914
|
class UIHistoryNode(QuantumNode, UILayoutMixin):
|
|
1900
1915
|
"""<ui:history table="t" key="{row.id}" datasource="db"> — a row's change history (DB-11)."""
|
|
1901
1916
|
|
|
@@ -1926,6 +1941,6 @@ CORE_TAGS = frozenset({
|
|
|
1926
1941
|
'window', 'hbox', 'vbox', 'grid', 'panel', 'section', 'scrollbox', 'spacer', 'rule',
|
|
1927
1942
|
'header', 'footer', 'card', 'card-header', 'card-body', 'card-footer', 'tabpanel', 'tab',
|
|
1928
1943
|
'text', 'badge', 'alert', 'link', 'image', 'progress',
|
|
1929
|
-
'table', 'column', 'list', 'item', 'pager', 'history',
|
|
1944
|
+
'table', 'column', 'list', 'item', 'pager', 'history', 'stream',
|
|
1930
1945
|
'form', 'formitem', 'input', 'checkbox', 'switch', 'radio', 'select', 'option', 'button',
|
|
1931
1946
|
})
|
{quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/features/ui_engine/src/parser.py
RENAMED
|
@@ -28,7 +28,7 @@ from .ast_nodes import (
|
|
|
28
28
|
UIToastNode, UIToastContainerNode,
|
|
29
29
|
UICarouselNode, UISlideNode,
|
|
30
30
|
UIStepperNode, UIStepNode,
|
|
31
|
-
UICalendarNode, UIDatePickerNode, UIPagerNode, UIHistoryNode,
|
|
31
|
+
UICalendarNode, UIDatePickerNode, UIPagerNode, UIHistoryNode, UIStreamNode,
|
|
32
32
|
)
|
|
33
33
|
from quantum.core.features.theming.src import UIThemeNode, UIColorNode
|
|
34
34
|
from quantum.core.ast_nodes import TextNode
|
|
@@ -83,6 +83,7 @@ class UIParser:
|
|
|
83
83
|
'column': '_parse_ui_column',
|
|
84
84
|
'pager': '_parse_ui_pager',
|
|
85
85
|
'history': '_parse_ui_history',
|
|
86
|
+
'stream': '_parse_ui_stream',
|
|
86
87
|
'list': '_parse_ui_list',
|
|
87
88
|
'item': '_parse_ui_item',
|
|
88
89
|
'image': '_parse_ui_image',
|
|
@@ -551,6 +552,14 @@ class UIParser:
|
|
|
551
552
|
self._apply_layout_attrs(node, element)
|
|
552
553
|
return node
|
|
553
554
|
|
|
555
|
+
def _parse_ui_stream(self, element: ET.Element) -> UIStreamNode:
|
|
556
|
+
node = UIStreamNode()
|
|
557
|
+
node.for_llm = element.get('for')
|
|
558
|
+
if not node.for_llm:
|
|
559
|
+
raise UIParseError('<ui:stream> needs for="<the q:llm name>"')
|
|
560
|
+
self._apply_layout_attrs(node, element)
|
|
561
|
+
return node
|
|
562
|
+
|
|
554
563
|
def _parse_ui_history(self, element: ET.Element) -> UIHistoryNode:
|
|
555
564
|
node = UIHistoryNode()
|
|
556
565
|
node.table = element.get('table')
|
|
@@ -480,7 +480,13 @@ class QuantumParser:
|
|
|
480
480
|
A direct else child of a q:if is already the nested form and stays
|
|
481
481
|
where it is. An else with no q:if right before it is an error.
|
|
482
482
|
"""
|
|
483
|
-
|
|
483
|
+
parents = list(root.iter())
|
|
484
|
+
# IF-4 looks at the else children as written: before any sibling-form
|
|
485
|
+
# else is moved into its q:if below (which is not ambiguous).
|
|
486
|
+
for parent in parents:
|
|
487
|
+
if self._get_element_name(parent) == 'if':
|
|
488
|
+
self._check_dangling_else(parent)
|
|
489
|
+
for parent in parents:
|
|
484
490
|
if self._get_element_name(parent) == 'if':
|
|
485
491
|
continue
|
|
486
492
|
anterior = None
|
|
@@ -502,6 +508,27 @@ class QuantumParser:
|
|
|
502
508
|
continue
|
|
503
509
|
anterior = child if nome == 'if' and self._is_quantum_tag(child) else None
|
|
504
510
|
|
|
511
|
+
def _check_dangling_else(self, if_element: ET.Element) -> None:
|
|
512
|
+
"""IF-4: inside a q:if, a q:else/q:elseif right after an inner </q:if> is ambiguous.
|
|
513
|
+
|
|
514
|
+
IF-1 gives it to the outer q:if (a direct child belongs to its if), but
|
|
515
|
+
written right after an inner if it reads as that if's else — the
|
|
516
|
+
sibling form. A page built that way drew the else branch of the inner
|
|
517
|
+
if when the OUTER condition was false. Refused, with both fixes."""
|
|
518
|
+
previous = None
|
|
519
|
+
for child in if_element:
|
|
520
|
+
if not isinstance(child.tag, str):
|
|
521
|
+
continue
|
|
522
|
+
name = self._get_element_name(child)
|
|
523
|
+
if (name in ('else', 'elseif') and self._is_quantum_tag(child) and previous is not None):
|
|
524
|
+
error = QuantumParseError(
|
|
525
|
+
f"<q:{name}> right after an inner </q:if>, inside another <q:if>, is ambiguous "
|
|
526
|
+
f"(IF-4): it would belong to the OUTER q:if (IF-1). If it is the inner q:if's, "
|
|
527
|
+
f"write it inside that q:if; if it is the outer's, put it before the inner q:if.")
|
|
528
|
+
error.line = getattr(child, 'sourceline', None)
|
|
529
|
+
raise error
|
|
530
|
+
previous = child if name == 'if' and self._is_quantum_tag(child) else None
|
|
531
|
+
|
|
505
532
|
# Tags that existed and were removed, with what to use instead.
|
|
506
533
|
REMOVED_TAGS = {
|
|
507
534
|
'persist': ('was removed in Quantum 0.16 (SET-2): it kept variables in the browser, '
|
{quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/ai/agent_parser.py
RENAMED
|
@@ -42,6 +42,15 @@ class AgentParser(BaseTagParser):
|
|
|
42
42
|
|
|
43
43
|
if not name:
|
|
44
44
|
raise ParserError("Agent requires 'name' attribute")
|
|
45
|
+
if element.get('max_iterations') is not None:
|
|
46
|
+
# The guide and the README wrote max_iterations; it was never read
|
|
47
|
+
# and every agent ran up to 10 steps.
|
|
48
|
+
raise ParserError(f'<q:agent name="{name}">: the attribute is maxIterations, '
|
|
49
|
+
f'not max_iterations')
|
|
50
|
+
on_error = self.get_attr(element, 'onerror', 'fail')
|
|
51
|
+
if on_error not in ('fail', 'continue'):
|
|
52
|
+
raise ParserError(f'<q:agent name="{name}"> onerror must be "fail" or "continue", '
|
|
53
|
+
f'not "{on_error}"')
|
|
45
54
|
|
|
46
55
|
agent_node = AgentNode(
|
|
47
56
|
name=name,
|
|
@@ -50,7 +59,8 @@ class AgentParser(BaseTagParser):
|
|
|
50
59
|
provider=self.get_attr(element, 'provider', 'auto'),
|
|
51
60
|
api_key=self.get_attr(element, 'apiKey', ''),
|
|
52
61
|
max_iterations=self.get_int_attr(element, 'maxIterations', 10),
|
|
53
|
-
timeout=self.get_int_attr(element, 'timeout', 60000)
|
|
62
|
+
timeout=self.get_int_attr(element, 'timeout', 60000),
|
|
63
|
+
on_error=on_error,
|
|
54
64
|
)
|
|
55
65
|
|
|
56
66
|
# Parse children
|
{quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/ai/knowledge_parser.py
RENAMED
|
@@ -52,6 +52,11 @@ class KnowledgeParser(BaseTagParser):
|
|
|
52
52
|
persist_path=self.get_attr(element, 'persistPath', './.quantum/knowledge'),
|
|
53
53
|
rebuild=self.get_bool_attr(element, 'rebuild', False)
|
|
54
54
|
)
|
|
55
|
+
# IA-5: a base that cannot be built stops the page unless the page handles it.
|
|
56
|
+
knowledge_node.on_error = self.get_attr(element, 'onerror', 'fail')
|
|
57
|
+
if knowledge_node.on_error not in ('fail', 'continue'):
|
|
58
|
+
raise ParserError(f'<q:knowledge name="{name}"> onerror must be "fail" or "continue", '
|
|
59
|
+
f'not "{knowledge_node.on_error}"')
|
|
55
60
|
|
|
56
61
|
# Parse sources
|
|
57
62
|
for child in element:
|
|
@@ -66,6 +71,11 @@ class KnowledgeParser(BaseTagParser):
|
|
|
66
71
|
def _parse_source(self, element: ET.Element) -> KnowledgeSourceNode:
|
|
67
72
|
"""Parse q:source within q:knowledge."""
|
|
68
73
|
source_type = self.get_attr(element, 'type', 'text')
|
|
74
|
+
# IA-8: type="url" was accepted and read nothing (a log line said "not
|
|
75
|
+
# yet implemented"); an unknown type read nothing at all.
|
|
76
|
+
if source_type not in ('text', 'file', 'directory', 'query'):
|
|
77
|
+
raise ParserError(f'<q:source type="{source_type}">: use text, file, directory or query'
|
|
78
|
+
+ (' (url is not supported)' if source_type == 'url' else ''))
|
|
69
79
|
|
|
70
80
|
source = KnowledgeSourceNode(
|
|
71
81
|
source_type=source_type,
|
|
@@ -60,7 +60,21 @@ class LLMParser(BaseTagParser):
|
|
|
60
60
|
# same attributes now work on both tags.
|
|
61
61
|
llm_node.provider = self.get_attr(element, 'provider')
|
|
62
62
|
llm_node.api_key = self.get_attr(element, 'apiKey')
|
|
63
|
-
|
|
63
|
+
# Seconds to wait for the model; undeclared, the service default (60).
|
|
64
|
+
llm_node.timeout = self.get_int_attr(element, 'timeout', 0) or None
|
|
65
|
+
# M5 (IA-6): answer from a knowledge base, citing its sources.
|
|
66
|
+
llm_node.knowledge = self.get_attr(element, 'knowledge')
|
|
67
|
+
top = self.get_attr(element, 'top')
|
|
68
|
+
if top is not None and not str(top).isdigit():
|
|
69
|
+
raise ParserError(f'<q:llm name="{name}" top="{top}">: the number of sources to retrieve')
|
|
70
|
+
llm_node.top = int(top) if top is not None else 4
|
|
71
|
+
# IA-7: in a web request, the answer arrives as it is written (<ui:stream>).
|
|
72
|
+
llm_node.stream = self.get_bool_attr(element, 'stream', False)
|
|
73
|
+
# IA-5: a failure stops the page unless the page handles it.
|
|
74
|
+
llm_node.on_error = self.get_attr(element, 'onerror', 'fail')
|
|
75
|
+
if llm_node.on_error not in ('fail', 'continue'):
|
|
76
|
+
raise ParserError(f'<q:llm name="{name}"> onerror must be "fail" or "continue", '
|
|
77
|
+
f'not "{llm_node.on_error}"')
|
|
64
78
|
|
|
65
79
|
# Parse children
|
|
66
80
|
for child in element:
|
{quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/core/parsers/data/query_parser.py
RENAMED
|
@@ -108,6 +108,12 @@ class QueryParser(BaseTagParser):
|
|
|
108
108
|
or None
|
|
109
109
|
)
|
|
110
110
|
query_node.result = self.get_attr(element, 'result')
|
|
111
|
+
# IA-5 / DB: onerror="continue" hands a failure to the page as <name>_result.
|
|
112
|
+
query_node.on_error = self.get_attr(element, 'onerror', 'fail')
|
|
113
|
+
if query_node.on_error not in ('fail', 'continue'):
|
|
114
|
+
from quantum.core.parser import QuantumParseError
|
|
115
|
+
raise QuantumParseError(f'<q:query name="{name}"> onerror must be "fail" or "continue", '
|
|
116
|
+
f'not "{query_node.on_error}"')
|
|
111
117
|
|
|
112
118
|
# RAG/Knowledge attributes
|
|
113
119
|
query_node.mode = self.get_attr(element, 'mode')
|
|
@@ -78,6 +78,8 @@ class ToolCall:
|
|
|
78
78
|
return {
|
|
79
79
|
"tool": self.tool,
|
|
80
80
|
"args": self.args,
|
|
81
|
+
# IA-4: the call as a page shows it — low_stock(below=5)
|
|
82
|
+
"call": f"{self.tool}({', '.join(f'{k}={v}' for k, v in (self.args or {}).items())})",
|
|
81
83
|
"result": self.result,
|
|
82
84
|
"error": self.error,
|
|
83
85
|
"duration_ms": self.duration_ms
|
|
@@ -271,7 +273,9 @@ IMPORTANT: Always respond with valid JSON in the format shown above. Nothing els
|
|
|
271
273
|
model=model,
|
|
272
274
|
endpoint=endpoint,
|
|
273
275
|
provider=provider,
|
|
274
|
-
api_key=api_key
|
|
276
|
+
api_key=api_key,
|
|
277
|
+
# the model gets what is left of the agent's timeout, not a fixed 60s
|
|
278
|
+
timeout=max(1, int((timeout_ms - elapsed_ms) / 1000)),
|
|
275
279
|
)
|
|
276
280
|
|
|
277
281
|
# Get assistant message
|
|
@@ -409,7 +413,8 @@ IMPORTANT: Always respond with valid JSON in the format shown above. Nothing els
|
|
|
409
413
|
model: str,
|
|
410
414
|
endpoint: str,
|
|
411
415
|
provider: str = "auto",
|
|
412
|
-
api_key: str = ""
|
|
416
|
+
api_key: str = "",
|
|
417
|
+
timeout: Optional[int] = None
|
|
413
418
|
) -> Dict[str, Any]:
|
|
414
419
|
"""
|
|
415
420
|
Call LLM with messages using multi-provider support.
|
|
@@ -433,6 +438,7 @@ IMPORTANT: Always respond with valid JSON in the format shown above. Nothing els
|
|
|
433
438
|
endpoint=endpoint if endpoint else None,
|
|
434
439
|
api_key=api_key if api_key else None,
|
|
435
440
|
temperature=0.1, # Low temperature for deterministic tool use
|
|
441
|
+
timeout=timeout,
|
|
436
442
|
)
|
|
437
443
|
|
|
438
444
|
# Handle response format from MultiProviderLLMService
|
|
@@ -901,27 +901,12 @@ class ComponentRuntime:
|
|
|
901
901
|
# Extract knowledge base name from datasource
|
|
902
902
|
kb_name = query_node.datasource.replace('knowledge:', '', 1)
|
|
903
903
|
|
|
904
|
-
#
|
|
904
|
+
# IA-5: a base that could not be built is an error here too — never an
|
|
905
|
+
# answer ("still loading", success=True) that the page shows as one.
|
|
905
906
|
kb_meta = exec_context.get_variable(f"_knowledge_{kb_name}")
|
|
906
907
|
if isinstance(kb_meta, dict) and kb_meta.get("_failed"):
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
if mode == 'rag':
|
|
910
|
-
empty_data = [{"answer": "Knowledge base is still loading. Please refresh the page.", "sources": "", "confidence": "0"}]
|
|
911
|
-
result = _QR(data=empty_data, column_list=['answer', 'sources', 'confidence'], execution_time=0.0, record_count=1, success=True)
|
|
912
|
-
else:
|
|
913
|
-
result = _QR(data=[], column_list=['content', 'relevance', 'source', 'chunk_index'], execution_time=0.0, record_count=0, success=True)
|
|
914
|
-
result_dict = result.to_dict()
|
|
915
|
-
exec_context.set_variable(query_node.name, result.data, scope="component")
|
|
916
|
-
exec_context.set_variable(f"{query_node.name}_result", result_dict, scope="component")
|
|
917
|
-
self.context[query_node.name] = result.data
|
|
918
|
-
self.context[f"{query_node.name}_result"] = result_dict
|
|
919
|
-
if result.data and len(result.data) == 1 and isinstance(result.data[0], dict):
|
|
920
|
-
for field_name, field_value in result.data[0].items():
|
|
921
|
-
dotted_key = f"{query_node.name}.{field_name}"
|
|
922
|
-
exec_context.set_variable(dotted_key, field_value, scope="component")
|
|
923
|
-
self.context[dotted_key] = field_value
|
|
924
|
-
return result
|
|
908
|
+
raise KnowledgeError(f"knowledge base '{kb_name}' could not be built: "
|
|
909
|
+
f"{kb_meta.get('error', 'unknown error')}")
|
|
925
910
|
|
|
926
911
|
# Get the search query from the first parameter value
|
|
927
912
|
search_text = None
|
{quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/ai/agent_executor.py
RENAMED
|
@@ -122,18 +122,24 @@ class AgentExecutor(BaseExecutor):
|
|
|
122
122
|
exec_context.set_variable(node.name, result.get('result', ''), scope="component")
|
|
123
123
|
exec_context.set_variable(f"{node.name}_result", result, scope="component")
|
|
124
124
|
|
|
125
|
-
return result
|
|
126
|
-
|
|
127
125
|
except Exception as e:
|
|
128
|
-
|
|
126
|
+
result = {
|
|
129
127
|
'success': False,
|
|
130
128
|
'error': {'message': str(e)},
|
|
131
129
|
'result': '',
|
|
132
130
|
'iterations': 0,
|
|
133
131
|
'actions': []
|
|
134
132
|
}
|
|
135
|
-
exec_context.set_variable(
|
|
136
|
-
|
|
133
|
+
exec_context.set_variable(node.name, '', scope="component")
|
|
134
|
+
exec_context.set_variable(f"{node.name}_result", result, scope="component")
|
|
135
|
+
|
|
136
|
+
# IA-5: an agent that did not finish used to leave success=false and an
|
|
137
|
+
# empty answer on a page that went on as if nothing happened.
|
|
138
|
+
if not result.get('success') and getattr(node, 'on_error', 'fail') != 'continue':
|
|
139
|
+
message = (result.get('error') or {}).get('message') or 'the agent did not finish'
|
|
140
|
+
raise ExecutorError(f'Agent "{node.name}" failed: {message}. Add onerror="continue" to '
|
|
141
|
+
f'handle it on the page ({node.name}_result.success is false).')
|
|
142
|
+
return result
|
|
137
143
|
|
|
138
144
|
|
|
139
145
|
def coerce_tool_args(params, tool_args: Dict[str, Any]) -> Dict[str, Any]:
|
|
@@ -105,10 +105,12 @@ class KnowledgeExecutor(BaseExecutor):
|
|
|
105
105
|
'error': str(e),
|
|
106
106
|
'name': node.name
|
|
107
107
|
}, scope="component")
|
|
108
|
-
#
|
|
109
|
-
#
|
|
110
|
-
#
|
|
108
|
+
# IA-5: a q:query on this base then fails with this reason (it used
|
|
109
|
+
# to answer "Knowledge base is still loading" as if that were the
|
|
110
|
+
# answer, with success=True).
|
|
111
111
|
exec_context.set_variable(f"_knowledge_{node.name}", {
|
|
112
|
-
'_failed': True,
|
|
112
|
+
'_failed': True, 'error': str(e),
|
|
113
113
|
}, scope="component")
|
|
114
|
+
if getattr(node, 'on_error', 'fail') == 'continue':
|
|
115
|
+
return None
|
|
114
116
|
raise ExecutorError(f"Knowledge base creation error: {e}")
|
{quantum_framework-0.19.0 → quantum_framework-0.20.0}/quantum/runtime/executors/ai/llm_executor.py
RENAMED
|
@@ -5,6 +5,7 @@ Handles LLM invocation across providers (Ollama, OpenAI, Anthropic, LM Studio).
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import json
|
|
8
|
+
import re
|
|
8
9
|
from typing import Any, List, Dict, Type
|
|
9
10
|
from quantum.runtime.executors.base import BaseExecutor, ExecutorError
|
|
10
11
|
from quantum.core.ast_nodes import LLMNode
|
|
@@ -64,10 +65,49 @@ class LLMExecutor(BaseExecutor):
|
|
|
64
65
|
if not messages:
|
|
65
66
|
prompt_text = self.apply_databinding(node.prompt, context) if node.prompt else ''
|
|
66
67
|
|
|
68
|
+
sources = None
|
|
69
|
+
if getattr(node, 'knowledge', None):
|
|
70
|
+
# IA-6 (M5): answer from the knowledge base, citing its sources.
|
|
71
|
+
question = next((m['content'] for m in reversed(messages) if m['role'] == 'user'), prompt_text)
|
|
72
|
+
sources = self._retrieve(node, question or '', exec_context)
|
|
73
|
+
if not sources:
|
|
74
|
+
# Nothing to answer from: the model is not asked (it would
|
|
75
|
+
# answer from memory, uncited). The page sees found=false.
|
|
76
|
+
return self._store(node, {'data': '', 'success': True, 'model': model}, exec_context,
|
|
77
|
+
cached=False, extra={'found': False, 'sources': [], 'cited': []})
|
|
78
|
+
grounding = self._grounding(sources)
|
|
79
|
+
# Small models follow the last instruction best: repeat it with the question.
|
|
80
|
+
reminder = ' (Answer from the sources and cite them like [1].)'
|
|
81
|
+
if messages and messages[-1]['role'] == 'user':
|
|
82
|
+
messages[-1] = {'role': 'user', 'content': messages[-1]['content'] + reminder}
|
|
83
|
+
elif prompt_text is not None:
|
|
84
|
+
prompt_text += reminder
|
|
85
|
+
system_text = f'{grounding}\n\n{system_text}' if system_text else grounding
|
|
86
|
+
if messages:
|
|
87
|
+
if messages[0]['role'] == 'system':
|
|
88
|
+
messages[0] = {'role': 'system', 'content': f"{grounding}\n\n{messages[0]['content']}"}
|
|
89
|
+
else:
|
|
90
|
+
messages.insert(0, {'role': 'system', 'content': grounding})
|
|
91
|
+
|
|
67
92
|
temperature = float(node.temperature) if node.temperature is not None else None
|
|
68
93
|
max_tokens = int(node.max_tokens) if node.max_tokens is not None else None
|
|
69
94
|
response_format = node.response_format or 'text'
|
|
70
95
|
|
|
96
|
+
if getattr(node, 'stream', False) and self._in_web_request():
|
|
97
|
+
# IA-7: the page renders now; <ui:stream> reads the answer from /_stream/<token>.
|
|
98
|
+
from quantum.runtime import llm_stream
|
|
99
|
+
chat = messages or ([{'role': 'system', 'content': system_text}] if system_text else []) + [{'role': 'user', 'content': prompt_text or ''}]
|
|
100
|
+
token = llm_stream.register({
|
|
101
|
+
'messages': chat, 'model': model, 'provider': provider, 'endpoint': endpoint,
|
|
102
|
+
'api_key': api_key, 'temperature': temperature, 'max_tokens': max_tokens,
|
|
103
|
+
'timeout': node.timeout,
|
|
104
|
+
}, exec_context.session_vars)
|
|
105
|
+
extra = {'stream': f'/_stream/{token}'}
|
|
106
|
+
if sources is not None:
|
|
107
|
+
extra.update({'found': True, 'sources': sources, 'cited': []})
|
|
108
|
+
return self._store(node, {'data': '', 'success': True, 'model': model}, exec_context,
|
|
109
|
+
cached=False, extra=extra)
|
|
110
|
+
|
|
71
111
|
cache = self.services.llm_cache if node.cache else None
|
|
72
112
|
cache_key = None
|
|
73
113
|
if cache is not None:
|
|
@@ -96,6 +136,7 @@ class LLMExecutor(BaseExecutor):
|
|
|
96
136
|
temperature=temperature,
|
|
97
137
|
max_tokens=max_tokens,
|
|
98
138
|
response_format=response_format,
|
|
139
|
+
timeout=node.timeout,
|
|
99
140
|
)
|
|
100
141
|
else:
|
|
101
142
|
response = llm.generate(
|
|
@@ -108,22 +149,74 @@ class LLMExecutor(BaseExecutor):
|
|
|
108
149
|
temperature=temperature,
|
|
109
150
|
max_tokens=max_tokens,
|
|
110
151
|
response_format=response_format,
|
|
152
|
+
timeout=node.timeout,
|
|
111
153
|
)
|
|
112
154
|
|
|
113
155
|
if cache is not None and response.get('success', True):
|
|
114
156
|
cache.set(cache_key, response, ttl=node.ttl)
|
|
115
157
|
|
|
116
|
-
|
|
158
|
+
extra = None
|
|
159
|
+
if sources is not None:
|
|
160
|
+
extra = {'found': True, 'sources': sources,
|
|
161
|
+
'cited': self._cited(str(response.get('data', '')), len(sources))}
|
|
162
|
+
return self._store(node, response, exec_context, cached=False, extra=extra)
|
|
117
163
|
|
|
118
164
|
except Exception as e:
|
|
165
|
+
# IA-5: same shape as q:invoke (INV-2): <name>_result.error.message.
|
|
119
166
|
exec_context.set_variable(f"{node.name}_result", {
|
|
120
167
|
'success': False,
|
|
121
|
-
'error': str(e),
|
|
168
|
+
'error': {'message': str(e)},
|
|
122
169
|
'model': node.model
|
|
123
170
|
}, scope="component")
|
|
124
|
-
|
|
171
|
+
if getattr(node, 'on_error', 'fail') == 'continue':
|
|
172
|
+
exec_context.set_variable(node.name, '', scope="component")
|
|
173
|
+
return None
|
|
174
|
+
raise ExecutorError(f"LLM execution error: {e}. Add onerror=\"continue\" to handle it "
|
|
175
|
+
f"with {node.name}_result instead.")
|
|
176
|
+
|
|
177
|
+
@staticmethod
|
|
178
|
+
def _in_web_request() -> bool:
|
|
179
|
+
"""IA-7: streaming needs a browser (or the console) to read /_stream; `quantum run` waits."""
|
|
180
|
+
try:
|
|
181
|
+
from flask import has_request_context
|
|
182
|
+
return has_request_context()
|
|
183
|
+
except ImportError:
|
|
184
|
+
return False
|
|
125
185
|
|
|
126
|
-
|
|
186
|
+
# -- IA-6: answers grounded in a knowledge base --------------------------------
|
|
187
|
+
|
|
188
|
+
def _retrieve(self, node: LLMNode, question: str, exec_context) -> list:
|
|
189
|
+
"""The top chunks for the question, numbered as the model will cite them."""
|
|
190
|
+
name = node.knowledge
|
|
191
|
+
try:
|
|
192
|
+
meta = exec_context.get_variable(f'_knowledge_{name}')
|
|
193
|
+
except Exception:
|
|
194
|
+
meta = None
|
|
195
|
+
if not isinstance(meta, dict):
|
|
196
|
+
raise ExecutorError(f'<q:llm knowledge="{name}">: there is no <q:knowledge name="{name}"> '
|
|
197
|
+
f'on this page')
|
|
198
|
+
if meta.get('_failed'):
|
|
199
|
+
raise ExecutorError(f"knowledge base '{name}' could not be built: {meta.get('error')}")
|
|
200
|
+
hits = self.runtime.knowledge_service.search(
|
|
201
|
+
name, question, int(getattr(node, 'top', 4) or 4), meta.get('embed_model', 'nomic-embed-text'))
|
|
202
|
+
from pathlib import PurePath
|
|
203
|
+
return [{'n': i + 1, 'source': h.get('source') or 'unknown',
|
|
204
|
+
'name': PurePath(str(h.get('source') or 'unknown').replace('\\', '/')).name,
|
|
205
|
+
'text': h.get('content', ''), 'relevance': h.get('relevance')} for i, h in enumerate(hits)]
|
|
206
|
+
|
|
207
|
+
@staticmethod
|
|
208
|
+
def _grounding(sources: list) -> str:
|
|
209
|
+
numbered = '\n\n'.join(f"[{s['n']}] ({s['name']})\n{s['text']}" for s in sources)
|
|
210
|
+
return ('Answer using only the sources below. After each statement, cite the source it '
|
|
211
|
+
'comes from by its number in brackets, like [1]. If the sources do not contain '
|
|
212
|
+
'the answer, say that you do not know.\n\nSources:\n' + numbered)
|
|
213
|
+
|
|
214
|
+
@staticmethod
|
|
215
|
+
def _cited(text: str, count: int) -> list:
|
|
216
|
+
return sorted({int(n) for n in re.findall(r'\[(\d+)\]', text) if 1 <= int(n) <= count})
|
|
217
|
+
|
|
218
|
+
def _store(self, node: LLMNode, response: Dict[str, Any], exec_context, cached: bool,
|
|
219
|
+
extra: Dict[str, Any] = None) -> Any:
|
|
127
220
|
"""Unpack a provider response, store it, and return the value."""
|
|
128
221
|
text = response.get('data', '')
|
|
129
222
|
value = text
|
|
@@ -148,6 +241,7 @@ class LLMExecutor(BaseExecutor):
|
|
|
148
241
|
'provider': response.get('provider'),
|
|
149
242
|
'usage': response.get('usage'),
|
|
150
243
|
'cached': cached,
|
|
244
|
+
**(extra or {}),
|
|
151
245
|
}, scope="component")
|
|
152
246
|
|
|
153
247
|
return value
|
|
@@ -56,6 +56,13 @@ class QueryExecutor(BaseExecutor):
|
|
|
56
56
|
return self._execute_database_query(node, resolved_params, exec_context)
|
|
57
57
|
|
|
58
58
|
except Exception as e:
|
|
59
|
+
if getattr(node, 'on_error', 'fail') == 'continue':
|
|
60
|
+
# IA-5: the page handles it — no rows, and why.
|
|
61
|
+
exec_context.set_variable(node.name, [], scope="component")
|
|
62
|
+
exec_context.set_variable(f"{node.name}_result", {
|
|
63
|
+
'success': False, 'error': {'message': str(e)}, 'recordCount': 0, 'data': [],
|
|
64
|
+
}, scope="component")
|
|
65
|
+
return None
|
|
59
66
|
raise ExecutorError(f"Query execution error in '{node.name}': {e}")
|
|
60
67
|
|
|
61
68
|
def _resolve_params(self, node: QueryNode, context: Dict[str, Any]) -> Dict[str, Any]:
|