Files
cleveragents-core/features/tool_lifecycle_execute_hook.feature
freemo 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
fix(domain): add missing execute hook to ToolLifecycle model to satisfy spec four-stage lifecycle
- 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
2026-04-05 04:19:52 +00:00

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"