feat(actor): add actor registry and loader
This commit is contained in:
@@ -0,0 +1,255 @@
|
||||
Feature: Actor registry and loader
|
||||
As a CleverAgents user
|
||||
I want to discover, load, and cache actor YAML configs from the filesystem
|
||||
So that actors are available for compilation and execution
|
||||
|
||||
# ────────────────────────────────────────────────────────────
|
||||
# Discovery from search roots
|
||||
# ────────────────────────────────────────────────────────────
|
||||
|
||||
Scenario: Discover actors from a single directory
|
||||
Given a temporary actors directory with files
|
||||
| filename | name | type | model |
|
||||
| reviewer.yaml | assistants/reviewer | llm | gpt-4 |
|
||||
| formatter.yaml | utilities/formatter | llm | gpt-4 |
|
||||
When I create an actor loader with that directory as search root
|
||||
And I run discovery
|
||||
Then the loader should find 2 actors
|
||||
And the loader should contain actor "assistants/reviewer"
|
||||
And the loader should contain actor "utilities/formatter"
|
||||
|
||||
Scenario: Discover actors from multiple search roots
|
||||
Given a temporary actors directory "root_a" with files
|
||||
| filename | name | type | model |
|
||||
| writer.yaml | assistants/writer | llm | gpt-4 |
|
||||
And a temporary actors directory "root_b" with files
|
||||
| filename | name | type | model |
|
||||
| analyst.yaml | data/analyst | llm | gpt-4 |
|
||||
When I create an actor loader with both directories as search roots
|
||||
And I run discovery
|
||||
Then the loader should find 2 actors
|
||||
And the loader should contain actor "assistants/writer"
|
||||
And the loader should contain actor "data/analyst"
|
||||
|
||||
Scenario: Only YAML files are discovered
|
||||
Given a temporary actors directory with files
|
||||
| filename | name | type | model |
|
||||
| valid.yaml | assistants/valid | llm | gpt-4 |
|
||||
And a non-YAML file "readme.txt" in the directory
|
||||
And a non-YAML file "config.json" in the directory
|
||||
When I create an actor loader with that directory as search root
|
||||
And I run discovery
|
||||
Then the loader should find 1 actors
|
||||
|
||||
Scenario: Nested YAML files are discovered recursively
|
||||
Given a temporary actors directory with nested structure
|
||||
| subdir | filename | name | type | model |
|
||||
| sub | nested.yaml | assistants/nested | llm | gpt-4 |
|
||||
| sub/deep | deep.yaml | assistants/deep | llm | gpt-4 |
|
||||
And a top-level actor file
|
||||
| filename | name | type | model |
|
||||
| top.yaml | assistants/top | llm | gpt-4 |
|
||||
When I create an actor loader with that directory as search root
|
||||
And I run discovery
|
||||
Then the loader should find 3 actors
|
||||
|
||||
# ────────────────────────────────────────────────────────────
|
||||
# Duplicate detection
|
||||
# ────────────────────────────────────────────────────────────
|
||||
|
||||
Scenario: Duplicate actor names across search roots emit consolidated error
|
||||
Given a temporary actors directory "dup_a" with files
|
||||
| filename | name | type | model |
|
||||
| writer.yaml | assistants/writer | llm | gpt-4 |
|
||||
And a temporary actors directory "dup_b" with files
|
||||
| filename | name | type | model |
|
||||
| writer2.yaml | assistants/writer | llm | gpt-4 |
|
||||
When I create an actor loader with both directories as search roots
|
||||
And I run discovery expecting errors
|
||||
Then the loader should raise a validation error mentioning "assistants/writer"
|
||||
|
||||
Scenario: Duplicate actor names within a single search root emit error
|
||||
Given a temporary actors directory with files
|
||||
| filename | name | type | model |
|
||||
| one.yaml | assistants/helper | llm | gpt-4 |
|
||||
| two.yaml | assistants/helper | llm | gpt-4 |
|
||||
When I create an actor loader with that directory as search root
|
||||
And I run discovery expecting errors
|
||||
Then the loader should raise a validation error mentioning "assistants/helper"
|
||||
|
||||
# ────────────────────────────────────────────────────────────
|
||||
# Namespace handling
|
||||
# ────────────────────────────────────────────────────────────
|
||||
|
||||
Scenario: Default local/ namespace applied when namespace omitted
|
||||
Given a temporary actors directory with a nameless actor file
|
||||
| filename | raw_name | type | model |
|
||||
| bare.yaml | my-agent | llm | gpt-4 |
|
||||
When I create an actor loader with that directory as search root
|
||||
And I run discovery
|
||||
Then the loader should contain actor "local/my-agent"
|
||||
|
||||
Scenario: Explicit namespace preserved as-is
|
||||
Given a temporary actors directory with files
|
||||
| filename | name | type | model |
|
||||
| custom.yaml | myteam/my-actor | llm | gpt-4 |
|
||||
When I create an actor loader with that directory as search root
|
||||
And I run discovery
|
||||
Then the loader should contain actor "myteam/my-actor"
|
||||
|
||||
# ────────────────────────────────────────────────────────────
|
||||
# Namespaced lookup
|
||||
# ────────────────────────────────────────────────────────────
|
||||
|
||||
Scenario: Get actor by namespaced name
|
||||
Given a temporary actors directory with files
|
||||
| filename | name | type | model |
|
||||
| helper.yaml | assistants/helper | llm | gpt-4 |
|
||||
When I create an actor loader with that directory as search root
|
||||
And I run discovery
|
||||
Then I can retrieve actor "assistants/helper" by name
|
||||
And the retrieved actor type should be "llm"
|
||||
|
||||
Scenario: Get nonexistent actor returns None
|
||||
Given a temporary actors directory with files
|
||||
| filename | name | type | model |
|
||||
| helper.yaml | assistants/helper | llm | gpt-4 |
|
||||
When I create an actor loader with that directory as search root
|
||||
And I run discovery
|
||||
Then getting actor "assistants/missing" should return None
|
||||
|
||||
Scenario: List actors filtered by namespace
|
||||
Given a temporary actors directory with files
|
||||
| filename | name | type | model |
|
||||
| rev.yaml | assistants/reviewer | llm | gpt-4 |
|
||||
| fmt.yaml | utilities/formatter | llm | gpt-4 |
|
||||
| ana.yaml | assistants/analyzer | llm | gpt-4 |
|
||||
When I create an actor loader with that directory as search root
|
||||
And I run discovery
|
||||
Then listing actors with namespace "assistants" should return 2 actors
|
||||
And listing actors with namespace "utilities" should return 1 actors
|
||||
|
||||
# ────────────────────────────────────────────────────────────
|
||||
# Content hash caching
|
||||
# ────────────────────────────────────────────────────────────
|
||||
|
||||
Scenario: Unchanged files are not reloaded on re-discovery
|
||||
Given a temporary actors directory with files
|
||||
| filename | name | type | model |
|
||||
| cached.yaml | assistants/cached | llm | gpt-4 |
|
||||
When I create an actor loader with that directory as search root
|
||||
And I run discovery
|
||||
And I run discovery again
|
||||
Then the actor "assistants/cached" should have been loaded only once
|
||||
|
||||
Scenario: Modified files are reloaded on re-discovery
|
||||
Given a temporary actors directory with files
|
||||
| filename | name | type | model |
|
||||
| mutable.yaml | assistants/mutable | llm | gpt-4 |
|
||||
When I create an actor loader with that directory as search root
|
||||
And I run discovery
|
||||
And I modify the actor file "mutable.yaml" to change the model to "gpt-3.5-turbo"
|
||||
And I run discovery again
|
||||
Then the actor "assistants/mutable" model should be "gpt-3.5-turbo"
|
||||
|
||||
# ────────────────────────────────────────────────────────────
|
||||
# Validation at load time
|
||||
# ────────────────────────────────────────────────────────────
|
||||
|
||||
Scenario: Invalid YAML file is rejected with clear error
|
||||
Given a temporary actors directory with an invalid YAML file "bad.yaml"
|
||||
When I create an actor loader with that directory as search root
|
||||
And I run discovery expecting errors
|
||||
Then the loader should raise a validation error mentioning "bad.yaml"
|
||||
|
||||
Scenario: YAML file missing required fields is rejected
|
||||
Given a temporary actors directory with a schema-invalid file "incomplete.yaml"
|
||||
When I create an actor loader with that directory as search root
|
||||
And I run discovery expecting errors
|
||||
Then the loader should raise a validation error
|
||||
|
||||
# ────────────────────────────────────────────────────────────
|
||||
# Integration with example actors
|
||||
# ────────────────────────────────────────────────────────────
|
||||
|
||||
Scenario: Discover all example actors from examples/actors/
|
||||
Given the project examples/actors directory exists
|
||||
When I create an actor loader with the examples/actors directory
|
||||
And I run discovery
|
||||
Then the loader should find at least 5 actors
|
||||
|
||||
# ────────────────────────────────────────────────────────────
|
||||
# Cache invalidation
|
||||
# ────────────────────────────────────────────────────────────
|
||||
|
||||
Scenario: Clear cache removes all loaded actors
|
||||
Given a temporary actors directory with files
|
||||
| filename | name | type | model |
|
||||
| test.yaml | assistants/test | llm | gpt-4 |
|
||||
When I create an actor loader with that directory as search root
|
||||
And I run discovery
|
||||
And I clear the loader cache
|
||||
Then the loader should find 0 actors
|
||||
|
||||
Scenario: Deleted actor file is removed on re-discovery
|
||||
Given a temporary actors directory with files
|
||||
| filename | name | type | model |
|
||||
| keep.yaml | assistants/keep | llm | gpt-4 |
|
||||
| remove.yaml | assistants/removable | llm | gpt-4 |
|
||||
When I create an actor loader with that directory as search root
|
||||
And I run discovery
|
||||
And I delete the actor file "remove.yaml"
|
||||
And I run discovery again
|
||||
Then the loader should find 1 actors
|
||||
And the loader should contain actor "assistants/keep"
|
||||
And getting actor "assistants/removable" should return None
|
||||
|
||||
# ────────────────────────────────────────────────────────────
|
||||
# Tool Registry integration
|
||||
# ────────────────────────────────────────────────────────────
|
||||
|
||||
Scenario: Actor loader resolves tool references through tool registry
|
||||
Given a tool registry with tool "files/read_file"
|
||||
And a temporary actors directory with a tool-actor file
|
||||
| filename | name | type | tools |
|
||||
| tools.yaml | utilities/file_ops | tool | files/read_file |
|
||||
When I create an actor loader with that directory and the tool registry
|
||||
And I run discovery
|
||||
Then the loader should contain actor "utilities/file_ops"
|
||||
And the actor "utilities/file_ops" tools should include "files/read_file"
|
||||
|
||||
Scenario: Actor with unresolvable tool reference logs warning
|
||||
Given an empty tool registry
|
||||
And a temporary actors directory with a tool-actor file
|
||||
| filename | name | type | tools |
|
||||
| tools.yaml | utilities/ops | tool | missing/nonexistent |
|
||||
When I create an actor loader with that directory and the tool registry
|
||||
And I run discovery
|
||||
Then the loader should contain actor "utilities/ops"
|
||||
And the loader should have a warning about unresolved tool "missing/nonexistent"
|
||||
|
||||
# ────────────────────────────────────────────────────────────
|
||||
# Edge cases for coverage
|
||||
# ────────────────────────────────────────────────────────────
|
||||
|
||||
Scenario: Non-existent search root is skipped gracefully
|
||||
Given a non-existent directory path as search root
|
||||
When I create an actor loader with that directory as search root
|
||||
And I run discovery
|
||||
Then the loader should find 0 actors
|
||||
|
||||
Scenario: YAML file containing a list instead of a mapping is rejected
|
||||
Given a temporary actors directory with a list-content YAML file "list.yaml"
|
||||
When I create an actor loader with that directory as search root
|
||||
And I run discovery expecting errors
|
||||
Then the loader should raise a validation error mentioning "list.yaml"
|
||||
|
||||
Scenario: LLM actor without tools does not produce warnings with tool registry
|
||||
Given a tool registry with tool "files/read_file"
|
||||
And a temporary actors directory with files
|
||||
| filename | name | type | model |
|
||||
| simple.yaml | assistants/simple | llm | gpt-4 |
|
||||
When I create an actor loader with that directory and the tool registry
|
||||
And I run discovery
|
||||
Then the loader should contain actor "assistants/simple"
|
||||
And the loader should have 0 warnings
|
||||
Reference in New Issue
Block a user