tactus 0.25.0__tar.gz → 0.26.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 (560) hide show
  1. {tactus-0.25.0 → tactus-0.26.0}/CHANGELOG.md +8 -0
  2. {tactus-0.25.0 → tactus-0.26.0}/PKG-INFO +16 -1
  3. {tactus-0.25.0 → tactus-0.26.0}/README.md +15 -0
  4. {tactus-0.25.0 → tactus-0.26.0}/SPECIFICATION.md +18 -0
  5. {tactus-0.25.0 → tactus-0.26.0}/pyproject.toml +1 -1
  6. {tactus-0.25.0 → tactus-0.26.0}/tactus/__init__.py +1 -1
  7. {tactus-0.25.0 → tactus-0.26.0}/tactus/adapters/cli_hitl.py +2 -2
  8. tactus-0.26.0/tactus/adapters/cost_collector_log.py +56 -0
  9. {tactus-0.25.0 → tactus-0.26.0}/tactus/cli/app.py +99 -10
  10. {tactus-0.25.0 → tactus-0.26.0}/tactus/core/config_manager.py +2 -2
  11. {tactus-0.25.0 → tactus-0.26.0}/tactus/core/dsl_stubs.py +51 -43
  12. {tactus-0.25.0 → tactus-0.26.0}/tactus/core/execution_context.py +2 -2
  13. {tactus-0.25.0 → tactus-0.26.0}/tactus/core/lua_sandbox.py +2 -2
  14. {tactus-0.25.0 → tactus-0.26.0}/tactus/docker/Dockerfile +4 -0
  15. {tactus-0.25.0 → tactus-0.26.0}/tactus/dspy/agent.py +22 -7
  16. {tactus-0.25.0 → tactus-0.26.0}/tactus/primitives/handles.py +12 -12
  17. {tactus-0.25.0 → tactus-0.26.0}/tactus/sandbox/container_runner.py +122 -5
  18. {tactus-0.25.0 → tactus-0.26.0}/tactus/sandbox/docker_manager.py +16 -4
  19. {tactus-0.25.0 → tactus-0.26.0}/tactus/sandbox/entrypoint.py +30 -2
  20. tactus-0.26.0/tactus/stdlib/io/fs.py +154 -0
  21. {tactus-0.25.0 → tactus-0.26.0}/tactus/stdlib/loader.py +1 -1
  22. {tactus-0.25.0 → tactus-0.26.0}/tests/cli/test_cli.py +73 -0
  23. {tactus-0.25.0 → tactus-0.26.0}/.claude/agents.md +0 -0
  24. {tactus-0.25.0 → tactus-0.26.0}/.github/workflows/desktop-release.yml +0 -0
  25. {tactus-0.25.0 → tactus-0.26.0}/.github/workflows/release.yml +0 -0
  26. {tactus-0.25.0 → tactus-0.26.0}/.gitignore +0 -0
  27. {tactus-0.25.0 → tactus-0.26.0}/.tactus/config.yml.example +0 -0
  28. {tactus-0.25.0 → tactus-0.26.0}/AGENTS.md +0 -0
  29. {tactus-0.25.0 → tactus-0.26.0}/IMPLEMENTATION.md +0 -0
  30. {tactus-0.25.0 → tactus-0.26.0}/LICENSE +0 -0
  31. {tactus-0.25.0 → tactus-0.26.0}/Makefile +0 -0
  32. {tactus-0.25.0 → tactus-0.26.0}/TECHNICAL_DEBT.md +0 -0
  33. {tactus-0.25.0 → tactus-0.26.0}/behave.ini +0 -0
  34. {tactus-0.25.0 → tactus-0.26.0}/docs/AGENTS.md +0 -0
  35. {tactus-0.25.0 → tactus-0.26.0}/docs/BDD_TESTING.md +0 -0
  36. {tactus-0.25.0 → tactus-0.26.0}/docs/CONFIGURATION.md +0 -0
  37. {tactus-0.25.0 → tactus-0.26.0}/docs/DURABILITY.md +0 -0
  38. {tactus-0.25.0 → tactus-0.26.0}/docs/FILE_IO.md +0 -0
  39. {tactus-0.25.0 → tactus-0.26.0}/docs/SANDBOXING.md +0 -0
  40. {tactus-0.25.0 → tactus-0.26.0}/docs/STREAMING.md +0 -0
  41. {tactus-0.25.0 → tactus-0.26.0}/docs/TOOLS.md +0 -0
  42. {tactus-0.25.0 → tactus-0.26.0}/docs/TOOL_ROADMAP.md +0 -0
  43. {tactus-0.25.0 → tactus-0.26.0}/examples/.tactus/config.yml +0 -0
  44. {tactus-0.25.0 → tactus-0.26.0}/examples/01-basics-hello-world.tac +0 -0
  45. {tactus-0.25.0 → tactus-0.26.0}/examples/02-basics-simple-logic.tac +0 -0
  46. {tactus-0.25.0 → tactus-0.26.0}/examples/03-basics-parameters.tac +0 -0
  47. {tactus-0.25.0 → tactus-0.26.0}/examples/04-basics-simple-agent.tac +0 -0
  48. {tactus-0.25.0 → tactus-0.26.0}/examples/05-basics-multi-model.tac +0 -0
  49. {tactus-0.25.0 → tactus-0.26.0}/examples/06-basics-streaming.tac +0 -0
  50. {tactus-0.25.0 → tactus-0.26.0}/examples/07-basics-bedrock.tac +0 -0
  51. {tactus-0.25.0 → tactus-0.26.0}/examples/08-basics-models.tac +0 -0
  52. {tactus-0.25.0 → tactus-0.26.0}/examples/09-basics-google-gemini.tac +0 -0
  53. {tactus-0.25.0 → tactus-0.26.0}/examples/10-feature-state.tac +0 -0
  54. {tactus-0.25.0 → tactus-0.26.0}/examples/11-feature-message-history.tac +0 -0
  55. {tactus-0.25.0 → tactus-0.26.0}/examples/12-feature-structured-output.tac +0 -0
  56. {tactus-0.25.0 → tactus-0.26.0}/examples/13-feature-session.tac +0 -0
  57. {tactus-0.25.0 → tactus-0.26.0}/examples/14-feature-per-turn-tools-simple.tac +0 -0
  58. {tactus-0.25.0 → tactus-0.26.0}/examples/14-feature-per-turn-tools.tac +0 -0
  59. {tactus-0.25.0 → tactus-0.26.0}/examples/15-feature-local-tools.tac +0 -0
  60. {tactus-0.25.0 → tactus-0.26.0}/examples/16-feature-toolsets-advanced.tac +0 -0
  61. {tactus-0.25.0 → tactus-0.26.0}/examples/17-feature-toolsets-dsl.tac +0 -0
  62. {tactus-0.25.0 → tactus-0.26.0}/examples/18-feature-lua-tools-individual.tac +0 -0
  63. {tactus-0.25.0 → tactus-0.26.0}/examples/18-feature-lua-tools-inline.tac +0 -0
  64. {tactus-0.25.0 → tactus-0.26.0}/examples/18-feature-lua-tools-toolset.tac +0 -0
  65. {tactus-0.25.0 → tactus-0.26.0}/examples/19-feature-direct-tool-calls.tac +0 -0
  66. {tactus-0.25.0 → tactus-0.26.0}/examples/20-bdd-complete.tac +0 -0
  67. {tactus-0.25.0 → tactus-0.26.0}/examples/20-bdd-complete.tac.bak2 +0 -0
  68. {tactus-0.25.0 → tactus-0.26.0}/examples/21-bdd-passing.tac +0 -0
  69. {tactus-0.25.0 → tactus-0.26.0}/examples/21-bdd-passing.tac.bak2 +0 -0
  70. {tactus-0.25.0 → tactus-0.26.0}/examples/30-eval-simple.tac +0 -0
  71. {tactus-0.25.0 → tactus-0.26.0}/examples/31-eval-demo.tac +0 -0
  72. {tactus-0.25.0 → tactus-0.26.0}/examples/32-eval-success-rate.tac +0 -0
  73. {tactus-0.25.0 → tactus-0.26.0}/examples/33-eval-thresholds.tac +0 -0
  74. {tactus-0.25.0 → tactus-0.26.0}/examples/34-eval-dataset.jsonl +0 -0
  75. {tactus-0.25.0 → tactus-0.26.0}/examples/34-eval-dataset.tac +0 -0
  76. {tactus-0.25.0 → tactus-0.26.0}/examples/35-eval-trace.tac +0 -0
  77. {tactus-0.25.0 → tactus-0.26.0}/examples/35-eval-trace.tac.bak2 +0 -0
  78. {tactus-0.25.0 → tactus-0.26.0}/examples/36-eval-advanced.tac +0 -0
  79. {tactus-0.25.0 → tactus-0.26.0}/examples/37-eval-comprehensive.tac +0 -0
  80. {tactus-0.25.0 → tactus-0.26.0}/examples/37-eval-comprehensive.tac.bak2 +0 -0
  81. {tactus-0.25.0 → tactus-0.26.0}/examples/39-model-simple.tac +0 -0
  82. {tactus-0.25.0 → tactus-0.26.0}/examples/40-mcp-test.tac +0 -0
  83. {tactus-0.25.0 → tactus-0.26.0}/examples/40-model-text-classifier.tac +0 -0
  84. {tactus-0.25.0 → tactus-0.26.0}/examples/41-mcp-simple.tac +0 -0
  85. {tactus-0.25.0 → tactus-0.26.0}/examples/41-model-pytorch.tac +0 -0
  86. {tactus-0.25.0 → tactus-0.26.0}/examples/43-sub-procedure-simple.tac +0 -0
  87. {tactus-0.25.0 → tactus-0.26.0}/examples/44-sub-procedure-composition.tac +0 -0
  88. {tactus-0.25.0 → tactus-0.26.0}/examples/45-sub-procedure-recursive.tac +0 -0
  89. {tactus-0.25.0 → tactus-0.26.0}/examples/46-checkpoint-explicit.tac +0 -0
  90. {tactus-0.25.0 → tactus-0.26.0}/examples/47-checkpoint-expensive-ops.tac +0 -0
  91. {tactus-0.25.0 → tactus-0.26.0}/examples/48-script-mode-simple.tac +0 -0
  92. {tactus-0.25.0 → tactus-0.26.0}/examples/50-inputs-showcase.tac +0 -0
  93. {tactus-0.25.0 → tactus-0.26.0}/examples/51-inputs-calculator.tac +0 -0
  94. {tactus-0.25.0 → tactus-0.26.0}/examples/52-file-io-basics.tac +0 -0
  95. {tactus-0.25.0 → tactus-0.26.0}/examples/53-tsv-file-io.tac +0 -0
  96. {tactus-0.25.0 → tactus-0.26.0}/examples/54-json-file-io.tac +0 -0
  97. {tactus-0.25.0 → tactus-0.26.0}/examples/55-parquet-file-io.tac +0 -0
  98. {tactus-0.25.0 → tactus-0.26.0}/examples/56-hdf5-file-io.tac +0 -0
  99. {tactus-0.25.0 → tactus-0.26.0}/examples/57-excel-file-io.tac +0 -0
  100. {tactus-0.25.0 → tactus-0.26.0}/examples/58-text-file-io.tac +0 -0
  101. {tactus-0.25.0 → tactus-0.26.0}/examples/60-tool-sources.tac +0 -0
  102. {tactus-0.25.0 → tactus-0.26.0}/examples/61-inline-toolset-lua.tac +0 -0
  103. {tactus-0.25.0 → tactus-0.26.0}/examples/62-mcp-toolset-by-server.tac +0 -0
  104. {tactus-0.25.0 → tactus-0.26.0}/examples/63-toolset-import-from-file.tac +0 -0
  105. {tactus-0.25.0 → tactus-0.26.0}/examples/64-require-modules.tac +0 -0
  106. {tactus-0.25.0 → tactus-0.26.0}/examples/65-optional-state-demo.tac +0 -0
  107. {tactus-0.25.0 → tactus-0.26.0}/examples/70-mocking-static.tac +0 -0
  108. {tactus-0.25.0 → tactus-0.26.0}/examples/71-mocking-temporal.tac +0 -0
  109. {tactus-0.25.0 → tactus-0.26.0}/examples/72-mocking-conditional.tac +0 -0
  110. {tactus-0.25.0 → tactus-0.26.0}/examples/99-misc-test-loading.tac +0 -0
  111. {tactus-0.25.0 → tactus-0.26.0}/examples/README.md +0 -0
  112. {tactus-0.25.0 → tactus-0.26.0}/examples/app_config.ini +0 -0
  113. {tactus-0.25.0 → tactus-0.26.0}/examples/data/sample.csv +0 -0
  114. {tactus-0.25.0 → tactus-0.26.0}/examples/demo_output.json +0 -0
  115. {tactus-0.25.0 → tactus-0.26.0}/examples/helpers/math_module.tac +0 -0
  116. {tactus-0.25.0 → tactus-0.26.0}/examples/helpers/product.tac +0 -0
  117. {tactus-0.25.0 → tactus-0.26.0}/examples/helpers/string_module.tac +0 -0
  118. {tactus-0.25.0 → tactus-0.26.0}/examples/helpers/sum.tac +0 -0
  119. {tactus-0.25.0 → tactus-0.26.0}/examples/helpers/text_tools.tac +0 -0
  120. {tactus-0.25.0 → tactus-0.26.0}/examples/inventory_summary.tsv +0 -0
  121. {tactus-0.25.0 → tactus-0.26.0}/examples/mock-config.json +0 -0
  122. {tactus-0.25.0 → tactus-0.26.0}/examples/models/README.md +0 -0
  123. {tactus-0.25.0 → tactus-0.26.0}/examples/models/create_sentiment_model.py +0 -0
  124. {tactus-0.25.0 → tactus-0.26.0}/examples/output_summary.txt +0 -0
  125. {tactus-0.25.0 → tactus-0.26.0}/examples/test-raw-module.tac +0 -0
  126. {tactus-0.25.0 → tactus-0.26.0}/examples/test-raw-streaming.tac +0 -0
  127. {tactus-0.25.0 → tactus-0.26.0}/examples/tools/calculations.py +0 -0
  128. {tactus-0.25.0 → tactus-0.26.0}/examples/tools/data_analysis.py +0 -0
  129. {tactus-0.25.0 → tactus-0.26.0}/examples/tools/search.py +0 -0
  130. {tactus-0.25.0 → tactus-0.26.0}/examples/with_dependencies/README.md +0 -0
  131. {tactus-0.25.0 → tactus-0.26.0}/examples/with_dependencies/simple_http_test.tac +0 -0
  132. {tactus-0.25.0 → tactus-0.26.0}/examples/with_dependencies/time_lookup.tac +0 -0
  133. {tactus-0.25.0 → tactus-0.26.0}/features/01_state_management.feature +0 -0
  134. {tactus-0.25.0 → tactus-0.26.0}/features/02_checkpointing.feature +0 -0
  135. {tactus-0.25.0 → tactus-0.26.0}/features/03_human_in_the_loop.feature +0 -0
  136. {tactus-0.25.0 → tactus-0.26.0}/features/04_control_flow.feature +0 -0
  137. {tactus-0.25.0 → tactus-0.26.0}/features/05_tool_integration.feature +0 -0
  138. {tactus-0.25.0 → tactus-0.26.0}/features/06_retry_logic.feature +0 -0
  139. {tactus-0.25.0 → tactus-0.26.0}/features/07_file_operations.feature +0 -0
  140. {tactus-0.25.0 → tactus-0.26.0}/features/08_agent_primitives.feature +0 -0
  141. {tactus-0.25.0 → tactus-0.26.0}/features/09_workflow_execution.feature +0 -0
  142. {tactus-0.25.0 → tactus-0.26.0}/features/10_lua_integration.feature +0 -0
  143. {tactus-0.25.0 → tactus-0.26.0}/features/11_storage_backends.feature +0 -0
  144. {tactus-0.25.0 → tactus-0.26.0}/features/12_json_operations.feature +0 -0
  145. {tactus-0.25.0 → tactus-0.26.0}/features/13_logging.feature +0 -0
  146. {tactus-0.25.0 → tactus-0.26.0}/features/14_stage_and_step_tracking.feature +0 -0
  147. {tactus-0.25.0 → tactus-0.26.0}/features/15_procedure_calls.feature +0 -0
  148. {tactus-0.25.0 → tactus-0.26.0}/features/16_session_management.feature +0 -0
  149. {tactus-0.25.0 → tactus-0.26.0}/features/17_lua_dsl_validation.feature +0 -0
  150. {tactus-0.25.0 → tactus-0.26.0}/features/18_example_procedures.feature +0 -0
  151. {tactus-0.25.0 → tactus-0.26.0}/features/19_ide_server.feature +0 -0
  152. {tactus-0.25.0 → tactus-0.26.0}/features/20_parameters.feature +0 -0
  153. {tactus-0.25.0 → tactus-0.26.0}/features/21_outputs.feature +0 -0
  154. {tactus-0.25.0 → tactus-0.26.0}/features/23_prompts.feature +0 -0
  155. {tactus-0.25.0 → tactus-0.26.0}/features/24_bdd_specifications.feature +0 -0
  156. {tactus-0.25.0 → tactus-0.26.0}/features/25_bdd_custom_steps.feature +0 -0
  157. {tactus-0.25.0 → tactus-0.26.0}/features/26_bdd_evaluation.feature +0 -0
  158. {tactus-0.25.0 → tactus-0.26.0}/features/27_default_settings.feature +0 -0
  159. {tactus-0.25.0 → tactus-0.26.0}/features/28_custom_prompts.feature +0 -0
  160. {tactus-0.25.0 → tactus-0.26.0}/features/29_execution_settings.feature +0 -0
  161. {tactus-0.25.0 → tactus-0.26.0}/features/30_session_filters.feature +0 -0
  162. {tactus-0.25.0 → tactus-0.26.0}/features/31_matchers.feature +0 -0
  163. {tactus-0.25.0 → tactus-0.26.0}/features/32_result_object.feature +0 -0
  164. {tactus-0.25.0 → tactus-0.26.0}/features/33_output_type.feature +0 -0
  165. {tactus-0.25.0 → tactus-0.26.0}/features/42_model_primitive.feature +0 -0
  166. {tactus-0.25.0 → tactus-0.26.0}/features/43_sub_procedure_checkpointing.feature +0 -0
  167. {tactus-0.25.0 → tactus-0.26.0}/features/46_explicit_checkpoint.feature +0 -0
  168. {tactus-0.25.0 → tactus-0.26.0}/features/48_script_mode.feature +0 -0
  169. {tactus-0.25.0 → tactus-0.26.0}/features/51_dspy_lm_config.feature +0 -0
  170. {tactus-0.25.0 → tactus-0.26.0}/features/52_dspy_signature.feature +0 -0
  171. {tactus-0.25.0 → tactus-0.26.0}/features/53_dspy_module.feature +0 -0
  172. {tactus-0.25.0 → tactus-0.26.0}/features/54_dspy_history.feature +0 -0
  173. {tactus-0.25.0 → tactus-0.26.0}/features/55_dspy_prediction.feature +0 -0
  174. {tactus-0.25.0 → tactus-0.26.0}/features/56_dspy_agent.feature +0 -0
  175. {tactus-0.25.0 → tactus-0.26.0}/features/57_chat_assistant.feature +0 -0
  176. {tactus-0.25.0 → tactus-0.26.0}/features/documentation/IDE_SERVER_BEHAVIOR.md +0 -0
  177. {tactus-0.25.0 → tactus-0.26.0}/features/documentation/Lua DSL/README.md +0 -0
  178. {tactus-0.25.0 → tactus-0.26.0}/features/environment.py +0 -0
  179. {tactus-0.25.0 → tactus-0.26.0}/features/steps/agent_primitives_steps.py +0 -0
  180. {tactus-0.25.0 → tactus-0.26.0}/features/steps/chat_assistant_steps.py +0 -0
  181. {tactus-0.25.0 → tactus-0.26.0}/features/steps/checkpointing_steps.py +0 -0
  182. {tactus-0.25.0 → tactus-0.26.0}/features/steps/control_flow_steps.py +0 -0
  183. {tactus-0.25.0 → tactus-0.26.0}/features/steps/dspy_agent_steps.py +0 -0
  184. {tactus-0.25.0 → tactus-0.26.0}/features/steps/dspy_history_steps.py +0 -0
  185. {tactus-0.25.0 → tactus-0.26.0}/features/steps/dspy_lm_steps.py +0 -0
  186. {tactus-0.25.0 → tactus-0.26.0}/features/steps/dspy_module_steps.py +0 -0
  187. {tactus-0.25.0 → tactus-0.26.0}/features/steps/dspy_prediction_steps.py +0 -0
  188. {tactus-0.25.0 → tactus-0.26.0}/features/steps/dspy_signature_steps.py +0 -0
  189. {tactus-0.25.0 → tactus-0.26.0}/features/steps/example_procedures_steps.py +0 -0
  190. {tactus-0.25.0 → tactus-0.26.0}/features/steps/file_operations_steps.py +0 -0
  191. {tactus-0.25.0 → tactus-0.26.0}/features/steps/human_in_the_loop_steps.py +0 -0
  192. {tactus-0.25.0 → tactus-0.26.0}/features/steps/ide_server_steps.py +0 -0
  193. {tactus-0.25.0 → tactus-0.26.0}/features/steps/json_operations_steps.py +0 -0
  194. {tactus-0.25.0 → tactus-0.26.0}/features/steps/logging_steps.py +0 -0
  195. {tactus-0.25.0 → tactus-0.26.0}/features/steps/lua_dsl_validation_steps.py +0 -0
  196. {tactus-0.25.0 → tactus-0.26.0}/features/steps/lua_integration_steps.py +0 -0
  197. {tactus-0.25.0 → tactus-0.26.0}/features/steps/mocking_steps.py +0 -0
  198. {tactus-0.25.0 → tactus-0.26.0}/features/steps/procedure_calls_steps.py +0 -0
  199. {tactus-0.25.0 → tactus-0.26.0}/features/steps/result_and_output_steps.py +0 -0
  200. {tactus-0.25.0 → tactus-0.26.0}/features/steps/retry_logic_steps.py +0 -0
  201. {tactus-0.25.0 → tactus-0.26.0}/features/steps/session_management_steps.py +0 -0
  202. {tactus-0.25.0 → tactus-0.26.0}/features/steps/stage_tracking_steps.py +0 -0
  203. {tactus-0.25.0 → tactus-0.26.0}/features/steps/state_management_steps.py +0 -0
  204. {tactus-0.25.0 → tactus-0.26.0}/features/steps/storage_backend_steps.py +0 -0
  205. {tactus-0.25.0 → tactus-0.26.0}/features/steps/support/__init__.py +0 -0
  206. {tactus-0.25.0 → tactus-0.26.0}/features/steps/support/harnesses.py +0 -0
  207. {tactus-0.25.0 → tactus-0.26.0}/features/steps/tool_integration_steps.py +0 -0
  208. {tactus-0.25.0 → tactus-0.26.0}/features/steps/workflow_execution_steps.py +0 -0
  209. {tactus-0.25.0 → tactus-0.26.0}/scripts/audit_examples_mocking.py +0 -0
  210. {tactus-0.25.0 → tactus-0.26.0}/scripts/convert_examples.py +0 -0
  211. {tactus-0.25.0 → tactus-0.26.0}/start-web-ide.sh +0 -0
  212. {tactus-0.25.0 → tactus-0.26.0}/tactus/adapters/__init__.py +0 -0
  213. {tactus-0.25.0 → tactus-0.26.0}/tactus/adapters/cli_log.py +0 -0
  214. {tactus-0.25.0 → tactus-0.26.0}/tactus/adapters/file_storage.py +0 -0
  215. {tactus-0.25.0 → tactus-0.26.0}/tactus/adapters/http_callback_log.py +0 -0
  216. {tactus-0.25.0 → tactus-0.26.0}/tactus/adapters/ide_log.py +0 -0
  217. {tactus-0.25.0 → tactus-0.26.0}/tactus/adapters/lua_tools.py +0 -0
  218. {tactus-0.25.0 → tactus-0.26.0}/tactus/adapters/mcp.py +0 -0
  219. {tactus-0.25.0 → tactus-0.26.0}/tactus/adapters/mcp_manager.py +0 -0
  220. {tactus-0.25.0 → tactus-0.26.0}/tactus/adapters/memory.py +0 -0
  221. {tactus-0.25.0 → tactus-0.26.0}/tactus/adapters/plugins.py +0 -0
  222. {tactus-0.25.0 → tactus-0.26.0}/tactus/backends/http_backend.py +0 -0
  223. {tactus-0.25.0 → tactus-0.26.0}/tactus/backends/model_backend.py +0 -0
  224. {tactus-0.25.0 → tactus-0.26.0}/tactus/backends/pytorch_backend.py +0 -0
  225. {tactus-0.25.0 → tactus-0.26.0}/tactus/cli/__init__.py +0 -0
  226. {tactus-0.25.0 → tactus-0.26.0}/tactus/cli/commands/__init__.py +0 -0
  227. {tactus-0.25.0 → tactus-0.26.0}/tactus/core/__init__.py +0 -0
  228. {tactus-0.25.0 → tactus-0.26.0}/tactus/core/dependencies/__init__.py +0 -0
  229. {tactus-0.25.0 → tactus-0.26.0}/tactus/core/dependencies/registry.py +0 -0
  230. {tactus-0.25.0 → tactus-0.26.0}/tactus/core/exceptions.py +0 -0
  231. {tactus-0.25.0 → tactus-0.26.0}/tactus/core/message_history_manager.py +0 -0
  232. {tactus-0.25.0 → tactus-0.26.0}/tactus/core/mocking.py +0 -0
  233. {tactus-0.25.0 → tactus-0.26.0}/tactus/core/output_validator.py +0 -0
  234. {tactus-0.25.0 → tactus-0.26.0}/tactus/core/registry.py +0 -0
  235. {tactus-0.25.0 → tactus-0.26.0}/tactus/core/runtime.py +0 -0
  236. {tactus-0.25.0 → tactus-0.26.0}/tactus/core/template_resolver.py +0 -0
  237. {tactus-0.25.0 → tactus-0.26.0}/tactus/core/yaml_parser.py +0 -0
  238. {tactus-0.25.0 → tactus-0.26.0}/tactus/docker/entrypoint.sh +0 -0
  239. {tactus-0.25.0 → tactus-0.26.0}/tactus/dspy/__init__.py +0 -0
  240. {tactus-0.25.0 → tactus-0.26.0}/tactus/dspy/config.py +0 -0
  241. {tactus-0.25.0 → tactus-0.26.0}/tactus/dspy/history.py +0 -0
  242. {tactus-0.25.0 → tactus-0.26.0}/tactus/dspy/module.py +0 -0
  243. {tactus-0.25.0 → tactus-0.26.0}/tactus/dspy/prediction.py +0 -0
  244. {tactus-0.25.0 → tactus-0.26.0}/tactus/dspy/signature.py +0 -0
  245. {tactus-0.25.0 → tactus-0.26.0}/tactus/ide/__init__.py +0 -0
  246. {tactus-0.25.0 → tactus-0.26.0}/tactus/ide/coding_assistant.py +0 -0
  247. {tactus-0.25.0 → tactus-0.26.0}/tactus/ide/server.py +0 -0
  248. {tactus-0.25.0 → tactus-0.26.0}/tactus/primitives/__init__.py +0 -0
  249. {tactus-0.25.0 → tactus-0.26.0}/tactus/primitives/control.py +0 -0
  250. {tactus-0.25.0 → tactus-0.26.0}/tactus/primitives/file.py +0 -0
  251. {tactus-0.25.0 → tactus-0.26.0}/tactus/primitives/human.py +0 -0
  252. {tactus-0.25.0 → tactus-0.26.0}/tactus/primitives/json.py +0 -0
  253. {tactus-0.25.0 → tactus-0.26.0}/tactus/primitives/log.py +0 -0
  254. {tactus-0.25.0 → tactus-0.26.0}/tactus/primitives/message_history.py +0 -0
  255. {tactus-0.25.0 → tactus-0.26.0}/tactus/primitives/model.py +0 -0
  256. {tactus-0.25.0 → tactus-0.26.0}/tactus/primitives/procedure.py +0 -0
  257. {tactus-0.25.0 → tactus-0.26.0}/tactus/primitives/procedure_callable.py +0 -0
  258. {tactus-0.25.0 → tactus-0.26.0}/tactus/primitives/retry.py +0 -0
  259. {tactus-0.25.0 → tactus-0.26.0}/tactus/primitives/session.py +0 -0
  260. {tactus-0.25.0 → tactus-0.26.0}/tactus/primitives/stage.py +0 -0
  261. {tactus-0.25.0 → tactus-0.26.0}/tactus/primitives/state.py +0 -0
  262. {tactus-0.25.0 → tactus-0.26.0}/tactus/primitives/step.py +0 -0
  263. {tactus-0.25.0 → tactus-0.26.0}/tactus/primitives/system.py +0 -0
  264. {tactus-0.25.0 → tactus-0.26.0}/tactus/primitives/tool.py +0 -0
  265. {tactus-0.25.0 → tactus-0.26.0}/tactus/primitives/tool_handle.py +0 -0
  266. {tactus-0.25.0 → tactus-0.26.0}/tactus/primitives/toolset.py +0 -0
  267. {tactus-0.25.0 → tactus-0.26.0}/tactus/protocols/__init__.py +0 -0
  268. {tactus-0.25.0 → tactus-0.26.0}/tactus/protocols/chat_recorder.py +0 -0
  269. {tactus-0.25.0 → tactus-0.26.0}/tactus/protocols/config.py +0 -0
  270. {tactus-0.25.0 → tactus-0.26.0}/tactus/protocols/cost.py +0 -0
  271. {tactus-0.25.0 → tactus-0.26.0}/tactus/protocols/hitl.py +0 -0
  272. {tactus-0.25.0 → tactus-0.26.0}/tactus/protocols/log_handler.py +0 -0
  273. {tactus-0.25.0 → tactus-0.26.0}/tactus/protocols/models.py +0 -0
  274. {tactus-0.25.0 → tactus-0.26.0}/tactus/protocols/result.py +0 -0
  275. {tactus-0.25.0 → tactus-0.26.0}/tactus/protocols/storage.py +0 -0
  276. {tactus-0.25.0 → tactus-0.26.0}/tactus/providers/__init__.py +0 -0
  277. {tactus-0.25.0 → tactus-0.26.0}/tactus/providers/base.py +0 -0
  278. {tactus-0.25.0 → tactus-0.26.0}/tactus/providers/bedrock.py +0 -0
  279. {tactus-0.25.0 → tactus-0.26.0}/tactus/providers/google.py +0 -0
  280. {tactus-0.25.0 → tactus-0.26.0}/tactus/providers/openai.py +0 -0
  281. {tactus-0.25.0 → tactus-0.26.0}/tactus/sandbox/__init__.py +0 -0
  282. {tactus-0.25.0 → tactus-0.26.0}/tactus/sandbox/config.py +0 -0
  283. {tactus-0.25.0 → tactus-0.26.0}/tactus/sandbox/protocol.py +0 -0
  284. {tactus-0.25.0 → tactus-0.26.0}/tactus/stdlib/__init__.py +0 -0
  285. {tactus-0.25.0 → tactus-0.26.0}/tactus/stdlib/io/__init__.py +0 -0
  286. {tactus-0.25.0 → tactus-0.26.0}/tactus/stdlib/io/csv.py +0 -0
  287. {tactus-0.25.0 → tactus-0.26.0}/tactus/stdlib/io/excel.py +0 -0
  288. {tactus-0.25.0 → tactus-0.26.0}/tactus/stdlib/io/file.py +0 -0
  289. {tactus-0.25.0 → tactus-0.26.0}/tactus/stdlib/io/hdf5.py +0 -0
  290. {tactus-0.25.0 → tactus-0.26.0}/tactus/stdlib/io/json.py +0 -0
  291. {tactus-0.25.0 → tactus-0.26.0}/tactus/stdlib/io/parquet.py +0 -0
  292. {tactus-0.25.0 → tactus-0.26.0}/tactus/stdlib/io/tsv.py +0 -0
  293. {tactus-0.25.0 → tactus-0.26.0}/tactus/stdlib/tac/tactus/tools/done.tac +0 -0
  294. {tactus-0.25.0 → tactus-0.26.0}/tactus/stdlib/tac/tactus/tools/log.tac +0 -0
  295. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/README.md +0 -0
  296. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/__init__.py +0 -0
  297. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/behave_integration.py +0 -0
  298. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/context.py +0 -0
  299. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/eval_models.py +0 -0
  300. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/evaluation_runner.py +0 -0
  301. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/evaluators.py +0 -0
  302. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/events.py +0 -0
  303. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/gherkin_parser.py +0 -0
  304. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/mock_agent.py +0 -0
  305. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/mock_dependencies.py +0 -0
  306. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/mock_hitl.py +0 -0
  307. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/mock_registry.py +0 -0
  308. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/mock_tools.py +0 -0
  309. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/models.py +0 -0
  310. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/pydantic_eval_runner.py +0 -0
  311. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/steps/__init__.py +0 -0
  312. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/steps/builtin.py +0 -0
  313. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/steps/custom.py +0 -0
  314. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/steps/registry.py +0 -0
  315. {tactus-0.25.0 → tactus-0.26.0}/tactus/testing/test_runner.py +0 -0
  316. {tactus-0.25.0 → tactus-0.26.0}/tactus/tracing/__init__.py +0 -0
  317. {tactus-0.25.0 → tactus-0.26.0}/tactus/tracing/trace_manager.py +0 -0
  318. {tactus-0.25.0 → tactus-0.26.0}/tactus/utils/__init__.py +0 -0
  319. {tactus-0.25.0 → tactus-0.26.0}/tactus/utils/cost_calculator.py +0 -0
  320. {tactus-0.25.0 → tactus-0.26.0}/tactus/utils/model_pricing.py +0 -0
  321. {tactus-0.25.0 → tactus-0.26.0}/tactus/utils/safe_file_library.py +0 -0
  322. {tactus-0.25.0 → tactus-0.26.0}/tactus/utils/safe_libraries.py +0 -0
  323. {tactus-0.25.0 → tactus-0.26.0}/tactus/validation/LuaLexerBase.py +0 -0
  324. {tactus-0.25.0 → tactus-0.26.0}/tactus/validation/LuaParserBase.py +0 -0
  325. {tactus-0.25.0 → tactus-0.26.0}/tactus/validation/README.md +0 -0
  326. {tactus-0.25.0 → tactus-0.26.0}/tactus/validation/__init__.py +0 -0
  327. {tactus-0.25.0 → tactus-0.26.0}/tactus/validation/error_listener.py +0 -0
  328. {tactus-0.25.0 → tactus-0.26.0}/tactus/validation/generated/LuaLexer.interp +0 -0
  329. {tactus-0.25.0 → tactus-0.26.0}/tactus/validation/generated/LuaLexer.py +0 -0
  330. {tactus-0.25.0 → tactus-0.26.0}/tactus/validation/generated/LuaLexer.tokens +0 -0
  331. {tactus-0.25.0 → tactus-0.26.0}/tactus/validation/generated/LuaLexerBase.py +0 -0
  332. {tactus-0.25.0 → tactus-0.26.0}/tactus/validation/generated/LuaParser.interp +0 -0
  333. {tactus-0.25.0 → tactus-0.26.0}/tactus/validation/generated/LuaParser.py +0 -0
  334. {tactus-0.25.0 → tactus-0.26.0}/tactus/validation/generated/LuaParser.tokens +0 -0
  335. {tactus-0.25.0 → tactus-0.26.0}/tactus/validation/generated/LuaParserBase.py +0 -0
  336. {tactus-0.25.0 → tactus-0.26.0}/tactus/validation/generated/LuaParserVisitor.py +0 -0
  337. {tactus-0.25.0 → tactus-0.26.0}/tactus/validation/generated/__init__.py +0 -0
  338. {tactus-0.25.0 → tactus-0.26.0}/tactus/validation/grammar/LuaLexer.g4 +0 -0
  339. {tactus-0.25.0 → tactus-0.26.0}/tactus/validation/grammar/LuaParser.g4 +0 -0
  340. {tactus-0.25.0 → tactus-0.26.0}/tactus/validation/semantic_visitor.py +0 -0
  341. {tactus-0.25.0 → tactus-0.26.0}/tactus/validation/validator.py +0 -0
  342. {tactus-0.25.0 → tactus-0.26.0}/tactus-desktop/.gitignore +0 -0
  343. {tactus-0.25.0 → tactus-0.26.0}/tactus-desktop/README.md +0 -0
  344. {tactus-0.25.0 → tactus-0.26.0}/tactus-desktop/RUN_ELECTRON.md +0 -0
  345. {tactus-0.25.0 → tactus-0.26.0}/tactus-desktop/SETUP_COMPLETE.md +0 -0
  346. {tactus-0.25.0 → tactus-0.26.0}/tactus-desktop/backend/hook-lupa.py +0 -0
  347. {tactus-0.25.0 → tactus-0.26.0}/tactus-desktop/backend/tactus_backend.spec +0 -0
  348. {tactus-0.25.0 → tactus-0.26.0}/tactus-desktop/package-lock.json +0 -0
  349. {tactus-0.25.0 → tactus-0.26.0}/tactus-desktop/package.json +0 -0
  350. {tactus-0.25.0 → tactus-0.26.0}/tactus-desktop/preload/preload.ts +0 -0
  351. {tactus-0.25.0 → tactus-0.26.0}/tactus-desktop/preload/tsconfig.json +0 -0
  352. {tactus-0.25.0 → tactus-0.26.0}/tactus-desktop/rebuild-and-test.sh +0 -0
  353. {tactus-0.25.0 → tactus-0.26.0}/tactus-desktop/scripts/build-backend.js +0 -0
  354. {tactus-0.25.0 → tactus-0.26.0}/tactus-desktop/scripts/build-frontend.js +0 -0
  355. {tactus-0.25.0 → tactus-0.26.0}/tactus-desktop/src/backend-manager.ts +0 -0
  356. {tactus-0.25.0 → tactus-0.26.0}/tactus-desktop/src/main.ts +0 -0
  357. {tactus-0.25.0 → tactus-0.26.0}/tactus-desktop/src/menu.ts +0 -0
  358. {tactus-0.25.0 → tactus-0.26.0}/tactus-desktop/tsconfig.json +0 -0
  359. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/ARCHITECTURE.md +0 -0
  360. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/CHANGELOG.md +0 -0
  361. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/DEV_MODE.md +0 -0
  362. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/QUICK_START.md +0 -0
  363. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/README.md +0 -0
  364. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/RESTART_INSTRUCTIONS.md +0 -0
  365. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/TROUBLESHOOTING.md +0 -0
  366. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/backend/README.md +0 -0
  367. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/backend/assistant_service.py +0 -0
  368. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/backend/assistant_tools.py +0 -0
  369. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/backend/chat_server.py +0 -0
  370. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/backend/config_server.py +0 -0
  371. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/backend/events.py +0 -0
  372. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/backend/logging_capture.py +0 -0
  373. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/backend/lsp_server.py +0 -0
  374. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/backend/requirements.txt +0 -0
  375. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/backend/tactus_lsp_handler.py +0 -0
  376. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/backend/test_lsp_server.py +0 -0
  377. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/backend/text_editor_tool.py +0 -0
  378. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/dev.sh +0 -0
  379. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/.storybook/main.ts +0 -0
  380. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/.storybook/preview.ts +0 -0
  381. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/.storybook/vitest.setup.ts +0 -0
  382. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/README.md +0 -0
  383. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/demo.ts +0 -0
  384. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/index.html +0 -0
  385. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/jest.config.js +0 -0
  386. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/package-lock.json +0 -0
  387. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/package.json +0 -0
  388. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/postcss.config.js +0 -0
  389. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/App.tsx +0 -0
  390. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/Editor.tsx +0 -0
  391. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/LSPClient.ts +0 -0
  392. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/LSPClientHTTP.ts +0 -0
  393. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/TactusLanguage.ts +0 -0
  394. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/commands/registry.ts +0 -0
  395. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/AboutDialog.tsx +0 -0
  396. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ChatSidebar.tsx +0 -0
  397. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/CheckpointSummary.tsx +0 -0
  398. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/CollapsibleRun.tsx +0 -0
  399. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/Duration.stories.tsx +0 -0
  400. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/Duration.tsx +0 -0
  401. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/FileTree.stories.tsx +0 -0
  402. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/FileTree.tsx +0 -0
  403. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/MessageFeed.tsx +0 -0
  404. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/PreferencesView.tsx +0 -0
  405. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ProcedureInputsDisplay.stories.tsx +0 -0
  406. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ProcedureInputsDisplay.tsx +0 -0
  407. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ProcedureInputsModal.stories.tsx +0 -0
  408. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ProcedureInputsModal.tsx +0 -0
  409. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ProcedureTab.stories.tsx +0 -0
  410. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ProcedureTab.tsx +0 -0
  411. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ResizeHandle.tsx +0 -0
  412. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ResultsSidebar.stories.tsx +0 -0
  413. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ResultsSidebar.tsx +0 -0
  414. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/TestOptionsModal.tsx +0 -0
  415. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/Timestamp.stories.tsx +0 -0
  416. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/Timestamp.tsx +0 -0
  417. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/TopMenuBar.stories.tsx +0 -0
  418. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/chat/ChatInterface.tsx +0 -0
  419. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/chat/MessageInput.tsx +0 -0
  420. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/chat/MessageList.tsx +0 -0
  421. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/debugger/CheckpointDetails.stories.tsx +0 -0
  422. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/debugger/CheckpointDetails.tsx +0 -0
  423. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/debugger/CheckpointList.stories.tsx +0 -0
  424. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/debugger/CheckpointList.tsx +0 -0
  425. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/debugger/DebuggerPanel.stories.tsx +0 -0
  426. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/debugger/DebuggerPanel.tsx +0 -0
  427. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/debugger/RunSelector.stories.tsx +0 -0
  428. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/debugger/RunSelector.tsx +0 -0
  429. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/debugger/StatisticsPanel.stories.tsx +0 -0
  430. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/debugger/StatisticsPanel.tsx +0 -0
  431. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/AgentStreamingComponent.tsx +0 -0
  432. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/BaseEventComponent.tsx +0 -0
  433. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/CheckpointEventComponent.tsx +0 -0
  434. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/CollapsibleTestScenario.tsx +0 -0
  435. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/ContainerStatusEventComponent.tsx +0 -0
  436. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/CostEventComponent.stories.tsx +0 -0
  437. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/CostEventComponent.tsx +0 -0
  438. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/EvaluationEventComponent.stories.tsx +0 -0
  439. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/EvaluationEventComponent.tsx +0 -0
  440. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/EventRenderer.tsx +0 -0
  441. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/ExecutionEventComponent.stories.tsx +0 -0
  442. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/ExecutionEventComponent.tsx +0 -0
  443. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/ExecutionSummaryEventComponent.stories.tsx +0 -0
  444. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/ExecutionSummaryEventComponent.tsx +0 -0
  445. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/LoadingEventComponent.stories.tsx +0 -0
  446. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/LoadingEventComponent.tsx +0 -0
  447. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/LogCluster.tsx +0 -0
  448. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/LogEventComponent.stories.tsx +0 -0
  449. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/LogEventComponent.tsx +0 -0
  450. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/OutputEventComponent.stories.tsx +0 -0
  451. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/OutputEventComponent.tsx +0 -0
  452. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/TestEventComponent.stories.tsx +0 -0
  453. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/TestEventComponent.tsx +0 -0
  454. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/TestProgressContainer.tsx +0 -0
  455. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/ToolCallEventComponent.tsx +0 -0
  456. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/ValidationEventComponent.stories.tsx +0 -0
  457. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/events/ValidationEventComponent.tsx +0 -0
  458. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/metadata/AgentsSection.tsx +0 -0
  459. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/metadata/EvaluationsSection.tsx +0 -0
  460. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/metadata/MetadataSections.stories.tsx +0 -0
  461. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/metadata/OutputsSection.tsx +0 -0
  462. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/metadata/ParametersSection.tsx +0 -0
  463. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/metadata/SpecificationsSection.tsx +0 -0
  464. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/metadata/StagesSection.tsx +0 -0
  465. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/metadata/ToolsSection.tsx +0 -0
  466. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/preferences/ConfigFieldView.tsx +0 -0
  467. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/preferences/SourceBadge.tsx +0 -0
  468. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/preferences/YamlCodeEditor.tsx +0 -0
  469. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/scenarios/EvaluateScenarios.stories.tsx +0 -0
  470. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/scenarios/RunScenarios.stories.tsx +0 -0
  471. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/scenarios/TestScenarios.stories.tsx +0 -0
  472. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/scenarios/ValidationScenarios.stories.tsx +0 -0
  473. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/theme-provider.tsx +0 -0
  474. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ui/ai/conversation.tsx +0 -0
  475. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ui/ai/message.tsx +0 -0
  476. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ui/ai/prompt-input.tsx +0 -0
  477. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ui/badge.tsx +0 -0
  478. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ui/button.tsx +0 -0
  479. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ui/dialog.tsx +0 -0
  480. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ui/dropdown-menu.tsx +0 -0
  481. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ui/input.tsx +0 -0
  482. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ui/label.tsx +0 -0
  483. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ui/logo.stories.tsx +0 -0
  484. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ui/logo.tsx +0 -0
  485. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ui/menubar.tsx +0 -0
  486. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ui/scroll-area.tsx +0 -0
  487. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ui/select.tsx +0 -0
  488. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ui/separator.tsx +0 -0
  489. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ui/switch.tsx +0 -0
  490. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ui/tabs.tsx +0 -0
  491. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/components/ui/tooltip.tsx +0 -0
  492. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/hooks/useChatSSE.ts +0 -0
  493. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/hooks/useEventStream.ts +0 -0
  494. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/hooks/useTracing.ts +0 -0
  495. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/index.css +0 -0
  496. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/lib/utils.ts +0 -0
  497. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/main.tsx +0 -0
  498. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/types/events.ts +0 -0
  499. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/types/metadata.ts +0 -0
  500. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/types/preferences.ts +0 -0
  501. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/types/results.ts +0 -0
  502. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/types/tracing.ts +0 -0
  503. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/utils/yamlSync.ts +0 -0
  504. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/validation/TactusValidator.ts +0 -0
  505. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/validation/generated/LuaParser.interp +0 -0
  506. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/validation/generated/LuaParser.tokens +0 -0
  507. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/validation/types.ts +0 -0
  508. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/src/vite-env.d.ts +0 -0
  509. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/tailwind.config.js +0 -0
  510. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/tsconfig.json +0 -0
  511. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/tsconfig.node.json +0 -0
  512. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/vite.config.ts +0 -0
  513. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/frontend/vitest.shims.d.ts +0 -0
  514. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/package.json +0 -0
  515. {tactus-0.25.0 → tactus-0.26.0}/tactus-ide/start-dev.sh +0 -0
  516. {tactus-0.25.0 → tactus-0.26.0}/tests/__init__.py +0 -0
  517. {tactus-0.25.0 → tactus-0.26.0}/tests/adapters/__init__.py +0 -0
  518. {tactus-0.25.0 → tactus-0.26.0}/tests/adapters/test_lua_tools_adapter.py +0 -0
  519. {tactus-0.25.0 → tactus-0.26.0}/tests/adapters/test_plugins.py +0 -0
  520. {tactus-0.25.0 → tactus-0.26.0}/tests/cli/__init__.py +0 -0
  521. {tactus-0.25.0 → tactus-0.26.0}/tests/cli/test_cli_inputs.py +0 -0
  522. {tactus-0.25.0 → tactus-0.26.0}/tests/conftest.py +0 -0
  523. {tactus-0.25.0 → tactus-0.26.0}/tests/core/__init__.py +0 -0
  524. {tactus-0.25.0 → tactus-0.26.0}/tests/core/test_config_manager.py +0 -0
  525. {tactus-0.25.0 → tactus-0.26.0}/tests/core/test_determinism_safety.py +0 -0
  526. {tactus-0.25.0 → tactus-0.26.0}/tests/core/test_lua_sandbox_security.py +0 -0
  527. {tactus-0.25.0 → tactus-0.26.0}/tests/core/test_runtime_inputs.py +0 -0
  528. {tactus-0.25.0 → tactus-0.26.0}/tests/core/test_script_mode.py +0 -0
  529. {tactus-0.25.0 → tactus-0.26.0}/tests/dspy/__init__.py +0 -0
  530. {tactus-0.25.0 → tactus-0.26.0}/tests/dspy/test_module_parameter.py +0 -0
  531. {tactus-0.25.0 → tactus-0.26.0}/tests/dspy/test_streaming.py +0 -0
  532. {tactus-0.25.0 → tactus-0.26.0}/tests/fixtures/__init__.py +0 -0
  533. {tactus-0.25.0 → tactus-0.26.0}/tests/fixtures/test_mcp_server.py +0 -0
  534. {tactus-0.25.0 → tactus-0.26.0}/tests/integration/test_named_procedures.py +0 -0
  535. {tactus-0.25.0 → tactus-0.26.0}/tests/mocks/__init__.py +0 -0
  536. {tactus-0.25.0 → tactus-0.26.0}/tests/mocks/llm_mocks.py +0 -0
  537. {tactus-0.25.0 → tactus-0.26.0}/tests/primitives/test_checkpoint_primitive.py +0 -0
  538. {tactus-0.25.0 → tactus-0.26.0}/tests/primitives/test_retry_primitive.py +0 -0
  539. {tactus-0.25.0 → tactus-0.26.0}/tests/primitives/test_state_primitive.py +0 -0
  540. {tactus-0.25.0 → tactus-0.26.0}/tests/primitives/test_system_alert.py +0 -0
  541. {tactus-0.25.0 → tactus-0.26.0}/tests/primitives/test_tool_primitive.py +0 -0
  542. {tactus-0.25.0 → tactus-0.26.0}/tests/primitives/test_toolset_dsl.py +0 -0
  543. {tactus-0.25.0 → tactus-0.26.0}/tests/stdlib/__init__.py +0 -0
  544. {tactus-0.25.0 → tactus-0.26.0}/tests/stdlib/test_loader.py +0 -0
  545. {tactus-0.25.0 → tactus-0.26.0}/tests/stdlib/test_require_python.py +0 -0
  546. {tactus-0.25.0 → tactus-0.26.0}/tests/test_checkpoints_integration.py +0 -0
  547. {tactus-0.25.0 → tactus-0.26.0}/tests/test_mcp_integration.py +0 -0
  548. {tactus-0.25.0 → tactus-0.26.0}/tests/test_tracing.py +0 -0
  549. {tactus-0.25.0 → tactus-0.26.0}/tests/testing/__init__.py +0 -0
  550. {tactus-0.25.0 → tactus-0.26.0}/tests/testing/conftest.py +0 -0
  551. {tactus-0.25.0 → tactus-0.26.0}/tests/testing/test_all_examples.py +0 -0
  552. {tactus-0.25.0 → tactus-0.26.0}/tests/testing/test_e2e.py +0 -0
  553. {tactus-0.25.0 → tactus-0.26.0}/tests/testing/test_gherkin_parser.py +0 -0
  554. {tactus-0.25.0 → tactus-0.26.0}/tests/testing/test_integration.py +0 -0
  555. {tactus-0.25.0 → tactus-0.26.0}/tests/testing/test_models.py +0 -0
  556. {tactus-0.25.0 → tactus-0.26.0}/tests/testing/test_runtime_integration.py +0 -0
  557. {tactus-0.25.0 → tactus-0.26.0}/tests/testing/test_step_registry.py +0 -0
  558. {tactus-0.25.0 → tactus-0.26.0}/tests/utils/__init__.py +0 -0
  559. {tactus-0.25.0 → tactus-0.26.0}/tests/utils/test_safe_file_library.py +0 -0
  560. {tactus-0.25.0 → tactus-0.26.0}/tests/validation/__init__.py +0 -0
