18482b938f
CI / typecheck (push) Waiting to run
CI / lint (push) Waiting to run
CI / security (push) Waiting to run
CI / quality (push) Waiting to run
CI / unit_tests (push) Waiting to run
CI / integration_tests (push) Waiting to run
CI / coverage (push) Blocked by required conditions
CI / build (push) Waiting to run
CI / docker (push) Blocked by required conditions
CI / lint (pull_request) Successful in 14s
CI / typecheck (pull_request) Successful in 27s
CI / security (pull_request) Successful in 22s
CI / quality (pull_request) Successful in 15s
CI / integration_tests (pull_request) Successful in 4m32s
CI / build (pull_request) Successful in 16s
CI / unit_tests (pull_request) Successful in 9m45s
CI / coverage (pull_request) Successful in 6m53s
CI / docker (pull_request) Successful in 39s
212 lines
7.8 KiB
Gherkin
212 lines
7.8 KiB
Gherkin
Feature: Tool Runtime Core
|
|
As a developer
|
|
I want a tool runtime with registry, runner, and lifecycle management
|
|
So that tools can be registered, discovered, activated, executed, and deactivated
|
|
|
|
# ---- Tool Registration ----
|
|
|
|
Scenario: Register a tool in the registry
|
|
Given a tool registry
|
|
And a tool spec named "test/echo" with a handler
|
|
When I register the tool spec
|
|
Then the tool should be in the registry
|
|
|
|
Scenario: Get a registered tool by name
|
|
Given a tool registry
|
|
And a registered tool spec named "test/echo"
|
|
When I get the tool by name "test/echo"
|
|
Then the retrieved tool spec name should be "test/echo"
|
|
|
|
Scenario: List all tools in the registry
|
|
Given a tool registry
|
|
And a registered tool spec named "test/alpha"
|
|
And a registered tool spec named "test/beta"
|
|
When I list all tools
|
|
Then the tool list should contain 2 tools
|
|
|
|
Scenario: List tools filtered by namespace
|
|
Given a tool registry
|
|
And a registered tool spec named "ns1/tool-a"
|
|
And a registered tool spec named "ns2/tool-b"
|
|
And a registered tool spec named "ns1/tool-c"
|
|
When I list tools with namespace "ns1"
|
|
Then the tool list should contain 2 tools
|
|
|
|
Scenario: Remove a tool from the registry
|
|
Given a tool registry
|
|
And a registered tool spec named "test/remove-me"
|
|
When I remove the tool "test/remove-me"
|
|
Then the removal should succeed
|
|
And getting "test/remove-me" should return None
|
|
|
|
# ---- Missing Tool Errors ----
|
|
|
|
Scenario: Get a missing tool returns None
|
|
Given a tool registry
|
|
When I get the tool by name "test/nonexistent"
|
|
Then the retrieved tool spec should be None
|
|
|
|
Scenario: Remove a missing tool returns False
|
|
Given a tool registry
|
|
When I remove the tool "test/nonexistent"
|
|
Then the removal should fail
|
|
|
|
# ---- Name Collision Detection ----
|
|
|
|
Scenario: Duplicate registration raises ToolError
|
|
Given a tool registry
|
|
And a registered tool spec named "test/duplicate"
|
|
When I try to register a duplicate tool "test/duplicate"
|
|
Then a ToolError should be raised with type "RegistrationError"
|
|
|
|
# ---- Capability Flag Validation ----
|
|
|
|
Scenario: Tool spec with read-only capability
|
|
Given a tool spec named "test/reader" with read_only capability
|
|
Then the tool spec capabilities read_only should be True
|
|
And the tool spec capabilities writes should be False
|
|
|
|
Scenario: Tool spec with write capability
|
|
Given a tool spec named "test/writer" with writes capability
|
|
Then the tool spec capabilities writes should be True
|
|
|
|
# ---- Tool Lifecycle Hook Ordering ----
|
|
|
|
Scenario: Full lifecycle discover activate execute deactivate
|
|
Given a tool registry
|
|
And a registered tool spec named "test/lifecycle"
|
|
And a tool runner for the registry
|
|
When I discover tools from the runner
|
|
And I activate tool "test/lifecycle"
|
|
And I execute tool "test/lifecycle" with inputs {"key": "value"}
|
|
And I deactivate tool "test/lifecycle"
|
|
Then the lifecycle should complete in order
|
|
|
|
# ---- Execute With Valid Inputs ----
|
|
|
|
Scenario: Execute with valid inputs returns success
|
|
Given a tool registry
|
|
And a registered tool spec named "test/add" with an adder handler
|
|
And a tool runner for the registry
|
|
When I activate tool "test/add"
|
|
And I execute tool "test/add" with inputs {"a": 1, "b": 2}
|
|
Then the tool result should be successful
|
|
And the tool result output should contain key "sum"
|
|
And the tool result duration_ms should be non-negative
|
|
|
|
# ---- Execute With Handler Failure ----
|
|
|
|
Scenario: Execute with handler failure returns failure result
|
|
Given a tool registry
|
|
And a registered tool spec named "test/fail" with a failing handler
|
|
And a tool runner for the registry
|
|
When I execute tool "test/fail" with inputs {}
|
|
Then the tool result should not be successful
|
|
And the tool result error should not be empty
|
|
|
|
# ---- Thread-Safe Concurrent Registration ----
|
|
|
|
Scenario: Concurrent registrations are thread-safe
|
|
Given a tool registry
|
|
When I concurrently register 50 tools
|
|
Then all 50 tools should be in the registry
|
|
|
|
# ---- JSON-Serialisable IO Validation ----
|
|
|
|
Scenario: Execute rejects non-JSON-serialisable inputs
|
|
Given a tool registry
|
|
And a registered tool spec named "test/json-check"
|
|
And a tool runner for the registry
|
|
When I execute tool "test/json-check" with non-serialisable inputs
|
|
Then the tool result should not be successful
|
|
And the tool result error should mention "JSON"
|
|
|
|
Scenario: Execute rejects non-JSON-serialisable outputs
|
|
Given a tool registry
|
|
And a registered tool spec named "test/bad-output" with a non-serialisable handler
|
|
And a tool runner for the registry
|
|
When I execute tool "test/bad-output" with inputs {}
|
|
Then the tool result should not be successful
|
|
And the tool result error should mention "JSON"
|
|
|
|
# ---- ToolError Exception ----
|
|
|
|
Scenario: ToolError carries structured context
|
|
When I create a ToolError with name "test/err" type "TestError" and details "something broke"
|
|
Then the ToolError tool_name should be "test/err"
|
|
And the ToolError error_type should be "TestError"
|
|
And the ToolError details should be "something broke"
|
|
And the ToolError message should contain "TestError"
|
|
|
|
# ---- ToolResult Model ----
|
|
|
|
Scenario: ToolResult with success and metadata
|
|
When I create a ToolResult with success True and metadata
|
|
Then the ToolResult success should be True
|
|
And the ToolResult metadata should not be empty
|
|
|
|
Scenario: ToolResult with failure
|
|
When I create a ToolResult with success False and error "handler crashed"
|
|
Then the ToolResult success should be False
|
|
And the ToolResult error should be "handler crashed"
|
|
|
|
# ---- Runner Activate Errors ----
|
|
|
|
Scenario: Activate missing tool raises ToolError
|
|
Given a tool registry
|
|
And a tool runner for the registry
|
|
When I try to activate a missing tool "test/missing"
|
|
Then a ToolError should be raised with type "ActivationError"
|
|
|
|
# ---- Runner Execute Missing Tool ----
|
|
|
|
Scenario: Execute missing tool raises ToolError
|
|
Given a tool registry
|
|
And a tool runner for the registry
|
|
When I try to execute a missing tool "test/missing" with inputs {}
|
|
Then a ToolError should be raised with type "ExecutionError"
|
|
|
|
# ---- Runner Deactivate ----
|
|
|
|
Scenario: Deactivate a non-active tool returns False
|
|
Given a tool registry
|
|
And a tool runner for the registry
|
|
When I deactivate tool "test/nonexistent"
|
|
Then the deactivation should return False
|
|
|
|
# ---- Discover With Alternate Registry ----
|
|
|
|
Scenario: Discover from an alternate registry
|
|
Given a tool registry
|
|
And a tool runner for the registry
|
|
And an alternate registry with 3 tools
|
|
When I discover tools from the alternate registry
|
|
Then the discovered list should contain 3 tools
|
|
|
|
# ---- Execute Without Prior Activate ----
|
|
|
|
Scenario: Execute without prior activate still works via registry lookup
|
|
Given a tool registry
|
|
And a registered tool spec named "test/no-activate" with an adder handler
|
|
And a tool runner for the registry
|
|
When I execute tool "test/no-activate" with inputs {"a": 5, "b": 3}
|
|
Then the tool result should be successful
|
|
|
|
# ---- Handler Returns Non-Dict ----
|
|
|
|
Scenario: Handler returning non-dict is wrapped in result dict
|
|
Given a tool registry
|
|
And a registered tool spec named "test/scalar" with a scalar handler
|
|
And a tool runner for the registry
|
|
When I execute tool "test/scalar" with inputs {}
|
|
Then the tool result should be successful
|
|
And the tool result output should contain key "result"
|
|
|
|
# ---- List Tools With tool_type Filter ----
|
|
|
|
Scenario: List tools with tool_type filter
|
|
Given a tool registry
|
|
And a registered tool spec named "test/filtered"
|
|
When I list tools with tool_type "tool"
|
|
Then the tool list should contain 1 tools
|