voodoo-framework 2.9.0__tar.gz → 3.0.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.
- {voodoo_framework-2.9.0/src/voodoo_framework.egg-info → voodoo_framework-3.0.0}/PKG-INFO +1 -1
- voodoo_framework-3.0.0/src/voodoo/__init__.py +25 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/adapters/tailwind.py +31 -19
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/adapters/voodoo_css.py +1 -3
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ai/agent_legacy.py +42 -34
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ai/agent_runtime_truth.py +2 -2
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ai/providers/__init__.py +8 -8
- voodoo_framework-3.0.0/src/voodoo/ai/providers/anthropic.py +7 -0
- voodoo_framework-3.0.0/src/voodoo/ai/providers/gemini.py +7 -0
- voodoo_framework-3.0.0/src/voodoo/ai/providers/ollama.py +7 -0
- voodoo_framework-3.0.0/src/voodoo/ai/providers/openai.py +7 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ai/tools/__init__.py +3 -3
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ai/tools/registry.py +2 -2
- voodoo_framework-3.0.0/src/voodoo/auth/guards.py +144 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/auth/jwt.py +28 -34
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/__init__.py +2 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/approvals.py +1 -1
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/dev.py +1 -1
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/doctor.py +78 -73
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/fabric.py +1 -1
- voodoo_framework-3.0.0/src/voodoo/cli/graph.py +36 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/inspect.py +91 -55
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/new.py +78 -110
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/recover.py +1 -1
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/scaffolding.py +103 -102
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/status.py +2 -2
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/tasks.py +1 -1
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/theme.py +4 -4
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/workers_cmd.py +1 -1
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/core/__init__.py +2 -1
- voodoo_framework-3.0.0/src/voodoo/core/app.py +561 -0
- voodoo_framework-3.0.0/src/voodoo/core/events.py +23 -0
- voodoo_framework-3.0.0/src/voodoo/core/routing.py +14 -0
- voodoo_framework-3.0.0/src/voodoo/core/sitemap.py +110 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/core/state.py +4 -5
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/data/base.py +15 -4
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/data/model.py +5 -5
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/data/store_facade.py +1 -1
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/edge/gateway.py +2 -2
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/edge/http.py +1 -1
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/edge/mqtt.py +5 -6
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/edge/protocol.py +2 -2
- voodoo_framework-3.0.0/src/voodoo/integrations/__init__.py +1 -0
- voodoo_framework-3.0.0/src/voodoo/integrations/ai/__init__.py +1 -0
- {voodoo_framework-2.9.0/src/voodoo/ai/providers → voodoo_framework-3.0.0/src/voodoo/integrations/ai}/anthropic.py +1 -1
- {voodoo_framework-2.9.0/src/voodoo/ai/providers → voodoo_framework-3.0.0/src/voodoo/integrations/ai}/gemini.py +1 -1
- {voodoo_framework-2.9.0/src/voodoo/ai/providers → voodoo_framework-3.0.0/src/voodoo/integrations/ai}/ollama.py +1 -1
- {voodoo_framework-2.9.0/src/voodoo/ai/providers → voodoo_framework-3.0.0/src/voodoo/integrations/ai}/openai.py +1 -1
- {voodoo_framework-2.9.0/src/voodoo → voodoo_framework-3.0.0/src/voodoo/integrations}/mcp/__init__.py +67 -107
- voodoo_framework-2.9.0/src/voodoo/telemetry/otlp.py → voodoo_framework-3.0.0/src/voodoo/integrations/otel.py +8 -9
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/memory/interfaces.py +2 -3
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/mesh/__init__.py +10 -10
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/mesh/client.py +1 -1
- {voodoo_framework-2.9.0/src/voodoo/telemetry → voodoo_framework-3.0.0/src/voodoo/observability}/__init__.py +5 -3
- {voodoo_framework-2.9.0/src/voodoo/telemetry → voodoo_framework-3.0.0/src/voodoo/observability}/api.py +1 -1
- {voodoo_framework-2.9.0/src/voodoo/telemetry → voodoo_framework-3.0.0/src/voodoo/observability}/middleware.py +1 -1
- {voodoo_framework-2.9.0/src/voodoo/telemetry → voodoo_framework-3.0.0/src/voodoo/observability}/store.py +5 -5
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/protocol/schemas.py +2 -2
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/routing/api.py +78 -74
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/runtime/__init__.py +138 -30
- voodoo_framework-3.0.0/src/voodoo/runtime/agency/__init__.py +39 -0
- {voodoo_framework-2.9.0/src/voodoo/runtime → voodoo_framework-3.0.0/src/voodoo/runtime/agency}/adaptive.py +102 -98
- {voodoo_framework-2.9.0/src/voodoo/runtime → voodoo_framework-3.0.0/src/voodoo/runtime/agency}/goal.py +3 -3
- voodoo_framework-3.0.0/src/voodoo/runtime/application_graph.py +541 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/runtime/context.py +1 -1
- voodoo_framework-3.0.0/src/voodoo/runtime/conventions.py +71 -0
- voodoo_framework-3.0.0/src/voodoo/runtime/dependency_graph.py +138 -0
- voodoo_framework-3.0.0/src/voodoo/runtime/distributed/__init__.py +35 -0
- {voodoo_framework-2.9.0/src/voodoo/runtime → voodoo_framework-3.0.0/src/voodoo/runtime/distributed}/fabric.py +10 -4
- {voodoo_framework-2.9.0/src/voodoo/mesh → voodoo_framework-3.0.0/src/voodoo/runtime/distributed}/replay.py +4 -1
- voodoo_framework-3.0.0/src/voodoo/runtime/execution/__init__.py +5 -0
- {voodoo_framework-2.9.0/src/voodoo/runtime → voodoo_framework-3.0.0/src/voodoo/runtime/execution}/engine.py +7 -7
- voodoo_framework-2.9.0/src/voodoo/runtime/execution.py → voodoo_framework-3.0.0/src/voodoo/runtime/execution/model.py +1 -1
- voodoo_framework-3.0.0/src/voodoo/runtime/extension.py +116 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/runtime/graph.py +1 -1
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/runtime/human.py +1 -1
- voodoo_framework-3.0.0/src/voodoo/runtime/inspection/__init__.py +11 -0
- voodoo_framework-3.0.0/src/voodoo/runtime/inspection/lineage.py +147 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/runtime/persistence.py +1 -1
- voodoo_framework-3.0.0/src/voodoo/runtime/reconciliation/__init__.py +25 -0
- voodoo_framework-3.0.0/src/voodoo/runtime/reconciliation/reconcile.py +318 -0
- voodoo_framework-3.0.0/src/voodoo/runtime/runtime.py +468 -0
- voodoo_framework-3.0.0/src/voodoo/runtime/scheduling/__init__.py +34 -0
- voodoo_framework-3.0.0/src/voodoo/runtime/scheduling/dispatch.py +104 -0
- voodoo_framework-3.0.0/src/voodoo/runtime/scheduling/handoff.py +81 -0
- voodoo_framework-2.9.0/src/voodoo/runtime/scheduler.py → voodoo_framework-3.0.0/src/voodoo/runtime/scheduling/schedule_service.py +1 -1
- voodoo_framework-2.9.0/src/voodoo/workers/__init__.py → voodoo_framework-3.0.0/src/voodoo/runtime/scheduling/tasks.py +6 -6
- voodoo_framework-3.0.0/src/voodoo/runtime/scheduling/work.py +275 -0
- voodoo_framework-2.9.0/src/voodoo/workers/queue.py → voodoo_framework-3.0.0/src/voodoo/runtime/scheduling/workers.py +12 -7
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/runtime/store.py +3 -3
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/runtime/task.py +3 -3
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/runtime/workflow.py +5 -5
- voodoo_framework-3.0.0/src/voodoo/security/headers.py +46 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/security/secrets.py +1 -1
- voodoo_framework-3.0.0/src/voodoo/seo.py +292 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/status.py +3 -3
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/events/local.py +1 -1
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/events/postgres.py +1 -1
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/events/sqlite.py +1 -1
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/events/store.py +1 -1
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/objects/s3.py +3 -3
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/component.py +2 -4
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/controls.py +6 -10
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/data_extended.py +13 -15
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/forms_extended.py +12 -6
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/foundation.py +10 -6
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/interaction_kernel.py +4 -11
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/interactions.py +1 -2
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/library.py +2 -6
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/navigation.py +5 -7
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/navigation_extended.py +15 -17
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/state.py +49 -1
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/styles/palette.py +3 -1
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/styles/presets.py +2 -2
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/workspace.py +27 -19
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0/src/voodoo_framework.egg-info}/PKG-INFO +1 -1
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo_framework.egg-info/SOURCES.txt +46 -145
- voodoo_framework-2.9.0/src/voodoo/__init__.py +0 -413
- voodoo_framework-2.9.0/src/voodoo/agent.py +0 -9
- voodoo_framework-2.9.0/src/voodoo/api.py +0 -13
- voodoo_framework-2.9.0/src/voodoo/auth/guards.py +0 -282
- voodoo_framework-2.9.0/src/voodoo/core/app.py +0 -443
- voodoo_framework-2.9.0/src/voodoo/core/events.py +0 -21
- voodoo_framework-2.9.0/src/voodoo/core/routing.py +0 -18
- voodoo_framework-2.9.0/src/voodoo/core/sitemap.py +0 -134
- voodoo_framework-2.9.0/src/voodoo/queue.py +0 -12
- voodoo_framework-2.9.0/src/voodoo/security/headers.py +0 -50
- voodoo_framework-2.9.0/src/voodoo/seo.py +0 -292
- voodoo_framework-2.9.0/src/voodoo/theme.py +0 -29
- voodoo_framework-2.9.0/src/voodoo/tools/__init__.py +0 -9
- voodoo_framework-2.9.0/src/voodoo/tools/registry.py +0 -20
- voodoo_framework-2.9.0/tests/test_adaptive_agency_correctness.py +0 -233
- voodoo_framework-2.9.0/tests/test_agency_runtime_truth.py +0 -172
- voodoo_framework-2.9.0/tests/test_agent.py +0 -603
- voodoo_framework-2.9.0/tests/test_agent_registry.py +0 -391
- voodoo_framework-2.9.0/tests/test_agent_runtime.py +0 -108
- voodoo_framework-2.9.0/tests/test_app.py +0 -344
- voodoo_framework-2.9.0/tests/test_auth.py +0 -267
- voodoo_framework-2.9.0/tests/test_brand.py +0 -61
- voodoo_framework-2.9.0/tests/test_capability_security.py +0 -426
- voodoo_framework-2.9.0/tests/test_checkpoint_resume.py +0 -134
- voodoo_framework-2.9.0/tests/test_chrome.py +0 -156
- voodoo_framework-2.9.0/tests/test_cli.py +0 -431
- voodoo_framework-2.9.0/tests/test_cli_fabric.py +0 -28
- voodoo_framework-2.9.0/tests/test_cli_inspect.py +0 -223
- voodoo_framework-2.9.0/tests/test_components.py +0 -269
- voodoo_framework-2.9.0/tests/test_config.py +0 -234
- voodoo_framework-2.9.0/tests/test_contract_api.py +0 -242
- voodoo_framework-2.9.0/tests/test_create.py +0 -104
- voodoo_framework-2.9.0/tests/test_create_store_smoke.py +0 -60
- voodoo_framework-2.9.0/tests/test_data.py +0 -92
- voodoo_framework-2.9.0/tests/test_data_extended.py +0 -275
- voodoo_framework-2.9.0/tests/test_design_system.py +0 -201
- voodoo_framework-2.9.0/tests/test_design_system2.py +0 -136
- voodoo_framework-2.9.0/tests/test_design_system_premium.py +0 -101
- voodoo_framework-2.9.0/tests/test_design_system_theme_contract.py +0 -53
- voodoo_framework-2.9.0/tests/test_durable_goal_runtime.py +0 -161
- voodoo_framework-2.9.0/tests/test_durable_hitl.py +0 -346
- voodoo_framework-2.9.0/tests/test_durable_workflow_runtime.py +0 -157
- voodoo_framework-2.9.0/tests/test_edge_device.py +0 -325
- voodoo_framework-2.9.0/tests/test_edge_e2e.py +0 -186
- voodoo_framework-2.9.0/tests/test_edge_gateway.py +0 -1002
- voodoo_framework-2.9.0/tests/test_edge_http.py +0 -331
- voodoo_framework-2.9.0/tests/test_edge_protocol.py +0 -159
- voodoo_framework-2.9.0/tests/test_edge_security.py +0 -399
- voodoo_framework-2.9.0/tests/test_edge_voodoo_store.py +0 -102
- voodoo_framework-2.9.0/tests/test_edge_world.py +0 -156
- voodoo_framework-2.9.0/tests/test_events.py +0 -54
- voodoo_framework-2.9.0/tests/test_execution_sqlite_store.py +0 -152
- voodoo_framework-2.9.0/tests/test_forms_extended.py +0 -209
- voodoo_framework-2.9.0/tests/test_foundation_components.py +0 -138
- voodoo_framework-2.9.0/tests/test_goal_runtime.py +0 -169
- voodoo_framework-2.9.0/tests/test_hitl_persistence_correctness.py +0 -140
- voodoo_framework-2.9.0/tests/test_http_runtime.py +0 -129
- voodoo_framework-2.9.0/tests/test_human.py +0 -133
- voodoo_framework-2.9.0/tests/test_i18n.py +0 -77
- voodoo_framework-2.9.0/tests/test_identity_execution.py +0 -149
- voodoo_framework-2.9.0/tests/test_identity_foundation.py +0 -156
- voodoo_framework-2.9.0/tests/test_integration.py +0 -626
- voodoo_framework-2.9.0/tests/test_interaction_components.py +0 -363
- voodoo_framework-2.9.0/tests/test_interaction_kernel.py +0 -307
- voodoo_framework-2.9.0/tests/test_mcp.py +0 -326
- voodoo_framework-2.9.0/tests/test_mcp_runtime.py +0 -102
- voodoo_framework-2.9.0/tests/test_memory.py +0 -412
- voodoo_framework-2.9.0/tests/test_mesh.py +0 -350
- voodoo_framework-2.9.0/tests/test_mesh_event_bus.py +0 -67
- voodoo_framework-2.9.0/tests/test_mesh_remote_auth.py +0 -216
- voodoo_framework-2.9.0/tests/test_mesh_remote_authority.py +0 -164
- voodoo_framework-2.9.0/tests/test_mesh_remote_execution.py +0 -326
- voodoo_framework-2.9.0/tests/test_mesh_remote_outcomes.py +0 -205
- voodoo_framework-2.9.0/tests/test_mesh_remote_replay.py +0 -178
- voodoo_framework-2.9.0/tests/test_mesh_two_node_acceptance.py +0 -254
- voodoo_framework-2.9.0/tests/test_model.py +0 -193
- voodoo_framework-2.9.0/tests/test_navigation_extended.py +0 -224
- voodoo_framework-2.9.0/tests/test_node_membership.py +0 -134
- voodoo_framework-2.9.0/tests/test_object_store.py +0 -92
- voodoo_framework-2.9.0/tests/test_observability.py +0 -459
- voodoo_framework-2.9.0/tests/test_operational_policy.py +0 -160
- voodoo_framework-2.9.0/tests/test_operational_runtime_ui.py +0 -70
- voodoo_framework-2.9.0/tests/test_persistence.py +0 -187
- voodoo_framework-2.9.0/tests/test_planner_adaptive.py +0 -269
- voodoo_framework-2.9.0/tests/test_primitives.py +0 -529
- voodoo_framework-2.9.0/tests/test_product_components.py +0 -176
- voodoo_framework-2.9.0/tests/test_protocol.py +0 -369
- voodoo_framework-2.9.0/tests/test_protocol_fabric.py +0 -55
- voodoo_framework-2.9.0/tests/test_protocol_operational.py +0 -96
- voodoo_framework-2.9.0/tests/test_provider_switching.py +0 -71
- voodoo_framework-2.9.0/tests/test_providers.py +0 -352
- voodoo_framework-2.9.0/tests/test_public_api_3.py +0 -43
- voodoo_framework-2.9.0/tests/test_public_assets.py +0 -48
- voodoo_framework-2.9.0/tests/test_queue.py +0 -44
- voodoo_framework-2.9.0/tests/test_reactive.py +0 -332
- voodoo_framework-2.9.0/tests/test_runtime.py +0 -596
- voodoo_framework-2.9.0/tests/test_runtime_correctness.py +0 -93
- voodoo_framework-2.9.0/tests/test_runtime_fabric.py +0 -226
- voodoo_framework-2.9.0/tests/test_runtime_store_app_lifecycle.py +0 -53
- voodoo_framework-2.9.0/tests/test_runtime_store_lifecycle.py +0 -211
- voodoo_framework-2.9.0/tests/test_runtime_store_provider.py +0 -200
- voodoo_framework-2.9.0/tests/test_runtime_transaction.py +0 -156
- voodoo_framework-2.9.0/tests/test_scheduler.py +0 -128
- voodoo_framework-2.9.0/tests/test_security.py +0 -460
- voodoo_framework-2.9.0/tests/test_seo.py +0 -508
- voodoo_framework-2.9.0/tests/test_sprint27_convergence.py +0 -129
- voodoo_framework-2.9.0/tests/test_sprint28_acceptance.py +0 -154
- voodoo_framework-2.9.0/tests/test_state.py +0 -108
- voodoo_framework-2.9.0/tests/test_store_first_user_journey.py +0 -116
- voodoo_framework-2.9.0/tests/test_store_model_backend.py +0 -209
- voodoo_framework-2.9.0/tests/test_store_only_core_import.py +0 -89
- voodoo_framework-2.9.0/tests/test_theme.py +0 -119
- voodoo_framework-2.9.0/tests/test_theme_presets.py +0 -107
- voodoo_framework-2.9.0/tests/test_tools.py +0 -241
- voodoo_framework-2.9.0/tests/test_ui.py +0 -603
- voodoo_framework-2.9.0/tests/test_ui_magic.py +0 -101
- voodoo_framework-2.9.0/tests/test_ui_magic_acceptance.py +0 -99
- voodoo_framework-2.9.0/tests/test_voodoo_store_events.py +0 -64
- voodoo_framework-2.9.0/tests/test_voodoo_store_execution.py +0 -104
- voodoo_framework-2.9.0/tests/test_voodoo_store_hitl_restart.py +0 -138
- voodoo_framework-2.9.0/tests/test_voodoo_store_queue.py +0 -290
- voodoo_framework-2.9.0/tests/test_voodoo_store_scheduler.py +0 -253
- voodoo_framework-2.9.0/tests/test_voodoo_system_components.py +0 -197
- voodoo_framework-2.9.0/tests/test_websocket.py +0 -62
- voodoo_framework-2.9.0/tests/test_worker_retry_semantics.py +0 -77
- voodoo_framework-2.9.0/tests/test_workers.py +0 -201
- voodoo_framework-2.9.0/tests/test_workspace.py +0 -249
- voodoo_framework-2.9.0/tests/test_world_aware_execution.py +0 -103
- voodoo_framework-2.9.0/tests/test_world_model.py +0 -134
- voodoo_framework-2.9.0/tests/test_world_sqlite.py +0 -121
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/LICENSE +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/README.md +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/pyproject.toml +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/setup.cfg +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/adapters/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/adapters/capabilities.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/adapters/registry.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/agents/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/agents/models.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/agents/registry.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ai/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ai/agent.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ai/providers/mock.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/auth/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/auth/cookies.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/auth/middleware.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/auth/passwords.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/auth/user.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/__main__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/agents.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/ai.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/auth.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/create.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/executions.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/generate.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/objects.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/protocol.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/routes.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/schedules.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/start.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/terminal.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/cli/version.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/components.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/config.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/core/errors.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/core/render.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/data/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/data/store_backend.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/data/store_model.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/edge/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/edge/auth.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/edge/errors.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/edge/models.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/edge/simulator.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/edge/store.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/edge/store_voodoo.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/edge/world.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/i18n.py +0 -0
- {voodoo_framework-2.9.0/src/voodoo → voodoo_framework-3.0.0/src/voodoo/integrations}/mcp/client.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/memory/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/memory/sqlite.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/mesh/event_bus.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/primitives/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/primitives/capability.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/primitives/compute.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/primitives/constraint.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/primitives/effect.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/primitives/intent.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/primitives/resource.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/primitives/state.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/primitives/time.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/protocol/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/protocol/export.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/protocol/fabric.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/protocol/operational.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/py.typed +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/routing/pages.py +0 -0
- {voodoo_framework-2.9.0/src/voodoo/runtime → voodoo_framework-3.0.0/src/voodoo/runtime/agency}/goal_store.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/runtime/capability.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/runtime/constraint.py +0 -0
- {voodoo_framework-2.9.0/src/voodoo/mesh → voodoo_framework-3.0.0/src/voodoo/runtime/distributed}/auth.py +0 -0
- {voodoo_framework-2.9.0/src/voodoo/runtime → voodoo_framework-3.0.0/src/voodoo/runtime/distributed}/membership.py +0 -0
- {voodoo_framework-2.9.0/src/voodoo/mesh → voodoo_framework-3.0.0/src/voodoo/runtime/distributed}/remote.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/runtime/errors.py +0 -0
- /voodoo_framework-2.9.0/src/voodoo/runtime/world_execution.py → /voodoo_framework-3.0.0/src/voodoo/runtime/execution/world.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/runtime/identity.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/runtime/identity_store.py +0 -0
- {voodoo_framework-2.9.0/src/voodoo/runtime → voodoo_framework-3.0.0/src/voodoo/runtime/inspection}/dashboard.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/runtime/operations.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/runtime/planner.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/runtime/policy.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/runtime/transaction.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/runtime/workflow_store.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/schedule.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/security/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/security/cors.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/security/csrf.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/security/passwords.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/security/rate_limit.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/security/redaction.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/static/client.js +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/cache/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/cache/interfaces.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/cache/memory.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/cache/redis.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/database/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/database/interfaces.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/database/postgres.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/database/sqlite.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/events/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/events/interfaces.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/execution/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/execution/migrations.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/execution/postgres.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/execution/sqlite.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/execution/store.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/manager.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/objects/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/objects/interfaces.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/objects/local.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/objects/store.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/queue/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/queue/interfaces.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/queue/memory.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/queue/postgres.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/queue/redis.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/queue/sqlite.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/queue/store.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/scheduler/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/scheduler/sqlite.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/storage/scheduler/store.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/brand.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/events.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/interactive.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/layout.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/markdown.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/primitives.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/product.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/rendering.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/styles/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/styles/extended.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/styles/product.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/styles/system.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/styles/theme.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/styles/theme_contract.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/styles/voodoo_system.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/ui/voodoo_system.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/world/__init__.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/world/model.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/world/models.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/world/sqlite.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo/world/store.py +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo_framework.egg-info/dependency_links.txt +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo_framework.egg-info/entry_points.txt +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo_framework.egg-info/requires.txt +0 -0
- {voodoo_framework-2.9.0 → voodoo_framework-3.0.0}/src/voodoo_framework.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: voodoo-framework
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0
|
|
4
4
|
Summary: The programmable runtime for adaptive applications and operational systems — web, APIs, agents, workers, human workflows, distributed systems, and physical systems in one runtime.
|
|
5
5
|
Author-email: Helder Perez <contact@helderperez.com>
|
|
6
6
|
Maintainer-email: Helder Perez <contact@helderperez.com>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Voodoo — programmable runtime for adaptive applications and operational systems.
|
|
2
|
+
|
|
3
|
+
The package root is intentionally small. It exposes only the common application
|
|
4
|
+
vocabulary. Catalogs and advanced primitives live in the namespace that owns
|
|
5
|
+
their semantics: voodoo.ui, voodoo.runtime, voodoo.world, voodoo.edge,
|
|
6
|
+
voodoo.protocol, voodoo.observability and voodoo.integrations.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from .ai.agent import Agent
|
|
10
|
+
from .ai.tools import tool
|
|
11
|
+
from .core import App, page, state
|
|
12
|
+
from .data import Model
|
|
13
|
+
from .runtime.scheduling.tasks import task
|
|
14
|
+
|
|
15
|
+
__version__ = "3.0.0"
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"Agent",
|
|
19
|
+
"App",
|
|
20
|
+
"Model",
|
|
21
|
+
"page",
|
|
22
|
+
"state",
|
|
23
|
+
"task",
|
|
24
|
+
"tool",
|
|
25
|
+
]
|
|
@@ -420,18 +420,17 @@ def _alert(props: dict[str, Any], theme: Theme) -> str:
|
|
|
420
420
|
if variant == "solid":
|
|
421
421
|
foreground = "text-black" if tone == "warning" else "text-white"
|
|
422
422
|
return f"{base} {foreground} bg-[{color}] border-[{color}]"
|
|
423
|
-
background =
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
f"
|
|
423
|
+
background = (
|
|
424
|
+
"bg-transparent"
|
|
425
|
+
if variant == "outline"
|
|
426
|
+
else f"bg-[color-mix(in_srgb,{color}_8%,transparent)]"
|
|
427
427
|
)
|
|
428
|
+
return f"{base} {background} border-[color-mix(in_srgb,{color}_28%,transparent)]"
|
|
428
429
|
|
|
429
430
|
|
|
430
431
|
def _progress(props: dict[str, Any], theme: Theme) -> str:
|
|
431
432
|
tone = props.get("tone", "primary")
|
|
432
|
-
size = {"sm": "h-1", "md": "h-2", "lg": "h-3"}.get(
|
|
433
|
-
props.get("size", "md"), "h-2"
|
|
434
|
-
)
|
|
433
|
+
size = {"sm": "h-1", "md": "h-2", "lg": "h-3"}.get(props.get("size", "md"), "h-2")
|
|
435
434
|
return (
|
|
436
435
|
f"block w-full {size} appearance-none overflow-hidden rounded-full "
|
|
437
436
|
"bg-[var(--vd-color-surface-raised)] "
|
|
@@ -481,7 +480,9 @@ def _breadcrumb_item(props: dict[str, Any], theme: Theme) -> str:
|
|
|
481
480
|
|
|
482
481
|
|
|
483
482
|
def _breadcrumb_link(props: dict[str, Any], theme: Theme) -> str:
|
|
484
|
-
return
|
|
483
|
+
return (
|
|
484
|
+
"text-inherit no-underline transition-colors hover:text-[var(--vd-color-text)]"
|
|
485
|
+
)
|
|
485
486
|
|
|
486
487
|
|
|
487
488
|
def _breadcrumb_current(props: dict[str, Any], theme: Theme) -> str:
|
|
@@ -518,15 +519,14 @@ def _accordion(props: dict[str, Any], theme: Theme) -> str:
|
|
|
518
519
|
"[&>details+details]:border-t"
|
|
519
520
|
)
|
|
520
521
|
if variant == "ghost":
|
|
521
|
-
return
|
|
522
|
-
"grid gap-2 [&>details]:border-transparent "
|
|
523
|
-
"[&>details]:bg-transparent"
|
|
524
|
-
)
|
|
522
|
+
return "grid gap-2 [&>details]:border-transparent [&>details]:bg-transparent"
|
|
525
523
|
return "grid gap-2"
|
|
526
524
|
|
|
527
525
|
|
|
528
526
|
def _accordion_item(props: dict[str, Any], theme: Theme) -> str:
|
|
529
|
-
return
|
|
527
|
+
return (
|
|
528
|
+
"rounded-lg border border-[var(--vd-color-border)] bg-[var(--vd-color-surface)]"
|
|
529
|
+
)
|
|
530
530
|
|
|
531
531
|
|
|
532
532
|
def _accordion_summary(props: dict[str, Any], theme: Theme) -> str:
|
|
@@ -793,12 +793,18 @@ _STYLES: dict[str, Callable[[dict[str, Any], Theme], str]] = {
|
|
|
793
793
|
"bg-[var(--vd-color-surface)] px-2 pb-[env(safe-area-inset-bottom)] md:hidden"
|
|
794
794
|
),
|
|
795
795
|
"bottom-nav-item": _bottom_nav_item,
|
|
796
|
-
"bottom-nav-item.icon": lambda props, theme:
|
|
796
|
+
"bottom-nav-item.icon": lambda props, theme: (
|
|
797
|
+
"inline-flex size-6 items-center justify-center"
|
|
798
|
+
),
|
|
797
799
|
"bottom-nav-item.label": lambda props, theme: "max-w-full truncate",
|
|
798
800
|
"sidebar-item": _sidebar_item,
|
|
799
|
-
"sidebar-item.icon": lambda props, theme:
|
|
801
|
+
"sidebar-item.icon": lambda props, theme: (
|
|
802
|
+
"inline-flex size-6 shrink-0 items-center justify-center"
|
|
803
|
+
),
|
|
800
804
|
"sidebar-item.label": lambda props, theme: "min-w-0 truncate",
|
|
801
|
-
"sidebar-item.badge": lambda props, theme:
|
|
805
|
+
"sidebar-item.badge": lambda props, theme: (
|
|
806
|
+
"ml-auto text-xs text-[var(--vd-color-text-muted)]"
|
|
807
|
+
),
|
|
802
808
|
"sidebar-header": lambda props, theme: (
|
|
803
809
|
"flex min-h-10 shrink-0 items-center justify-between gap-2 "
|
|
804
810
|
"[aside[data-vd-sidebar-mode=rail]_&]:flex-col "
|
|
@@ -836,14 +842,20 @@ _STYLES: dict[str, Callable[[dict[str, Any], Theme], str]] = {
|
|
|
836
842
|
"border-b border-[var(--vd-color-border)] p-4"
|
|
837
843
|
),
|
|
838
844
|
"drawer.title": lambda props, theme: "text-lg font-semibold",
|
|
839
|
-
"drawer.description": lambda props, theme:
|
|
845
|
+
"drawer.description": lambda props, theme: (
|
|
846
|
+
"text-sm text-[var(--vd-color-text-muted)]"
|
|
847
|
+
),
|
|
840
848
|
"drawer.body": lambda props, theme: "min-h-0 flex-1 overflow-y-auto p-4",
|
|
841
849
|
"dropdown-shell": lambda props, theme: "contents",
|
|
842
850
|
"dropdown-menu": _dropdown_menu,
|
|
843
851
|
"menu-item": _menu_item,
|
|
844
852
|
"menu-item.label": lambda props, theme: "min-w-0 flex-1",
|
|
845
|
-
"menu-shortcut": lambda props, theme:
|
|
846
|
-
|
|
853
|
+
"menu-shortcut": lambda props, theme: (
|
|
854
|
+
"ml-auto text-xs text-[var(--vd-color-text-muted)]"
|
|
855
|
+
),
|
|
856
|
+
"menu-separator": lambda props, theme: (
|
|
857
|
+
"my-1 h-px border-0 bg-[var(--vd-color-border)]"
|
|
858
|
+
),
|
|
847
859
|
"tabs": _tabs,
|
|
848
860
|
"tabs.list": lambda props, theme: (
|
|
849
861
|
"flex items-center gap-1 border-b border-[var(--vd-color-border)]"
|
|
@@ -141,9 +141,7 @@ class VoodooCSSAdapter:
|
|
|
141
141
|
if component == "sidebar":
|
|
142
142
|
classes.append(f"vd-sidebar--{props.get('mode', 'expanded')}")
|
|
143
143
|
if component == "sidebar-toggle":
|
|
144
|
-
classes.append(
|
|
145
|
-
f"vd-sidebar-toggle--{props.get('placement', 'standalone')}"
|
|
146
|
-
)
|
|
144
|
+
classes.append(f"vd-sidebar-toggle--{props.get('placement', 'standalone')}")
|
|
147
145
|
if component == "sidebar-item" and props.get("active"):
|
|
148
146
|
classes.append("vd-sidebar-item--active")
|
|
149
147
|
if component == "bottom-nav-item" and props.get("active"):
|
|
@@ -6,7 +6,7 @@ The Agent turns a prompt into a final answer by iterating:
|
|
|
6
6
|
|
|
7
7
|
The Agent is a *participant* in the runtime, not a parallel execution
|
|
8
8
|
framework. ``run()`` creates an :class:`~voodoo.runtime.execution.Execution`
|
|
9
|
-
via the :class:`~voodoo.runtime.engine.ExecutionEngine` so that agent
|
|
9
|
+
via the :class:`~voodoo.runtime.execution.engine.ExecutionEngine` so that agent
|
|
10
10
|
runs share the same lifecycle, persistence, recovery, authorization and
|
|
11
11
|
observability as every other execution path (HTTP, Worker, Task, MCP, …).
|
|
12
12
|
|
|
@@ -33,7 +33,7 @@ from enum import StrEnum
|
|
|
33
33
|
from typing import Any
|
|
34
34
|
|
|
35
35
|
from voodoo.ai.providers import LLMProvider, Message, default_model, get_provider
|
|
36
|
-
from voodoo.tools.registry import ToolRegistry, default_registry
|
|
36
|
+
from voodoo.ai.tools.registry import ToolRegistry, default_registry
|
|
37
37
|
|
|
38
38
|
__all__ = ["Agent", "AgentRun", "AgentEvent"]
|
|
39
39
|
|
|
@@ -312,7 +312,7 @@ class Agent:
|
|
|
312
312
|
)
|
|
313
313
|
try:
|
|
314
314
|
self.memory.write(entry)
|
|
315
|
-
except Exception:
|
|
315
|
+
except Exception:
|
|
316
316
|
pass
|
|
317
317
|
|
|
318
318
|
# -- helpers -----------------------------------------------------------
|
|
@@ -361,7 +361,7 @@ class Agent:
|
|
|
361
361
|
Flow: Agent → Intent → capability check → Tool → Effect → Mesh.
|
|
362
362
|
|
|
363
363
|
When running inside an
|
|
364
|
-
:class:`~voodoo.runtime.engine.ExecutionEngine` Execution, each
|
|
364
|
+
:class:`~voodoo.runtime.execution.engine.ExecutionEngine` Execution, each
|
|
365
365
|
tool call creates a *child* Execution so the full agent activity
|
|
366
366
|
is visible in the execution graph:
|
|
367
367
|
|
|
@@ -422,7 +422,7 @@ class Agent:
|
|
|
422
422
|
await self._broadcast("tool.called", {"tool": name, "arguments": arguments})
|
|
423
423
|
try:
|
|
424
424
|
result = await self.registry.call(name, **arguments)
|
|
425
|
-
except Exception as e:
|
|
425
|
+
except Exception as e:
|
|
426
426
|
effect.mark_failed(str(e))
|
|
427
427
|
if ctx is not None:
|
|
428
428
|
ctx.add_effect(effect)
|
|
@@ -470,7 +470,7 @@ class Agent:
|
|
|
470
470
|
{"tool": name, "status": "succeeded"},
|
|
471
471
|
)
|
|
472
472
|
return result
|
|
473
|
-
except Exception as e:
|
|
473
|
+
except Exception as e:
|
|
474
474
|
await self._broadcast(
|
|
475
475
|
"tool.completed",
|
|
476
476
|
{"tool": name, "status": "failed", "error": str(e)},
|
|
@@ -496,7 +496,7 @@ class Agent:
|
|
|
496
496
|
) -> AgentRun:
|
|
497
497
|
"""Execute prompt → provider → tool calls → final; return AgentRun.
|
|
498
498
|
|
|
499
|
-
When an :class:`~voodoo.runtime.engine.ExecutionEngine` is
|
|
499
|
+
When an :class:`~voodoo.runtime.execution.engine.ExecutionEngine` is
|
|
500
500
|
available (either passed at construction or attached to the
|
|
501
501
|
active :class:`~voodoo.runtime.context.ExecutionContext`), the
|
|
502
502
|
run creates a first-class
|
|
@@ -537,7 +537,7 @@ class Agent:
|
|
|
537
537
|
observability. The agent's provider loop is the *compute*
|
|
538
538
|
participant — it receives an
|
|
539
539
|
:class:`~voodoo.runtime.context.ExecutionContext` and returns a
|
|
540
|
-
:class:`~voodoo.runtime.engine.ComputeResult`.
|
|
540
|
+
:class:`~voodoo.runtime.execution.engine.ComputeResult`.
|
|
541
541
|
"""
|
|
542
542
|
from voodoo.primitives.intent import Intent
|
|
543
543
|
from voodoo.runtime.context import ExecutionContext
|
|
@@ -613,7 +613,7 @@ class Agent:
|
|
|
613
613
|
When ``run_id`` is ``None``, a new UUID is generated. When
|
|
614
614
|
called inside an engine Execution, ``run_id`` is the execution id.
|
|
615
615
|
"""
|
|
616
|
-
from voodoo.
|
|
616
|
+
from voodoo.observability import telemetry_store
|
|
617
617
|
|
|
618
618
|
run_id = run_id or str(uuid.uuid4())
|
|
619
619
|
trace_id = (
|
|
@@ -652,7 +652,7 @@ class Agent:
|
|
|
652
652
|
try:
|
|
653
653
|
desc = self.provider.describe()
|
|
654
654
|
tools_arg = self._tools_for_provider() if desc.tool_use else None
|
|
655
|
-
except Exception:
|
|
655
|
+
except Exception:
|
|
656
656
|
tools_arg = self._tools_for_provider()
|
|
657
657
|
response = await self.provider.complete(messages, tools=tools_arg)
|
|
658
658
|
await self._broadcast(
|
|
@@ -724,7 +724,7 @@ class Agent:
|
|
|
724
724
|
output = response.content
|
|
725
725
|
break
|
|
726
726
|
|
|
727
|
-
except Exception as e:
|
|
727
|
+
except Exception as e:
|
|
728
728
|
self.state = AgentState.error
|
|
729
729
|
error = str(e)
|
|
730
730
|
await self._broadcast("agent.failed", {"run_id": run_id, "error": error})
|
|
@@ -771,7 +771,18 @@ class Agent:
|
|
|
771
771
|
|
|
772
772
|
# -- stream ------------------------------------------------------------
|
|
773
773
|
|
|
774
|
-
async def
|
|
774
|
+
async def _stream_provider_events(
|
|
775
|
+
self, messages: list[Message]
|
|
776
|
+
) -> AsyncIterator[tuple[str, Any]]:
|
|
777
|
+
try:
|
|
778
|
+
description = self.provider.describe()
|
|
779
|
+
tools = self._tools_for_provider() if description.tool_use else None
|
|
780
|
+
except Exception:
|
|
781
|
+
tools = self._tools_for_provider()
|
|
782
|
+
async for event in self.provider.stream(messages, tools=tools):
|
|
783
|
+
yield event.type, event.data
|
|
784
|
+
|
|
785
|
+
async def stream(
|
|
775
786
|
self,
|
|
776
787
|
prompt: str,
|
|
777
788
|
context: dict | None = None,
|
|
@@ -779,7 +790,7 @@ class Agent:
|
|
|
779
790
|
) -> AsyncIterator[AgentEvent]:
|
|
780
791
|
"""Yield normalized events: text, tool_started, tool_finished, thinking, error, completed."""
|
|
781
792
|
run_id = str(uuid.uuid4())
|
|
782
|
-
from voodoo.
|
|
793
|
+
from voodoo.observability import telemetry_store
|
|
783
794
|
|
|
784
795
|
trace_id = (
|
|
785
796
|
telemetry_store.trace_id_var.get()
|
|
@@ -813,27 +824,24 @@ class Agent:
|
|
|
813
824
|
"model": self.model,
|
|
814
825
|
},
|
|
815
826
|
)
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
accumulated_text += event.data.get("text", "")
|
|
824
|
-
yield AgentEvent(type="text", data=event.data)
|
|
825
|
-
elif event.type == "tool_call":
|
|
827
|
+
async for event_type, event_data in self._stream_provider_events(
|
|
828
|
+
messages
|
|
829
|
+
):
|
|
830
|
+
if event_type == "text":
|
|
831
|
+
accumulated_text += event_data.get("text", "")
|
|
832
|
+
yield AgentEvent(type="text", data=event_data)
|
|
833
|
+
elif event_type == "tool_call":
|
|
826
834
|
structured_tool_request = {
|
|
827
|
-
"name":
|
|
828
|
-
"arguments":
|
|
829
|
-
"id":
|
|
835
|
+
"name": event_data.get("name", ""),
|
|
836
|
+
"arguments": event_data.get("arguments", {}),
|
|
837
|
+
"id": event_data.get("id"),
|
|
830
838
|
}
|
|
831
|
-
elif
|
|
832
|
-
tokens_in +=
|
|
833
|
-
tokens_out +=
|
|
834
|
-
cost +=
|
|
835
|
-
elif
|
|
836
|
-
raise Exception(
|
|
839
|
+
elif event_type == "done":
|
|
840
|
+
tokens_in += event_data.get("tokens_in", 0)
|
|
841
|
+
tokens_out += event_data.get("tokens_out", 0)
|
|
842
|
+
cost += event_data.get("cost", 0.0)
|
|
843
|
+
elif event_type == "error":
|
|
844
|
+
raise Exception(event_data.get("error", "Provider error"))
|
|
837
845
|
await self._broadcast(
|
|
838
846
|
"model.completed",
|
|
839
847
|
{
|
|
@@ -918,7 +926,7 @@ class Agent:
|
|
|
918
926
|
output = accumulated_text
|
|
919
927
|
break
|
|
920
928
|
|
|
921
|
-
except Exception as e:
|
|
929
|
+
except Exception as e:
|
|
922
930
|
self.state = AgentState.error
|
|
923
931
|
error = str(e)
|
|
924
932
|
yield AgentEvent(type="error", data={"error": error})
|
|
@@ -1083,5 +1091,5 @@ class Agent:
|
|
|
1083
1091
|
from voodoo.mesh import mesh
|
|
1084
1092
|
|
|
1085
1093
|
await mesh.broadcast(event, payload)
|
|
1086
|
-
except Exception:
|
|
1094
|
+
except Exception:
|
|
1087
1095
|
pass
|
|
@@ -23,7 +23,7 @@ class RuntimeTruthAgent(LegacyAgent):
|
|
|
23
23
|
from voodoo.runtime.context import current_context
|
|
24
24
|
|
|
25
25
|
return current_context()
|
|
26
|
-
except Exception:
|
|
26
|
+
except Exception:
|
|
27
27
|
return None
|
|
28
28
|
|
|
29
29
|
def _canonical_execution_id(self, run_record: AgentRun) -> str | None:
|
|
@@ -113,7 +113,7 @@ class RuntimeTruthAgent(LegacyAgent):
|
|
|
113
113
|
)
|
|
114
114
|
try:
|
|
115
115
|
self.memory.write(entry)
|
|
116
|
-
except Exception:
|
|
116
|
+
except Exception:
|
|
117
117
|
pass
|
|
118
118
|
|
|
119
119
|
async def _execute_tool_as_child_execution(
|
|
@@ -188,7 +188,7 @@ class LLMProvider(ABC):
|
|
|
188
188
|
"""Yield normalized streaming events."""
|
|
189
189
|
raise NotImplementedError
|
|
190
190
|
# pragma: no cover - abstract generator marker
|
|
191
|
-
yield # type: ignore[unreachable]
|
|
191
|
+
yield # type: ignore[unreachable]
|
|
192
192
|
|
|
193
193
|
async def generate(
|
|
194
194
|
self, messages: list[Message], **kwargs: Any
|
|
@@ -230,10 +230,10 @@ class LLMProvider(ABC):
|
|
|
230
230
|
|
|
231
231
|
#: Maps provider name → fully-qualified provider class path (lazy import).
|
|
232
232
|
_PROVIDER_CLASSES: dict[str, str] = {
|
|
233
|
-
"openai": "voodoo.ai.
|
|
234
|
-
"anthropic": "voodoo.ai.
|
|
235
|
-
"gemini": "voodoo.ai.
|
|
236
|
-
"ollama": "voodoo.ai.
|
|
233
|
+
"openai": "voodoo.integrations.ai.openai.OpenAIProvider",
|
|
234
|
+
"anthropic": "voodoo.integrations.ai.anthropic.AnthropicProvider",
|
|
235
|
+
"gemini": "voodoo.integrations.ai.gemini.GeminiProvider",
|
|
236
|
+
"ollama": "voodoo.integrations.ai.ollama.OllamaProvider",
|
|
237
237
|
"mock": "voodoo.ai.providers.mock.MockProvider",
|
|
238
238
|
}
|
|
239
239
|
|
|
@@ -270,7 +270,7 @@ def _routing_aliases(aliases: dict[str, str] | None) -> dict[str, str]:
|
|
|
270
270
|
|
|
271
271
|
merged.update(config.models.aliases or {})
|
|
272
272
|
merged.update(config.ai.aliases or {})
|
|
273
|
-
except Exception:
|
|
273
|
+
except Exception:
|
|
274
274
|
pass
|
|
275
275
|
if aliases:
|
|
276
276
|
merged.update(aliases)
|
|
@@ -329,7 +329,7 @@ def default_model() -> str:
|
|
|
329
329
|
provider = config.ai.provider or "openai"
|
|
330
330
|
return f"{provider}:{config.ai.model}"
|
|
331
331
|
return config.models.default
|
|
332
|
-
except Exception:
|
|
332
|
+
except Exception:
|
|
333
333
|
return "mock:default"
|
|
334
334
|
|
|
335
335
|
|
|
@@ -357,7 +357,7 @@ def get_provider(model: str, **kwargs: Any) -> LLMProvider:
|
|
|
357
357
|
kwargs.setdefault("base_url", config.ai.base_url)
|
|
358
358
|
if config.ai.api_key:
|
|
359
359
|
kwargs.setdefault("api_key", config.ai.api_key)
|
|
360
|
-
except Exception:
|
|
360
|
+
except Exception:
|
|
361
361
|
pass
|
|
362
362
|
|
|
363
363
|
return provider_cls(model=model_id, **kwargs)
|
|
@@ -15,7 +15,7 @@ Usage::
|
|
|
15
15
|
|
|
16
16
|
The decorated function remains callable as plain Python while carrying a
|
|
17
17
|
``__tool_spec__`` attribute (a :class:`ToolSpec`) and being registered in the
|
|
18
|
-
default registry (``voodoo.tools.registry.default_registry``).
|
|
18
|
+
default registry (``voodoo.ai.tools.registry.default_registry``).
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
21
|
from __future__ import annotations
|
|
@@ -29,7 +29,7 @@ __all__ = ["tool", "ToolSpec", "ToolRegistry", "default_registry"]
|
|
|
29
29
|
|
|
30
30
|
# Re-export the default registry instance (lives in the registry module so it
|
|
31
31
|
# can be monkeypatched in tests without being shadowed by this package).
|
|
32
|
-
from voodoo.ai.tools.registry import default_registry
|
|
32
|
+
from voodoo.ai.tools.registry import default_registry
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
def _resolve_default_registry() -> ToolRegistry:
|
|
@@ -54,7 +54,7 @@ def tool(
|
|
|
54
54
|
) -> Callable[[Callable[..., Any]], Callable[..., Any]]: ...
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
def tool(
|
|
57
|
+
def tool(
|
|
58
58
|
func: Callable[..., Any] | None = None,
|
|
59
59
|
*,
|
|
60
60
|
name: str | None = None,
|
|
@@ -76,7 +76,7 @@ def _build_schemas(func: Callable[..., Any]) -> tuple[dict[str, Any], dict[str,
|
|
|
76
76
|
"""Derive input/output JSON schemas from a function's type hints."""
|
|
77
77
|
try:
|
|
78
78
|
hints = get_type_hints(func)
|
|
79
|
-
except Exception:
|
|
79
|
+
except Exception:
|
|
80
80
|
hints = getattr(func, "__annotations__", {}) or {}
|
|
81
81
|
|
|
82
82
|
sig = inspect.signature(func)
|
|
@@ -108,7 +108,7 @@ def _source_metadata(func: Callable[..., Any]) -> str:
|
|
|
108
108
|
try:
|
|
109
109
|
file = inspect.getsourcefile(inspect.unwrap(func)) or "<unknown>"
|
|
110
110
|
line = inspect.getsourcelines(inspect.unwrap(func))[1]
|
|
111
|
-
except (OSError, TypeError):
|
|
111
|
+
except (OSError, TypeError):
|
|
112
112
|
line = 0
|
|
113
113
|
file = "<unknown>"
|
|
114
114
|
return f"{module}:{file}:{line}"
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
from collections.abc import Callable
|
|
3
|
+
from functools import wraps
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from starlette.requests import Request
|
|
7
|
+
from starlette.responses import JSONResponse, RedirectResponse
|
|
8
|
+
|
|
9
|
+
from voodoo.auth.user import get_current_user
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _request(args: tuple[Any, ...], kwargs: dict[str, Any]) -> Request | None:
|
|
13
|
+
req = kwargs.get("request")
|
|
14
|
+
if isinstance(req, Request):
|
|
15
|
+
return req
|
|
16
|
+
if args and isinstance(args[0], Request):
|
|
17
|
+
return args[0]
|
|
18
|
+
return None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _unauthenticated(req: Request | None, redirect_url: str | None = None) -> Any:
|
|
22
|
+
if req and redirect_url and "text/html" in req.headers.get("accept", ""):
|
|
23
|
+
return RedirectResponse(url=redirect_url, status_code=302)
|
|
24
|
+
return JSONResponse(
|
|
25
|
+
{"error": "Authentication required", "code": 401}, status_code=401
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _inject_user(sig: inspect.Signature, kwargs: dict[str, Any], user: Any) -> None:
|
|
30
|
+
if "user" in sig.parameters and "user" not in kwargs:
|
|
31
|
+
kwargs["user"] = user
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _guard(
|
|
35
|
+
check: Callable[[Any], Any | None],
|
|
36
|
+
redirect_url: str | None = None,
|
|
37
|
+
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
38
|
+
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
39
|
+
sig = inspect.signature(func)
|
|
40
|
+
|
|
41
|
+
def authorize(
|
|
42
|
+
args: tuple[Any, ...], kwargs: dict[str, Any]
|
|
43
|
+
) -> tuple[Any, Any | None]:
|
|
44
|
+
req = _request(args, kwargs)
|
|
45
|
+
user = get_current_user(req)
|
|
46
|
+
if not user or not user.is_authenticated:
|
|
47
|
+
return None, _unauthenticated(req, redirect_url)
|
|
48
|
+
denied = check(user)
|
|
49
|
+
if denied is not None:
|
|
50
|
+
return None, denied
|
|
51
|
+
_inject_user(sig, kwargs, user)
|
|
52
|
+
return user, None
|
|
53
|
+
|
|
54
|
+
@wraps(func)
|
|
55
|
+
async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
56
|
+
_, denied = authorize(args, kwargs)
|
|
57
|
+
if denied is not None:
|
|
58
|
+
return denied
|
|
59
|
+
return await func(*args, **kwargs)
|
|
60
|
+
|
|
61
|
+
@wraps(func)
|
|
62
|
+
def sync_wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
63
|
+
_, denied = authorize(args, kwargs)
|
|
64
|
+
if denied is not None:
|
|
65
|
+
return denied
|
|
66
|
+
return func(*args, **kwargs)
|
|
67
|
+
|
|
68
|
+
return async_wrapper if inspect.iscoroutinefunction(func) else sync_wrapper
|
|
69
|
+
|
|
70
|
+
return decorator
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def require_auth(
|
|
74
|
+
redirect_url: str | None = None,
|
|
75
|
+
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
76
|
+
"""Require an authenticated user."""
|
|
77
|
+
return _guard(lambda _user: None, redirect_url)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def require_roles(
|
|
81
|
+
*roles: str, redirect_url: str | None = None
|
|
82
|
+
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
83
|
+
"""Require the user to hold one of the specified roles."""
|
|
84
|
+
|
|
85
|
+
def check(user: Any) -> Any | None:
|
|
86
|
+
if user.has_role(*roles):
|
|
87
|
+
return None
|
|
88
|
+
return JSONResponse(
|
|
89
|
+
{
|
|
90
|
+
"error": "Forbidden: Insufficient role permissions",
|
|
91
|
+
"code": 403,
|
|
92
|
+
"required_roles": list(roles),
|
|
93
|
+
},
|
|
94
|
+
status_code=403,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
return _guard(check, redirect_url)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def require_scopes(*scopes: str) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
101
|
+
"""Require specific API key scopes or permissions."""
|
|
102
|
+
|
|
103
|
+
def check(user: Any) -> Any | None:
|
|
104
|
+
if user.has_scope(*scopes):
|
|
105
|
+
return None
|
|
106
|
+
return JSONResponse(
|
|
107
|
+
{
|
|
108
|
+
"error": "Forbidden: Missing required scope",
|
|
109
|
+
"code": 403,
|
|
110
|
+
"required_scopes": list(scopes),
|
|
111
|
+
},
|
|
112
|
+
status_code=403,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
return _guard(check)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def require_api_key(
|
|
119
|
+
scopes: list[str] | None = None,
|
|
120
|
+
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
121
|
+
"""Enforce machine-to-machine API key authentication."""
|
|
122
|
+
|
|
123
|
+
def check(user: Any) -> Any | None:
|
|
124
|
+
if user.auth_type != "api_key":
|
|
125
|
+
return JSONResponse(
|
|
126
|
+
{"error": "Valid API Key required", "code": 401}, status_code=401
|
|
127
|
+
)
|
|
128
|
+
if scopes and not user.has_scope(*scopes):
|
|
129
|
+
return JSONResponse(
|
|
130
|
+
{"error": "Forbidden: Insufficient API key permissions", "code": 403},
|
|
131
|
+
status_code=403,
|
|
132
|
+
)
|
|
133
|
+
return None
|
|
134
|
+
|
|
135
|
+
return _guard(check)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
login_required = require_auth
|
|
139
|
+
requires_role = require_roles
|
|
140
|
+
requires_roles = require_roles
|
|
141
|
+
requires_permission = require_scopes
|
|
142
|
+
requires_permissions = require_scopes
|
|
143
|
+
requires_scopes = require_scopes
|
|
144
|
+
requires_api_key = require_api_key
|