tactus 0.26.0__tar.gz → 0.27.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 (582) hide show
  1. {tactus-0.26.0 → tactus-0.27.0}/.gitignore +2 -0
  2. {tactus-0.26.0 → tactus-0.27.0}/CHANGELOG.md +9 -0
  3. {tactus-0.26.0 → tactus-0.27.0}/Makefile +9 -0
  4. {tactus-0.26.0 → tactus-0.27.0}/PKG-INFO +1 -1
  5. {tactus-0.26.0 → tactus-0.27.0}/docs/DURABILITY.md +2 -2
  6. {tactus-0.26.0 → tactus-0.27.0}/docs/SANDBOXING.md +3 -2
  7. {tactus-0.26.0 → tactus-0.27.0}/docs/TOOLS.md +92 -13
  8. {tactus-0.26.0 → tactus-0.27.0}/docs/TOOL_ROADMAP.md +1 -1
  9. tactus-0.27.0/examples/01-basics-hello-world.tac +23 -0
  10. {tactus-0.26.0 → tactus-0.27.0}/examples/05-basics-multi-model.tac +2 -2
  11. {tactus-0.26.0 → tactus-0.27.0}/examples/06-basics-streaming.tac +8 -1
  12. {tactus-0.26.0 → tactus-0.27.0}/examples/07-basics-bedrock.tac +3 -3
  13. {tactus-0.26.0 → tactus-0.27.0}/examples/08-basics-models.tac +3 -3
  14. {tactus-0.26.0 → tactus-0.27.0}/examples/09-basics-google-gemini.tac +4 -4
  15. {tactus-0.26.0 → tactus-0.27.0}/examples/12-feature-structured-output.tac +20 -8
  16. {tactus-0.26.0 → tactus-0.27.0}/examples/14-feature-per-turn-tools-simple.tac +10 -1
  17. {tactus-0.26.0 → tactus-0.27.0}/examples/15-feature-local-tools.tac +11 -1
  18. {tactus-0.26.0 → tactus-0.27.0}/examples/16-feature-toolsets-advanced.tac +2 -2
  19. {tactus-0.26.0 → tactus-0.27.0}/examples/17-feature-toolsets-dsl.tac +1 -2
  20. {tactus-0.26.0 → tactus-0.27.0}/examples/18-feature-lua-tools-individual.tac +1 -1
  21. {tactus-0.26.0 → tactus-0.27.0}/examples/18-feature-lua-tools-inline.tac +1 -1
  22. {tactus-0.26.0 → tactus-0.27.0}/examples/18-feature-lua-tools-toolset.tac +1 -1
  23. {tactus-0.26.0 → tactus-0.27.0}/examples/40-model-text-classifier.tac +9 -18
  24. {tactus-0.26.0 → tactus-0.27.0}/examples/41-model-pytorch.tac +9 -20
  25. {tactus-0.26.0 → tactus-0.27.0}/examples/44-sub-procedure-composition.tac +11 -19
  26. {tactus-0.26.0 → tactus-0.27.0}/examples/60-tool-sources.tac +2 -1
  27. {tactus-0.26.0 → tactus-0.27.0}/examples/61-inline-toolset-lua.tac +2 -2
  28. {tactus-0.26.0 → tactus-0.27.0}/examples/62-mcp-toolset-by-server.tac +2 -2
  29. {tactus-0.26.0 → tactus-0.27.0}/examples/63-toolset-import-from-file.tac +3 -3
  30. {tactus-0.26.0 → tactus-0.27.0}/examples/65-optional-state-demo.tac +4 -6
  31. tactus-0.27.0/examples/66-host-tools-via-broker.tac +36 -0
  32. {tactus-0.26.0 → tactus-0.27.0}/examples/99-misc-test-loading.tac +2 -2
  33. {tactus-0.26.0 → tactus-0.27.0}/features/18_example_procedures.feature +1 -1
  34. {tactus-0.26.0 → tactus-0.27.0}/features/32_result_object.feature +8 -6
  35. {tactus-0.26.0 → tactus-0.27.0}/features/steps/example_procedures_steps.py +15 -10
  36. {tactus-0.26.0 → tactus-0.27.0}/features/steps/result_and_output_steps.py +7 -7
  37. tactus-0.27.0/planning/BROKER_AND_TOOL_RUNNERS.md +617 -0
  38. {tactus-0.26.0 → tactus-0.27.0}/pyproject.toml +9 -1
  39. {tactus-0.26.0 → tactus-0.27.0}/tactus/__init__.py +1 -1
  40. tactus-0.27.0/tactus/adapters/broker_log.py +55 -0
  41. {tactus-0.26.0 → tactus-0.27.0}/tactus/adapters/cli_log.py +0 -25
  42. tactus-0.27.0/tactus/broker/__init__.py +12 -0
  43. tactus-0.27.0/tactus/broker/client.py +260 -0
  44. tactus-0.27.0/tactus/broker/server.py +505 -0
  45. tactus-0.27.0/tactus/broker/stdio.py +12 -0
  46. {tactus-0.26.0 → tactus-0.27.0}/tactus/cli/app.py +38 -2
  47. {tactus-0.26.0 → tactus-0.27.0}/tactus/core/dsl_stubs.py +2 -1
  48. {tactus-0.26.0 → tactus-0.27.0}/tactus/core/output_validator.py +6 -3
  49. {tactus-0.26.0 → tactus-0.27.0}/tactus/core/registry.py +8 -1
  50. {tactus-0.26.0 → tactus-0.27.0}/tactus/core/runtime.py +15 -1
  51. {tactus-0.26.0 → tactus-0.27.0}/tactus/core/yaml_parser.py +1 -11
  52. {tactus-0.26.0 → tactus-0.27.0}/tactus/dspy/agent.py +190 -102
  53. tactus-0.27.0/tactus/dspy/broker_lm.py +181 -0
  54. {tactus-0.26.0 → tactus-0.27.0}/tactus/dspy/config.py +21 -8
  55. {tactus-0.26.0 → tactus-0.27.0}/tactus/dspy/prediction.py +71 -5
  56. {tactus-0.26.0 → tactus-0.27.0}/tactus/ide/server.py +37 -142
  57. {tactus-0.26.0 → tactus-0.27.0}/tactus/primitives/__init__.py +2 -0
  58. {tactus-0.26.0 → tactus-0.27.0}/tactus/primitives/handles.py +34 -7
  59. tactus-0.27.0/tactus/primitives/host.py +94 -0
  60. {tactus-0.26.0 → tactus-0.27.0}/tactus/primitives/log.py +4 -0
  61. {tactus-0.26.0 → tactus-0.27.0}/tactus/primitives/model.py +20 -2
  62. {tactus-0.26.0 → tactus-0.27.0}/tactus/primitives/procedure.py +106 -51
  63. {tactus-0.26.0 → tactus-0.27.0}/tactus/primitives/tool.py +0 -2
  64. {tactus-0.26.0 → tactus-0.27.0}/tactus/protocols/__init__.py +0 -7
  65. {tactus-0.26.0 → tactus-0.27.0}/tactus/protocols/log_handler.py +2 -2
  66. {tactus-0.26.0 → tactus-0.27.0}/tactus/protocols/models.py +1 -1
  67. {tactus-0.26.0 → tactus-0.27.0}/tactus/sandbox/config.py +33 -5
  68. tactus-0.27.0/tactus/sandbox/container_runner.py +1022 -0
  69. {tactus-0.26.0 → tactus-0.27.0}/tactus/sandbox/entrypoint.py +30 -17
  70. {tactus-0.26.0 → tactus-0.27.0}/tactus/sandbox/protocol.py +0 -9
  71. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/README.md +0 -4
  72. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/mock_agent.py +80 -23
  73. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/test_runner.py +0 -18
  74. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/backend/test_lsp_server.py +4 -4
  75. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/MessageFeed.tsx +1 -27
  76. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/EventRenderer.tsx +3 -9
  77. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/types/events.ts +0 -8
  78. tactus-0.27.0/tests/broker/test_broker_integration.py +108 -0
  79. tactus-0.27.0/tests/broker/test_broker_tcp_integration.py +109 -0
  80. tactus-0.27.0/tests/broker/test_broker_tcp_unit.py +160 -0
  81. tactus-0.27.0/tests/broker/test_brokered_lm_unit.py +72 -0
  82. {tactus-0.26.0 → tactus-0.27.0}/tests/cli/test_cli.py +2 -1
  83. {tactus-0.26.0 → tactus-0.27.0}/tests/cli/test_cli_inputs.py +11 -10
  84. tactus-0.27.0/tests/dspy/test_agent_messages.py +187 -0
  85. tactus-0.27.0/tests/dspy/test_mock_field_normalization.py +120 -0
  86. tactus-0.27.0/tests/dspy/test_prediction_messages.py +114 -0
  87. tactus-0.27.0/tests/primitives/test_host_primitive.py +32 -0
  88. tactus-0.27.0/tests/sandbox/test_container_runner.py +98 -0
  89. tactus-0.27.0/tests/sandbox/test_docker_sandbox_smoke.py +98 -0
  90. tactus-0.27.0/tests/test_checkpoints_integration.py +59 -0
  91. {tactus-0.26.0 → tactus-0.27.0}/tests/test_mcp_integration.py +5 -2
  92. tactus-0.26.0/examples/01-basics-hello-world.tac +0 -8
  93. tactus-0.26.0/tactus/sandbox/container_runner.py +0 -584
  94. tactus-0.26.0/tests/test_checkpoints_integration.py +0 -104
  95. {tactus-0.26.0 → tactus-0.27.0}/.claude/agents.md +0 -0
  96. {tactus-0.26.0 → tactus-0.27.0}/.github/workflows/desktop-release.yml +0 -0
  97. {tactus-0.26.0 → tactus-0.27.0}/.github/workflows/release.yml +0 -0
  98. {tactus-0.26.0 → tactus-0.27.0}/.tactus/config.yml.example +0 -0
  99. {tactus-0.26.0 → tactus-0.27.0}/AGENTS.md +0 -0
  100. {tactus-0.26.0 → tactus-0.27.0}/IMPLEMENTATION.md +0 -0
  101. {tactus-0.26.0 → tactus-0.27.0}/LICENSE +0 -0
  102. {tactus-0.26.0 → tactus-0.27.0}/README.md +0 -0
  103. {tactus-0.26.0 → tactus-0.27.0}/SPECIFICATION.md +0 -0
  104. {tactus-0.26.0 → tactus-0.27.0}/TECHNICAL_DEBT.md +0 -0
  105. {tactus-0.26.0 → tactus-0.27.0}/behave.ini +0 -0
  106. {tactus-0.26.0 → tactus-0.27.0}/docs/AGENTS.md +0 -0
  107. {tactus-0.26.0 → tactus-0.27.0}/docs/BDD_TESTING.md +0 -0
  108. {tactus-0.26.0 → tactus-0.27.0}/docs/CONFIGURATION.md +0 -0
  109. {tactus-0.26.0 → tactus-0.27.0}/docs/FILE_IO.md +0 -0
  110. {tactus-0.26.0 → tactus-0.27.0}/docs/STREAMING.md +0 -0
  111. {tactus-0.26.0 → tactus-0.27.0}/examples/.tactus/config.yml +0 -0
  112. {tactus-0.26.0 → tactus-0.27.0}/examples/02-basics-simple-logic.tac +0 -0
  113. {tactus-0.26.0 → tactus-0.27.0}/examples/03-basics-parameters.tac +0 -0
  114. {tactus-0.26.0 → tactus-0.27.0}/examples/04-basics-simple-agent.tac +0 -0
  115. {tactus-0.26.0 → tactus-0.27.0}/examples/10-feature-state.tac +0 -0
  116. {tactus-0.26.0 → tactus-0.27.0}/examples/11-feature-message-history.tac +0 -0
  117. {tactus-0.26.0 → tactus-0.27.0}/examples/13-feature-session.tac +0 -0
  118. {tactus-0.26.0 → tactus-0.27.0}/examples/14-feature-per-turn-tools.tac +0 -0
  119. {tactus-0.26.0 → tactus-0.27.0}/examples/19-feature-direct-tool-calls.tac +0 -0
  120. {tactus-0.26.0 → tactus-0.27.0}/examples/20-bdd-complete.tac +0 -0
  121. {tactus-0.26.0 → tactus-0.27.0}/examples/20-bdd-complete.tac.bak2 +0 -0
  122. {tactus-0.26.0 → tactus-0.27.0}/examples/21-bdd-passing.tac +0 -0
  123. {tactus-0.26.0 → tactus-0.27.0}/examples/21-bdd-passing.tac.bak2 +0 -0
  124. {tactus-0.26.0 → tactus-0.27.0}/examples/30-eval-simple.tac +0 -0
  125. {tactus-0.26.0 → tactus-0.27.0}/examples/31-eval-demo.tac +0 -0
  126. {tactus-0.26.0 → tactus-0.27.0}/examples/32-eval-success-rate.tac +0 -0
  127. {tactus-0.26.0 → tactus-0.27.0}/examples/33-eval-thresholds.tac +0 -0
  128. {tactus-0.26.0 → tactus-0.27.0}/examples/34-eval-dataset.jsonl +0 -0
  129. {tactus-0.26.0 → tactus-0.27.0}/examples/34-eval-dataset.tac +0 -0
  130. {tactus-0.26.0 → tactus-0.27.0}/examples/35-eval-trace.tac +0 -0
  131. {tactus-0.26.0 → tactus-0.27.0}/examples/35-eval-trace.tac.bak2 +0 -0
  132. {tactus-0.26.0 → tactus-0.27.0}/examples/36-eval-advanced.tac +0 -0
  133. {tactus-0.26.0 → tactus-0.27.0}/examples/37-eval-comprehensive.tac +0 -0
  134. {tactus-0.26.0 → tactus-0.27.0}/examples/37-eval-comprehensive.tac.bak2 +0 -0
  135. {tactus-0.26.0 → tactus-0.27.0}/examples/39-model-simple.tac +0 -0
  136. {tactus-0.26.0 → tactus-0.27.0}/examples/40-mcp-test.tac +0 -0
  137. {tactus-0.26.0 → tactus-0.27.0}/examples/41-mcp-simple.tac +0 -0
  138. {tactus-0.26.0 → tactus-0.27.0}/examples/43-sub-procedure-simple.tac +0 -0
  139. {tactus-0.26.0 → tactus-0.27.0}/examples/45-sub-procedure-recursive.tac +0 -0
  140. {tactus-0.26.0 → tactus-0.27.0}/examples/46-checkpoint-explicit.tac +0 -0
  141. {tactus-0.26.0 → tactus-0.27.0}/examples/47-checkpoint-expensive-ops.tac +0 -0
  142. {tactus-0.26.0 → tactus-0.27.0}/examples/48-script-mode-simple.tac +0 -0
  143. {tactus-0.26.0 → tactus-0.27.0}/examples/50-inputs-showcase.tac +0 -0
  144. {tactus-0.26.0 → tactus-0.27.0}/examples/51-inputs-calculator.tac +0 -0
  145. {tactus-0.26.0 → tactus-0.27.0}/examples/52-file-io-basics.tac +0 -0
  146. {tactus-0.26.0 → tactus-0.27.0}/examples/53-tsv-file-io.tac +0 -0
  147. {tactus-0.26.0 → tactus-0.27.0}/examples/54-json-file-io.tac +0 -0
  148. {tactus-0.26.0 → tactus-0.27.0}/examples/55-parquet-file-io.tac +0 -0
  149. {tactus-0.26.0 → tactus-0.27.0}/examples/56-hdf5-file-io.tac +0 -0
  150. {tactus-0.26.0 → tactus-0.27.0}/examples/57-excel-file-io.tac +0 -0
  151. {tactus-0.26.0 → tactus-0.27.0}/examples/58-text-file-io.tac +0 -0
  152. {tactus-0.26.0 → tactus-0.27.0}/examples/64-require-modules.tac +0 -0
  153. {tactus-0.26.0 → tactus-0.27.0}/examples/70-mocking-static.tac +0 -0
  154. {tactus-0.26.0 → tactus-0.27.0}/examples/71-mocking-temporal.tac +0 -0
  155. {tactus-0.26.0 → tactus-0.27.0}/examples/72-mocking-conditional.tac +0 -0
  156. {tactus-0.26.0 → tactus-0.27.0}/examples/README.md +0 -0
  157. {tactus-0.26.0 → tactus-0.27.0}/examples/app_config.ini +0 -0
  158. {tactus-0.26.0 → tactus-0.27.0}/examples/data/sample.csv +0 -0
  159. {tactus-0.26.0 → tactus-0.27.0}/examples/demo_output.json +0 -0
  160. {tactus-0.26.0 → tactus-0.27.0}/examples/helpers/math_module.tac +0 -0
  161. {tactus-0.26.0 → tactus-0.27.0}/examples/helpers/product.tac +0 -0
  162. {tactus-0.26.0 → tactus-0.27.0}/examples/helpers/string_module.tac +0 -0
  163. {tactus-0.26.0 → tactus-0.27.0}/examples/helpers/sum.tac +0 -0
  164. {tactus-0.26.0 → tactus-0.27.0}/examples/helpers/text_tools.tac +0 -0
  165. {tactus-0.26.0 → tactus-0.27.0}/examples/inventory_summary.tsv +0 -0
  166. {tactus-0.26.0 → tactus-0.27.0}/examples/mock-config.json +0 -0
  167. {tactus-0.26.0 → tactus-0.27.0}/examples/models/README.md +0 -0
  168. {tactus-0.26.0 → tactus-0.27.0}/examples/models/create_sentiment_model.py +0 -0
  169. {tactus-0.26.0 → tactus-0.27.0}/examples/output_summary.txt +0 -0
  170. {tactus-0.26.0 → tactus-0.27.0}/examples/test-raw-module.tac +0 -0
  171. {tactus-0.26.0 → tactus-0.27.0}/examples/test-raw-streaming.tac +0 -0
  172. {tactus-0.26.0 → tactus-0.27.0}/examples/tools/calculations.py +0 -0
  173. {tactus-0.26.0 → tactus-0.27.0}/examples/tools/data_analysis.py +0 -0
  174. {tactus-0.26.0 → tactus-0.27.0}/examples/tools/search.py +0 -0
  175. {tactus-0.26.0 → tactus-0.27.0}/examples/with_dependencies/README.md +0 -0
  176. {tactus-0.26.0 → tactus-0.27.0}/examples/with_dependencies/simple_http_test.tac +0 -0
  177. {tactus-0.26.0 → tactus-0.27.0}/examples/with_dependencies/time_lookup.tac +0 -0
  178. {tactus-0.26.0 → tactus-0.27.0}/features/01_state_management.feature +0 -0
  179. {tactus-0.26.0 → tactus-0.27.0}/features/02_checkpointing.feature +0 -0
  180. {tactus-0.26.0 → tactus-0.27.0}/features/03_human_in_the_loop.feature +0 -0
  181. {tactus-0.26.0 → tactus-0.27.0}/features/04_control_flow.feature +0 -0
  182. {tactus-0.26.0 → tactus-0.27.0}/features/05_tool_integration.feature +0 -0
  183. {tactus-0.26.0 → tactus-0.27.0}/features/06_retry_logic.feature +0 -0
  184. {tactus-0.26.0 → tactus-0.27.0}/features/07_file_operations.feature +0 -0
  185. {tactus-0.26.0 → tactus-0.27.0}/features/08_agent_primitives.feature +0 -0
  186. {tactus-0.26.0 → tactus-0.27.0}/features/09_workflow_execution.feature +0 -0
  187. {tactus-0.26.0 → tactus-0.27.0}/features/10_lua_integration.feature +0 -0
  188. {tactus-0.26.0 → tactus-0.27.0}/features/11_storage_backends.feature +0 -0
  189. {tactus-0.26.0 → tactus-0.27.0}/features/12_json_operations.feature +0 -0
  190. {tactus-0.26.0 → tactus-0.27.0}/features/13_logging.feature +0 -0
  191. {tactus-0.26.0 → tactus-0.27.0}/features/14_stage_and_step_tracking.feature +0 -0
  192. {tactus-0.26.0 → tactus-0.27.0}/features/15_procedure_calls.feature +0 -0
  193. {tactus-0.26.0 → tactus-0.27.0}/features/16_session_management.feature +0 -0
  194. {tactus-0.26.0 → tactus-0.27.0}/features/17_lua_dsl_validation.feature +0 -0
  195. {tactus-0.26.0 → tactus-0.27.0}/features/19_ide_server.feature +0 -0
  196. {tactus-0.26.0 → tactus-0.27.0}/features/20_parameters.feature +0 -0
  197. {tactus-0.26.0 → tactus-0.27.0}/features/21_outputs.feature +0 -0
  198. {tactus-0.26.0 → tactus-0.27.0}/features/23_prompts.feature +0 -0
  199. {tactus-0.26.0 → tactus-0.27.0}/features/24_bdd_specifications.feature +0 -0
  200. {tactus-0.26.0 → tactus-0.27.0}/features/25_bdd_custom_steps.feature +0 -0
  201. {tactus-0.26.0 → tactus-0.27.0}/features/26_bdd_evaluation.feature +0 -0
  202. {tactus-0.26.0 → tactus-0.27.0}/features/27_default_settings.feature +0 -0
  203. {tactus-0.26.0 → tactus-0.27.0}/features/28_custom_prompts.feature +0 -0
  204. {tactus-0.26.0 → tactus-0.27.0}/features/29_execution_settings.feature +0 -0
  205. {tactus-0.26.0 → tactus-0.27.0}/features/30_session_filters.feature +0 -0
  206. {tactus-0.26.0 → tactus-0.27.0}/features/31_matchers.feature +0 -0
  207. {tactus-0.26.0 → tactus-0.27.0}/features/33_output_type.feature +0 -0
  208. {tactus-0.26.0 → tactus-0.27.0}/features/42_model_primitive.feature +0 -0
  209. {tactus-0.26.0 → tactus-0.27.0}/features/43_sub_procedure_checkpointing.feature +0 -0
  210. {tactus-0.26.0 → tactus-0.27.0}/features/46_explicit_checkpoint.feature +0 -0
  211. {tactus-0.26.0 → tactus-0.27.0}/features/48_script_mode.feature +0 -0
  212. {tactus-0.26.0 → tactus-0.27.0}/features/51_dspy_lm_config.feature +0 -0
  213. {tactus-0.26.0 → tactus-0.27.0}/features/52_dspy_signature.feature +0 -0
  214. {tactus-0.26.0 → tactus-0.27.0}/features/53_dspy_module.feature +0 -0
  215. {tactus-0.26.0 → tactus-0.27.0}/features/54_dspy_history.feature +0 -0
  216. {tactus-0.26.0 → tactus-0.27.0}/features/55_dspy_prediction.feature +0 -0
  217. {tactus-0.26.0 → tactus-0.27.0}/features/56_dspy_agent.feature +0 -0
  218. {tactus-0.26.0 → tactus-0.27.0}/features/57_chat_assistant.feature +0 -0
  219. {tactus-0.26.0 → tactus-0.27.0}/features/documentation/IDE_SERVER_BEHAVIOR.md +0 -0
  220. {tactus-0.26.0 → tactus-0.27.0}/features/documentation/Lua DSL/README.md +0 -0
  221. {tactus-0.26.0 → tactus-0.27.0}/features/environment.py +0 -0
  222. {tactus-0.26.0 → tactus-0.27.0}/features/steps/agent_primitives_steps.py +0 -0
  223. {tactus-0.26.0 → tactus-0.27.0}/features/steps/chat_assistant_steps.py +0 -0
  224. {tactus-0.26.0 → tactus-0.27.0}/features/steps/checkpointing_steps.py +0 -0
  225. {tactus-0.26.0 → tactus-0.27.0}/features/steps/control_flow_steps.py +0 -0
  226. {tactus-0.26.0 → tactus-0.27.0}/features/steps/dspy_agent_steps.py +0 -0
  227. {tactus-0.26.0 → tactus-0.27.0}/features/steps/dspy_history_steps.py +0 -0
  228. {tactus-0.26.0 → tactus-0.27.0}/features/steps/dspy_lm_steps.py +0 -0
  229. {tactus-0.26.0 → tactus-0.27.0}/features/steps/dspy_module_steps.py +0 -0
  230. {tactus-0.26.0 → tactus-0.27.0}/features/steps/dspy_prediction_steps.py +0 -0
  231. {tactus-0.26.0 → tactus-0.27.0}/features/steps/dspy_signature_steps.py +0 -0
  232. {tactus-0.26.0 → tactus-0.27.0}/features/steps/file_operations_steps.py +0 -0
  233. {tactus-0.26.0 → tactus-0.27.0}/features/steps/human_in_the_loop_steps.py +0 -0
  234. {tactus-0.26.0 → tactus-0.27.0}/features/steps/ide_server_steps.py +0 -0
  235. {tactus-0.26.0 → tactus-0.27.0}/features/steps/json_operations_steps.py +0 -0
  236. {tactus-0.26.0 → tactus-0.27.0}/features/steps/logging_steps.py +0 -0
  237. {tactus-0.26.0 → tactus-0.27.0}/features/steps/lua_dsl_validation_steps.py +0 -0
  238. {tactus-0.26.0 → tactus-0.27.0}/features/steps/lua_integration_steps.py +0 -0
  239. {tactus-0.26.0 → tactus-0.27.0}/features/steps/mocking_steps.py +0 -0
  240. {tactus-0.26.0 → tactus-0.27.0}/features/steps/procedure_calls_steps.py +0 -0
  241. {tactus-0.26.0 → tactus-0.27.0}/features/steps/retry_logic_steps.py +0 -0
  242. {tactus-0.26.0 → tactus-0.27.0}/features/steps/session_management_steps.py +0 -0
  243. {tactus-0.26.0 → tactus-0.27.0}/features/steps/stage_tracking_steps.py +0 -0
  244. {tactus-0.26.0 → tactus-0.27.0}/features/steps/state_management_steps.py +0 -0
  245. {tactus-0.26.0 → tactus-0.27.0}/features/steps/storage_backend_steps.py +0 -0
  246. {tactus-0.26.0 → tactus-0.27.0}/features/steps/support/__init__.py +0 -0
  247. {tactus-0.26.0 → tactus-0.27.0}/features/steps/support/harnesses.py +0 -0
  248. {tactus-0.26.0 → tactus-0.27.0}/features/steps/tool_integration_steps.py +0 -0
  249. {tactus-0.26.0 → tactus-0.27.0}/features/steps/workflow_execution_steps.py +0 -0
  250. {tactus-0.26.0 → tactus-0.27.0}/scripts/audit_examples_mocking.py +0 -0
  251. {tactus-0.26.0 → tactus-0.27.0}/scripts/convert_examples.py +0 -0
  252. {tactus-0.26.0 → tactus-0.27.0}/start-web-ide.sh +0 -0
  253. {tactus-0.26.0 → tactus-0.27.0}/tactus/adapters/__init__.py +0 -0
  254. {tactus-0.26.0 → tactus-0.27.0}/tactus/adapters/cli_hitl.py +0 -0
  255. {tactus-0.26.0 → tactus-0.27.0}/tactus/adapters/cost_collector_log.py +0 -0
  256. {tactus-0.26.0 → tactus-0.27.0}/tactus/adapters/file_storage.py +0 -0
  257. {tactus-0.26.0 → tactus-0.27.0}/tactus/adapters/http_callback_log.py +0 -0
  258. {tactus-0.26.0 → tactus-0.27.0}/tactus/adapters/ide_log.py +0 -0
  259. {tactus-0.26.0 → tactus-0.27.0}/tactus/adapters/lua_tools.py +0 -0
  260. {tactus-0.26.0 → tactus-0.27.0}/tactus/adapters/mcp.py +0 -0
  261. {tactus-0.26.0 → tactus-0.27.0}/tactus/adapters/mcp_manager.py +0 -0
  262. {tactus-0.26.0 → tactus-0.27.0}/tactus/adapters/memory.py +0 -0
  263. {tactus-0.26.0 → tactus-0.27.0}/tactus/adapters/plugins.py +0 -0
  264. {tactus-0.26.0 → tactus-0.27.0}/tactus/backends/http_backend.py +0 -0
  265. {tactus-0.26.0 → tactus-0.27.0}/tactus/backends/model_backend.py +0 -0
  266. {tactus-0.26.0 → tactus-0.27.0}/tactus/backends/pytorch_backend.py +0 -0
  267. {tactus-0.26.0 → tactus-0.27.0}/tactus/cli/__init__.py +0 -0
  268. {tactus-0.26.0 → tactus-0.27.0}/tactus/cli/commands/__init__.py +0 -0
  269. {tactus-0.26.0 → tactus-0.27.0}/tactus/core/__init__.py +0 -0
  270. {tactus-0.26.0 → tactus-0.27.0}/tactus/core/config_manager.py +0 -0
  271. {tactus-0.26.0 → tactus-0.27.0}/tactus/core/dependencies/__init__.py +0 -0
  272. {tactus-0.26.0 → tactus-0.27.0}/tactus/core/dependencies/registry.py +0 -0
  273. {tactus-0.26.0 → tactus-0.27.0}/tactus/core/exceptions.py +0 -0
  274. {tactus-0.26.0 → tactus-0.27.0}/tactus/core/execution_context.py +0 -0
  275. {tactus-0.26.0 → tactus-0.27.0}/tactus/core/lua_sandbox.py +0 -0
  276. {tactus-0.26.0 → tactus-0.27.0}/tactus/core/message_history_manager.py +0 -0
  277. {tactus-0.26.0 → tactus-0.27.0}/tactus/core/mocking.py +0 -0
  278. {tactus-0.26.0 → tactus-0.27.0}/tactus/core/template_resolver.py +0 -0
  279. {tactus-0.26.0 → tactus-0.27.0}/tactus/docker/Dockerfile +0 -0
  280. {tactus-0.26.0 → tactus-0.27.0}/tactus/docker/entrypoint.sh +0 -0
  281. {tactus-0.26.0 → tactus-0.27.0}/tactus/dspy/__init__.py +0 -0
  282. {tactus-0.26.0 → tactus-0.27.0}/tactus/dspy/history.py +0 -0
  283. {tactus-0.26.0 → tactus-0.27.0}/tactus/dspy/module.py +0 -0
  284. {tactus-0.26.0 → tactus-0.27.0}/tactus/dspy/signature.py +0 -0
  285. {tactus-0.26.0 → tactus-0.27.0}/tactus/ide/__init__.py +0 -0
  286. {tactus-0.26.0 → tactus-0.27.0}/tactus/ide/coding_assistant.py +0 -0
  287. {tactus-0.26.0 → tactus-0.27.0}/tactus/primitives/control.py +0 -0
  288. {tactus-0.26.0 → tactus-0.27.0}/tactus/primitives/file.py +0 -0
  289. {tactus-0.26.0 → tactus-0.27.0}/tactus/primitives/human.py +0 -0
  290. {tactus-0.26.0 → tactus-0.27.0}/tactus/primitives/json.py +0 -0
  291. {tactus-0.26.0 → tactus-0.27.0}/tactus/primitives/message_history.py +0 -0
  292. {tactus-0.26.0 → tactus-0.27.0}/tactus/primitives/procedure_callable.py +0 -0
  293. {tactus-0.26.0 → tactus-0.27.0}/tactus/primitives/retry.py +0 -0
  294. {tactus-0.26.0 → tactus-0.27.0}/tactus/primitives/session.py +0 -0
  295. {tactus-0.26.0 → tactus-0.27.0}/tactus/primitives/stage.py +0 -0
  296. {tactus-0.26.0 → tactus-0.27.0}/tactus/primitives/state.py +0 -0
  297. {tactus-0.26.0 → tactus-0.27.0}/tactus/primitives/step.py +0 -0
  298. {tactus-0.26.0 → tactus-0.27.0}/tactus/primitives/system.py +0 -0
  299. {tactus-0.26.0 → tactus-0.27.0}/tactus/primitives/tool_handle.py +0 -0
  300. {tactus-0.26.0 → tactus-0.27.0}/tactus/primitives/toolset.py +0 -0
  301. {tactus-0.26.0 → tactus-0.27.0}/tactus/protocols/chat_recorder.py +0 -0
  302. {tactus-0.26.0 → tactus-0.27.0}/tactus/protocols/config.py +0 -0
  303. {tactus-0.26.0 → tactus-0.27.0}/tactus/protocols/cost.py +0 -0
  304. {tactus-0.26.0 → tactus-0.27.0}/tactus/protocols/hitl.py +0 -0
  305. {tactus-0.26.0 → tactus-0.27.0}/tactus/protocols/result.py +0 -0
  306. {tactus-0.26.0 → tactus-0.27.0}/tactus/protocols/storage.py +0 -0
  307. {tactus-0.26.0 → tactus-0.27.0}/tactus/providers/__init__.py +0 -0
  308. {tactus-0.26.0 → tactus-0.27.0}/tactus/providers/base.py +0 -0
  309. {tactus-0.26.0 → tactus-0.27.0}/tactus/providers/bedrock.py +0 -0
  310. {tactus-0.26.0 → tactus-0.27.0}/tactus/providers/google.py +0 -0
  311. {tactus-0.26.0 → tactus-0.27.0}/tactus/providers/openai.py +0 -0
  312. {tactus-0.26.0 → tactus-0.27.0}/tactus/sandbox/__init__.py +0 -0
  313. {tactus-0.26.0 → tactus-0.27.0}/tactus/sandbox/docker_manager.py +0 -0
  314. {tactus-0.26.0 → tactus-0.27.0}/tactus/stdlib/__init__.py +0 -0
  315. {tactus-0.26.0 → tactus-0.27.0}/tactus/stdlib/io/__init__.py +0 -0
  316. {tactus-0.26.0 → tactus-0.27.0}/tactus/stdlib/io/csv.py +0 -0
  317. {tactus-0.26.0 → tactus-0.27.0}/tactus/stdlib/io/excel.py +0 -0
  318. {tactus-0.26.0 → tactus-0.27.0}/tactus/stdlib/io/file.py +0 -0
  319. {tactus-0.26.0 → tactus-0.27.0}/tactus/stdlib/io/fs.py +0 -0
  320. {tactus-0.26.0 → tactus-0.27.0}/tactus/stdlib/io/hdf5.py +0 -0
  321. {tactus-0.26.0 → tactus-0.27.0}/tactus/stdlib/io/json.py +0 -0
  322. {tactus-0.26.0 → tactus-0.27.0}/tactus/stdlib/io/parquet.py +0 -0
  323. {tactus-0.26.0 → tactus-0.27.0}/tactus/stdlib/io/tsv.py +0 -0
  324. {tactus-0.26.0 → tactus-0.27.0}/tactus/stdlib/loader.py +0 -0
  325. {tactus-0.26.0 → tactus-0.27.0}/tactus/stdlib/tac/tactus/tools/done.tac +0 -0
  326. {tactus-0.26.0 → tactus-0.27.0}/tactus/stdlib/tac/tactus/tools/log.tac +0 -0
  327. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/__init__.py +0 -0
  328. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/behave_integration.py +0 -0
  329. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/context.py +0 -0
  330. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/eval_models.py +0 -0
  331. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/evaluation_runner.py +0 -0
  332. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/evaluators.py +0 -0
  333. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/events.py +0 -0
  334. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/gherkin_parser.py +0 -0
  335. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/mock_dependencies.py +0 -0
  336. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/mock_hitl.py +0 -0
  337. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/mock_registry.py +0 -0
  338. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/mock_tools.py +0 -0
  339. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/models.py +0 -0
  340. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/pydantic_eval_runner.py +0 -0
  341. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/steps/__init__.py +0 -0
  342. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/steps/builtin.py +0 -0
  343. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/steps/custom.py +0 -0
  344. {tactus-0.26.0 → tactus-0.27.0}/tactus/testing/steps/registry.py +0 -0
  345. {tactus-0.26.0 → tactus-0.27.0}/tactus/tracing/__init__.py +0 -0
  346. {tactus-0.26.0 → tactus-0.27.0}/tactus/tracing/trace_manager.py +0 -0
  347. {tactus-0.26.0 → tactus-0.27.0}/tactus/utils/__init__.py +0 -0
  348. {tactus-0.26.0 → tactus-0.27.0}/tactus/utils/cost_calculator.py +0 -0
  349. {tactus-0.26.0 → tactus-0.27.0}/tactus/utils/model_pricing.py +0 -0
  350. {tactus-0.26.0 → tactus-0.27.0}/tactus/utils/safe_file_library.py +0 -0
  351. {tactus-0.26.0 → tactus-0.27.0}/tactus/utils/safe_libraries.py +0 -0
  352. {tactus-0.26.0 → tactus-0.27.0}/tactus/validation/LuaLexerBase.py +0 -0
  353. {tactus-0.26.0 → tactus-0.27.0}/tactus/validation/LuaParserBase.py +0 -0
  354. {tactus-0.26.0 → tactus-0.27.0}/tactus/validation/README.md +0 -0
  355. {tactus-0.26.0 → tactus-0.27.0}/tactus/validation/__init__.py +0 -0
  356. {tactus-0.26.0 → tactus-0.27.0}/tactus/validation/error_listener.py +0 -0
  357. {tactus-0.26.0 → tactus-0.27.0}/tactus/validation/generated/LuaLexer.interp +0 -0
  358. {tactus-0.26.0 → tactus-0.27.0}/tactus/validation/generated/LuaLexer.py +0 -0
  359. {tactus-0.26.0 → tactus-0.27.0}/tactus/validation/generated/LuaLexer.tokens +0 -0
  360. {tactus-0.26.0 → tactus-0.27.0}/tactus/validation/generated/LuaLexerBase.py +0 -0
  361. {tactus-0.26.0 → tactus-0.27.0}/tactus/validation/generated/LuaParser.interp +0 -0
  362. {tactus-0.26.0 → tactus-0.27.0}/tactus/validation/generated/LuaParser.py +0 -0
  363. {tactus-0.26.0 → tactus-0.27.0}/tactus/validation/generated/LuaParser.tokens +0 -0
  364. {tactus-0.26.0 → tactus-0.27.0}/tactus/validation/generated/LuaParserBase.py +0 -0
  365. {tactus-0.26.0 → tactus-0.27.0}/tactus/validation/generated/LuaParserVisitor.py +0 -0
  366. {tactus-0.26.0 → tactus-0.27.0}/tactus/validation/generated/__init__.py +0 -0
  367. {tactus-0.26.0 → tactus-0.27.0}/tactus/validation/grammar/LuaLexer.g4 +0 -0
  368. {tactus-0.26.0 → tactus-0.27.0}/tactus/validation/grammar/LuaParser.g4 +0 -0
  369. {tactus-0.26.0 → tactus-0.27.0}/tactus/validation/semantic_visitor.py +0 -0
  370. {tactus-0.26.0 → tactus-0.27.0}/tactus/validation/validator.py +0 -0
  371. {tactus-0.26.0 → tactus-0.27.0}/tactus-desktop/.gitignore +0 -0
  372. {tactus-0.26.0 → tactus-0.27.0}/tactus-desktop/README.md +0 -0
  373. {tactus-0.26.0 → tactus-0.27.0}/tactus-desktop/RUN_ELECTRON.md +0 -0
  374. {tactus-0.26.0 → tactus-0.27.0}/tactus-desktop/SETUP_COMPLETE.md +0 -0
  375. {tactus-0.26.0 → tactus-0.27.0}/tactus-desktop/backend/hook-lupa.py +0 -0
  376. {tactus-0.26.0 → tactus-0.27.0}/tactus-desktop/backend/tactus_backend.spec +0 -0
  377. {tactus-0.26.0 → tactus-0.27.0}/tactus-desktop/package-lock.json +0 -0
  378. {tactus-0.26.0 → tactus-0.27.0}/tactus-desktop/package.json +0 -0
  379. {tactus-0.26.0 → tactus-0.27.0}/tactus-desktop/preload/preload.ts +0 -0
  380. {tactus-0.26.0 → tactus-0.27.0}/tactus-desktop/preload/tsconfig.json +0 -0
  381. {tactus-0.26.0 → tactus-0.27.0}/tactus-desktop/rebuild-and-test.sh +0 -0
  382. {tactus-0.26.0 → tactus-0.27.0}/tactus-desktop/scripts/build-backend.js +0 -0
  383. {tactus-0.26.0 → tactus-0.27.0}/tactus-desktop/scripts/build-frontend.js +0 -0
  384. {tactus-0.26.0 → tactus-0.27.0}/tactus-desktop/src/backend-manager.ts +0 -0
  385. {tactus-0.26.0 → tactus-0.27.0}/tactus-desktop/src/main.ts +0 -0
  386. {tactus-0.26.0 → tactus-0.27.0}/tactus-desktop/src/menu.ts +0 -0
  387. {tactus-0.26.0 → tactus-0.27.0}/tactus-desktop/tsconfig.json +0 -0
  388. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/ARCHITECTURE.md +0 -0
  389. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/CHANGELOG.md +0 -0
  390. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/DEV_MODE.md +0 -0
  391. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/QUICK_START.md +0 -0
  392. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/README.md +0 -0
  393. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/RESTART_INSTRUCTIONS.md +0 -0
  394. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/TROUBLESHOOTING.md +0 -0
  395. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/backend/README.md +0 -0
  396. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/backend/assistant_service.py +0 -0
  397. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/backend/assistant_tools.py +0 -0
  398. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/backend/chat_server.py +0 -0
  399. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/backend/config_server.py +0 -0
  400. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/backend/events.py +0 -0
  401. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/backend/logging_capture.py +0 -0
  402. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/backend/lsp_server.py +0 -0
  403. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/backend/requirements.txt +0 -0
  404. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/backend/tactus_lsp_handler.py +0 -0
  405. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/backend/text_editor_tool.py +0 -0
  406. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/dev.sh +0 -0
  407. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/.storybook/main.ts +0 -0
  408. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/.storybook/preview.ts +0 -0
  409. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/.storybook/vitest.setup.ts +0 -0
  410. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/README.md +0 -0
  411. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/demo.ts +0 -0
  412. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/index.html +0 -0
  413. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/jest.config.js +0 -0
  414. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/package-lock.json +0 -0
  415. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/package.json +0 -0
  416. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/postcss.config.js +0 -0
  417. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/App.tsx +0 -0
  418. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/Editor.tsx +0 -0
  419. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/LSPClient.ts +0 -0
  420. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/LSPClientHTTP.ts +0 -0
  421. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/TactusLanguage.ts +0 -0
  422. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/commands/registry.ts +0 -0
  423. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/AboutDialog.tsx +0 -0
  424. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ChatSidebar.tsx +0 -0
  425. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/CheckpointSummary.tsx +0 -0
  426. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/CollapsibleRun.tsx +0 -0
  427. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/Duration.stories.tsx +0 -0
  428. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/Duration.tsx +0 -0
  429. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/FileTree.stories.tsx +0 -0
  430. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/FileTree.tsx +0 -0
  431. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/PreferencesView.tsx +0 -0
  432. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ProcedureInputsDisplay.stories.tsx +0 -0
  433. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ProcedureInputsDisplay.tsx +0 -0
  434. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ProcedureInputsModal.stories.tsx +0 -0
  435. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ProcedureInputsModal.tsx +0 -0
  436. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ProcedureTab.stories.tsx +0 -0
  437. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ProcedureTab.tsx +0 -0
  438. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ResizeHandle.tsx +0 -0
  439. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ResultsSidebar.stories.tsx +0 -0
  440. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ResultsSidebar.tsx +0 -0
  441. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/TestOptionsModal.tsx +0 -0
  442. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/Timestamp.stories.tsx +0 -0
  443. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/Timestamp.tsx +0 -0
  444. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/TopMenuBar.stories.tsx +0 -0
  445. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/chat/ChatInterface.tsx +0 -0
  446. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/chat/MessageInput.tsx +0 -0
  447. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/chat/MessageList.tsx +0 -0
  448. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/debugger/CheckpointDetails.stories.tsx +0 -0
  449. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/debugger/CheckpointDetails.tsx +0 -0
  450. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/debugger/CheckpointList.stories.tsx +0 -0
  451. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/debugger/CheckpointList.tsx +0 -0
  452. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/debugger/DebuggerPanel.stories.tsx +0 -0
  453. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/debugger/DebuggerPanel.tsx +0 -0
  454. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/debugger/RunSelector.stories.tsx +0 -0
  455. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/debugger/RunSelector.tsx +0 -0
  456. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/debugger/StatisticsPanel.stories.tsx +0 -0
  457. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/debugger/StatisticsPanel.tsx +0 -0
  458. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/AgentStreamingComponent.tsx +0 -0
  459. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/BaseEventComponent.tsx +0 -0
  460. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/CheckpointEventComponent.tsx +0 -0
  461. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/CollapsibleTestScenario.tsx +0 -0
  462. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/ContainerStatusEventComponent.tsx +0 -0
  463. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/CostEventComponent.stories.tsx +0 -0
  464. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/CostEventComponent.tsx +0 -0
  465. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/EvaluationEventComponent.stories.tsx +0 -0
  466. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/EvaluationEventComponent.tsx +0 -0
  467. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/ExecutionEventComponent.stories.tsx +0 -0
  468. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/ExecutionEventComponent.tsx +0 -0
  469. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/ExecutionSummaryEventComponent.stories.tsx +0 -0
  470. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/ExecutionSummaryEventComponent.tsx +0 -0
  471. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/LoadingEventComponent.stories.tsx +0 -0
  472. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/LoadingEventComponent.tsx +0 -0
  473. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/LogCluster.tsx +0 -0
  474. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/LogEventComponent.stories.tsx +0 -0
  475. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/LogEventComponent.tsx +0 -0
  476. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/OutputEventComponent.stories.tsx +0 -0
  477. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/OutputEventComponent.tsx +0 -0
  478. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/TestEventComponent.stories.tsx +0 -0
  479. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/TestEventComponent.tsx +0 -0
  480. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/TestProgressContainer.tsx +0 -0
  481. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/ToolCallEventComponent.tsx +0 -0
  482. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/ValidationEventComponent.stories.tsx +0 -0
  483. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/events/ValidationEventComponent.tsx +0 -0
  484. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/metadata/AgentsSection.tsx +0 -0
  485. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/metadata/EvaluationsSection.tsx +0 -0
  486. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/metadata/MetadataSections.stories.tsx +0 -0
  487. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/metadata/OutputsSection.tsx +0 -0
  488. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/metadata/ParametersSection.tsx +0 -0
  489. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/metadata/SpecificationsSection.tsx +0 -0
  490. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/metadata/StagesSection.tsx +0 -0
  491. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/metadata/ToolsSection.tsx +0 -0
  492. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/preferences/ConfigFieldView.tsx +0 -0
  493. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/preferences/SourceBadge.tsx +0 -0
  494. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/preferences/YamlCodeEditor.tsx +0 -0
  495. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/scenarios/EvaluateScenarios.stories.tsx +0 -0
  496. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/scenarios/RunScenarios.stories.tsx +0 -0
  497. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/scenarios/TestScenarios.stories.tsx +0 -0
  498. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/scenarios/ValidationScenarios.stories.tsx +0 -0
  499. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/theme-provider.tsx +0 -0
  500. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ui/ai/conversation.tsx +0 -0
  501. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ui/ai/message.tsx +0 -0
  502. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ui/ai/prompt-input.tsx +0 -0
  503. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ui/badge.tsx +0 -0
  504. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ui/button.tsx +0 -0
  505. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ui/dialog.tsx +0 -0
  506. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ui/dropdown-menu.tsx +0 -0
  507. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ui/input.tsx +0 -0
  508. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ui/label.tsx +0 -0
  509. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ui/logo.stories.tsx +0 -0
  510. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ui/logo.tsx +0 -0
  511. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ui/menubar.tsx +0 -0
  512. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ui/scroll-area.tsx +0 -0
  513. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ui/select.tsx +0 -0
  514. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ui/separator.tsx +0 -0
  515. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ui/switch.tsx +0 -0
  516. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ui/tabs.tsx +0 -0
  517. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/components/ui/tooltip.tsx +0 -0
  518. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/hooks/useChatSSE.ts +0 -0
  519. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/hooks/useEventStream.ts +0 -0
  520. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/hooks/useTracing.ts +0 -0
  521. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/index.css +0 -0
  522. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/lib/utils.ts +0 -0
  523. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/main.tsx +0 -0
  524. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/types/metadata.ts +0 -0
  525. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/types/preferences.ts +0 -0
  526. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/types/results.ts +0 -0
  527. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/types/tracing.ts +0 -0
  528. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/utils/yamlSync.ts +0 -0
  529. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/validation/TactusValidator.ts +0 -0
  530. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/validation/generated/LuaParser.interp +0 -0
  531. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/validation/generated/LuaParser.tokens +0 -0
  532. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/validation/types.ts +0 -0
  533. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/src/vite-env.d.ts +0 -0
  534. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/tailwind.config.js +0 -0
  535. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/tsconfig.json +0 -0
  536. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/tsconfig.node.json +0 -0
  537. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/vite.config.ts +0 -0
  538. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/frontend/vitest.shims.d.ts +0 -0
  539. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/package.json +0 -0
  540. {tactus-0.26.0 → tactus-0.27.0}/tactus-ide/start-dev.sh +0 -0
  541. {tactus-0.26.0 → tactus-0.27.0}/tests/__init__.py +0 -0
  542. {tactus-0.26.0 → tactus-0.27.0}/tests/adapters/__init__.py +0 -0
  543. {tactus-0.26.0 → tactus-0.27.0}/tests/adapters/test_lua_tools_adapter.py +0 -0
  544. {tactus-0.26.0 → tactus-0.27.0}/tests/adapters/test_plugins.py +0 -0
  545. {tactus-0.26.0 → tactus-0.27.0}/tests/cli/__init__.py +0 -0
  546. {tactus-0.26.0 → tactus-0.27.0}/tests/conftest.py +0 -0
  547. {tactus-0.26.0 → tactus-0.27.0}/tests/core/__init__.py +0 -0
  548. {tactus-0.26.0 → tactus-0.27.0}/tests/core/test_config_manager.py +0 -0
  549. {tactus-0.26.0 → tactus-0.27.0}/tests/core/test_determinism_safety.py +0 -0
  550. {tactus-0.26.0 → tactus-0.27.0}/tests/core/test_lua_sandbox_security.py +0 -0
  551. {tactus-0.26.0 → tactus-0.27.0}/tests/core/test_runtime_inputs.py +0 -0
  552. {tactus-0.26.0 → tactus-0.27.0}/tests/core/test_script_mode.py +0 -0
  553. {tactus-0.26.0 → tactus-0.27.0}/tests/dspy/__init__.py +0 -0
  554. {tactus-0.26.0 → tactus-0.27.0}/tests/dspy/test_module_parameter.py +0 -0
  555. {tactus-0.26.0 → tactus-0.27.0}/tests/dspy/test_streaming.py +0 -0
  556. {tactus-0.26.0 → tactus-0.27.0}/tests/fixtures/__init__.py +0 -0
  557. {tactus-0.26.0 → tactus-0.27.0}/tests/fixtures/test_mcp_server.py +0 -0
  558. {tactus-0.26.0 → tactus-0.27.0}/tests/integration/test_named_procedures.py +0 -0
  559. {tactus-0.26.0 → tactus-0.27.0}/tests/mocks/__init__.py +0 -0
  560. {tactus-0.26.0 → tactus-0.27.0}/tests/mocks/llm_mocks.py +0 -0
  561. {tactus-0.26.0 → tactus-0.27.0}/tests/primitives/test_checkpoint_primitive.py +0 -0
  562. {tactus-0.26.0 → tactus-0.27.0}/tests/primitives/test_retry_primitive.py +0 -0
  563. {tactus-0.26.0 → tactus-0.27.0}/tests/primitives/test_state_primitive.py +0 -0
  564. {tactus-0.26.0 → tactus-0.27.0}/tests/primitives/test_system_alert.py +0 -0
  565. {tactus-0.26.0 → tactus-0.27.0}/tests/primitives/test_tool_primitive.py +0 -0
  566. {tactus-0.26.0 → tactus-0.27.0}/tests/primitives/test_toolset_dsl.py +0 -0
  567. {tactus-0.26.0 → tactus-0.27.0}/tests/stdlib/__init__.py +0 -0
  568. {tactus-0.26.0 → tactus-0.27.0}/tests/stdlib/test_loader.py +0 -0
  569. {tactus-0.26.0 → tactus-0.27.0}/tests/stdlib/test_require_python.py +0 -0
  570. {tactus-0.26.0 → tactus-0.27.0}/tests/test_tracing.py +0 -0
  571. {tactus-0.26.0 → tactus-0.27.0}/tests/testing/__init__.py +0 -0
  572. {tactus-0.26.0 → tactus-0.27.0}/tests/testing/conftest.py +0 -0
  573. {tactus-0.26.0 → tactus-0.27.0}/tests/testing/test_all_examples.py +0 -0
  574. {tactus-0.26.0 → tactus-0.27.0}/tests/testing/test_e2e.py +0 -0
  575. {tactus-0.26.0 → tactus-0.27.0}/tests/testing/test_gherkin_parser.py +0 -0
  576. {tactus-0.26.0 → tactus-0.27.0}/tests/testing/test_integration.py +0 -0
  577. {tactus-0.26.0 → tactus-0.27.0}/tests/testing/test_models.py +0 -0
  578. {tactus-0.26.0 → tactus-0.27.0}/tests/testing/test_runtime_integration.py +0 -0
  579. {tactus-0.26.0 → tactus-0.27.0}/tests/testing/test_step_registry.py +0 -0
  580. {tactus-0.26.0 → tactus-0.27.0}/tests/utils/__init__.py +0 -0
  581. {tactus-0.26.0 → tactus-0.27.0}/tests/utils/test_safe_file_library.py +0 -0
  582. {tactus-0.26.0 → tactus-0.27.0}/tests/validation/__init__.py +0 -0
