Files
cleveragents-core/features/actor_config_coverage.feature
T

433 lines
16 KiB
Gherkin

Feature: Actor configuration uncovered lines coverage
As a developer maintaining actor configuration parsing
I want robust coverage for actor config edge cases
So that failures and overrides are validated
Background:
Given an isolated actor config workspace
# --- load_blob_from_file: lines 39-55 ---
Scenario: Missing config file surfaces helpful error
When I load the actor config blob from "missing.json"
Then a ValueError should be raised containing "Config file not found"
Scenario: JSON null config becomes empty mapping
Given an actor config file "null.json" with content:
"""
null
"""
When I load the actor config blob from "null.json"
Then the loaded actor config blob should equal {}
Scenario: JSON list config raises validation error
Given an actor config file "list.json" with content:
"""
[1, 2, 3]
"""
When I load the actor config blob from "list.json"
Then a ValueError should be raised containing "Config must be a JSON or YAML object"
Scenario: Valid JSON config is loaded correctly
Given an actor config file "valid.json" with content:
"""
{"provider": "openai", "model": "gpt-4"}
"""
When I load the actor config blob from "valid.json"
Then the loaded actor config blob should equal {"provider": "openai", "model": "gpt-4"}
# --- _load_v2_yaml_content: lines 59-60 (yaml unavailable) ---
Scenario: YAML dependency absence surfaces requirement
Given PyYAML parsing is unavailable for actor config
And an actor config file "needs_yaml.yaml" with content:
"""
provider: openai
"""
When I load the actor config blob from "needs_yaml.yaml"
Then a ValueError should be raised containing "PyYAML is required for YAML actor configs"
# --- _load_v2_yaml_content: lines 63-106 (YAML parsing paths) ---
Scenario: Empty YAML returns empty object
Given an actor config file "empty.yaml" with content:
"""
"""
When I load the actor config blob from "empty.yaml"
Then the loaded actor config blob should equal {}
Scenario: Non-object YAML raises validation error
Given an actor config file "list.yaml" with content:
"""
- provider: openai
"""
When I load the actor config blob from "list.yaml"
Then a ValueError should be raised containing "Config must be a JSON or YAML object"
Scenario: Plain YAML config is loaded via safe_load path
Given an actor config file "plain.yaml" with content:
"""
provider: openai
model: gpt-4
"""
When I load the actor config blob from "plain.yaml"
Then the loaded actor config blob should equal {"provider": "openai", "model": "gpt-4"}
# --- _load_v2_yaml_content: lines 64-92 (templated YAML branch) ---
Scenario: Templated YAML preserves double-brace placeholders in system_prompt
Given an actor config file "templated.yaml" with content:
"""
provider: openai
model: gpt-4
system_prompt: "Use {{ context.paper_details.topic }} to write."
"""
When I load the actor config blob from "templated.yaml"
Then the loaded actor config value at "system_prompt" should equal "Use {{ context.paper_details.topic }} to write."
Scenario: Templated YAML preserves block-tag placeholders in system_prompt
Given an actor config file "block_template.yaml" with content:
"""
provider: openai
model: gpt-4
system_prompt: "{% if context.brainstorming_summary %}summary{% endif %}"
"""
When I load the actor config blob from "block_template.yaml"
Then the loaded actor config value at "system_prompt" should contain "summary"
# --- _restore_template_syntax: lines 110-130 (dict and list recursion) ---
Scenario: Restore template syntax recurses into nested dicts
Given an actor config file "nested_template.yaml" with content:
"""
provider: openai
model: gpt-4
outer:
system_prompt: "Hello {{ context.paper_details.topic }}"
"""
When I load the actor config blob from "nested_template.yaml"
Then the loaded actor config nested value at "outer.system_prompt" should equal "Hello {{ context.paper_details.topic }}"
Scenario: Restore template syntax recurses into lists
Given an actor config file "list_template.yaml" with content:
"""
provider: openai
model: gpt-4
messages:
- role: system
system_prompt: "Topic is {{ context.paper_details.topic }}"
- role: user
content: "plain text"
"""
When I load the actor config blob from "list_template.yaml"
Then the loaded actor config nested value at "messages.0.system_prompt" should equal "Topic is {{ context.paper_details.topic }}"
# --- _interpolate_env_vars: lines 134-174 (env var substitution and type coercion) ---
Scenario: Environment variable interpolation uses default boolean value
Given an actor config file "env_bool.yaml" with content:
"""
provider: openai
model: gpt-4
options:
flag: "${MISSING_BOOL_VAR:true}"
"""
And the actor config environment variable "MISSING_BOOL_VAR" is unset
When I load the actor config blob from "env_bool.yaml"
Then the loaded actor config value at "options.flag" should equal True
Scenario: Environment variable interpolation uses default false boolean value
Given an actor config file "env_false.yaml" with content:
"""
provider: openai
model: gpt-4
options:
flag: "${MISSING_BOOL_FALSE:false}"
"""
And the actor config environment variable "MISSING_BOOL_FALSE" is unset
When I load the actor config blob from "env_false.yaml"
Then the loaded actor config value at "options.flag" should equal False
Scenario: Environment variable interpolation uses default integer value
Given an actor config file "env_int.yaml" with content:
"""
provider: openai
model: gpt-4
options:
count: "${MISSING_INT_VAR:42}"
"""
And the actor config environment variable "MISSING_INT_VAR" is unset
When I load the actor config blob from "env_int.yaml"
Then the loaded actor config value at "options.count" should equal 42
Scenario: Environment variable interpolation uses default string value
Given an actor config file "env_str.yaml" with content:
"""
provider: openai
model: gpt-4
options:
greeting: "${MISSING_STR_VAR:hello}"
"""
And the actor config environment variable "MISSING_STR_VAR" is unset
When I load the actor config blob from "env_str.yaml"
Then the loaded actor config value at "options.greeting" should equal "hello"
Scenario: Environment variable interpolation uses default float value
Given an actor config file "env_float.yaml" with content:
"""
provider: openai
model: gpt-4
options:
ratio: "${MISSING_FLOAT_VAR:2.5}"
"""
And the actor config environment variable "MISSING_FLOAT_VAR" is unset
When I load the actor config blob from "env_float.yaml"
Then the loaded actor config value at "options.ratio" should equal 2.5
Scenario: Environment variable interpolation reads set env var
Given an actor config file "env_set.yaml" with content:
"""
provider: openai
model: gpt-4
options:
api_key: "${TEST_ACTOR_API_KEY}"
"""
And the actor config environment variable "TEST_ACTOR_API_KEY" is set to "secret123"
When I load the actor config blob from "env_set.yaml"
Then the loaded actor config value at "options.api_key" should equal "secret123"
Scenario: Missing required environment variable raises an error
Given an actor config file "required_env.yaml" with content:
"""
provider: openai
model: gpt-4
secret: "${REQUIRED_SECRET}"
"""
And the actor config environment variable "REQUIRED_SECRET" is unset
When I load the actor config blob from "required_env.yaml"
Then a ValueError should be raised containing "Environment variable 'REQUIRED_SECRET' is not set"
Scenario: Environment variable coerces top-level string true to boolean
Given an actor config file "env_top_bool.yaml" with content:
"""
provider: openai
model: gpt-4
enabled: true
"""
When I load the actor config blob from "env_top_bool.yaml"
Then the loaded actor config value at "enabled" should equal True
Scenario: Environment variable coerces string integer to int
Given an actor config file "env_top_int.yaml" with content:
"""
provider: openai
model: gpt-4
retries: 3
"""
When I load the actor config blob from "env_top_int.yaml"
Then the loaded actor config value at "retries" should equal 3
Scenario: Interpolation coerces negative integer default
Given an actor config file "env_neg_int.yaml" with content:
"""
provider: openai
model: gpt-4
options:
offset: "${MISSING_NEG_INT:-5}"
"""
And the actor config environment variable "MISSING_NEG_INT" is unset
When I load the actor config blob from "env_neg_int.yaml"
Then the loaded actor config value at "options.offset" should equal -5
Scenario: Interpolation recurses into nested dicts and lists
Given an actor config file "env_nested.yaml" with content:
"""
provider: openai
model: gpt-4
options:
items:
- "${MISSING_ITEM_VAR:default_item}"
"""
And the actor config environment variable "MISSING_ITEM_VAR" is unset
When I load the actor config blob from "env_nested.yaml"
Then the loaded actor config nested value at "options.items.0" should equal "default_item"
# --- from_file: lines 189-190 ---
Scenario: from_file applies overrides and unsafe flag
Given an actor config file "valid_ff.json" with content:
"""
{"provider": "file-provider", "model": "file-model", "options": {"k": "v"}, "graph_descriptor": {"node": true}}
"""
When I parse the actor configuration from file "valid_ff.json" with overrides:
"""
{"name": "cli-name", "graph_descriptor": {"node": "override"}, "unsafe": true}
"""
Then the actor configuration should have provider "file-provider" and model "file-model"
And the actor configuration name should be "cli-name"
And the actor configuration graph descriptor should equal {"node": "override"}
And the actor configuration options should equal {"k": "v"}
And the actor configuration unsafe flag should be true
# --- from_blob: lines 236 (default_options), 238 (v2_options), 250 (missing model) ---
Scenario: from_blob rejects missing provider
When I build an actor configuration from blob {"model": "only-model"}
Then a ValueError should be raised containing "provider is required"
Scenario: from_blob rejects missing model
When I build an actor configuration from blob {"provider": "only-provider"}
Then a ValueError should be raised containing "model is required"
Scenario: from_blob merges default and v2 and override options
When I build an actor configuration from structured blob with defaults and overrides:
"""
{
"blob": {
"provider": "cli-provider",
"model": "cli-model",
"options": {"user": "blob"},
"agents": {
"writer": {
"config": {
"options": {"v2": "v2-option"}
}
}
}
},
"default_options": {"base": "default"},
"option_overrides": {"user": "override", "extra": "added"}
}
"""
Then the actor configuration should have provider "cli-provider" and model "cli-model"
And the actor configuration options should equal {"base": "default", "v2": "v2-option", "user": "override", "extra": "added"}
Scenario: from_blob with None blob defaults to empty data
When I build actor config from None blob with provider and model overrides
Then the actor configuration should have provider "override-provider" and model "override-model"
# --- _extract_v2_actor: lines 275-307 ---
Scenario: v2 YAML actor config infers provider and model
Given an actor config file "v2.yaml" with content:
"""
cleveragents:
default_router: main_router
agents:
paper_writer:
type: llm
config:
provider: openai
model: gpt-4
unsafe: true
options:
temperature: 0.5
routes:
main_router:
type: stream
operators:
- type: map
params:
agent: paper_writer
publications:
- __output__
"""
When I parse the actor configuration from file "v2.yaml" with overrides:
"""
{}
"""
Then the actor configuration should have provider "openai" and model "gpt-4"
And the actor configuration unsafe flag should be true
And the actor configuration graph descriptor should include key "routes"
And the actor configuration graph descriptor should include key "agents"
And the actor configuration graph descriptor should include key "cleveragents"
And the actor configuration options should equal {"temperature": 0.5}
Scenario: v2 extraction includes merges and templates keys when present
Given an actor config file "v2_merges.yaml" with content:
"""
agents:
writer:
config:
provider: openai
model: gpt-4
merges:
combined:
type: join
templates:
default:
system_prompt: "hello"
"""
When I parse the actor configuration from file "v2_merges.yaml" with overrides:
"""
{}
"""
Then the actor configuration should have provider "openai" and model "gpt-4"
And the actor configuration graph descriptor should include key "merges"
And the actor configuration graph descriptor should include key "templates"
Scenario: v2 extraction handles agent entry without config block
Given an actor config file "v2_no_config.yaml" with content:
"""
provider: fallback-provider
model: fallback-model
agents:
first:
type: llm
"""
When I parse the actor configuration from file "v2_no_config.yaml" with overrides:
"""
{}
"""
Then the actor configuration should have provider "fallback-provider" and model "fallback-model"
# --- _extract_v2_options: lines 316-326 ---
Scenario: v2 extraction skips non-dict agent entries
Given an actor config file "invalid_v2.yaml" with content:
"""
provider: fallback-provider
model: fallback-model
agents:
first: not-a-dict
"""
When I parse the actor configuration from file "invalid_v2.yaml" with overrides:
"""
{}
"""
Then the actor configuration should have provider "fallback-provider" and model "fallback-model"
Scenario: v2 options extraction returns None for agents without options
Given an actor config file "v2_no_opts.yaml" with content:
"""
agents:
writer:
config:
provider: openai
model: gpt-4
"""
When I parse the actor configuration from file "v2_no_opts.yaml" with overrides:
"""
{}
"""
Then the actor configuration should have provider "openai" and model "gpt-4"
And the actor configuration options should equal {}
Scenario: from_blob reads provider_type and model_id aliases
When I build an actor configuration from blob {"provider_type": "aliased-provider", "model_id": "aliased-model"}
Then the actor configuration should have provider "aliased-provider" and model "aliased-model"
Scenario: from_blob resolves graph from graph key alias
When I build actor config from blob using graph key alias
Then the actor configuration graph descriptor should equal {"step": "one"}
Scenario: from_blob sets unsafe from blob data
When I build an actor configuration from blob {"provider": "p", "model": "m", "unsafe": True}
Then the actor configuration should have provider "p" and model "m"
And the actor configuration unsafe flag should be true
Scenario: from_blob with non-dict graph coerces to None
When I build an actor configuration from blob {"provider": "p", "model": "m", "graph_descriptor": "not-a-dict"}
Then the actor configuration should have provider "p" and model "m"
And the actor configuration graph descriptor should be None