b3851693c8
CI / push-validation (push) Successful in 38s
CI / helm (push) Successful in 49s
CI / lint (push) Successful in 1m20s
CI / build (push) Successful in 1m13s
CI / quality (push) Successful in 1m38s
CI / typecheck (push) Successful in 2m6s
CI / security (push) Successful in 2m5s
CI / benchmark-regression (push) Failing after 1m3s
CI / e2e_tests (push) Successful in 57s
CI / integration_tests (push) Successful in 4m37s
CI / unit_tests (push) Successful in 7m0s
CI / docker (push) Successful in 1m31s
CI / coverage (push) Successful in 13m59s
CI / status-check (push) Successful in 2s
CI / benchmark-publish (push) Successful in 1h37m21s
Two code paths in the reactive actor run pipeline silently discarded the options: block from v3 actor YAML, preventing custom OpenAI-compatible backends (llama.cpp, Ollama, etc.) from being used. Review fixes applied: - Fix 1: Relabeled issue #11223 from Type/Task to Type/Bug; added @tdd_issue/@tdd_issue_11223 tags to all 5 Behave scenarios. - Fix 2: openai_api_key in options now routes through the registry's __api_key_sentinel mechanism so user-provided keys correctly override environment defaults. (stream_router.py) - Fix 3: type: graph actors now propagate actor-level options to individual node configs via setdefault. (config_parser.py) - Fix 4: Options keys are validated against an explicit allowlist; reserved keys (provider_type, model_id) are excluded; unrecognized keys log a WARNING instead of being silently forwarded. (stream_router.py) - Fix 5: Updated _build_from_v3 docstring to list options as a propagated field. (config_parser.py) - Fix 6: Removed inconsistent and options_raw emptiness guard; empty options dicts are now preserved consistently. (config_parser.py) - Fix 7: Reserved keys provider_type and model_id are excluded from the options merge loop to prevent TypeError. (stream_router.py) - Fix 8: Added Behave scenario verifying top-level temperature takes precedence over options duplicate. (consolidated_routing.feature + steps) - Fix 9: Strengthened "no extra kwargs" assertion to assert kwargs == {} directly instead of using an allow-list filter. (stream_router steps) - Fix 10: Strengthened options assertion to exact dict equality. (actor_v3_schema_extended_steps.py) - N1: Comment style aligned to M5: prefix convention. - N2: Type annotations changed from Any to Context (behave.runner). - N3: Added Behave scenario for empty options: {} dict behavior. Tests: 5 new Behave scenarios (3 in actor_v3_schema.feature, 2 in consolidated_routing.feature) with @tdd_issue/@tdd_issue_11223 tags. ISSUES CLOSED: #11223
235 lines
12 KiB
Gherkin
235 lines
12 KiB
Gherkin
Feature: v3 Actor YAML schema support in CLI and registry
|
|
As a developer using v3 actor YAML configs
|
|
I want the CLI and registry to validate, persist, and execute v3 schema actors
|
|
So that spec-compliant actors with skills, LSP bindings, and LangGraph routes work
|
|
|
|
Scenario: ActorConfiguration.from_blob extracts provider and model from v3 LLM YAML
|
|
Given a v3 LLM actor blob with model "gpt-4"
|
|
When I call ActorConfiguration.from_blob with the v3 blob
|
|
Then the configuration should have provider "custom"
|
|
And the configuration should have model "gpt-4"
|
|
|
|
Scenario: ActorConfiguration.from_blob infers provider from model with slash
|
|
Given a v3 LLM actor blob with model "openai/gpt-4"
|
|
When I call ActorConfiguration.from_blob with the v3 blob
|
|
Then the configuration should have provider "openai"
|
|
And the configuration should have model "openai/gpt-4"
|
|
|
|
Scenario: ActorConfiguration.from_blob infers custom provider for slash-prefixed model
|
|
Given a v3 LLM actor blob with model "/gpt-4"
|
|
When I call ActorConfiguration.from_blob with the v3 blob
|
|
Then the configuration should have provider "custom"
|
|
And the configuration should have model "/gpt-4"
|
|
|
|
Scenario: ActorConfiguration.from_blob builds graph descriptor for graph actors
|
|
Given a v3 graph actor blob with a route block
|
|
When I call ActorConfiguration.from_blob with the v3 blob
|
|
Then the configuration should have a graph_descriptor with type "graph"
|
|
|
|
Scenario: ActorRegistry.add validates v3 LLM actor YAML
|
|
Given a mock actor service for v3 testing
|
|
And a v3 LLM actor YAML text
|
|
When I call ActorRegistry.add with the v3 YAML
|
|
Then the actor should be persisted with v3 fields in config_blob
|
|
And the persisted config_blob should contain skills
|
|
And the persisted config_blob should contain lsp bindings
|
|
|
|
Scenario: ActorRegistry.add rejects v3 YAML without required description
|
|
Given a mock actor service for v3 testing
|
|
And a v3 actor YAML text missing description
|
|
When I call ActorRegistry.add with the invalid v3 YAML
|
|
Then a ValidationError should be raised mentioning description
|
|
|
|
Scenario: ActorRegistry.add validates and compiles v3 graph actor
|
|
Given a mock actor service for v3 testing
|
|
And a v3 graph actor YAML text with route
|
|
When I call ActorRegistry.add with the v3 graph YAML
|
|
Then the actor should be persisted with compiled metadata
|
|
And the graph_descriptor should contain route information
|
|
|
|
Scenario: ReactiveConfigParser handles v3 LLM actor format
|
|
Given a v3 LLM actor config dict
|
|
When I parse the v3 config through ReactiveConfigParser
|
|
Then the reactive config should have one agent
|
|
And the agent config should contain the model
|
|
And the agent config should contain skills
|
|
|
|
Scenario: ReactiveConfigParser handles v3 graph actor format
|
|
Given a v3 graph actor config dict with route
|
|
When I parse the v3 config through ReactiveConfigParser
|
|
Then the reactive config should have agents for each node
|
|
And the reactive config should have a graph route
|
|
And the graph route edges should use source and target keys
|
|
|
|
# M14: test update=True path
|
|
Scenario: ActorRegistry.add with update=True overwrites existing actor
|
|
Given a mock actor service for v3 testing
|
|
And an existing actor in the mock service
|
|
And a v3 LLM actor YAML text
|
|
When I call ActorRegistry.add with update=True for the v3 YAML
|
|
Then the actor should be persisted successfully with update
|
|
|
|
# M15: test type:tool extraction and parsing paths
|
|
# from_blob requires model for ActorConfiguration — tool actors without
|
|
# model raise ValueError. The proper v3 path is ActorRegistry.add().
|
|
Scenario: ActorConfiguration.from_blob rejects type tool without model
|
|
Given a v3 tool actor blob without model
|
|
When I call ActorConfiguration.from_blob with the v3 tool blob
|
|
Then the tool actor from_blob should raise ValueError for missing model
|
|
|
|
Scenario: ActorRegistry.add validates v3 tool actor YAML
|
|
Given a mock actor service for v3 testing
|
|
And a v3 tool actor YAML text
|
|
When I call ActorRegistry.add with the v3 tool YAML
|
|
Then the tool actor should be persisted with type tool
|
|
|
|
# m13: test _build_from_v3 with lsp as dict
|
|
Scenario: ReactiveConfigParser handles v3 LLM actor with lsp as dict
|
|
Given a v3 LLM actor config dict with lsp as dict
|
|
When I parse the v3 config through ReactiveConfigParser
|
|
Then the reactive config should have one agent
|
|
And the agent config should contain lsp as dict
|
|
|
|
# m13: test context_view, memory, env_vars, response_format propagation
|
|
Scenario: ReactiveConfigParser propagates context_view memory env_vars and response_format
|
|
Given a v3 LLM actor config dict with context_view and memory
|
|
When I parse the v3 config through ReactiveConfigParser
|
|
Then the reactive config should have one agent
|
|
And the agent config should contain context_view
|
|
And the agent config should contain memory settings
|
|
And the agent config should contain env_vars
|
|
And the agent config should contain response_format
|
|
|
|
# m13: positive _is_v3_format test
|
|
Scenario: v3 format detection returns true for v3 LLM data
|
|
Given a v3 LLM actor config dict
|
|
When I check if the v3 LLM config is v3 format
|
|
Then it should be detected as v3
|
|
|
|
# Cycle 2 review: defensive guard BDD coverage
|
|
Scenario: ReactiveConfigParser rejects graph with invalid entry_node
|
|
Given a v3 graph actor config dict with invalid entry_node
|
|
When I parse the v3 config through ReactiveConfigParser expecting error
|
|
Then a ConfigurationError should be raised mentioning entry_node
|
|
|
|
Scenario: ReactiveConfigParser skips edges with missing from_node or to_node
|
|
Given a v3 graph actor config dict with incomplete edges
|
|
When I parse the v3 config through ReactiveConfigParser
|
|
Then the graph route should have fewer edges than the raw input
|
|
|
|
Scenario: ReactiveConfigParser skips non-dict edge entries
|
|
Given a v3 graph actor config dict with non-dict edges
|
|
When I parse the v3 config through ReactiveConfigParser
|
|
Then the graph route should have only valid dict edges
|
|
|
|
# Coverage: v3_registry.py — name without slash gets local/ prefix
|
|
Scenario: ActorRegistry.add namespaces bare actor name with local prefix
|
|
Given a mock actor service for v3 testing
|
|
And a v3 LLM actor YAML text with bare name
|
|
When I call ActorRegistry.add with the bare-name v3 YAML
|
|
Then the persisted actor name should be prefixed with local
|
|
|
|
# Coverage: v3_registry.py — unsafe actor rejected without allow_unsafe
|
|
Scenario: ActorRegistry.add rejects unsafe v3 actor without allow_unsafe flag
|
|
Given a mock actor service for v3 testing
|
|
And a v3 LLM actor YAML text marked unsafe
|
|
When I call ActorRegistry.add with the unsafe v3 YAML
|
|
Then a ValidationError should be raised mentioning unsafe
|
|
|
|
# Coverage: v3_registry.py — duplicate actor rejected when update=False
|
|
Scenario: ActorRegistry.add rejects duplicate v3 actor when update is False
|
|
Given a mock actor service for v3 testing
|
|
And an existing actor in the mock service
|
|
And a v3 LLM actor YAML text
|
|
When I call ActorRegistry.add with the v3 YAML expecting error
|
|
Then a ValidationError should be raised mentioning already exists
|
|
|
|
# Coverage: v3_registry.py — ActorCompilationError during graph compilation
|
|
Scenario: ActorRegistry.add persists graph actor even when compilation fails
|
|
Given a mock actor service for v3 testing
|
|
And a v3 graph actor YAML text with route
|
|
When I call ActorRegistry.add with the v3 graph YAML and compilation fails
|
|
Then the actor should still be persisted without compiled metadata
|
|
|
|
# Coverage: registry.py — _ensure_namespaced via get()
|
|
Scenario: ActorRegistry.get namespaces bare actor name with local prefix
|
|
Given a mock actor service for v3 testing
|
|
When I call ActorRegistry.get with a bare actor name
|
|
Then the actor service should be queried with local-prefixed name
|
|
|
|
# Coverage: registry.py — add() with non-dict YAML
|
|
Scenario: ActorRegistry.add rejects non-mapping YAML
|
|
Given a mock actor service for v3 testing
|
|
When I call ActorRegistry.add with a non-mapping YAML string
|
|
Then a ValidationError should be raised mentioning mapping
|
|
|
|
# Coverage: registry.py — upsert_actor v3 validation failure
|
|
Scenario: ActorRegistry.upsert_actor rejects invalid v3 config_blob
|
|
Given a mock actor service for v3 testing
|
|
When I call ActorRegistry.upsert_actor with an invalid v3 config_blob
|
|
Then a ValidationError should be raised mentioning invalid v3 actor
|
|
|
|
# Coverage: config_parser.py — _merge with new=None
|
|
Scenario: ReactiveConfigParser merge handles None new dict gracefully
|
|
When I merge a None dict into a base config
|
|
Then the base config should remain unchanged
|
|
|
|
# Coverage: config_parser.py — missing model for llm actor
|
|
Scenario: ReactiveConfigParser rejects v3 LLM actor with missing model
|
|
Given a v3 LLM actor config dict with no model field
|
|
When I parse the v3 config through ReactiveConfigParser expecting error
|
|
Then a ConfigurationError should be raised mentioning model
|
|
|
|
# Coverage: config_parser.py — lsp_capabilities and lsp_context_enrichment propagation
|
|
Scenario: ReactiveConfigParser propagates lsp_capabilities and lsp_context_enrichment
|
|
Given a v3 LLM actor config dict with lsp_capabilities and lsp_context_enrichment
|
|
When I parse the v3 config through ReactiveConfigParser
|
|
Then the agent config should contain lsp_capabilities
|
|
And the agent config should contain lsp_context_enrichment
|
|
|
|
# Coverage: config_parser.py — graph actor without route raises ConfigurationError
|
|
Scenario: ReactiveConfigParser rejects v3 graph actor without route
|
|
Given a v3 graph actor config dict without route
|
|
When I parse the v3 config through ReactiveConfigParser expecting error
|
|
Then a ConfigurationError should be raised mentioning route
|
|
|
|
# Coverage: config_parser.py — non-dict node and empty-id node skipped in graph
|
|
Scenario: ReactiveConfigParser skips non-dict and empty-id nodes in graph route
|
|
Given a v3 graph actor config dict with malformed nodes
|
|
When I parse the v3 config through ReactiveConfigParser
|
|
Then the reactive config should only have agents for valid nodes
|
|
|
|
# Coverage: config_parser.py — skills and lsp propagated to graph nodes
|
|
Scenario: ReactiveConfigParser propagates skills and lsp bindings to graph nodes
|
|
Given a v3 graph actor config dict with skills and lsp
|
|
When I parse the v3 config through ReactiveConfigParser
|
|
Then each graph node agent should have skills propagated
|
|
And each graph node agent should have lsp propagated
|
|
|
|
# Coverage: config_parser.py — lsp as dict propagated to graph nodes (line 330)
|
|
Scenario: ReactiveConfigParser propagates lsp dict bindings to graph nodes
|
|
Given a v3 graph actor config dict with skills and lsp as dict
|
|
When I parse the v3 config through ReactiveConfigParser
|
|
Then each graph node agent should have lsp dict propagated
|
|
|
|
# M5: options block forwarded to agent_config in _build_from_v3 (#11223).
|
|
@tdd_issue @tdd_issue_11223
|
|
Scenario: ReactiveConfigParser propagates options block to agent config
|
|
Given a v3 LLM actor config dict with options block
|
|
When I parse the v3 config through ReactiveConfigParser
|
|
Then the agent config should contain the options block
|
|
|
|
# M5: actor without options block is unaffected (#11223).
|
|
@tdd_issue @tdd_issue_11223
|
|
Scenario: ReactiveConfigParser handles v3 actor without options block
|
|
Given a v3 LLM actor config dict without options block
|
|
When I parse the v3 config through ReactiveConfigParser
|
|
Then the agent config should not contain an options key
|
|
|
|
# M5: empty options dict is preserved (#11223).
|
|
@tdd_issue @tdd_issue_11223
|
|
Scenario: ReactiveConfigParser preserves empty options block
|
|
Given a v3 LLM actor config dict with empty options block
|
|
When I parse the v3 config through ReactiveConfigParser
|
|
Then the agent config should contain an empty options block
|