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.
- {tactus-0.21.1 → tactus-0.23.0}/CHANGELOG.md +17 -0
- {tactus-0.21.1 → tactus-0.23.0}/PKG-INFO +1 -1
- {tactus-0.21.1 → tactus-0.23.0}/SPECIFICATION.md +66 -0
- tactus-0.23.0/examples/01-basics-hello-world.tac +8 -0
- tactus-0.23.0/examples/test-raw-module.tac +11 -0
- tactus-0.23.0/examples/test-raw-streaming.tac +11 -0
- tactus-0.23.0/features/57_chat_assistant.feature +60 -0
- tactus-0.23.0/features/steps/chat_assistant_steps.py +160 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/support/harnesses.py +158 -0
- {tactus-0.21.1 → tactus-0.23.0}/pyproject.toml +1 -1
- {tactus-0.21.1 → tactus-0.23.0}/tactus/__init__.py +1 -1
- {tactus-0.21.1 → tactus-0.23.0}/tactus/dspy/agent.py +37 -2
- {tactus-0.21.1 → tactus-0.23.0}/tactus/dspy/config.py +66 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/dspy/module.py +144 -4
- {tactus-0.21.1 → tactus-0.23.0}/tactus/ide/server.py +66 -54
- {tactus-0.21.1 → tactus-0.23.0}/tactus/sandbox/container_runner.py +76 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/sandbox/docker_manager.py +103 -3
- tactus-0.23.0/tactus-ide/backend/assistant_service.py +444 -0
- tactus-0.23.0/tactus-ide/backend/assistant_tools.py +397 -0
- tactus-0.23.0/tactus-ide/backend/chat_server.py +339 -0
- tactus-0.23.0/tactus-ide/backend/text_editor_tool.py +172 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/package-lock.json +0 -154
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/App.tsx +3 -3
- tactus-0.23.0/tactus-ide/frontend/src/components/ChatSidebar.tsx +24 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ResultsSidebar.tsx +64 -43
- tactus-0.23.0/tactus-ide/frontend/src/components/chat/ChatInterface.tsx +96 -0
- tactus-0.23.0/tactus-ide/frontend/src/components/chat/MessageInput.tsx +84 -0
- tactus-0.23.0/tactus-ide/frontend/src/components/chat/MessageList.tsx +125 -0
- tactus-0.23.0/tactus-ide/frontend/src/hooks/useChatSSE.ts +204 -0
- tactus-0.23.0/tests/dspy/test_module_parameter.py +142 -0
- tactus-0.21.1/examples/01-basics-hello-world.tac +0 -9
- tactus-0.21.1/tactus-ide/frontend/src/components/ChatSidebar.tsx +0 -195
- {tactus-0.21.1 → tactus-0.23.0}/.claude/agents.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/.github/workflows/desktop-release.yml +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/.github/workflows/release.yml +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/.gitignore +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/.tactus/config.yml.example +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/AGENTS.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/IMPLEMENTATION.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/LICENSE +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/Makefile +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/README.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/SPECIFICATION.md.bak +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/TECHNICAL_DEBT.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/behave.ini +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/docs/AGENTS.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/docs/BDD_TESTING.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/docs/CONFIGURATION.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/docs/DURABILITY.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/docs/FILE_IO.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/docs/SANDBOXING.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/docs/STREAMING.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/docs/TOOLS.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/docs/TOOL_ROADMAP.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/.tactus/config.yml +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/02-basics-simple-logic.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/03-basics-parameters.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/04-basics-simple-agent.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/05-basics-multi-model.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/06-basics-streaming.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/07-basics-bedrock.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/08-basics-models.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/09-basics-google-gemini.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/10-feature-state.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/11-feature-message-history.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/12-feature-structured-output.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/13-feature-session.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/14-feature-per-turn-tools-simple.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/14-feature-per-turn-tools.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/15-feature-local-tools.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/16-feature-toolsets-advanced.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/17-feature-toolsets-dsl.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/18-feature-lua-tools-individual.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/18-feature-lua-tools-inline.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/18-feature-lua-tools-toolset.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/19-feature-direct-tool-calls.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/20-bdd-complete.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/20-bdd-complete.tac.bak +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/20-bdd-complete.tac.bak2 +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/21-bdd-passing.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/21-bdd-passing.tac.bak +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/21-bdd-passing.tac.bak2 +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/30-eval-simple.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/31-eval-demo.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/32-eval-success-rate.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/33-eval-thresholds.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/34-eval-dataset.jsonl +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/34-eval-dataset.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/35-eval-trace.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/35-eval-trace.tac.bak +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/35-eval-trace.tac.bak2 +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/36-eval-advanced.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/37-eval-comprehensive.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/37-eval-comprehensive.tac.bak +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/37-eval-comprehensive.tac.bak2 +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/39-model-simple.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/40-mcp-test.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/40-model-text-classifier.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/41-mcp-simple.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/41-model-pytorch.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/43-sub-procedure-simple.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/44-sub-procedure-composition.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/45-sub-procedure-recursive.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/46-checkpoint-explicit.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/47-checkpoint-expensive-ops.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/48-script-mode-simple.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/50-inputs-showcase.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/51-inputs-calculator.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/52-file-io-basics.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/53-tsv-file-io.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/54-json-file-io.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/55-parquet-file-io.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/56-hdf5-file-io.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/57-excel-file-io.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/58-text-file-io.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/60-tool-sources.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/61-inline-toolset-lua.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/62-mcp-toolset-by-server.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/63-toolset-import-from-file.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/64-require-modules.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/65-optional-state-demo.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/70-mocking-static.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/71-mocking-temporal.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/72-mocking-conditional.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/99-misc-test-loading.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/README.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/app_config.ini +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/data/sample.csv +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/demo_output.json +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/helpers/math_module.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/helpers/product.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/helpers/string_module.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/helpers/sum.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/helpers/text_tools.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/inventory_summary.tsv +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/mock-config.json +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/models/README.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/models/create_sentiment_model.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/output_summary.txt +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/tools/calculations.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/tools/data_analysis.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/tools/search.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/with_dependencies/README.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/with_dependencies/simple_http_test.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/examples/with_dependencies/time_lookup.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/01_state_management.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/02_checkpointing.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/03_human_in_the_loop.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/04_control_flow.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/05_tool_integration.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/06_retry_logic.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/07_file_operations.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/08_agent_primitives.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/09_workflow_execution.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/10_lua_integration.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/11_storage_backends.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/12_json_operations.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/13_logging.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/14_stage_and_step_tracking.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/15_procedure_calls.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/16_session_management.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/17_lua_dsl_validation.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/18_example_procedures.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/19_ide_server.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/20_parameters.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/21_outputs.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/23_prompts.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/24_bdd_specifications.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/25_bdd_custom_steps.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/26_bdd_evaluation.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/27_default_settings.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/28_custom_prompts.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/29_execution_settings.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/30_session_filters.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/31_matchers.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/32_result_object.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/33_output_type.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/42_model_primitive.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/43_sub_procedure_checkpointing.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/46_explicit_checkpoint.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/48_script_mode.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/51_dspy_lm_config.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/52_dspy_signature.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/53_dspy_module.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/54_dspy_history.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/55_dspy_prediction.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/56_dspy_agent.feature +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/documentation/IDE_SERVER_BEHAVIOR.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/documentation/Lua DSL/README.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/environment.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/agent_primitives_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/checkpointing_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/control_flow_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/dspy_agent_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/dspy_history_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/dspy_lm_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/dspy_module_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/dspy_prediction_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/dspy_signature_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/example_procedures_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/file_operations_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/human_in_the_loop_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/ide_server_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/json_operations_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/logging_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/lua_dsl_validation_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/lua_integration_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/mocking_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/procedure_calls_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/result_and_output_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/retry_logic_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/session_management_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/stage_tracking_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/state_management_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/storage_backend_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/support/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/tool_integration_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/features/steps/workflow_execution_steps.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/scripts/audit_examples_mocking.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/scripts/convert_examples.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/start-web-ide.sh +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/cli_hitl.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/cli_log.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/file_storage.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/http_callback_log.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/ide_log.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/lua_tools.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/mcp.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/mcp_manager.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/memory.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/adapters/plugins.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/backends/http_backend.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/backends/model_backend.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/backends/pytorch_backend.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/cli/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/cli/app.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/cli/commands/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/core/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/core/config_manager.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/core/dependencies/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/core/dependencies/registry.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/core/dsl_stubs.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/core/exceptions.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/core/execution_context.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/core/lua_sandbox.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/core/message_history_manager.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/core/mocking.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/core/output_validator.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/core/registry.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/core/runtime.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/core/template_resolver.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/core/yaml_parser.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/docker/Dockerfile +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/docker/entrypoint.sh +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/dspy/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/dspy/history.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/dspy/prediction.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/dspy/signature.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/ide/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/ide/coding_assistant.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/control.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/file.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/handles.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/human.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/json.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/log.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/message_history.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/model.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/procedure.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/procedure_callable.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/retry.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/session.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/stage.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/state.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/step.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/system.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/tool.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/tool_handle.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/primitives/toolset.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/protocols/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/protocols/chat_recorder.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/protocols/config.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/protocols/cost.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/protocols/hitl.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/protocols/log_handler.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/protocols/models.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/protocols/result.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/protocols/storage.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/providers/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/providers/base.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/providers/bedrock.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/providers/google.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/providers/openai.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/sandbox/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/sandbox/config.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/sandbox/entrypoint.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/sandbox/protocol.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/io/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/io/csv.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/io/excel.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/io/file.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/io/hdf5.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/io/json.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/io/parquet.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/io/tsv.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/loader.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/tac/tactus/tools/done.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/stdlib/tac/tactus/tools/log.tac +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/README.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/behave_integration.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/context.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/eval_models.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/evaluation_runner.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/evaluators.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/events.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/gherkin_parser.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/mock_agent.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/mock_dependencies.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/mock_hitl.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/mock_registry.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/mock_tools.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/models.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/pydantic_eval_runner.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/steps/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/steps/builtin.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/steps/custom.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/steps/registry.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/testing/test_runner.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/tracing/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/tracing/trace_manager.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/utils/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/utils/cost_calculator.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/utils/model_pricing.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/utils/safe_file_library.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/utils/safe_libraries.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/LuaLexerBase.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/LuaParserBase.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/README.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/error_listener.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/generated/LuaLexer.interp +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/generated/LuaLexer.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/generated/LuaLexer.tokens +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/generated/LuaLexerBase.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/generated/LuaParser.interp +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/generated/LuaParser.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/generated/LuaParser.tokens +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/generated/LuaParserBase.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/generated/LuaParserVisitor.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/generated/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/grammar/LuaLexer.g4 +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/grammar/LuaParser.g4 +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/semantic_visitor.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus/validation/validator.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/.gitignore +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/README.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/RUN_ELECTRON.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/SETUP_COMPLETE.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/backend/hook-lupa.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/backend/tactus_backend.spec +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/package-lock.json +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/package.json +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/preload/preload.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/preload/tsconfig.json +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/rebuild-and-test.sh +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/scripts/build-backend.js +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/scripts/build-frontend.js +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/src/backend-manager.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/src/main.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/src/menu.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-desktop/tsconfig.json +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/ARCHITECTURE.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/CHANGELOG.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/DEV_MODE.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/QUICK_START.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/README.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/RESTART_INSTRUCTIONS.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/TROUBLESHOOTING.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/backend/README.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/backend/events.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/backend/logging_capture.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/backend/lsp_server.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/backend/requirements.txt +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/backend/tactus_lsp_handler.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/backend/test_lsp_server.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/dev.sh +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/.storybook/main.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/.storybook/preview.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/.storybook/vitest.setup.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/README.md +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/demo.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/index.html +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/jest.config.js +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/package.json +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/postcss.config.js +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/Editor.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/LSPClient.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/LSPClientHTTP.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/TactusLanguage.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/commands/registry.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/CheckpointSummary.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/CollapsibleRun.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/Duration.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/Duration.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/FileTree.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/FileTree.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/MessageFeed.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ProcedureInputsDisplay.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ProcedureInputsDisplay.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ProcedureInputsModal.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ProcedureInputsModal.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ProcedureTab.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ProcedureTab.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ResizeHandle.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ResultsSidebar.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/TestOptionsModal.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/Timestamp.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/Timestamp.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/TopMenuBar.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/debugger/CheckpointDetails.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/debugger/CheckpointDetails.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/debugger/CheckpointList.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/debugger/CheckpointList.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/debugger/DebuggerPanel.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/debugger/DebuggerPanel.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/debugger/RunSelector.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/debugger/RunSelector.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/debugger/StatisticsPanel.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/debugger/StatisticsPanel.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/AgentStreamingComponent.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/BaseEventComponent.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/CheckpointEventComponent.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/CollapsibleTestScenario.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/ContainerStatusEventComponent.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/CostEventComponent.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/CostEventComponent.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/EvaluationEventComponent.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/EvaluationEventComponent.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/EventRenderer.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/ExecutionEventComponent.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/ExecutionEventComponent.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/ExecutionSummaryEventComponent.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/ExecutionSummaryEventComponent.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/LoadingEventComponent.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/LoadingEventComponent.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/LogCluster.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/LogEventComponent.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/LogEventComponent.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/OutputEventComponent.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/OutputEventComponent.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/TestEventComponent.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/TestEventComponent.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/TestProgressContainer.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/ToolCallEventComponent.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/ValidationEventComponent.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/events/ValidationEventComponent.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/metadata/AgentsSection.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/metadata/EvaluationsSection.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/metadata/MetadataSections.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/metadata/OutputsSection.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/metadata/ParametersSection.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/metadata/SpecificationsSection.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/metadata/StagesSection.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/metadata/ToolsSection.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/scenarios/EvaluateScenarios.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/scenarios/RunScenarios.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/scenarios/TestScenarios.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/scenarios/ValidationScenarios.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/theme-provider.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/ai/conversation.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/ai/message.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/ai/prompt-input.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/button.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/dialog.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/input.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/logo.stories.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/logo.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/menubar.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/scroll-area.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/separator.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/components/ui/tabs.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/hooks/useEventStream.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/hooks/useTracing.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/index.css +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/lib/utils.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/main.tsx +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/types/events.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/types/metadata.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/types/results.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/types/tracing.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/validation/TactusValidator.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/validation/generated/LuaParser.interp +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/validation/generated/LuaParser.tokens +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/validation/types.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/src/vite-env.d.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/tailwind.config.js +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/tsconfig.json +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/tsconfig.node.json +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/vite.config.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/frontend/vitest.shims.d.ts +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/package.json +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tactus-ide/start-dev.sh +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/adapters/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/adapters/test_lua_tools_adapter.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/adapters/test_plugins.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/cli/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/cli/test_cli.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/cli/test_cli_inputs.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/conftest.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/core/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/core/test_config_manager.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/core/test_determinism_safety.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/core/test_lua_sandbox_security.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/core/test_runtime_inputs.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/core/test_script_mode.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/dspy/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/dspy/test_streaming.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/fixtures/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/fixtures/test_mcp_server.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/integration/test_named_procedures.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/mocks/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/mocks/llm_mocks.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/primitives/test_checkpoint_primitive.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/primitives/test_retry_primitive.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/primitives/test_state_primitive.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/primitives/test_system_alert.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/primitives/test_tool_primitive.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/primitives/test_toolset_dsl.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/stdlib/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/stdlib/test_loader.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/stdlib/test_require_python.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/test_checkpoints_integration.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/test_mcp_integration.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/test_tracing.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/testing/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/testing/conftest.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/testing/test_all_examples.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/testing/test_e2e.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/testing/test_gherkin_parser.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/testing/test_integration.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/testing/test_models.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/testing/test_runtime_integration.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/testing/test_step_registry.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/utils/__init__.py +0 -0
- {tactus-0.21.1 → tactus-0.23.0}/tests/utils/test_safe_file_library.py +0 -0
- {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
|
|
@@ -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,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)
|
|
@@ -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
|
-
-
|
|
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":
|
|
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",
|