@@ -2,6 +2,14 @@
2
2
 
3
3
  <!-- version list -->
4
4
 
5
+ ## v0.26.0 (2026-01-11)
6
+
7
+ ### Features
8
+
9
+ - Improve logging UX and fs helpers (#26) ([#26](https://github.com/AnthusAI/Tactus/pull/26),
10
+ [`a2a8704`](https://github.com/AnthusAI/Tactus/commit/a2a8704c1a0ab3b2cad45b9514af2152d12faa3b))
11
+
12
+
5
13
  ## v0.25.0 (2026-01-11)
6
14
 
7
15
  ### Features
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tactus
3
- Version: 0.25.0
3
+ Version: 0.26.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
@@ -1488,6 +1488,21 @@ tactus run workflow.tac # If procedure has required inputs, you'll be prompted
1488
1488
  tactus run workflow.tac --storage file --storage-path ./data
1489
1489
  ```
1490
1490
 
1491
+ #### Logging Options
1492
+
1493
+ The `run` command supports filtering and formatting logs:
1494
+
1495
+ ```bash
1496
+ # Show less/more output
1497
+ tactus run workflow.tac --log-level warning
1498
+ tactus run workflow.tac --log-level debug
1499
+
1500
+ # Choose a log format
1501
+ tactus run workflow.tac --log-format rich # default, grouped timestamps
1502
+ tactus run workflow.tac --log-format terminal # no timestamps, higher-signal terminal output
1503
+ tactus run workflow.tac --log-format raw # one-line-per-record, timestamped (CloudWatch-friendly)
1504
+ ```
1505
+
1491
1506
  The CLI automatically parses parameter types:
1492
1507
  - **Strings**: Direct values or quoted strings
1493
1508
  - **Numbers**: Integers or floats are auto-detected
@@ -1437,6 +1437,21 @@ tactus run workflow.tac # If procedure has required inputs, you'll be prompted
1437
1437
  tactus run workflow.tac --storage file --storage-path ./data
1438
1438
  ```
1439
1439
 
1440
+ #### Logging Options
1441
+
1442
+ The `run` command supports filtering and formatting logs:
1443
+
1444
+ ```bash
1445
+ # Show less/more output
1446
+ tactus run workflow.tac --log-level warning
1447
+ tactus run workflow.tac --log-level debug
1448
+
1449
+ # Choose a log format
1450
+ tactus run workflow.tac --log-format rich # default, grouped timestamps
1451
+ tactus run workflow.tac --log-format terminal # no timestamps, higher-signal terminal output
1452
+ tactus run workflow.tac --log-format raw # one-line-per-record, timestamped (CloudWatch-friendly)
1453
+ ```
1454
+
1440
1455
  The CLI automatically parses parameter types:
1441
1456
  - **Strings**: Direct values or quoted strings
1442
1457
  - **Numbers**: Integers or floats are auto-detected
@@ -2457,6 +2457,24 @@ File.write(path, contents)
2457
2457
  File.exists(path)
2458
2458
  ```
2459
2459
 
2460
+ ### Filesystem Helpers (stdlib)
2461
+
2462
+ Workflows sometimes need to enumerate files within the sandboxed working directory (for example, iterating over documents to lint or review). Use the filesystem helper module:
2463
+
2464
+ ```lua
2465
+ local fs = require("tactus.io.fs")
2466
+
2467
+ -- List entries in a directory (relative paths)
2468
+ local entries = fs.list_dir("chapters", {files_only = true, sort = true})
2469
+
2470
+ -- Glob files (relative paths)
2471
+ local qmd_files = fs.glob("chapters/*.qmd", {sort = true})
2472
+ ```
2473
+
2474
+ **Security model:** Paths are restricted to the procedure working directory; absolute paths and path traversal (`..`) are rejected.
2475
+
2476
+ **Determinism:** Filesystem contents can change between runs; wrap file enumeration and reads in `Step.checkpoint()` for durable workflows.
2477
+
2460
2478
  ---
2461
2479
 
2462
2480
  ## Matchers
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "tactus"
7
- version = "0.25.0"
7
+ version = "0.26.0"
8
8
  description = "Tactus: Lua-based DSL for agentic workflows"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -5,7 +5,7 @@ Tactus provides a declarative workflow engine for AI agents with pluggable
5
5
  backends for storage, HITL, and chat recording.
6
6
  """
7
7
 
8
- __version__ = "0.25.0"
8
+ __version__ = "0.26.0"
9
9
 
10
10
  # Core exports
11
11
  from tactus.core.runtime import TactusRuntime
@@ -32,7 +32,7 @@ class CLIHITLHandler:
32
32
  console: Rich Console instance (creates new one if not provided)
33
33
  """
34
34
  self.console = console or Console()
35
- logger.info("CLIHITLHandler initialized")
35
+ logger.debug("CLIHITLHandler initialized")
36
36
 
37
37
  def request_interaction(self, procedure_id: str, request: HITLRequest) -> HITLResponse:
38
38
  """
@@ -45,7 +45,7 @@ class CLIHITLHandler:
45
45
  Returns:
46
46
  HITLResponse with user's response
47
47
  """
48
- logger.info(f"HITL request: {request.request_type} - {request.message}")
48
+ logger.debug(f"HITL request: {request.request_type} - {request.message}")
49
49
 
50
50
  # Display the request in a panel
51
51
  self.console.print()
@@ -0,0 +1,56 @@
1
+ """
2
+ Cost-only log handler for headless/sandbox runs.
3
+
4
+ Collects CostEvent instances so the runtime can report total_cost/total_tokens,
5
+ without enabling streaming UI behavior.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import logging
11
+ import json
12
+ from typing import List
13
+
14
+ from tactus.protocols.models import CostEvent, LogEvent
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ class CostCollectorLogHandler:
20
+ """
21
+ Minimal LogHandler for sandbox runs.
22
+
23
+ This is useful in environments like Docker sandboxes where stdout is reserved
24
+ for protocol output, but we still want:
25
+ - accurate cost accounting (CostEvent)
26
+ - basic procedure logging (LogEvent) via stderr/Python logging
27
+ """
28
+
29
+ supports_streaming = False
30
+
31
+ def __init__(self):
32
+ self.cost_events: List[CostEvent] = []
33
+ logger.debug("CostCollectorLogHandler initialized")
34
+
35
+ def log(self, event: LogEvent) -> None:
36
+ if isinstance(event, CostEvent):
37
+ self.cost_events.append(event)
38
+ return
39
+
40
+ # Preserve useful procedure logs even when no IDE callback is present.
41
+ if isinstance(event, LogEvent):
42
+ event_logger = logging.getLogger(event.logger_name or "procedure")
43
+
44
+ msg = event.message
45
+ if event.context:
46
+ msg = f"{msg}\nContext: {json.dumps(event.context, indent=2, default=str)}"
47
+
48
+ level = (event.level or "INFO").upper()
49
+ if level == "DEBUG":
50
+ event_logger.debug(msg)
51
+ elif level in ("WARN", "WARNING"):
52
+ event_logger.warning(msg)
53
+ elif level == "ERROR":
54
+ event_logger.error(msg)
55
+ else:
56
+ event_logger.info(msg)
@@ -134,15 +134,92 @@ def load_tactus_config():
134
134
  return {}
135
135
 
136
136
 
137
- def setup_logging(verbose: bool = False):
138
- """Setup logging with rich handler."""
139
- level = logging.DEBUG if verbose else logging.INFO
140
-
141
- logging.basicConfig(
142
- level=level,
143
- format="%(message)s",
144
- handlers=[RichHandler(console=console, show_path=False, rich_tracebacks=True)],
145
- )
137
+ _LOG_LEVELS = {
138
+ "debug": logging.DEBUG,
139
+ "info": logging.INFO,
140
+ "warning": logging.WARNING,
141
+ "warn": logging.WARNING,
142
+ "error": logging.ERROR,
143
+ "critical": logging.CRITICAL,
144
+ }
145
+
146
+ _LOG_FORMATS = {"rich", "terminal", "raw"}
147
+
148
+
149
+ class _TerminalLogHandler(logging.Handler):
150
+ """Minimal, high-signal terminal logger (no timestamps/levels)."""
151
+
152
+ def __init__(self, console: Console):
153
+ super().__init__()
154
+ self._console = console
155
+ self.setFormatter(logging.Formatter("%(message)s"))
156
+
157
+ def emit(self, record: logging.LogRecord) -> None:
158
+ try:
159
+ message = self.format(record)
160
+
161
+ # Make procedure-level logs the most prominent.
162
+ if record.name.startswith("procedure"):
163
+ style = "bold"
164
+ elif record.levelno >= logging.ERROR:
165
+ style = "bold red"
166
+ elif record.levelno >= logging.WARNING:
167
+ style = "yellow"
168
+ elif record.levelno <= logging.DEBUG:
169
+ style = "dim"
170
+ else:
171
+ style = ""
172
+
173
+ self._console.print(message, style=style, markup=False, highlight=False)
174
+ except Exception:
175
+ self.handleError(record)
176
+
177
+
178
+ def setup_logging(
179
+ verbose: bool = False,
180
+ log_level: Optional[str] = None,
181
+ log_format: str = "rich",
182
+ ) -> None:
183
+ """Setup CLI logging (level + format)."""
184
+ if log_level is None:
185
+ level = logging.DEBUG if verbose else logging.INFO
186
+ else:
187
+ key = str(log_level).strip().lower()
188
+ if key not in _LOG_LEVELS:
189
+ raise typer.BadParameter(
190
+ f"Invalid --log-level '{log_level}'. "
191
+ f"Use one of: {', '.join(sorted(_LOG_LEVELS.keys()))}"
192
+ )
193
+ level = _LOG_LEVELS[key]
194
+
195
+ fmt = (log_format or "rich").strip().lower()
196
+ if fmt not in _LOG_FORMATS:
197
+ raise typer.BadParameter(
198
+ f"Invalid --log-format '{log_format}'. Use one of: {', '.join(sorted(_LOG_FORMATS))}"
199
+ )
200
+
201
+ # Default: rich logs (group repeated timestamps).
202
+ if fmt == "rich":
203
+ handler: logging.Handler = RichHandler(
204
+ console=console,
205
+ show_path=False,
206
+ rich_tracebacks=True,
207
+ omit_repeated_times=True,
208
+ )
209
+ handler.setFormatter(logging.Formatter("%(message)s"))
210
+ logging.basicConfig(level=level, format="%(message)s", handlers=[handler], force=True)
211
+ return
212
+
213
+ # Raw logs: one line per entry, CloudWatch-friendly.
214
+ if fmt == "raw":
215
+ handler = logging.StreamHandler(stream=sys.stderr)
216
+ handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(name)s: %(message)s"))
217
+ logging.basicConfig(level=level, handlers=[handler], force=True)
218
+ return
219
+
220
+ # Terminal logs: no timestamps/levels, color by signal.
221
+ handler = _TerminalLogHandler(console)
222
+ logging.basicConfig(level=level, handlers=[handler], force=True)
146
223
 
147
224
 
148
225
  def _parse_value(value_str: str, field_type: str) -> Any:
@@ -352,6 +429,12 @@ def run(
352
429
  None, envvar="OPENAI_API_KEY", help="OpenAI API key"
353
430
  ),
354
431
  verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable verbose logging"),
432
+ log_level: Optional[str] = typer.Option(
433
+ None, "--log-level", help="Log level: debug, info, warning, error, critical"
434
+ ),
435
+ log_format: str = typer.Option(
436
+ "rich", "--log-format", help="Log format: rich (default), terminal, raw"
437
+ ),
355
438
  param: Optional[list[str]] = typer.Option(None, help="Parameters in format key=value"),
356
439
  interactive: bool = typer.Option(
357
440
  False, "--interactive", "-i", help="Interactively prompt for all inputs"
@@ -399,7 +482,7 @@ def run(
399
482
  # Use real implementation for specific tools while mocking others
400
483
  tactus run workflow.tac --mock-all --real done
401
484
  """
402
- setup_logging(verbose)
485
+ setup_logging(verbose=verbose, log_level=log_level, log_format=log_format)
403
486
 
404
487
  # Check if file exists
405
488
  if not workflow_file.exists():
@@ -530,6 +613,12 @@ def run(
530
613
  sandbox_config_dict["enabled"] = sandbox
531
614
  sandbox_config = SandboxConfig(**sandbox_config_dict)
532
615
 
616
+ # Pass logging preferences through to the sandbox container so container stderr matches CLI UX.
617
+ sandbox_config.env.setdefault(
618
+ "TACTUS_LOG_LEVEL", str(log_level or ("debug" if verbose else "info"))
619
+ )
620
+ sandbox_config.env.setdefault("TACTUS_LOG_FORMAT", str(log_format))
621
+
533
622
  # Check Docker availability
534
623
  docker_available, docker_reason = is_docker_available()
535
624
 
@@ -150,7 +150,7 @@ class ConfigManager:
150
150
  sidecar_config = self._load_yaml_file(sidecar_path)
151
151
  if sidecar_config:
152
152
  configs.append(("sidecar", sidecar_config))
153
- logger.info(f"Loaded sidecar config: {sidecar_path}")
153
+ logger.debug(f"Loaded sidecar config: {sidecar_path}")
154
154
 
155
155
  # Store for debugging
156
156
  self.loaded_configs = configs
@@ -158,7 +158,7 @@ class ConfigManager:
158
158
  # Merge all configs (later configs override earlier ones)
159
159
  merged = self._merge_configs([c[1] for c in configs])
160
160
 
161
- logger.info(f"Merged configuration from {len(configs)} source(s)")
161
+ logger.debug(f"Merged configuration from {len(configs)} source(s)")
162
162
  return merged
163
163
 
164
164
  def _find_sidecar_config(self, tac_path: Path) -> Optional[Path]:
@@ -915,43 +915,49 @@ def create_dsl_stubs(
915
915
  if not isinstance(mock_config, dict):
916
916
  continue
917
917
 
918
- # Check if this is an agent mock (has tool_calls key)
919
- if "tool_calls" in mock_config:
920
- # Agent mock - specifies what tool calls the agent should simulate
918
+ # Tool mocks use explicit keys.
919
+ tool_mock_keys = {"returns", "temporal", "conditional", "error"}
920
+ if any(k in mock_config for k in tool_mock_keys):
921
+ # Convert DSL syntax to MockConfig format
922
+ processed_config = {}
923
+
924
+ # Static mocking with 'returns' key
925
+ if "returns" in mock_config:
926
+ processed_config["output"] = mock_config["returns"]
927
+
928
+ # Temporal mocking
929
+ elif "temporal" in mock_config:
930
+ processed_config["temporal"] = mock_config["temporal"]
931
+
932
+ # Conditional mocking
933
+ elif "conditional" in mock_config:
934
+ # Convert DSL conditional format to MockManager format
935
+ conditionals = []
936
+ for cond in mock_config["conditional"]:
937
+ if isinstance(cond, dict) and "when" in cond and "returns" in cond:
938
+ conditionals.append({"when": cond["when"], "return": cond["returns"]})
939
+ processed_config["conditional_mocks"] = conditionals
940
+
941
+ # Error simulation
942
+ elif "error" in mock_config:
943
+ processed_config["error"] = mock_config["error"]
944
+
945
+ # Register the tool mock configuration
946
+ builder.register_mock(name, processed_config)
947
+ continue
948
+
949
+ # Agent mocks can be message-only, tool_calls-only, or both.
950
+ if any(k in mock_config for k in ("tool_calls", "message", "data")):
921
951
  agent_config = {
922
952
  "tool_calls": mock_config.get("tool_calls", []),
923
953
  "message": mock_config.get("message", ""),
954
+ "data": mock_config.get("data"),
924
955
  }
925
956
  builder.register_agent_mock(name, agent_config)
926
957
  continue
927
958
 
928
- # Otherwise, it's a tool mock
929
- # Convert DSL syntax to MockConfig format
930
- processed_config = {}
931
-
932
- # Static mocking with 'returns' key
933
- if "returns" in mock_config:
934
- processed_config["output"] = mock_config["returns"]
935
-
936
- # Temporal mocking
937
- elif "temporal" in mock_config:
938
- processed_config["temporal"] = mock_config["temporal"]
939
-
940
- # Conditional mocking
941
- elif "conditional" in mock_config:
942
- # Convert DSL conditional format to MockManager format
943
- conditionals = []
944
- for cond in mock_config["conditional"]:
945
- if isinstance(cond, dict) and "when" in cond and "returns" in cond:
946
- conditionals.append({"when": cond["when"], "return": cond["returns"]})
947
- processed_config["conditional_mocks"] = conditionals
948
-
949
- # Error simulation
950
- elif "error" in mock_config:
951
- processed_config["error"] = mock_config["error"]
952
-
953
- # Register the tool mock configuration
954
- builder.register_mock(name, processed_config)
959
+ # Otherwise, ignore unknown mock config.
960
+ continue
955
961
 
956
962
  def _history(messages=None):
957
963
  """
@@ -1413,14 +1419,14 @@ def create_dsl_stubs(
1413
1419
 
1414
1420
  logger = logging.getLogger(__name__)
1415
1421
 
1416
- logger.info(
1422
+ logger.debug(
1417
1423
  f"[AGENT_CREATION] Agent '{agent_name}': runtime_context={bool(_runtime_context)}, skip_agents={_runtime_context.get('skip_agents', 'N/A') if _runtime_context else 'N/A'}, has_log_handler={('log_handler' in _runtime_context) if _runtime_context else False}"
1418
1424
  )
1419
1425
 
1420
1426
  if _runtime_context and not _runtime_context.get("skip_agents", False):
1421
1427
  from tactus.dspy.agent import create_dspy_agent
1422
1428
 
1423
- logger.info(f"[AGENT_CREATION] Attempting immediate creation for agent '{agent_name}'")
1429
+ logger.debug(f"[AGENT_CREATION] Attempting immediate creation for agent '{agent_name}'")
1424
1430
 
1425
1431
  try:
1426
1432
  # Create the actual agent primitive NOW
@@ -1450,7 +1456,7 @@ def create_dsl_stubs(
1450
1456
  handle._set_primitive(
1451
1457
  agent_primitive, execution_context=_runtime_context.get("execution_context")
1452
1458
  )
1453
- logger.info(
1459
+ logger.debug(
1454
1460
  f"[AGENT_CREATION] Agent '{agent_name}' created immediately during declaration, has_log_handler={hasattr(agent_primitive, 'log_handler') and agent_primitive.log_handler is not None}"
1455
1461
  )
1456
1462
 
@@ -1458,7 +1464,9 @@ def create_dsl_stubs(
1458
1464
  if "_created_agents" not in _runtime_context:
1459
1465
  _runtime_context["_created_agents"] = {}
1460
1466
  _runtime_context["_created_agents"][agent_name] = agent_primitive
1461
- logger.info(f"[AGENT_CREATION] Stored agent '{agent_name}' in _created_agents dict")
1467
+ logger.debug(
1468
+ f"[AGENT_CREATION] Stored agent '{agent_name}' in _created_agents dict"
1469
+ )
1462
1470
 
1463
1471
  except Exception as e:
1464
1472
  logger.error(
@@ -1567,14 +1575,14 @@ def create_dsl_stubs(
1567
1575
 
1568
1576
  logger = logging.getLogger(__name__)
1569
1577
 
1570
- logger.info(
1578
+ logger.debug(
1571
1579
  f"[AGENT_CREATION] Agent '{temp_name}': runtime_context={bool(_runtime_context)}, skip_agents={_runtime_context.get('skip_agents', 'N/A') if _runtime_context else 'N/A'}, has_log_handler={('log_handler' in _runtime_context) if _runtime_context else False}"
1572
1580
  )
1573
1581
 
1574
1582
  if _runtime_context and not _runtime_context.get("skip_agents", False):
1575
1583
  from tactus.dspy.agent import create_dspy_agent
1576
1584
 
1577
- logger.info(f"[AGENT_CREATION] Attempting immediate creation for agent '{temp_name}'")
1585
+ logger.debug(f"[AGENT_CREATION] Attempting immediate creation for agent '{temp_name}'")
1578
1586
 
1579
1587
  try:
1580
1588
  # Create the actual agent primitive NOW
@@ -1593,7 +1601,7 @@ def create_dsl_stubs(
1593
1601
  if "log_handler" in _runtime_context:
1594
1602
  agent_config["log_handler"] = _runtime_context["log_handler"]
1595
1603
 
1596
- logger.info(
1604
+ logger.debug(
1597
1605
  f"[AGENT_CREATION] Creating agent immediately: name={temp_name}, has_log_handler={'log_handler' in agent_config}"
1598
1606
  )
1599
1607
  agent_primitive = create_dspy_agent(
@@ -1607,7 +1615,7 @@ def create_dsl_stubs(
1607
1615
  handle._set_primitive(
1608
1616
  agent_primitive, execution_context=_runtime_context.get("execution_context")
1609
1617
  )
1610
- logger.info(
1618
+ logger.debug(
1611
1619
  f"[AGENT_CREATION] Agent '{temp_name}' created immediately during declaration, has_log_handler={hasattr(agent_primitive, 'log_handler') and agent_primitive.log_handler is not None}"
1612
1620
  )
1613
1621
 
@@ -1615,7 +1623,7 @@ def create_dsl_stubs(
1615
1623
  if "_created_agents" not in _runtime_context:
1616
1624
  _runtime_context["_created_agents"] = {}
1617
1625
  _runtime_context["_created_agents"][temp_name] = agent_primitive
1618
- logger.info(f"[AGENT_CREATION] Stored agent '{temp_name}' in _created_agents dict")
1626
+ logger.debug(f"[AGENT_CREATION] Stored agent '{temp_name}' in _created_agents dict")
1619
1627
 
1620
1628
  except Exception as e:
1621
1629
  import traceback
@@ -1757,13 +1765,13 @@ def _make_binding_callback(
1757
1765
  old_name = value.name
1758
1766
  if old_name.startswith("_temp_agent_"):
1759
1767
  # Rename the agent handle
1760
- callback_logger.info(f"[AGENT_RENAME] Renaming agent '{old_name}' to '{name}'")
1768
+ callback_logger.debug(f"[AGENT_RENAME] Renaming agent '{old_name}' to '{name}'")
1761
1769
  value.name = name
1762
1770
 
1763
1771
  # Also rename the underlying primitive if it exists
1764
1772
  if value._primitive is not None:
1765
1773
  value._primitive.name = name
1766
- callback_logger.info(
1774
+ callback_logger.debug(
1767
1775
  f"[AGENT_RENAME] Updated primitive name: '{old_name}' -> '{name}'"
1768
1776
  )
1769
1777
 
@@ -1777,7 +1785,7 @@ def _make_binding_callback(
1777
1785
  if hasattr(builder, "registry") and old_name in builder.registry.agents:
1778
1786
  agent_data = builder.registry.agents.pop(old_name)
1779
1787
  builder.registry.agents[name] = agent_data
1780
- callback_logger.info(
1788
+ callback_logger.debug(
1781
1789
  f"[AGENT_RENAME] Re-registered agent '{name}' in builder.registry.agents"
1782
1790
  )
1783
1791
 
@@ -1786,7 +1794,7 @@ def _make_binding_callback(
1786
1794
  if old_name in runtime_context["_created_agents"]:
1787
1795
  agent_primitive = runtime_context["_created_agents"].pop(old_name)
1788
1796
  runtime_context["_created_agents"][name] = agent_primitive
1789
- callback_logger.info(
1797
+ callback_logger.debug(
1790
1798
  f"[AGENT_RENAME] Updated _created_agents dict: '{old_name}' -> '{name}'"
1791
1799
  )
1792
1800
 
@@ -187,7 +187,7 @@ class BaseExecutionContext(ExecutionContext):
187
187
  On replay, returns cached result from execution log.
188
188
  On first execution, runs fn(), records in log, and returns result.
189
189
  """
190
- logger.info(
190
+ logger.debug(
191
191
  f"[CHECKPOINT] checkpoint() called, type={checkpoint_type}, has_log_handler={self.log_handler is not None}"
192
192
  )
193
193
  current_position = self.metadata.replay_index
@@ -259,7 +259,7 @@ class BaseExecutionContext(ExecutionContext):
259
259
  source_location=source_location,
260
260
  procedure_id=self.procedure_id,
261
261
  )
262
- logger.info(
262
+ logger.debug(
263
263
  f"[CHECKPOINT] Emitting CheckpointCreatedEvent: position={current_position}, type={checkpoint_type}, duration_ms={duration_ms}"
264
264
  )
265
265
  self.log_handler.log(event)
@@ -73,7 +73,7 @@ class LuaSandbox:
73
73
  # Setup safe globals
74
74
  self._setup_safe_globals()
75
75
 
76
- logger.info("Lua sandbox initialized successfully")
76
+ logger.debug("Lua sandbox initialized successfully")
77
77
 
78
78
  def _attribute_filter(self, obj, attr_name, is_setting):
79
79
  """
@@ -274,7 +274,7 @@ class LuaSandbox:
274
274
  self.lua.globals()["math"] = safe_math_table
275
275
  self.lua.globals()["os"] = safe_os_table
276
276
 
277
- logger.info("Installed safe math and os libraries with determinism checking")
277
+ logger.debug("Installed safe math and os libraries with determinism checking")
278
278
  return # Skip default os.date setup below
279
279
 
280
280
  # Add safe subset of os module (only date function for timestamps)
@@ -36,6 +36,10 @@ COPY pyproject.toml ./
36
36
  COPY README.md ./
37
37
  COPY tactus/ ./tactus/
38
38
 
39
+ # Ensure the non-root runtime user can read the codebase even if the host
40
+ # working tree has restrictive permissions (e.g., umask 077).
41
+ RUN chmod -R a+rX /app/tactus
42
+
39
43
  # Install Tactus and its dependencies
40
44
  RUN pip install --no-cache-dir -e .
41
45
 
@@ -191,11 +191,19 @@ class DSPyAgentHandle:
191
191
  if response and hasattr(response, "_hidden_params"):
192
192
  total_cost = response._hidden_params.get("response_cost")
193
193
 
194
- if total_cost is None and response:
194
+ if total_cost is None and total_tokens > 0:
195
195
  try:
196
- import litellm
197
-
198
- total_cost = litellm.completion_cost(completion_response=response)
196
+ # We already have token counts, so compute cost from tokens to avoid relying
197
+ # on provider-specific response object shapes.
198
+ from litellm.cost_calculator import cost_per_token
199
+
200
+ prompt_cost, completion_cost = cost_per_token(
201
+ model=str(model) if model is not None else "",
202
+ prompt_tokens=prompt_tokens,
203
+ completion_tokens=completion_tokens,
204
+ call_type="completion",
205
+ )
206
+ total_cost = float(prompt_cost) + float(completion_cost)
199
207
  except Exception as e:
200
208
  logger.warning(f"[COST] Agent '{self.name}': failed to calculate cost: {e}")
201
209
  total_cost = 0.0
@@ -326,6 +334,7 @@ class DSPyAgentHandle:
326
334
 
327
335
  Streaming is enabled when:
328
336
  - log_handler is available (for emitting events)
337
+ - log_handler supports streaming events
329
338
  - disable_streaming is False
330
339
  - No structured output schema (streaming only works with plain text)
331
340
 
@@ -337,6 +346,14 @@ class DSPyAgentHandle:
337
346
  logger.debug(f"[STREAMING] Agent '{self.name}': no log_handler, streaming disabled")
338
347
  return False
339
348
 
349
+ # Allow log handlers to opt out of streaming (e.g., cost-only collectors)
350
+ supports_streaming = getattr(self.log_handler, "supports_streaming", True)
351
+ if not supports_streaming:
352
+ logger.debug(
353
+ f"[STREAMING] Agent '{self.name}': log_handler supports_streaming=False, streaming disabled"
354
+ )
355
+ return False
356
+
340
357
  # Respect explicit disable flag
341
358
  if self.disable_streaming:
342
359
  logger.debug(
@@ -673,9 +690,7 @@ class DSPyAgentHandle:
673
690
  result = worker({message = "Process this task"})
674
691
  print(result.response)
675
692
  """
676
- logger.info(
677
- f"[CHECKPOINT] DSPyAgentHandle.__call__ invoked directly for agent '{self.name}' - THIS BYPASSES AgentHandle checkpoint logic!"
678
- )
693
+ logger.debug(f"Agent '{self.name}' invoked via __call__()")
679
694
  inputs = inputs or {}
680
695
 
681
696
  # Handle string input as a convenience: Agent("message") -> Agent({message="message"})