@@ -39,6 +39,8 @@ progress.output
39
39
  .tac/
40
40
  tmp/
41
41
  examples/output/
42
+ _recovery/
43
+ .tactus-broker/
42
44
 
43
45
  *storybook.log
44
46
  storybook-static
@@ -2,6 +2,15 @@
2
2
 
3
3
  <!-- version list -->
4
4
 
5
+ ## v0.27.0 (2026-01-11)
6
+
7
+ ### Features
8
+
9
+ - **broker**: Brokered sandbox runtime MVP (secretless runtime container) (#24)
10
+ ([#24](https://github.com/AnthusAI/Tactus/pull/24),
11
+ [`f922432`](https://github.com/AnthusAI/Tactus/commit/f922432da5a881c5eceb7c1410276ab45264ddaa))
12
+
13
+
5
14
  ## v0.26.0 (2026-01-11)
6
15
 
7
16
  ### Features
@@ -1,4 +1,5 @@
1
1
  .PHONY: help generate-parsers generate-python-parser generate-typescript-parser test-parsers clean-generated dev-ide test-examples test-examples-fast test-examples-parallel test-examples-bdd
2
+ .PHONY: test-docker-sandbox
2
3
 
3
4
  help:
4
5
  @echo "Tactus Parser Generation and Testing"
@@ -17,6 +18,9 @@ help:
17
18
  @echo " test-examples-parallel - Test examples in parallel for speed"
18
19
  @echo " test-examples-bdd - Test only examples with BDD specifications"
19
20
  @echo ""
21
+ @echo "Docker Sandbox Testing:"
22
+ @echo " test-docker-sandbox - Run opt-in Docker sandbox smoke tests"
23
+ @echo ""
20
24
  @echo "Requirements:"
21
25
  @echo " - Docker must be running (for parser generation)"
22
26
  @echo " - Python 3.11+ with dependencies installed"
@@ -113,6 +117,11 @@ test-examples-bdd:
113
117
  @echo "Testing examples with BDD specifications..."
114
118
  pytest tests/testing/test_all_examples.py::TestAllExamples::test_example_bdd_specs -v --tb=short
115
119
 
120
+ # Docker sandbox integration tests (dev-only, opt-in)
121
+ test-docker-sandbox:
122
+ @echo "Running Docker sandbox integration tests (opt-in)..."
123
+ @echo "Pre-req: tactus sandbox rebuild --force"
124
+ TACTUS_RUN_DOCKER_TESTS=1 pytest -m docker -v --tb=short
116
125
 
117
126
 
118
127
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tactus
3
- Version: 0.26.0
3
+ Version: 0.27.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
@@ -1097,7 +1097,7 @@ class AgentPrimitive:
1097
1097
  )
1098
1098
  return {
1099
1099
  "output": result.output,
1100
- "messages": self.messages
1100
+ "messages": self.messages + result.new_messages()
1101
1101
  }
1102
1102
  ```
1103
1103
 
@@ -1390,4 +1390,4 @@ result = await runtime.execute(
1390
1390
 
1391
1391
  4. **Observability**: Integration with Logfire/OpenTelemetry for tracing?
1392
1392
 
1393
- 5. **Error recovery**: Retry policies, dead letter queues, manual intervention?
1393
+ 5. **Error recovery**: Retry policies, dead letter queues, manual intervention?
@@ -1,6 +1,6 @@
1
1
  # Sandboxing & Security
2
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.
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 designed to support secure multi-tenant AI systems.
4
4
 
5
5
  ## Overview: Three Layers of Protection
6
6
 
@@ -458,6 +458,7 @@ logger.info(f"Tool call: {tool_name}", extra={
458
458
  ## Development
459
459
  - [ ] Docker Desktop installed and running
460
460
  - [ ] Sandbox enabled in config (default)
461
+ - [ ] Run opt-in Docker sandbox tests (dev-only): `tactus sandbox rebuild --force` then `make test-docker-sandbox` (or `TACTUS_RUN_DOCKER_TESTS=1 pytest -m docker -v`)
461
462
  - [ ] MCP servers reviewed for security issues
462
463
  - [ ] Tool calls logged for debugging
463
464
  - [ ] Resource limits configured appropriately
@@ -485,7 +486,7 @@ logger.info(f"Tool call: {tool_name}", extra={
485
486
  2. **Default security:** Sandbox enabled by default, opt-out requires explicit acknowledgment
486
487
  3. **AI-native design:** Built from the ground up to prevent session leakage
487
488
  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
+ 5. **Multi-tenant isolation:** Cloud sandboxing provides per-invocation isolation at scale
489
490
  6. **Information security DNA:** Per-invocation sandboxing prevents AI session leakage, a critical requirement for multi-tenant AI systems
490
491
 
491
492
  ---
@@ -1,23 +1,33 @@
1
- # Defining Tools with Lua Functions
1
+ # Tools in Tactus
2
2
 
3
- This guide explains how to define tools as Lua functions within Tactus procedures, giving agents the ability to perform custom operations without requiring external Python plugins or MCP servers.
3
+ This guide explains the major tool types in Tactus, where they run, and how to keep secrets out of sandboxed runs.
4
4
 
5
5
  ## Table of Contents
6
6
 
7
7
  1. [Overview](#overview)
8
- 2. [Quick Start](#quick-start)
9
- 3. [Three Approaches](#three-approaches)
10
- 4. [Parameter Specifications](#parameter-specifications)
11
- 5. [Tool Implementation Patterns](#tool-implementation-patterns)
12
- 6. [Error Handling](#error-handling)
13
- 7. [Tool Call Tracking](#tool-call-tracking)
14
- 8. [Advanced Examples](#advanced-examples)
15
- 9. [Comparison with Plugin Tools](#comparison-with-plugin-tools)
16
- 10. [Best Practices](#best-practices)
8
+ 2. [Trust Zones](#trust-zones)
9
+ 3. [Brokered Host Tools](#brokered-host-tools)
10
+ 4. [Quick Start](#quick-start)
11
+ 5. [Three Approaches](#three-approaches)
12
+ 6. [Parameter Specifications](#parameter-specifications)
13
+ 7. [Tool Implementation Patterns](#tool-implementation-patterns)
14
+ 8. [Error Handling](#error-handling)
15
+ 9. [Tool Call Tracking](#tool-call-tracking)
16
+ 10. [Advanced Examples](#advanced-examples)
17
+ 11. [Comparison with Plugin Tools](#comparison-with-plugin-tools)
18
+ 12. [Best Practices](#best-practices)
17
19
 
18
20
  ## Overview
19
21
 
20
- Tactus supports three ways to define tools as Lua functions:
22
+ Tactus supports several tool types:
23
+
24
+ - **Built-in Tactus tools** (shipped with Tactus): e.g. `tactus.tools.done`
25
+ - **Lua function tools** (defined inside `.tac`): simple, fast, co-located with the workflow
26
+ - **Python plugin tools** (loaded from `tool_paths`): run Python code from your repo without MCP
27
+ - **MCP tools** (Model Context Protocol): tools provided by external stdio servers
28
+ - **Brokered host tools** (Phase 1B): privileged “host-side” tools executed by the broker and invoked from the sandbox via `Host.call(...)`
29
+
30
+ Lua function tools support three ways to define tools:
21
31
 
22
32
  1. **Individual `tool()` declarations** - Define single tools globally
23
33
  2. **`toolset()` with `type="lua"`** - Group multiple related tools
@@ -33,6 +43,53 @@ All three approaches are powered by Pydantic AI's function toolset feature and i
33
43
  - **Tracked**: Full integration with `Tool.called()` and `Tool.last_call()`
34
44
  - **Fast**: Minimal overhead for simple operations
35
45
 
46
+ ## Trust Zones
47
+
48
+ Tactus aims to keep the **runtime container** (when using `--sandbox`) both:
49
+
50
+ - **Networkless** by default (`--network none`)
51
+ - **Secretless** (no long-lived API keys in the container env, mounts, or request payload)
52
+
53
+ That means not all “tools” are equal: different tool types run in different trust zones.
54
+
55
+ At a high level:
56
+
57
+ - **Lua tools** run inside the runtime (and therefore inside the sandbox container when `--sandbox` is enabled).
58
+ - **MCP servers** run as subprocesses of the runtime (so they share the runtime’s trust zone unless explicitly isolated).
59
+ - **Brokered host tools** run on the trusted host-side broker and can hold secrets without exposing them to the sandbox.
60
+
61
+ For the broader architecture (including future isolated tool runners), see `planning/BROKER_AND_TOOL_RUNNERS.md`.
62
+
63
+ ## Brokered Host Tools
64
+
65
+ Brokered host tools are allowlisted operations executed by the **host-side broker** and invoked from the runtime via the `Host` primitive.
66
+
67
+ This is the core mechanism for “remote tools with secrets” (e.g., a Tab search API key) while keeping the sandbox container secretless.
68
+
69
+ ### Running the Example
70
+
71
+ Run the example:
72
+
73
+ ```bash
74
+ tactus sandbox rebuild --force
75
+ tactus run examples/66-host-tools-via-broker.tac --sandbox --verbose
76
+ ```
77
+
78
+ Call a host tool from Lua:
79
+
80
+ ```lua
81
+ local result = Host.call("host.ping", {value = 1})
82
+ ```
83
+
84
+ ### Default Allowlist (Phase 1B)
85
+
86
+ The default broker allowlist intentionally starts small:
87
+
88
+ - `host.ping`
89
+ - `host.echo`
90
+
91
+ To add real host tools, extend the broker’s allowlist (see `tactus/broker/server.py:HostToolRegistry`).
92
+
36
93
  ## Quick Start
37
94
 
38
95
  Here's the simplest example:
@@ -652,7 +709,7 @@ content_editor = Agent {
652
709
  - Lua language constraints
653
710
  - No async operations
654
711
  - Limited to Lua ecosystem
655
- - Can't call external APIs directly
712
+ - Can't safely hold secrets (use brokered host tools instead)
656
713
 
657
714
  **Best for:**
658
715
  - Data transformations
@@ -683,6 +740,23 @@ content_editor = Agent {
683
740
  - Shared across projects
684
741
  - Complex algorithms
685
742
 
743
+ ### Brokered Host Tools (via Host.call)
744
+
745
+ **Pros:**
746
+ - Secrets stay out of the sandbox container
747
+ - Can perform network calls without giving the runtime network access
748
+ - Centralized allowlist and auditing point (the broker)
749
+
750
+ **Cons:**
751
+ - Requires a broker transport (`--sandbox` uses broker by default)
752
+ - Must be explicitly allowlisted (deny-by-default)
753
+ - Privileged by design; treat host tools as trusted code
754
+
755
+ **Best for:**
756
+ - Remote API tools that require API keys
757
+ - “Host-integrated” capabilities (e.g., talking to a local index, keychain, or daemon)
758
+ - Anything that must be kept out of the untrusted runtime container
759
+
686
760
  ### When to Use Which?
687
761
 
688
762
  Use **Lua Function Tools** when:
@@ -705,6 +779,11 @@ Use **MCP Tools** when:
705
779
  - Tool is maintained separately
706
780
  - Multiple procedures share it
707
781
 
782
+ Use **Brokered Host Tools** when:
783
+ - A tool needs secrets but the runtime container must remain secretless
784
+ - The runtime container must remain networkless (`--network none`)
785
+ - You want a narrow, allowlisted capability surface area
786
+
708
787
  ## Best Practices
709
788
 
710
789
  ### 1. Clear Descriptions
@@ -1126,7 +1126,7 @@ sequenceDiagram
1126
1126
  PA->>LLM: Send tool result
1127
1127
  LLM-->>PA: Final response
1128
1128
  PA-->>AP: RunResult
1129
- AP-->>Lua: Result
1129
+ AP-->>Lua: ResultPrimitive
1130
1130
 
1131
1131
  Lua->>Lua: search.called()
1132
1132
  Lua->>Lua: search.last_result()
@@ -0,0 +1,23 @@
1
+ World = Agent {
2
+ provider = "openai",
3
+ model = "gpt-4o-mini",
4
+ system_prompt = "Your name is World.",
5
+ module = "Raw" -- No DSPy delimiter formatting
6
+ }
7
+
8
+ Procedure {
9
+ output = {
10
+ message = field.string{required = true}
11
+ },
12
+ function(_)
13
+ local result = World({message = "Hello, World!"})
14
+ return {message = result.response}
15
+ end
16
+ }
17
+
18
+ Mocks {
19
+ World = {
20
+ tool_calls = {},
21
+ message = "Hello, World!"
22
+ }
23
+ }
@@ -45,7 +45,7 @@ Procedure {
45
45
  if done.called() then
46
46
  research = done.last_result() or "Task completed"
47
47
  else
48
- research = tostring(result.value) or "Research not completed"
48
+ research = result.message or "Research not completed"
49
49
  Log.warn("Researcher did not call done within max turns")
50
50
  end
51
51
  state.research = research
@@ -66,7 +66,7 @@ Procedure {
66
66
  if done.called() then
67
67
  summary = done.last_result() or "Task completed"
68
68
  else
69
- summary = tostring(result.value) or "Summary not completed"
69
+ summary = result.message or "Summary not completed"
70
70
  Log.warn("Summarizer did not call done within max turns")
71
71
  end
72
72
 
@@ -26,8 +26,15 @@ Procedure {
26
26
  local result = storyteller({message = input.prompt})
27
27
 
28
28
  return {
29
- story = result.value,
29
+ story = result.response,
30
30
  success = true
31
31
  }
32
32
  end
33
33
  }
34
+
35
+ Mocks {
36
+ storyteller = {
37
+ tool_calls = {},
38
+ message = "A curious robot dipped its brush into blue paint and discovered joy in every stroke."
39
+ }
40
+ }
@@ -36,9 +36,9 @@ Procedure {
36
36
  local response = haiku_assistant()
37
37
  turn_count = turn_count + 1
38
38
 
39
- -- Accumulate the response value from each turn using .value property
40
- if response.value and response.value ~= "" then
41
- response_text = response_text .. response.value
39
+ -- Accumulate the response message from each turn using .message property
40
+ if response.message and response.message ~= "" then
41
+ response_text = response_text .. response.message
42
42
  end
43
43
 
44
44
  -- Safety check: exit if too many turns
@@ -137,8 +137,8 @@ Procedure {
137
137
  local response = agent_ref()
138
138
  turn_count = turn_count + 1
139
139
 
140
- if response.value and response.value ~= "" then
141
- response_text = response_text .. response.value
140
+ if response.message and response.message ~= "" then
141
+ response_text = response_text .. response.message
142
142
  end
143
143
 
144
144
  if turn_count >= max_turns then
@@ -175,7 +175,7 @@ Procedure {
175
175
  local success, result = pcall(function(input)
176
176
  local response = agent_ref()
177
177
  return {
178
- response = response.value or "",
178
+ response = response.message or "",
179
179
  turns = 1,
180
180
  success = true,
181
181
  error = nil
@@ -56,8 +56,8 @@ Procedure {
56
56
  pro_turns = pro_turns + 1
57
57
 
58
58
  -- Accumulate the response text
59
- if response.value and response.value ~= "" then
60
- pro_response = pro_response .. response.value
59
+ if response.message and response.message ~= "" then
60
+ pro_response = pro_response .. response.message
61
61
  end
62
62
 
63
63
  -- Safety check
@@ -86,8 +86,8 @@ Procedure {
86
86
  flash_turns = flash_turns + 1
87
87
 
88
88
  -- Accumulate the response text
89
- if response.value and response.value ~= "" then
90
- flash_response = flash_response .. response.value
89
+ if response.message and response.message ~= "" then
90
+ flash_response = flash_response .. response.message
91
91
  end
92
92
 
93
93
  -- Safety check
@@ -1,11 +1,11 @@
1
1
  -- Structured Output Demo
2
2
  -- Demonstrates using output for structured data extraction
3
- -- and accessing result.value, result.usage
3
+ -- and accessing result.data, result.usage
4
4
 
5
5
  extractor = Agent {
6
6
  provider = "openai",
7
7
  model = "gpt-4o-mini",
8
- system_prompt = [[You extract city information. Return ONLY a JSON object with these fields:
8
+ system_prompt = [[You extract city information. Return ONLY structured data with these fields:
9
9
  - city: city name
10
10
  - country: country name
11
11
  - population: estimated population (number, optional)
@@ -32,14 +32,14 @@ Procedure {
32
32
  function(input)
33
33
  Log.info("Starting structured output demo", {query = input.query})
34
34
 
35
- -- Agent returns a Result wrapper (not raw data)
35
+ -- Agent returns ResultPrimitive (not raw data)
36
36
  local result = extractor()
37
37
 
38
- -- Access structured data via result.value
38
+ -- Access structured data via result.data
39
39
  Log.info("Extracted city information", {
40
- city = result.value.city,
41
- country = result.value.country,
42
- population = result.value.population or "unknown"
40
+ city = result.data.city,
41
+ country = result.data.country,
42
+ population = result.data.population or "unknown"
43
43
  })
44
44
 
45
45
  -- Access token usage stats
@@ -49,8 +49,20 @@ Procedure {
49
49
  total_tokens = result.usage.total_tokens
50
50
  })
51
51
 
52
+ -- Access messages from this turn
53
+ local new_msgs = result.new_messages()
54
+ Log.info("Messages generated in this turn", {count = #new_msgs})
55
+
56
+ -- Log first message (if any)
57
+ if #new_msgs > 0 then
58
+ Log.info("First message", {
59
+ role = new_msgs[1].role,
60
+ content_preview = string.sub(new_msgs[1].content, 1, 100)
61
+ })
62
+ end
63
+
52
64
  return {
53
- city_data = result.value,
65
+ city_data = result.data,
54
66
  tokens_used = result.usage.total_tokens
55
67
  }
56
68
  end
@@ -50,4 +50,13 @@ Procedure {
50
50
  return {success = true}
51
51
 
52
52
  end
53
- }
53
+ }
54
+
55
+ Mocks {
56
+ tester = {
57
+ tool_calls = {
58
+ {tool = "done", args = {reason = "Completed per-turn tool control demo"}}
59
+ },
60
+ message = "No tools available"
61
+ }
62
+ }
@@ -83,7 +83,7 @@ Procedure {
83
83
  end
84
84
  else
85
85
  -- Max turns reached - use last response
86
- answer = tostring(result.value)
86
+ answer = result.message
87
87
  end
88
88
 
89
89
  return {
@@ -92,3 +92,13 @@ Procedure {
92
92
  }
93
93
  end
94
94
  }
95
+
96
+ Mocks {
97
+ assistant = {
98
+ tool_calls = {
99
+ {tool = "calculate_mortgage", args = {principal = 300000, annual_interest_rate = 0.065, years = 30}},
100
+ {tool = "done", args = {reason = "Monthly payment is $1,896.20 (mocked)."}}
101
+ },
102
+ message = "Monthly payment is $1,896.20 (mocked)."
103
+ }
104
+ }
@@ -103,7 +103,7 @@ Procedure {
103
103
  turn_count = turn_count + 1
104
104
  until done.called() or turn_count >= max_turns
105
105
 
106
- local response = tostring(result.value)
106
+ local response = result.message
107
107
  Log.info(agent_name .. " response", {text = response})
108
108
  return response
109
109
  end
@@ -123,7 +123,7 @@ Procedure {
123
123
  -- Test Agent 5: No tools (explicitly empty) - only needs 1 turn
124
124
  Log.info("Testing Agent 5: No tools")
125
125
  local observer_result = observer()
126
- local observer_response = tostring(observer_result.value)
126
+ local observer_response = observer_result.message
127
127
  Log.info("Observer response", {text = observer_response})
128
128
 
129
129
  return {
@@ -94,8 +94,7 @@ Procedure {
94
94
  else
95
95
  Log.warn("Agent did not call done within max turns")
96
96
  return {
97
- calculation_result = (result and result.value and tostring(result.value))
98
- or "Agent did not complete",
97
+ calculation_result = result.message or "Agent did not complete",
99
98
  completed = false
100
99
  }
101
100
  end
@@ -110,7 +110,7 @@ Procedure {
110
110
  if done.called() then
111
111
  answer = done.last_result() or "Task completed"
112
112
  else
113
- answer = tostring(result.value)
113
+ answer = result.message
114
114
  end
115
115
 
116
116
  return {
@@ -140,7 +140,7 @@ Procedure {
140
140
  if done.called() then
141
141
  answer = done.last_result() or "Task completed"
142
142
  else
143
- answer = tostring(result.value)
143
+ answer = result.message
144
144
  end
145
145
 
146
146
  if #tools_used > 0 then
@@ -158,7 +158,7 @@ Procedure {
158
158
  if done.called() then
159
159
  answer = done.last_result() or "Task completed"
160
160
  else
161
- answer = tostring(result.value)
161
+ answer = result.message
162
162
  end
163
163
 
164
164
  return {
@@ -47,29 +47,17 @@ Procedure {
47
47
  },
48
48
  function(input)
49
49
 
50
- -- Simple sentiment detection for demo/testing
51
- -- Note: Model primitive mocking not yet implemented, using simple heuristic
52
- local msg_lower = string.lower(input.customer_message)
53
- if string.find(msg_lower, "love") or string.find(msg_lower, "great") or string.find(msg_lower, "amazing") then
54
- State.sentiment = "positive"
55
- elseif string.find(msg_lower, "hate") or string.find(msg_lower, "terrible") or string.find(msg_lower, "awful") then
56
- State.sentiment = "negative"
57
- else
58
- State.sentiment = "neutral"
59
- end
50
+ -- 1. Classify sentiment with ML model (checkpointed)
51
+ State.sentiment = Model("sentiment_classifier").predict({
52
+ text = input.customer_message
53
+ })
60
54
 
61
- -- Agent responds based on sentiment (checkpointed)
55
+ -- 2. Agent responds based on sentiment (checkpointed)
62
56
  support_agent({message = input.customer_message})
63
57
 
64
- -- Get response from done tool
65
- local response = "Thank you for your message."
66
- if done.called() then
67
- response = done.last_result() or "I'm here to help."
68
- end
69
-
70
58
  return {
71
59
  sentiment = State.sentiment,
72
- response = response
60
+ response = support_agent.output
73
61
  }
74
62
 
75
63
  -- BDD Specifications
@@ -78,6 +66,9 @@ Procedure {
78
66
 
79
67
  -- Agent Mocks for CI testing
80
68
  Mocks {
69
+ sentiment_classifier = {
70
+ returns = "positive"
71
+ },
81
72
  support_agent = {
82
73
  tool_calls = {
83
74
  {tool = "done", args = {reason = "I'm happy to help! Thank you for your positive feedback."}}
@@ -13,7 +13,7 @@ local done = require("tactus.tools.done")
13
13
 
14
14
  -- Define a PyTorch sentiment classifier
15
15
  -- (This requires the .pt file to exist and PyTorch to be installed)
16
- -- Model "sentiment_classifier" { type = "pytorch", path = "models/sentiment.pt" }
16
+ Model "sentiment_classifier" { type = "pytorch", path = "models/sentiment.pt" }
17
17
 
18
18
  support_agent = Agent {
19
19
  provider = "openai",
@@ -31,7 +31,7 @@ Call done when finished.
31
31
 
32
32
  Procedure {
33
33
  input = {
34
- customer_message = field.string{required = true, description = "Customer message to analyze"}
34
+ customer_message = field.string{default = "I love this product!", description = "Customer message to analyze"}
35
35
  },
36
36
  output = {
37
37
  sentiment = field.string{required = true, description = "Detected sentiment label"},
@@ -39,29 +39,16 @@ Procedure {
39
39
  },
40
40
  function(input)
41
41
 
42
- -- Simple sentiment detection for demo/testing
43
- -- Note: PyTorch model mocking not yet implemented, using simple heuristic
44
- local msg_lower = string.lower(input.customer_message)
45
- if string.find(msg_lower, "love") or string.find(msg_lower, "great") then
46
- State.sentiment = "positive"
47
- elseif string.find(msg_lower, "hate") or string.find(msg_lower, "bad") then
48
- State.sentiment = "negative"
49
- else
50
- State.sentiment = "neutral"
51
- end
42
+ -- Classify sentiment with PyTorch model
43
+ -- Input: tensor of word indices (for demo, just pass a simple tensor)
44
+ State.sentiment = Model("sentiment_classifier").predict({1, 2, 3, 4, 5})
52
45
 
53
46
  -- Agent responds based on sentiment
54
47
  support_agent({message = input.customer_message})
55
48
 
56
- -- Get response from done tool
57
- local response = "I'm here to help."
58
- if done.called() then
59
- response = done.last_result() or "Thank you for your message."
60
- end
61
-
62
49
  return {
63
50
  sentiment = State.sentiment,
64
- response = response
51
+ response = support_agent.output
65
52
  }
66
53
 
67
54
  -- BDD Specifications
@@ -70,6 +57,9 @@ Procedure {
70
57
 
71
58
  -- Agent Mocks for CI testing
72
59
  Mocks {
60
+ sentiment_classifier = {
61
+ returns = "positive"
62
+ },
73
63
  support_agent = {
74
64
  tool_calls = {
75
65
  {tool = "done", args = {reason = "Based on the sentiment analysis, I've provided an appropriate response."}}
@@ -82,7 +72,6 @@ Specifications([[
82
72
  Feature: PyTorch Model Integration
83
73
  Scenario: PyTorch model performs inference
84
74
  Given the procedure has started
85
- And the input customer_message is "I love this product!"
86
75
  When the procedure runs
87
76
  Then the done tool should be called
88
77
  And the output sentiment should exist