7e55d522b4
CI / lint (pull_request) Successful in 19s
CI / typecheck (pull_request) Successful in 49s
CI / quality (pull_request) Successful in 34s
CI / security (pull_request) Successful in 59s
CI / build (pull_request) Successful in 29s
CI / helm (pull_request) Successful in 24s
CI / unit_tests (pull_request) Successful in 7m0s
CI / e2e_tests (pull_request) Successful in 17m41s
CI / coverage (pull_request) Successful in 10m42s
CI / integration_tests (pull_request) Successful in 23m17s
CI / docker (pull_request) Successful in 1m21s
CI / status-check (pull_request) Successful in 1s
CI / benchmark-publish (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Successful in 56m6s
- What was implemented
- Added execute: str | None = Field(default=None, description="Hook for tool execution") to ToolLifecycle in src/cleveragents/domain/models/core/tool.py, completing the four-stage lifecycle (discover / activate / execute / deactivate) as required by the spec.
- Updated Tool.as_cli_dict() to render the lifecycle block (including execute) when set, and to omit the lifecycle block entirely when no hooks are configured, keeping CLI output clean for tools without lifecycle hooks.
- Created features/tool_lifecycle_execute_hook.feature with 8 Behave scenarios covering:
- issue-capture TDD test
- all four hooks (discover, activate, execute, deactivate)
- execute defaults to None
- execute set independently
- from_config parsing
- as_cli_dict rendering
- Created features/steps/tool_lifecycle_execute_hook_steps.py with all step definitions implementing Given/When/Then for the scenarios.
- Key design decisions
- The execute field follows the same pattern as the existing discover, activate, and deactivate fields: str | None with Field(default=None).
- as_cli_dict() renders the lifecycle block only when at least one hook is set (non-None), ensuring clean output for tools that do not utilize lifecycle hooks.
- The issue-capture TDD scenario uses @tdd_issue and @tdd_issue_2820 tags (without @tdd_expected_fail since the fix is in place), aligning with the test-driven approach described in the metadata.
- Impact and considerations
- Changes are additive and backward-compatible; tools configured without lifecycle hooks will continue to render without a lifecycle block.
- Introduces Behave-based acceptance tests to validate the four-stage lifecycle handling and CLI rendering.
- Affects only ToolLifecycle modeling, CLI rendering, and associated tests; no changes to external APIs.
ISSUES CLOSED: #2820
59 lines
2.8 KiB
Gherkin
59 lines
2.8 KiB
Gherkin
Feature: ToolLifecycle domain model execute hook
|
|
Verify that ToolLifecycle exposes the execute hook required by the
|
|
spec four-stage lifecycle (discover / activate / execute / deactivate).
|
|
|
|
# ---------------------------------------------------------------
|
|
# TDD issue-capture test for #2820
|
|
# The @tdd_expected_fail tag is removed once the fix is in place.
|
|
# ---------------------------------------------------------------
|
|
|
|
@tdd_issue @tdd_issue_2820
|
|
Scenario: ToolLifecycle has an execute field (issue capture)
|
|
When I create a tool lifecycle with execute hook "my.module.execute"
|
|
Then the tool lifecycle execute should be "my.module.execute"
|
|
|
|
# ---------------------------------------------------------------
|
|
# Positive scenarios — all four lifecycle hooks present
|
|
# ---------------------------------------------------------------
|
|
|
|
Scenario: ToolLifecycle with all four hooks set
|
|
When I create a tool lifecycle with all four hooks set
|
|
Then the tool lifecycle discover should be "hooks.discover"
|
|
And the tool lifecycle activate should be "hooks.activate"
|
|
And the tool lifecycle execute should be "hooks.execute"
|
|
And the tool lifecycle deactivate should be "hooks.deactivate"
|
|
|
|
Scenario: ToolLifecycle execute defaults to None
|
|
When I create a tool lifecycle with no hooks
|
|
Then the tool lifecycle execute should be None
|
|
|
|
Scenario: ToolLifecycle execute can be set independently
|
|
When I create a tool lifecycle with only execute hook "run.tool"
|
|
Then the tool lifecycle execute should be "run.tool"
|
|
And the tool lifecycle discover should be None
|
|
And the tool lifecycle activate should be None
|
|
And the tool lifecycle deactivate should be None
|
|
|
|
# ---------------------------------------------------------------
|
|
# Round-trip YAML serialisation/deserialisation
|
|
# ---------------------------------------------------------------
|
|
|
|
Scenario: Tool from_config parses execute hook from YAML lifecycle block
|
|
When I load a tool from config with lifecycle execute "my.execute.hook"
|
|
Then the tool model should be created
|
|
And the tool lifecycle execute should be "my.execute.hook"
|
|
|
|
Scenario: Tool from_config with execute=None preserves None
|
|
When I load a tool from config with lifecycle execute None
|
|
Then the tool model should be created
|
|
And the tool lifecycle execute should be None
|
|
|
|
Scenario: Tool as_cli_dict renders execute hook when set
|
|
When I create a tool with lifecycle execute "cli.execute.hook" and call as_cli_dict
|
|
Then the tool cli dict lifecycle should have key "execute"
|
|
And the tool cli dict lifecycle execute should be "cli.execute.hook"
|
|
|
|
Scenario: Tool as_cli_dict omits execute when None
|
|
When I create a tool with no lifecycle and call as_cli_dict
|
|
Then the tool cli dict should not have key "lifecycle"
|