tactus 0.31.2__tar.gz → 0.32.1__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.
- {tactus-0.31.2 → tactus-0.32.1}/.gitignore +3 -0
- tactus-0.32.1/.tactus/config.yml.example +12 -0
- {tactus-0.31.2 → tactus-0.32.1}/CHANGELOG.md +21 -0
- {tactus-0.31.2 → tactus-0.32.1}/PKG-INFO +3 -1
- tactus-0.32.1/examples/.tactus/config.yml.example +12 -0
- {tactus-0.31.2 → tactus-0.32.1}/pyproject.toml +4 -1
- {tactus-0.31.2 → tactus-0.32.1}/tactus/__init__.py +1 -1
- {tactus-0.31.2 → tactus-0.32.1}/tactus/dspy/agent.py +21 -0
- tactus-0.32.1/tactus/ide/config_server.py +536 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/ide/server.py +45 -12
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/backend/tactus_backend.spec +2 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/package.json +2 -3
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/preload/preload.ts +6 -1
- tactus-0.31.2/tactus-desktop/scripts/build-backend.js → tactus-0.32.1/tactus-desktop/scripts/build-backend.mjs +22 -8
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/src/main.ts +28 -4
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/src/menu.ts +15 -1
- tactus-0.32.1/tactus-desktop/src/preferences-window.ts +47 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/backend/config_server.py +18 -1
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/App.tsx +100 -5
- tactus-0.32.1/tactus-ide/frontend/src/components/AuthErrorDialog.tsx +69 -0
- tactus-0.31.2/.tactus/config.yml.example +0 -41
- {tactus-0.31.2 → tactus-0.32.1}/.claude/agents.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/.github/workflows/release.yml +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/AGENTS.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/IMPLEMENTATION.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/LICENSE +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/Makefile +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/README.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/SPECIFICATION.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/TECHNICAL_DEBT.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/behave.ini +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/docs/AGENTS.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/docs/BDD_TESTING.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/docs/CONFIGURATION.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/docs/DURABILITY.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/docs/FILE_IO.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/docs/SANDBOXING.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/docs/STREAMING.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/docs/TOOLS.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/docs/TOOL_ROADMAP.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/docs/development-mode.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/.tactus/config.yml +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/01-basics-hello-world.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/02-basics-simple-logic.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/03-basics-parameters.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/04-basics-simple-agent.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/05-basics-multi-model.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/06-basics-streaming.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/07-basics-bedrock.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/08-basics-models.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/09-basics-google-gemini.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/10-feature-state.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/11-feature-message-history.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/12-feature-structured-output.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/13-feature-session.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/14-feature-per-turn-tools-simple.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/14-feature-per-turn-tools.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/15-feature-local-tools.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/16-feature-toolsets-advanced.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/17-feature-toolsets-dsl.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/18-feature-lua-tools-individual.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/18-feature-lua-tools-inline.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/18-feature-lua-tools-toolset.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/19-feature-direct-tool-calls.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/20-bdd-complete.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/21-bdd-passing.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/22-bdd-fuzzy-matching.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/30-eval-simple.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/31-eval-demo.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/32-eval-success-rate.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/33-eval-thresholds.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/34-eval-dataset.jsonl +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/34-eval-dataset.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/35-eval-trace.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/36-eval-advanced.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/37-eval-comprehensive.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/39-model-simple.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/40-mcp-test.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/40-model-text-classifier.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/41-mcp-simple.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/41-model-pytorch.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/43-sub-procedure-simple.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/44-sub-procedure-composition.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/45-sub-procedure-recursive.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/46-checkpoint-explicit.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/47-checkpoint-expensive-ops.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/48-script-mode-simple.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/50-inputs-showcase.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/51-inputs-calculator.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/52-file-io-basics.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/53-tsv-file-io.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/54-json-file-io.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/55-parquet-file-io.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/56-hdf5-file-io.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/57-excel-file-io.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/58-text-file-io.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/60-tool-sources.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/61-inline-toolset-lua.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/62-mcp-toolset-by-server.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/63-toolset-import-from-file.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/64-require-modules.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/65-optional-state-demo.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/66-host-tools-via-broker.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/67-host-tool-source.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/70-mocking-static.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/71-mocking-temporal.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/72-mocking-conditional.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/99-misc-test-loading.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/README.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/app_config.ini +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/data/sample.csv +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/demo_output.json +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/helpers/math_module.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/helpers/product.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/helpers/string_module.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/helpers/sum.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/helpers/text_tools.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/inventory_summary.tsv +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/mock-config.json +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/models/README.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/models/create_sentiment_model.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/output_summary.txt +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/test-raw-module.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/test-raw-streaming.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/tools/calculations.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/tools/data_analysis.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/tools/search.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/with_dependencies/README.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/with_dependencies/simple_http_test.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/examples/with_dependencies/time_lookup.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/01_state_management.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/02_checkpointing.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/03_human_in_the_loop.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/04_control_flow.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/05_tool_integration.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/06_retry_logic.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/07_file_operations.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/08_agent_primitives.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/09_workflow_execution.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/10_lua_integration.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/11_storage_backends.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/12_json_operations.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/13_logging.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/15_procedure_calls.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/16_session_management.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/17_lua_dsl_validation.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/18_example_procedures.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/19_ide_server.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/20_parameters.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/21_outputs.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/23_prompts.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/24_bdd_specifications.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/25_bdd_custom_steps.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/26_bdd_evaluation.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/27_default_settings.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/28_custom_prompts.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/29_execution_settings.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/30_session_filters.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/31_matchers.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/32_result_object.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/33_output_type.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/42_model_primitive.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/43_sub_procedure_checkpointing.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/46_explicit_checkpoint.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/48_script_mode.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/51_dspy_lm_config.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/52_dspy_signature.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/53_dspy_module.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/54_dspy_history.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/55_dspy_prediction.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/56_dspy_agent.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/57_chat_assistant.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/60_formatting.feature +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/documentation/IDE_SERVER_BEHAVIOR.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/documentation/Lua DSL/README.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/environment.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/agent_primitives_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/chat_assistant_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/checkpointing_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/control_flow_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/dspy_agent_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/dspy_history_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/dspy_lm_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/dspy_module_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/dspy_prediction_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/dspy_signature_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/example_procedures_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/file_operations_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/formatting_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/human_in_the_loop_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/ide_server_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/json_operations_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/logging_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/lua_dsl_validation_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/lua_integration_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/mocking_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/procedure_calls_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/result_and_output_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/retry_logic_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/session_management_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/state_management_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/storage_backend_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/support/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/support/harnesses.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/tool_integration_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/features/steps/workflow_execution_steps.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/planning/BROKER_AND_TOOL_RUNNERS.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/planning/FORMATTER.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/scripts/audit_examples_mocking.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/scripts/convert_examples.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/scripts/run_precommit_suite.sh +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/scripts/timeout.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/start-web-ide.sh +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/adapters/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/adapters/broker_log.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/adapters/cli_hitl.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/adapters/cli_log.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/adapters/cost_collector_log.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/adapters/file_storage.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/adapters/http_callback_log.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/adapters/ide_log.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/adapters/lua_tools.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/adapters/mcp.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/adapters/mcp_manager.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/adapters/memory.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/adapters/plugins.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/backends/http_backend.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/backends/model_backend.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/backends/pytorch_backend.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/broker/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/broker/client.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/broker/protocol.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/broker/server.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/broker/stdio.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/cli/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/cli/app.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/cli/commands/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/core/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/core/config_manager.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/core/dependencies/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/core/dependencies/registry.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/core/dsl_stubs.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/core/exceptions.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/core/execution_context.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/core/lua_sandbox.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/core/message_history_manager.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/core/mocking.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/core/output_validator.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/core/registry.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/core/runtime.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/core/template_resolver.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/core/yaml_parser.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/docker/Dockerfile +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/docker/entrypoint.sh +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/dspy/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/dspy/broker_lm.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/dspy/config.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/dspy/history.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/dspy/module.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/dspy/prediction.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/dspy/signature.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/formatting/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/formatting/formatter.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/ide/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/ide/coding_assistant.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/primitives/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/primitives/control.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/primitives/file.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/primitives/handles.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/primitives/host.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/primitives/human.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/primitives/json.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/primitives/log.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/primitives/message_history.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/primitives/model.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/primitives/procedure.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/primitives/procedure_callable.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/primitives/retry.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/primitives/session.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/primitives/state.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/primitives/step.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/primitives/system.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/primitives/tool.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/primitives/tool_handle.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/primitives/toolset.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/protocols/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/protocols/chat_recorder.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/protocols/config.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/protocols/cost.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/protocols/hitl.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/protocols/log_handler.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/protocols/models.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/protocols/result.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/protocols/storage.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/providers/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/providers/base.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/providers/bedrock.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/providers/google.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/providers/openai.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/sandbox/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/sandbox/config.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/sandbox/container_runner.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/sandbox/docker_manager.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/sandbox/entrypoint.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/sandbox/protocol.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/stdlib/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/stdlib/io/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/stdlib/io/csv.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/stdlib/io/excel.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/stdlib/io/file.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/stdlib/io/fs.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/stdlib/io/hdf5.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/stdlib/io/json.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/stdlib/io/parquet.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/stdlib/io/tsv.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/stdlib/loader.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/stdlib/tac/tactus/tools/done.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/stdlib/tac/tactus/tools/log.tac +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/README.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/behave_integration.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/context.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/eval_models.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/evaluation_runner.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/evaluators.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/events.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/gherkin_parser.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/mock_agent.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/mock_dependencies.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/mock_hitl.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/mock_registry.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/mock_tools.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/models.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/pydantic_eval_runner.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/steps/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/steps/builtin.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/steps/custom.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/steps/registry.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/testing/test_runner.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/tracing/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/tracing/trace_manager.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/utils/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/utils/cost_calculator.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/utils/model_pricing.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/utils/safe_file_library.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/utils/safe_libraries.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/validation/LuaLexerBase.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/validation/LuaParserBase.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/validation/README.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/validation/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/validation/error_listener.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/validation/generated/LuaLexer.interp +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/validation/generated/LuaLexer.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/validation/generated/LuaLexer.tokens +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/validation/generated/LuaLexerBase.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/validation/generated/LuaParser.interp +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/validation/generated/LuaParser.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/validation/generated/LuaParser.tokens +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/validation/generated/LuaParserBase.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/validation/generated/LuaParserVisitor.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/validation/generated/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/validation/grammar/LuaLexer.g4 +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/validation/grammar/LuaParser.g4 +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/validation/semantic_visitor.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus/validation/validator.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/.gitignore +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/BUILD_GUIDE.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/ELECTRON_INTEGRATION.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/README.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/RUN_ELECTRON.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/SETUP_COMPLETE.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/backend/hook-lupa.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/package-lock.json +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/preload/tsconfig.json +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/rebuild-and-test.sh +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/resources/app-icon.icns +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/resources/app-icon.ico +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/resources/app-icon.png +0 -0
- /tactus-0.31.2/tactus-desktop/scripts/build-frontend.js → /tactus-0.32.1/tactus-desktop/scripts/build-frontend.mjs +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/scripts/generate-icons.sh +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/src/backend-manager.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-desktop/tsconfig.json +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/ARCHITECTURE.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/CHANGELOG.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/DEV_MODE.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/QUICK_START.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/README.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/RESTART_INSTRUCTIONS.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/TROUBLESHOOTING.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/backend/README.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/backend/assistant_service.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/backend/assistant_tools.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/backend/chat_server.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/backend/events.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/backend/logging_capture.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/backend/lsp_server.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/backend/requirements.txt +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/backend/tactus_lsp_handler.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/backend/test_lsp_server.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/backend/text_editor_tool.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/dev.sh +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/.storybook/main.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/.storybook/preview.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/.storybook/vitest.setup.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/README.md +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/demo.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/index.html +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/jest.config.js +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/package-lock.json +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/package.json +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/postcss.config.js +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/Editor.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/LSPClient.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/LSPClientHTTP.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/TactusLanguage.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/commands/registry.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/AboutDialog.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ChatSidebar.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/CheckpointSummary.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/CollapsibleRun.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/Duration.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/Duration.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/FileTree.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/FileTree.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/MessageFeed.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/PreferencesView.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ProcedureInputsDisplay.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ProcedureInputsDisplay.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ProcedureInputsModal.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ProcedureInputsModal.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ProcedureTab.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ProcedureTab.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ResizeHandle.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ResultsSidebar.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ResultsSidebar.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/TestOptionsModal.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/Timestamp.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/Timestamp.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/TopMenuBar.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/chat/ChatInterface.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/chat/MessageInput.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/chat/MessageList.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/debugger/CheckpointDetails.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/debugger/CheckpointDetails.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/debugger/CheckpointList.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/debugger/CheckpointList.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/debugger/DebuggerPanel.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/debugger/DebuggerPanel.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/debugger/RunSelector.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/debugger/RunSelector.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/debugger/StatisticsPanel.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/debugger/StatisticsPanel.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/AgentStreamingComponent.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/BaseEventComponent.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/CheckpointEventComponent.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/CollapsibleTestScenario.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/ContainerStatusEventComponent.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/CostEventComponent.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/CostEventComponent.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/EvaluationEventComponent.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/EvaluationEventComponent.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/EventRenderer.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/ExecutionEventComponent.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/ExecutionEventComponent.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/ExecutionSummaryEventComponent.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/ExecutionSummaryEventComponent.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/LoadingEventComponent.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/LoadingEventComponent.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/LogCluster.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/LogEventComponent.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/LogEventComponent.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/OutputEventComponent.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/OutputEventComponent.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/TestEventComponent.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/TestEventComponent.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/TestProgressContainer.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/ToolCallEventComponent.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/ValidationEventComponent.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/events/ValidationEventComponent.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/metadata/AgentsSection.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/metadata/EvaluationsSection.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/metadata/MetadataSections.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/metadata/OutputsSection.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/metadata/ParametersSection.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/metadata/SpecificationsSection.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/metadata/StagesSection.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/metadata/ToolsSection.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/preferences/ConfigFieldView.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/preferences/SourceBadge.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/preferences/YamlCodeEditor.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/scenarios/EvaluateScenarios.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/scenarios/RunScenarios.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/scenarios/TestScenarios.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/scenarios/ValidationScenarios.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/theme-provider.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ui/ai/conversation.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ui/ai/message.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ui/ai/prompt-input.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ui/badge.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ui/button.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ui/dialog.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ui/dropdown-menu.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ui/input.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ui/label.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ui/logo.stories.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ui/logo.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ui/menubar.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ui/scroll-area.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ui/select.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ui/separator.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ui/switch.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ui/tabs.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/components/ui/tooltip.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/hooks/useChatSSE.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/hooks/useEventStream.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/hooks/useTracing.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/index.css +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/lib/utils.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/main.tsx +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/types/events.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/types/metadata.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/types/preferences.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/types/results.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/types/tracing.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/utils/yamlSync.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/validation/TactusValidator.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/validation/generated/LuaParser.interp +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/validation/generated/LuaParser.tokens +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/validation/types.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/src/vite-env.d.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/tailwind.config.js +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/tsconfig.json +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/tsconfig.node.json +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/vite.config.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/frontend/vitest.shims.d.ts +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/package.json +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tactus-ide/start-dev.sh +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/test-ci.sh +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/adapters/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/adapters/test_lua_tools_adapter.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/adapters/test_plugins.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/broker/test_broker_host_tool_source.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/broker/test_broker_integration.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/broker/test_broker_tcp_integration.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/broker/test_broker_tcp_unit.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/broker/test_brokered_lm_unit.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/cli/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/cli/test_cli.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/cli/test_cli_inputs.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/conftest.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/core/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/core/test_config_manager.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/core/test_determinism_safety.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/core/test_lua_sandbox_security.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/core/test_runtime_inputs.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/core/test_script_mode.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/dspy/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/dspy/test_mock_field_normalization.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/dspy/test_module_parameter.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/dspy/test_prediction_messages.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/dspy/test_streaming.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/fixtures/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/fixtures/brave_search_mcp_server.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/fixtures/filesystem_mcp_server.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/fixtures/test_mcp_server.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/integration/test_named_procedures.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/mocks/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/mocks/llm_mocks.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/primitives/test_checkpoint_primitive.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/primitives/test_host_primitive.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/primitives/test_retry_primitive.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/primitives/test_state_primitive.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/primitives/test_system_alert.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/primitives/test_tool_primitive.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/primitives/test_toolset_dsl.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/sandbox/test_container_runner.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/sandbox/test_docker_sandbox_smoke.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/stdlib/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/stdlib/test_loader.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/stdlib/test_require_python.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/test_checkpoints_integration.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/test_formatter.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/test_mcp_integration.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/test_tracing.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/testing/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/testing/conftest.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/testing/test_all_examples.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/testing/test_e2e.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/testing/test_gherkin_parser.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/testing/test_integration.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/testing/test_models.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/testing/test_runtime_integration.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/testing/test_step_registry.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/utils/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/utils/test_safe_file_library.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/validation/__init__.py +0 -0
- {tactus-0.31.2 → tactus-0.32.1}/tests/validation/test_tool_curried_syntax_disallowed.py +0 -0
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- version list -->
|
|
4
4
|
|
|
5
|
+
## v0.32.1 (2026-01-17)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- Add Flask and Flask-CORS to package dependencies for IDE server
|
|
10
|
+
([`a7ccb69`](https://github.com/AnthusAI/Tactus/commit/a7ccb6957c77628601407f53b8a41d074c6d5568))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## v0.32.0 (2026-01-17)
|
|
14
|
+
|
|
15
|
+
### Code Style
|
|
16
|
+
|
|
17
|
+
- Apply Black formatting to IDE server and config files
|
|
18
|
+
([`65641cc`](https://github.com/AnthusAI/Tactus/commit/65641cc4b806230c086dff071853d1527f82781d))
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
- Add authentication error dialog and automatic config reload
|
|
23
|
+
([`5f3dd95`](https://github.com/AnthusAI/Tactus/commit/5f3dd9572e545cfeb94c26af656ad1d36723cc43))
|
|
24
|
+
|
|
25
|
+
|
|
5
26
|
## v0.31.2 (2026-01-16)
|
|
6
27
|
|
|
7
28
|
### Bug Fixes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tactus
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.32.1
|
|
4
4
|
Summary: Tactus: Lua-based DSL for agentic workflows
|
|
5
5
|
Project-URL: Homepage, https://github.com/AnthusAI/Tactus
|
|
6
6
|
Project-URL: Documentation, https://github.com/AnthusAI/Tactus/tree/main/docs
|
|
@@ -24,6 +24,8 @@ Requires-Dist: behave>=1.2.6
|
|
|
24
24
|
Requires-Dist: boto3>=1.28.0
|
|
25
25
|
Requires-Dist: dotyaml>=0.1.0
|
|
26
26
|
Requires-Dist: dspy>=2.5
|
|
27
|
+
Requires-Dist: flask-cors>=4.0.0
|
|
28
|
+
Requires-Dist: flask>=3.0.0
|
|
27
29
|
Requires-Dist: gherkin-official>=28.0.0
|
|
28
30
|
Requires-Dist: h5py>=3.10
|
|
29
31
|
Requires-Dist: lupa>=2.6
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tactus"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.32.1"
|
|
8
8
|
description = "Tactus: Lua-based DSL for agentic workflows"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -45,6 +45,9 @@ dependencies = [
|
|
|
45
45
|
"openpyxl>=3.1",
|
|
46
46
|
# DSPy for prompt optimization and LLM abstraction
|
|
47
47
|
"dspy>=2.5",
|
|
48
|
+
# IDE server dependencies
|
|
49
|
+
"flask>=3.0.0",
|
|
50
|
+
"flask-cors>=4.0.0",
|
|
48
51
|
]
|
|
49
52
|
|
|
50
53
|
[project.optional-dependencies]
|
|
@@ -599,6 +599,27 @@ class DSPyAgentHandle:
|
|
|
599
599
|
|
|
600
600
|
# Check for errors
|
|
601
601
|
if result_holder["error"] is not None:
|
|
602
|
+
error = result_holder["error"]
|
|
603
|
+
|
|
604
|
+
# Unwrap ExceptionGroup to find the real error
|
|
605
|
+
original_error = error
|
|
606
|
+
if hasattr(error, "__class__") and error.__class__.__name__ == "ExceptionGroup":
|
|
607
|
+
# Python 3.11+ ExceptionGroup
|
|
608
|
+
if hasattr(error, "exceptions") and error.exceptions:
|
|
609
|
+
original_error = error.exceptions[0]
|
|
610
|
+
|
|
611
|
+
# Check if it's an authentication error (in original or wrapped)
|
|
612
|
+
error_str = str(original_error).lower()
|
|
613
|
+
error_type = str(type(original_error).__name__)
|
|
614
|
+
|
|
615
|
+
if "authenticationerror" in error_type.lower() or "api_key" in error_str:
|
|
616
|
+
from tactus.core.exceptions import TactusRuntimeError
|
|
617
|
+
|
|
618
|
+
raise TactusRuntimeError(
|
|
619
|
+
f"API authentication failed for agent '{self.name}': "
|
|
620
|
+
f"Missing or invalid API key. Please configure your API key in Settings (Cmd+,)."
|
|
621
|
+
) from error
|
|
622
|
+
|
|
602
623
|
raise result_holder["error"]
|
|
603
624
|
|
|
604
625
|
# If streaming failed to produce a result, fall back to non-streaming
|
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Configuration API endpoints for Tactus IDE.
|
|
3
|
+
|
|
4
|
+
Provides RESTful API for loading and saving configuration files,
|
|
5
|
+
with support for the configuration cascade system.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
import shutil
|
|
10
|
+
import yaml
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from flask import Blueprint, request, jsonify
|
|
13
|
+
from typing import Dict, Any, List, Tuple, Optional
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
config_bp = Blueprint("config", __name__, url_prefix="/api/config")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def build_cascade_map(loaded_configs: List[Tuple[str, Dict[str, Any]]]) -> Dict[str, str]:
|
|
21
|
+
"""
|
|
22
|
+
Build a map of config path -> source for cascade visualization.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
loaded_configs: List of (source_name, config_dict) tuples
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
Dictionary mapping config paths to their source
|
|
29
|
+
"""
|
|
30
|
+
cascade_map = {}
|
|
31
|
+
|
|
32
|
+
def add_paths(obj: Any, prefix: str = "", source: str = ""):
|
|
33
|
+
"""Recursively add paths from nested config structure."""
|
|
34
|
+
if isinstance(obj, dict):
|
|
35
|
+
for key, value in obj.items():
|
|
36
|
+
path = f"{prefix}.{key}" if prefix else key
|
|
37
|
+
cascade_map[path] = source
|
|
38
|
+
add_paths(value, path, source)
|
|
39
|
+
elif isinstance(obj, list):
|
|
40
|
+
for i, item in enumerate(obj):
|
|
41
|
+
path = f"{prefix}[{i}]"
|
|
42
|
+
add_paths(item, path, source)
|
|
43
|
+
|
|
44
|
+
# Process configs in order (later ones override)
|
|
45
|
+
for source, config in loaded_configs:
|
|
46
|
+
# Extract simple source name (e.g., "user" from "user:/path/to/config.yml")
|
|
47
|
+
source_name = source.split(":")[0] if ":" in source else source
|
|
48
|
+
add_paths(config, "", source_name)
|
|
49
|
+
|
|
50
|
+
return cascade_map
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def load_yaml_file(path: Path) -> Optional[Dict[str, Any]]:
|
|
54
|
+
"""
|
|
55
|
+
Load YAML file safely.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
path: Path to YAML file
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Configuration dictionary or None if file doesn't exist or fails to load
|
|
62
|
+
"""
|
|
63
|
+
if not path.exists():
|
|
64
|
+
return None
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
with open(path, "r") as f:
|
|
68
|
+
config = yaml.safe_load(f)
|
|
69
|
+
return config if isinstance(config, dict) else {}
|
|
70
|
+
except Exception as e:
|
|
71
|
+
logger.warning(f"Failed to load config from {path}: {e}")
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def save_yaml_file(path: Path, config: Dict[str, Any], create_backup: bool = True):
|
|
76
|
+
"""
|
|
77
|
+
Save configuration to YAML file.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
path: Path to save config
|
|
81
|
+
config: Configuration dictionary
|
|
82
|
+
create_backup: Whether to create backup of existing file
|
|
83
|
+
"""
|
|
84
|
+
# Create .tactus directory if needed
|
|
85
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
86
|
+
|
|
87
|
+
# Create backup if requested and file exists
|
|
88
|
+
if create_backup and path.exists():
|
|
89
|
+
backup_path = path.with_suffix(".yml.bak")
|
|
90
|
+
shutil.copy2(path, backup_path)
|
|
91
|
+
logger.info(f"Created backup: {backup_path}")
|
|
92
|
+
|
|
93
|
+
# Save config
|
|
94
|
+
with open(path, "w") as f:
|
|
95
|
+
yaml.safe_dump(
|
|
96
|
+
config,
|
|
97
|
+
f,
|
|
98
|
+
default_flow_style=False,
|
|
99
|
+
sort_keys=False,
|
|
100
|
+
allow_unicode=True,
|
|
101
|
+
indent=2,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
logger.info(f"Saved config to: {path}")
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@config_bp.route("", methods=["GET"])
|
|
108
|
+
def get_config():
|
|
109
|
+
"""
|
|
110
|
+
Get configuration with cascade information.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
JSON response with:
|
|
114
|
+
- config: Merged effective configuration
|
|
115
|
+
- project_config: Project .tactus/config.yml
|
|
116
|
+
- user_config: User ~/.tactus/config.yml
|
|
117
|
+
- system_config: System config if exists
|
|
118
|
+
- cascade: Map of config paths to their source (legacy)
|
|
119
|
+
- source_details: Detailed source tracking with override chains
|
|
120
|
+
- writable_configs: Which configs can be edited
|
|
121
|
+
- config_paths: Full paths to all config files
|
|
122
|
+
"""
|
|
123
|
+
try:
|
|
124
|
+
from tactus.core.config_manager import ConfigManager
|
|
125
|
+
|
|
126
|
+
# Create config manager
|
|
127
|
+
config_manager = ConfigManager()
|
|
128
|
+
|
|
129
|
+
# For IDE purposes, we load config without a specific procedure
|
|
130
|
+
# Use a dummy path to trigger the cascade from project/user/system
|
|
131
|
+
dummy_path = Path.cwd() / "dummy.tac"
|
|
132
|
+
|
|
133
|
+
# Load cascade with source tracking
|
|
134
|
+
effective_config, source_map = config_manager.load_cascade_with_sources(dummy_path)
|
|
135
|
+
|
|
136
|
+
# Build legacy cascade map from loaded configs (for backward compatibility)
|
|
137
|
+
cascade_map = build_cascade_map(config_manager.loaded_configs)
|
|
138
|
+
|
|
139
|
+
# Convert source_map to JSON-serializable format
|
|
140
|
+
source_details = {path: config_value.to_dict() for path, config_value in source_map.items()}
|
|
141
|
+
|
|
142
|
+
# Load individual config files for editing
|
|
143
|
+
project_config_path = Path.cwd() / ".tactus" / "config.yml"
|
|
144
|
+
project_config = load_yaml_file(project_config_path)
|
|
145
|
+
|
|
146
|
+
# Check if we should initialize from example template
|
|
147
|
+
# This happens when:
|
|
148
|
+
# 1. No config.yml exists, OR
|
|
149
|
+
# 2. Config exists but has no API keys configured (openai_api_key is empty/missing)
|
|
150
|
+
should_initialize_from_example = False
|
|
151
|
+
|
|
152
|
+
if project_config is None:
|
|
153
|
+
should_initialize_from_example = True
|
|
154
|
+
elif isinstance(project_config, dict):
|
|
155
|
+
# Check if API keys are configured
|
|
156
|
+
# Support both old flat format (openai_api_key) and new nested format (openai.api_key)
|
|
157
|
+
openai_key = None
|
|
158
|
+
if "openai" in project_config and isinstance(project_config["openai"], dict):
|
|
159
|
+
openai_key = project_config["openai"].get("api_key")
|
|
160
|
+
else:
|
|
161
|
+
openai_key = project_config.get("openai_api_key")
|
|
162
|
+
|
|
163
|
+
aws_key = None
|
|
164
|
+
if "aws" in project_config and isinstance(project_config["aws"], dict):
|
|
165
|
+
aws_key = project_config["aws"].get("profile") or project_config["aws"].get(
|
|
166
|
+
"access_key_id"
|
|
167
|
+
)
|
|
168
|
+
else:
|
|
169
|
+
aws_key = project_config.get("aws_access_key_id")
|
|
170
|
+
|
|
171
|
+
google_key = None
|
|
172
|
+
if "google" in project_config and isinstance(project_config["google"], dict):
|
|
173
|
+
google_key = project_config["google"].get("api_key")
|
|
174
|
+
|
|
175
|
+
# Check if keys are present and not placeholder values
|
|
176
|
+
# Empty strings or None mean not configured
|
|
177
|
+
has_openai_key = (
|
|
178
|
+
openai_key
|
|
179
|
+
and str(openai_key).strip() != ""
|
|
180
|
+
and not str(openai_key).startswith("your-")
|
|
181
|
+
)
|
|
182
|
+
has_aws_keys = (
|
|
183
|
+
aws_key
|
|
184
|
+
and str(aws_key).strip() != ""
|
|
185
|
+
and str(aws_key) != "default"
|
|
186
|
+
and not str(aws_key).startswith("your-")
|
|
187
|
+
)
|
|
188
|
+
has_google_key = (
|
|
189
|
+
google_key
|
|
190
|
+
and str(google_key).strip() != ""
|
|
191
|
+
and not str(google_key).startswith("your-")
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
# If no API keys are configured, initialize from example
|
|
195
|
+
if not has_openai_key and not has_aws_keys and not has_google_key:
|
|
196
|
+
should_initialize_from_example = True
|
|
197
|
+
else:
|
|
198
|
+
project_config = {}
|
|
199
|
+
|
|
200
|
+
if should_initialize_from_example:
|
|
201
|
+
example_config_path = Path.cwd() / ".tactus" / "config.yml.example"
|
|
202
|
+
if example_config_path.exists():
|
|
203
|
+
example_config = load_yaml_file(example_config_path) or {}
|
|
204
|
+
# Merge with existing config (keeps existing values, adds missing fields from example)
|
|
205
|
+
if project_config and isinstance(project_config, dict):
|
|
206
|
+
# Deep merge: example provides defaults, existing values are kept
|
|
207
|
+
merged_config = {**example_config, **project_config}
|
|
208
|
+
else:
|
|
209
|
+
merged_config = example_config
|
|
210
|
+
project_config = merged_config
|
|
211
|
+
# Save the merged config
|
|
212
|
+
try:
|
|
213
|
+
save_yaml_file(project_config_path, project_config, create_backup=True)
|
|
214
|
+
logger.info(
|
|
215
|
+
f"Initialized/merged config with example template: {example_config_path}"
|
|
216
|
+
)
|
|
217
|
+
except Exception as e:
|
|
218
|
+
logger.warning(f"Failed to save merged config: {e}")
|
|
219
|
+
elif not project_config:
|
|
220
|
+
# No example found and no existing config, use empty
|
|
221
|
+
project_config = {}
|
|
222
|
+
|
|
223
|
+
user_config_path = Path.home() / ".tactus" / "config.yml"
|
|
224
|
+
user_config = load_yaml_file(user_config_path) or {}
|
|
225
|
+
|
|
226
|
+
# Try to find system config
|
|
227
|
+
system_config_path = Path("/etc/tactus/config.yml")
|
|
228
|
+
system_config = load_yaml_file(system_config_path) or {}
|
|
229
|
+
|
|
230
|
+
# Determine which configs are writable
|
|
231
|
+
writable_configs = {
|
|
232
|
+
"system": False, # System config is never writable from IDE
|
|
233
|
+
"user": user_config_path.parent.exists() or True, # Can create user config
|
|
234
|
+
"project": True, # Can always write to project config
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return jsonify(
|
|
238
|
+
{
|
|
239
|
+
"config": effective_config,
|
|
240
|
+
"project_config": project_config,
|
|
241
|
+
"user_config": user_config,
|
|
242
|
+
"system_config": system_config,
|
|
243
|
+
"cascade": cascade_map,
|
|
244
|
+
"source_details": source_details,
|
|
245
|
+
"writable_configs": writable_configs,
|
|
246
|
+
"config_paths": {
|
|
247
|
+
"system": str(system_config_path),
|
|
248
|
+
"user": str(user_config_path),
|
|
249
|
+
"project": str(project_config_path),
|
|
250
|
+
},
|
|
251
|
+
# Keep old fields for backward compatibility
|
|
252
|
+
"project_config_path": str(project_config_path),
|
|
253
|
+
"user_config_path": str(user_config_path),
|
|
254
|
+
}
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
except Exception as e:
|
|
258
|
+
logger.error(f"Error loading config: {e}", exc_info=True)
|
|
259
|
+
return jsonify({"error": str(e)}), 500
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
@config_bp.route("", methods=["POST"])
|
|
263
|
+
def save_config():
|
|
264
|
+
"""
|
|
265
|
+
Save configuration to specified target file.
|
|
266
|
+
|
|
267
|
+
Request body:
|
|
268
|
+
{
|
|
269
|
+
"config": {...},
|
|
270
|
+
"targetFile": "project" | "user",
|
|
271
|
+
"createBackup": true
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
JSON response with success status and saved path
|
|
276
|
+
"""
|
|
277
|
+
try:
|
|
278
|
+
data = request.json
|
|
279
|
+
|
|
280
|
+
if not data:
|
|
281
|
+
return jsonify({"error": "Missing request body"}), 400
|
|
282
|
+
|
|
283
|
+
config = data.get("config")
|
|
284
|
+
target = data.get("targetFile", "project")
|
|
285
|
+
create_backup = data.get("createBackup", True)
|
|
286
|
+
|
|
287
|
+
if not config:
|
|
288
|
+
return jsonify({"error": "Missing config"}), 400
|
|
289
|
+
|
|
290
|
+
if not isinstance(config, dict):
|
|
291
|
+
return jsonify({"error": "Config must be an object"}), 400
|
|
292
|
+
|
|
293
|
+
# Determine target path
|
|
294
|
+
if target == "project":
|
|
295
|
+
config_path = Path.cwd() / ".tactus" / "config.yml"
|
|
296
|
+
elif target == "user":
|
|
297
|
+
config_path = Path.home() / ".tactus" / "config.yml"
|
|
298
|
+
else:
|
|
299
|
+
return jsonify({"error": f"Invalid target: {target}"}), 400
|
|
300
|
+
|
|
301
|
+
# Save config
|
|
302
|
+
save_yaml_file(config_path, config, create_backup)
|
|
303
|
+
|
|
304
|
+
# Trigger a runtime reload by emitting an event or clearing caches
|
|
305
|
+
# This ensures the new config is picked up without requiring a restart
|
|
306
|
+
try:
|
|
307
|
+
from tactus.ide.server import clear_runtime_caches
|
|
308
|
+
|
|
309
|
+
clear_runtime_caches()
|
|
310
|
+
logger.info("Cleared runtime caches after config save")
|
|
311
|
+
except (ImportError, AttributeError):
|
|
312
|
+
# If function doesn't exist yet, that's okay - just log it
|
|
313
|
+
logger.debug("Runtime cache clearing not available")
|
|
314
|
+
|
|
315
|
+
return jsonify({"success": True, "path": str(config_path)})
|
|
316
|
+
|
|
317
|
+
except Exception as e:
|
|
318
|
+
logger.error(f"Error saving config: {e}", exc_info=True)
|
|
319
|
+
return jsonify({"error": str(e)}), 500
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
@config_bp.route("/save-by-source", methods=["POST"])
|
|
323
|
+
def save_config_by_source():
|
|
324
|
+
"""
|
|
325
|
+
Save configuration changes to the appropriate file based on source tracking.
|
|
326
|
+
|
|
327
|
+
This endpoint intelligently routes config changes to the correct file based on
|
|
328
|
+
where each value is currently sourced from, or uses a fallback strategy.
|
|
329
|
+
|
|
330
|
+
Request body:
|
|
331
|
+
{
|
|
332
|
+
"changes": {
|
|
333
|
+
"aws.region": "us-west-2",
|
|
334
|
+
"default_model": "gpt-4o"
|
|
335
|
+
},
|
|
336
|
+
"target_strategy": "source_aware" | "force_user" | "force_project"
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
Returns:
|
|
340
|
+
JSON response with:
|
|
341
|
+
- success: Boolean
|
|
342
|
+
- saved_to: Dict mapping change paths to files they were saved to
|
|
343
|
+
- errors: List of any errors (e.g., trying to override env var)
|
|
344
|
+
"""
|
|
345
|
+
try:
|
|
346
|
+
from tactus.core.config_manager import ConfigManager
|
|
347
|
+
|
|
348
|
+
data = request.json
|
|
349
|
+
|
|
350
|
+
if not data:
|
|
351
|
+
return jsonify({"error": "Missing request body"}), 400
|
|
352
|
+
|
|
353
|
+
changes = data.get("changes")
|
|
354
|
+
strategy = data.get("target_strategy", "source_aware")
|
|
355
|
+
|
|
356
|
+
if not changes:
|
|
357
|
+
return jsonify({"error": "Missing changes"}), 400
|
|
358
|
+
|
|
359
|
+
if not isinstance(changes, dict):
|
|
360
|
+
return jsonify({"error": "Changes must be an object"}), 400
|
|
361
|
+
|
|
362
|
+
# Load current config with sources
|
|
363
|
+
config_manager = ConfigManager()
|
|
364
|
+
dummy_path = Path.cwd() / "dummy.tac"
|
|
365
|
+
effective_config, source_map = config_manager.load_cascade_with_sources(dummy_path)
|
|
366
|
+
|
|
367
|
+
# Load current project and user configs
|
|
368
|
+
project_config_path = Path.cwd() / ".tactus" / "config.yml"
|
|
369
|
+
project_config = load_yaml_file(project_config_path) or {}
|
|
370
|
+
|
|
371
|
+
user_config_path = Path.home() / ".tactus" / "config.yml"
|
|
372
|
+
user_config = load_yaml_file(user_config_path) or {}
|
|
373
|
+
|
|
374
|
+
saved_to = {}
|
|
375
|
+
errors = []
|
|
376
|
+
|
|
377
|
+
# Process each change
|
|
378
|
+
for path, new_value in changes.items():
|
|
379
|
+
# Determine target file based on strategy
|
|
380
|
+
if strategy == "force_user":
|
|
381
|
+
target_file = "user"
|
|
382
|
+
target_config = user_config
|
|
383
|
+
elif strategy == "force_project":
|
|
384
|
+
target_file = "project"
|
|
385
|
+
target_config = project_config
|
|
386
|
+
else: # source_aware
|
|
387
|
+
# Check current source
|
|
388
|
+
if path in source_map:
|
|
389
|
+
source_info = source_map[path]
|
|
390
|
+
|
|
391
|
+
# Check if sourced from environment variable
|
|
392
|
+
if source_info.is_env_override:
|
|
393
|
+
errors.append(
|
|
394
|
+
f"{path}: Cannot override environment variable "
|
|
395
|
+
f"{source_info.original_env_var} in config file"
|
|
396
|
+
)
|
|
397
|
+
continue
|
|
398
|
+
|
|
399
|
+
# Route to the source file
|
|
400
|
+
if source_info.source_type == "user":
|
|
401
|
+
target_file = "user"
|
|
402
|
+
target_config = user_config
|
|
403
|
+
elif source_info.source_type == "project":
|
|
404
|
+
target_file = "project"
|
|
405
|
+
target_config = project_config
|
|
406
|
+
else:
|
|
407
|
+
# For system or other sources, default to user config
|
|
408
|
+
target_file = "user"
|
|
409
|
+
target_config = user_config
|
|
410
|
+
else:
|
|
411
|
+
# New value, default to user config
|
|
412
|
+
target_file = "user"
|
|
413
|
+
target_config = user_config
|
|
414
|
+
|
|
415
|
+
# Update the target config dict
|
|
416
|
+
_set_nested_value(target_config, path, new_value)
|
|
417
|
+
saved_to[path] = target_file
|
|
418
|
+
|
|
419
|
+
# Save modified configs
|
|
420
|
+
if any(v == "user" for v in saved_to.values()):
|
|
421
|
+
save_yaml_file(user_config_path, user_config, create_backup=True)
|
|
422
|
+
|
|
423
|
+
if any(v == "project" for v in saved_to.values()):
|
|
424
|
+
save_yaml_file(project_config_path, project_config, create_backup=True)
|
|
425
|
+
|
|
426
|
+
return jsonify(
|
|
427
|
+
{
|
|
428
|
+
"success": len(errors) == 0,
|
|
429
|
+
"saved_to": saved_to,
|
|
430
|
+
"errors": errors,
|
|
431
|
+
}
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
except Exception as e:
|
|
435
|
+
logger.error(f"Error saving config by source: {e}", exc_info=True)
|
|
436
|
+
return jsonify({"error": str(e)}), 500
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
def _set_nested_value(config: Dict[str, Any], path: str, value: Any) -> None:
|
|
440
|
+
"""
|
|
441
|
+
Set a nested value in a config dict using dot notation path.
|
|
442
|
+
|
|
443
|
+
Args:
|
|
444
|
+
config: Configuration dictionary to modify
|
|
445
|
+
path: Dot-separated path (e.g., "aws.region")
|
|
446
|
+
value: Value to set
|
|
447
|
+
"""
|
|
448
|
+
keys = path.split(".")
|
|
449
|
+
current = config
|
|
450
|
+
|
|
451
|
+
# Navigate to the parent of the target key
|
|
452
|
+
for key in keys[:-1]:
|
|
453
|
+
if key not in current:
|
|
454
|
+
current[key] = {}
|
|
455
|
+
elif not isinstance(current[key], dict):
|
|
456
|
+
# Path conflicts with existing non-dict value
|
|
457
|
+
raise ValueError(f"Cannot set nested value: {key} is not a dict")
|
|
458
|
+
current = current[key]
|
|
459
|
+
|
|
460
|
+
# Set the final value
|
|
461
|
+
current[keys[-1]] = value
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
@config_bp.route("/validate", methods=["POST"])
|
|
465
|
+
def validate_config():
|
|
466
|
+
"""
|
|
467
|
+
Validate configuration structure without saving.
|
|
468
|
+
|
|
469
|
+
Request body:
|
|
470
|
+
{
|
|
471
|
+
"config": {...}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
Returns:
|
|
475
|
+
JSON response with validation results
|
|
476
|
+
"""
|
|
477
|
+
try:
|
|
478
|
+
data = request.json
|
|
479
|
+
|
|
480
|
+
if not data:
|
|
481
|
+
return jsonify({"error": "Missing request body"}), 400
|
|
482
|
+
|
|
483
|
+
config = data.get("config")
|
|
484
|
+
|
|
485
|
+
if not config:
|
|
486
|
+
return jsonify({"error": "Missing config"}), 400
|
|
487
|
+
|
|
488
|
+
errors = []
|
|
489
|
+
warnings = []
|
|
490
|
+
|
|
491
|
+
# Basic validation
|
|
492
|
+
if not isinstance(config, dict):
|
|
493
|
+
errors.append("Config must be an object")
|
|
494
|
+
return jsonify({"valid": False, "errors": errors, "warnings": warnings})
|
|
495
|
+
|
|
496
|
+
# Validate known structure (optional - can be expanded)
|
|
497
|
+
# Check for common mistakes
|
|
498
|
+
if "default_provider" in config:
|
|
499
|
+
if config["default_provider"] not in ["openai", "bedrock", "google"]:
|
|
500
|
+
warnings.append(
|
|
501
|
+
f"Unknown provider: {config['default_provider']}. Expected openai, bedrock, or google."
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
if "ide" in config:
|
|
505
|
+
ide_config = config["ide"]
|
|
506
|
+
if not isinstance(ide_config, dict):
|
|
507
|
+
errors.append("ide config must be an object")
|
|
508
|
+
|
|
509
|
+
# Try to serialize to YAML (validation)
|
|
510
|
+
try:
|
|
511
|
+
yaml.safe_dump(config)
|
|
512
|
+
except Exception as e:
|
|
513
|
+
errors.append(f"Config cannot be serialized to YAML: {str(e)}")
|
|
514
|
+
|
|
515
|
+
return jsonify(
|
|
516
|
+
{
|
|
517
|
+
"valid": len(errors) == 0,
|
|
518
|
+
"errors": errors,
|
|
519
|
+
"warnings": warnings,
|
|
520
|
+
}
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
except Exception as e:
|
|
524
|
+
logger.error(f"Error validating config: {e}", exc_info=True)
|
|
525
|
+
return jsonify({"error": str(e)}), 500
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
def register_config_routes(app):
|
|
529
|
+
"""
|
|
530
|
+
Register config routes with Flask app.
|
|
531
|
+
|
|
532
|
+
Args:
|
|
533
|
+
app: Flask application instance
|
|
534
|
+
"""
|
|
535
|
+
app.register_blueprint(config_bp)
|
|
536
|
+
logger.info("Registered config API routes")
|