tactus 0.21.1__tar.gz → 0.23.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 (551) hide show
  1. {tactus-0.21.1 → tactus-0.23.0}/CHANGELOG.md +17 -0
  2. {tactus-0.21.1 → tactus-0.23.0}/PKG-INFO +1 -1
  3. {tactus-0.21.1 → tactus-0.23.0}/SPECIFICATION.md +66 -0
  4. tactus-0.23.0/examples/01-basics-hello-world.tac +8 -0
  5. tactus-0.23.0/examples/test-raw-module.tac +11 -0
  6. tactus-0.23.0/examples/test-raw-streaming.tac +11 -0
  7. tactus-0.23.0/features/57_chat_assistant.feature +60 -0
  8. tactus-0.23.0/features/steps/chat_assistant_steps.py +160 -0
  9. {tactus-0.21.1 → tactus-0.23.0}/features/steps/support/harnesses.py +158 -0
  10. {tactus-0.21.1 → tactus-0.23.0}/pyproject.toml +1 -1
  11. {tactus-0.21.1 → tactus-0.23.0}/tactus/__init__.py +1 -1
  12. {tactus-0.21.1 → tactus-0.23.0}/tactus/dspy/agent.py +37 -2
  13. {tactus-0.21.1 → tactus-0.23.0}/tactus/dspy/config.py +66 -0
  14. {tactus-0.21.1 → tactus-0.23.0}/tactus/dspy/module.py +144 -4
  15. {tactus-0.21.1 → tactus-0.23.0}/tactus/ide/server.py +66 -54
  16. {tactus-0.21.1 → tactus-0.23.0}/tactus/sandbox/container_runner.py +76 -0
  17. {tactus-0.21.1 → tactus-0.23.0}/tactus/sandbox/docker_manager.py +103 -3
  18. tactus-0.23.0/tactus-ide/backend/assistant_service.py +444 -0
  19. tactus-0.23.0/tactus-ide/backend/assistant_tools.py +397 -0
  20. tactus-0.23.0/tactus-ide/backend/chat_server.py +339 -0
  21. tactus-0.23.0/tactus-ide/backend/text_editor_tool.py +172 -0
  22. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/package-lock.json +0 -154
  23. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/App.tsx +3 -3
  24. tactus-0.23.0/tactus-ide/frontend/src/components/ChatSidebar.tsx +24 -0
  25. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ResultsSidebar.tsx +64 -43
  26. tactus-0.23.0/tactus-ide/frontend/src/components/chat/ChatInterface.tsx +96 -0
  27. tactus-0.23.0/tactus-ide/frontend/src/components/chat/MessageInput.tsx +84 -0
  28. tactus-0.23.0/tactus-ide/frontend/src/components/chat/MessageList.tsx +125 -0
  29. tactus-0.23.0/tactus-ide/frontend/src/hooks/useChatSSE.ts +204 -0
  30. tactus-0.23.0/tests/dspy/test_module_parameter.py +142 -0
  31. tactus-0.21.1/examples/01-basics-hello-world.tac +0 -9
  32. tactus-0.21.1/tactus-ide/frontend/src/components/ChatSidebar.tsx +0 -195
  33. {tactus-0.21.1 → tactus-0.23.0}/.claude/agents.md +0 -0
  34. {tactus-0.21.1 → tactus-0.23.0}/.github/workflows/desktop-release.yml +0 -0
  35. {tactus-0.21.1 → tactus-0.23.0}/.github/workflows/release.yml +0 -0
  36. {tactus-0.21.1 → tactus-0.23.0}/.gitignore +0 -0
  37. {tactus-0.21.1 → tactus-0.23.0}/.tactus/config.yml.example +0 -0
  38. {tactus-0.21.1 → tactus-0.23.0}/AGENTS.md +0 -0
  39. {tactus-0.21.1 → tactus-0.23.0}/IMPLEMENTATION.md +0 -0
  40. {tactus-0.21.1 → tactus-0.23.0}/LICENSE +0 -0
  41. {tactus-0.21.1 → tactus-0.23.0}/Makefile +0 -0
  42. {tactus-0.21.1 → tactus-0.23.0}/README.md +0 -0
  43. {tactus-0.21.1 → tactus-0.23.0}/SPECIFICATION.md.bak +0 -0
  44. {tactus-0.21.1 → tactus-0.23.0}/TECHNICAL_DEBT.md +0 -0
  45. {tactus-0.21.1 → tactus-0.23.0}/behave.ini +0 -0
  46. {tactus-0.21.1 → tactus-0.23.0}/docs/AGENTS.md +0 -0
  47. {tactus-0.21.1 → tactus-0.23.0}/docs/BDD_TESTING.md +0 -0
  48. {tactus-0.21.1 → tactus-0.23.0}/docs/CONFIGURATION.md +0 -0
  49. {tactus-0.21.1 → tactus-0.23.0}/docs/DURABILITY.md +0 -0
  50. {tactus-0.21.1 → tactus-0.23.0}/docs/FILE_IO.md +0 -0
  51. {tactus-0.21.1 → tactus-0.23.0}/docs/SANDBOXING.md +0 -0
  52. {tactus-0.21.1 → tactus-0.23.0}/docs/STREAMING.md +0 -0
  53. {tactus-0.21.1 → tactus-0.23.0}/docs/TOOLS.md +0 -0
  54. {tactus-0.21.1 → tactus-0.23.0}/docs/TOOL_ROADMAP.md +0 -0
  55. {tactus-0.21.1 → tactus-0.23.0}/examples/.tactus/config.yml +0 -0
  56. {tactus-0.21.1 → tactus-0.23.0}/examples/02-basics-simple-logic.tac +0 -0
  57. {tactus-0.21.1 → tactus-0.23.0}/examples/03-basics-parameters.tac +0 -0
  58. {tactus-0.21.1 → tactus-0.23.0}/examples/04-basics-simple-agent.tac +0 -0
  59. {tactus-0.21.1 → tactus-0.23.0}/examples/05-basics-multi-model.tac +0 -0
  60. {tactus-0.21.1 → tactus-0.23.0}/examples/06-basics-streaming.tac +0 -0
  61. {tactus-0.21.1 → tactus-0.23.0}/examples/07-basics-bedrock.tac +0 -0
  62. {tactus-0.21.1 → tactus-0.23.0}/examples/08-basics-models.tac +0 -0
  63. {tactus-0.21.1 → tactus-0.23.0}/examples/09-basics-google-gemini.tac +0 -0
  64. {tactus-0.21.1 → tactus-0.23.0}/examples/10-feature-state.tac +0 -0
  65. {tactus-0.21.1 → tactus-0.23.0}/examples/11-feature-message-history.tac +0 -0
  66. {tactus-0.21.1 → tactus-0.23.0}/examples/12-feature-structured-output.tac +0 -0
  67. {tactus-0.21.1 → tactus-0.23.0}/examples/13-feature-session.tac +0 -0
  68. {tactus-0.21.1 → tactus-0.23.0}/examples/14-feature-per-turn-tools-simple.tac +0 -0
  69. {tactus-0.21.1 → tactus-0.23.0}/examples/14-feature-per-turn-tools.tac +0 -0
  70. {tactus-0.21.1 → tactus-0.23.0}/examples/15-feature-local-tools.tac +0 -0
  71. {tactus-0.21.1 → tactus-0.23.0}/examples/16-feature-toolsets-advanced.tac +0 -0
  72. {tactus-0.21.1 → tactus-0.23.0}/examples/17-feature-toolsets-dsl.tac +0 -0
  73. {tactus-0.21.1 → tactus-0.23.0}/examples/18-feature-lua-tools-individual.tac +0 -0
  74. {tactus-0.21.1 → tactus-0.23.0}/examples/18-feature-lua-tools-inline.tac +0 -0
  75. {tactus-0.21.1 → tactus-0.23.0}/examples/18-feature-lua-tools-toolset.tac +0 -0
  76. {tactus-0.21.1 → tactus-0.23.0}/examples/19-feature-direct-tool-calls.tac +0 -0
  77. {tactus-0.21.1 → tactus-0.23.0}/examples/20-bdd-complete.tac +0 -0
  78. {tactus-0.21.1 → tactus-0.23.0}/examples/20-bdd-complete.tac.bak +0 -0
  79. {tactus-0.21.1 → tactus-0.23.0}/examples/20-bdd-complete.tac.bak2 +0 -0
  80. {tactus-0.21.1 → tactus-0.23.0}/examples/21-bdd-passing.tac +0 -0
  81. {tactus-0.21.1 → tactus-0.23.0}/examples/21-bdd-passing.tac.bak +0 -0
  82. {tactus-0.21.1 → tactus-0.23.0}/examples/21-bdd-passing.tac.bak2 +0 -0
  83. {tactus-0.21.1 → tactus-0.23.0}/examples/30-eval-simple.tac +0 -0
  84. {tactus-0.21.1 → tactus-0.23.0}/examples/31-eval-demo.tac +0 -0
  85. {tactus-0.21.1 → tactus-0.23.0}/examples/32-eval-success-rate.tac +0 -0
  86. {tactus-0.21.1 → tactus-0.23.0}/examples/33-eval-thresholds.tac +0 -0
  87. {tactus-0.21.1 → tactus-0.23.0}/examples/34-eval-dataset.jsonl +0 -0
  88. {tactus-0.21.1 → tactus-0.23.0}/examples/34-eval-dataset.tac +0 -0
  89. {tactus-0.21.1 → tactus-0.23.0}/examples/35-eval-trace.tac +0 -0
  90. {tactus-0.21.1 → tactus-0.23.0}/examples/35-eval-trace.tac.bak +0 -0
  91. {tactus-0.21.1 → tactus-0.23.0}/examples/35-eval-trace.tac.bak2 +0 -0
  92. {tactus-0.21.1 → tactus-0.23.0}/examples/36-eval-advanced.tac +0 -0
  93. {tactus-0.21.1 → tactus-0.23.0}/examples/37-eval-comprehensive.tac +0 -0
  94. {tactus-0.21.1 → tactus-0.23.0}/examples/37-eval-comprehensive.tac.bak +0 -0
  95. {tactus-0.21.1 → tactus-0.23.0}/examples/37-eval-comprehensive.tac.bak2 +0 -0
  96. {tactus-0.21.1 → tactus-0.23.0}/examples/39-model-simple.tac +0 -0
  97. {tactus-0.21.1 → tactus-0.23.0}/examples/40-mcp-test.tac +0 -0
  98. {tactus-0.21.1 → tactus-0.23.0}/examples/40-model-text-classifier.tac +0 -0
  99. {tactus-0.21.1 → tactus-0.23.0}/examples/41-mcp-simple.tac +0 -0
  100. {tactus-0.21.1 → tactus-0.23.0}/examples/41-model-pytorch.tac +0 -0
  101. {tactus-0.21.1 → tactus-0.23.0}/examples/43-sub-procedure-simple.tac +0 -0
  102. {tactus-0.21.1 → tactus-0.23.0}/examples/44-sub-procedure-composition.tac +0 -0
  103. {tactus-0.21.1 → tactus-0.23.0}/examples/45-sub-procedure-recursive.tac +0 -0
  104. {tactus-0.21.1 → tactus-0.23.0}/examples/46-checkpoint-explicit.tac +0 -0
  105. {tactus-0.21.1 → tactus-0.23.0}/examples/47-checkpoint-expensive-ops.tac +0 -0
  106. {tactus-0.21.1 → tactus-0.23.0}/examples/48-script-mode-simple.tac +0 -0
  107. {tactus-0.21.1 → tactus-0.23.0}/examples/50-inputs-showcase.tac +0 -0
  108. {tactus-0.21.1 → tactus-0.23.0}/examples/51-inputs-calculator.tac +0 -0
  109. {tactus-0.21.1 → tactus-0.23.0}/examples/52-file-io-basics.tac +0 -0
  110. {tactus-0.21.1 → tactus-0.23.0}/examples/53-tsv-file-io.tac +0 -0
  111. {tactus-0.21.1 → tactus-0.23.0}/examples/54-json-file-io.tac +0 -0
  112. {tactus-0.21.1 → tactus-0.23.0}/examples/55-parquet-file-io.tac +0 -0
  113. {tactus-0.21.1 → tactus-0.23.0}/examples/56-hdf5-file-io.tac +0 -0
  114. {tactus-0.21.1 → tactus-0.23.0}/examples/57-excel-file-io.tac +0 -0
  115. {tactus-0.21.1 → tactus-0.23.0}/examples/58-text-file-io.tac +0 -0
  116. {tactus-0.21.1 → tactus-0.23.0}/examples/60-tool-sources.tac +0 -0
  117. {tactus-0.21.1 → tactus-0.23.0}/examples/61-inline-toolset-lua.tac +0 -0
  118. {tactus-0.21.1 → tactus-0.23.0}/examples/62-mcp-toolset-by-server.tac +0 -0
  119. {tactus-0.21.1 → tactus-0.23.0}/examples/63-toolset-import-from-file.tac +0 -0
  120. {tactus-0.21.1 → tactus-0.23.0}/examples/64-require-modules.tac +0 -0
  121. {tactus-0.21.1 → tactus-0.23.0}/examples/65-optional-state-demo.tac +0 -0
  122. {tactus-0.21.1 → tactus-0.23.0}/examples/70-mocking-static.tac +0 -0
  123. {tactus-0.21.1 → tactus-0.23.0}/examples/71-mocking-temporal.tac +0 -0
  124. {tactus-0.21.1 → tactus-0.23.0}/examples/72-mocking-conditional.tac +0 -0
  125. {tactus-0.21.1 → tactus-0.23.0}/examples/99-misc-test-loading.tac +0 -0
  126. {tactus-0.21.1 → tactus-0.23.0}/examples/README.md +0 -0
  127. {tactus-0.21.1 → tactus-0.23.0}/examples/app_config.ini +0 -0
  128. {tactus-0.21.1 → tactus-0.23.0}/examples/data/sample.csv +0 -0
  129. {tactus-0.21.1 → tactus-0.23.0}/examples/demo_output.json +0 -0
  130. {tactus-0.21.1 → tactus-0.23.0}/examples/helpers/math_module.tac +0 -0
  131. {tactus-0.21.1 → tactus-0.23.0}/examples/helpers/product.tac +0 -0
  132. {tactus-0.21.1 → tactus-0.23.0}/examples/helpers/string_module.tac +0 -0
  133. {tactus-0.21.1 → tactus-0.23.0}/examples/helpers/sum.tac +0 -0
  134. {tactus-0.21.1 → tactus-0.23.0}/examples/helpers/text_tools.tac +0 -0
  135. {tactus-0.21.1 → tactus-0.23.0}/examples/inventory_summary.tsv +0 -0
  136. {tactus-0.21.1 → tactus-0.23.0}/examples/mock-config.json +0 -0
  137. {tactus-0.21.1 → tactus-0.23.0}/examples/models/README.md +0 -0
  138. {tactus-0.21.1 → tactus-0.23.0}/examples/models/create_sentiment_model.py +0 -0
  139. {tactus-0.21.1 → tactus-0.23.0}/examples/output_summary.txt +0 -0
  140. {tactus-0.21.1 → tactus-0.23.0}/examples/tools/calculations.py +0 -0
  141. {tactus-0.21.1 → tactus-0.23.0}/examples/tools/data_analysis.py +0 -0
  142. {tactus-0.21.1 → tactus-0.23.0}/examples/tools/search.py +0 -0
  143. {tactus-0.21.1 → tactus-0.23.0}/examples/with_dependencies/README.md +0 -0
  144. {tactus-0.21.1 → tactus-0.23.0}/examples/with_dependencies/simple_http_test.tac +0 -0
  145. {tactus-0.21.1 → tactus-0.23.0}/examples/with_dependencies/time_lookup.tac +0 -0
  146. {tactus-0.21.1 → tactus-0.23.0}/features/01_state_management.feature +0 -0
  147. {tactus-0.21.1 → tactus-0.23.0}/features/02_checkpointing.feature +0 -0
  148. {tactus-0.21.1 → tactus-0.23.0}/features/03_human_in_the_loop.feature +0 -0
  149. {tactus-0.21.1 → tactus-0.23.0}/features/04_control_flow.feature +0 -0
  150. {tactus-0.21.1 → tactus-0.23.0}/features/05_tool_integration.feature +0 -0
  151. {tactus-0.21.1 → tactus-0.23.0}/features/06_retry_logic.feature +0 -0
  152. {tactus-0.21.1 → tactus-0.23.0}/features/07_file_operations.feature +0 -0
  153. {tactus-0.21.1 → tactus-0.23.0}/features/08_agent_primitives.feature +0 -0
  154. {tactus-0.21.1 → tactus-0.23.0}/features/09_workflow_execution.feature +0 -0
  155. {tactus-0.21.1 → tactus-0.23.0}/features/10_lua_integration.feature +0 -0
  156. {tactus-0.21.1 → tactus-0.23.0}/features/11_storage_backends.feature +0 -0
  157. {tactus-0.21.1 → tactus-0.23.0}/features/12_json_operations.feature +0 -0
  158. {tactus-0.21.1 → tactus-0.23.0}/features/13_logging.feature +0 -0
  159. {tactus-0.21.1 → tactus-0.23.0}/features/14_stage_and_step_tracking.feature +0 -0
  160. {tactus-0.21.1 → tactus-0.23.0}/features/15_procedure_calls.feature +0 -0
  161. {tactus-0.21.1 → tactus-0.23.0}/features/16_session_management.feature +0 -0
  162. {tactus-0.21.1 → tactus-0.23.0}/features/17_lua_dsl_validation.feature +0 -0
  163. {tactus-0.21.1 → tactus-0.23.0}/features/18_example_procedures.feature +0 -0
  164. {tactus-0.21.1 → tactus-0.23.0}/features/19_ide_server.feature +0 -0
  165. {tactus-0.21.1 → tactus-0.23.0}/features/20_parameters.feature +0 -0
  166. {tactus-0.21.1 → tactus-0.23.0}/features/21_outputs.feature +0 -0
  167. {tactus-0.21.1 → tactus-0.23.0}/features/23_prompts.feature +0 -0
  168. {tactus-0.21.1 → tactus-0.23.0}/features/24_bdd_specifications.feature +0 -0
  169. {tactus-0.21.1 → tactus-0.23.0}/features/25_bdd_custom_steps.feature +0 -0
  170. {tactus-0.21.1 → tactus-0.23.0}/features/26_bdd_evaluation.feature +0 -0
  171. {tactus-0.21.1 → tactus-0.23.0}/features/27_default_settings.feature +0 -0
  172. {tactus-0.21.1 → tactus-0.23.0}/features/28_custom_prompts.feature +0 -0
  173. {tactus-0.21.1 → tactus-0.23.0}/features/29_execution_settings.feature +0 -0
  174. {tactus-0.21.1 → tactus-0.23.0}/features/30_session_filters.feature +0 -0
  175. {tactus-0.21.1 → tactus-0.23.0}/features/31_matchers.feature +0 -0
  176. {tactus-0.21.1 → tactus-0.23.0}/features/32_result_object.feature +0 -0
  177. {tactus-0.21.1 → tactus-0.23.0}/features/33_output_type.feature +0 -0
  178. {tactus-0.21.1 → tactus-0.23.0}/features/42_model_primitive.feature +0 -0
  179. {tactus-0.21.1 → tactus-0.23.0}/features/43_sub_procedure_checkpointing.feature +0 -0
  180. {tactus-0.21.1 → tactus-0.23.0}/features/46_explicit_checkpoint.feature +0 -0
  181. {tactus-0.21.1 → tactus-0.23.0}/features/48_script_mode.feature +0 -0
  182. {tactus-0.21.1 → tactus-0.23.0}/features/51_dspy_lm_config.feature +0 -0
  183. {tactus-0.21.1 → tactus-0.23.0}/features/52_dspy_signature.feature +0 -0
  184. {tactus-0.21.1 → tactus-0.23.0}/features/53_dspy_module.feature +0 -0
  185. {tactus-0.21.1 → tactus-0.23.0}/features/54_dspy_history.feature +0 -0
  186. {tactus-0.21.1 → tactus-0.23.0}/features/55_dspy_prediction.feature +0 -0
  187. {tactus-0.21.1 → tactus-0.23.0}/features/56_dspy_agent.feature +0 -0
  188. {tactus-0.21.1 → tactus-0.23.0}/features/documentation/IDE_SERVER_BEHAVIOR.md +0 -0
  189. {tactus-0.21.1 → tactus-0.23.0}/features/documentation/Lua DSL/README.md +0 -0
  190. {tactus-0.21.1 → tactus-0.23.0}/features/environment.py +0 -0
  191. {tactus-0.21.1 → tactus-0.23.0}/features/steps/agent_primitives_steps.py +0 -0
  192. {tactus-0.21.1 → tactus-0.23.0}/features/steps/checkpointing_steps.py +0 -0
  193. {tactus-0.21.1 → tactus-0.23.0}/features/steps/control_flow_steps.py +0 -0
  194. {tactus-0.21.1 → tactus-0.23.0}/features/steps/dspy_agent_steps.py +0 -0
  195. {tactus-0.21.1 → tactus-0.23.0}/features/steps/dspy_history_steps.py +0 -0
  196. {tactus-0.21.1 → tactus-0.23.0}/features/steps/dspy_lm_steps.py +0 -0
  197. {tactus-0.21.1 → tactus-0.23.0}/features/steps/dspy_module_steps.py +0 -0
  198. {tactus-0.21.1 → tactus-0.23.0}/features/steps/dspy_prediction_steps.py +0 -0
  199. {tactus-0.21.1 → tactus-0.23.0}/features/steps/dspy_signature_steps.py +0 -0
  200. {tactus-0.21.1 → tactus-0.23.0}/features/steps/example_procedures_steps.py +0 -0
  201. {tactus-0.21.1 → tactus-0.23.0}/features/steps/file_operations_steps.py +0 -0
  202. {tactus-0.21.1 → tactus-0.23.0}/features/steps/human_in_the_loop_steps.py +0 -0
  203. {tactus-0.21.1 → tactus-0.23.0}/features/steps/ide_server_steps.py +0 -0
  204. {tactus-0.21.1 → tactus-0.23.0}/features/steps/json_operations_steps.py +0 -0
  205. {tactus-0.21.1 → tactus-0.23.0}/features/steps/logging_steps.py +0 -0
  206. {tactus-0.21.1 → tactus-0.23.0}/features/steps/lua_dsl_validation_steps.py +0 -0
  207. {tactus-0.21.1 → tactus-0.23.0}/features/steps/lua_integration_steps.py +0 -0
  208. {tactus-0.21.1 → tactus-0.23.0}/features/steps/mocking_steps.py +0 -0
  209. {tactus-0.21.1 → tactus-0.23.0}/features/steps/procedure_calls_steps.py +0 -0
  210. {tactus-0.21.1 → tactus-0.23.0}/features/steps/result_and_output_steps.py +0 -0
  211. {tactus-0.21.1 → tactus-0.23.0}/features/steps/retry_logic_steps.py +0 -0
  212. {tactus-0.21.1 → tactus-0.23.0}/features/steps/session_management_steps.py +0 -0
  213. {tactus-0.21.1 → tactus-0.23.0}/features/steps/stage_tracking_steps.py +0 -0
  214. {tactus-0.21.1 → tactus-0.23.0}/features/steps/state_management_steps.py +0 -0
  215. {tactus-0.21.1 → tactus-0.23.0}/features/steps/storage_backend_steps.py +0 -0
  216. {tactus-0.21.1 → tactus-0.23.0}/features/steps/support/__init__.py +0 -0
  217. {tactus-0.21.1 → tactus-0.23.0}/features/steps/tool_integration_steps.py +0 -0
  218. {tactus-0.21.1 → tactus-0.23.0}/features/steps/workflow_execution_steps.py +0 -0
  219. {tactus-0.21.1 → tactus-0.23.0}/scripts/audit_examples_mocking.py +0 -0
  220. {tactus-0.21.1 → tactus-0.23.0}/scripts/convert_examples.py +0 -0
  221. {tactus-0.21.1 → tactus-0.23.0}/start-web-ide.sh +0 -0
  222. {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/__init__.py +0 -0
  223. {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/cli_hitl.py +0 -0
  224. {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/cli_log.py +0 -0
  225. {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/file_storage.py +0 -0
  226. {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/http_callback_log.py +0 -0
  227. {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/ide_log.py +0 -0
  228. {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/lua_tools.py +0 -0
  229. {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/mcp.py +0 -0
  230. {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/mcp_manager.py +0 -0
  231. {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/memory.py +0 -0
  232. {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/plugins.py +0 -0
  233. {tactus-0.21.1 → tactus-0.23.0}/tactus/backends/http_backend.py +0 -0
  234. {tactus-0.21.1 → tactus-0.23.0}/tactus/backends/model_backend.py +0 -0
  235. {tactus-0.21.1 → tactus-0.23.0}/tactus/backends/pytorch_backend.py +0 -0
  236. {tactus-0.21.1 → tactus-0.23.0}/tactus/cli/__init__.py +0 -0
  237. {tactus-0.21.1 → tactus-0.23.0}/tactus/cli/app.py +0 -0
  238. {tactus-0.21.1 → tactus-0.23.0}/tactus/cli/commands/__init__.py +0 -0
  239. {tactus-0.21.1 → tactus-0.23.0}/tactus/core/__init__.py +0 -0
  240. {tactus-0.21.1 → tactus-0.23.0}/tactus/core/config_manager.py +0 -0
  241. {tactus-0.21.1 → tactus-0.23.0}/tactus/core/dependencies/__init__.py +0 -0
  242. {tactus-0.21.1 → tactus-0.23.0}/tactus/core/dependencies/registry.py +0 -0
  243. {tactus-0.21.1 → tactus-0.23.0}/tactus/core/dsl_stubs.py +0 -0
  244. {tactus-0.21.1 → tactus-0.23.0}/tactus/core/exceptions.py +0 -0
  245. {tactus-0.21.1 → tactus-0.23.0}/tactus/core/execution_context.py +0 -0
  246. {tactus-0.21.1 → tactus-0.23.0}/tactus/core/lua_sandbox.py +0 -0
  247. {tactus-0.21.1 → tactus-0.23.0}/tactus/core/message_history_manager.py +0 -0
  248. {tactus-0.21.1 → tactus-0.23.0}/tactus/core/mocking.py +0 -0
  249. {tactus-0.21.1 → tactus-0.23.0}/tactus/core/output_validator.py +0 -0
  250. {tactus-0.21.1 → tactus-0.23.0}/tactus/core/registry.py +0 -0
  251. {tactus-0.21.1 → tactus-0.23.0}/tactus/core/runtime.py +0 -0
  252. {tactus-0.21.1 → tactus-0.23.0}/tactus/core/template_resolver.py +0 -0
  253. {tactus-0.21.1 → tactus-0.23.0}/tactus/core/yaml_parser.py +0 -0
  254. {tactus-0.21.1 → tactus-0.23.0}/tactus/docker/Dockerfile +0 -0
  255. {tactus-0.21.1 → tactus-0.23.0}/tactus/docker/entrypoint.sh +0 -0
  256. {tactus-0.21.1 → tactus-0.23.0}/tactus/dspy/__init__.py +0 -0
  257. {tactus-0.21.1 → tactus-0.23.0}/tactus/dspy/history.py +0 -0
  258. {tactus-0.21.1 → tactus-0.23.0}/tactus/dspy/prediction.py +0 -0
  259. {tactus-0.21.1 → tactus-0.23.0}/tactus/dspy/signature.py +0 -0
  260. {tactus-0.21.1 → tactus-0.23.0}/tactus/ide/__init__.py +0 -0
  261. {tactus-0.21.1 → tactus-0.23.0}/tactus/ide/coding_assistant.py +0 -0
  262. {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/__init__.py +0 -0
  263. {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/control.py +0 -0
  264. {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/file.py +0 -0
  265. {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/handles.py +0 -0
  266. {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/human.py +0 -0
  267. {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/json.py +0 -0
  268. {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/log.py +0 -0
  269. {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/message_history.py +0 -0
  270. {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/model.py +0 -0
  271. {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/procedure.py +0 -0
  272. {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/procedure_callable.py +0 -0
  273. {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/retry.py +0 -0
  274. {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/session.py +0 -0
  275. {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/stage.py +0 -0
  276. {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/state.py +0 -0
  277. {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/step.py +0 -0
  278. {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/system.py +0 -0
  279. {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/tool.py +0 -0
  280. {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/tool_handle.py +0 -0
  281. {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/toolset.py +0 -0
  282. {tactus-0.21.1 → tactus-0.23.0}/tactus/protocols/__init__.py +0 -0
  283. {tactus-0.21.1 → tactus-0.23.0}/tactus/protocols/chat_recorder.py +0 -0
  284. {tactus-0.21.1 → tactus-0.23.0}/tactus/protocols/config.py +0 -0
  285. {tactus-0.21.1 → tactus-0.23.0}/tactus/protocols/cost.py +0 -0
  286. {tactus-0.21.1 → tactus-0.23.0}/tactus/protocols/hitl.py +0 -0
  287. {tactus-0.21.1 → tactus-0.23.0}/tactus/protocols/log_handler.py +0 -0
  288. {tactus-0.21.1 → tactus-0.23.0}/tactus/protocols/models.py +0 -0
  289. {tactus-0.21.1 → tactus-0.23.0}/tactus/protocols/result.py +0 -0
  290. {tactus-0.21.1 → tactus-0.23.0}/tactus/protocols/storage.py +0 -0
  291. {tactus-0.21.1 → tactus-0.23.0}/tactus/providers/__init__.py +0 -0
  292. {tactus-0.21.1 → tactus-0.23.0}/tactus/providers/base.py +0 -0
  293. {tactus-0.21.1 → tactus-0.23.0}/tactus/providers/bedrock.py +0 -0
  294. {tactus-0.21.1 → tactus-0.23.0}/tactus/providers/google.py +0 -0
  295. {tactus-0.21.1 → tactus-0.23.0}/tactus/providers/openai.py +0 -0
  296. {tactus-0.21.1 → tactus-0.23.0}/tactus/sandbox/__init__.py +0 -0
  297. {tactus-0.21.1 → tactus-0.23.0}/tactus/sandbox/config.py +0 -0
  298. {tactus-0.21.1 → tactus-0.23.0}/tactus/sandbox/entrypoint.py +0 -0
  299. {tactus-0.21.1 → tactus-0.23.0}/tactus/sandbox/protocol.py +0 -0
  300. {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/__init__.py +0 -0
  301. {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/io/__init__.py +0 -0
  302. {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/io/csv.py +0 -0
  303. {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/io/excel.py +0 -0
  304. {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/io/file.py +0 -0
  305. {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/io/hdf5.py +0 -0
  306. {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/io/json.py +0 -0
  307. {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/io/parquet.py +0 -0
  308. {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/io/tsv.py +0 -0
  309. {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/loader.py +0 -0
  310. {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/tac/tactus/tools/done.tac +0 -0
  311. {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/tac/tactus/tools/log.tac +0 -0
  312. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/README.md +0 -0
  313. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/__init__.py +0 -0
  314. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/behave_integration.py +0 -0
  315. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/context.py +0 -0
  316. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/eval_models.py +0 -0
  317. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/evaluation_runner.py +0 -0
  318. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/evaluators.py +0 -0
  319. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/events.py +0 -0
  320. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/gherkin_parser.py +0 -0
  321. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/mock_agent.py +0 -0
  322. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/mock_dependencies.py +0 -0
  323. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/mock_hitl.py +0 -0
  324. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/mock_registry.py +0 -0
  325. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/mock_tools.py +0 -0
  326. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/models.py +0 -0
  327. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/pydantic_eval_runner.py +0 -0
  328. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/steps/__init__.py +0 -0
  329. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/steps/builtin.py +0 -0
  330. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/steps/custom.py +0 -0
  331. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/steps/registry.py +0 -0
  332. {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/test_runner.py +0 -0
  333. {tactus-0.21.1 → tactus-0.23.0}/tactus/tracing/__init__.py +0 -0
  334. {tactus-0.21.1 → tactus-0.23.0}/tactus/tracing/trace_manager.py +0 -0
  335. {tactus-0.21.1 → tactus-0.23.0}/tactus/utils/__init__.py +0 -0
  336. {tactus-0.21.1 → tactus-0.23.0}/tactus/utils/cost_calculator.py +0 -0
  337. {tactus-0.21.1 → tactus-0.23.0}/tactus/utils/model_pricing.py +0 -0
  338. {tactus-0.21.1 → tactus-0.23.0}/tactus/utils/safe_file_library.py +0 -0
  339. {tactus-0.21.1 → tactus-0.23.0}/tactus/utils/safe_libraries.py +0 -0
  340. {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/LuaLexerBase.py +0 -0
  341. {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/LuaParserBase.py +0 -0
  342. {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/README.md +0 -0
  343. {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/__init__.py +0 -0
  344. {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/error_listener.py +0 -0
  345. {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/generated/LuaLexer.interp +0 -0
  346. {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/generated/LuaLexer.py +0 -0
  347. {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/generated/LuaLexer.tokens +0 -0
  348. {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/generated/LuaLexerBase.py +0 -0
  349. {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/generated/LuaParser.interp +0 -0
  350. {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/generated/LuaParser.py +0 -0
  351. {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/generated/LuaParser.tokens +0 -0
  352. {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/generated/LuaParserBase.py +0 -0
  353. {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/generated/LuaParserVisitor.py +0 -0
  354. {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/generated/__init__.py +0 -0
  355. {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/grammar/LuaLexer.g4 +0 -0
  356. {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/grammar/LuaParser.g4 +0 -0
  357. {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/semantic_visitor.py +0 -0
  358. {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/validator.py +0 -0
  359. {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/.gitignore +0 -0
  360. {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/README.md +0 -0
  361. {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/RUN_ELECTRON.md +0 -0
  362. {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/SETUP_COMPLETE.md +0 -0
  363. {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/backend/hook-lupa.py +0 -0
  364. {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/backend/tactus_backend.spec +0 -0
  365. {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/package-lock.json +0 -0
  366. {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/package.json +0 -0
  367. {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/preload/preload.ts +0 -0
  368. {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/preload/tsconfig.json +0 -0
  369. {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/rebuild-and-test.sh +0 -0
  370. {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/scripts/build-backend.js +0 -0
  371. {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/scripts/build-frontend.js +0 -0
  372. {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/src/backend-manager.ts +0 -0
  373. {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/src/main.ts +0 -0
  374. {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/src/menu.ts +0 -0
  375. {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/tsconfig.json +0 -0
  376. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/ARCHITECTURE.md +0 -0
  377. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/CHANGELOG.md +0 -0
  378. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/DEV_MODE.md +0 -0
  379. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/QUICK_START.md +0 -0
  380. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/README.md +0 -0
  381. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/RESTART_INSTRUCTIONS.md +0 -0
  382. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/TROUBLESHOOTING.md +0 -0
  383. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/backend/README.md +0 -0
  384. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/backend/events.py +0 -0
  385. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/backend/logging_capture.py +0 -0
  386. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/backend/lsp_server.py +0 -0
  387. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/backend/requirements.txt +0 -0
  388. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/backend/tactus_lsp_handler.py +0 -0
  389. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/backend/test_lsp_server.py +0 -0
  390. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/dev.sh +0 -0
  391. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/.storybook/main.ts +0 -0
  392. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/.storybook/preview.ts +0 -0
  393. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/.storybook/vitest.setup.ts +0 -0
  394. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/README.md +0 -0
  395. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/demo.ts +0 -0
  396. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/index.html +0 -0
  397. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/jest.config.js +0 -0
  398. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/package.json +0 -0
  399. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/postcss.config.js +0 -0
  400. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/Editor.tsx +0 -0
  401. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/LSPClient.ts +0 -0
  402. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/LSPClientHTTP.ts +0 -0
  403. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/TactusLanguage.ts +0 -0
  404. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/commands/registry.ts +0 -0
  405. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/CheckpointSummary.tsx +0 -0
  406. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/CollapsibleRun.tsx +0 -0
  407. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/Duration.stories.tsx +0 -0
  408. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/Duration.tsx +0 -0
  409. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/FileTree.stories.tsx +0 -0
  410. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/FileTree.tsx +0 -0
  411. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/MessageFeed.tsx +0 -0
  412. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ProcedureInputsDisplay.stories.tsx +0 -0
  413. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ProcedureInputsDisplay.tsx +0 -0
  414. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ProcedureInputsModal.stories.tsx +0 -0
  415. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ProcedureInputsModal.tsx +0 -0
  416. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ProcedureTab.stories.tsx +0 -0
  417. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ProcedureTab.tsx +0 -0
  418. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ResizeHandle.tsx +0 -0
  419. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ResultsSidebar.stories.tsx +0 -0
  420. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/TestOptionsModal.tsx +0 -0
  421. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/Timestamp.stories.tsx +0 -0
  422. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/Timestamp.tsx +0 -0
  423. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/TopMenuBar.stories.tsx +0 -0
  424. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/debugger/CheckpointDetails.stories.tsx +0 -0
  425. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/debugger/CheckpointDetails.tsx +0 -0
  426. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/debugger/CheckpointList.stories.tsx +0 -0
  427. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/debugger/CheckpointList.tsx +0 -0
  428. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/debugger/DebuggerPanel.stories.tsx +0 -0
  429. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/debugger/DebuggerPanel.tsx +0 -0
  430. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/debugger/RunSelector.stories.tsx +0 -0
  431. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/debugger/RunSelector.tsx +0 -0
  432. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/debugger/StatisticsPanel.stories.tsx +0 -0
  433. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/debugger/StatisticsPanel.tsx +0 -0
  434. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/AgentStreamingComponent.tsx +0 -0
  435. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/BaseEventComponent.tsx +0 -0
  436. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/CheckpointEventComponent.tsx +0 -0
  437. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/CollapsibleTestScenario.tsx +0 -0
  438. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/ContainerStatusEventComponent.tsx +0 -0
  439. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/CostEventComponent.stories.tsx +0 -0
  440. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/CostEventComponent.tsx +0 -0
  441. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/EvaluationEventComponent.stories.tsx +0 -0
  442. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/EvaluationEventComponent.tsx +0 -0
  443. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/EventRenderer.tsx +0 -0
  444. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/ExecutionEventComponent.stories.tsx +0 -0
  445. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/ExecutionEventComponent.tsx +0 -0
  446. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/ExecutionSummaryEventComponent.stories.tsx +0 -0
  447. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/ExecutionSummaryEventComponent.tsx +0 -0
  448. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/LoadingEventComponent.stories.tsx +0 -0
  449. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/LoadingEventComponent.tsx +0 -0
  450. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/LogCluster.tsx +0 -0
  451. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/LogEventComponent.stories.tsx +0 -0
  452. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/LogEventComponent.tsx +0 -0
  453. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/OutputEventComponent.stories.tsx +0 -0
  454. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/OutputEventComponent.tsx +0 -0
  455. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/TestEventComponent.stories.tsx +0 -0
  456. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/TestEventComponent.tsx +0 -0
  457. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/TestProgressContainer.tsx +0 -0
  458. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/ToolCallEventComponent.tsx +0 -0
  459. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/ValidationEventComponent.stories.tsx +0 -0
  460. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/ValidationEventComponent.tsx +0 -0
  461. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/metadata/AgentsSection.tsx +0 -0
  462. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/metadata/EvaluationsSection.tsx +0 -0
  463. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/metadata/MetadataSections.stories.tsx +0 -0
  464. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/metadata/OutputsSection.tsx +0 -0
  465. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/metadata/ParametersSection.tsx +0 -0
  466. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/metadata/SpecificationsSection.tsx +0 -0
  467. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/metadata/StagesSection.tsx +0 -0
  468. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/metadata/ToolsSection.tsx +0 -0
  469. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/scenarios/EvaluateScenarios.stories.tsx +0 -0
  470. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/scenarios/RunScenarios.stories.tsx +0 -0
  471. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/scenarios/TestScenarios.stories.tsx +0 -0
  472. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/scenarios/ValidationScenarios.stories.tsx +0 -0
  473. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/theme-provider.tsx +0 -0
  474. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/ai/conversation.tsx +0 -0
  475. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/ai/message.tsx +0 -0
  476. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/ai/prompt-input.tsx +0 -0
  477. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/button.tsx +0 -0
  478. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/dialog.tsx +0 -0
  479. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/input.tsx +0 -0
  480. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/logo.stories.tsx +0 -0
  481. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/logo.tsx +0 -0
  482. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/menubar.tsx +0 -0
  483. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/scroll-area.tsx +0 -0
  484. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/separator.tsx +0 -0
  485. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/tabs.tsx +0 -0
  486. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/hooks/useEventStream.ts +0 -0
  487. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/hooks/useTracing.ts +0 -0
  488. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/index.css +0 -0
  489. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/lib/utils.ts +0 -0
  490. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/main.tsx +0 -0
  491. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/types/events.ts +0 -0
  492. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/types/metadata.ts +0 -0
  493. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/types/results.ts +0 -0
  494. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/types/tracing.ts +0 -0
  495. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/validation/TactusValidator.ts +0 -0
  496. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/validation/generated/LuaParser.interp +0 -0
  497. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/validation/generated/LuaParser.tokens +0 -0
  498. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/validation/types.ts +0 -0
  499. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/vite-env.d.ts +0 -0
  500. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/tailwind.config.js +0 -0
  501. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/tsconfig.json +0 -0
  502. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/tsconfig.node.json +0 -0
  503. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/vite.config.ts +0 -0
  504. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/vitest.shims.d.ts +0 -0
  505. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/package.json +0 -0
  506. {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/start-dev.sh +0 -0
  507. {tactus-0.21.1 → tactus-0.23.0}/tests/__init__.py +0 -0
  508. {tactus-0.21.1 → tactus-0.23.0}/tests/adapters/__init__.py +0 -0
  509. {tactus-0.21.1 → tactus-0.23.0}/tests/adapters/test_lua_tools_adapter.py +0 -0
  510. {tactus-0.21.1 → tactus-0.23.0}/tests/adapters/test_plugins.py +0 -0
  511. {tactus-0.21.1 → tactus-0.23.0}/tests/cli/__init__.py +0 -0
  512. {tactus-0.21.1 → tactus-0.23.0}/tests/cli/test_cli.py +0 -0
  513. {tactus-0.21.1 → tactus-0.23.0}/tests/cli/test_cli_inputs.py +0 -0
  514. {tactus-0.21.1 → tactus-0.23.0}/tests/conftest.py +0 -0
  515. {tactus-0.21.1 → tactus-0.23.0}/tests/core/__init__.py +0 -0
  516. {tactus-0.21.1 → tactus-0.23.0}/tests/core/test_config_manager.py +0 -0
  517. {tactus-0.21.1 → tactus-0.23.0}/tests/core/test_determinism_safety.py +0 -0
  518. {tactus-0.21.1 → tactus-0.23.0}/tests/core/test_lua_sandbox_security.py +0 -0
  519. {tactus-0.21.1 → tactus-0.23.0}/tests/core/test_runtime_inputs.py +0 -0
  520. {tactus-0.21.1 → tactus-0.23.0}/tests/core/test_script_mode.py +0 -0
  521. {tactus-0.21.1 → tactus-0.23.0}/tests/dspy/__init__.py +0 -0
  522. {tactus-0.21.1 → tactus-0.23.0}/tests/dspy/test_streaming.py +0 -0
  523. {tactus-0.21.1 → tactus-0.23.0}/tests/fixtures/__init__.py +0 -0
  524. {tactus-0.21.1 → tactus-0.23.0}/tests/fixtures/test_mcp_server.py +0 -0
  525. {tactus-0.21.1 → tactus-0.23.0}/tests/integration/test_named_procedures.py +0 -0
  526. {tactus-0.21.1 → tactus-0.23.0}/tests/mocks/__init__.py +0 -0
  527. {tactus-0.21.1 → tactus-0.23.0}/tests/mocks/llm_mocks.py +0 -0
  528. {tactus-0.21.1 → tactus-0.23.0}/tests/primitives/test_checkpoint_primitive.py +0 -0
  529. {tactus-0.21.1 → tactus-0.23.0}/tests/primitives/test_retry_primitive.py +0 -0
  530. {tactus-0.21.1 → tactus-0.23.0}/tests/primitives/test_state_primitive.py +0 -0
  531. {tactus-0.21.1 → tactus-0.23.0}/tests/primitives/test_system_alert.py +0 -0
  532. {tactus-0.21.1 → tactus-0.23.0}/tests/primitives/test_tool_primitive.py +0 -0
  533. {tactus-0.21.1 → tactus-0.23.0}/tests/primitives/test_toolset_dsl.py +0 -0
  534. {tactus-0.21.1 → tactus-0.23.0}/tests/stdlib/__init__.py +0 -0
  535. {tactus-0.21.1 → tactus-0.23.0}/tests/stdlib/test_loader.py +0 -0
  536. {tactus-0.21.1 → tactus-0.23.0}/tests/stdlib/test_require_python.py +0 -0
  537. {tactus-0.21.1 → tactus-0.23.0}/tests/test_checkpoints_integration.py +0 -0
  538. {tactus-0.21.1 → tactus-0.23.0}/tests/test_mcp_integration.py +0 -0
  539. {tactus-0.21.1 → tactus-0.23.0}/tests/test_tracing.py +0 -0
  540. {tactus-0.21.1 → tactus-0.23.0}/tests/testing/__init__.py +0 -0
  541. {tactus-0.21.1 → tactus-0.23.0}/tests/testing/conftest.py +0 -0
  542. {tactus-0.21.1 → tactus-0.23.0}/tests/testing/test_all_examples.py +0 -0
  543. {tactus-0.21.1 → tactus-0.23.0}/tests/testing/test_e2e.py +0 -0
  544. {tactus-0.21.1 → tactus-0.23.0}/tests/testing/test_gherkin_parser.py +0 -0
  545. {tactus-0.21.1 → tactus-0.23.0}/tests/testing/test_integration.py +0 -0
  546. {tactus-0.21.1 → tactus-0.23.0}/tests/testing/test_models.py +0 -0
  547. {tactus-0.21.1 → tactus-0.23.0}/tests/testing/test_runtime_integration.py +0 -0
  548. {tactus-0.21.1 → tactus-0.23.0}/tests/testing/test_step_registry.py +0 -0
  549. {tactus-0.21.1 → tactus-0.23.0}/tests/utils/__init__.py +0 -0
  550. {tactus-0.21.1 → tactus-0.23.0}/tests/utils/test_safe_file_library.py +0 -0
  551. {tactus-0.21.1 → tactus-0.23.0}/tests/validation/__init__.py +0 -0
@@ -2,6 +2,23 @@
2
2
 
3
3
  <!-- version list -->
4
4
 
5
+ ## v0.23.0 (2026-01-11)
6
+
7
+ ### Features
8
+
9
+ - Add AI chat assistant to Tactus IDE with streaming and tool execution
10
+ ([`81f544a`](https://github.com/AnthusAI/Tactus/commit/81f544a16e86a8f26b328583b432ad2f1ad26504))
11
+
12
+
13
+ ## v0.22.0 (2026-01-10)
14
+
15
+ ### Features
16
+
17
+ - **agent**: Add configurable `module` parameter for DSPy module selection (#21)
18
+ ([#21](https://github.com/AnthusAI/Tactus/pull/21),
19
+ [`0c93af0`](https://github.com/AnthusAI/Tactus/commit/0c93af0575d191be58ed0635ed236e359d8b35af))
20
+
21
+
5
22
  ## v0.21.1 (2026-01-10)
6
23
 
7
24
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tactus
3
- Version: 0.21.1
3
+ Version: 0.23.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
@@ -1633,6 +1633,72 @@ bedrock_agent = Agent {
1633
1633
  }
1634
1634
  ```
1635
1635
 
1636
+ ### Module Configuration
1637
+
1638
+ Agents can specify which DSPy module strategy to use via the `module` parameter. This controls how prompts are formatted and whether reasoning steps are included.
1639
+
1640
+ **Default module** (Predict):
1641
+
1642
+ ```lua
1643
+ local done = require("tactus.tools.done")
1644
+
1645
+ simple_agent = Agent {
1646
+ provider = "openai",
1647
+ model = "gpt-4o-mini",
1648
+ system_prompt = "You are a helpful assistant.",
1649
+ tools = {done}
1650
+ }
1651
+ ```
1652
+
1653
+ **ChainOfThought module** (adds reasoning steps):
1654
+
1655
+ ```lua
1656
+ local done = require("tactus.tools.done")
1657
+
1658
+ thinking_agent = Agent {
1659
+ provider = "openai",
1660
+ model = "gpt-4o",
1661
+ module = "ChainOfThought",
1662
+ system_prompt = "You are a careful analyst.",
1663
+ tools = {done}
1664
+ }
1665
+ ```
1666
+
1667
+ **Raw module** (minimal formatting for cost optimization):
1668
+
1669
+ ```lua
1670
+ local done = require("tactus.tools.done")
1671
+
1672
+ efficient_agent = Agent {
1673
+ provider = "openai",
1674
+ model = "gpt-4o-mini",
1675
+ module = "Raw",
1676
+ system_prompt = "You are concise.",
1677
+ tools = {done}
1678
+ }
1679
+ ```
1680
+
1681
+ **Available module options:**
1682
+
1683
+ - **`"Predict"`** (default): Simple prediction without reasoning traces. Uses DSPy's standard field delimiters (~300-400 characters overhead per call).
1684
+
1685
+ - **`"ChainOfThought"`**: Adds step-by-step reasoning before generating the final response. Useful for complex tasks requiring explicit reasoning. Increases token usage due to reasoning output (~500-2000 additional tokens depending on complexity).
1686
+
1687
+ - **`"Raw"`**: Minimal formatting with direct LM calls. No DSPy delimiter overhead. Best for simple interactions, cost optimization, or when prompt space is constrained.
1688
+
1689
+ **Token overhead comparison:**
1690
+
1691
+ For a simple "Hello, World!" interaction:
1692
+ - **Raw**: 29 tokens total (20 prompt + 9 completion)
1693
+ - **Predict**: 230 tokens total (210 prompt + 19 completion)
1694
+ - **Difference**: ~8x more tokens with Predict due to delimiter formatting
1695
+
1696
+ **When to use each module:**
1697
+
1698
+ - Use **`Raw`** for simple interactions, high-volume API calls, or when minimizing cost is a priority
1699
+ - Use **`Predict`** when you need structured outputs or are using DSPy's optimization features (bootstrapping, etc.)
1700
+ - Use **`ChainOfThought`** for complex reasoning tasks where you want to see the agent's thought process
1701
+
1636
1702
  ---
1637
1703
 
1638
1704
  ## DSPy Integration
@@ -0,0 +1,8 @@
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
+ return World("Hello, World!")
@@ -0,0 +1,11 @@
1
+ -- Test Raw module with minimal formatting
2
+ WorldRaw = Agent {
3
+ provider = "openai",
4
+ model = "gpt-4o-mini",
5
+ system_prompt = "Your name is World.",
6
+ module = "Raw" -- Use raw module for minimal overhead
7
+ }
8
+
9
+ return {
10
+ WorldRaw("Hello, World!")
11
+ }
@@ -0,0 +1,11 @@
1
+ -- Test Raw module streaming
2
+ Story = Agent {
3
+ provider = "openai",
4
+ model = "gpt-4o-mini",
5
+ system_prompt = "You are a storyteller.",
6
+ module = "Raw" -- Use raw module for minimal overhead
7
+ }
8
+
9
+ return {
10
+ Story("Tell me a very short story about a robot.")
11
+ }
@@ -0,0 +1,60 @@
1
+ Feature: Chat Assistant with File Tools
2
+ As a developer using the Tactus IDE
3
+ I want to chat with an AI assistant that can read files
4
+ So that I can get help understanding my codebase
5
+
6
+ Background:
7
+ Given a workspace at "examples/"
8
+ And the chat assistant is configured with:
9
+ | parameter | value |
10
+ | provider | openai |
11
+ | model | gpt-4o |
12
+ | temperature | 0.7 |
13
+
14
+ Scenario: Basic chat without tools
15
+ When I send the message "Hello"
16
+ Then the assistant should respond
17
+ And the response should contain text
18
+ And no tools should be called
19
+
20
+ Scenario: View a file
21
+ When I send the message "Show me 01-basics-hello-world.tac"
22
+ Then the assistant should call tool "str_replace_based_edit_tool"
23
+ And the tool should be called with:
24
+ | parameter | value |
25
+ | command | view |
26
+ | path | 01-basics-hello-world.tac |
27
+ And the tool result should contain line numbers
28
+ And the response should describe the file contents
29
+
30
+ Scenario: List directory contents
31
+ When I send the message "What files are in this directory?"
32
+ Then the assistant should call tool "str_replace_based_edit_tool"
33
+ And the tool should be called with:
34
+ | parameter | value |
35
+ | command | view |
36
+ | path | . |
37
+ And the tool result should show directories and files
38
+ And the response should list the files
39
+
40
+ Scenario: View specific line range
41
+ Given a workspace at "."
42
+ And the chat assistant is configured with:
43
+ | parameter | value |
44
+ | provider | openai |
45
+ | model | gpt-4o |
46
+ | temperature | 0.7 |
47
+ When I send the message "Show me lines 10-20 of tactus/validation/validator.py"
48
+ Then the assistant should call tool "str_replace_based_edit_tool"
49
+ And the tool should be called with:
50
+ | parameter | value |
51
+ | command | view |
52
+ | path | tactus/validation/validator.py |
53
+ | view_range | [10, 20] |
54
+ And the tool result should contain exactly 11 lines
55
+
56
+ Scenario: Security - reject path outside workspace
57
+ When I send the message "Show me /etc/passwd"
58
+ Then the assistant should call tool "str_replace_based_edit_tool"
59
+ And the tool result should contain "Error"
60
+ And the tool result should contain "outside workspace"
@@ -0,0 +1,160 @@
1
+ """
2
+ Step definitions for chat assistant feature.
3
+ """
4
+
5
+ from behave import given, when, then
6
+ from features.steps.support.harnesses import ChatAssistantHarness
7
+ import ast
8
+
9
+
10
+ @given('a workspace at "{path}"')
11
+ def step_workspace_at(context, path):
12
+ """Set up workspace for chat assistant."""
13
+ context.workspace_root = path
14
+ context.chat = ChatAssistantHarness(workspace_root=path)
15
+
16
+
17
+ @given("the chat assistant is configured with:")
18
+ def step_configure_assistant(context):
19
+ """Configure assistant with parameters from table."""
20
+ config = {row["parameter"]: row["value"] for row in context.table}
21
+ context.chat.configure(config)
22
+
23
+
24
+ @when('I send the message "{message}"')
25
+ def step_send_message(context, message):
26
+ """Send a message to the assistant."""
27
+ context.chat.send_message(message)
28
+
29
+
30
+ @then("the assistant should respond")
31
+ def step_assistant_responds(context):
32
+ """Verify assistant generated a response."""
33
+ assert context.chat.has_response(), "No response from assistant"
34
+
35
+
36
+ @then("the response should contain text")
37
+ def step_response_contains_text(context):
38
+ """Verify response has text content."""
39
+ response = context.chat.get_response()
40
+ assert response, "Response is empty"
41
+ assert len(response.strip()) > 0, "Response contains no text"
42
+
43
+
44
+ @then("no tools should be called")
45
+ def step_no_tools_called(context):
46
+ """Verify no tools were invoked."""
47
+ tool_calls = context.chat.get_tool_calls()
48
+ assert len(tool_calls) == 0, f"Expected no tool calls, but got: {tool_calls}"
49
+
50
+
51
+ @then('the assistant should call tool "{tool_name}"')
52
+ def step_tool_called(context, tool_name):
53
+ """Verify a specific tool was called."""
54
+ assert context.chat.tool_was_called(
55
+ tool_name
56
+ ), f"Tool '{tool_name}' was not called. Called: {context.chat.get_tool_calls()}"
57
+
58
+
59
+ @then("the tool should be called with:")
60
+ def step_tool_called_with(context):
61
+ """Verify tool was called with specific parameters."""
62
+ expected_params = {row["parameter"]: row["value"] for row in context.table}
63
+
64
+ # Get the last tool call
65
+ tool_calls = context.chat.get_tool_calls()
66
+ assert len(tool_calls) > 0, "No tool calls found"
67
+
68
+ last_call = tool_calls[-1]
69
+ actual_params = last_call["params"]
70
+
71
+ for param, expected_value in expected_params.items():
72
+ assert (
73
+ param in actual_params
74
+ ), f"Parameter '{param}' not found in tool call. Available: {actual_params.keys()}"
75
+
76
+ actual_value = actual_params[param]
77
+
78
+ # Handle list parameters (like view_range)
79
+ if expected_value.startswith("["):
80
+ expected_value = ast.literal_eval(expected_value)
81
+
82
+ assert (
83
+ actual_value == expected_value
84
+ ), f"Parameter '{param}': expected {expected_value}, got {actual_value}"
85
+
86
+
87
+ @then("the tool result should contain line numbers")
88
+ def step_tool_result_has_line_numbers(context):
89
+ """Verify tool result includes line numbers."""
90
+ tool_calls = context.chat.get_tool_calls()
91
+ assert len(tool_calls) > 0, "No tool calls found"
92
+
93
+ last_call = tool_calls[-1]
94
+ result = last_call["result"]
95
+
96
+ # Check for line number format: "1: content"
97
+ lines = result.split("\n")
98
+ has_line_numbers = any(
99
+ line.strip() and line.split(":")[0].strip().isdigit() for line in lines if ":" in line
100
+ )
101
+
102
+ assert has_line_numbers, f"Tool result does not contain line numbers:\n{result}"
103
+
104
+
105
+ @then("the response should describe the file contents")
106
+ def step_response_describes_file(context):
107
+ """Verify response mentions file contents."""
108
+ response = context.chat.get_response()
109
+ assert response, "No response from assistant"
110
+ # Basic check - response should be non-empty
111
+ assert len(response.strip()) > 0, "Response is empty"
112
+
113
+
114
+ @then("the tool result should show directories and files")
115
+ def step_tool_result_shows_dirs_and_files(context):
116
+ """Verify tool result shows directory listing."""
117
+ tool_calls = context.chat.get_tool_calls()
118
+ assert len(tool_calls) > 0, "No tool calls found"
119
+
120
+ last_call = tool_calls[-1]
121
+ result = last_call["result"]
122
+
123
+ # Check for [DIR] or [FILE] markers
124
+ has_markers = "[DIR]" in result or "[FILE]" in result
125
+ assert has_markers, f"Tool result does not show directory markers:\n{result}"
126
+
127
+
128
+ @then("the response should list the files")
129
+ def step_response_lists_files(context):
130
+ """Verify response mentions files."""
131
+ response = context.chat.get_response()
132
+ assert response, "No response from assistant"
133
+ assert len(response.strip()) > 0, "Response is empty"
134
+
135
+
136
+ @then("the tool result should contain exactly {count:d} lines")
137
+ def step_tool_result_line_count(context, count):
138
+ """Verify tool result has specific number of lines."""
139
+ tool_calls = context.chat.get_tool_calls()
140
+ assert len(tool_calls) > 0, "No tool calls found"
141
+
142
+ last_call = tool_calls[-1]
143
+ result = last_call["result"]
144
+
145
+ lines = [line for line in result.split("\n") if line.strip()]
146
+ actual_count = len(lines)
147
+
148
+ assert actual_count == count, f"Expected {count} lines, got {actual_count}:\n{result}"
149
+
150
+
151
+ @then('the tool result should contain "{text}"')
152
+ def step_tool_result_contains(context, text):
153
+ """Verify tool result contains specific text."""
154
+ tool_calls = context.chat.get_tool_calls()
155
+ assert len(tool_calls) > 0, "No tool calls found"
156
+
157
+ last_call = tool_calls[-1]
158
+ result = last_call["result"]
159
+
160
+ assert text in result, f"Tool result does not contain '{text}':\n{result}"
@@ -515,3 +515,161 @@ class FakeSessionStore:
515
515
  for session in self.sessions.values()
516
516
  if session.context.get("task_type") == task_type
517
517
  ]
518
+
519
+
520
+ # ---------------------------------------------------------------------------
521
+ # Chat assistant helpers
522
+ # ---------------------------------------------------------------------------
523
+
524
+
525
+ class ChatAssistantHarness:
526
+ """
527
+ Test harness for chat assistant that captures tool calls and responses.
528
+
529
+ Mocks the LLM to return deterministic tool calls based on message patterns,
530
+ but calls the actual tool implementations to verify they work correctly.
531
+ """
532
+
533
+ def __init__(self, workspace_root: str):
534
+ import os
535
+
536
+ # Convert to absolute path if relative
537
+ if not os.path.isabs(workspace_root):
538
+ # Resolve relative to project root (where behave is run from)
539
+ workspace_root = os.path.abspath(workspace_root)
540
+ self.workspace_root = workspace_root
541
+ self.config = {}
542
+ self.messages = []
543
+ self.tool_calls = []
544
+ self.response = None
545
+
546
+ def configure(self, config: Dict[str, Any]):
547
+ """Configure assistant (provider, model, etc.)"""
548
+ self.config = config
549
+
550
+ def send_message(self, message: str):
551
+ """
552
+ Send message and simulate assistant behavior.
553
+
554
+ For testing, we mock the LLM's decision-making but call real tools.
555
+ """
556
+ self.messages.append({"role": "user", "content": message})
557
+
558
+ # Mock LLM behavior based on message patterns
559
+ message_lower = message.lower()
560
+
561
+ if "hello" in message_lower and "show" not in message_lower:
562
+ # Simple greeting - no tools
563
+ self.response = "Hello! How can I help you today?"
564
+
565
+ elif "show me" in message_lower or "what files" in message_lower:
566
+ # File operation - simulate tool call
567
+ self._simulate_file_tool_call(message)
568
+
569
+ else:
570
+ # Default response
571
+ self.response = "I'm not sure how to help with that."
572
+
573
+ def _simulate_file_tool_call(self, message: str):
574
+ """
575
+ Simulate LLM deciding to call the file tool.
576
+
577
+ Parse the message to extract file path and determine command,
578
+ then call the actual tool implementation.
579
+ """
580
+ # Extract file path from message
581
+ # Simple pattern matching for testing
582
+ import re
583
+
584
+ # Check for line range first (more specific pattern)
585
+ view_range = None
586
+ range_match = re.search(r"lines (\d+)-(\d+) of (.+)", message.lower())
587
+ if range_match:
588
+ start = int(range_match.group(1))
589
+ end = int(range_match.group(2))
590
+ view_range = [start, end]
591
+ path = range_match.group(3).strip()
592
+ else:
593
+ # Pattern: "show me <path>" or "what files in <path>"
594
+ path_match = re.search(r"show me ([^\s]+)", message.lower())
595
+ if not path_match:
596
+ # Pattern: "what files are in this directory"
597
+ if "in this directory" in message.lower():
598
+ path = "."
599
+ else:
600
+ # Pattern: "what files are in the <path> directory"
601
+ path_match = re.search(r"in the ([^\s]+) directory", message.lower())
602
+ if path_match:
603
+ # Add trailing slash for directory
604
+ path = path_match.group(1) + "/"
605
+ else:
606
+ self.response = "I couldn't find a file path in your message."
607
+ return
608
+ else:
609
+ path = path_match.group(1)
610
+
611
+ # Determine if it's a directory or file
612
+ command = "view"
613
+
614
+ # Call the actual tool (will be implemented later)
615
+ try:
616
+ # For now, just record the call - tool implementation comes next
617
+ tool_result = self._call_tool(command, path, view_range)
618
+
619
+ self.tool_calls.append(
620
+ {
621
+ "tool": "str_replace_based_edit_tool",
622
+ "params": {
623
+ "command": command,
624
+ "path": path,
625
+ **({"view_range": view_range} if view_range else {}),
626
+ },
627
+ "result": tool_result,
628
+ }
629
+ )
630
+
631
+ # Generate response based on tool result
632
+ if "Error" in tool_result:
633
+ self.response = f"I encountered an error: {tool_result}"
634
+ else:
635
+ self.response = f"Here's what I found:\n\n{tool_result}"
636
+
637
+ except Exception as e:
638
+ self.response = f"Error calling tool: {str(e)}"
639
+
640
+ def _call_tool(self, command: str, path: str, view_range: Optional[List[int]] = None) -> str:
641
+ """
642
+ Call the actual tool implementation.
643
+ """
644
+ # Import the real tool
645
+ import sys
646
+ import os
647
+
648
+ backend_path = os.path.join(
649
+ os.path.dirname(__file__), "..", "..", "..", "tactus-ide", "backend"
650
+ )
651
+ if backend_path not in sys.path:
652
+ sys.path.insert(0, backend_path)
653
+
654
+ from text_editor_tool import str_replace_based_edit_tool
655
+
656
+ # Call the real tool
657
+ return str_replace_based_edit_tool(
658
+ workspace_root=self.workspace_root, command=command, path=path, view_range=view_range
659
+ )
660
+
661
+ def has_response(self) -> bool:
662
+ """Check if assistant generated a response."""
663
+ return self.response is not None
664
+
665
+ def get_response(self) -> str:
666
+ """Get the assistant's response."""
667
+ return self.response or ""
668
+
669
+ def get_tool_calls(self) -> List[Dict[str, Any]]:
670
+ """Get list of tool calls made."""
671
+ return self.tool_calls
672
+
673
+ def tool_was_called(self, tool_name: str) -> bool:
674
+ """Check if a specific tool was called."""
675
+ return any(call["tool"] == tool_name for call in self.tool_calls)
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "tactus"
7
- version = "0.21.1"
7
+ version = "0.23.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.21.1"
8
+ __version__ = "0.23.0"
9
9
 
10
10
  # Core exports
11
11
  from tactus.core.runtime import TactusRuntime
@@ -6,7 +6,7 @@ This module provides an Agent implementation built on top of DSPy primitives
6
6
  as the original pydantic_ai-based Agent while using DSPy for LLM interactions.
7
7
 
8
8
  The Agent uses:
9
- - Module with chain_of_thought strategy for reasoning
9
+ - Configurable DSPy module (default: Predict for simple pass-through, or ChainOfThought for reasoning)
10
10
  - History for conversation management
11
11
  - Tool handling similar to DSPy's ReAct pattern
12
12
  - Unified mocking via Mocks {} primitive
@@ -56,6 +56,7 @@ class DSPyAgentHandle:
56
56
  temperature: float = 0.7,
57
57
  max_tokens: Optional[int] = None,
58
58
  model_type: Optional[str] = None,
59
+ module: str = "Predict",
59
60
  initial_message: Optional[str] = None,
60
61
  registry: Any = None,
61
62
  mock_manager: Any = None,
@@ -78,6 +79,10 @@ class DSPyAgentHandle:
78
79
  temperature: Model temperature (default: 0.7)
79
80
  max_tokens: Maximum tokens for response
80
81
  model_type: Model type for DSPy (e.g., "chat", "responses" for reasoning models)
82
+ module: DSPy module type to use (default: "Predict"). Options:
83
+ - "Predict": Simple pass-through prediction (no reasoning traces)
84
+ - "ChainOfThought": Adds step-by-step reasoning before response
85
+ - "Raw": Minimal formatting, direct LM calls (lowest token overhead)
81
86
  initial_message: Initial message to send on first turn if no inject
82
87
  registry: Optional Registry instance for accessing mocks
83
88
  mock_manager: Optional MockManager instance for checking mocks
@@ -98,6 +103,7 @@ class DSPyAgentHandle:
98
103
  self.temperature = temperature
99
104
  self.max_tokens = max_tokens
100
105
  self.model_type = model_type
106
+ self.module = module
101
107
  self.initial_message = initial_message
102
108
  self.registry = registry
103
109
  self.mock_manager = mock_manager
@@ -267,6 +273,32 @@ class DSPyAgentHandle:
267
273
  cost_stats=cost_stats,
268
274
  )
269
275
 
276
+ def _module_to_strategy(self, module: str) -> str:
277
+ """
278
+ Map DSPy module name to internal strategy name.
279
+
280
+ Args:
281
+ module: DSPy module name (e.g., "Predict", "ChainOfThought")
282
+
283
+ Returns:
284
+ Internal strategy name for create_module()
285
+
286
+ Raises:
287
+ ValueError: If module name is not recognized
288
+ """
289
+ mapping = {
290
+ "Predict": "predict",
291
+ "ChainOfThought": "chain_of_thought",
292
+ "Raw": "raw",
293
+ # Future modules can be added here:
294
+ # "ReAct": "react",
295
+ # "ProgramOfThought": "program_of_thought",
296
+ }
297
+ strategy = mapping.get(module)
298
+ if strategy is None:
299
+ raise ValueError(f"Unknown module '{module}'. Supported: {list(mapping.keys())}")
300
+ return strategy
301
+
270
302
  def _build_module(self) -> TactusModule:
271
303
  """Build the internal DSPy module for this agent."""
272
304
  # Create a signature for agent turns
@@ -284,7 +316,7 @@ class DSPyAgentHandle:
284
316
  f"{self.name}_module",
285
317
  {
286
318
  "signature": signature,
287
- "strategy": "chain_of_thought",
319
+ "strategy": self._module_to_strategy(self.module),
288
320
  },
289
321
  )
290
322
 
@@ -874,6 +906,7 @@ def create_dspy_agent(
874
906
  - model: Model name (LiteLLM format)
875
907
  - tools: List of tools
876
908
  - toolsets: List of toolset names
909
+ - module: DSPy module type (default: "Predict"). Options: "Predict", "ChainOfThought"
877
910
  - Other optional configuration
878
911
  registry: Optional Registry instance for accessing mocks
879
912
  mock_manager: Optional MockManager instance for checking mocks
@@ -901,6 +934,7 @@ def create_dspy_agent(
901
934
  temperature=config.get("temperature", 0.7),
902
935
  max_tokens=config.get("max_tokens"),
903
936
  model_type=config.get("model_type"),
937
+ module=config.get("module", "Predict"),
904
938
  initial_message=config.get("initial_message"),
905
939
  registry=registry,
906
940
  mock_manager=mock_manager,
@@ -921,6 +955,7 @@ def create_dspy_agent(
921
955
  "temperature",
922
956
  "max_tokens",
923
957
  "model_type",
958
+ "module",
924
959
  "initial_message",
925
960
  "log_handler",
926
961
  "disable_streaming",